agent-device 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,30 @@
1
- let e;import{isCancel as t,select as i}from"@clack/prompts";import{node_path as r,readProcessCommand as n,validateAndNormalizeBatchSteps as a,isAgentDeviceDaemonProcess as o,runCmdBackground as s,node_crypto as l,runCmd as d,displayLabel as c,spawn as u,asAppError as p,AppError as f,whichCmd as m,buildSnapshotDisplayLines as h,fileURLToPath as w,runCmdStreaming as g,formatRole as v,normalizeError as I,readVersion as y,findProjectRoot as A,getDiagnosticsMeta as S,withDiagnosticTimer as N,emitDiagnostic as b,promises as _,DEFAULT_BATCH_MAX_STEPS as D,isProcessAlive as k,readProcessStartTime as O,node_fs as E,withDiagnosticsScope as M,flushDiagnosticsToSessionFile as x,node_os as L,node_net as C,formatSnapshotLine as R}from"./350.js";async function T(e,r){let n=e,a=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(r.platform&&(n=n.filter(e=>e.platform===r.platform)),r.udid){let e=n.find(e=>e.id===r.udid&&"ios"===e.platform);if(!e)throw new f("DEVICE_NOT_FOUND",`No iOS device with UDID ${r.udid}`);return e}if(r.serial){let e=n.find(e=>e.id===r.serial&&"android"===e.platform);if(!e)throw new f("DEVICE_NOT_FOUND",`No Android device with serial ${r.serial}`);return e}if(r.deviceName){let e=a(r.deviceName),t=n.find(t=>a(t.name)===e);if(!t)throw new f("DEVICE_NOT_FOUND",`No device named ${r.deviceName}`);return t}if(1===n.length)return n[0];if(0===n.length)throw new f("DEVICE_NOT_FOUND","No devices found",{selector:r});let o=n.filter(e=>e.booted);if(1===o.length)return o[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await i({message:"Multiple devices available. Choose a device to continue:",options:(o.length>0?o:n).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(t(e))throw new f("INVALID_ARGS","Device selection cancelled");if(e){let t=n.find(t=>t.id===e);if(t)return t}}return o[0]??n[0]}let P=$(process.env.AGENT_DEVICE_RETRY_LOGS);function $(e){return["1","true","yes","on"].includes((e??"").toLowerCase())}let F=2e4,G=12e4,V=1e4;class U{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new U(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function B(e,t={},i={}){let r,n={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=n.maxAttempts&&(!i.deadline?.isExpired()||!(t>1));t+=1)try{let r=await e({attempt:t,maxAttempts:n.maxAttempts,deadline:i.deadline});return i.onEvent?.({phase:i.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:i.deadline?.elapsedMs(),remainingMs:i.deadline?.remainingMs()}),j({phase:i.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:i.deadline?.elapsedMs(),remainingMs:i.deadline?.remainingMs()}),r}catch(d){r=d;let e=i.classifyReason?.(d),a={phase:i.phase,event:"attempt_failed",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:i.deadline?.elapsedMs(),remainingMs:i.deadline?.remainingMs(),reason:e};if(i.onEvent?.(a),j(a),t>=n.maxAttempts||n.shouldRetry&&!n.shouldRetry(d,t))break;let o=function(e,t,i,r){let n=Math.min(t,e*2**(r-1));return Math.max(0,n+n*i*(2*Math.random()-1))}(n.baseDelayMs,n.maxDelayMs,n.jitter,t),s=i.deadline?Math.min(o,i.deadline.remainingMs()):o;if(s<=0)break;let l={phase:i.phase,event:"retry_scheduled",attempt:t,maxAttempts:n.maxAttempts,delayMs:s,elapsedMs:i.deadline?.elapsedMs(),remainingMs:i.deadline?.remainingMs(),reason:e};i.onEvent?.(l),j(l),await function(e){return new Promise(t=>setTimeout(t,e))}(s)}let a={phase:i.phase,event:"exhausted",attempt:n.maxAttempts,maxAttempts:n.maxAttempts,elapsedMs:i.deadline?.elapsedMs(),remainingMs:i.deadline?.remainingMs(),reason:i.classifyReason?.(r)};if(i.onEvent?.(a),j(a),r)throw r;throw new f("COMMAND_FAILED","retry failed")}async function q(e,t={}){return B(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function j(e){b({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}}),P&&process.stderr.write(`[agent-device][retry] ${JSON.stringify(e)}
2
- `)}function W(e){let t=e.error?p(e.error):null,i=e.context?.platform,r=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===i?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let n=t?.details??{},a="string"==typeof n.message?n.message:void 0,o="string"==typeof n.stdout?n.stdout:void 0,s="string"==typeof n.stderr?n.stderr:void 0,l=n.boot&&"object"==typeof n.boot?n.boot:null,d=n.bootstatus&&"object"==typeof n.bootstatus?n.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,a,o,s,"string"==typeof l?.stdout?l.stdout:void 0,"string"==typeof l?.stderr?l.stderr:void 0,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===i&&(c.includes("runner did not accept connection")||"connect"===r&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===i&&"boot"===r&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===i&&"boot"===r&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===i&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function z(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI consider increasing AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS.";case"IOS_RUNNER_CONNECT_TIMEOUT":return"Retry runner startup, inspect xcodebuild logs, and verify simulator responsiveness before command execution.";case"ANDROID_BOOT_TIMEOUT":return"Retry emulator startup and verify sys.boot_completed reaches 1; consider increasing startup budget in CI.";case"ADB_TRANSPORT_UNAVAILABLE":return"Check adb server/device transport (adb devices -l), restart adb, and ensure the target device is online and authorized.";case"CI_RESOURCE_STARVATION_SUSPECTED":return"CI machine may be resource constrained; reduce parallel jobs or use a larger runner.";case"IOS_TOOL_MISSING":return"Xcode command-line tools are missing or not in PATH; run xcode-select --install and verify xcrun works.";case"BOOT_COMMAND_FAILED":return"Inspect command stderr/stdout for the failing boot phase and retry after environment validation.";default:return"Retry once and inspect verbose logs for the failing phase."}}function J(e){return e.startsWith("emulator-")}async function H(e,t=V){return d("adb",["-s",e,"shell","getprop","sys.boot_completed"],{allowFailure:!0,timeoutMs:t})}async function X(e,t){let i=t.replace(/_/g," ").trim();if(!J(e))return i||e;let r=await d("adb",["-s",e,"emu","avd","name"],{allowFailure:!0,timeoutMs:V}),n=r.stdout.trim();return 0===r.exitCode&&n?n.replace(/_/g," "):i||e}async function Y(){if(!await m("adb"))throw new f("TOOL_MISSING","adb not found in PATH");let e=(await d("adb",["devices","-l"],{timeoutMs:V})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}));return await Promise.all(e.map(async({serial:e,rawModel:t})=>{let[i,r]=await Promise.all([X(e,t),K(e)]);return{platform:"android",id:e,name:i,kind:J(e)?"emulator":"device",booted:r}}))}async function K(e){try{let t=await H(e);return"1"===t.stdout.trim()}catch{return!1}}async function Z(e,t=6e4){let i,r=U.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await B(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new f("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),s=await H(e,Math.min(o,V));if(i=s,"1"!==s.stdout.trim())throw new f("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:n,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=W({error:e,stdout:i?.stdout,stderr:i?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:r,phase:"boot",classifyReason:e=>W({error:e,stdout:i?.stdout,stderr:i?.stderr,context:{platform:"android",phase:"boot"}})})}catch(u){let n=p(u),o=i?.stdout,s=i?.stderr,l=i?.exitCode,d=W({error:u,stdout:o,stderr:s,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===d&&"Android device is still booting"===n.message&&(d="ANDROID_BOOT_TIMEOUT");let c={serial:e,timeoutMs:t,elapsedMs:r.elapsedMs(),reason:d,hint:z(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new f("COMMAND_FAILED","Android device did not finish booting in time",c);if("TOOL_MISSING"===n.code)throw new f("TOOL_MISSING",n.message,{...c,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new f("COMMAND_FAILED",n.message,{...c,...n.details??{}});throw new f(n.code,n.message,{...c,...n.details??{}},n.cause)}}function Q(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let i=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!i)return!1;let r=i[1]?.toLowerCase(),n=i[2]??"";return"http"!==r&&"https"!==r&&"ws"!==r&&"wss"!==r&&"ftp"!==r&&"ftps"!==r||n.startsWith("//")}function ee(e,t){let i,r=e?.trim();return r?r:"http"===(i=t.trim().split(":")[0]?.toLowerCase())||"https"===i?"com.apple.mobilesafari":void 0}function et(e){let t=ei(e),i=e=>{let i=er(t,e);if(null!==i)return"true"===i};return{text:er(t,"text"),desc:er(t,"content-desc"),resourceId:er(t,"resource-id"),className:er(t,"class"),bounds:er(t,"bounds"),clickable:i("clickable"),enabled:i("enabled"),focusable:i("focusable"),focused:i("focused")}}function ei(e){let t=new Map,i=e.indexOf(" "),r=e.lastIndexOf(">");if(i<0||r<=i)return t;let n=/([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/y,a=i;for(;a<r;){for(;a<r;){let t=e[a];if(" "!==t&&"\n"!==t&&"\r"!==t&&" "!==t)break;a+=1}if(a>=r)break;let i=e[a];if("/"===i||">"===i)break;n.lastIndex=a;let o=n.exec(e);if(!o)break;t.set(o[1],o[3]),a=n.lastIndex}return t}function er(e,t){return e.get(t)??null}function en(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let i=Number(t[1]),r=Number(t[2]);return{x:i,y:r,width:Math.max(0,Number(t[3])-i),height:Math.max(0,Number(t[4])-r)}}function ea(e){return e?e.toLowerCase():""}function eo(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}let es=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function el(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new f("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function ed(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 f("INVALID_ARGS",`permission setting requires a target: ${es.join("|")}`)}let ec={settings:{type:"intent",value:"android.settings.SETTINGS"}};function eu(e,t){return["-s",e.id,...t]}async function ep(e,t){let i=t.trim();if(i.includes("."))return{type:"package",value:i};let r=ec[i.toLowerCase()];if(r)return r;let n=(await d("adb",eu(e,["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(i.toLowerCase()));if(1===n.length)return{type:"package",value:n[0]};if(n.length>1)throw new f("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new f("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function ef(e,t="all"){let i=await em(e);return("user-installed"===t?(await eh(e)).filter(e=>i.has(e)):Array.from(i)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:function(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),i=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),r=i[i.length-1]??e;for(let e=i.length-1;e>=0;e-=1){let n=i[e];if(!t.has(n)){r=n;break}}return r.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}(e)}))}async function em(e){let t=await d("adb",eu(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER"]),{allowFailure:!0});if(0!==t.exitCode||0===t.stdout.trim().length)return new Set;let i=new Set;for(let e of t.stdout.split("\n")){let t=e.trim();if(!t)continue;let r=t.split(/\s+/)[0],n=r.includes("/")?r.split("/")[0]:r;n&&i.add(n)}return i}async function eh(e){return(await d("adb",eu(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function ew(e){let t=await eg(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let i=await eg(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return i||{}}async function eg(e,t){for(let i of t){let t=function(e){for(let t of[/mCurrentFocus=Window\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mFocusedApp=AppWindowToken\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/,/ResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/]){let i=t.exec(e);if(i)return{package:i[1],activity:i[2]}}return null}((await d("adb",eu(e,i),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function ev(e,t,i){var r,n;let a;e.booted||await Z(e.id);let o=t.trim();if(Q(o)){if(i)throw new f("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await d("adb",eu(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await ep(e,t);if("intent"===s.type){if(i)throw new f("INVALID_ARGS","Activity override requires a package name, not an intent");await d("adb",eu(e,["shell","am","start","-W","-a",s.value]));return}if(i){let t=i.includes("/")?i:`${s.value}/${i.startsWith(".")?i:`.${i}`}`;await d("adb",eu(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-n",t]));return}let l=await d("adb",eu(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-p",s.value]),{allowFailure:!0});if(0===l.exitCode&&(r=l.stdout,n=l.stderr,a=`${r}
3
- ${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let c=await eI(e,s.value);if(!c)throw new f("COMMAND_FAILED",`Failed to launch ${s.value}`,{stdout:l.stdout,stderr:l.stderr});await d("adb",eu(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-n",c]))}async function eI(e,t){let i=await d("adb",eu(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER",t]),{allowFailure:!0});return 0!==i.exitCode?null:function(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let i=t[e];if(i.includes("/"))return i.split(/\s+/)[0]}return null}(i.stdout)}async function ey(e){e.booted||await Z(e.id)}async function eA(e,t){if("settings"===t.trim().toLowerCase())return void await d("adb",eu(e,["shell","am","force-stop","com.android.settings"]));let i=await ep(e,t);if("intent"===i.type)throw new f("INVALID_ARGS","Close requires a package name, not an intent");await d("adb",eu(e,["shell","am","force-stop",i.value]))}async function eS(e,t){let i=await ep(e,t);if("intent"===i.type)throw new f("INVALID_ARGS","reinstall requires a package name, not an intent");let r=await d("adb",eu(e,["uninstall",i.value]),{allowFailure:!0});if(0!==r.exitCode){let e=`${r.stdout}
4
- ${r.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new f("COMMAND_FAILED",`adb uninstall failed for ${i.value}`,{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}return{package:i.value}}async function eN(e,t){await d("adb",eu(e,["install",t]))}async function eb(e,t,i){e.booted||await Z(e.id);let{package:r}=await eS(e,t);return await eN(e,i),{package:r}}async function e_(e,t,i){await d("adb",eu(e,["shell","input","tap",String(t),String(i)]))}async function eD(e,t,i,r,n,a=250){await d("adb",eu(e,["shell","input","swipe",String(t),String(i),String(r),String(n),String(a)]))}async function ek(e){await d("adb",eu(e,["shell","input","keyevent","4"]))}async function eO(e){await d("adb",eu(e,["shell","input","keyevent","3"]))}async function eE(e){await d("adb",eu(e,["shell","input","keyevent","187"]))}async function eM(e,t,i,r=800){await d("adb",eu(e,["shell","input","swipe",String(t),String(i),String(t),String(i),String(r)]))}async function ex(e,t){if(!eY(t)||"ok"!==await eK(e,t))try{let i=t.replace(/ /g,"%s");await d("adb",eu(e,["shell","input","text",i]))}catch(e){if(eY(t)&&function(e){if(!(e instanceof f)||"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 f("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 eL(e,t,i){await e_(e,t,i)}async function eC(e,t,i,r){let n=Array.from(r).length;await eL(e,t,i);let a=null;for(let l of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:4,delayMs:0},{clearPadding:24,minClear:16,maxClear:96,chunkSize:1,delayMs:15}]){var o,s;let d=(o=n+l.clearPadding,s=l.minClear,Math.max(s,Math.min(l.maxClear,o)));if(await eZ(e,d),await eX(e,r,l.chunkSize,l.delayMs),(a=await eQ(e,t,i))===r)return}throw new f("COMMAND_FAILED","Android fill verification failed",{expected:r,actual:a??null})}async function eR(e,t,i=.6){let{width:r,height:n}=await eV(e),a=Math.floor(r*i),o=Math.floor(n*i),s=Math.floor(r/2),l=Math.floor(n/2),c=s,u=l,p=s,m=l;switch(t){case"up":u=l-Math.floor(o/2),m=l+Math.floor(o/2);break;case"down":u=l+Math.floor(o/2),m=l-Math.floor(o/2);break;case"left":c=s-Math.floor(a/2),p=s+Math.floor(a/2);break;case"right":c=s+Math.floor(a/2),p=s-Math.floor(a/2);break;default:throw new f("INVALID_ARGS",`Unknown direction: ${t}`)}await d("adb",eu(e,["shell","input","swipe",String(c),String(u),String(p),String(m),"300"]))}async function eT(e,t){for(let i=0;i<8;i+=1){let i="";try{i=await eU(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new f("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let i=t.toLowerCase(),r=/<node[^>]+>/g,n=r.exec(e);for(;n;){let t=ei(n[0]),a=(er(t,"text")??"").toLowerCase(),o=(er(t,"content-desc")??"").toLowerCase();if(a.includes(i)||o.includes(i)){let e=en(er(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=r.exec(e)}return null}(i,t))return;await eR(e,"down",.5)}throw new f("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function eP(e,t){let i=await d("adb",eu(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!i.stdoutBuffer)throw new f("COMMAND_FAILED","Failed to capture screenshot");await _.writeFile(t,i.stdoutBuffer)}async function e$(e,t,i,r,n){switch(t.toLowerCase()){case"wifi":{let t=eW(i);await d("adb",eu(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=eW(i);await d("adb",eu(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await d("adb",eu(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=eW(i);await d("adb",eu(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"permission":{if(!r)throw new f("INVALID_ARGS","permission setting requires an active app in session");let t=el(i),a=function(e,t){let i=ed(e);if(t?.trim())throw new f("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===i)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===i)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===i)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===i)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===i)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new f("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 eJ(e,r,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await ez(e,r,o);await d("adb",eu(e,["shell","pm",o,r,a.value]));return}default:throw new f("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function eF(e,t={}){return function(e,t,i){let r=function(e){let t={type:null,label:null,value:null,identifier:null,depth:-1,children:[]},i=[t],r=/<node\b[^>]*>|<\/node>/g,n=r.exec(e);for(;n;){let t=n[0];if(t.startsWith("</node")){i.length>1&&i.pop(),n=r.exec(e);continue}let a=et(t),o=en(a.bounds),s=i[i.length-1],l={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,rect:o,enabled:a.enabled,hittable:a.clickable??a.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||i.push(l),n=r.exec(e)}return t}(e),n=[],a=!1,o=i.depth??1/0,s=i.scope?function(e,t){let i=t.toLowerCase(),r=[...e.children];for(;r.length>0;){let e=r.shift(),t=e.label?.toLowerCase()??"",n=e.value?.toLowerCase()??"",a=e.identifier?.toLowerCase()??"";if(t.includes(i)||n.includes(i)||a.includes(i))return e;r.push(...e.children)}return null}(r,i.scope):null,l=s?[s]:r.children,d=new Map,c=e=>{let t=d.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||c(t))return d.set(e,!0),!0;return d.set(e,!1),!1},u=(e,t,r,s=!1,l=!1)=>{var d,p,f,m,h,w;let g,v,I,y,A,S,N,b;if(n.length>=800){a=!0;return}if(t>o)return;let _=!!i.raw||(d=e,p=i,f=s,m=c(e),h=l,v=ea(d.type),I=!!(d.label&&d.label.trim().length>0),y=!!(d.identifier&&d.identifier.trim().length>0),A=I&&!eo(d.label??""),S=y&&!eo(d.identifier??""),N=(g=(w=v).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,b="imageview"===v||"imagebutton"===v,p.interactiveOnly?!!d.hittable||!!(A||S)&&!b&&(!N||!!h)&&(f||m||h):p.compact?A||S||!!d.hittable:!N&&!b||!!d.hittable||!!A||!!S&&!!m||m),D=r;_&&(D=n.length,n.push({index:D,type:e.type??void 0,label:e.label??void 0,value:e.value??void 0,identifier:e.identifier??void 0,rect:e.rect,enabled:e.enabled,hittable:e.hittable,depth:t,parentIndex:r}));let k=s||!!e.hittable,O=l||function(e){if(!e)return!1;let t=ea(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let i of e.children)if(u(i,t+1,D,k,O),a)return};for(let e of l)if(u(e,0,void 0,!1,!1),a)break;return a?{nodes:n,truncated:a}:{nodes:n}}(await eU(e),0,t)}async function eG(){if(!await m("adb"))throw new f("TOOL_MISSING","adb not found in PATH")}async function eV(e){let t=(await d("adb",eu(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new f("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function eU(e){return q(()=>eB(e),{shouldRetry:ej})}async function eB(e){var t,i,r;let n,a,o=await d("adb",eu(e,["exec-out","uiautomator","dump","/dev/tty"]),{allowFailure:!0});if(0===o.exitCode){let e=eq(o.stdout,o.stderr);if(e)return e}let s="/sdcard/window_dump.xml",l=await d("adb",eu(e,["shell","uiautomator","dump",s])),c=(t=s,i=l.stdout,r=l.stderr,n=`${i}
5
- ${r}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await d("adb",eu(e,["shell","cat",c])),p=eq(u.stdout,u.stderr);if(!p)throw new f("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:u.stdout,stderr:u.stderr});return p}function eq(e,t){let i=`${e}
6
- ${t}`,r=i.indexOf("<?xml"),n=r>=0?r:i.indexOf("<hierarchy");if(n<0)return null;let a=i.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=i.slice(n,a+12).trim();return o.length>0?o:null}function ej(e){if(!(e instanceof f)||"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"))}function eW(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 f("INVALID_ARGS",`Invalid setting state: ${e}`)}async function ez(e,t,i){let r=await eH(e),n=[];for(let a of null!==r&&r>=33?["android.permission.READ_MEDIA_IMAGES","android.permission.READ_EXTERNAL_STORAGE"]:["android.permission.READ_EXTERNAL_STORAGE","android.permission.READ_MEDIA_IMAGES"]){let r=await d("adb",eu(e,["shell","pm",i,t,a]),{allowFailure:!0});if(0===r.exitCode)return;n.push({permission:a,stderr:r.stderr,exitCode:r.exitCode})}throw new f("COMMAND_FAILED",`Failed to ${i} Android photos permission`,{appPackage:t,sdkInt:r,attempts:n})}async function eJ(e,t,i,r){"grant"===i?await d("adb",eu(e,["shell","pm","grant",t,r.permission]),{allowFailure:!0}):(await d("adb",eu(e,["shell","pm","revoke",t,r.permission]),{allowFailure:!0}),"reset"===i&&(await d("adb",eu(e,["shell","pm","clear-permission-flags",t,r.permission,"user-set"]),{allowFailure:!0}),await d("adb",eu(e,["shell","pm","clear-permission-flags",t,r.permission,"user-fixed"]),{allowFailure:!0}))),await d("adb",eu(e,["shell","appops","set",t,r.appOps,"grant"===i?"allow":"deny"===i?"deny":"default"]))}async function eH(e){let t=await d("adb",eu(e,["shell","getprop","ro.build.version.sdk"]),{allowFailure:!0});if(0!==t.exitCode)return null;let i=Number.parseInt(t.stdout.trim(),10);return!Number.isFinite(i)||i<=0?null:i}async function eX(e,t,i,r){let n=Math.max(1,Math.floor(i)),a=Array.from(t);for(let t=0;t<a.length;t+=n){let i=a.slice(t,t+n).join("");await ex(e,i),r>0&&t+n<a.length&&await e1(r)}}function eY(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 eK(e,t){var i,r;let n,a=await d("adb",eu(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==a.exitCode?"failed":(i=a.stdout,r=a.stderr,(n=`${i}
7
- ${r}`.toLowerCase()).includes("no shell command implementation")||n.includes("unknown command"))?"unsupported":0===(await d("adb",eu(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await d("adb",eu(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}async function eZ(e,t){let i=Math.max(0,t);await d("adb",eu(e,["shell","input","keyevent","KEYCODE_MOVE_END"]),{allowFailure:!0});for(let t=0;t<i;t+=24){let r=Math.min(24,i-t);await d("adb",eu(e,["shell","input","keyevent",...Array(r).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function eQ(e,t,i){let r,n=await eU(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(r=a.exec(n));){let e=et(r[0]),n=en(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&"),c=e.focused??!1;if(!d)continue;let u=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&i>=n.y&&i<=n.y+n.height;if(c&&e0(a)){(!o||u<=o.area)&&(o={text:d,area:u});continue}if(p&&e0(a)){(!s||u<=s.area)&&(s={text:d,area:u});continue}p&&(!l||u<=l.area)&&(l={text:d,area:u})}return o?.text??s?.text??l?.text??null}function e0(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function e1(e){await new Promise(t=>setTimeout(t,e))}function e2(e,t,i){if(!e)return t;let r=Number(e);return Number.isFinite(r)?Math.max(i,Math.floor(r)):t}let e3=e2(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500);async function e4(){if("darwin"!==process.platform)throw new f("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await m("xcrun"))throw new f("TOOL_MISSING","xcrun not found in PATH");let e=[],t=await d("xcrun",["simctl","list","devices","-j"]);try{let i=JSON.parse(t.stdout);for(let t of Object.values(i.devices))for(let i of t)i.isAvailable&&e.push({platform:"ios",id:i.udid,name:i.name,kind:"simulator",booted:"Booted"===i.state})}catch(e){throw new f("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}let i=null;try{i=r.join(L.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let t=await d("xcrun",["devicectl","list","devices","--json-output",i],{allowFailure:!0,timeoutMs:e3});if(0!==t.exitCode)return e;let n=await _.readFile(i,"utf8"),a=JSON.parse(n);for(let t of a.result?.devices??[])if((t.hardwareProperties?.platform??"").toLowerCase().includes("ios")){let i=t.hardwareProperties?.udid??t.identifier??"",r=t.name??t.deviceProperties?.name??i;if(!i)continue;e.push({platform:"ios",id:i,name:r,kind:"device",booted:!0})}}catch{}finally{i&&await _.rm(i,{force:!0}).catch(()=>{})}return e}let e5=e2(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,G,5e3),e8=e2(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,F,1e3),e6=e2(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),e9=e2(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3);async function e7(e,t){let i=["devicectl",...e],r=await d("xcrun",i,{allowFailure:!0,timeoutMs:e9});if(0===r.exitCode)return;let n=String(r.stdout??""),a=String(r.stderr??"");throw new f("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:i,exitCode:r.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:ti(n,a)??tt})}async function te(e,t){let i=r.join(L.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),n=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",i],a=await d("xcrun",n,{allowFailure:!0,timeoutMs:e9});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),i=String(a.stderr??"");throw new f("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:n,exitCode:a.exitCode,stdout:t,stderr:i,deviceId:e.id,hint:ti(t,i)??tt})}let r=await _.readFile(i,"utf8");return o=function(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let i=[];for(let e of t){if(!e||"object"!=typeof e)continue;let t="string"==typeof e.bundleIdentifier?e.bundleIdentifier.trim():"";if(!t)continue;let r="string"==typeof e.name&&e.name.trim().length>0?e.name.trim():t;i.push({bundleId:t,name:r})}return i}(JSON.parse(r)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof f)throw t;throw new f("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await _.unlink(i).catch(()=>{})}}let tt="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function ti(e,t){let i=`${e}
8
- ${t}`.toLowerCase();return i.includes("device is busy")&&i.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":i.includes("coredeviceservice")&&i.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}async function tr(e){let t,i;if("simulator"!==e.kind||"Booted"===await tn(e.id))return;let r=U.fromTimeoutMs(e5);try{await B(async({deadline:r})=>{if(r?.isExpired())throw new f("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:e5});let n=Math.max(1e3,r?.remainingMs()??e5),a=await d("xcrun",["simctl","boot",e.id],{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
9
- ${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new f("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await d("xcrun",["simctl","bootstatus",e.id,"-b"],{allowFailure:!0,timeoutMs:n});if(i={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==i.exitCode)throw new f("COMMAND_FAILED","simctl bootstatus failed",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let c=await tn(e.id);if("Booted"!==c)throw new f("COMMAND_FAILED","Simulator is still booting",{state:c})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let r=W({error:e,stdout:i?.stdout??t?.stdout,stderr:i?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});return"IOS_BOOT_TIMEOUT"!==r&&"CI_RESOURCE_STARVATION_SUSPECTED"!==r}},{deadline:r,phase:"boot",classifyReason:e=>W({error:e,stdout:i?.stdout??t?.stdout,stderr:i?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=W({error:a,stdout:i?.stdout??t?.stdout,stderr:i?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new f("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:e5,elapsedMs:r.elapsedMs(),reason:n,hint:z(n),boot:t,bootstatus:i})}}async function tn(e){let t=await d("xcrun",["simctl","list","devices","-j"],{allowFailure:!0,timeoutMs:e8});if(0!==t.exitCode)return null;try{let i=JSON.parse(String(t.stdout??""));for(let t of Object.values(i.devices??{})){let i=t.find(t=>t.udid===e);if(i)return i.state}return null}catch{return null}}let ta={settings:"com.apple.Preferences"},to=null;function ts(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function tl(e,t){let i=t.trim();if(i.includes("."))return i;let r=ta[i.toLowerCase()];if(r)return r;let n=("simulator"===e.kind?await tv(e):await te(e,"all")).filter(e=>e.name.toLowerCase()===i.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new f("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new f("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function td(e,t,i){let r=i?.url?.trim();if(r){if(!Q(r))throw new f("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await tr(e),await d("open",["-a","Simulator"],{allowFailure:!0}),await d("xcrun",["simctl","openurl",e.id,r]);return}let n=ee(i?.appBundleId??await tl(e,t),r);if(!n)throw new f("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await tD(e,n,{payloadUrl:r});return}let n=t.trim();if(Q(n)){if("simulator"===e.kind){await tr(e),await d("open",["-a","Simulator"],{allowFailure:!0}),await d("xcrun",["simctl","openurl",e.id,n]);return}let t=ee(i?.appBundleId,n);if(!t)throw new f("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await tD(e,t,{payloadUrl:n});return}let a=i?.appBundleId??await tl(e,t);"simulator"===e.kind?await t_(e,a):await tD(e,a)}async function tc(e){"simulator"!==e.kind||"Booted"!==await tn(e.id)&&(await tr(e),await d("open",["-a","Simulator"],{allowFailure:!0}))}async function tu(e,t){let i=await tl(e,t);if("simulator"===e.kind){await tr(e);let t=await d("xcrun",["simctl","terminate",e.id,i],{allowFailure:!0});if(0!==t.exitCode){if(t.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new f("COMMAND_FAILED",`xcrun exited with code ${t.exitCode}`,{cmd:"xcrun",args:["simctl","terminate",e.id,i],stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode})}return}await e7(["device","process","terminate","--device",e.id,i],{action:"terminate iOS app",deviceId:e.id})}async function tp(e,t){let i=await tl(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,i],r=await d("xcrun",t,{allowFailure:!0,timeoutMs:e9});if(0!==r.exitCode){let n=String(r.stdout??""),a=String(r.stderr??"");if(!ts(`${n}
10
- ${a}`.toLowerCase()))throw new f("COMMAND_FAILED",`Failed to uninstall iOS app ${i}`,{cmd:"xcrun",args:t,exitCode:r.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:ti(n,a)??tt})}return{bundleId:i}}await tr(e);let r=await d("xcrun",["simctl","uninstall",e.id,i],{allowFailure:!0});if(0!==r.exitCode&&!ts(`${r.stdout}
11
- ${r.stderr}`.toLowerCase()))throw new f("COMMAND_FAILED",`simctl uninstall failed for ${i}`,{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});return{bundleId:i}}async function tf(e,t){"simulator"!==e.kind?await e7(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await tr(e),await d("xcrun",["simctl","install",e.id,t]))}async function tm(e,t,i){let{bundleId:r}=await tp(e,t);return await tf(e,i),{bundleId:r}}async function th(e,t){if("simulator"===e.kind){await tr(e),await d("xcrun",["simctl","io",e.id,"screenshot",t]);return}await e7(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id})}async function tw(e,t,i,r,n){if("simulator"!==e.kind)throw new f("UNSUPPORTED_OPERATION","settings is only supported on iOS simulators");switch(await tr(e),t.toLowerCase()){case"wifi":{let t=tI(i);await d("xcrun",["simctl","status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(tI(i)?await d("xcrun",["simctl","status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await d("xcrun",["simctl","status_bar",e.id,"clear"]));case"location":{let t=tI(i);if(!r)throw new f("INVALID_ARGS","location setting requires an active app in session");await d("xcrun",["simctl","privacy",e.id,t?"grant":"revoke","location",r]);return}case"faceid":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";if("enroll"===t)return"enroll";if("unenroll"===t)return"unenroll";throw new f("INVALID_ARGS",`Invalid faceid state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(i);await tN(e.id,t);return}case"permission":{var a;if(!r)throw new f("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(a=el(i))?"revoke":a,o=function(e,t){let i=ed(e);if("photos"!==i&&t?.trim())throw new f("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===i)return"camera";if("microphone"===i)return"microphone";if("contacts"===i)return"contacts";if("contacts-limited"===i)return"contacts-limited";if("notifications"===i)return"notifications";if("calendar"===i)return"calendar";if("location"===i)return"location";if("location-always"===i)return"location-always";if("media-library"===i)return"media-library";if("motion"===i)return"motion";if("reminders"===i)return"reminders";if("siri"===i)return"siri";if("photos"===i){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new f("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new f("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 ty(e.id,t,o,r);return}default:throw new f("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function tg(e,t="all"){var i;return"simulator"===e.kind?(i=await tv(e),"user-installed"===t?i.filter(e=>!e.bundleId.startsWith("com.apple.")):i):await te(e,t)}async function tv(e){let t=(await d("xcrun",["simctl","listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let i=null;if(t.startsWith("{"))try{i=JSON.parse(t)}catch{i=null}if(!i&&t.startsWith("{"))try{let e=await d("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(i=JSON.parse(e.stdout))}catch{i=null}return i?Object.entries(i).map(([e,t])=>({bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e})):[]}function tI(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 f("INVALID_ARGS",`Invalid setting state: ${e}`)}async function ty(e,t,i,r){let n=await tS();if(!n.has(i))throw new f("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${i}" on this runtime.`,{deviceId:e,appBundleId:r,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["simctl","privacy",e,t,i,r],o="notifications"===i;if(!("reset"===t&&o))try{await d("xcrun",a);return}catch(t){if(!(o&&tA(t)))throw t;throw new f("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e,appBundleId:r,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await d("xcrun",a);return}catch(e){if(!tA(e))throw e}try{await d("xcrun",["simctl","privacy",e,"reset","all",r])}catch(t){throw new f("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e,appBundleId:r,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function tA(e){if(!(e instanceof f)||"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 tS(){let t=process.env.PATH;if(to&&e===t)return to;let i=await d("xcrun",["simctl","privacy","help"],{allowFailure:!0}),r=function(e){let t=new Set,i=!1;for(let r of e.split("\n")){let e=r.trim();if(!e)continue;if("service"===e){i=!0;continue}if(!i)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${i.stdout}
12
- ${i.stderr}`);if(0===r.size)throw new f("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return to=r,e=t,r}async function tN(e,t){let i=function(e,t){switch(t){case"match":return[["simctl","biometric",e,"match","face"],["simctl","biometric","match",e,"face"]];case"nonmatch":return[["simctl","biometric",e,"nonmatch","face"],["simctl","biometric",e,"nomatch","face"],["simctl","biometric","nonmatch",e,"face"],["simctl","biometric","nomatch",e,"face"]];case"enroll":return[["simctl","biometric",e,"enroll","yes"],["simctl","biometric",e,"enroll","1"],["simctl","biometric","enroll",e,"yes"],["simctl","biometric","enroll",e,"1"]];case"unenroll":return[["simctl","biometric",e,"enroll","no"],["simctl","biometric",e,"enroll","0"],["simctl","biometric","enroll",e,"no"],["simctl","biometric","enroll",e,"0"]]}}(e,t),r=[];for(let e of i){let t=await d("xcrun",e,{allowFailure:!0});if(0===t.exitCode)return;r.push({args:e,stderr:t.stderr,stdout:t.stdout,exitCode:t.exitCode})}throw new f("COMMAND_FAILED","simctl biometric command failed. Ensure your Xcode Simulator runtime supports Face ID control.",{deviceId:e,action:t,attempts:r.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}))})}function tb(e){if(!(e instanceof f)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let i=String(t.stderr??"").toLowerCase();return i.includes("fbsopenapplicationserviceerrordomain")&&i.includes("the request to open")}async function t_(e,t){await tr(e),await d("open",["-a","Simulator"],{allowFailure:!0});let i=U.fromTimeoutMs(e6);await B(async({deadline:i})=>{if(i?.isExpired())throw new f("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:e6});let r=await d("xcrun",["simctl","launch",e.id,t],{allowFailure:!0});if(0!==r.exitCode)throw new f("COMMAND_FAILED",`xcrun exited with code ${r.exitCode}`,{cmd:"xcrun",args:["simctl","launch",e.id,t],stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:tb},{deadline:i})}async function tD(e,t,i){let r=["device","process","launch","--device",e.id,t];i?.payloadUrl&&r.push("--payload-url",i.payloadUrl),await e7(r,{action:"launch iOS app",deviceId:e.id})}async function tk(e,t,i){let r=(e.get(t)??Promise.resolve()).catch(()=>{}).then(i);return e.set(t,r),r.finally(()=>{e.get(t)===r&&e.delete(t)})}let tO=new Set;function tE(e){return!!e&&tO.has(e)}let tM=new Map,tx=new Map,tL=new Set,tC=e2(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),tR=e2(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),tT=e2(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),tP=e2(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),t$=e2(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),tF=e2(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),tG=e2(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),tV=e2(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5),tU=r.join(L.homedir(),".agent-device","ios-runner");async function tB(e,t,i={}){var r;return(function(e){if("ios"!==e.platform)throw new f("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new f("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`)}(e),t5(i.requestId),"snapshot"===(r=t.command)||"findText"===r||"alert"===r)?q(()=>(t5(i.requestId),tq(e,t,i)),{shouldRetry:e=>(t5(i.requestId),function(e){if(!(e instanceof f)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!(t.includes("xcodebuild exited early")||t.includes("device is busy")&&t.includes("connecting"))&&!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}(e))}):tq(e,t,i)}async function tq(e,t,i={}){let r;t5(i.requestId);try{let n=(r=await tZ(e,i)).ready?tR:tC;return await tj(e,r,t,i.logPath,n)}catch(a){let n=a instanceof f?a:new f("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===n.code&&"string"==typeof n.message&&n.message.includes("Runner did not accept connection")&&t6(n)&&r?.ready){t5(i.requestId),r?await tX(r):await tz(e.id),r=await tZ(e,i);let n=await t7(r.device,r.port,t,i.logPath,tC);return await tW(n,r,i.logPath)}throw a}}async function tj(e,t,i,r,n){let a=await t7(e,t.port,i,r,n,t);return await tW(a,t,r)}async function tW(e,t,i){let r=await e.text(),n={};try{n=JSON.parse(r)}catch{throw new f("COMMAND_FAILED","Invalid runner response",{text:r})}if(!n.ok)throw new f("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:i});return t.ready=!0,n.data??{}}async function tz(e){await tk(tx,e,async()=>{await tY(e)})}async function tJ(){let e=Array.from(tM.values()),t=Array.from(tL);await Promise.allSettled(e.map(async e=>{await tQ(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await tQ(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await tQ(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await tQ(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await tQ(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await tQ(e.pid,"SIGKILL"),tL.delete(e)}))}async function tH(){await tJ();let e=Array.from(tM.keys());await Promise.allSettled(e.map(async e=>{await tz(e)})),await t1()}async function tX(e){await tk(tx,e.deviceId,async()=>{await tY(e.deviceId,e)})}async function tY(e,t){let i=t??tM.get(e);if(i){try{await t7(i.device,i.port,{command:"shutdown"},void 0,15e3)}catch{await tQ(i.child.pid,"SIGTERM")}try{await Promise.race([i.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await tQ(i.child.pid,"SIGKILL"),is(i.xctestrunPath),is(i.jsonPath),tM.get(e)===i&&tM.delete(e)}}async function tK(e){await d("xcrun",["simctl","bootstatus",e,"-b"],{allowFailure:!0,timeoutMs:tC})}async function tZ(e,t){return await tk(tx,e.id,async()=>{var i,r;let n=tM.get(e.id);if(n){if((i=n.child.pid)&&k(i))return n;await tY(e.id,n)}await ("simulator"!==(r=e).kind?Promise.resolve():tK(r.id));let a=await t0(e,t),o=await ia(),{xctestrunPath:l,jsonPath:d}=await io(a,{AGENT_DEVICE_RUNNER_PORT:String(o)},`session-${e.id}-${o}`),{child:c,wait:u}=s("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-collect-test-diagnostics","never",t2(e),"1","-destination-timeout",String(tV),"-xctestrun",l,"-destination",function(e){if("ios"!==e.platform)throw new f("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"simulator"===e.kind?`platform=iOS Simulator,id=${e.id}`:`platform=iOS,id=${e.id}`}(e)],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(o)},detached:!0});c.stdout?.on("data",e=>{t4(e,t.logPath,t.traceLogPath,t.verbose)}),c.stderr?.on("data",e=>{t4(e,t.logPath,t.traceLogPath,t.verbose)});let p={device:e,deviceId:e.id,port:o,xctestrunPath:l,jsonPath:d,testPromise:u,child:c,ready:!1};return tM.set(e.id,p),p})}async function tQ(e,t){if(!e||e<=0)return;try{process.kill(-e,t)}catch{}try{process.kill(e,t)}catch{}let i="SIGINT"===t?"INT":"SIGTERM"===t?"TERM":"KILL";try{await d("pkill",[`-${i}`,"-P",String(e)],{allowFailure:!0})}catch{}}async function t0(e,t){var i,n;let a,o=(i=e.kind,(a=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?r.resolve(a):"simulator"===i?r.join(tU,"derived"):r.join(tU,"derived",i));if($(process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)){!function(e,t=process.env){if(t.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim()&&!function(e=process.env){return $(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new f("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(o);try{E.rmSync(o,{recursive:!0,force:!0})}catch{}}let s=t3(o);if(s)return s;let l=function(){let e=r.dirname(w(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=r.join(t,"package.json");if(E.existsSync(e))return t;t=r.dirname(t)}return e}(),d=r.join(l,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!E.existsSync(d))throw new f("COMMAND_FAILED","iOS runner project not found",{projectPath:d});let c=function(e=process.env,t=!1){if(!t)return[];let i=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||"",r=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||"",n=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||"",a=["CODE_SIGN_STYLE=Automatic"];return i&&a.push(`DEVELOPMENT_TEAM=${i}`),r&&a.push(`CODE_SIGN_IDENTITY=${r}`),n&&a.push(`PROVISIONING_PROFILE_SPECIFIER=${n}`),a}(process.env,"device"===e.kind),u="device"===e.kind?["-allowProvisioningUpdates"]:[];try{await g("xcodebuild",["build-for-testing","-project",d,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",t2(e),"1","-destination",function(e){if("ios"!==e.platform)throw new f("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"simulator"===e.kind?`platform=iOS Simulator,id=${e.id}`:"generic/platform=iOS"}(e),"-derivedDataPath",o,...u,...c],{detached:!0,onSpawn:e=>{tL.add(e),e.on("close",()=>{tL.delete(e)})},onStdoutChunk:e=>{t4(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{t4(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(o){let e,i,r=o instanceof f?o:new f("COMMAND_FAILED",String(o)),a=(e=(n=r).details?JSON.stringify(n.details):"",(i=`${n.message}
13
- ${e}`.toLowerCase()).includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":i.includes("no profiles for")||i.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":i.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new f("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:r.message,details:r.details,logPath:t.logPath,hint:a})}let p=t3(o);if(!p)throw new f("COMMAND_FAILED","Failed to locate .xctestrun after build");return p}async function t1(){let e=Array.from(tL);await Promise.allSettled(e.map(async e=>{try{await tQ(e.pid,"SIGTERM"),await tQ(e.pid,"SIGKILL")}finally{tL.delete(e)}}))}function t2(e){return"device"===e.kind?"-maximum-concurrent-test-device-destinations":"-maximum-concurrent-test-simulator-destinations"}function t3(e){if(!E.existsSync(e))return null;let t=[],i=[e];for(;i.length>0;){let e=i.pop();for(let n of E.readdirSync(e,{withFileTypes:!0})){let a=r.join(e,n.name);if(n.isDirectory()){i.push(a);continue}if(n.isFile()&&n.name.endsWith(".xctestrun"))try{let e=E.statSync(a);t.push({path:a,mtimeMs:e.mtimeMs})}catch{}}}return 0===t.length?null:(t.sort((e,t)=>t.mtimeMs-e.mtimeMs),t[0]?.path??null)}function t4(e,t,i,r){t&&E.appendFileSync(t,e),i&&E.appendFileSync(i,e),r&&process.stderr.write(e)}function t5(e){if(tE(e))throw new f("COMMAND_FAILED","request canceled")}function t8(e){let{port:t,endpoints:i,logPath:r,lastError:n}=e,a="Runner did not accept connection";return new f("COMMAND_FAILED",a,{port:t,endpoints:i,logPath:r,lastError:n?String(n):void 0,reason:W({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:z("IOS_RUNNER_CONNECT_TIMEOUT")})}function t6(e){return!(e instanceof f)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}async function t9(e){var t,i;let r,{session:n,port:a,logPath:o}=e,s=await n.testPromise,l="Runner did not accept connection (xcodebuild exited early)",d=W({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new f("COMMAND_FAILED",l,{port:a,logPath:o,xcodebuild:{exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr},reason:d,hint:(t=s.stdout,i=s.stderr,(r=`${l}
1
+ let e;import{isCancel as t,select as r}from"@clack/prompts";import{node_path as i,readProcessCommand as n,validateAndNormalizeBatchSteps as a,isAgentDeviceDaemonProcess as o,runCmdBackground as s,SETTINGS_INVALID_ARGS_MESSAGE as l,node_crypto as d,runCmd as c,displayLabel as u,spawn as p,asAppError as f,AppError as m,whichCmd as h,buildSnapshotDisplayLines as w,fileURLToPath as g,runCmdStreaming as v,formatRole as I,normalizeError as y,readVersion as A,findProjectRoot as S,getDiagnosticsMeta as b,withDiagnosticTimer as N,emitDiagnostic as D,promises as _,DEFAULT_BATCH_MAX_STEPS as k,isProcessAlive as x,readProcessStartTime as O,node_fs as E,withDiagnosticsScope as M,flushDiagnosticsToSessionFile as L,node_os as C,node_net as R,formatSnapshotLine as T}from"./735.js";function P(e){return"apple"===e?"ios":e}async function $(e,i){let n=e,a=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(i.platform&&(n=n.filter(e=>e.platform===i.platform)),i.target&&(n=n.filter(e=>(e.target??"mobile")===i.target)),i.udid){let e=n.find(e=>e.id===i.udid&&"ios"===e.platform);if(!e)throw new m("DEVICE_NOT_FOUND",`No iOS device with UDID ${i.udid}`);return e}if(i.serial){let e=n.find(e=>e.id===i.serial&&"android"===e.platform);if(!e)throw new m("DEVICE_NOT_FOUND",`No Android device with serial ${i.serial}`);return e}if(i.deviceName){let e=a(i.deviceName),t=n.find(t=>a(t.name)===e);if(!t)throw new m("DEVICE_NOT_FOUND",`No device named ${i.deviceName}`);return t}if(1===n.length)return n[0];if(0===n.length)throw new m("DEVICE_NOT_FOUND","No devices found",{selector:i});let o=n.filter(e=>e.booted);if(1===o.length)return o[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await r({message:"Multiple devices available. Choose a device to continue:",options:(o.length>0?o:n).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(t(e))throw new m("INVALID_ARGS","Device selection cancelled");if(e){let t=n.find(t=>t.id===e);if(t)return t}}return o[0]??n[0]}let F=G(process.env.AGENT_DEVICE_RETRY_LOGS);function G(e){return["1","true","yes","on"].includes((e??"").toLowerCase())}let V=2e4,U=12e4,B=1e4;class j{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new j(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function q(e,t={},r={}){let i,n={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=n.maxAttempts&&(!r.deadline?.isExpired()||!(t>1));t+=1)try{let i=await e({attempt:t,maxAttempts:n.maxAttempts,deadline:r.deadline});return r.onEvent?.({phase:r.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs()}),J({phase:r.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs()}),i}catch(d){i=d;let e=r.classifyReason?.(d),a={phase:r.phase,event:"attempt_failed",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:e};if(r.onEvent?.(a),J(a),t>=n.maxAttempts||n.shouldRetry&&!n.shouldRetry(d,t))break;let o=function(e,t,r,i){let n=Math.min(t,e*2**(i-1));return Math.max(0,n+n*r*(2*Math.random()-1))}(n.baseDelayMs,n.maxDelayMs,n.jitter,t),s=r.deadline?Math.min(o,r.deadline.remainingMs()):o;if(s<=0)break;let l={phase:r.phase,event:"retry_scheduled",attempt:t,maxAttempts:n.maxAttempts,delayMs:s,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:e};r.onEvent?.(l),J(l),await function(e){return new Promise(t=>setTimeout(t,e))}(s)}let a={phase:r.phase,event:"exhausted",attempt:n.maxAttempts,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:r.classifyReason?.(i)};if(r.onEvent?.(a),J(a),i)throw i;throw new m("COMMAND_FAILED","retry failed")}async function W(e,t={}){return q(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function J(e){D({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}}),F&&process.stderr.write(`[agent-device][retry] ${JSON.stringify(e)}
2
+ `)}function z(e){let t=e.error?f(e.error):null,r=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===r?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let n=t?.details??{},a="string"==typeof n.message?n.message:void 0,o="string"==typeof n.stdout?n.stdout:void 0,s="string"==typeof n.stderr?n.stderr:void 0,l=n.boot&&"object"==typeof n.boot?n.boot:null,d=n.bootstatus&&"object"==typeof n.bootstatus?n.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,a,o,s,"string"==typeof l?.stdout?l.stdout:void 0,"string"==typeof l?.stderr?l.stderr:void 0,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===r&&(c.includes("runner did not accept connection")||"connect"===i&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===r&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===r&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===r&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function H(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI consider increasing AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS.";case"IOS_RUNNER_CONNECT_TIMEOUT":return"Retry runner startup, inspect xcodebuild logs, and verify simulator responsiveness before command execution.";case"ANDROID_BOOT_TIMEOUT":return"Retry emulator startup and verify sys.boot_completed reaches 1; consider increasing startup budget in CI.";case"ADB_TRANSPORT_UNAVAILABLE":return"Check adb server/device transport (adb devices -l), restart adb, and ensure the target device is online and authorized.";case"CI_RESOURCE_STARVATION_SUSPECTED":return"CI machine may be resource constrained; reduce parallel jobs or use a larger runner.";case"IOS_TOOL_MISSING":return"Xcode command-line tools are missing or not in PATH; run xcode-select --install and verify xcrun works.";case"BOOT_COMMAND_FAILED":return"Inspect command stderr/stdout for the failing boot phase and retry after environment validation.";default:return"Retry once and inspect verbose logs for the failing phase."}}let X=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];function Y(e){return`${e.stdout}
3
+ ${e.stderr}`}function K(e,t){return["-s",e,...t]}function Z(e){return e.startsWith("emulator-")}async function Q(e,t=B){return c("adb",K(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function ee(e,t){let r=t.replace(/_/g," ").trim();if(!Z(e))return r||e;let i=await c("adb",K(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:B}),n=i.stdout.trim();return 0===i.exitCode&&n?n.replace(/_/g," "):r||e}async function et(e,t){let r=Y(await c("adb",K(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:B})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function er(e){return(await Promise.all(X.map(async t=>await et(e,t)))).some(e=>!0===e)}async function ei(e){var t;let r;return"tv"===((r=Y(await c("adb",K(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:B})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await er(e)?"tv":(t=Y(await c("adb",K(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:B})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function en(){if(!await h("adb"))throw new m("TOOL_MISSING","adb not found in PATH");let e=(await c("adb",["devices","-l"],{timeoutMs:B})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}));return await Promise.all(e.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([ee(e,t),ea(e),ei(e)]);return{platform:"android",id:e,name:r,kind:Z(e)?"emulator":"device",target:n,booted:i}}))}async function ea(e){try{let t=await Q(e);return"1"===t.stdout.trim()}catch{return!1}}async function eo(e,t=6e4){let r,i=j.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await q(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new m("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),s=await Q(e,Math.min(o,B));if(r=s,"1"!==s.stdout.trim())throw new m("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:n,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=z({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:i,phase:"boot",classifyReason:e=>z({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(u){let n=f(u),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=z({error:u,stdout:o,stderr:s,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===d&&"Android device is still booting"===n.message&&(d="ANDROID_BOOT_TIMEOUT");let c={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:H(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new m("COMMAND_FAILED","Android device did not finish booting in time",c);if("TOOL_MISSING"===n.code)throw new m("TOOL_MISSING",n.message,{...c,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new m("COMMAND_FAILED",n.message,{...c,...n.details??{}});throw new m(n.code,n.message,{...c,...n.details??{}},n.cause)}}function es(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let r=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!r)return!1;let i=r[1]?.toLowerCase(),n=r[2]??"";return"http"!==i&&"https"!==i&&"ws"!==i&&"wss"!==i&&"ftp"!==i&&"ftps"!==i||n.startsWith("//")}function el(e,t){let r,i=e?.trim();return i?i:"http"===(r=t.trim().split(":")[0]?.toLowerCase())||"https"===r?"com.apple.mobilesafari":void 0}function ed(e){let t=ec(e),r=e=>{let r=eu(t,e);if(null!==r)return"true"===r};return{text:eu(t,"text"),desc:eu(t,"content-desc"),resourceId:eu(t,"resource-id"),className:eu(t,"class"),bounds:eu(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused")}}function ec(e){let t=new Map,r=e.indexOf(" "),i=e.lastIndexOf(">");if(r<0||i<=r)return t;let n=/([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/y,a=r;for(;a<i;){for(;a<i;){let t=e[a];if(" "!==t&&"\n"!==t&&"\r"!==t&&" "!==t)break;a+=1}if(a>=i)break;let r=e[a];if("/"===r||">"===r)break;n.lastIndex=a;let o=n.exec(e);if(!o)break;t.set(o[1],o[3]),a=n.lastIndex}return t}function eu(e,t){return e.get(t)??null}function ep(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let r=Number(t[1]),i=Number(t[2]);return{x:r,y:i,width:Math.max(0,Number(t[3])-r),height:Math.max(0,Number(t[4])-i)}}function ef(e){return e?e.toLowerCase():""}function em(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}let eh=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function ew(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new m("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function eg(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 m("INVALID_ARGS",`permission setting requires a target: ${eh.join("|")}`)}function ev(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new m("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}let eI={settings:{type:"intent",value:"android.settings.SETTINGS"}},ey="android.intent.category.LAUNCHER",eA="android.intent.category.LEANBACK_LAUNCHER",eS="android.intent.category.DEFAULT";function eb(e,t){return["-s",e.id,...t]}async function eN(e,t){let r=t.trim();if(r.includes("."))return{type:"package",value:r};let i=eI[r.toLowerCase()];if(i)return i;let n=(await c("adb",eb(e,["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(r.toLowerCase()));if(1===n.length)return{type:"package",value:n[0]};if(n.length>1)throw new m("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new m("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function eD(e,t="all"){let r=await e_(e);return("user-installed"===t?(await ex(e)).filter(e=>r.has(e)):Array.from(r)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:function(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),r=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),i=r[r.length-1]??e;for(let e=r.length-1;e>=0;e-=1){let n=r[e];if(!t.has(n)){i=n;break}}return i.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}(e)}))}async function e_(e){let t=new Set;for(let r of ek(e,{includeFallbackWhenUnknown:!0})){let i=await c("adb",eb(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",r]),{allowFailure:!0});if(0===i.exitCode&&0!==i.stdout.trim().length)for(let e of i.stdout.split("\n")){let r=e.trim();if(!r)continue;let i=r.split(/\s+/)[0],n=i.includes("/")?i.split("/")[0]:i;n&&t.add(n)}}return t}function ek(e,t={}){return"tv"===e.target?[eA]:"mobile"===e.target?[ey]:t.includeFallbackWhenUnknown?[ey,eA]:[ey]}async function ex(e){return(await c("adb",eb(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function eO(e){let t=await eE(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let r=await eE(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return r||{}}async function eE(e,t){for(let r of t){let t=function(e){for(let t of[/mCurrentFocus=Window\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mFocusedApp=AppWindowToken\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/,/ResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/]){let r=t.exec(e);if(r)return{package:r[1],activity:r[2]}}return null}((await c("adb",eb(e,r),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function eM(e,t,r){var i,n;let a;e.booted||await eo(e.id);let o=t.trim();if(es(o)){if(r)throw new m("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await c("adb",eb(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await eN(e,t),l=ek(e)[0]??ey;if("intent"===s.type){if(r)throw new m("INVALID_ARGS","Activity override requires a package name, not an intent");await c("adb",eb(e,["shell","am","start","-W","-a",s.value]));return}if(r){let t=r.includes("/")?r:`${s.value}/${r.startsWith(".")?r:`.${r}`}`;await c("adb",eb(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eS,"-c",l,"-n",t]));return}let d=await c("adb",eb(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eS,"-c",l,"-p",s.value]),{allowFailure:!0});if(0===d.exitCode&&(i=d.stdout,n=d.stderr,a=`${i}
4
+ ${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let u=await eL(e,s.value);if(!u)throw new m("COMMAND_FAILED",`Failed to launch ${s.value}`,{stdout:d.stdout,stderr:d.stderr});await c("adb",eb(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eS,"-c",l,"-n",u]))}async function eL(e,t){for(let r of Array.from(new Set(ek(e,{includeFallbackWhenUnknown:!0})))){let i=await c("adb",eb(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",r,t]),{allowFailure:!0});if(0!==i.exitCode)continue;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let r=t[e];if(r.includes("/"))return r.split(/\s+/)[0]}return null}(i.stdout);if(n)return n}return null}async function eC(e){e.booted||await eo(e.id)}async function eR(e,t){if("settings"===t.trim().toLowerCase())return void await c("adb",eb(e,["shell","am","force-stop","com.android.settings"]));let r=await eN(e,t);if("intent"===r.type)throw new m("INVALID_ARGS","Close requires a package name, not an intent");await c("adb",eb(e,["shell","am","force-stop",r.value]))}async function eT(e,t){let r=await eN(e,t);if("intent"===r.type)throw new m("INVALID_ARGS","reinstall requires a package name, not an intent");let i=await c("adb",eb(e,["uninstall",r.value]),{allowFailure:!0});if(0!==i.exitCode){let e=`${i.stdout}
5
+ ${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new m("COMMAND_FAILED",`adb uninstall failed for ${r.value}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return{package:r.value}}async function eP(e,t){await c("adb",eb(e,["install",t]))}async function e$(e,t,r){e.booted||await eo(e.id);let{package:i}=await eT(e,t);return await eP(e,r),{package:i}}async function eF(e,t,r){await c("adb",eb(e,["shell","input","tap",String(t),String(r)]))}async function eG(e,t,r,i,n,a=250){await c("adb",eb(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function eV(e){await c("adb",eb(e,["shell","input","keyevent","4"]))}async function eU(e){await c("adb",eb(e,["shell","input","keyevent","3"]))}async function eB(e){await c("adb",eb(e,["shell","input","keyevent","187"]))}async function ej(e,t,r,i=800){await c("adb",eb(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function eq(e,t){if(!ti(t)||"ok"!==await tn(e,t))try{let r=t.replace(/ /g,"%s");await c("adb",eb(e,["shell","input","text",r]))}catch(e){if(ti(t)&&function(e){if(!(e instanceof m)||"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 m("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 eW(e){let t,r;return(r=(t=(await to(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 eJ(e,t){await to(e,["shell","cmd","clipboard","set","text",t],"write")}async function ez(e,t,r){await eF(e,t,r)}async function eH(e,t,r,i){let n=Array.from(i).length;await ez(e,t,r);let a=null;for(let l of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:4,delayMs:0},{clearPadding:24,minClear:16,maxClear:96,chunkSize:1,delayMs:15}]){var o,s;let d=(o=n+l.clearPadding,s=l.minClear,Math.max(s,Math.min(l.maxClear,o)));if(await ts(e,d),await tr(e,i,l.chunkSize,l.delayMs),(a=await tl(e,t,r))===i)return}throw new m("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:a??null})}async function eX(e,t,r=.6){let{width:i,height:n}=await e2(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,p=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),p=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),p=s-Math.floor(a/2);break;default:throw new m("INVALID_ARGS",`Unknown direction: ${t}`)}await c("adb",eb(e,["shell","input","swipe",String(d),String(u),String(p),String(f),"300"]))}async function eY(e,t){for(let r=0;r<8;r+=1){let r="";try{r=await e3(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new m("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=ec(n[0]),a=(eu(t,"text")??"").toLowerCase(),o=(eu(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=ep(eu(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 eX(e,"down",.5)}throw new m("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function eK(e,t){let r=await c("adb",eb(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!r.stdoutBuffer)throw new m("COMMAND_FAILED","Failed to capture screenshot");await _.writeFile(t,r.stdoutBuffer)}async function eZ(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=e6(r);await c("adb",eb(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=e6(r);await c("adb",eb(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await c("adb",eb(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=e6(r);await c("adb",eb(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await e9(e,r);await c("adb",eb(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"permission":{if(!i)throw new m("INVALID_ARGS","permission setting requires an active app in session");let t=ew(r),a=function(e,t){let r=eg(e);if(t?.trim())throw new m("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 m("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 te(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await e7(e,i,o);await c("adb",eb(e,["shell","pm",o,i,a.value]));return}default:throw new m("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function eQ(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 m("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 m("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(n,e,t),s+=1);return await c("adb",eb(e,n)),{action:i,extrasCount:s}}async function e0(e,t={}){return function(e,t,r){let i=function(e){let t={type:null,label:null,value:null,identifier:null,depth:-1,children:[]},r=[t],i=/<node\b[^>]*>|<\/node>/g,n=i.exec(e);for(;n;){let t=n[0];if(t.startsWith("</node")){r.length>1&&r.pop(),n=i.exec(e);continue}let a=ed(t),o=ep(a.bounds),s=r[r.length-1],l={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,rect:o,enabled:a.enabled,hittable:a.clickable??a.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||r.push(l),n=i.exec(e)}return t}(e),n=[],a=!1,o=r.depth??1/0,s=r.scope?function(e,t){let r=t.toLowerCase(),i=[...e.children];for(;i.length>0;){let e=i.shift(),t=e.label?.toLowerCase()??"",n=e.value?.toLowerCase()??"",a=e.identifier?.toLowerCase()??"";if(t.includes(r)||n.includes(r)||a.includes(r))return e;i.push(...e.children)}return null}(i,r.scope):null,l=s?[s]:i.children,d=new Map,c=e=>{let t=d.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||c(t))return d.set(e,!0),!0;return d.set(e,!1),!1},u=(e,t,i,s=!1,l=!1)=>{var d,p,f,m,h,w;let g,v,I,y,A,S,b,N;if(n.length>=800){a=!0;return}if(t>o)return;let D=!!r.raw||(d=e,p=r,f=s,m=c(e),h=l,v=ef(d.type),I=!!(d.label&&d.label.trim().length>0),y=!!(d.identifier&&d.identifier.trim().length>0),A=I&&!em(d.label??""),S=y&&!em(d.identifier??""),b=(g=(w=v).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,N="imageview"===v||"imagebutton"===v,p.interactiveOnly?!!d.hittable||!!(A||S)&&!N&&(!b||!!h)&&(f||m||h):p.compact?A||S||!!d.hittable:!b&&!N||!!d.hittable||!!A||!!S&&!!m||m),_=i;D&&(_=n.length,n.push({index:_,type:e.type??void 0,label:e.label??void 0,value:e.value??void 0,identifier:e.identifier??void 0,rect:e.rect,enabled:e.enabled,hittable:e.hittable,depth:t,parentIndex:i}));let k=s||!!e.hittable,x=l||function(e){if(!e)return!1;let t=ef(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let r of e.children)if(u(r,t+1,_,k,x),a)return};for(let e of l)if(u(e,0,void 0,!1,!1),a)break;return a?{nodes:n,truncated:a}:{nodes:n}}(await e3(e),0,t)}async function e1(){if(!await h("adb"))throw new m("TOOL_MISSING","adb not found in PATH")}async function e2(e){let t=(await c("adb",eb(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new m("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function e3(e){return W(()=>e4(e),{shouldRetry:e8})}async function e4(e){var t,r,i;let n,a,o=await c("adb",eb(e,["exec-out","uiautomator","dump","/dev/tty"]),{allowFailure:!0});if(0===o.exitCode){let e=e5(o.stdout,o.stderr);if(e)return e}let s="/sdcard/window_dump.xml",l=await c("adb",eb(e,["shell","uiautomator","dump",s])),d=(t=s,r=l.stdout,i=l.stderr,n=`${r}
6
+ ${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await c("adb",eb(e,["shell","cat",d])),p=e5(u.stdout,u.stderr);if(!p)throw new m("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:u.stdout,stderr:u.stderr});return p}function e5(e,t){let r=`${e}
7
+ ${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 e8(e){if(!(e instanceof m)||"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"))}function e6(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 m("INVALID_ARGS",`Invalid setting state: ${e}`)}async function e9(e,t){let r=ev(t);if("toggle"!==r)return r;let i=await c("adb",eb(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new m("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}
8
+ ${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 m("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 e7(e,t,r){let i=await tt(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 c("adb",eb(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 m("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function te(e,t,r,i){"grant"===r?await c("adb",eb(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await c("adb",eb(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await c("adb",eb(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await c("adb",eb(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await c("adb",eb(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function tt(e){let t=await c("adb",eb(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 tr(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 eq(e,r),i>0&&t+n<a.length&&await tc(i)}}function ti(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 tn(e,t){let r=await c("adb",eb(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":ta(r.stdout,r.stderr)?"unsupported":0===(await c("adb",eb(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await c("adb",eb(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}function ta(e,t){let r=`${e}
9
+ ${t}`.toLowerCase();return r.includes("no shell command implementation")||r.includes("unknown command")}async function to(e,t,r){let i=await c("adb",eb(e,t),{allowFailure:!0});if(ta(i.stdout,i.stderr))throw new m("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new m("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}async function ts(e,t){let r=Math.max(0,t);await c("adb",eb(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 c("adb",eb(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function tl(e,t,r){let i,n=await e3(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=ed(i[0]),n=ep(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&"),c=e.focused??!1;if(!d)continue;let u=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(c&&td(a)){(!o||u<=o.area)&&(o={text:d,area:u});continue}if(p&&td(a)){(!s||u<=s.area)&&(s={text:d,area:u});continue}p&&(!l||u<=l.area)&&(l={text:d,area:u})}return o?.text??s?.text??l?.text??null}function td(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function tc(e){await new Promise(t=>setTimeout(t,e))}function tu(e,t,r){if(!e)return t;let i=Number(e);return Number.isFinite(i)?Math.max(r,Math.floor(i)):t}let tp=tu(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),tf=/^(iphone|ipad|ipod|appletv)/i,tm=/^appletv/i,th=["apple tv","appletv","tvos"];function tw(e){return(e??"").trim().toLowerCase()}function tg(e){return tw(e.hardwareProperties?.platform)}function tv(e){return e.includes("tvos")}function tI(e){let t=tw(e);return th.some(e=>t.includes(e))}function ty(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function tA(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function tS(){if("darwin"!==process.platform)throw new m("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await h("xcrun"))throw new m("TOOL_MISSING","xcrun not found in PATH");let e=[],t=await c("xcrun",["simctl","list","devices","-j"]);try{let i=JSON.parse(t.stdout);for(let[t,n]of Object.entries(i.devices))if(function(e){let t=tw(e);return t.includes("ios")||t.includes("tvos")}(t))for(let i of n){var r;i.isAvailable&&e.push({platform:"ios",id:i.udid,name:i.name,kind:"simulator",target:(r=t,tv(tw(r))?"tv":"mobile"),booted:"Booted"===i.state})}}catch(e){throw new m("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}let n=null;try{n=i.join(C.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let t=await c("xcrun",["devicectl","list","devices","--json-output",n],{allowFailure:!0,timeoutMs:tp});if(0!==t.exitCode)return e;let r=await _.readFile(n,"utf8"),a=JSON.parse(r);for(let t of a.result?.devices??[])if(function(e){var t;let r=tg(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=tA(e),!!tf.test(t.trim())||ty(e).some(tI))}(t)){let r=t.hardwareProperties?.udid??t.identifier??"",i=t.name??t.deviceProperties?.name??r;if(!r)continue;e.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return tv(tg(e))?"tv":(t=tA(e),tm.test(t.trim())||ty(e).some(tI))?"tv":"mobile"}(t),booted:!0})}}catch{}finally{n&&await _.rm(n,{force:!0}).catch(()=>{})}return e}let tb=tu(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,U,5e3),tN=tu(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,V,1e3),tD=tu(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),t_=tu(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3);async function tk(e,t){let r=["devicectl",...e],i=await c("xcrun",r,{allowFailure:!0,timeoutMs:t_});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new m("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:tE(n,a)??tO})}async function tx(e,t){let r=i.join(C.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),n=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",r],a=await c("xcrun",n,{allowFailure:!0,timeoutMs:t_});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new m("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:n,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:tE(t,r)??tO})}let i=await _.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(i)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof m)throw t;throw new m("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await _.unlink(r).catch(()=>{})}}let tO="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function tE(e,t){let r=`${e}
10
+ ${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}async function tM(e,t,r){let i=(e.get(t)??Promise.resolve()).catch(()=>{}).then(r);return e.set(t,i),i.finally(()=>{e.get(t)===i&&e.delete(t)})}let tL=new Set;function tC(e){return!!e&&tL.has(e)}let tR=Array.from(new Set([process.env.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID,process.env.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID,"com.myapp.AgentDeviceRunnerUITests.xctrunner","com.myapp.AgentDeviceRunner"].map(e=>e?.trim()??"").filter(e=>e.length>0))),tT=new Map,tP=new Map,t$=new Set,tF=tu(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),tG=tu(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),tV=tu(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),tU=tu(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),tB=tu(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),tj=tu(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),tq=tu(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),tW=tu(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5),tJ=i.join(C.homedir(),".agent-device","ios-runner");async function tz(e,t,r={}){var i;return(function(e){if("ios"!==e.platform)throw new m("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new m("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`)}(e),rt(r.requestId),"snapshot"===(i=t.command)||"screenshot"===i||"findText"===i||"alert"===i)?W(()=>(rt(r.requestId),tH(e,t,r)),{shouldRetry:e=>(rt(r.requestId),function(e){if(!(e instanceof m)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!(t.includes("xcodebuild exited early")||t.includes("device is busy")&&t.includes("connecting"))&&!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}(e))}):tH(e,t,r)}async function tH(e,t,r={}){let i;rt(r.requestId);try{let n=(i=await t3(e,r)).ready?tG:tF;return await tX(e,i,t,r.logPath,n)}catch(a){let n=a instanceof m?a:new m("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===n.code&&"string"==typeof n.message&&n.message.includes("Runner did not accept connection")&&ri(n)&&i?.ready){rt(r.requestId),i?await t0(i):await tK(e.id),i=await t3(e,r);let n=await ra(i.device,i.port,t,r.logPath,tF);return await tY(n,i,r.logPath)}throw a}}async function tX(e,t,r,i,n){let a=await ra(e,t.port,r,i,n,t);return await tY(a,t,i)}async function tY(e,t,r){let i=await e.text(),n={};try{n=JSON.parse(i)}catch{throw new m("COMMAND_FAILED","Invalid runner response",{text:i})}if(!n.ok)throw new m("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:r});return t.ready=!0,n.data??{}}async function tK(e){await tM(tP,e,async()=>{await t1(e)})}async function tZ(){let e=Array.from(tT.values()),t=Array.from(t$);await Promise.allSettled(e.map(async e=>{await t4(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await t4(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await t4(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await t4(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await t4(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await t4(e.pid,"SIGKILL"),t$.delete(e)}))}async function tQ(){await tZ();let e=Array.from(tT.keys());await Promise.allSettled(e.map(async e=>{await tK(e)})),await t8()}async function t0(e){await tM(tP,e.deviceId,async()=>{await t1(e.deviceId,e)})}async function t1(e,t){let r=t??tT.get(e);if(r){try{await ra(r.device,r.port,{command:"shutdown"},void 0,15e3)}catch{await t4(r.child.pid,"SIGTERM")}try{await Promise.race([r.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await t4(r.child.pid,"SIGKILL"),rp(r.xctestrunPath),rp(r.jsonPath),tT.get(e)===r&&tT.delete(e)}}async function t2(e){await c("xcrun",["simctl","bootstatus",e,"-b"],{allowFailure:!0,timeoutMs:tF})}async function t3(e,t){return await tM(tP,e.id,async()=>{var r,i,n;let a,o=tT.get(e.id);if(o){if((r=o.child.pid)&&x(r))return o;await t1(e.id,o)}await ("simulator"!==(i=e).kind?Promise.resolve():t2(i.id));let l=await t5(e,t),d=await rc(),{xctestrunPath:c,jsonPath:u}=await ru(l,{AGENT_DEVICE_RUNNER_PORT:String(d)},`session-${e.id}-${d}`),{child:p,wait:f}=s("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-collect-test-diagnostics","never",t9(e),"1","-destination-timeout",String(tW),"-xctestrun",c,"-destination",(a=t6(n=e),"simulator"===n.kind?`platform=${a} Simulator,id=${n.id}`:`platform=${a},id=${n.id}`)],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(d)},detached:!0});p.stdout?.on("data",e=>{re(e,t.logPath,t.traceLogPath,t.verbose)}),p.stderr?.on("data",e=>{re(e,t.logPath,t.traceLogPath,t.verbose)});let m={device:e,deviceId:e.id,port:d,xctestrunPath:c,jsonPath:u,testPromise:f,child:p,ready:!1};return tT.set(e.id,m),m})}async function t4(e,t){if(!e||e<=0)return;try{process.kill(-e,t)}catch{}try{process.kill(e,t)}catch{}let r="SIGINT"===t?"INT":"SIGTERM"===t?"TERM":"KILL";try{await c("pkill",[`-${r}`,"-P",String(e)],{allowFailure:!0})}catch{}}async function t5(e,t){var r,n,a;let o,s=(r=e.kind,(o=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?i.resolve(o):"simulator"===r?i.join(tJ,"derived"):i.join(tJ,"derived",r));if(G(process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)){!function(e,t=process.env){if(t.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim()&&!function(e=process.env){return G(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new m("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(s);try{E.rmSync(s,{recursive:!0,force:!0})}catch{}}let l=t7(s);if(l)return l;let d=function(){let e=i.dirname(g(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=i.join(t,"package.json");if(E.existsSync(e))return t;t=i.dirname(t)}return e}(),c=i.join(d,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!E.existsSync(c))throw new m("COMMAND_FAILED","iOS runner project not found",{projectPath:c});let u=function(e=process.env,t=!1){if(!t)return[];let r=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||"",i=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||"",n=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||"",a=["CODE_SIGN_STYLE=Automatic"];return r&&a.push(`DEVELOPMENT_TEAM=${r}`),i&&a.push(`CODE_SIGN_IDENTITY=${i}`),n&&a.push(`PROVISIONING_PROFILE_SPECIFIER=${n}`),a}(process.env,"device"===e.kind),p="device"===e.kind?["-allowProvisioningUpdates"]:[];try{let r;await v("xcodebuild",["build-for-testing","-project",c,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",t9(e),"1","-destination",(n=e,r=t6(n),"simulator"===n.kind?`platform=${r} Simulator,id=${n.id}`:`generic/platform=${r}`),"-derivedDataPath",s,...p,...u],{detached:!0,onSpawn:e=>{t$.add(e),e.on("close",()=>{t$.delete(e)})},onStdoutChunk:e=>{re(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{re(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(o){let e,r,i=o instanceof m?o:new m("COMMAND_FAILED",String(o)),n=(e=(a=i).details?JSON.stringify(a.details):"",(r=`${a.message}
11
+ ${e}`.toLowerCase()).includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new m("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:i.message,details:i.details,logPath:t.logPath,hint:n})}let f=t7(s);if(!f)throw new m("COMMAND_FAILED","Failed to locate .xctestrun after build");return f}async function t8(){let e=Array.from(t$);await Promise.allSettled(e.map(async e=>{try{await t4(e.pid,"SIGTERM"),await t4(e.pid,"SIGKILL")}finally{t$.delete(e)}}))}function t6(e){if("ios"!==e.platform)throw new m("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"tv"===e.target?"tvOS":"iOS"}function t9(e){return"device"===e.kind?"-maximum-concurrent-test-device-destinations":"-maximum-concurrent-test-simulator-destinations"}function t7(e){if(!E.existsSync(e))return null;let t=[],r=[e];for(;r.length>0;){let e=r.pop();for(let n of E.readdirSync(e,{withFileTypes:!0})){let a=i.join(e,n.name);if(n.isDirectory()){r.push(a);continue}if(n.isFile()&&n.name.endsWith(".xctestrun"))try{let e=E.statSync(a);t.push({path:a,mtimeMs:e.mtimeMs})}catch{}}}return 0===t.length?null:(t.sort((e,t)=>t.mtimeMs-e.mtimeMs),t[0]?.path??null)}function re(e,t,r,i){t&&E.appendFileSync(t,e),r&&E.appendFileSync(r,e),i&&process.stderr.write(e)}function rt(e){if(tC(e))throw new m("COMMAND_FAILED","request canceled")}function rr(e){let{port:t,endpoints:r,logPath:i,lastError:n}=e,a="Runner did not accept connection";return new m("COMMAND_FAILED",a,{port:t,endpoints:r,logPath:i,lastError:n?String(n):void 0,reason:z({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:H("IOS_RUNNER_CONNECT_TIMEOUT")})}function ri(e){return!(e instanceof m)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}async function rn(e){var t,r;let i,{session:n,port:a,logPath:o}=e,s=await n.testPromise,l="Runner did not accept connection (xcodebuild exited early)",d=z({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new m("COMMAND_FAILED",l,{port:a,logPath:o,xcodebuild:{exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr},reason:d,hint:(t=s.stdout,r=s.stderr,(i=`${l}
14
12
  ${t}
15
- ${i}`.toLowerCase()).includes("device is busy")&&r.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":z("IOS_RUNNER_CONNECT_TIMEOUT"))})}async function t7(e,t,i,r,n=tC,a){let o=U.fromTimeoutMs(n),s=await ie(e,t,o.remainingMs()),l=null,d=Math.max(1,Math.ceil(n/tT));try{return await B(async({deadline:o})=>{if(o?.isExpired())throw new f("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await t9({session:a,port:t,logPath:r});for(let r of("device"===e.kind&&(s=await ie(e,t,o?.remainingMs())),s))try{let e=o?.remainingMs()??n;if(e<=0)throw new f("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await it(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)},Math.min(tF,e))}catch(e){l=e}throw new f("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:s,lastError:l?String(l):void 0})},{maxAttempts:d,baseDelayMs:tP,maxDelayMs:t$,jitter:.2,shouldRetry:t6},{deadline:o,phase:"ios_runner_connect"})}catch(e){l||(l=e)}if("simulator"===e.kind){let n=o.remainingMs();if(n<=0)throw t8({port:t,endpoints:s,logPath:r,lastError:l});let a=await ir(e.id,t,i,n);return new Response(a.body,{status:a.status})}throw t8({port:t,endpoints:s,logPath:r,lastError:l})}async function ie(e,t,i){let r=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return r;let n=await ii(e.id,i);return n&&r.unshift(`http://[${n}]:${t}/command`),r}async function it(e,t,i){let r=new AbortController,n=setTimeout(()=>r.abort(),i);try{return await fetch(e,{...t,signal:r.signal})}finally{clearTimeout(n)}}async function ii(e,t){if("number"==typeof t&&t<=0)return null;let i="number"==typeof t?Math.max(1,Math.min(tG,t)):tG,n=r.join(L.tmpdir(),`agent-device-devicectl-info-${process.pid}-${Date.now()}.json`);try{let t=Math.max(1,Math.ceil(i/1e3)),r=await d("xcrun",["devicectl","device","info","details","--device",e,"--json-output",n,"--timeout",String(t)],{allowFailure:!0,timeoutMs:i});if(0!==r.exitCode||!E.existsSync(n))return null;let a=JSON.parse(E.readFileSync(n,"utf8"));if(a.info?.outcome&&"success"!==a.info.outcome)return null;let o=(a.result?.connectionProperties?.tunnelIPAddress??a.result?.device?.connectionProperties?.tunnelIPAddress)?.trim();return o&&o.length>0?o:null}catch{return null}finally{is(n)}}async function ir(e,t,i,r){let n=JSON.stringify(i),a=await d("xcrun",["simctl","spawn",e,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`],{allowFailure:!0,timeoutMs:r}),o=a.stdout;if(0!==a.exitCode){let e=W({message:"Runner did not accept connection (simctl spawn)",stdout:a.stdout,stderr:a.stderr,context:{platform:"ios",phase:"connect"}});throw new f("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,reason:e,hint:z(e)})}return{status:200,body:o}}async function ia(){return await new Promise((e,t)=>{let i=C.createServer();i.listen(0,"127.0.0.1",()=>{let r=i.address();i.close(),"object"==typeof r&&r?.port?e(r.port):t(new f("COMMAND_FAILED","Failed to allocate port"))}),i.on("error",t)})}async function io(e,t,i){let n,a=r.dirname(e),o=i.replace(/[^a-zA-Z0-9._-]/g,"_"),s=r.join(a,`AgentDeviceRunner.env.${o}.json`),l=r.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),c=await d("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==c.exitCode||!c.stdout.trim())throw new f("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:c.stderr});try{n=JSON.parse(c.stdout)}catch(t){throw new f("COMMAND_FAILED","Failed to parse xctestrun JSON",{xctestrunPath:e,error:String(t)})}let u=e=>{e.EnvironmentVariables={...e.EnvironmentVariables??{},...t},e.UITestEnvironmentVariables={...e.UITestEnvironmentVariables??{},...t},e.UITargetAppEnvironmentVariables={...e.UITargetAppEnvironmentVariables??{},...t},e.TestingEnvironmentVariables={...e.TestingEnvironmentVariables??{},...t}},p=n.TestConfigurations;if(Array.isArray(p))for(let e of p){if(!e||"object"!=typeof e)continue;let t=e.TestTargets;if(Array.isArray(t))for(let e of t)e&&"object"==typeof e&&u(e)}for(let[e,t]of Object.entries(n))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),n[e]=t);E.writeFileSync(s,JSON.stringify(n,null,2));let m=await d("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==m.exitCode)throw new f("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:m.stderr});return{xctestrunPath:l,jsonPath:s}}function is(e){try{E.existsSync(e)&&E.unlinkSync(e)}catch{}}async function il(e){return await N("resolve_target_device",async()=>{let t={platform:e.platform,deviceName:e.device,udid:e.udid,serial:e.serial};if("android"===t.platform){await eG();let e=await Y();return await T(e,t)}if("ios"===t.platform){let e=await e4();return await T(e,t)}let i=[];try{i.push(...await Y())}catch{}try{i.push(...await e4())}catch{}return await T(i,t)},{platform:e.platform})}async function id(e,t,i,n,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,i)=>ev(e,t,i?.activity),openDevice:()=>ey(e),close:t=>eA(e,t),tap:(t,i)=>e_(e,t,i),doubleTap:async(t,i)=>{await e_(e,t,i),await e_(e,t,i)},swipe:(t,i,r,n,a)=>eD(e,t,i,r,n,a),longPress:(t,i,r)=>eM(e,t,i,r),focus:(t,i)=>eL(e,t,i),type:t=>ex(e,t),fill:(t,i,r)=>eC(e,t,i,r),scroll:(t,i)=>eR(e,t,i),scrollIntoView:t=>eT(e,t),screenshot:t=>eP(e,t)};case"ios":var i,r;let n,a;return{open:(t,i)=>td(e,t,{appBundleId:i?.appBundleId,url:i?.url}),openDevice:()=>tc(e),close:t=>tu(e,t),screenshot:t=>th(e,t),...(i=e,n={verbose:(r=t).verbose,logPath:r.logPath,traceLogPath:r.traceLogPath,requestId:r.requestId},a=()=>{if(tE(r.requestId))throw new f("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await tB(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},n)},doubleTap:async(e,t)=>{await tB(i,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:r.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await tB(i,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:r.appBundleId},n)},longPress:async(e,t,a)=>{await tB(i,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:r.appBundleId},n)},focus:async(e,t)=>{await tB(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},n)},type:async e=>{await tB(i,{command:"type",text:e,appBundleId:r.appBundleId},n)},fill:async(e,t,a)=>{await tB(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},n),await tB(i,{command:"type",text:a,clearFirst:!0,appBundleId:r.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new f("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 tB(i,{command:"swipe",direction:a,appBundleId:r.appBundleId},n)},scrollIntoView:async e=>{let t=await tB(i,{command:"findText",text:e,appBundleId:r.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 tB(i,{command:"swipe",direction:"up",appBundleId:r.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await tB(i,{command:"findText",text:e,appBundleId:r.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new f("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new f("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return b({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await N("platform_command",async()=>{var s,l,d,c,u,p;switch(t){case"open":{let t=i[0],r=i[1];if(i.length>2)throw new f("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==r){if("ios"!==e.platform)throw new f("INVALID_ARGS","open <app> <url> is supported only on iOS");if(Q(t))throw new f("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!Q(r))throw new f("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:r}),{app:t,url:r}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=i[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,r]=i.map(Number);if(Number.isNaN(t)||Number.isNaN(r))throw new f("INVALID_ARGS","press requires x y");let n=iu(a?.count??1,"count",1,200),u=iu(a?.intervalMs??0,"interval-ms",0,1e4),p=iu(a?.holdMs??0,"hold-ms",0,1e4),m=iu(a?.jitterPx??0,"jitter-px",0,100),h=a?.doubleTap===!0;if(h&&p>0)throw new f("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(h&&m>0)throw new f("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,c=m,"ios"===s.platform&&l>1&&0===d&&0===c)return await tB(e,{command:"tapSeries",x:t,y:r,count:n,intervalMs:u,doubleTap:h,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:r,count:n,intervalMs:u,holdMs:p,jitterPx:m,doubleTap:h,timingMode:"runner-series"};return await ip(n,u,async e=>{let[i,n]=function(e,t){if(t<=0)return[0,0];let[i,r]=ic[e%ic.length];return[i*t,r*t]}(e,m),a=t+i,s=r+n;h?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:r,count:n,intervalMs:u,holdMs:p,jitterPx:m,doubleTap:h}}case"swipe":{let t=Number(i[0]),r=Number(i[1]),n=Number(i[2]),s=Number(i[3]);if([t,r,n,s].some(Number.isNaN))throw new f("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=iu(i[4]?Number(i[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,c=iu(a?.count??1,"count",1,200),m=iu(a?.pauseMs??0,"pause-ms",0,1e4),h=a?.pattern??"one-way";if("one-way"!==h&&"ping-pong"!==h)throw new f("INVALID_ARGS",`Invalid pattern: ${h}`);if(u=e,p=c,"ios"===u.platform&&p>1)return await tB(e,{command:"dragSeries",x:t,y:r,x2:n,y2:s,durationMs:d,count:c,pauseMs:m,pattern:h,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:r,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:c,pauseMs:m,pattern:h};return await ip(c,m,async e=>{"ping-pong"===h&&e%2==1?await o.swipe(n,s,t,r,d):await o.swipe(t,r,n,s,d)}),{x1:t,y1:r,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:c,pauseMs:m,pattern:h}}case"longpress":{let e=Number(i[0]),t=Number(i[1]),r=i[2]?Number(i[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new f("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,r),{x:e,y:t,durationMs:r}}case"focus":{let[e,t]=i.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new f("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=i.join(" ");if(!e)throw new f("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(i[0]),t=Number(i[1]),r=i.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!r)throw new f("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,r),{x:e,y:t,text:r}}case"scroll":{let e=i[0],t=i[1]?Number(i[1]):void 0;if(!e)throw new f("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=i.join(" ").trim();if(!e)throw new f("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 f("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(i[0]),r=i[1]?Number(i[1]):void 0,n=i[2]?Number(i[2]):void 0;if(Number.isNaN(t)||t<=0)throw new f("INVALID_ARGS","pinch requires scale > 0");return await tB(e,{command:"pinch",scale:t,x:r,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:r,y:n}}case"screenshot":{let e=i[0]??n??`./screenshot-${Date.now()}.png`;return await _.mkdir(r.dirname(e),{recursive:!0}),await o.screenshot(e),{path:e}}case"back":if("ios"===e.platform)return await tB(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await ek(e),{action:"back"};case"home":if("ios"===e.platform)return await tB(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await eO(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await tB(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await eE(e),{action:"app-switcher"};case"settings":{let[t,r,n,o,s]=i,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(b({level:"debug",phase:"settings_apply",data:{setting:t,state:r,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await tw(e,t,r,s??a?.appBundleId,l),{setting:t,state:r};return await e$(e,t,r,s??a?.appBundleId,l),{setting:t,state:r}}case"snapshot":{if("ios"===e.platform){let t=await N("snapshot_capture",async()=>await tB(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"}),i=t.nodes??[];if(0===i.length&&"simulator"===e.kind)throw new f("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:i,truncated:t.truncated??!1,backend:"xctest"}}let t=await N("snapshot_capture",async()=>await eF(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 f("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let ic=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function iu(e,t,i,r){if(!Number.isFinite(e)||!Number.isInteger(e)||e<i||e>r)throw new f("INVALID_ARGS",`${t} must be an integer between ${i} and ${r}`);return e}async function ip(e,t,i){for(let r=0;r<e;r+=1)await i(r),r<e-1&&t>0&&await im(t)}async function im(e){await new Promise(t=>setTimeout(t,e))}let ih={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}},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}},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}},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}},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}},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 iw(e,t){let i=ih[e];if(!i)return!0;let r=i[t.platform];return!!r&&!0===r[t.kind??"unknown"]}function ig(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let i=e.positionals??[];return 0===i.length?"":i[0].startsWith("@")?i.length>=3?i.slice(2).join(" ").trim():i.slice(1).join(" ").trim():!(i.length>=3)||Number.isNaN(Number(i[0]))||Number.isNaN(Number(i[1]))?i.slice(1).join(" ").trim():i.slice(2).join(" ").trim()}function iv(e){let t=new Set,i=[];for(let r of e)t.has(r)||(t.add(r),i.push(r));return i}let iI=/^-?\d+(\.\d+)?$/,iy=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),iA=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function iS(e){return"click"===e||"press"===e}function iN(e){let t=e.trim();return t.startsWith("@")||iI.test(t)?t:JSON.stringify(t)}function ib(e,t){let i=t.flags??{};if(iS(t.command)){"number"==typeof i.count&&e.push("--count",String(i.count)),"number"==typeof i.intervalMs&&e.push("--interval-ms",String(i.intervalMs)),"number"==typeof i.holdMs&&e.push("--hold-ms",String(i.holdMs)),"number"==typeof i.jitterPx&&e.push("--jitter-px",String(i.jitterPx)),!0===i.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof i.count&&e.push("--count",String(i.count)),"number"==typeof i.pauseMs&&e.push("--pause-ms",String(i.pauseMs)),("one-way"===i.pattern||"ping-pong"===i.pattern)&&e.push("--pattern",i.pattern))}function i_(e,t){let i=[],r={},n=iS(e)?iy:"swipe"===e?iA:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(iS(e)&&"--double-tap"===o){r.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(r[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(r.pattern=e),a+=1;continue}i.push(o)}return{positionals:i,flags:r}}class iD{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=iD.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:i,udid:r,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}=e;return{platform:t,device:i,udid:r,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}}(t.flags),result:t.result}),b({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),i=r.dirname(t);E.existsSync(i)||E.mkdirSync(i,{recursive:!0});let n=function(e,t){let i=[],r=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(i.push(`context platform=${e.device.platform} device="${r}"${n} theme=unknown`),t))a.flags?.noRecord||i.push(function(e){let t=[e.command];if(iS(e.command)){let i=e.positionals?.[0];if(i){if(i.startsWith("@")){t.push(iN(i));let r=e.result?.refLabel;return"string"==typeof r&&r.trim().length>0&&t.push(iN(r)),ib(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(iN(i)),ib(t,e),t.join(" ")}}if("fill"===e.command){let i=e.positionals?.[0];if(i&&i.startsWith("@")){t.push(iN(i));let r=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof r&&r.trim().length>0&&t.push(iN(r)),n&&t.push(iN(n)),t.join(" ")}}if("get"===e.command){let i=e.positionals?.[0],r=e.positionals?.[1];if(i&&r){if(t.push(iN(i)),t.push(iN(r)),r.startsWith("@")){let i=e.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push(iN(i))}return t.join(" ")}}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",iN(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let i of e.positionals??[])t.push(iN(i));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let i of e.positionals??[])t.push(iN(i));return ib(t,e),t.join(" ")}(a));return`${i.join("\n")}
16
- `}(e,this.buildOptimizedActions(e));E.writeFileSync(t,n)}catch{}}defaultTracePath(e){let t=iD.safeSessionName(e.name),i=new Date().toISOString().replace(/[:.]/g,"-");return r.join(this.sessionsDir,`${t}-${i}.trace.log`)}resolveAppLogPath(e){return r.join(this.sessionsDir,iD.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return r.join(this.sessionsDir,iD.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?r.join(L.homedir(),e.slice(2)):t&&!r.isAbsolute(e)?r.resolve(t,e):r.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return iD.expandHome(e.saveScriptPath);E.existsSync(this.sessionsDir)||E.mkdirSync(this.sessionsDir,{recursive:!0});let t=iD.safeSessionName(e.name),i=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-");return r.join(this.sessionsDir,`${t}-${i}.ad`)}buildOptimizedActions(e){let t=[];for(let i of e.actions){if("snapshot"===i.command)continue;let r=Array.isArray(i.result?.selectorChain)&&i.result?.selectorChain.every(e=>"string"==typeof e)?i.result.selectorChain:[];if(r.length>0&&(iS(i.command)||"fill"===i.command||"get"===i.command)){let e=r.join(" || ");if(iS(i.command)){t.push({...i,positionals:[e]});continue}if("fill"===i.command){let r=ig(i);if(r.length>0){t.push({...i,positionals:[e,r]});continue}}if("get"===i.command){let r=i.positionals?.[0];if("text"===r||"attrs"===r){t.push({...i,positionals:[r,e]});continue}}}if(iS(i.command)||"fill"===i.command||"get"===i.command){let r=i.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push({ts:i.ts,command:"snapshot",positionals:[],flags:{platform:e.device.platform,snapshotInteractiveOnly:!0,snapshotCompact:!0,snapshotScope:r.trim()},result:{scope:r.trim()}})}t.push(i)}return t}}function ik(e,t,i,r,n){return{requestId:n??S().requestId,appBundleId:i,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:r,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 iO=e2(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function iE(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:tr}));await t(e);return}if("device"===e.kind)return void await iM(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:Z}));await t(e.id)}}async function iM(e){let t=r.join(L.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=Math.max(1,Math.ceil(iO/1e3));try{let r=await d("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(i)],{allowFailure:!0,timeoutMs:iO+3e3}),n=String(r.stdout??""),a=String(r.stderr??""),o=await ix(t);if(0===r.exitCode){if(!o.parsed)throw new f("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 f("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 f("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:r.exitCode,tunnelState:o?.tunnelState,hint:iL(n,a)})}catch(t){if(t instanceof f&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let i=t.details??{},r=String(i.stdout??""),n=String(i.stderr??""),a=Number(i.timeoutMs??iO),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 f("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:r,stderr:n,hint:r||n?iL(r,n):o},t)}throw new f("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 _.rm(t,{force:!0}).catch(()=>{})}}async function ix(e){try{let t=await _.readFile(e,"utf8"),i=JSON.parse(t),r=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let i=t.connectionProperties?.tunnelState,r=t.device?.connectionProperties?.tunnelState,n="string"==typeof i?i:"string"==typeof r?r:void 0;return n?{tunnelState:n}:{}}(i);return{parsed:!0,tunnelState:r.tunnelState}}catch{return{parsed:!1}}}function iL(e,t){let i=ti(e,t);return i||(`${e}
17
- ${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":tt)}function iC(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function iR(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function iT(e,t){return e.find(e=>e.ref===t)??null}function iP(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function i$(e,t){let i=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),r=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(i)||r.includes(i)||n.includes(i)})??null}function iF(e,t){let i=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return i&&iG(i)?i:function(e,t){if(!e.rect)return;let i=e.rect.y+e.rect.height/2,r=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||!iG(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-i);(!r||n<r.distance)&&(r={label:t,distance:n})}return r?.label}(e,t)??(i&&iG(i)?i:void 0)}function iG(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function iV(e){let t=[],i=[];for(let r of e){let e=r.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=iU(r.type??""),a=[r.label,r.value,r.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&iG(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);i.push({...r,depth:s})}return i}function iU(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),i=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==i&&(t=t.slice(i+1)),t}function iB(e,t){let i=iU(e);return!i||("android"===t?i.includes("edittext")||i.includes("autocompletetextview"):i.includes("textfield")||i.includes("securetextfield")||i.includes("searchfield")||i.includes("textview")||i.includes("textarea")||"search"===i)}function iq(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let ij=new Set(["id","role","text","label","value"]),iW=new Set(["visible","hidden","editable","selected","enabled","hittable"]),iz=new Set([...ij,...iW]);function iJ(e){let t=e.trim();if(!t)throw new f("INVALID_ARGS","Selector expression cannot be empty");let i=function(e){let t=[],i="",r=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!rt(e,n)){r?r===a&&(r=null):r=a,i+=a;continue}if(!r&&"|"===a&&"|"===e[n+1]){let r=i.trim();if(!r)throw new f("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(r),i="",n+=1;continue}i+=a}let n=i.trim();if(!n)throw new f("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===i.length)throw new f("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:i.map(e=>(function(e){let t=e.trim();if(!t)throw new f("INVALID_ARGS","Selector segment cannot be empty");let i=function(e){let t=[],i="",r=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!rt(e,n)){r?r===a&&(r=null):r=a,i+=a;continue}if(!r&&/\s/.test(a)){i.trim().length>0&&t.push(i.trim()),i="";continue}i+=a}if(r)throw new f("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return i.trim().length>0&&t.push(i.trim()),t}(t);if(0===i.length)throw new f("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:i.map(i3)}})(e))}}function iH(e){try{return iJ(e)}catch{return null}}function iX(e,t,i){let r=i.requireRect??!1,n=i.requireUnique??!0,a=i.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,i){let r=0,n=null,a=null,o=!1;for(let s of e){if(i.requireRect&&!s.rect||!i4(s,t,i.platform))continue;if(r+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let i=e.depth??0,r=t.depth??0;if(i!==r)return i>r?1:-1;let n=re(e),a=re(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:r,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:i.platform,requireRect:r});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 iY(e,t,i){let r=i.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,i){let r=0;for(let n of e)(!i.requireRect||n.rect)&&i4(n,t,i.platform)&&(r+=1);return r}(e,o,{platform:i.platform,requireRect:r});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function iK(e,t,i){let r=i.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return r?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function iZ(e,t={}){if(0===e.length)return null;let i=t.preferTrailingValue??!1,r=0,n=[];for(;r<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let i=t.indexOf("=");if(-1!==i){let e=t.slice(0,i).trim().toLowerCase();return iz.has(e)}return iz.has(t.toLowerCase())}(e[r]);){r+=1;let t=e.slice(0,r).join(" ").trim();t&&iH(t)&&n.push(r)}if(0===n.length)return null;let a=n[n.length-1];if(i){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 iQ(e){let t=e[0]??"",i=iZ(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:i}}function i0(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function i1(e,t){return iB(e.type??"",t)&&!1!==e.enabled}function i2(e,t,i={}){let r=[],n=iU(e.type??""),a=i7(e.identifier),o=i7(e.label),s=i7(e.value),l=i7(iq(e)),d="fill"===i.action;a&&r.push(`id=${i9(a)}`),n&&o&&r.push(d?`role=${i9(n)} label=${i9(o)} editable=true`:`role=${i9(n)} label=${i9(o)}`),o&&r.push(d?`label=${i9(o)} editable=true`:`label=${i9(o)}`),s&&r.push(d?`value=${i9(s)} editable=true`:`value=${i9(s)}`),l&&l!==o&&l!==s&&r.push(d?`text=${i9(l)} editable=true`:`text=${i9(l)}`),n&&d&&!r.some(e=>e.includes("editable=true"))&&r.push(`role=${i9(n)} editable=true`);let c=iv(r);return 0===c.length&&n&&c.push(d?`role=${i9(n)} editable=true`:`role=${i9(n)}`),0===c.length&&i0(e)&&c.push("visible=true"),c}function i3(e){let t=e.trim();if(!t)throw new f("INVALID_ARGS","Empty selector term");let i=t.indexOf("=");if(-1===i){let i=t.toLowerCase();if(!iW.has(i))throw new f("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:i,value:!0}}let r=t.slice(0,i).trim().toLowerCase(),n=t.slice(i+1).trim();if(!iz.has(r))throw new f("INVALID_ARGS",`Unknown selector key: ${r}`);if(!n)throw new f("INVALID_ARGS",`Missing selector value for key: ${r}`);if(iW.has(r)){let e,t="true"===(e=i5(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new f("INVALID_ARGS",`Invalid boolean value for ${r}: ${n}`);return{key:r,value:t}}return{key:r,value:i5(n)}}function i4(e,t,i){return t.terms.every(t=>(function(e,t,i){switch(t.key){case"id":return i8(e.identifier,String(t.value));case"role":var r,n;return r=e.type,n=String(t.value),function(e){return iU(e)}(r??"")===function(e){return iU(e)}(n);case"label":return i8(e.label,String(t.value));case"value":return i8(e.value,String(t.value));case"text":{let i=i6(String(t.value));return i6(iq(e))===i}case"visible":return i0(e)===!!t.value;case"hidden":return!i0(e)==!!t.value;case"editable":return i1(e,i)===!!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,i))}function i5(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function i8(e,t){return i6(e??"")===i6(t)}function i6(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function i9(e){return JSON.stringify(e)}function i7(e){if(!e)return null;let t=e.trim();return t||null}function re(e){return e.rect?e.rect.width*e.rect.height:1/0}function rt(e,t){let i=0;for(let r=t-1;r>=0&&"\\"===e[r];r-=1)i+=1;return i%2==1}function ri(e,t){let i=process.env[e];if(!i)return t;let r=Number.parseInt(i,10);return Number.isInteger(r)&&r>0?r:t}function rr(e,t){if(!e)return;let i=r.dirname(e);E.existsSync(i)||E.mkdirSync(i,{recursive:!0});let a={pid:t,startTime:O(t)??void 0,command:n(t)??void 0};E.writeFileSync(e,`${JSON.stringify(a)}
18
- `)}function rn(e){if(e&&E.existsSync(e))try{E.unlinkSync(e)}catch{}}function ra(e){let t=r.dirname(e);E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),function(e,t){if(E.existsSync(e)&&!(E.statSync(e).size<t.maxBytes))for(let i=t.maxRotatedFiles;i>=1;i-=1){let t=1===i?e:`${e}.${i-1}`,r=`${e}.${i}`;E.existsSync(t)&&(E.existsSync(r)&&E.unlinkSync(r),E.renameSync(t,r))}}(e,{maxBytes:ri("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:ri("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function ro(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function rs(e){await new Promise(t=>setTimeout(t,e))}function rl(e,t){let i=t.includeTokens?.filter(e=>e.length>0)??[],r="",n=r=>{(!(i.length>0)||i.some(e=>r.includes(e)))&&e.write(function(e,t){if(0===t.length)return e;let i=e;for(let e of t)i=i.replace(e,"[REDACTED]");return i}(r,t.redactionPatterns))};return{onChunk:e=>{let t=`${r}${e}`.split("\n");for(let e of(r=t.pop()??"",t))n(`${e}
19
- `)},flush:()=>{r&&(n(r),r="")}}}function rd(e,t,i){let r=e.stdout,n=e.stderr;return r&&n?(r.setEncoding("utf8"),n.setEncoding("utf8"),r.on("data",i.writer.onChunk),n.on("data",i.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(r=>{e.on("close",e=>{i.writer.flush(),i.endStreamOnClose&&t.end(),r({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function rc(e,t){let i=(await d("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return i&&/^\d+$/.test(i)?i:null}async function ru(e,t,i,r){let n="active",a=u("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=rl(t,{redactionPatterns:i});"number"==typeof a.pid&&rr(r,a.pid);let s=rd(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),rn(r),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await ro(s),a.killed||a.kill("SIGKILL"),await ro(s),rn(r)}}}async function rp(e,t,i,r){let n="active",a=u("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=rl(t,{redactionPatterns:i});"number"==typeof a.pid&&rr(r,a.pid);let s=rd(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),rn(r),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await ro(s),a.killed||a.kill("SIGKILL"),await ro(s),rn(r)}}}async function rf(e,t,i,r,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await rc(e,t);if(!d){await rs(1e3);continue}let c=u("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=c;let p=rl(i,{redactionPatterns:r});o=rd(c,i,{endStreamOnClose:!1,writer:p}),"number"==typeof c.pid&&rr(n,c.pid);let f=await o;if(rn(n),a=void 0,o=void 0,l)break;0!==f.exitCode&&(s="failed"),await rs(500)}return{stdout:"",stderr:"",exitCode:0}}finally{i.end(),rn(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await ro(o),a&&!a.killed&&a.kill("SIGKILL"),await ro(d),rn(n)}}}async function rm(e,t,i,r){ra(i);let n=E.createWriteStream(i,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),i=[];for(let e of t)try{i.push(RegExp(e,"gi"))}catch{}return i}();if("ios"===e.platform)return"device"===e.kind?await rp(e.id,n,a,r):await ru(t,n,a,r);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new f("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await rf(e.id,t,n,a,r)}throw n.end(),new f("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function rh(e){await e.stop(),await ro(e.wait)}async function rw(e,t){let i={},r=[];if(t||r.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await d("adb",["version"],{allowFailure:!0});i.adbAvailable=0===e.exitCode}catch{i.adbAvailable=!1}if(t)try{i.androidPidVisible=(await d("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{i.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await d("xcrun",["simctl","help"],{allowFailure:!0});i.simctlAvailable=0===e.exitCode}catch{i.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await d("xcrun",["devicectl","--version"],{allowFailure:!0});i.devicectlAvailable=0===e.exitCode}catch{i.devicectlAvailable=!1}return{checks:i,notes:r}}function rg(e){let t=r.dirname(e),i=r.basename(e);E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),E.existsSync(e)?E.truncateSync(e,0):E.writeFileSync(e,"","utf8");let n=0;for(let e of E.readdirSync(t)){if(!e.startsWith(`${i}.`))continue;let a=e.slice(i.length+1);if(/^\d+$/.test(a))try{E.unlinkSync(r.join(t,e)),n+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:n}}let rv='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',rI=["platform","device","udid","serial","verbose","out"],ry=["platform","device","udid","serial","verbose","out"],rA=["path","start","stop","doctor","mark","clear"],rS=`logs requires ${rA.slice(0,-1).join(", ")}, or ${rA.at(-1)}`;function rN(e,t,i){return t||rb(i)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function rb(e){return!!(e?.platform||e?.device||e?.udid||e?.serial)}async function r_(e){let t=rb(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}let rD={ios:async(e,t,i)=>{let{reinstallIosApp:r}=await Promise.resolve().then(()=>({reinstallIosApp:tm}));return await r(e,t,i)},android:async(e,t,i)=>{let{reinstallAndroidApp:r}=await Promise.resolve().then(()=>({reinstallAndroidApp:eb}));return await r(e,t,i)}};async function rk(e,t,i){if("ios"===e.platform&&t)return Q(t)?"device"===e.kind?ee(i,t):void 0:await rO(e,t)}async function rO(e,t){try{let{resolveIosApp:i}=await Promise.resolve().then(()=>({resolveIosApp:tl}));return await i(e,t)}catch{return}}async function rE(e,t){if(!("android"!==e.platform||!t||Q(t)))try{let{resolveAndroidApp:i}=await Promise.resolve().then(()=>({resolveAndroidApp:ep})),r=await i(e,t);return"package"===r.type?r.value:void 0}catch{return}}async function rM(e){let{req:t,sessionName:i,sessionStore:r,ensureReady:n,resolveDevice:a}=e,o=r.get(i),s=t.flags??{};if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===s.platform?`No active session "${i}". Run open with --session ${i} first.`:`No active session "${i}". Run open with --session ${i} first, or omit --session to query by device selector.`}};let l=rN("appstate",o,s);if(l)return l;let d=o?.device.platform==="ios"&&!!o&&(!rb(s)||!(s?.platform&&s.platform!==o.device.platform||s?.udid&&s.udid!==o.device.id||s?.serial&&s.serial!==o.device.id)&&(!s?.device||s.device.trim().toLowerCase()===o.device.name.trim().toLowerCase()));if("ios"===s.platform&&!d)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:rv}};if(d){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{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 r_({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:rv}};let{getAndroidAppState:u}=await Promise.resolve().then(()=>({getAndroidAppState:ew})),p=await u(c);return{ok:!0,data:{platform:"android",package:p.package,activity:p.activity}}}async function rx(e){var t;let{req:i,sessionName:r,logPath:n,sessionStore:a,invoke:o,dispatch:s,ensureReady:l,resolveTargetDevice:d,reinstallOps:c=rD,stopIosRunner:u,appLogOps:m={start:rm,stop:rh},resolveAndroidPackageForOpen:h=rE}=e,w=s??id,g=l??iE,v=d??il,y=i.command;if("session_list"===y)return{ok:!0,data:{sessions:a.toArray().map(e=>({name:e.name,platform:e.device.platform,device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===y)try{let e=[];if(i.flags?.platform==="android"){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:Y}));e.push(...await t())}else if(i.flags?.platform==="ios"){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:e4}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:Y})),{listIosDevices:i}=await Promise.resolve().then(()=>({listIosDevices:e4}));try{e.push(...await t())}catch{}try{e.push(...await i())}catch{}}return{ok:!0,data:{devices:e}}}catch(t){let e=p(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===y){let e=a.get(r),t=i.flags??{},n=rN(y,e,t);if(n)return n;let o=await r_({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});if(!iw("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=i.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:tg}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:ef}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===y){let e=a.get(r),t=i.flags??{},n=rN(y,e,t);if(n)return n;let o=await r_({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});return iw("boot",o)?{ok:!0,data:{platform:o.platform,device:o.name,id:o.id,kind:o.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===y)return await rM({req:i,sessionName:r,sessionStore:a,ensureReady:g,resolveDevice:v});if("reinstall"===y){let e,t=a.get(r),n=i.flags??{},o=rN(y,t,n);if(o)return o;let s=i.positionals?.[0]?.trim(),l=i.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let d=iD.expandHome(l);if(!E.existsSync(d))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${d}`}};let u=await r_({session:t,flags:n,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!1});if(!iw("reinstall",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===u.platform){let t=await c.ios(u,s,d);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await c.android(u,s,d);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:d,...e};return t&&a.recordAction(t,{command:y,positionals:i.positionals??[],flags:i.flags??{},result:p}),{ok:!0,data:p}}if("open"===y){let e=i.flags?.relaunch===!0;if(a.has(r)){let o=a.get(r),s=i.positionals?.[0],l=s??(e?o?.appName:void 0);if(!o||!l)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&&Q(l))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await g(o.device);let d=await rk(o.device,l,o.appBundleId)??await h(o.device,l)??((t=o.device,"android"===t.platform&&l&&Q(l))?o.appBundleId:void 0),c=s?i.positionals??[]:[l];if(e){let e=d??l;await w(o.device,"close",[e],i.flags?.out,{...ik(n,i.flags,d??o.appBundleId,o.trace?.outPath)})}await w(o.device,"open",c,i.flags?.out,{...ik(n,i.flags,d)});let u={...o,appBundleId:d,appName:l,recordSession:o.recordSession||!!i.flags?.saveScript,snapshot:void 0};return a.recordAction(u,{command:y,positionals:c,flags:i.flags??{},result:{session:r,appName:l,appBundleId:d}}),a.set(r,u),{ok:!0,data:{session:r,appName:l,appBundleId:d}}}let o=i.positionals?.[0];if(e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&o&&Q(o))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let s=await v(i.flags??{}),l=a.toArray().find(e=>e.device.id===s.id);if(l)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${l.name}".`,details:{session:l.name,deviceId:s.id,deviceName:s.name}}};await g(s);let d=await rk(s,o)??await h(s,o);if(e&&o){let e=d??o;await w(s,"close",[e],i.flags?.out,{...ik(n,i.flags,d)})}await w(s,"open",i.positionals??[],i.flags?.out,{...ik(n,i.flags,d)});let c={name:r,device:s,createdAt:Date.now(),appBundleId:d,appName:o,recordSession:!!i.flags?.saveScript,actions:[]};return a.recordAction(c,{command:y,positionals:i.positionals??[],flags:i.flags??{},result:{session:r}}),a.set(r,c),{ok:!0,data:{session:r}}}if("replay"===y){let e=i.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=iD.expandHome(e,i.meta?.cwd),s=E.readFileSync(t,"utf8"),l=s.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 i of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let i=function(e){let t=[],i=0;for(;i<e.length;){for(;i<e.length&&/\s/.test(e[i]);)i+=1;if(i>=e.length)break;if('"'===e[i]){let r=i+1,n=!1;for(;r<e.length;){let t=e[r];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),r+=1}if(r>=e.length)throw new f("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(i,r+1);t.push(JSON.parse(a)),i=r+1;continue}let r=i;for(;r<e.length&&!/\s/.test(e[r]);)r+=1;t.push(e.slice(i,r)),i=r}return t}(t);if(0===i.length)return null;let[r,...n]=i;if("context"===r)return null;let a={ts:Date.now(),command:r,positionals:[],flags:{}};if("snapshot"===r){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"===r){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(iS(r)){let e=i_(r,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 i=e.positionals[0],o=e.positionals[1];return rG(i)&&rG(o)&&e.positionals.length>=2?a.positionals=[i,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===r){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"===r){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"===r){let e=i_(r,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(i);e&&t.push(e)}return t}(s),c=i.flags?.replayUpdate===!0,u=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await o({token:i.token,session:r,command:s.command,positionals:s.positionals??[],flags:rT(i.flags,s.flags),meta:i.meta});if(l.ok)continue;if(!c)return rR(l,s,e,t);let p=await rP({action:s,sessionName:r,logPath:n,sessionStore:a,dispatch:w});if(!p)return rR(l,s,e,t);if(d[e]=p,!(l=await o({token:i.token,session:r,command:p.command,positionals:p.positionals??[],flags:rT(i.flags,p.flags),meta:i.meta})).ok)return rR(l,p,e,t);u+=1}if(c&&u>0){let e=a.get(r);!function(e,t,i){let r=[];if(i){let e=i.device.name.replace(/"/g,'\\"'),t=i.device.kind?` kind=${i.device.kind}`:"";r.push(`context platform=${i.device.platform} device="${e}"${t} theme=unknown`)}for(let e of t)r.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",iN(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let i of e.positionals??[])t.push(iN(i));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let i of e.positionals??[])t.push(iN(i));return ib(t,e),t.join(" ")}(e));let n=`${r.join("\n")}
20
- `,a=`${e}.tmp-${process.pid}-${Date.now()}`;E.writeFileSync(a,n),E.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:u,session:r}}}catch(t){let e=p(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===y){let e=a.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(i.positionals?.[0]??"path").toLowerCase(),n=!!i.flags?.restart;if(!rA.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:rS}};if(n&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=a.resolveAppLogPath(r),i=function(e){if(!E.existsSync(e))return{exists:!1,sizeBytes:0};let t=E.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),n=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:n,sizeBytes:i.sizeBytes,modifiedAt:i.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=a.resolveAppLogPath(r),i=await rw(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:i.checks,notes:i.notes}}}if("mark"===t){let e,t=i.positionals?.slice(1).join(" ")??"",n=a.resolveAppLogPath(r);return ra(n),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
21
- `,E.appendFileSync(n,e,"utf8"),{ok:!0,data:{path:n,marked:!0}}}if("clear"===t){if(e.appLog&&!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(n){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!iw("logs",e.device))return{ok:!1,error:I(new f("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=a.resolveAppLogPath(r);if(n){e.appLog&&await m.stop(e.appLog);let i=rg(t),n=a.resolveAppLogPidPath(r);try{let o=await m.start(e.device,e.appBundleId,t,n),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return a.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=I(i);return a.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:rg(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(!iw("logs",e.device))return{ok:!1,error:I(new f("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=a.resolveAppLogPath(r),i=a.resolveAppLogPidPath(r);try{let n=await m.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:n.backend,outPath:t,startedAt:n.startedAt,getState:n.getState,stop:n.stop,wait:n.wait}};return a.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:I(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),a.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("batch"===y)return await rL(i,r,o);if("close"===y){let e=a.get(r);return e?(e.appLog&&await m.stop(e.appLog),i.positionals&&i.positionals.length>0&&await w(e.device,"close",i.positionals??[],i.flags?.out,{...ik(n,i.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??tz)(e.device.id),a.recordAction(e,{command:y,positionals:i.positionals??[],flags:i.flags??{},result:{session:r}}),i.flags?.saveScript&&(e.recordSession=!0),a.writeSessionLog(e),a.delete(r),{ok:!0,data:{session:r}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function rL(e,t,i){let r=e.flags?.batchOnError??"stop";if("stop"!==r)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${r}.`}};let n=e.flags?.batchMaxSteps??D;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 r=a(e.flags?.batchSteps,n),o=Date.now(),s=[];for(let n=0;n<r.length;n+=1){let a=r[n],o=await rC(e,t,a,i,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:r.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:r.length,executed:r.length,totalDurationMs:Date.now()-o,results:s}}}catch(t){let e=p(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function rC(e,t,i,r,n){let a=Date.now(),o=await r({token:e.token,session:t,command:i.command,positionals:i.positionals,flags:function(e,t){let i={...t??{}};delete i.batchSteps,delete i.batchOnError,delete i.batchMaxSteps;let r=e??{};for(let e of rI)void 0===i[e]&&void 0!==r[e]&&(i[e]=r[e]);return i}(e.flags,i.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:i.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function rR(e,t,i,r){if(e.ok)return e;let n=i+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>iN(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:r,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 rT(e,t){let i={...t??{}},r=e??{};for(let e of ry)void 0===i[e]&&void 0!==r[e]&&(i[e]=r[e]);return i}async function rP(e){let{action:t,sessionName:i,logPath:r,sessionStore:n,dispatch:a}=e;if(!(iS(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(i);if(!o)return null;let s=iS(t.command)||"fill"===t.command,l=iS(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await r$(o,t,r,s,a,n);for(let e of function(e){let t=[],i=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...i),iS(e.command)){let i=e.positionals?.[0]??"";i&&!i.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let i=e.positionals?.[0]??"";i&&!i.startsWith("@")&&Number.isNaN(Number(i))&&t.push(i)}if("get"===e.command){let i=e.positionals?.[1]??"";i&&!i.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:i}=iQ(e.positionals);i&&t.push(i.selectorExpression)}if("wait"===e.command){let{selectorExpression:i}=rF(e.positionals??[]);i&&t.push(i)}let r="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(r.length>0){let i=JSON.stringify(r);"fill"===e.command?(t.push(`id=${i} editable=true`),t.push(`label=${i} editable=true`),t.push(`text=${i} editable=true`),t.push(`value=${i} editable=true`)):(t.push(`id=${i}`),t.push(`label=${i}`),t.push(`text=${i}`),t.push(`value=${i}`))}return iv(t).filter(e=>e.trim().length>0)}(t)){let i=iH(e);if(!i)continue;let r=iX(d.nodes,i,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!r)continue;let n=i2(r.node,o.device.platform,{action:iS(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(iS(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ig(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:i}=iQ(t.positionals);if(!e)continue;let r=i?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&r.length>0&&a.push(r),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=rF(t.positionals??[]),i=[n];return e&&i.push(e),{...t,positionals:i}}}let c=function(e,t,i){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let r=e.positionals?.[1];if(!r)return null;let n=iH(r);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(iU(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=iq(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(iU(e.type??"")))});if(0===s.length||1!==iv(s.map(e=>iq(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=i2(l,i.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return c||null}async function r$(e,t,i,r,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...ik(i,{...t.flags??{},snapshotInteractiveOnly:r,snapshotCompact:r},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:iC(t.flags?.snapshotRaw?s:iV(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function rF(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],i=/^\d+$/.test(t??""),r=iZ(i?e.slice(0,-1):e.slice());return!r||r.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:r.selectorExpression,selectorTimeout:i?t:null}}function rG(e){return!!e&&!Number.isNaN(Number(e))}function rV(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function rU(e,t){let i=v(e.type??"Element"),r=c(e,i),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),i,r,n,a,o].join("|")}function rB(e,t){return t.flatten?e.map(e=>({text:R(e,0,!1),comparable:rU(e,0)})):h(e).map(e=>({text:e.text,comparable:rU(e.node,e.depth)}))}function rq(e,t){return e.get(t)??0}async function rj(e){let{req:t,sessionName:i,logPath:r,sessionStore:n}=e,a=e.dispatchSnapshotCommand??id,o=t.command;if("snapshot"===o){let{session:e,device:o}=await rJ(n,i,t.flags);if(!iw("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=rz(t.flags?.snapshotScope,e);return s.ok?await rH(e,o,async()=>{let l=e?.appBundleId,d=await rW({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:r,snapshotScope:s.scope}),c=e?{...e,snapshot:d.snapshot}:{name:i,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return rX(n,c,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(i,c),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:c.appBundleId?c.appName??c.appBundleId:void 0,appBundleId:c.appBundleId}}}):s.response}if("diff"===o){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 rJ(n,i,t.flags);if(!iw("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=rz(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await rH(e,o,async()=>{let d=e?.appBundleId,c=(await rW({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:r,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let r=function(e,t={}){return rB(e,t).length}(c.nodes,{flatten:l}),a=e?{...e,snapshot:c}:{name:i,device:o,createdAt:Date.now(),appBundleId:d,snapshot:c,actions:[]};return rX(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:r}}),n.set(i,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:r},lines:[]}}}let u=function(e,t,i={}){let r=function(e,t){let i=e.length,r=t.length,n=i+r,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&&rq(a,n-1)<rq(a,n+1)?rq(a,n+1):rq(a,n-1)+1,d=l-n;for(;l<i&&d<r&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=i&&d>=r)return function(e,t,i,r,n){let a=[],o=r,s=n;for(let r=e.length-1;r>=0;r-=1){let n=e[r],l=o-s,d=l===-r||l!==r&&rq(n,l-1)<rq(n,l+1)?l+1:l-1,c=rq(n,d),u=c-d;for(;o>c&&s>u;)a.push({kind:"unchanged",text:i[s-1].text}),o-=1,s-=1;if(0===r)break;o===c?(a.push({kind:"added",text:i[u].text}),s=u):(a.push({kind:"removed",text:t[c].text}),o=c)}return a.reverse(),a}(o,e,t,i,r)}}return[]}(rB(e,i),rB(t,i)),n={additions:0,removals:0,unchanged:0};for(let e of r)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:r}}(e.snapshot.nodes,c.nodes,{flatten:l}),p={...e,snapshot:c};return rX(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:u.summary}),n.set(i,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:u.summary,lines:u.lines}}})}if("wait"===o){let{session:e,device:o}=await rJ(n,i,t.flags),s=function(e){if(0===e.length)return null;let t=rV(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=rV(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=rV(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let i=rV(e[e.length-1]),r=iZ(null!==i?e.slice(0,-1):e.slice());if(r&&0===r.rest.length){let e=iH(r.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:r.selectorExpression,timeoutMs:i}}return{kind:"text",text:(null!==i?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:i}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),rX(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):iw("wait",o)?await rH(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,{...ik(r,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),c=l?.nodes??[],u=iC(t.flags?.snapshotRaw?c:iV(c));e&&(e.snapshot={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(i,e));let p=iY(u,s.selector,{platform:o.platform});if(p)return rX(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=iR(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let i=iT(e.snapshot.nodes,t),r=i?iF(i,e.snapshot.nodes):void 0;if(!r)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=r,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let c=d??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===o.platform){let i=await tB(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(i?.found)return rX(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}}}else if("android"===o.platform&&i$(iC((await eF(o,{scope:l})).nodes??[]),l))return rX(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}};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"===o){let{session:e,device:a}=await rJ(n,i,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return iw("alert",a)?await rH(e,a,async()=>{if("wait"===o){let i=rV(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<i;){try{let i=await tB(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return rX(n,e,t,i),{ok:!0,data:i}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let i=await tB(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return rX(n,e,t,i),{ok:!0,data:i}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){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:"settings requires <wifi|airplane|location> <on|off>, faceid <match|nonmatch|enroll|unenroll>, or permission <grant|deny|reset> <camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri> [full|limited]"}};let{session:s,device:l}=await rJ(n,i,t.flags);return iw("settings",l)?await rH(s,l,async()=>{let i=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",i??""]:[e,a,i??""],c=await id(l,"settings",d,t.flags?.out,{...ik(r,t.flags,i,s?.trace?.outPath)});return rX(n,s,t,c??{setting:e,state:a}),{ok:!0,data:c??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function rW(e){let{dispatchSnapshotCommand:t,device:i,session:r,req:n,logPath:a,snapshotScope:o}=e,s=await t(i,"snapshot",[],n.flags?.out,{...ik(a,{...n.flags,snapshotScope:o},r?.appBundleId,r?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:iC(n.flags?.snapshotRaw?l:iV(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function rz(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 i=iR(e.trim());if(!i)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let r=iT(t.snapshot.nodes,i),n=r?iF(r,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 rJ(e,t,i){let r=e.get(t),n=r?.device??await il(i??{});return r||await iE(n),{session:r,device:n}}async function rH(e,t,i){let r=!e&&"ios"===t.platform;try{return await i()}finally{r&&await tz(t.id)}}function rX(e,t,i,r){t&&e.recordAction(t,{command:i.command,positionals:i.positionals??[],flags:i.flags??{},result:r})}function rY(e,t,i,r={}){let n=rZ(i);if(!n)return{matches:[],score:0};let a=0,o=[];for(let i of e){if(r.requireRect&&!i.rect)continue;let e=function(e,t,i){switch(t){case"role":return function(e,t){let i=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return i?i===t?2:+!!i.includes(t):0}(e.type,i);case"label":return rK(e.label,i);case"value":return rK(e.value,i);case"id":return rK(e.identifier,i);default:return Math.max(rK(e.label,i),rK(e.value,i),rK(e.identifier,i))}}(i,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(i);continue}e===a&&o.push(i)}}return{matches:o,score:a}}function rK(e,t){let i=rZ(e??"");return i?i===t?2:+!!i.includes(t):0}function rZ(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function rQ(e){let{req:t,sessionName:i,logPath:r,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:c,value:u,timeoutMs:p}=function(e){let t="any",i=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],i=1);let r=e[i]??"",n=e.slice(i+1);if(0===n.length)return{locator:t,query:r,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:r,action:"get_text"};if("attrs"===e)return{locator:t,query:r,action:"get_attrs"};throw new f("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:r,action:"wait",timeoutMs:rV(n[1])??void 0};if("exists"===a)return{locator:t,query:r,action:"exists"};if("click"===a)return{locator:t,query:r,action:"click"};if("focus"===a)return{locator:t,query:r,action:"focus"};if("fill"===a)return{locator:t,query:r,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:r,action:"type",value:n.slice(1).join(" ")};throw new f("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(i);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 il(t.flags??{});m||await iE(h);let w=m?.appBundleId,g="role"!==l?d:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,I=0,y=null,A=async()=>{let e=Date.now();if(y&&e-I<750)return{nodes:y};let a=await id(h,"snapshot",[],t.flags?.out,{...ik(r,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),o=a?.nodes??[],s=iC(t.flags?.snapshotRaw?o:iV(o));return I=e,y=s,m&&(m.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(i,m)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=p??1e4,i=Date.now();for(;Date.now()-i<e;){let{nodes:e}=await A();if(rY(e,l,d,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-i}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-i}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:S}=await A(),N=rY(S,l,d,{requireRect:v});if(v&&N.matches.length>1){let e=N.matches.slice(0,8).map(e=>{let t=iq(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${N.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:N.matches.length,candidates:e}}}}let b=N.matches[0]??null;if(!b)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let _="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let i=t,r=new Set;for(;void 0!==i.parentIndex&&!r.has(i.ref);){r.add(i.ref);let t=e[i.parentIndex];if(!t)break;if(t.hittable)return t;i=t}return null}(S,b)??b:b,D=`@${_.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=iq(b);return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get text",text:e}}),{ok:!0,data:{ref:D,text:e,node:b}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get attrs"}}),{ok:!0,data:{ref:D,node:b}};if("click"===c){let e=await a({token:t.token,session:i,command:"click",positionals:[D],flags:k});return e.ok&&m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"click"}}),e}if("fill"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:i,command:"fill",positionals:[D,u],flags:k});return e.ok&&m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"fill"}}),e}if("focus"===c){let e=b.rect?iP(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let i=await id(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...ik(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"focus"}}),{ok:!0,data:i??{ref:D}}}if("type"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=b.rect?iP(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await id(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...ik(r,t.flags,m?.appBundleId,m?.trace?.outPath)});let i=await id(h,"type",[u],t.flags?.out,{...ik(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"type"}}),{ok:!0,data:i??{ref:D}}}return null}let r0=function(e){let t=new Set,i=[];for(let r of e){if(!r)continue;let e=r.trim();!e||t.has(e)||(t.add(e),i.push(e))}return i}([process.env.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID,process.env.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID,"com.myapp.AgentDeviceRunnerUITests.xctrunner","com.myapp.AgentDeviceRunner"]);function r1(e){return e instanceof Error?e.message:String(e)}function r2(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function r3(e,t,i){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:i.trace?.outPath}}async function r4(e){let{req:t,sessionName:i,sessionStore:n,logPath:a}=e,o=e.deps??{runCmd:d,runCmdBackground:s,runIosRunnerCommand:tB},l=t.command;if("record"===l){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let s=n.get(i),d=s?.device??await il(t.flags??{});s||await iE(d);let p=s??{name:i,device:d,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 s=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!iw("record",d))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===d.platform&&"device"===d.kind?r2(p):void 0;if("ios"===d.platform&&"device"===d.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=iD.expandHome(s,t.meta?.cwd);E.mkdirSync(r.dirname(m),{recursive:!0});let h=r3(t,a,p);if("ios"===d.platform&&"device"===d.kind){let t=`agent-device-recording-${Date.now()}.mp4`,i=`tmp/${t}`,r=async()=>{await o.runIosRunnerCommand(d,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await r()}catch(e){if(!r1(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${r1(e)}`}};{var c,u;b({level:"warn",phase:"record_start_runner_desynced",data:{platform:d.platform,kind:d.kind,deviceId:d.id,session:p.name,error:r1(e)}});let t=(c=d.id,u=p.name,n.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===c&&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(d,{command:"recordStop",appBundleId:f},h)}catch{}try{await r()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${r1(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:i}}else if("ios"===d.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",["simctl","io",d.id,"recordVideo",m],{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:i}=o.runCmdBackground("adb",["-s",d.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:i}}return n.set(i,p),n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:s}}}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=r2(p);try{await o.runIosRunnerCommand(d,{command:"recordStop",appBundleId:e},r3(t,a,p))}catch(e){b({level:"warn",phase:"record_stop_runner_failed",data:{platform:d.platform,kind:d.kind,deviceId:d.id,session:p.name,error:r1(e)}})}let i={stdout:"",stderr:"",exitCode:1};for(let e of r0)if(0===(i=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",d.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==i.exitCode){let e=i.stderr.trim()||i.stdout.trim()||`devicectl exited with code ${i.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",d.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",d.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===l){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=n.get(i);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]??n.defaultTracePath(a),i=iD.expandHome(e);return E.mkdirSync(r.dirname(i),{recursive:!0}),E.appendFileSync(i,""),a.trace={outPath:i,startedAt:Date.now()},n.recordAction(a,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:i}}),{ok:!0,data:{trace:"started",outPath:i}}}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=iD.expandHome(t.positionals[1]);E.mkdirSync(r.dirname(e),{recursive:!0}),E.existsSync(o)?E.renameSync(o,e):E.appendFileSync(e,""),o=e}return a.trace=void 0,n.recordAction(a,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function r5(e,t,i){return t>=e.x&&t<=e.x+e.width&&i>=e.y&&i<=e.y+e.height}function r8(e){let t=null,i=-1;for(let r of e){let e=r.width*r.height;e>i&&(t=r,i=e)}return t}function r6(e,t,i){return Math.min(i,Math.max(t,Math.round(e)))}async function r9(e){let{req:t,sessionName:i,sessionStore:r,contextFromFlags:n}=e,a=e.dispatch??id,o=t.command;if("press"===o){let e=r.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),i=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(i)?{x:t,y:i}:null}(t.positionals??[]);if(s){let i=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return r.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:i??{x:s.x,y:s.y}}),{ok:!0,data:i??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let i=nt("press",t.flags);if(i)return i;let s=ni({session:e,refInput:d,fallbackLabel:t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!s.ok)return s.response;let{ref:c,node:u,snapshotNodes:p}=s.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has no bounds`}};let f=iF(u,p),m=i2(u,e.device.platform,{action:l}),{x:h,y:w}=iP(u.rect),g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:h,y:w,refLabel:f,selectorChain:m}}),{ok:!0,data:{...g??{},ref:c,x:h,y:w}}}let c=(t.positionals??[]).join(" ").trim();if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let u=iJ(c),p=await r7(e,t.flags,r,n,{interactiveOnly:!0},a),f=await N("selector_resolve",()=>iX(p.nodes,u,{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:iK(u,f?.diagnostics??[],{unique:!0})}};let{x:m,y:h}=iP(f.node.rect),w=await a(e.device,"press",[String(m),String(h)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=i2(f.node,e.device.platform,{action:l}),v=iF(f.node,p.nodes);return r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:m,y:h,selector:f.selector.raw,selectorChain:g,refLabel:v}}),{ok:!0,data:{...w??{},selector:f.selector.raw,x:m,y:h}}}if("fill"===o){let e=r.get(i);if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let i=nt("fill",t.flags);if(i)return i;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=ni({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:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=u.type??"",m=f&&!iB(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iF(u,p),w=i2(u,e.device.platform,{action:"fill"}),{x:g,y:v}=iP(u.rect),I={...await a(e.device,"fill",[String(g),String(v),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:c,x:g,y:v}};return m&&(I.warning=m),r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...I,refLabel:h,selectorChain:w}}),{ok:!0,data:I}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=iZ(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 i=s.rest.join(" ").trim();if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=iJ(s.selectorExpression),d=await r7(e,t.flags,r,n,{interactiveOnly:!0},a),c=await N("selector_resolve",()=>iX(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iK(l,c?.diagnostics??[],{unique:!0})}};let u=c.node,p=u.type??"",f=p&&!iB(p,e.device.platform)?`fill target ${c.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=iP(c.node.rect),w=await a(e.device,"fill",[String(m),String(h),i],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=i2(u,e.device.platform,{action:"fill"}),v={...w??{x:m,y:h,text:i},selector:c.selector.raw,selectorChain:g,refLabel:iF(u,d.nodes)};return f&&(v.warning=f),r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:v}),{ok:!0,data:v}}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=r.get(i);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let i=nt("get",t.flags);if(i)return i;let n=ni({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,c=i2(d,s.device.platform,{action:"get"});if("attrs"===e)return r.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:c}}),{ok:!0,data:{ref:a,node:d}};let u=iq(d);return r.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:u,refLabel:u||void 0,selectorChain:c}}),{ok:!0,data:{ref:a,text:u,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 c=iJ(d),u=await r7(s,t.flags,r,n,{interactiveOnly:!1},a),p=await N("selector_resolve",()=>iX(u.nodes,c,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iK(c,[],{unique:!0})}};let f=p.node,m=i2(f,s.device.platform,{action:"get"});if("attrs"===e)return r.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=iq(f);return r.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=r.get(i);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iw("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=iQ(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 c=iJ(l.selectorExpression),u=await r7(s,t.flags,r,n,{interactiveOnly:!1},a);if("exists"===e){let i=iY(u.nodes,c,{platform:s.device.platform});return i?(r.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:i.selector.raw,selectorChain:c.selectors.map(e=>e.raw),pass:!0,matches:i.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:i.selector.raw,matches:i.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:iK(c,[],{unique:!1})}}}let p=await N("selector_resolve",()=>iX(u.nodes,c,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iK(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:i,expectedText:r,platform:n}=e,a=iq(i),o=!1;switch(t){case"visible":o=i0(i);break;case"hidden":o=!i0(i);break;case"editable":o=i1(i,n);break;case"selected":o=!0===i.selected;break;case"text":o=a===(r??"")}let s="text"===t?`expected="${r??""}" actual="${a}"`:`actual=${JSON.stringify({visible:i0(i),editable:i1(i,n),selected:!0===i.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(r.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:c.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=r.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=nt("scrollintoview",t.flags);if(l)return l;let d=ni({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:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let i=iP(t),r=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=r.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=r8(n.map(e=>e.rect).filter(e=>r5(e,i.x,i.y)));if(a)return a;let o=r8(n.map(e=>e.rect));if(o)return o;let s=r8(r.map(e=>e.rect).filter(e=>r5(e,i.x,i.y)));return s||null}(p,u.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var i,r;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,c=o+.25*n,u=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=c&&f<=u)return null;let h=Math.round((i=m,r=l+p,Math.min(d-p,Math.max(r,i)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),v=Math.max(1,Math.abs(w-g));return f>u?{x:h,startY:w,endY:g,count:r6(Math.ceil((f-u)/v),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:r6(Math.ceil((c-f)/v),1,50),direction:"up"}}(u.rect,f),h=iF(u,p),w=i2(u,e.device.platform,{action:"get"});if(!m)return r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:c,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 r.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:c,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:c,attempts:m.count,direction:m.direction}}}return null}async function r7(e,t,i,r,n,a=id){let o=await a(e.device,"snapshot",[],t?.out,{...r({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:iC(t?.snapshotRaw?s:iV(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},i.set(e.name,e),e.snapshot}let ne=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function nt(e,t){let i=function(e){if(!e)return[];let t=[];for(let[i,r]of ne)void 0!==e[i]&&t.push(r);return t}(t);return 0===i.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${i.join(", ")}.`}}}function ni(e){let{session:t,refInput:i,fallbackLabel:r,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=iR(i);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=iT(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&r.length>0&&(l=i$(t.snapshot.nodes,r)),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}}}}let nr=r.join(L.homedir(),".agent-device"),nn=r.join(nr,"daemon.json"),na=r.join(nr,"daemon.lock"),no=r.join(nr,"daemon.log"),ns=r.join(nr,"sessions");var nl=ns;if(E.existsSync(nl))for(let e of E.readdirSync(nl,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=r.join(nl,e.name,"app-log.pid");if(E.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}}(E.readFileSync(t,"utf8"));if(e&&function(e){let t,i=O(e.pid);if(!i||e.startTime&&i!==e.startTime)return!1;let r=n(e.pid);return!!r&&!!((t=r.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||r===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{rn(t)}}let nd=new iD(ns),nc=y(),nu=l.randomBytes(24).toString("hex"),np=new Set(["session_list","devices"]),nf=O(process.pid)??void 0,nm=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=E.statSync(e),i=A(),n=r.relative(i,e)||e;return`${n}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function nh(e,t,i){let r=S().requestId;return{...ik(no,e,t,i,r),requestId:r}}async function nw(e){let t=!!(e.meta?.debug||e.flags?.verbose);return await M({session:e.session,requestId:e.meta?.requestId,command:e.command,debug:t,logPath:no},async()=>{if(e.token!==nu)return{ok:!1,error:I(new f("UNAUTHORIZED","Invalid token"))};b({level:"info",phase:"request_start",data:{session:e.session,command:e.command}});try{var t;let i=(t=e,"click"!==t.command?t:{...t,command:"press"}),r=i.command,n=function(e,t){var i;let r,n=e.session||"default";if(i=e,r=i.flags?.session,"string"==typeof r&&r.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(i,nd),a=nd.get(n);a&&!np.has(r)&&function(e,t){if(!t)return;let i=[],r=e.device;if(t.platform&&t.platform!==r.platform&&i.push(`--platform=${t.platform}`),t.udid&&("ios"!==r.platform||t.udid!==r.id)&&i.push(`--udid=${t.udid}`),t.serial&&("android"!==r.platform||t.serial!==r.id)&&i.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==r.name.trim().toLowerCase()&&i.push(`--device=${t.device}`),0!==i.length){var n;let t,r,a;throw new f("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(n=e).device.platform,r=n.device.name.trim(),a=n.device.id,`${t} device "${r}" (${a})`)} and cannot be used with ${i.join(", ")}. Use a different --session name or close this session first.`)}}(a,i.flags);let o=await rx({req:i,sessionName:n,logPath:no,sessionStore:nd,invoke:nw});if(o)return ng(o);let s=await rj({req:i,sessionName:n,logPath:no,sessionStore:nd});if(s)return ng(s);let l=await r4({req:e,sessionName:n,sessionStore:nd,logPath:no});if(l)return ng(l);let d=await rQ({req:i,sessionName:n,logPath:no,sessionStore:nd,invoke:nw});if(d)return ng(d);let c=await r9({req:i,sessionName:n,sessionStore:nd,contextFromFlags:nh});if(c)return ng(c);let u=nd.get(n);if(!u)return ng({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!iw(r,u.device))return ng({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${r} is not supported on this device`}});let p=await id(u.device,r,i.positionals??[],i.flags?.out,{...nh(i.flags,u.appBundleId,u.trace?.outPath)});return nd.recordAction(u,{command:r,positionals:i.positionals??[],flags:i.flags??{},result:p??{}}),ng({ok:!0,data:p??{}})}catch(i){b({level:"error",phase:"request_failed",data:{error:i instanceof Error?i.message:String(i)}});let e=S(),t=x({force:!0})??void 0;return{ok:!1,error:I(i,{diagnosticId:e.diagnosticId,logPath:t})}}})}function ng(e){let t=S();if(!e.ok){b({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let i=x({force:!0})??void 0;return{ok:!1,error:I(new f(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:i})}}return b({level:"info",phase:"request_success"}),x(),e}function nv(){if(!E.existsSync(na))return null;try{let e=JSON.parse(E.readFileSync(na,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}!function(){if(!function(){E.existsSync(nr)||E.mkdirSync(nr,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:nc,startedAt:Date.now(),processStartTime:nf},null,2),t=()=>{try{return E.writeFileSync(na,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let i=nv();if(i?.pid&&i.pid!==process.pid&&o(i.pid,i.processStartTime))return!1;try{E.unlinkSync(na)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let e=C.createServer(e=>{let t="",i=0,r=new Set,n=!1,a=()=>{if(!n&&0!==i){for(let e of(n=!0,r))e&&tO.add(e);b({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:i}}),(async()=>{let e=Date.now()+15e3;for(;i>0&&Date.now()<e&&(await tJ(),!(i<=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,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}i+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(r.add(s),tE(s)))throw new f("COMMAND_FAILED","request canceled");n=await nw(e)}catch(e){n={ok:!1,error:I(e)}}finally{if(i-=1,s){var o;r.delete(s),(o=s)&&tO.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
22
- `),a=t.indexOf("\n")}})});e.listen(0,"127.0.0.1",()=>{let t=e.address();if("object"==typeof t&&t?.port){var i;i=t.port,E.existsSync(nr)||E.mkdirSync(nr,{recursive:!0}),E.writeFileSync(no,""),E.writeFileSync(nn,JSON.stringify({port:i,token:nu,pid:process.pid,version:nc,codeSignature:nm,processStartTime:nf},null,2),{mode:384}),process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${t.port}
23
- `)}});let t=!1,i=async()=>{await new Promise(t=>{try{e.close(()=>t())}catch{t()}})},r=async()=>{if(t)return;for(let e of(t=!0,await i(),nd.toArray()))nd.writeSessionLog(e);await tH(),E.existsSync(nn)&&E.unlinkSync(nn);let e=nv();if(!e||e.pid===process.pid)try{E.existsSync(na)&&E.unlinkSync(na)}catch{}process.exit(0)};process.on("SIGINT",()=>{r()}),process.on("SIGTERM",()=>{r()}),process.on("SIGHUP",()=>{r()}),process.on("uncaughtException",e=>{let t=e instanceof f?e:p(e);process.stderr.write(`Daemon error: ${t.message}
24
- `),r()})}();
13
+ ${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":H("IOS_RUNNER_CONNECT_TIMEOUT"))})}async function ra(e,t,r,i,n=tF,a){let o=j.fromTimeoutMs(n),s=await ro(e,t,o.remainingMs()),l=null,d=Math.max(1,Math.ceil(n/tV));try{return await q(async({deadline:o})=>{if(o?.isExpired())throw new m("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await rn({session:a,port:t,logPath:i});for(let i of("device"===e.kind&&(s=await ro(e,t,o?.remainingMs())),s))try{let e=o?.remainingMs()??n;if(e<=0)throw new m("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await rs(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)},Math.min(tj,e))}catch(e){l=e}throw new m("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:s,lastError:l?String(l):void 0})},{maxAttempts:d,baseDelayMs:tU,maxDelayMs:tB,jitter:.2,shouldRetry:ri},{deadline:o,phase:"ios_runner_connect"})}catch(e){l||(l=e)}if("simulator"===e.kind){let n=o.remainingMs();if(n<=0)throw rr({port:t,endpoints:s,logPath:i,lastError:l});let a=await rd(e.id,t,r,n);return new Response(a.body,{status:a.status})}throw rr({port:t,endpoints:s,logPath:i,lastError:l})}async function ro(e,t,r){let i=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return i;let n=await rl(e.id,r);return n&&i.unshift(`http://[${n}]:${t}/command`),i}async function rs(e,t,r){let i=new AbortController,n=setTimeout(()=>i.abort(),r);try{return await fetch(e,{...t,signal:i.signal})}finally{clearTimeout(n)}}async function rl(e,t){if("number"==typeof t&&t<=0)return null;let r="number"==typeof t?Math.max(1,Math.min(tq,t)):tq,n=i.join(C.tmpdir(),`agent-device-devicectl-info-${process.pid}-${Date.now()}.json`);try{let t=Math.max(1,Math.ceil(r/1e3)),i=await c("xcrun",["devicectl","device","info","details","--device",e,"--json-output",n,"--timeout",String(t)],{allowFailure:!0,timeoutMs:r});if(0!==i.exitCode||!E.existsSync(n))return null;let a=JSON.parse(E.readFileSync(n,"utf8"));if(a.info?.outcome&&"success"!==a.info.outcome)return null;let o=(a.result?.connectionProperties?.tunnelIPAddress??a.result?.device?.connectionProperties?.tunnelIPAddress)?.trim();return o&&o.length>0?o:null}catch{return null}finally{rp(n)}}async function rd(e,t,r,i){let n=JSON.stringify(r),a=await c("xcrun",["simctl","spawn",e,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`],{allowFailure:!0,timeoutMs:i}),o=a.stdout;if(0!==a.exitCode){let e=z({message:"Runner did not accept connection (simctl spawn)",stdout:a.stdout,stderr:a.stderr,context:{platform:"ios",phase:"connect"}});throw new m("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,reason:e,hint:H(e)})}return{status:200,body:o}}async function rc(){return await new Promise((e,t)=>{let r=R.createServer();r.listen(0,"127.0.0.1",()=>{let i=r.address();r.close(),"object"==typeof i&&i?.port?e(i.port):t(new m("COMMAND_FAILED","Failed to allocate port"))}),r.on("error",t)})}async function ru(e,t,r){let n,a=i.dirname(e),o=r.replace(/[^a-zA-Z0-9._-]/g,"_"),s=i.join(a,`AgentDeviceRunner.env.${o}.json`),l=i.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),d=await c("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==d.exitCode||!d.stdout.trim())throw new m("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:d.stderr});try{n=JSON.parse(d.stdout)}catch(t){throw new m("COMMAND_FAILED","Failed to parse xctestrun JSON",{xctestrunPath:e,error:String(t)})}let u=e=>{e.EnvironmentVariables={...e.EnvironmentVariables??{},...t},e.UITestEnvironmentVariables={...e.UITestEnvironmentVariables??{},...t},e.UITargetAppEnvironmentVariables={...e.UITargetAppEnvironmentVariables??{},...t},e.TestingEnvironmentVariables={...e.TestingEnvironmentVariables??{},...t}},p=n.TestConfigurations;if(Array.isArray(p))for(let e of p){if(!e||"object"!=typeof e)continue;let t=e.TestTargets;if(Array.isArray(t))for(let e of t)e&&"object"==typeof e&&u(e)}for(let[e,t]of Object.entries(n))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),n[e]=t);E.writeFileSync(s,JSON.stringify(n,null,2));let f=await c("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==f.exitCode)throw new m("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:f.stderr});return{xctestrunPath:l,jsonPath:s}}function rp(e){try{E.existsSync(e)&&E.unlinkSync(e)}catch{}}function rf(e,t){if("simulator"!==e.kind)throw new m("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function rm(e){let t,r;if("simulator"!==e.kind||"Booted"===await rh(e.id))return;let i=j.fromTimeoutMs(tb);try{await q(async({deadline:i})=>{if(i?.isExpired())throw new m("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:tb});let n=Math.max(1e3,i?.remainingMs()??tb),a=await c("xcrun",["simctl","boot",e.id],{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
14
+ ${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new m("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await c("xcrun",["simctl","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 m("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await rh(e.id);if("Booted"!==d)throw new m("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=z({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=>z({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=z({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new m("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:tb,elapsedMs:i.elapsedMs(),reason:n,hint:H(n),boot:t,bootstatus:r})}}async function rh(e){let t=await c("xcrun",["simctl","list","devices","-j"],{allowFailure:!0,timeoutMs:tN});if(0!==t.exitCode)return null;try{let r=JSON.parse(String(t.stdout??""));for(let t of Object.values(r.devices??{})){let r=t.find(t=>t.udid===e);if(r)return r.state}return null}catch{return null}}let rw={settings:"com.apple.Preferences"},rg=null;function rv(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function rI(e,t){let r=t.trim();if(r.includes("."))return r;let i=rw[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await rL(e):await tx(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new m("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new m("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function ry(e,t,r){let i=r?.url?.trim();if(i){if(!es(i))throw new m("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await rm(e),await c("open",["-a","Simulator"],{allowFailure:!0}),await c("xcrun",["simctl","openurl",e.id,i]);return}let n=el(r?.appBundleId??await rI(e,t),i);if(!n)throw new m("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await rU(e,n,{payloadUrl:i});return}let n=t.trim();if(es(n)){if("simulator"===e.kind){await rm(e),await c("open",["-a","Simulator"],{allowFailure:!0}),await c("xcrun",["simctl","openurl",e.id,n]);return}let t=el(r?.appBundleId,n);if(!t)throw new m("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await rU(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await rI(e,t);"simulator"===e.kind?await rV(e,a):await rU(e,a)}async function rA(e){"simulator"!==e.kind||"Booted"!==await rh(e.id)&&(await rm(e),await c("open",["-a","Simulator"],{allowFailure:!0}))}async function rS(e,t){let r=await rI(e,t);if("simulator"===e.kind){await rm(e);let t=await c("xcrun",["simctl","terminate",e.id,r],{allowFailure:!0});if(0!==t.exitCode){if(t.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new m("COMMAND_FAILED",`xcrun exited with code ${t.exitCode}`,{cmd:"xcrun",args:["simctl","terminate",e.id,r],stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode})}return}await tk(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function rb(e,t){let r=await rI(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await c("xcrun",t,{allowFailure:!0,timeoutMs:t_});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!rv(`${n}
15
+ ${a}`.toLowerCase()))throw new m("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:tE(n,a)??tO})}return{bundleId:r}}await rm(e);let i=await c("xcrun",["simctl","uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!rv(`${i.stdout}
16
+ ${i.stderr}`.toLowerCase()))throw new m("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function rN(e,t){"simulator"!==e.kind?await tk(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await rm(e),await c("xcrun",["simctl","install",e.id,t]))}async function rD(e,t,r){let{bundleId:i}=await rb(e,t);return await rN(e,r),{bundleId:i}}async function r_(e,t,r){if("simulator"===e.kind){await rm(e),await c("xcrun",["simctl","io",e.id,"screenshot",t]);return}try{await tk(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(e){if(!function(e){if(!(e instanceof m)||"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}
17
+ ${r}
18
+ ${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(e))throw e}let i=(await tz(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new m("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");let n={exitCode:1,stdout:"",stderr:""};for(let r of tR)if(0===(n=await c("xcrun",["devicectl","device","copy","from","--device",e.id,"--source",i,"--destination",t,"--domain-type","appDataContainer","--domain-identifier",r],{allowFailure:!0})).exitCode)break;if(0!==n.exitCode){let e=n.stderr.trim()||n.stdout.trim()||`devicectl exited with code ${n.exitCode}`;throw new m("COMMAND_FAILED",`Failed to capture iOS screenshot: ${e}`)}}async function rk(e){rf(e,"clipboard"),await rm(e);let t=await c("xcrun",["simctl","pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new m("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 rx(e,t){rf(e,"clipboard"),await rm(e);let r=await c("xcrun",["simctl","pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new m("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function rO(e,t,r){rf(e,"push"),await rm(e);let n=await _.mkdtemp(i.join(C.tmpdir(),"agent-device-ios-push-")),a=i.join(n,"payload.apns");try{await _.writeFile(a,`${JSON.stringify(r)}
19
+ `,"utf8"),await c("xcrun",["simctl","push",e.id,t,a])}finally{await _.rm(n,{recursive:!0,force:!0})}}async function rE(e,t,r,i,n){switch(rf(e,"settings"),await rm(e),t.toLowerCase()){case"wifi":{let t=rC(r);await c("xcrun",["simctl","status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(rC(r)?await c("xcrun",["simctl","status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await c("xcrun",["simctl","status_bar",e.id,"clear"]));case"location":{let t=rC(r);if(!i)throw new m("INVALID_ARGS","location setting requires an active app in session");await c("xcrun",["simctl","privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";if("enroll"===t)return"enroll";if("unenroll"===t)return"unenroll";throw new m("INVALID_ARGS",`Invalid faceid state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r);await rF(e.id,t);return}case"appearance":{let t=await rR(e.id,r);await c("xcrun",["simctl","ui",e.id,"appearance",t]);return}case"permission":{var a;if(!i)throw new m("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(a=ew(r))?"revoke":a,o=function(e,t){let r=eg(e);if("photos"!==r&&t?.trim())throw new m("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 m("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new m("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 rT(e.id,t,o,i);return}default:throw new m("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function rM(e,t="all"){var r;return"simulator"===e.kind?(r=await rL(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await tx(e,t)}async function rL(e){let t=(await c("xcrun",["simctl","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 c("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 rC(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 m("INVALID_ARGS",`Invalid setting state: ${e}`)}async function rR(e,t){let r=ev(t);if("toggle"!==r)return r;let i=await c("xcrun",["simctl","ui",e,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new m("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}
20
+ ${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 m("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}async function rT(e,t,r,i){let n=await r$();if(!n.has(r))throw new m("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["simctl","privacy",e,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await c("xcrun",a);return}catch(t){if(!(o&&rP(t)))throw t;throw new m("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await c("xcrun",a);return}catch(e){if(!rP(e))throw e}try{await c("xcrun",["simctl","privacy",e,"reset","all",i])}catch(t){throw new m("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function rP(e){if(!(e instanceof m)||"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 r$(){let t=process.env.PATH;if(rg&&e===t)return rg;let r=await c("xcrun",["simctl","privacy","help"],{allowFailure:!0}),i=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}(`${r.stdout}
21
+ ${r.stderr}`);if(0===i.size)throw new m("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return rg=i,e=t,i}async function rF(e,t){let r=function(e,t){switch(t){case"match":return[["simctl","biometric",e,"match","face"],["simctl","biometric","match",e,"face"]];case"nonmatch":return[["simctl","biometric",e,"nonmatch","face"],["simctl","biometric",e,"nomatch","face"],["simctl","biometric","nonmatch",e,"face"],["simctl","biometric","nomatch",e,"face"]];case"enroll":return[["simctl","biometric",e,"enroll","yes"],["simctl","biometric",e,"enroll","1"],["simctl","biometric","enroll",e,"yes"],["simctl","biometric","enroll",e,"1"]];case"unenroll":return[["simctl","biometric",e,"enroll","no"],["simctl","biometric",e,"enroll","0"],["simctl","biometric","enroll",e,"no"],["simctl","biometric","enroll",e,"0"]]}}(e,t),i=[];for(let e of r){let t=await c("xcrun",e,{allowFailure:!0});if(0===t.exitCode)return;i.push({args:e,stderr:t.stderr,stdout:t.stdout,exitCode:t.exitCode})}throw new m("COMMAND_FAILED","simctl biometric command failed. Ensure your Xcode Simulator runtime supports Face ID control.",{deviceId:e,action:t,attempts:i.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}))})}function rG(e){if(!(e instanceof m)||"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 rV(e,t){await rm(e),await c("open",["-a","Simulator"],{allowFailure:!0});let r=j.fromTimeoutMs(tD);await q(async({deadline:r})=>{if(r?.isExpired())throw new m("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tD});let i=await c("xcrun",["simctl","launch",e.id,t],{allowFailure:!0});if(0!==i.exitCode)throw new m("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:["simctl","launch",e.id,t],stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:rG},{deadline:r})}async function rU(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tk(i,{action:"launch iOS app",deviceId:e.id})}function rB(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new m("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!E.statSync(a).isFile())throw new m("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof m)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new m("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new m("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 m("INVALID_ARGS",`${i} file not found: ${a}`)}async function rj(e){let t=P(e.platform);return await N("resolve_target_device",async()=>{let r={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(r.target&&!r.platform)throw new m("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===r.platform){await e1();let e=await en();return await $(e,r)}if("ios"===r.platform){let e=await tS();return await $(e,r)}let i=[];try{i.push(...await en())}catch{}try{i.push(...await tS())}catch{}return await $(i,r)},{platform:t,target:e.target})}async function rq(e,t,r,n,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>eM(e,t,r?.activity),openDevice:()=>eC(e),close:t=>eR(e,t),tap:(t,r)=>eF(e,t,r),doubleTap:async(t,r)=>{await eF(e,t,r),await eF(e,t,r)},swipe:(t,r,i,n,a)=>eG(e,t,r,i,n,a),longPress:(t,r,i)=>ej(e,t,r,i),focus:(t,r)=>ez(e,t,r),type:t=>eq(e,t),fill:(t,r,i)=>eH(e,t,r,i),scroll:(t,r)=>eX(e,t,r),scrollIntoView:t=>eY(e,t),screenshot:(t,r)=>eK(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>ry(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rA(e),close:t=>rS(e,t),screenshot:(t,r)=>r_(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(tC(i.requestId))throw new m("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await tz(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 tz(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await tz(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await tz(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await tz(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new m("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 tz(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await tz(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 tz(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await tz(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new m("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new m("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return D({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await N("platform_command",async()=>{var s,l,d,c,u,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new m("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 m("INVALID_ARGS","open <app> <url> is supported only on iOS");if(es(t))throw new m("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!es(i))throw new m("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 m("INVALID_ARGS","press requires x y");let n=rJ(a?.count??1,"count",1,200),u=rJ(a?.intervalMs??0,"interval-ms",0,1e4),p=rJ(a?.holdMs??0,"hold-ms",0,1e4),f=rJ(a?.jitterPx??0,"jitter-px",0,100),h=a?.doubleTap===!0;if(h&&p>0)throw new m("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(h&&f>0)throw new m("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,c=f,"ios"===s.platform&&l>1&&0===d&&0===c)return await tz(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:u,doubleTap:h,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:u,holdMs:p,jitterPx:f,doubleTap:h,timingMode:"runner-series"};return await rX(n,u,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=rW[e%rW.length];return[r*t,i*t]}(e,f),a=t+r,s=i+n;h?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:u,holdMs:p,jitterPx:f,doubleTap:h}}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 m("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=rJ(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,c=rJ(a?.count??1,"count",1,200),f=rJ(a?.pauseMs??0,"pause-ms",0,1e4),h=a?.pattern??"one-way";if("one-way"!==h&&"ping-pong"!==h)throw new m("INVALID_ARGS",`Invalid pattern: ${h}`);if(u=e,p=c,"ios"===u.platform&&p>1)return await tz(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:c,pauseMs:f,pattern:h,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:c,pauseMs:f,pattern:h};return await rX(c,f,async e=>{"ping-pong"===h&&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:c,pauseMs:f,pattern:h}}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 m("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 m("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 m("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 m("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 m("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 m("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 m("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 m("INVALID_ARGS","pinch requires scale > 0");return await tz(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"screenshot":{let e=r[0]??n??`./screenshot-${Date.now()}.png`;return await _.mkdir(i.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await tz(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await eV(e),{action:"back"};case"home":if("ios"===e.platform)return await tz(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await eU(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await tz(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await eB(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new m("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new m("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await rk(e):await eW(e)}}if(r.length<2)throw new m("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await rx(e,i):await eJ(e,i),{action:t,textLength:Array.from(i).length}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(D({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await rE(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await eZ(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 m("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await rz(i);if("ios"===e.platform)return await rO(e,t,n),{platform:"ios",bundleId:t};let a=await eQ(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await N("snapshot_capture",async()=>await tz(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 m("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await N("snapshot_capture",async()=>await e0(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 m("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let rW=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function rJ(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new m("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function rz(e){let t=rB(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await rH(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new m("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof m)throw t;throw new m("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function rH(e){try{return await _.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new m("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new m("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new m("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new m("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function rX(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await rY(t)}async function rY(e){await new Promise(t=>setTimeout(t,e))}let rK={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}},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}},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}},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 rZ(e,t){let r=rK[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function rQ(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function r0(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let r1=/^-?\d+(\.\d+)?$/,r2=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),r3=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function r4(e){return"click"===e||"press"===e}function r5(e){let t=e.trim();return t.startsWith("@")||r1.test(t)?t:JSON.stringify(t)}function r8(e,t){let r=t.flags??{};if(r4(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function r6(e,t){let r=[],i={},n=r4(e)?r2:"swipe"===e?r3:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(r4(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class r9{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=r9.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}}(t.flags),result:t.result}),D({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=i.dirname(t);E.existsSync(r)||E.mkdirSync(r,{recursive:!0});let n=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(r4(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(r5(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(r5(i)),r8(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(r5(r)),r8(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(r5(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(r5(i)),n&&t.push(r5(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(r5(r)),t.push(r5(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(r5(r))}return t.join(" ")}}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",r5(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(r5(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(r5(r));return r8(t,e),t.join(" ")}(a));return`${r.join("\n")}
22
+ `}(e,this.buildOptimizedActions(e));E.writeFileSync(t,n)}catch{}}defaultTracePath(e){let t=r9.safeSessionName(e.name),r=new Date().toISOString().replace(/[:.]/g,"-");return i.join(this.sessionsDir,`${t}-${r}.trace.log`)}resolveAppLogPath(e){return i.join(this.sessionsDir,r9.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return i.join(this.sessionsDir,r9.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?i.join(C.homedir(),e.slice(2)):t&&!i.isAbsolute(e)?i.resolve(t,e):i.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return r9.expandHome(e.saveScriptPath);E.existsSync(this.sessionsDir)||E.mkdirSync(this.sessionsDir,{recursive:!0});let t=r9.safeSessionName(e.name),r=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-");return i.join(this.sessionsDir,`${t}-${r}.ad`)}buildOptimizedActions(e){let t=[];for(let r of e.actions){if("snapshot"===r.command)continue;let i=Array.isArray(r.result?.selectorChain)&&r.result?.selectorChain.every(e=>"string"==typeof e)?r.result.selectorChain:[];if(i.length>0&&(r4(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(r4(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=rQ(r);if(i.length>0){t.push({...r,positionals:[e,i]});continue}}if("get"===r.command){let i=r.positionals?.[0];if("text"===i||"attrs"===i){t.push({...r,positionals:[i,e]});continue}}}if(r4(r.command)||"fill"===r.command||"get"===r.command){let i=r.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push({ts:r.ts,command:"snapshot",positionals:[],flags:{platform:e.device.platform,snapshotInteractiveOnly:!0,snapshotCompact:!0,snapshotScope:i.trim()},result:{scope:i.trim()}})}t.push(r)}return t}}function r7(e,t,r,i,n){return{requestId:n??b().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 ie=tu(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function it(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:rm}));await t(e);return}if("device"===e.kind)return void await ir(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:eo}));await t(e.id)}}async function ir(e){let t=i.join(C.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(ie/1e3));try{let i=await c("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:ie+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await ii(t);if(0===i.exitCode){if(!o.parsed)throw new m("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 m("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 m("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:ia(n,a)})}catch(t){if(t instanceof m&&"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??ie),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 m("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?ia(i,n):o},t)}throw new m("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 _.rm(t,{force:!0}).catch(()=>{})}}async function ii(e){try{let t=await _.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 ia(e,t){let r=tE(e,t);return r||(`${e}
23
+ ${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":tO)}function io(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function is(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function il(e,t){return e.find(e=>e.ref===t)??null}function id(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function ic(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 iu(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&&ip(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||!ip(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&&ip(r)?r:void 0)}function ip(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function im(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=ih(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&ip(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 ih(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 iw(e,t){let r=ih(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 ig(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let iv=new Set(["id","role","text","label","value"]),iI=new Set(["visible","hidden","editable","selected","enabled","hittable"]),iy=new Set([...iv,...iI]);function iA(e){let t=e.trim();if(!t)throw new m("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)&&!iG(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 m("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new m("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new m("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new m("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)&&!iG(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 m("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new m("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(iM)}})(e))}}function iS(e){try{return iA(e)}catch{return null}}function ib(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||!iL(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=iF(e),a=iF(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 iN(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)&&iL(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 iD(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 i_(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 iy.has(e)}return iy.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&iS(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 ik(e){let t=e[0]??"",r=i_(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function ix(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function iO(e,t){return iw(e.type??"",t)&&!1!==e.enabled}function iE(e,t,r={}){let i=[],n=ih(e.type??""),a=i$(e.identifier),o=i$(e.label),s=i$(e.value),l=i$(ig(e)),d="fill"===r.action;a&&i.push(`id=${iP(a)}`),n&&o&&i.push(d?`role=${iP(n)} label=${iP(o)} editable=true`:`role=${iP(n)} label=${iP(o)}`),o&&i.push(d?`label=${iP(o)} editable=true`:`label=${iP(o)}`),s&&i.push(d?`value=${iP(s)} editable=true`:`value=${iP(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${iP(l)} editable=true`:`text=${iP(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${iP(n)} editable=true`);let c=r0(i);return 0===c.length&&n&&c.push(d?`role=${iP(n)} editable=true`:`role=${iP(n)}`),0===c.length&&ix(e)&&c.push("visible=true"),c}function iM(e){let t=e.trim();if(!t)throw new m("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!iI.has(r))throw new m("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(!iy.has(i))throw new m("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new m("INVALID_ARGS",`Missing selector value for key: ${i}`);if(iI.has(i)){let e,t="true"===(e=iC(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new m("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:iC(n)}}function iL(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return iR(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return ih(e)}(i??"")===function(e){return ih(e)}(n);case"label":return iR(e.label,String(t.value));case"value":return iR(e.value,String(t.value));case"text":{let r=iT(String(t.value));return iT(ig(e))===r}case"visible":return ix(e)===!!t.value;case"hidden":return!ix(e)==!!t.value;case"editable":return iO(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 iC(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function iR(e,t){return iT(e??"")===iT(t)}function iT(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function iP(e){return JSON.stringify(e)}function i$(e){if(!e)return null;let t=e.trim();return t||null}function iF(e){return e.rect?e.rect.width*e.rect.height:1/0}function iG(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}function iV(e,t){let r=process.env[e];if(!r)return t;let i=Number.parseInt(r,10);return Number.isInteger(i)&&i>0?i:t}function iU(e,t){if(!e)return;let r=i.dirname(e);E.existsSync(r)||E.mkdirSync(r,{recursive:!0});let a={pid:t,startTime:O(t)??void 0,command:n(t)??void 0};E.writeFileSync(e,`${JSON.stringify(a)}
24
+ `)}function iB(e){if(e&&E.existsSync(e))try{E.unlinkSync(e)}catch{}}function ij(e){let t=i.dirname(e);E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),function(e,t){if(E.existsSync(e)&&!(E.statSync(e).size<t.maxBytes))for(let r=t.maxRotatedFiles;r>=1;r-=1){let t=1===r?e:`${e}.${r-1}`,i=`${e}.${r}`;E.existsSync(t)&&(E.existsSync(i)&&E.unlinkSync(i),E.renameSync(t,i))}}(e,{maxBytes:iV("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:iV("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function iq(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function iW(e){await new Promise(t=>setTimeout(t,e))}function iJ(e,t){let r=t.includeTokens?.filter(e=>e.length>0)??[],i="",n=i=>{(!(r.length>0)||r.some(e=>i.includes(e)))&&e.write(function(e,t){if(0===t.length)return e;let r=e;for(let e of t)r=r.replace(e,"[REDACTED]");return r}(i,t.redactionPatterns))};return{onChunk:e=>{let t=`${i}${e}`.split("\n");for(let e of(i=t.pop()??"",t))n(`${e}
25
+ `)},flush:()=>{i&&(n(i),i="")}}}function iz(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function iH(e,t){let r=(await c("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function iX(e,t,r,i){let n="active",a=p("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=iJ(t,{redactionPatterns:r});"number"==typeof a.pid&&iU(i,a.pid);let s=iz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iB(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iq(s),a.killed||a.kill("SIGKILL"),await iq(s),iB(i)}}}async function iY(e,t,r,i){let n="active",a=p("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=iJ(t,{redactionPatterns:r});"number"==typeof a.pid&&iU(i,a.pid);let s=iz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iB(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iq(s),a.killed||a.kill("SIGKILL"),await iq(s),iB(i)}}}async function iK(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await iH(e,t);if(!d){await iW(1e3);continue}let c=p("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=c;let u=iJ(r,{redactionPatterns:i});o=iz(c,r,{endStreamOnClose:!1,writer:u}),"number"==typeof c.pid&&iU(n,c.pid);let f=await o;if(iB(n),a=void 0,o=void 0,l)break;0!==f.exitCode&&(s="failed"),await iW(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),iB(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await iq(o),a&&!a.killed&&a.kill("SIGKILL"),await iq(d),iB(n)}}}async function iZ(e,t,r,i){ij(r);let n=E.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await iY(e.id,n,a,i):await iX(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new m("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await iK(e.id,t,n,a,i)}throw n.end(),new m("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function iQ(e){await e.stop(),await iq(e.wait)}async function i0(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await c("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await c("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await c("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await c("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function i1(e){let t=i.dirname(e),r=i.basename(e);E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),E.existsSync(e)?E.truncateSync(e,0):E.writeFileSync(e,"","utf8");let n=0;for(let e of E.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{E.unlinkSync(i.join(t,e)),n+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:n}}let i2=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),i3=/https?:\/\/[^\s"'<>\])]+/i,i4=[/\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 i5(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 i8(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return i6(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 i6(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function i9(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function i7(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let ne='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nt=["platform","target","device","udid","serial","verbose","out"],nr=["platform","target","device","udid","serial","verbose","out"],ni=["path","start","stop","doctor","mark","clear"],nn=`logs requires ${ni.slice(0,-1).join(", ")}, or ${ni.at(-1)}`,na="Not implemented for this platform in this release.",no="open-command-roundtrip";function ns(e){let{sessionName:t,appName:r,appBundleId:i,startup:n}=e,a={session:t};return r&&(a.appName=r),i&&(a.appBundleId=i),n&&(a.startup=n),a}function nl(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:no,appTarget:t,appBundleId:r}}let nd=["dump","log"],nc=`network requires ${nd.join(" or ")}`,nu=["summary","headers","body","all"],np=`network include mode must be one of: ${nu.join(", ")}`;function nf(e,t,r){return t||nm(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nm(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nh(e){let t=nm(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}let nw={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:rD}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e$}));return await i(e,t,r)}};async function ng(e,t,r){if("ios"===e.platform&&t)return es(t)?"device"===e.kind?el(r,t):void 0:await nv(e,t)}async function nv(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rI}));return await r(e,t)}catch{return}}async function nI(e,t){if(!("android"!==e.platform||!t||es(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eN})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function ny(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=P(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=nf("appstate",o,s);if(d)return d;let c=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nm(e))return!0;let r=P(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&&!c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:ne}};if(c){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{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 u=await nh({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===u.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:ne}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eO})),f=await p(u);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function nA(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},c=nf("clipboard",l,d);if(c)return c;let u=(t.positionals?.[0]??"").toLowerCase();if("read"!==u&&"write"!==u)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nh({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!rZ("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,{...r7(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 nS(e){var t;let{req:r,sessionName:i,logPath:n,sessionStore:a,invoke:o,dispatch:s,ensureReady:l,resolveTargetDevice:d,reinstallOps:c=nw,stopIosRunner:u,appLogOps:p={start:iZ,stop:iQ},resolveAndroidPackageForOpen:h=nI}=e,w=s??rq,g=l??it,v=d??rj,I=r.command;if("session_list"===I)return{ok:!0,data:{sessions:a.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}))}};if("devices"===I)try{let e=[],t=P(r.flags?.platform);if("android"===t){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:en}));e.push(...await t())}else if("ios"===t){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tS}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:en})),{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:tS}));try{e.push(...await t())}catch{}try{e.push(...await r())}catch{}}let i=r.flags?.target?e.filter(e=>(e.target??"mobile")===r.flags?.target):e;return{ok:!0,data:{devices:i}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===I){let e=a.get(i),t=r.flags??{},n=nf(I,e,t);if(n)return n;let o=await nh({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});if(!rZ("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=r.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:rM}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:eD}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===I){let e=a.get(i),t=r.flags??{},n=nf(I,e,t);if(n)return n;let o=await nh({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});return rZ("boot",o)?{ok:!0,data:{platform:o.platform,target:o.target??"mobile",device:o.name,id:o.id,kind:o.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===I)return await ny({req:r,sessionName:i,sessionStore:a,ensureReady:g,resolveDevice:v});if("clipboard"===I)return await nA({req:r,sessionName:i,logPath:n,sessionStore:a,ensureReady:g,resolveDevice:v,dispatch:w});if("perf"===I){let e,t,r,n=a.get(i);return n?{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===no&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:no,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)}(n.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:no,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:no},{session:n.name,platform:n.device.platform,device:n.device.name,deviceId:n.device.id,metrics:{startup:r,fps:{available:!1,reason:na},memory:{available:!1,reason:na},cpu:{available:!1,reason:na}},sampling:{startup:{method:no,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("reinstall"===I){let e,t=a.get(i),n=r.flags??{},o=nf(I,t,n);if(o)return o;let s=r.positionals?.[0]?.trim(),l=r.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let d=r9.expandHome(l);if(!E.existsSync(d))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${d}`}};let u=await nh({session:t,flags:n,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!1});if(!rZ("reinstall",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===u.platform){let t=await c.ios(u,s,d);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await c.android(u,s,d);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:d,...e};return t&&a.recordAction(t,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:p}),{ok:!0,data:p}}if("push"===I){let e,t=a.get(i),o=r.flags??{},s=nf(I,t,o);if(s)return s;let l=r.positionals?.[0]?.trim(),d=r.positionals?.[1]?.trim();if(!l||!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let c="file"===(e=rB(d,{subject:"Push payload",cwd:r.meta?.cwd,expandPath:(e,t)=>r9.expandHome(e,t)})).kind?e.path:e.text,u=await nh({session:t,flags:o,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});if(!rZ("push",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"push is not supported on this device"}};let p=await w(u,"push",[l,c],r.flags?.out,{...r7(n,r.flags,t?.appBundleId,t?.trace?.outPath)});return t&&a.recordAction(t,{command:I,positionals:[l,d],flags:r.flags??{},result:p??{}}),{ok:!0,data:p??{}}}if("open"===I){let e=r.flags?.relaunch===!0;if(a.has(i)){let o=a.get(i),s=r.positionals?.[0],l=s??(e?o?.appName:void 0);if(!o||!l)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&&es(l))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await g(o.device);let d=await ng(o.device,l,o.appBundleId)??await h(o.device,l)??((t=o.device,"android"===t.platform&&l&&es(l))?o.appBundleId:void 0),c=s?r.positionals??[]:[l];if(e){let e=d??l;await w(o.device,"close",[e],r.flags?.out,{...r7(n,r.flags,d??o.appBundleId,o.trace?.outPath)})}let u=Date.now();await w(o.device,"open",c,r.flags?.out,{...r7(n,r.flags,d)});let p=nl(u,l,d),f={...o,appBundleId:d,appName:l,recordSession:o.recordSession||!!r.flags?.saveScript,snapshot:void 0},m=ns({sessionName:i,appName:l,appBundleId:d,startup:p});return a.recordAction(f,{command:I,positionals:c,flags:r.flags??{},result:m}),a.set(i,f),{ok:!0,data:m}}let o=r.positionals?.[0];if(e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&o&&es(o))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let s=await v(r.flags??{}),l=a.toArray().find(e=>e.device.id===s.id);if(l)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${l.name}".`,details:{session:l.name,deviceId:s.id,deviceName:s.name}}};await g(s);let d=await ng(s,o)??await h(s,o);if(e&&o){let e=d??o;await w(s,"close",[e],r.flags?.out,{...r7(n,r.flags,d)})}let c=Date.now();await w(s,"open",r.positionals??[],r.flags?.out,{...r7(n,r.flags,d)});let u=o?nl(c,o,d):void 0,p={name:i,device:s,createdAt:Date.now(),appBundleId:d,appName:o,recordSession:!!r.flags?.saveScript,actions:[]},f=ns({sessionName:i,appName:o,appBundleId:d,startup:u});return a.recordAction(p,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:f}),a.set(i,p),{ok:!0,data:f}}if("replay"===I){let e=r.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=r9.expandHome(e,r.meta?.cwd),s=E.readFileSync(t,"utf8"),l=s.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 m("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(r4(i)){let e=r6(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 nE(r)&&nE(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=r6(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}(s),c=r.flags?.replayUpdate===!0,u=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await o({token:r.token,session:i,command:s.command,positionals:s.positionals??[],flags:n_(r.flags,s.flags),meta:r.meta});if(l.ok)continue;if(!c)return nD(l,s,e,t);let p=await nk({action:s,sessionName:i,logPath:n,sessionStore:a,dispatch:w});if(!p)return nD(l,s,e,t);if(d[e]=p,!(l=await o({token:r.token,session:i,command:p.command,positionals:p.positionals??[],flags:n_(r.flags,p.flags),meta:r.meta})).ok)return nD(l,p,e,t);u+=1}if(c&&u>0){let e=a.get(i);!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",r5(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(r5(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(r5(r));return r8(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
26
+ `,a=`${e}.tmp-${process.pid}-${Date.now()}`;E.writeFileSync(a,n),E.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:u,session:i}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===I){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(r.positionals?.[0]??"path").toLowerCase(),n=!!r.flags?.restart;if(!ni.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:nn}};if(n&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=a.resolveAppLogPath(i),r=function(e){if(!E.existsSync(e))return{exists:!1,sizeBytes:0};let t=E.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),n=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:n,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=a.resolveAppLogPath(i),r=await i0(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=r.positionals?.slice(1).join(" ")??"",n=a.resolveAppLogPath(i);return ij(n),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
27
+ `,E.appendFileSync(n,e,"utf8"),{ok:!0,data:{path:n,marked:!0}}}if("clear"===t){if(e.appLog&&!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(n){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!rZ("logs",e.device))return{ok:!1,error:y(new m("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=a.resolveAppLogPath(i);if(n){e.appLog&&await p.stop(e.appLog);let r=i1(t),n=a.resolveAppLogPidPath(i);try{let o=await p.start(e.device,e.appBundleId,t,n),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return a.set(i,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=y(r);return a.set(i,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:i1(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(!rZ("logs",e.device))return{ok:!1,error:y(new m("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=a.resolveAppLogPath(i),r=a.resolveAppLogPidPath(i);try{let n=await p.start(e.device,e.appBundleId,t,r),o={...e,appLog:{platform:e.device.platform,backend:n.backend,outPath:t,startedAt:n.startedAt,getState:n.getState,stop:n.stop,wait:n.wait}};return a.set(i,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:y(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 p.stop(e.appLog),a.set(i,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===I){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(r.positionals?.[0]??"dump").toLowerCase();if(!nd.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:nc}};let n=r.positionals?.[1],o=n?Number.parseInt(n,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(r.positionals?.[2]??"summary").toLowerCase();if(!nu.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:np}};let l=function(e,t){let r=i7(t?.maxEntries,25,1,200),i=t?.include??"summary",n=i7(t?.maxPayloadChars,2048,64,16384),a=i7(t?.maxScanLines,4e3,100,2e4);if(!E.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=E.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=i5(n,["method","httpMethod"]),o=i5(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=i2.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),c=(a??d?.[1]??l?.[1])?.toUpperCase(),u=i3.exec(e),p=o??u?.[0];if(!p)return null;let f={method:c,url:p,status:s??function(e){for(let t of i4){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:i9(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 i6(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=i9(t,i))}if("body"===r||"all"===r){let t=i8(e,n,["requestBody","body","payload","request"]),r=i8(e,n,["responseBody","response"]);t&&(f.requestBody=i9(t,i)),r&&(f.responseBody=i9(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}}}(a.resolveAppLogPath(i),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),c=[];return e.appLog||c.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&c.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:c}}}if("batch"===I)return await nb(r,i,o);if("close"===I){let e=a.get(i);return e?(e.appLog&&await p.stop(e.appLog),r.positionals&&r.positionals.length>0&&await w(e.device,"close",r.positionals??[],r.flags?.out,{...r7(n,r.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??tK)(e.device.id),a.recordAction(e,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:{session:i}}),r.flags?.saveScript&&(e.recordSession=!0),a.writeSessionLog(e),a.delete(i),{ok:!0,data:{session:i}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function nb(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??k;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=a(e.flags?.batchSteps,n),o=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await nN(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-o,results:s}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function nN(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 nt)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 nD(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>r5(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 n_(e,t){let r={...t??{}},i=e??{};for(let e of nr)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function nk(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(r4(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=r4(t.command)||"fill"===t.command,l=r4(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await nx(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),r4(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}=ik(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=nO(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 r0(t).filter(e=>e.trim().length>0)}(t)){let r=iS(e);if(!r)continue;let i=ib(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=iE(i.node,o.device.platform,{action:r4(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(r4(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=rQ(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}=ik(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}=nO(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let c=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=iS(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(ih(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=ig(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(ih(e.type??"")))});if(0===s.length||1!==r0(s.map(e=>ig(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=iE(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return c||null}async function nx(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...r7(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:io(t.flags?.snapshotRaw?s:im(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function nO(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=i_(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 nE(e){return!!e&&!Number.isNaN(Number(e))}function nM(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function nL(e,t){let r=I(e.type??"Element"),i=u(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 nC(e,t){return t.flatten?e.map(e=>({text:T(e,0,!1),comparable:nL(e,0)})):w(e).map(e=>({text:e.text,comparable:nL(e.node,e.depth)}))}function nR(e,t){return e.get(t)??0}async function nT(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??rq,o=t.command;if("snapshot"===o){let{session:e,device:o}=await nF(n,r,t.flags);if(!rZ("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=n$(t.flags?.snapshotScope,e);return s.ok?await nG(e,o,async()=>{let l=e?.appBundleId,d=await nP({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),c=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return nV(n,c,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,c),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:c.appBundleId?c.appName??c.appBundleId:void 0,appBundleId:c.appBundleId}}}):s.response}if("diff"===o){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 nF(n,r,t.flags);if(!rZ("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=n$(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await nG(e,o,async()=>{let d=e?.appBundleId,c=(await nP({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return nC(e,t).length}(c.nodes,{flatten:l}),a=e?{...e,snapshot:c}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:c,actions:[]};return nV(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 u=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&&nR(a,n-1)<nR(a,n+1)?nR(a,n+1):nR(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&&nR(n,l-1)<nR(n,l+1)?l+1:l-1,c=nR(n,d),u=c-d;for(;o>c&&s>u;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===c?(a.push({kind:"added",text:r[u].text}),s=u):(a.push({kind:"removed",text:t[c].text}),o=c)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(nC(e,r),nC(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,c.nodes,{flatten:l}),p={...e,snapshot:c};return nV(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:u.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:u.summary,lines:u.lines}}})}if("wait"===o){let{session:e,device:o}=await nF(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=nM(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=nM(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=nM(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=nM(e[e.length-1]),i=i_(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=iS(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)),nV(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):rZ("wait",o)?await nG(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,{...r7(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),c=l?.nodes??[],u=io(t.flags?.snapshotRaw?c:im(c));e&&(e.snapshot={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=iN(u,s.selector,{platform:o.platform});if(p)return nV(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=is(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=il(e.snapshot.nodes,t),i=r?iu(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 c=d??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===o.platform){let r=await tz(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 nV(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}}}else if("android"===o.platform&&ic(io((await e0(o,{scope:l})).nodes??[]),l))return nV(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}};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"===o){let{session:e,device:a}=await nF(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return rZ("alert",a)?await nG(e,a,async()=>{if("wait"===o){let r=nM(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await tz(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return nV(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=await tz(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return nV(n,e,t,r),{ok:!0,data:r}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){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:l}};let{session:s,device:d}=await nF(n,r,t.flags);return rZ("settings",d)?await nG(s,d,async()=>{let r=s?.appBundleId,l="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],c=await rq(d,"settings",l,t.flags?.out,{...r7(i,t.flags,r,s?.trace?.outPath)});return nV(n,s,t,c??{setting:e,state:a}),{ok:!0,data:c??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function nP(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...r7(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:io(n.flags?.snapshotRaw?l:im(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function n$(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=is(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=il(t.snapshot.nodes,r),n=i?iu(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 nF(e,t,r){let i=e.get(t),n=i?.device??await rj(r??{});return i||await it(n),{session:i,device:n}}async function nG(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await tK(t.id)}}function nV(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function nU(e,t,r,i={}){let n=nj(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 nB(e.label,r);case"value":return nB(e.value,r);case"id":return nB(e.identifier,r);default:return Math.max(nB(e.label,r),nB(e.value,r),nB(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 nB(e,t){let r=nj(e??"");return r?r===t?2:+!!r.includes(t):0}function nj(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function nq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:c,value:u,timeoutMs:p}=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 m("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:nM(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 m("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"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=f?.device??await rj(t.flags??{});f||await it(h);let w=f?.appBundleId,g="role"!==l?d:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,I=0,y=null,A=async()=>{let e=Date.now();if(y&&e-I<750)return{nodes:y};let a=await rq(h,"snapshot",[],t.flags?.out,{...r7(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,f?.trace?.outPath)}),o=a?.nodes??[],s=io(t.flags?.snapshotRaw?o:im(o));return I=e,y=s,f&&(f.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,f)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await A();if(nU(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,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:S}=await A(),b=nU(S,l,d,{requireRect:v});if(v&&b.matches.length>1){let e=b.matches.slice(0,8).map(e=>{let t=ig(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${b.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:b.matches.length,candidates:e}}}}let N=b.matches[0]??null;if(!N)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}(S,N)??N:N,_=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=ig(N);return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"get text",text:e}}),{ok:!0,data:{ref:_,text:e,node:N}}}if("get_attrs"===c)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"get attrs"}}),{ok:!0,data:{ref:_,node:N}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[_],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"click"}}),e}if("fill"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[_,u],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"fill"}}),e}if("focus"===c){let e=N.rect?id(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await rq(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"focus"}}),{ok:!0,data:r??{ref:_}}}if("type"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=N.rect?id(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await rq(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await rq(h,"type",[u],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"type"}}),{ok:!0,data:r??{ref:_}}}return null}function nW(e){return e instanceof Error?e.message:String(e)}function nJ(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function nz(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function nH(e){let{req:t,sessionName:r,sessionStore:n,logPath:a}=e,o=e.deps??{runCmd:c,runCmdBackground:s,runIosRunnerCommand:tz},l=t.command;if("record"===l){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let s=n.get(r),c=s?.device??await rj(t.flags??{});s||await it(c);let p=s??{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 s=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!rZ("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?nJ(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=r9.expandHome(s,t.meta?.cwd);E.mkdirSync(i.dirname(m),{recursive:!0});let h=nz(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,i=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await i()}catch(e){if(!nW(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nW(e)}`}};{var d,u;D({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:nW(e)}});let t=(d=c.id,u=p.name,n.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===d&&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},h)}catch{}try{await i()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nW(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",["simctl","io",c.id,"recordVideo",m],{allowFailure:!0});p.recording={platform:"ios",outPath:m,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,remotePath:e,child:t,wait:r}}return n.set(r,p),n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:s}}}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=nJ(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},nz(t,a,p))}catch(e){D({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:nW(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of tR)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}return n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===l){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=n.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]??n.defaultTracePath(a),r=r9.expandHome(e);return E.mkdirSync(i.dirname(r),{recursive:!0}),E.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},n.recordAction(a,{command:l,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=r9.expandHome(t.positionals[1]);E.mkdirSync(i.dirname(e),{recursive:!0}),E.existsSync(o)?E.renameSync(o,e):E.appendFileSync(e,""),o=e}return a.trace=void 0,n.recordAction(a,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function nX(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function nY(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 nK(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function nZ(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??rq,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(!rZ("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=n1("press",t.flags);if(r)return r;let s=n2({session:e,refInput:d,fallbackLabel:t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!s.ok)return s.response;let{ref:c,node:u,snapshotNodes:p}=s.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has no bounds`}};let f=iu(u,p),m=iE(u,e.device.platform,{action:l}),{x:h,y:w}=id(u.rect),g=await a(e.device,"press",[String(h),String(w)],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:h,y:w,refLabel:f,selectorChain:m}}),{ok:!0,data:{...g??{},ref:c,x:h,y:w}}}let c=(t.positionals??[]).join(" ").trim();if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let u=iA(c),p=await nQ(e,t.flags,i,n,{interactiveOnly:!0},a),f=await N("selector_resolve",()=>ib(p.nodes,u,{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:iD(u,f?.diagnostics??[],{unique:!0})}};let{x:m,y:h}=id(f.node.rect),w=await a(e.device,"press",[String(m),String(h)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=iE(f.node,e.device.platform,{action:l}),v=iu(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:m,y:h,selector:f.selector.raw,selectorChain:g,refLabel:v}}),{ok:!0,data:{...w??{},selector:f.selector.raw,x:m,y:h}}}if("fill"===o){let e=i.get(r);if(e&&!rZ("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=n1("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=n2({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:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=u.type??"",m=f&&!iw(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iu(u,p),w=iE(u,e.device.platform,{action:"fill"}),{x:g,y:v}=id(u.rect),I={...await a(e.device,"fill",[String(g),String(v),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:c,x:g,y:v}};return m&&(I.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...I,refLabel:h,selectorChain:w}}),{ok:!0,data:I}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=i_(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=iA(s.selectorExpression),d=await nQ(e,t.flags,i,n,{interactiveOnly:!0},a),c=await N("selector_resolve",()=>ib(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(l,c?.diagnostics??[],{unique:!0})}};let u=c.node,p=u.type??"",f=p&&!iw(p,e.device.platform)?`fill target ${c.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=id(c.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=iE(u,e.device.platform,{action:"fill"}),v={...w??{x:m,y:h,text:r},selector:c.selector.raw,selectorChain:g,refLabel:iu(u,d.nodes)};return f&&(v.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:v}),{ok:!0,data:v}}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(!rZ("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=n1("get",t.flags);if(r)return r;let n=n2({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,c=iE(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:c}}),{ok:!0,data:{ref:a,node:d}};let u=ig(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:u,refLabel:u||void 0,selectorChain:c}}),{ok:!0,data:{ref:a,text:u,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 c=iA(d),u=await nQ(s,t.flags,i,n,{interactiveOnly:!1},a),p=await N("selector_resolve",()=>ib(u.nodes,c,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(c,[],{unique:!0})}};let f=p.node,m=iE(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=ig(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(!rZ("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=ik(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 c=iA(l.selectorExpression),u=await nQ(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=iN(u.nodes,c,{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:c.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:iD(c,[],{unique:!1})}}}let p=await N("selector_resolve",()=>ib(u.nodes,c,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=ig(r),o=!1;switch(t){case"visible":o=ix(r);break;case"hidden":o=!ix(r);break;case"editable":o=iO(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:ix(r),editable:iO(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:c.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(!rZ("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=n1("scrollintoview",t.flags);if(l)return l;let d=n2({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:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=id(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=nY(n.map(e=>e.rect).filter(e=>nX(e,r.x,r.y)));if(a)return a;let o=nY(n.map(e=>e.rect));if(o)return o;let s=nY(i.map(e=>e.rect).filter(e=>nX(e,r.x,r.y)));return s||null}(p,u.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,c=o+.25*n,u=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=c&&f<=u)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),v=Math.max(1,Math.abs(w-g));return f>u?{x:h,startY:w,endY:g,count:nK(Math.ceil((f-u)/v),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:nK(Math.ceil((c-f)/v),1,50),direction:"up"}}(u.rect,f),h=iu(u,p),w=iE(u,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:c,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:c,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:c,attempts:m.count,direction:m.direction}}}return null}async function nQ(e,t,r,i,n,a=rq){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:io(t?.snapshotRaw?s:im(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let n0=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function n1(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of n0)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 n2(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=is(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=il(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=ic(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}}}}let n3=i.join(C.homedir(),".agent-device"),n4=i.join(n3,"daemon.json"),n5=i.join(n3,"daemon.lock"),n8=i.join(n3,"daemon.log"),n6=i.join(n3,"sessions");var n9=n6;if(E.existsSync(n9))for(let e of E.readdirSync(n9,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=i.join(n9,e.name,"app-log.pid");if(E.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}}(E.readFileSync(t,"utf8"));if(e&&function(e){let t,r=O(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=n(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{iB(t)}}let n7=new r9(n6),ae=A(),at=d.randomBytes(24).toString("hex"),ar=new Set(["session_list","devices"]),ai=O(process.pid)??void 0,an=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=E.statSync(e),r=S(),n=i.relative(r,e)||e;return`${n}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function aa(e,t,r){let i=b().requestId;return{...r7(n8,e,t,r,i),requestId:i}}async function ao(e){let t=!!(e.meta?.debug||e.flags?.verbose);return await M({session:e.session,requestId:e.meta?.requestId,command:e.command,debug:t,logPath:n8},async()=>{if(e.token!==at)return{ok:!1,error:y(new m("UNAUTHORIZED","Invalid token"))};D({level:"info",phase:"request_start",data:{session:e.session,command:e.command}});try{var t;let r=(t=e,"click"!==t.command?t:{...t,command:"press"}),i=r.command,n=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}(r,n7),a=n7.get(n);a&&!ar.has(i)&&function(e,t){if(!t)return;let r=[],i=e.device,n=P(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}`),0!==r.length){var a;let t,i,n;throw new m("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.`)}}(a,r.flags);let o=await nS({req:r,sessionName:n,logPath:n8,sessionStore:n7,invoke:ao});if(o)return as(o);let s=await nT({req:r,sessionName:n,logPath:n8,sessionStore:n7});if(s)return as(s);let l=await nH({req:e,sessionName:n,sessionStore:n7,logPath:n8});if(l)return as(l);let d=await nq({req:r,sessionName:n,logPath:n8,sessionStore:n7,invoke:ao});if(d)return as(d);let c=await nZ({req:r,sessionName:n,sessionStore:n7,contextFromFlags:aa});if(c)return as(c);let u=n7.get(n);if(!u)return as({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!rZ(i,u.device))return as({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${i} is not supported on this device`}});let p=await rq(u.device,i,r.positionals??[],r.flags?.out,{...aa(r.flags,u.appBundleId,u.trace?.outPath)});return n7.recordAction(u,{command:i,positionals:r.positionals??[],flags:r.flags??{},result:p??{}}),as({ok:!0,data:p??{}})}catch(r){D({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=b(),t=L({force:!0})??void 0;return{ok:!1,error:y(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function as(e){let t=b();if(!e.ok){D({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=L({force:!0})??void 0;return{ok:!1,error:y(new m(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return D({level:"info",phase:"request_success"}),L(),e}function al(){if(!E.existsSync(n5))return null;try{let e=JSON.parse(E.readFileSync(n5,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}!function(){if(!function(){E.existsSync(n3)||E.mkdirSync(n3,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:ae,startedAt:Date.now(),processStartTime:ai},null,2),t=()=>{try{return E.writeFileSync(n5,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=al();if(r?.pid&&r.pid!==process.pid&&o(r.pid,r.processStartTime))return!1;try{E.unlinkSync(n5)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let e=R.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&tL.add(e);D({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await tZ(),!(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,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(i.add(s),tC(s)))throw new m("COMMAND_FAILED","request canceled");n=await ao(e)}catch(e){n={ok:!1,error:y(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&tL.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
28
+ `),a=t.indexOf("\n")}})});e.listen(0,"127.0.0.1",()=>{let t=e.address();if("object"==typeof t&&t?.port){var r;r=t.port,E.existsSync(n3)||E.mkdirSync(n3,{recursive:!0}),E.writeFileSync(n8,""),E.writeFileSync(n4,JSON.stringify({port:r,token:at,pid:process.pid,version:ae,codeSignature:an,processStartTime:ai},null,2),{mode:384}),process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${t.port}
29
+ `)}});let t=!1,r=async()=>{await new Promise(t=>{try{e.close(()=>t())}catch{t()}})},i=async()=>{if(t)return;for(let e of(t=!0,await r(),n7.toArray()))n7.writeSessionLog(e);await tQ(),E.existsSync(n4)&&E.unlinkSync(n4);let e=al();if(!e||e.pid===process.pid)try{E.existsSync(n5)&&E.unlinkSync(n5)}catch{}process.exit(0)};process.on("SIGINT",()=>{i()}),process.on("SIGTERM",()=>{i()}),process.on("SIGHUP",()=>{i()}),process.on("uncaughtException",e=>{let t=e instanceof m?e:f(e);process.stderr.write(`Daemon error: ${t.message}
30
+ `),i()})}();