agent-device 0.2.6 → 0.3.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.
- package/dist/bin/axsnapshot +0 -0
- package/dist/src/daemon.js +8 -6
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -2
- package/package.json +2 -2
- package/src/platforms/android/__tests__/index.test.ts +74 -0
- package/src/platforms/android/index.ts +47 -293
- package/src/platforms/android/ui-hierarchy.ts +312 -0
- package/src/platforms/ios/runner-client.ts +115 -55
package/dist/bin/axsnapshot
CHANGED
|
Binary file
|
package/dist/src/daemon.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
let e,t;import i from"node:crypto";import{isCancel as r,select as a}from"@clack/prompts";import{node_path as n,runCmdStreaming as o,promises as s,asAppError as l,fileURLToPath as c,runCmdBackground as u,node_fs as d,node_os as f,errors_AppError as p,runCmd as m,node_net as h,whichCmd as w}from"./861.js";async function g(e,t){let i=e,n=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(t.platform&&(i=i.filter(e=>e.platform===t.platform)),t.udid){let e=i.find(e=>e.id===t.udid&&"ios"===e.platform);if(!e)throw new p("DEVICE_NOT_FOUND",`No iOS device with UDID ${t.udid}`);return e}if(t.serial){let e=i.find(e=>e.id===t.serial&&"android"===e.platform);if(!e)throw new p("DEVICE_NOT_FOUND",`No Android device with serial ${t.serial}`);return e}if(t.deviceName){let e=n(t.deviceName),r=i.find(t=>n(t.name)===e);if(!r)throw new p("DEVICE_NOT_FOUND",`No device named ${t.deviceName}`);return r}if(1===i.length)return i[0];if(0===i.length)throw new p("DEVICE_NOT_FOUND","No devices found",{selector:t});let o=i.filter(e=>e.booted);if(1===o.length)return o[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await a({message:"Multiple devices available. Choose a device to continue:",options:(o.length>0?o:i).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(r(e))throw new p("INVALID_ARGS","Device selection cancelled");if(e){let t=i.find(t=>t.id===e);if(t)return t}}return o[0]??i[0]}async function v(){if(!await w("adb"))throw new p("TOOL_MISSING","adb not found in PATH");let e=(await m("adb",["devices","-l"])).stdout.split("\n").map(e=>e.trim()),t=[];for(let i of e){if(!i||i.startsWith("List of devices"))continue;let e=i.split(/\s+/),r=e[0];if("device"!==e[1])continue;let a=(e.find(e=>e.startsWith("model:"))??"").replace("model:","").replace(/_/g," ").trim()||r;if(r.startsWith("emulator-")){let e=await m("adb",["-s",r,"emu","avd","name"],{allowFailure:!0}),t=e.stdout.trim();0===e.exitCode&&t&&(a=t.replace(/_/g," "))}let n=await y(r);t.push({platform:"android",id:r,name:a,kind:r.startsWith("emulator-")?"emulator":"device",booted:n})}return t}async function y(e){try{let t=await m("adb",["-s",e,"shell","getprop","sys.boot_completed"],{allowFailure:!0});return"1"===t.stdout.trim()}catch{return!1}}async function A(e,t=6e4){let i=Date.now();for(;Date.now()-i<t;){if(await y(e))return;await new Promise(e=>setTimeout(e,1e3))}throw new p("COMMAND_FAILED","Android device did not finish booting in time",{serial:e,timeoutMs:t})}async function I(e,t={}){let i,r=t.attempts??3,a=t.baseDelayMs??200,n=t.maxDelayMs??2e3,o=t.jitter??.2;for(let s=1;s<=r;s+=1)try{return await e()}catch(l){if(i=l,s>=r||t.shouldRetry&&!t.shouldRetry(l,s))break;let e=function(e,t,i,r){let a=Math.min(t,e*2**(r-1));return Math.max(0,a+a*i*(2*Math.random()-1))}(a,n,o,s);await function(e){return new Promise(t=>setTimeout(t,e))}(e)}if(i)throw i;throw new p("COMMAND_FAILED","retry failed")}let b={settings:{type:"intent",value:"android.settings.SETTINGS"}};function N(e,t){return["-s",e.id,...t]}async function k(e,t){let i=t.trim();if(i.includes("."))return{type:"package",value:i};let r=b[i.toLowerCase()];if(r)return r;let a=(await m("adb",N(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===a.length)return{type:"package",value:a[0]};if(a.length>1)throw new p("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:a});throw new p("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function S(e,t="launchable"){if("launchable"===t){let t=await m("adb",N(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER"]),{allowFailure:!0});if(0===t.exitCode&&t.stdout.trim().length>0){let e=new Set;for(let i of t.stdout.split("\n")){let t=i.trim();if(!t)continue;let r=t.split(/\s+/)[0],a=r.includes("/")?r.split("/")[0]:r;a&&e.add(a)}if(e.size>0)return Array.from(e)}}return(await m("adb",N(e,"user-installed"===t?["shell","pm","list","packages","-3"]:["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function D(e,t="launchable"){let i=await S(e,t),r=new Set("launchable"===t?i:await S(e,"launchable"));return i.map(e=>({package:e,launchable:r.has(e)}))}async function x(e){let t=await L(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let i=await L(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return i||{}}async function L(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 m("adb",N(e,i),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function _(e,t,i){e.booted||await A(e.id);let r=await k(e,t);if("intent"===r.type){if(i)throw new p("INVALID_ARGS","Activity override requires a package name, not an intent");await m("adb",N(e,["shell","am","start","-a",r.value]));return}if(i){let t=i.includes("/")?i:`${r.value}/${i.startsWith(".")?i:`.${i}`}`;await m("adb",N(e,["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-n",t]));return}await m("adb",N(e,["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-p",r.value]))}async function O(e){e.booted||await A(e.id)}async function P(e,t){if("settings"===t.trim().toLowerCase())return void await m("adb",N(e,["shell","am","force-stop","com.android.settings"]));let i=await k(e,t);if("intent"===i.type)throw new p("INVALID_ARGS","Close requires a package name, not an intent");await m("adb",N(e,["shell","am","force-stop",i.value]))}async function M(e,t,i){await m("adb",N(e,["shell","input","tap",String(t),String(i)]))}async function R(e){await m("adb",N(e,["shell","input","keyevent","4"]))}async function C(e){await m("adb",N(e,["shell","input","keyevent","3"]))}async function E(e){await m("adb",N(e,["shell","input","keyevent","187"]))}async function $(e,t,i,r=800){await m("adb",N(e,["shell","input","swipe",String(t),String(i),String(t),String(i),String(r)]))}async function F(e,t){let i=t.replace(/ /g,"%s");await m("adb",N(e,["shell","input","text",i]))}async function T(e,t,i){await M(e,t,i)}async function V(e,t,i,r){await T(e,t,i);let a=null;for(let s of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:4,delayMs:0},{clearPadding:24,minClear:16,maxClear:96,chunkSize:1,delayMs:15}]){var n,o;let l=(n=r.length+s.clearPadding,o=s.minClear,Math.max(o,Math.min(s.maxClear,n)));if(await K(e,l),await Y(e,r,s.chunkSize,s.delayMs),(a=await Z(e,t,i))===r)return}throw new p("COMMAND_FAILED","Android fill verification failed",{expected:r,actual:a??null})}async function B(e,t,i=.6){let{width:r,height:a}=await J(e),n=Math.floor(r*i),o=Math.floor(a*i),s=Math.floor(r/2),l=Math.floor(a/2),c=s,u=l,d=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":c=s-Math.floor(n/2),d=s+Math.floor(n/2);break;case"right":c=s+Math.floor(n/2),d=s-Math.floor(n/2);break;default:throw new p("INVALID_ARGS",`Unknown direction: ${t}`)}await m("adb",N(e,["shell","input","swipe",String(c),String(u),String(d),String(f),"300"]))}async function j(e,t){for(let i=0;i<8;i+=1){let i="";try{i=await H(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new p("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let i=t.toLowerCase(),r=/<node[^>]+>/g,a=r.exec(e);for(;a;){let t=a[0],n=/text="([^"]*)"/.exec(t),o=/content-desc="([^"]*)"/.exec(t),s=(n?.[1]??"").toLowerCase(),l=(o?.[1]??"").toLowerCase();if(s.includes(i)||l.includes(i)){let e=/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/.exec(t);if(e){let t=Number(e[1]),i=Number(e[2]);return{x:Math.floor((t+Number(e[3]))/2),y:Math.floor((i+Number(e[4]))/2)}}return{x:0,y:0}}a=r.exec(e)}return null}(i,t))return;await B(e,"down",.5)}throw new p("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function G(e,t){let i=await m("adb",N(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!i.stdoutBuffer)throw new p("COMMAND_FAILED","Failed to capture screenshot");await s.writeFile(t,i.stdoutBuffer)}async function U(e,t,i){let r=t.toLowerCase(),a=function(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 p("INVALID_ARGS",`Invalid setting state: ${e}`)}(i);switch(r){case"wifi":return void await m("adb",N(e,["shell","svc","wifi",a?"enable":"disable"]));case"airplane":await m("adb",N(e,["shell","settings","put","global","airplane_mode_on",a?"1":"0"])),await m("adb",N(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",a?"true":"false"]));return;case"location":return void await m("adb",N(e,["shell","settings","put","secure","location_mode",a?"3":"0"]));default:throw new p("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function q(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,a=r.exec(e);for(;a;){let t=a[0];if(t.startsWith("</node")){i.length>1&&i.pop(),a=r.exec(e);continue}let n=et(t),o=ei(n.bounds),s=i[i.length-1],l={type:n.className,label:n.text||n.desc,value:n.text,identifier:n.resourceId,rect:o,enabled:n.enabled,hittable:n.clickable??n.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||i.push(l),a=r.exec(e)}return t}(e),a=[],n=!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()??"",a=e.value?.toLowerCase()??"",n=e.identifier?.toLowerCase()??"";if(t.includes(i)||a.includes(i)||n.includes(i))return e;r.push(...e.children)}return null}(r,i.scope):null,l=s?[s]:r.children,c=new Map,u=e=>{let t=c.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||u(t))return c.set(e,!0),!0;return c.set(e,!1),!1},d=(e,t,r,s=!1,l=!1)=>{var c,f,p,m,h,w;let g,v,y,A,I,b,N,k;if(a.length>=800){n=!0;return}if(t>o)return;let S=!!i.raw||(c=e,f=i,p=s,m=u(e),h=l,v=er(c.type),y=!!(c.label&&c.label.trim().length>0),A=!!(c.identifier&&c.identifier.trim().length>0),I=y&&!ea(c.label??""),b=A&&!ea(c.identifier??""),N=(g=(w=v).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,k="imageview"===v||"imagebutton"===v,f.interactiveOnly?!!c.hittable||!!(I||b)&&!k&&(!N||!!h)&&(p||m||h):f.compact?I||b||!!c.hittable:!N&&!k||!!c.hittable||!!I||!!b&&!!m||m),D=r;S&&(D=a.length,a.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 x=s||!!e.hittable,L=l||function(e){if(!e)return!1;let t=er(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let i of e.children)if(d(i,t+1,D,x,L),n)return};for(let e of l)if(d(e,0,void 0,!1,!1),n)break;return n?{nodes:a,truncated:n}:{nodes:a}}(await H(e),800,t)}async function W(){if(!await w("adb"))throw new p("TOOL_MISSING","adb not found in PATH")}async function J(e){let t=(await m("adb",N(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new p("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function H(e){return I(()=>z(e),{shouldRetry:X})}async function z(e){return await m("adb",N(e,["shell","uiautomator","dump","/sdcard/window_dump.xml"])),(await m("adb",N(e,["shell","cat","/sdcard/window_dump.xml"]))).stdout}function X(e){if(!(e instanceof p)||"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"))}async function Y(e,t,i,r){let a=Math.max(1,Math.floor(i));for(let i=0;i<t.length;i+=a){let n=t.slice(i,i+a);await F(e,n),r>0&&i+a<t.length&&await ee(r)}}async function K(e,t){let i=Math.max(0,t);await m("adb",N(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 m("adb",N(e,["shell","input","keyevent",...Array(r).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function Z(e,t,i){let r,a=await H(e),n=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(r=n.exec(a));){let e=et(r[0]),a=ei(e.bounds);if(!a)continue;let n=e.className??"",c=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!c)continue;let d=Math.max(1,a.width*a.height),f=t>=a.x&&t<=a.x+a.width&&i>=a.y&&i<=a.y+a.height;if(u&&Q(n)){(!o||d<=o.area)&&(o={text:c,area:d});continue}if(f&&Q(n)){(!s||d<=s.area)&&(s={text:c,area:d});continue}f&&(!l||d<=l.area)&&(l={text:c,area:d})}return o?.text??s?.text??l?.text??null}function Q(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function ee(e){await new Promise(t=>setTimeout(t,e))}function et(e){let t=t=>{let i=RegExp(`${t}="([^"]*)"`).exec(e);return i?i[1]:null},i=e=>{let i=t(e);if(null!==i)return"true"===i};return{text:t("text"),desc:t("content-desc"),resourceId:t("resource-id"),className:t("class"),bounds:t("bounds"),clickable:i("clickable"),enabled:i("enabled"),focusable:i("focusable"),focused:i("focused")}}function ei(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 er(e){return e?e.toLowerCase():""}function ea(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}async function en(){if("darwin"!==process.platform)throw new p("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await w("xcrun"))throw new p("TOOL_MISSING","xcrun not found in PATH");let e=[],t=await m("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 p("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(await w("xcrun"))try{let t=await m("xcrun",["devicectl","list","devices","--json"]);for(let i of JSON.parse(t.stdout).devices??[])i.platform?.toLowerCase().includes("ios")&&e.push({platform:"ios",id:i.identifier,name:i.name,kind:"device",booted:!0})}catch{}return e}let eo={settings:"com.apple.Preferences"};async function es(e,t){let i=t.trim();if(i.includes("."))return i;let r=eo[i.toLowerCase()];if(r)return r;if("simulator"===e.kind){let r=(await ep(e)).filter(e=>e.name.toLowerCase()===i.toLowerCase());if(1===r.length)return r[0].bundleId;if(r.length>1)throw new p("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:r})}throw new p("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function el(e,t){let i=await es(e,t);if("simulator"===e.kind){await em(e),await m("open",["-a","Simulator"],{allowFailure:!0}),await m("xcrun",["simctl","launch",e.id,i]);return}await m("xcrun",["devicectl","device","process","launch","--device",e.id,i])}async function ec(e){"simulator"!==e.kind||"Booted"!==await eh(e.id)&&(await em(e),await m("open",["-a","Simulator"],{allowFailure:!0}))}async function eu(e,t){let i=await es(e,t);if("simulator"===e.kind){await em(e);let t=await m("xcrun",["simctl","terminate",e.id,i],{allowFailure:!0});if(0!==t.exitCode){if(t.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new p("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 m("xcrun",["devicectl","device","process","terminate","--device",e.id,i])}async function ed(e,t){if("simulator"===e.kind){await em(e),await m("xcrun",["simctl","io",e.id,"screenshot",t]);return}await m("xcrun",["devicectl","device","screenshot","--device",e.id,t])}async function ef(e,t,i,r){(function(e,t){if("simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators in v1`)})(e,"settings"),await em(e);let a=t.toLowerCase(),n=function(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 p("INVALID_ARGS",`Invalid setting state: ${e}`)}(i);switch(a){case"wifi":return void await m("xcrun",["simctl","status_bar",e.id,"override","--wifiMode",n?"active":"failed"]);case"airplane":n?await m("xcrun",["simctl","status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await m("xcrun",["simctl","status_bar",e.id,"clear"]);return;case"location":if(!r)throw new p("INVALID_ARGS","location setting requires an active app in session");await m("xcrun",["simctl","privacy",e.id,n?"grant":"revoke","location",r]);return;default:throw new p("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function ep(e){let t=(await m("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 m("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})):[]}async function em(e){"simulator"!==e.kind||"Booted"!==await eh(e.id)&&(await m("xcrun",["simctl","boot",e.id],{allowFailure:!0}),await m("xcrun",["simctl","bootstatus",e.id,"-b"],{allowFailure:!0}))}async function eh(e){let t=await m("xcrun",["simctl","list","devices","-j"],{allowFailure:!0});if(0!==t.exitCode)return null;try{let i=JSON.parse(t.stdout);for(let t of Object.values(i.devices??{})){let i=t.find(t=>t.udid===e);if(i)return i.state}}catch{}return null}let ew=new Map;async function eg(e,t,i={}){var r;return"snapshot"===(r=t.command)||"findText"===r||"listTappables"===r||"alert"===r?I(()=>ev(e,t,i),{shouldRetry:eS}):ev(e,t,i)}async function ev(e,t,i={}){if("simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION","iOS runner only supports simulators in v1");try{let r=await eI(e,i),a=await eD(e,r.port,t,i.logPath),n=await a.text(),o={};try{o=JSON.parse(n)}catch{throw new p("COMMAND_FAILED","Invalid runner response",{text:n})}if(!o.ok)throw new p("COMMAND_FAILED",o.error?.message??"Runner error",{runner:o,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:i.logPath});return o.data??{}}catch(a){let r=a instanceof p?a:new p("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===r.code&&"string"==typeof r.message&&r.message.includes("Runner did not accept connection")){await ey(e.id);let r=await eI(e,i),a=await eD(e,r.port,t,i.logPath),n=await a.text(),o={};try{o=JSON.parse(n)}catch{throw new p("COMMAND_FAILED","Invalid runner response",{text:n})}if(!o.ok)throw new p("COMMAND_FAILED",o.error?.message??"Runner error",{runner:o,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:i.logPath});return o.data??{}}throw a}}async function ey(e){let t=ew.get(e);if(t){try{await eD(t.device,t.port,{command:"shutdown"})}catch{}try{await t.testPromise}catch{}eO(t.xctestrunPath),eO(t.jsonPath),ew.delete(e)}}async function eA(e){await m("xcrun",["simctl","bootstatus",e,"-b"],{allowFailure:!0})}async function eI(e,t){let i=ew.get(e.id);if(i)return i;await eA(e.id);let r=await eb(e.id,t),a=await eL(),{xctestrunPath:n,jsonPath:s}=await e_(r,{AGENT_DEVICE_RUNNER_PORT:String(a)},`session-${e.id}-${a}`),l=o("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-maximum-concurrent-test-simulator-destinations","1","-xctestrun",n,"-destination",`platform=iOS Simulator,id=${e.id}`],{onStdoutChunk:e=>{ek(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{ek(e,t.logPath,t.traceLogPath,t.verbose)},allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(a)}}),c={device:e,deviceId:e.id,port:a,xctestrunPath:n,jsonPath:s,testPromise:l};return ew.set(e.id,c),c}async function eb(e,t){let i,r=n.join(f.homedir(),".agent-device","ios-runner"),a=n.join(r,"derived");if((i=process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)&&["1","true","yes","on"].includes(i.toLowerCase()))try{d.rmSync(a,{recursive:!0,force:!0})}catch{}let s=eN(a);if(s)return s;let l=function(){let e=n.dirname(c(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(d.existsSync(e))return t;t=n.dirname(t)}return e}(),u=n.join(l,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!d.existsSync(u))throw new p("COMMAND_FAILED","iOS runner project not found",{projectPath:u});try{await o("xcodebuild",["build-for-testing","-project",u,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO","-maximum-concurrent-test-simulator-destinations","1","-destination",`platform=iOS Simulator,id=${e}`,"-derivedDataPath",a],{onStdoutChunk:e=>{ek(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{ek(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(i){let e=i instanceof p?i:new p("COMMAND_FAILED",String(i));throw new p("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:e.message,details:e.details,logPath:t.logPath})}let m=eN(a);if(!m)throw new p("COMMAND_FAILED","Failed to locate .xctestrun after build");return m}function eN(e){if(!d.existsSync(e))return null;let t=[],i=[e];for(;i.length>0;){let e=i.pop();for(let r of d.readdirSync(e,{withFileTypes:!0})){let a=n.join(e,r.name);if(r.isDirectory()){i.push(a);continue}if(r.isFile()&&r.name.endsWith(".xctestrun"))try{let e=d.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 ek(e,t,i,r){t&&d.appendFileSync(t,e),i&&d.appendFileSync(i,e),r&&process.stderr.write(e)}function eS(e){if(!(e instanceof p)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}async function eD(e,t,i,r){let a=Date.now(),n=null;for(;Date.now()-a<15e3;)try{return await fetch(`http://127.0.0.1:${t}/command`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})}catch(e){n=e,await new Promise(e=>setTimeout(e,100))}if("simulator"===e.kind){let r=await ex(e.id,t,i);return new Response(r.body,{status:r.status})}throw new p("COMMAND_FAILED","Runner did not accept connection",{port:t,logPath:r,lastError:n?String(n):void 0})}async function ex(e,t,i){let r=JSON.stringify(i),a=await m("xcrun",["simctl","spawn",e,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",r,`http://127.0.0.1:${t}/command`],{allowFailure:!0}),n=a.stdout;if(0!==a.exitCode)throw new p("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});return{status:200,body:n}}async function eL(){return await new Promise((e,t)=>{let i=h.createServer();i.listen(0,"127.0.0.1",()=>{let r=i.address();i.close(),"object"==typeof r&&r?.port?e(r.port):t(new p("COMMAND_FAILED","Failed to allocate port"))}),i.on("error",t)})}async function e_(e,t,i){let r,a=n.dirname(e),o=i.replace(/[^a-zA-Z0-9._-]/g,"_"),s=n.join(a,`AgentDeviceRunner.env.${o}.json`),l=n.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),c=await m("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==c.exitCode||!c.stdout.trim())throw new p("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:c.stderr});try{r=JSON.parse(c.stdout)}catch(t){throw new p("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}},f=r.TestConfigurations;if(Array.isArray(f))for(let e of f){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(r))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),r[e]=t);d.writeFileSync(s,JSON.stringify(r,null,2));let h=await m("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==h.exitCode)throw new p("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:h.stderr});return{xctestrunPath:l,jsonPath:s}}function eO(e){try{d.existsSync(e)&&d.unlinkSync(e)}catch{}}async function eP(e,t={}){let i,r;if("ios"!==e.platform||"simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION","AX snapshot is only supported on iOS simulators");let a=await eM(),n=await I(async()=>{var e,i;let r,n,o,s=await m(a,[],{allowFailure:!0});if(t.traceLogPath&&(e=t.traceLogPath,r=((i=s).stdout??"").toString(),n=(i.stderr??"").toString(),o=`
|
|
1
|
+
let e,t;import i from"node:crypto";import{isCancel as r,select as a}from"@clack/prompts";import{node_path as n,runCmdStreaming as o,promises as s,asAppError as l,fileURLToPath as c,runCmdBackground as u,node_fs as d,node_os as f,errors_AppError as p,runCmd as m,node_net as h,whichCmd as w}from"./861.js";async function g(e,t){let i=e,n=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(t.platform&&(i=i.filter(e=>e.platform===t.platform)),t.udid){let e=i.find(e=>e.id===t.udid&&"ios"===e.platform);if(!e)throw new p("DEVICE_NOT_FOUND",`No iOS device with UDID ${t.udid}`);return e}if(t.serial){let e=i.find(e=>e.id===t.serial&&"android"===e.platform);if(!e)throw new p("DEVICE_NOT_FOUND",`No Android device with serial ${t.serial}`);return e}if(t.deviceName){let e=n(t.deviceName),r=i.find(t=>n(t.name)===e);if(!r)throw new p("DEVICE_NOT_FOUND",`No device named ${t.deviceName}`);return r}if(1===i.length)return i[0];if(0===i.length)throw new p("DEVICE_NOT_FOUND","No devices found",{selector:t});let o=i.filter(e=>e.booted);if(1===o.length)return o[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await a({message:"Multiple devices available. Choose a device to continue:",options:(o.length>0?o:i).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(r(e))throw new p("INVALID_ARGS","Device selection cancelled");if(e){let t=i.find(t=>t.id===e);if(t)return t}}return o[0]??i[0]}async function v(){if(!await w("adb"))throw new p("TOOL_MISSING","adb not found in PATH");let e=(await m("adb",["devices","-l"])).stdout.split("\n").map(e=>e.trim()),t=[];for(let i of e){if(!i||i.startsWith("List of devices"))continue;let e=i.split(/\s+/),r=e[0];if("device"!==e[1])continue;let a=(e.find(e=>e.startsWith("model:"))??"").replace("model:","").replace(/_/g," ").trim()||r;if(r.startsWith("emulator-")){let e=await m("adb",["-s",r,"emu","avd","name"],{allowFailure:!0}),t=e.stdout.trim();0===e.exitCode&&t&&(a=t.replace(/_/g," "))}let n=await y(r);t.push({platform:"android",id:r,name:a,kind:r.startsWith("emulator-")?"emulator":"device",booted:n})}return t}async function y(e){try{let t=await m("adb",["-s",e,"shell","getprop","sys.boot_completed"],{allowFailure:!0});return"1"===t.stdout.trim()}catch{return!1}}async function A(e,t=6e4){let i=Date.now();for(;Date.now()-i<t;){if(await y(e))return;await new Promise(e=>setTimeout(e,1e3))}throw new p("COMMAND_FAILED","Android device did not finish booting in time",{serial:e,timeoutMs:t})}async function I(e,t={}){let i,r=t.attempts??3,a=t.baseDelayMs??200,n=t.maxDelayMs??2e3,o=t.jitter??.2;for(let s=1;s<=r;s+=1)try{return await e()}catch(l){if(i=l,s>=r||t.shouldRetry&&!t.shouldRetry(l,s))break;let e=function(e,t,i,r){let a=Math.min(t,e*2**(r-1));return Math.max(0,a+a*i*(2*Math.random()-1))}(a,n,o,s);await function(e){return new Promise(t=>setTimeout(t,e))}(e)}if(i)throw i;throw new p("COMMAND_FAILED","retry failed")}function b(e){let t=N(e),i=e=>{let i=k(t,e);if(null!==i)return"true"===i};return{text:k(t,"text"),desc:k(t,"content-desc"),resourceId:k(t,"resource-id"),className:k(t,"class"),bounds:k(t,"bounds"),clickable:i("clickable"),enabled:i("enabled"),focusable:i("focusable"),focused:i("focused")}}function N(e){let t=new Map,i=e.indexOf(" "),r=e.lastIndexOf(">");if(i<0||r<=i)return t;let a=/([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/y,n=i;for(;n<r;){for(;n<r;){let t=e[n];if(" "!==t&&"\n"!==t&&"\r"!==t&&" "!==t)break;n+=1}if(n>=r)break;let i=e[n];if("/"===i||">"===i)break;a.lastIndex=n;let o=a.exec(e);if(!o)break;t.set(o[1],o[3]),n=a.lastIndex}return t}function k(e,t){return e.get(t)??null}function S(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 D(e){return e?e.toLowerCase():""}function x(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}let L={settings:{type:"intent",value:"android.settings.SETTINGS"}};function _(e,t){return["-s",e.id,...t]}async function O(e,t){let i=t.trim();if(i.includes("."))return{type:"package",value:i};let r=L[i.toLowerCase()];if(r)return r;let a=(await m("adb",_(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===a.length)return{type:"package",value:a[0]};if(a.length>1)throw new p("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:a});throw new p("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function M(e,t="launchable"){if("launchable"===t){let t=await m("adb",_(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c","android.intent.category.LAUNCHER"]),{allowFailure:!0});if(0===t.exitCode&&t.stdout.trim().length>0){let e=new Set;for(let i of t.stdout.split("\n")){let t=i.trim();if(!t)continue;let r=t.split(/\s+/)[0],a=r.includes("/")?r.split("/")[0]:r;a&&e.add(a)}if(e.size>0)return Array.from(e)}}return(await m("adb",_(e,"user-installed"===t?["shell","pm","list","packages","-3"]:["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function R(e,t="launchable"){let i=await M(e,t),r=new Set("launchable"===t?i:await M(e,"launchable"));return i.map(e=>({package:e,launchable:r.has(e)}))}async function P(e){let t=await C(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let i=await C(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return i||{}}async function C(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 m("adb",_(e,i),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function E(e,t,i){e.booted||await A(e.id);let r=await O(e,t);if("intent"===r.type){if(i)throw new p("INVALID_ARGS","Activity override requires a package name, not an intent");await m("adb",_(e,["shell","am","start","-a",r.value]));return}if(i){let t=i.includes("/")?i:`${r.value}/${i.startsWith(".")?i:`.${i}`}`;await m("adb",_(e,["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-n",t]));return}await m("adb",_(e,["shell","am","start","-a","android.intent.action.MAIN","-c","android.intent.category.DEFAULT","-c","android.intent.category.LAUNCHER","-p",r.value]))}async function $(e){e.booted||await A(e.id)}async function F(e,t){if("settings"===t.trim().toLowerCase())return void await m("adb",_(e,["shell","am","force-stop","com.android.settings"]));let i=await O(e,t);if("intent"===i.type)throw new p("INVALID_ARGS","Close requires a package name, not an intent");await m("adb",_(e,["shell","am","force-stop",i.value]))}async function T(e,t,i){await m("adb",_(e,["shell","input","tap",String(t),String(i)]))}async function V(e){await m("adb",_(e,["shell","input","keyevent","4"]))}async function B(e){await m("adb",_(e,["shell","input","keyevent","3"]))}async function j(e){await m("adb",_(e,["shell","input","keyevent","187"]))}async function G(e,t,i,r=800){await m("adb",_(e,["shell","input","swipe",String(t),String(i),String(t),String(i),String(r)]))}async function U(e,t){let i=t.replace(/ /g,"%s");await m("adb",_(e,["shell","input","text",i]))}async function q(e,t,i){await T(e,t,i)}async function W(e,t,i,r){await q(e,t,i);let a=null;for(let s of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:4,delayMs:0},{clearPadding:24,minClear:16,maxClear:96,chunkSize:1,delayMs:15}]){var n,o;let l=(n=r.length+s.clearPadding,o=s.minClear,Math.max(o,Math.min(s.maxClear,n)));if(await ea(e,l),await er(e,r,s.chunkSize,s.delayMs),(a=await en(e,t,i))===r)return}throw new p("COMMAND_FAILED","Android fill verification failed",{expected:r,actual:a??null})}async function J(e,t,i=.6){let{width:r,height:a}=await Z(e),n=Math.floor(r*i),o=Math.floor(a*i),s=Math.floor(r/2),l=Math.floor(a/2),c=s,u=l,d=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":c=s-Math.floor(n/2),d=s+Math.floor(n/2);break;case"right":c=s+Math.floor(n/2),d=s-Math.floor(n/2);break;default:throw new p("INVALID_ARGS",`Unknown direction: ${t}`)}await m("adb",_(e,["shell","input","swipe",String(c),String(u),String(d),String(f),"300"]))}async function H(e,t){for(let i=0;i<8;i+=1){let i="";try{i=await Q(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new p("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let i=t.toLowerCase(),r=/<node[^>]+>/g,a=r.exec(e);for(;a;){let t=N(a[0]),n=(k(t,"text")??"").toLowerCase(),o=(k(t,"content-desc")??"").toLowerCase();if(n.includes(i)||o.includes(i)){let e=S(k(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}}a=r.exec(e)}return null}(i,t))return;await J(e,"down",.5)}throw new p("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function z(e,t){let i=await m("adb",_(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!i.stdoutBuffer)throw new p("COMMAND_FAILED","Failed to capture screenshot");await s.writeFile(t,i.stdoutBuffer)}async function X(e,t,i){let r=t.toLowerCase(),a=function(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 p("INVALID_ARGS",`Invalid setting state: ${e}`)}(i);switch(r){case"wifi":return void await m("adb",_(e,["shell","svc","wifi",a?"enable":"disable"]));case"airplane":await m("adb",_(e,["shell","settings","put","global","airplane_mode_on",a?"1":"0"])),await m("adb",_(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",a?"true":"false"]));return;case"location":return void await m("adb",_(e,["shell","settings","put","secure","location_mode",a?"3":"0"]));default:throw new p("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function K(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,a=r.exec(e);for(;a;){let t=a[0];if(t.startsWith("</node")){i.length>1&&i.pop(),a=r.exec(e);continue}let n=b(t),o=S(n.bounds),s=i[i.length-1],l={type:n.className,label:n.text||n.desc,value:n.text,identifier:n.resourceId,rect:o,enabled:n.enabled,hittable:n.clickable??n.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||i.push(l),a=r.exec(e)}return t}(e),a=[],n=!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()??"",a=e.value?.toLowerCase()??"",n=e.identifier?.toLowerCase()??"";if(t.includes(i)||a.includes(i)||n.includes(i))return e;r.push(...e.children)}return null}(r,i.scope):null,l=s?[s]:r.children,c=new Map,u=e=>{let t=c.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||u(t))return c.set(e,!0),!0;return c.set(e,!1),!1},d=(e,t,r,s=!1,l=!1)=>{var c,f,p,m,h,w;let g,v,y,A,I,b,N,k;if(a.length>=800){n=!0;return}if(t>o)return;let S=!!i.raw||(c=e,f=i,p=s,m=u(e),h=l,v=D(c.type),y=!!(c.label&&c.label.trim().length>0),A=!!(c.identifier&&c.identifier.trim().length>0),I=y&&!x(c.label??""),b=A&&!x(c.identifier??""),N=(g=(w=v).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,k="imageview"===v||"imagebutton"===v,f.interactiveOnly?!!c.hittable||!!(I||b)&&!k&&(!N||!!h)&&(p||m||h):f.compact?I||b||!!c.hittable:!N&&!k||!!c.hittable||!!I||!!b&&!!m||m),L=r;S&&(L=a.length,a.push({index:L,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 _=s||!!e.hittable,O=l||function(e){if(!e)return!1;let t=D(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let i of e.children)if(d(i,t+1,L,_,O),n)return};for(let e of l)if(d(e,0,void 0,!1,!1),n)break;return n?{nodes:a,truncated:n}:{nodes:a}}(await Q(e),0,t)}async function Y(){if(!await w("adb"))throw new p("TOOL_MISSING","adb not found in PATH")}async function Z(e){let t=(await m("adb",_(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new p("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function Q(e){return I(()=>ee(e),{shouldRetry:ei})}async function ee(e){var t,i,r;let a,n,o=await m("adb",_(e,["exec-out","uiautomator","dump","/dev/tty"]),{allowFailure:!0});if(0===o.exitCode){let e=et(o.stdout,o.stderr);if(e)return e}let s="/sdcard/window_dump.xml",l=await m("adb",_(e,["shell","uiautomator","dump",s])),c=(t=s,i=l.stdout,r=l.stderr,a=`${i}
|
|
2
|
+
${r}`,n=/dumped to:\s*(\S+)/i.exec(a),n?.[1]??t),u=await m("adb",_(e,["shell","cat",c])),d=et(u.stdout,u.stderr);if(!d)throw new p("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:u.stdout,stderr:u.stderr});return d}function et(e,t){let i=`${e}
|
|
3
|
+
${t}`,r=i.indexOf("<?xml"),a=r>=0?r:i.indexOf("<hierarchy");if(a<0)return null;let n=i.lastIndexOf("</hierarchy>");if(n<0||n<a)return null;let o=i.slice(a,n+12).trim();return o.length>0?o:null}function ei(e){if(!(e instanceof p)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}async function er(e,t,i,r){let a=Math.max(1,Math.floor(i));for(let i=0;i<t.length;i+=a){let n=t.slice(i,i+a);await U(e,n),r>0&&i+a<t.length&&await es(r)}}async function ea(e,t){let i=Math.max(0,t);await m("adb",_(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 m("adb",_(e,["shell","input","keyevent",...Array(r).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function en(e,t,i){let r,a=await Q(e),n=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(r=n.exec(a));){let e=b(r[0]),a=S(e.bounds);if(!a)continue;let n=e.className??"",c=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!c)continue;let d=Math.max(1,a.width*a.height),f=t>=a.x&&t<=a.x+a.width&&i>=a.y&&i<=a.y+a.height;if(u&&eo(n)){(!o||d<=o.area)&&(o={text:c,area:d});continue}if(f&&eo(n)){(!s||d<=s.area)&&(s={text:c,area:d});continue}f&&(!l||d<=l.area)&&(l={text:c,area:d})}return o?.text??s?.text??l?.text??null}function eo(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function es(e){await new Promise(t=>setTimeout(t,e))}async function el(){if("darwin"!==process.platform)throw new p("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await w("xcrun"))throw new p("TOOL_MISSING","xcrun not found in PATH");let e=[],t=await m("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 p("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(await w("xcrun"))try{let t=await m("xcrun",["devicectl","list","devices","--json"]);for(let i of JSON.parse(t.stdout).devices??[])i.platform?.toLowerCase().includes("ios")&&e.push({platform:"ios",id:i.identifier,name:i.name,kind:"device",booted:!0})}catch{}return e}let ec={settings:"com.apple.Preferences"};async function eu(e,t){let i=t.trim();if(i.includes("."))return i;let r=ec[i.toLowerCase()];if(r)return r;if("simulator"===e.kind){let r=(await ew(e)).filter(e=>e.name.toLowerCase()===i.toLowerCase());if(1===r.length)return r[0].bundleId;if(r.length>1)throw new p("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:r})}throw new p("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function ed(e,t){let i=await eu(e,t);if("simulator"===e.kind){await eg(e),await m("open",["-a","Simulator"],{allowFailure:!0}),await m("xcrun",["simctl","launch",e.id,i]);return}await m("xcrun",["devicectl","device","process","launch","--device",e.id,i])}async function ef(e){"simulator"!==e.kind||"Booted"!==await ev(e.id)&&(await eg(e),await m("open",["-a","Simulator"],{allowFailure:!0}))}async function ep(e,t){let i=await eu(e,t);if("simulator"===e.kind){await eg(e);let t=await m("xcrun",["simctl","terminate",e.id,i],{allowFailure:!0});if(0!==t.exitCode){if(t.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new p("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 m("xcrun",["devicectl","device","process","terminate","--device",e.id,i])}async function em(e,t){if("simulator"===e.kind){await eg(e),await m("xcrun",["simctl","io",e.id,"screenshot",t]);return}await m("xcrun",["devicectl","device","screenshot","--device",e.id,t])}async function eh(e,t,i,r){(function(e,t){if("simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators in v1`)})(e,"settings"),await eg(e);let a=t.toLowerCase(),n=function(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 p("INVALID_ARGS",`Invalid setting state: ${e}`)}(i);switch(a){case"wifi":return void await m("xcrun",["simctl","status_bar",e.id,"override","--wifiMode",n?"active":"failed"]);case"airplane":n?await m("xcrun",["simctl","status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await m("xcrun",["simctl","status_bar",e.id,"clear"]);return;case"location":if(!r)throw new p("INVALID_ARGS","location setting requires an active app in session");await m("xcrun",["simctl","privacy",e.id,n?"grant":"revoke","location",r]);return;default:throw new p("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function ew(e){let t=(await m("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 m("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})):[]}async function eg(e){"simulator"!==e.kind||"Booted"!==await ev(e.id)&&(await m("xcrun",["simctl","boot",e.id],{allowFailure:!0}),await m("xcrun",["simctl","bootstatus",e.id,"-b"],{allowFailure:!0}))}async function ev(e){let t=await m("xcrun",["simctl","list","devices","-j"],{allowFailure:!0});if(0!==t.exitCode)return null;try{let i=JSON.parse(t.stdout);for(let t of Object.values(i.devices??{})){let i=t.find(t=>t.udid===e);if(i)return i.state}}catch{}return null}let ey=new Map,eA=eb(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,12e4,5e3),eI=eb(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,15e3,1e3);function eb(e,t,i){if(!e)return t;let r=Number(e);return Number.isFinite(r)?Math.max(i,Math.floor(r)):t}async function eN(e,t,i={}){var r;return"snapshot"===(r=t.command)||"findText"===r||"listTappables"===r||"alert"===r?I(()=>ek(e,t,i),{shouldRetry:eC}):ek(e,t,i)}async function ek(e,t,i={}){if("simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION","iOS runner only supports simulators in v1");try{let r=await e_(e,i),a=r.ready?eI:eA;return await eS(e,r,t,i.logPath,a)}catch(a){let r=a instanceof p?a:new p("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===r.code&&"string"==typeof r.message&&r.message.includes("Runner did not accept connection")){await ex(e.id);let r=await e_(e,i),a=await eE(r.device,r.port,t,i.logPath,eA);return await eD(a,r,i.logPath)}throw a}}async function eS(e,t,i,r,a){let n=await eE(e,t.port,i,r,a);return await eD(n,t,r)}async function eD(e,t,i){let r=await e.text(),a={};try{a=JSON.parse(r)}catch{throw new p("COMMAND_FAILED","Invalid runner response",{text:r})}if(!a.ok)throw new p("COMMAND_FAILED",a.error?.message??"Runner error",{runner:a,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:i});return t.ready=!0,a.data??{}}async function ex(e){let t=ey.get(e);if(t){try{await eE(t.device,t.port,{command:"shutdown"},void 0,15e3)}catch{await eO(t.child.pid,"SIGTERM")}try{await Promise.race([t.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await eO(t.child.pid,"SIGKILL"),eV(t.xctestrunPath),eV(t.jsonPath),ey.delete(e)}}async function eL(e){await m("xcrun",["simctl","bootstatus",e,"-b"],{allowFailure:!0})}async function e_(e,t){let i=ey.get(e.id);if(i)return i;await eL(e.id);let r=await eM(e.id,t),a=await eF(),{xctestrunPath:n,jsonPath:o}=await eT(r,{AGENT_DEVICE_RUNNER_PORT:String(a)},`session-${e.id}-${a}`),{child:s,wait:l}=u("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-maximum-concurrent-test-simulator-destinations","1","-xctestrun",n,"-destination",`platform=iOS Simulator,id=${e.id}`],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(a)}});s.stdout?.on("data",e=>{eP(e,t.logPath,t.traceLogPath,t.verbose)}),s.stderr?.on("data",e=>{eP(e,t.logPath,t.traceLogPath,t.verbose)});let c={device:e,deviceId:e.id,port:a,xctestrunPath:n,jsonPath:o,testPromise:l,child:s,ready:!1};return ey.set(e.id,c),c}async function eO(e,t){if(!e||e<=0)return;try{process.kill(e,t)}catch{}let i="SIGTERM"===t?"TERM":"KILL";try{await m("pkill",[`-${i}`,"-P",String(e)],{allowFailure:!0})}catch{}}async function eM(e,t){let i,r=n.join(f.homedir(),".agent-device","ios-runner"),a=n.join(r,"derived");if((i=process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)&&["1","true","yes","on"].includes(i.toLowerCase()))try{d.rmSync(a,{recursive:!0,force:!0})}catch{}let s=eR(a);if(s)return s;let l=function(){let e=n.dirname(c(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(d.existsSync(e))return t;t=n.dirname(t)}return e}(),u=n.join(l,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!d.existsSync(u))throw new p("COMMAND_FAILED","iOS runner project not found",{projectPath:u});try{await o("xcodebuild",["build-for-testing","-project",u,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO","-maximum-concurrent-test-simulator-destinations","1","-destination",`platform=iOS Simulator,id=${e}`,"-derivedDataPath",a],{onStdoutChunk:e=>{eP(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{eP(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(i){let e=i instanceof p?i:new p("COMMAND_FAILED",String(i));throw new p("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:e.message,details:e.details,logPath:t.logPath})}let m=eR(a);if(!m)throw new p("COMMAND_FAILED","Failed to locate .xctestrun after build");return m}function eR(e){if(!d.existsSync(e))return null;let t=[],i=[e];for(;i.length>0;){let e=i.pop();for(let r of d.readdirSync(e,{withFileTypes:!0})){let a=n.join(e,r.name);if(r.isDirectory()){i.push(a);continue}if(r.isFile()&&r.name.endsWith(".xctestrun"))try{let e=d.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 eP(e,t,i,r){t&&d.appendFileSync(t,e),i&&d.appendFileSync(i,e),r&&process.stderr.write(e)}function eC(e){if(!(e instanceof p)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}async function eE(e,t,i,r,a=eA){let n=Date.now(),o=null;for(;Date.now()-n<a;)try{return await fetch(`http://127.0.0.1:${t}/command`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})}catch(e){o=e,await new Promise(e=>setTimeout(e,100))}if("simulator"===e.kind){let r=await e$(e.id,t,i);return new Response(r.body,{status:r.status})}throw new p("COMMAND_FAILED","Runner did not accept connection",{port:t,logPath:r,lastError:o?String(o):void 0})}async function e$(e,t,i){let r=JSON.stringify(i),a=await m("xcrun",["simctl","spawn",e,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",r,`http://127.0.0.1:${t}/command`],{allowFailure:!0}),n=a.stdout;if(0!==a.exitCode)throw new p("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});return{status:200,body:n}}async function eF(){return await new Promise((e,t)=>{let i=h.createServer();i.listen(0,"127.0.0.1",()=>{let r=i.address();i.close(),"object"==typeof r&&r?.port?e(r.port):t(new p("COMMAND_FAILED","Failed to allocate port"))}),i.on("error",t)})}async function eT(e,t,i){let r,a=n.dirname(e),o=i.replace(/[^a-zA-Z0-9._-]/g,"_"),s=n.join(a,`AgentDeviceRunner.env.${o}.json`),l=n.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),c=await m("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==c.exitCode||!c.stdout.trim())throw new p("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:c.stderr});try{r=JSON.parse(c.stdout)}catch(t){throw new p("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}},f=r.TestConfigurations;if(Array.isArray(f))for(let e of f){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(r))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),r[e]=t);d.writeFileSync(s,JSON.stringify(r,null,2));let h=await m("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==h.exitCode)throw new p("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:h.stderr});return{xctestrunPath:l,jsonPath:s}}function eV(e){try{d.existsSync(e)&&d.unlinkSync(e)}catch{}}async function eB(e,t={}){let i,r;if("ios"!==e.platform||"simulator"!==e.kind)throw new p("UNSUPPORTED_OPERATION","AX snapshot is only supported on iOS simulators");let a=await ej(),n=await I(async()=>{var e,i;let r,n,o,s=await m(a,[],{allowFailure:!0});if(t.traceLogPath&&(e=t.traceLogPath,r=((i=s).stdout??"").toString(),n=(i.stderr??"").toString(),o=`
|
|
2
4
|
[axsnapshot] exit=${i.exitCode} stdoutBytes=${r.length} stderrBytes=${n.length}
|
|
3
5
|
`,d.appendFileSync(e,o),(0!==i.exitCode||n.length>0)&&(n.length>0&&d.appendFileSync(e,`${n}
|
|
4
6
|
`),0!==i.exitCode&&r.length>0&&d.appendFileSync(e,`${r}
|
|
5
|
-
`))),0!==s.exitCode){let e,t,i=(s.stderr??"").toString(),r=(e=i.toLowerCase()).includes("accessibility permission")?" Enable Accessibility for your terminal in System Settings > Privacy & Security > Accessibility, or use --backend xctest (slower snapshots via XCTest).":e.includes("could not find ios app content")?" AX snapshot sometimes caches empty content. Try restarting the Simulator app.":"",a=!!((t=i.toLowerCase()).includes("could not find ios app content")||t.includes("timeout"));throw new p("COMMAND_FAILED","AX snapshot failed",{stderr:`${i}${r}`,stdout:s.stdout,retryable:a})}return s},{shouldRetry:e=>{var t;return(t=e)instanceof p&&"COMMAND_FAILED"===t.code&&t.details?.retryable===!0}});try{let e=JSON.parse(n.stdout);if(e&&"object"==typeof e&&"root"in e){if(!e.root)throw Error("AX snapshot missing root");i=e.root,r=e.windowFrame??void 0}else i=e}catch(e){throw new p("COMMAND_FAILED","Invalid AX snapshot JSON",{error:String(e)})}let o=i.frame??r,s=[],l=[],c=(e,t)=>{e.frame&&s.push(e.frame);let i=e.frame&&o?{x:e.frame.x-o.x,y:e.frame.y-o.y,width:e.frame.width,height:e.frame.height}:e.frame;for(let r of(l.push({...e,frame:i,children:void 0,depth:t}),e.children??[]))c(r,t+1)};return c(i,0),{nodes:(function(e,t,i){if(!t||0===i.length)return e;let r=1/0,a=1/0;for(let e of i)e.x<r&&(r=e.x),e.y<a&&(a=e.y);return r<=5&&a<=5?e.map(e=>({...e,frame:e.frame?{x:e.frame.x+t.x,y:e.frame.y+t.y,width:e.frame.width,height:e.frame.height}:void 0})):e})(l,o,s).map((e,t)=>({index:t,type:e.subrole??e.role,label:e.label,value:e.value,identifier:e.identifier,rect:e.frame?{x:e.frame.x,y:e.frame.y,width:e.frame.width,height:e.frame.height}:void 0,depth:e.depth}))}}async function eM(){let e=function(){let e=n.dirname(c(import.meta.url));for(let t=0;t<6;t+=1){let t=n.join(e,"package.json");if(d.existsSync(t))return e;e=n.dirname(e)}return process.cwd()}(),t=n.join(e,"ios-runner","AXSnapshot"),i=process.env.AGENT_DEVICE_AX_BINARY;if(i&&d.existsSync(i))return i;let r=n.join(e,"dist","bin","axsnapshot");if(d.existsSync(r))return r;let a=n.join(t,".build","release","axsnapshot");if(d.existsSync(a))return a;let o=await m("swift",["build","-c","release"],{cwd:t,allowFailure:!0});if(0!==o.exitCode||!d.existsSync(a))throw new p("COMMAND_FAILED","Failed to build AX snapshot tool",{stderr:o.stderr,stdout:o.stdout});return a}async function eR(e){let t={platform:e.platform,deviceName:e.device,udid:e.udid,serial:e.serial};if("android"===t.platform){await W();let e=await v();return await g(e,t)}if("ios"===t.platform){let e=await en();return await g(e,t)}let i=[];try{i.push(...await v())}catch{}try{i.push(...await en())}catch{}return await g(i,t)}async function eC(e,t,i,r,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,i)=>_(e,t,i?.activity),openDevice:()=>O(e),close:t=>P(e,t),tap:(t,i)=>M(e,t,i),longPress:(t,i,r)=>$(e,t,i,r),focus:(t,i)=>T(e,t,i),type:t=>F(e,t),fill:(t,i,r)=>V(e,t,i,r),scroll:(t,i)=>B(e,t,i),scrollIntoView:t=>j(e,t),screenshot:t=>G(e,t)};case"ios":var i,r;let a;return{open:t=>el(e,t),openDevice:()=>ec(e),close:t=>eu(e,t),screenshot:t=>ed(e,t),...(i=e,a={verbose:(r=t).verbose,logPath:r.logPath,traceLogPath:r.traceLogPath},{tap:async(e,t)=>{await eg(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a)},longPress:async(e,t,n)=>{await eg(i,{command:"longPress",x:e,y:t,durationMs:n,appBundleId:r.appBundleId},a)},focus:async(e,t)=>{await eg(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a)},type:async e=>{await eg(i,{command:"type",text:e,appBundleId:r.appBundleId},a)},fill:async(e,t,n)=>{await eg(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a),await eg(i,{command:"type",text:n,clearFirst:!0,appBundleId:r.appBundleId},a)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new p("INVALID_ARGS",`Unknown direction: ${e}`);let n=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await eg(i,{command:"swipe",direction:n,appBundleId:r.appBundleId},a)},scrollIntoView:async e=>{for(let t=0;t<8;t+=1){let n=await eg(i,{command:"findText",text:e,appBundleId:r.appBundleId},a);if(n?.found)return{attempts:t+1};await eg(i,{command:"swipe",direction:"up",appBundleId:r.appBundleId},a),await new Promise(e=>setTimeout(e,300))}throw new p("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new p("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});switch(t){case"open":{let e=i[0];if(!e)return await o.openDevice(),{app:null};return await o.open(e,{activity:a?.activity}),{app:e}}case"close":{let e=i[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[e,t]=i.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new p("INVALID_ARGS","press requires x y");return await o.tap(e,t),{x:e,y:t}}case"long-press":{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 p("INVALID_ARGS","long-press 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 p("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 p("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 p("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 p("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 p("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":{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 p("INVALID_ARGS","pinch requires scale > 0");return await eg(e,{command:"pinch",scale:t,x:r,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{scale:t,x:r,y:n}}case"screenshot":{let e=i[0]??r??`./screenshot-${Date.now()}.png`;return await s.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e),{path:e}}case"back":if("ios"===e.platform)return await eg(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"back"};return await R(e),{action:"back"};case"home":if("ios"===e.platform)return await eg(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"home"};return await C(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await eg(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"app-switcher"};return await E(e),{action:"app-switcher"};case"settings":{let[t,r,n]=i;if("ios"===e.platform)return await ef(e,t,r,n??a?.appBundleId),{setting:t,state:r};return await U(e,t,r),{setting:t,state:r}}case"snapshot":{let t=a?.snapshotBackend??"xctest";if("ios"===e.platform){if("ax"===t)return{nodes:(await eP(e,{traceLogPath:a?.traceLogPath})).nodes??[],truncated:!1,backend:"ax"};let i=await eg(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}),r=i.nodes??[];if(0===r.length)try{return{nodes:(await eP(e,{traceLogPath:a?.traceLogPath})).nodes??[],truncated:!1,backend:"ax"}}catch{}return{nodes:r,truncated:i.truncated??!1,backend:"xctest"}}let i=await q(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw});return{nodes:i.nodes??[],truncated:i.truncated??!1,backend:"android"}}default:throw new p("INVALID_ARGS",`Unknown command: ${t}`)}}let eE={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},"long-press":{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}}};function e$(e,t){let i=eE[e];if(!i)return!0;let r=i[t.platform];return!!r&&!0===r[t.kind??"unknown"]}function eF(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 eT(e){let t=new Set,i=[];for(let r of e)t.has(r)||(t.add(r),i.push(r));return i}function eV(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class eB{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),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:a,out:n,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:c,snapshotScope:u,snapshotRaw:d,snapshotBackend:f,appsMetadata:p,saveScript:m,noRecord:h}=e;return{platform:t,device:i,udid:r,serial:a,out:n,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:c,snapshotScope:u,snapshotRaw:d,snapshotBackend:f,appsMetadata:p,saveScript:m,noRecord:h}}(t.flags),result:t.result}))}writeSessionLog(e){try{if(!e.recordSession)return;d.existsSync(this.sessionsDir)||d.mkdirSync(this.sessionsDir,{recursive:!0});let t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),i=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-"),r=n.join(this.sessionsDir,`${t}-${i}.ad`),a=function(e,t){let i=[],r=e.device.name.replace(/"/g,'\\"'),a=e.device.kind?` kind=${e.device.kind}`:"";for(let n of(i.push(`context platform=${e.device.platform} device="${r}"${a} theme=unknown`),t))n.flags?.noRecord||i.push(function(e){let t=[e.command];if("click"===e.command){let i=e.positionals?.[0];if(i){if(t.push(ej(i)),i.startsWith("@")){let i=e.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push(ej(i))}return t.join(" ")}}if("fill"===e.command){let i=e.positionals?.[0];if(i&&i.startsWith("@")){t.push(ej(i));let r=e.result?.refLabel,a=e.positionals.slice(1).join(" ");return"string"==typeof r&&r.trim().length>0&&t.push(ej(r)),a&&t.push(ej(a)),t.join(" ")}}if("get"===e.command){let i=e.positionals?.[0],r=e.positionals?.[1];if(i&&r){if(t.push(ej(i)),t.push(ej(r)),r.startsWith("@")){let i=e.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push(ej(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",ej(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),e.flags?.snapshotBackend&&t.push("--backend",e.flags.snapshotBackend),t.join(" ");for(let i of e.positionals??[])t.push(ej(i));return t.join(" ")}(n));return`${i.join("\n")}
|
|
6
|
-
`}(e,this.buildOptimizedActions(e));d.writeFileSync(r,a)}catch{}}defaultTracePath(e){let t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),i=new Date().toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${i}.trace.log`)}static expandHome(e){return e.startsWith("~/")?n.join(f.homedir(),e.slice(2)):n.resolve(e)}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&&("click"===i.command||"fill"===i.command||"get"===i.command)){let e=r.join(" || ");if("click"===i.command){t.push({...i,positionals:[e]});continue}if("fill"===i.command){let r=eF(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("click"===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}constructor(e){eV(this,"sessions",new Map),eV(this,"sessionsDir",void 0),this.sessionsDir=e}}function ej(e){let t=e.trim();return t.startsWith("@")||/^-?\d+(\.\d+)?$/.test(t)?t:JSON.stringify(t)}function eG(e,t,i,r){return{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,snapshotBackend:t?.snapshotBackend}}async function eU(e){if("ios"===e.platform&&"simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:em}));await t(e);return}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:A}));await t(e.id)}}function eq(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function eW(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function eJ(e,t){return e.find(e=>e.ref===t)??null}function eH(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function ez(e,t){let i=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),r=(e.value??"").toLowerCase(),a=(e.identifier??"").toLowerCase();return t.includes(i)||r.includes(i)||a.includes(i)})??null}function eX(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&&eY(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||!eY(t))continue;let a=Math.abs(e.rect.y+e.rect.height/2-i);(!r||a<r.distance)&&(r={label:t,distance:a})}return r?.label}(e,t)??(i&&eY(i)?i:void 0)}function eY(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function eK(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 a=eZ(r.type??""),n=[r.label,r.value,r.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!n&&eY(n);if(("group"===a||"ioscontentgroup"===a)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);i.push({...r,depth:s})}return i}function eZ(e){let t=e.replace(/XCUIElementType/gi,"").toLowerCase();return t.startsWith("ax")&&(t=t.replace(/^ax/,"")),t}function eQ(e,t){let i=eZ(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 e0(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}async function e1(e,t,i,r){let a=e2(await eC(e,"snapshot",[],r?.out,{...eG(t,{...r,snapshotDepth:1,snapshotCompact:!0,snapshotBackend:"ax"},void 0,i)}));if(a?.appName||a?.appBundleId)return{appName:a.appName??a.appBundleId??"unknown",appBundleId:a.appBundleId,source:"snapshot-ax"};let n=e2(await eC(e,"snapshot",[],r?.out,{...eG(t,{...r,snapshotDepth:1,snapshotCompact:!0,snapshotBackend:"xctest"},void 0,i)}));return{appName:n?.appName??n?.appBundleId??"unknown",appBundleId:n?.appBundleId,source:"snapshot-xctest"}}function e2(e){let t=eq(e?.nodes??[]),i=t.find(e=>"application"===eZ(e.type??""))??t[0];if(!i)return null;let r=i.label?.trim(),a=i.identifier?.trim();return r||a?{appName:r||void 0,appBundleId:a||void 0}:null}let e3=new Set(["id","role","text","label","value"]),e4=new Set(["visible","hidden","editable","selected","enabled","hittable"]),e8=new Set([...e3,...e4]);function e6(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Selector expression cannot be empty");let i=function(e){let t=[],i="",r=null;for(let a=0;a<e.length;a+=1){let n=e[a];if(('"'===n||"'"===n)&&"\\"!==e[a-1]){r?r===n&&(r=null):r=n,i+=n;continue}if(!r&&"|"===n&&"|"===e[a+1]){let r=i.trim();if(!r)throw new p("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(r),i="",a+=1;continue}i+=n}let a=i.trim();if(!a)throw new p("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(a),t}(t);if(0===i.length)throw new p("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:i.map(e=>(function(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Selector segment cannot be empty");let i=function(e){let t=[],i="",r=null;for(let a=0;a<e.length;a+=1){let n=e[a];if(('"'===n||"'"===n)&&"\\"!==e[a-1]){r?r===n&&(r=null):r=n,i+=n;continue}if(!r&&/\s/.test(n)){i.trim().length>0&&t.push(i.trim()),i="";continue}i+=n}if(r)throw new p("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return i.trim().length>0&&t.push(i.trim()),t}(t);if(0===i.length)throw new p("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:i.map(ta)}})(e))}}function e5(e,t,i){let r=i.requireRect??!1,a=i.requireUnique??!0,n=[];for(let o=0;o<t.selectors.length;o+=1){let s=t.selectors[o],l=e.filter(e=>(!r||!!e.rect)&&tn(e,s,i.platform));if((n.push({selector:s.raw,matches:l.length}),0!==l.length)&&(!a||1===l.length))return{node:l[0],selector:s,selectorIndex:o,matches:l.length,diagnostics:n}}return null}function e7(e,t,i){let r=i.requireRect??!1,a=[];for(let n=0;n<t.selectors.length;n+=1){let o=t.selectors[n],s=e.filter(e=>(!r||!!e.rect)&&tn(e,o,i.platform));if(a.push({selector:o.raw,matches:s.length}),s.length>0)return{selectorIndex:n,selector:o,matches:s.length,diagnostics:a}}return null}function e9(e,t,i){let r=i.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let a=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return r?`Selector did not resolve uniquely (${a})`:`Selector did not match (${a})`}function te(e){if(0===e.length)return null;let t=0;for(;t<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 e8.has(e)}return e8.has(t.toLowerCase())}(e[t]);)t+=1;if(0===t)return null;let i=e.slice(0,t).join(" ").trim();return i?{selectorExpression:i,rest:e.slice(t)}:null}function tt(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function ti(e,t){return eQ(e.type??"",t)&&!1!==e.enabled}function tr(e,t,i={}){let r=[],a=eZ(e.type??""),n=tu(e.identifier),o=tu(e.label),s=tu(e.value),l=tu(e0(e)),c="fill"===i.action;n&&r.push(`id=${tc(n)}`),a&&o&&r.push(c?`role=${tc(a)} label=${tc(o)} editable=true`:`role=${tc(a)} label=${tc(o)}`),o&&r.push(c?`label=${tc(o)} editable=true`:`label=${tc(o)}`),s&&r.push(c?`value=${tc(s)} editable=true`:`value=${tc(s)}`),l&&l!==o&&l!==s&&r.push(c?`text=${tc(l)} editable=true`:`text=${tc(l)}`),a&&c&&!r.some(e=>e.includes("editable=true"))&&r.push(`role=${tc(a)} editable=true`);let u=eT(r);return 0===u.length&&a&&u.push(c?`role=${tc(a)} editable=true`:`role=${tc(a)}`),0===u.length&&tt(e)&&u.push("visible=true"),u}function ta(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Empty selector term");let i=t.indexOf("=");if(-1===i){let i=t.toLowerCase();if(!e4.has(i))throw new p("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:i,value:!0}}let r=t.slice(0,i).trim().toLowerCase(),a=t.slice(i+1).trim();if(!e8.has(r))throw new p("INVALID_ARGS",`Unknown selector key: ${r}`);if(!a)throw new p("INVALID_ARGS",`Missing selector value for key: ${r}`);if(e4.has(r)){let e,t="true"===(e=to(a).toLowerCase())||"false"!==e&&null;if(null===t)throw new p("INVALID_ARGS",`Invalid boolean value for ${r}: ${a}`);return{key:r,value:t}}return{key:r,value:to(a)}}function tn(e,t,i){return t.terms.every(t=>(function(e,t,i){switch(t.key){case"id":return ts(e.identifier,String(t.value));case"role":var r,a;return r=e.type,a=String(t.value),function(e){return eZ(e)}(r??"")===function(e){return eZ(e)}(a);case"label":return ts(e.label,String(t.value));case"value":return ts(e.value,String(t.value));case"text":{let i=tl(String(t.value));return tl(e0(e))===i}case"visible":return tt(e)===!!t.value;case"hidden":return!tt(e)==!!t.value;case"editable":return ti(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 to(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function ts(e,t){return tl(e??"")===tl(t)}function tl(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function tc(e){return JSON.stringify(e)}function tu(e){if(!e)return null;let t=e.trim();return t||null}async function td(e){let{req:t,sessionName:i,logPath:r,sessionStore:a,invoke:n,dispatch:o}=e,s=o??eC,c=t.command;if("session_list"===c)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"===c)try{let e=[];if(t.flags?.platform==="android"){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:v}));e.push(...await t())}else if(t.flags?.platform==="ios"){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:en}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:v})),{listIosDevices:i}=await Promise.resolve().then(()=>({listIosDevices:en}));try{e.push(...await t())}catch{}try{e.push(...await i())}catch{}}return{ok:!0,data:{devices:e}}}catch(t){let e=l(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===c){let e=a.get(i),r=t.flags??{};if(!e&&!r.platform&&!r.device&&!r.udid&&!r.serial)return{ok:!1,error:{code:"INVALID_ARGS",message:"apps requires an active session or an explicit device selector (e.g. --platform ios)."}};let n=e?.device??await eR(r);if(await eU(n),!e$("apps",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};if("ios"===n.platform){let{listSimulatorApps:e}=await Promise.resolve().then(()=>({listSimulatorApps:ep})),i=await e(n);return t.flags?.appsMetadata?{ok:!0,data:{apps:i}}:{ok:!0,data:{apps:i.map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:o,listAndroidAppsMetadata:s}=await Promise.resolve().then(()=>({listAndroidApps:S,listAndroidAppsMetadata:D}));return t.flags?.appsMetadata?{ok:!0,data:{apps:await s(n,t.flags?.appsFilter)}}:{ok:!0,data:{apps:await o(n,t.flags?.appsFilter)}}}if("appstate"===c){let e=a.get(i),n=t.flags??{},o=e?.device??await eR(n);if(await eU(o),"ios"===o.platform){if(e?.appBundleId)return{ok:!0,data:{platform:"ios",appBundleId:e.appBundleId,appName:e.appName??e.appBundleId,source:"session"}};let i=await e1(o,r,e?.trace?.outPath,t.flags);return{ok:!0,data:{platform:"ios",appName:i.appName,appBundleId:i.appBundleId,source:i.source}}}let{getAndroidAppState:s}=await Promise.resolve().then(()=>({getAndroidAppState:x})),l=await s(o);return{ok:!0,data:{platform:"android",package:l.package,activity:l.activity}}}if("open"===c){let e;if(a.has(i)){let e,n=a.get(i),o=t.positionals?.[0];if(!n||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if("ios"===n.device.platform)try{let{resolveIosApp:t}=await Promise.resolve().then(()=>({resolveIosApp:es}));e=await t(n.device,o)}catch{e=void 0}await s(n.device,"open",t.positionals??[],t.flags?.out,{...eG(r,t.flags,e)});let l={...n,appBundleId:e,appName:o,recordSession:n.recordSession||t.flags?.saveScript===!0,snapshot:void 0};return a.recordAction(l,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i,appName:o,appBundleId:e}}),a.set(i,l),{ok:!0,data:{session:i,appName:o,appBundleId:e}}}let n=await eR(t.flags??{});await eU(n);let o=a.toArray().find(e=>e.device.id===n.id);if(o)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${o.name}".`,details:{session:o.name,deviceId:n.id,deviceName:n.name}}};let l=t.positionals?.[0];if("ios"===n.platform)try{let{resolveIosApp:i}=await Promise.resolve().then(()=>({resolveIosApp:es}));e=await i(n,t.positionals?.[0]??"")}catch{e=void 0}await s(n,"open",t.positionals??[],t.flags?.out,{...eG(r,t.flags,e)});let u={name:i,device:n,createdAt:Date.now(),appBundleId:e,appName:l,recordSession:t.flags?.saveScript===!0,actions:[]};return a.recordAction(u,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i}}),a.set(i,u),{ok:!0,data:{session:i}}}if("replay"===c){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=eB.expandHome(e),l=d.readFileSync(o,"utf8"),c=l.trimStart()[0];if("{"===c||"["===c)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let u=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,a=!1;for(;r<e.length;){let t=e[r];if('"'===t&&!a)break;a="\\"===t&&!a,"\\"!==t&&(a=!1),r+=1}if(r>=e.length)throw new p("INVALID_ARGS",`Invalid replay script line: ${e}`);let n=e.slice(i,r+1);t.push(JSON.parse(n)),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,...a]=i;if("context"===r)return null;let n={ts:Date.now(),command:r,positionals:[],flags:{}};if("snapshot"===r){n.positionals=[];for(let e=0;e<a.length;e+=1){let t=a[e];if("-i"===t){n.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){n.flags.snapshotCompact=!0;continue}if("--raw"===t){n.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<a.length){let t=Number(a[e+1]);Number.isFinite(t)&&t>=0&&(n.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<a.length){n.flags.snapshotScope=a[e+1],e+=1;continue}if("--backend"===t&&e+1<a.length){let t=a[e+1];("ax"===t||"xctest"===t)&&(n.flags.snapshotBackend=t),e+=1}}return n}if("click"===r){if(0===a.length)return n;let e=a[0];return e.startsWith("@")?(n.positionals=[e],a[1]&&(n.result={refLabel:a[1]})):n.positionals=[a.join(" ")],n}if("fill"===r){if(a.length<2)return n.positionals=a,n;let e=a[0];return e.startsWith("@")?(a.length>=3?(n.positionals=[e,a.slice(2).join(" ")],n.result={refLabel:a[1]}):n.positionals=[e,a[1]],n):(n.positionals=[e,a.slice(1).join(" ")],n)}if("get"===r){if(a.length<2)return n.positionals=a,n;let e=a[0],t=a[1];return t.startsWith("@")?(n.positionals=[e,t],a[2]&&(n.result={refLabel:a[2]})):n.positionals=[e,a.slice(1).join(" ")],n}return n.positionals=a,n}(i);e&&t.push(e)}return t}(l),f=t.flags?.replayUpdate===!0,m=0;for(let e=0;e<u.length;e+=1){let o=u[e];if(!o||"replay"===o.command)continue;let l=await n({token:t.token,session:i,command:o.command,positionals:o.positionals??[],flags:o.flags??{}});if(l.ok)continue;if(!f)return l;let c=await tf({action:o,sessionName:i,logPath:r,sessionStore:a,dispatch:s});if(!c||(u[e]=c,!(l=await n({token:t.token,session:i,command:c.command,positionals:c.positionals??[],flags:c.flags??{}})).ok))return l;m+=1}if(f&&m>0){let e=a.get(i);!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",th(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),e.flags?.snapshotBackend&&t.push("--backend",e.flags.snapshotBackend),t.join(" ");for(let i of e.positionals??[])t.push(th(i));return t.join(" ")}(e));let a=`${r.join("\n")}
|
|
7
|
-
`,n=`${e}.tmp-${process.pid}-${Date.now()}`;d.writeFileSync(n,a),d.renameSync(n,e)}(o,u,e)}return{ok:!0,data:{replayed:u.length,healed:m,session:i}}}catch(t){let e=l(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("close"===c){let e=a.get(i);return e?(t.positionals&&t.positionals.length>0&&await s(e.device,"close",t.positionals??[],t.flags?.out,{...eG(r,t.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&"simulator"===e.device.kind&&await ey(e.device.id),a.recordAction(e,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i}}),t.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 tf(e){let{action:t,sessionName:i,logPath:r,sessionStore:a,dispatch:n}=e;if(!["click","fill","get","is","wait"].includes(t.command))return null;let o=a.get(i);if(!o)return null;let s="click"===t.command||"fill"===t.command,l=await tp(o,t,r,s,n,a);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),"click"===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 i=te(e.positionals.slice(1));i&&t.push(i.selectorExpression)}if("wait"===e.command){let{selectorExpression:i}=tm(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 eT(t).filter(e=>e.trim().length>0)}(t)){let i=e6(e),r=e5(l.nodes,i,{platform:o.device.platform,requireRect:s,requireUnique:!0});if(!r)continue;let a=tr(r.node,o.device.platform,{action:"click"===t.command?"click":"fill"===t.command?"fill":"get"}).join(" || ");if("click"===t.command)return{...t,positionals:[a]};if("fill"===t.command){let e=eF(t);if(!e)continue;return{...t,positionals:[a,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,a]}}if("is"===t.command){let e=t.positionals?.[0];if(!e)continue;let i=te(t.positionals.slice(1)),r=i?.rest.join(" ").trim()??"",n=[e,a];return"text"===e&&r.length>0&&n.push(r),{...t,positionals:n}}if("wait"===t.command){let{selectorTimeout:e}=tm(t.positionals??[]),i=[a];return e&&i.push(e),{...t,positionals:i}}}return null}async function tp(e,t,i,r,a,n){let o=await a(e.device,"snapshot",[],t.flags?.out,{...eG(i,{...t.flags??{},snapshotInteractiveOnly:r,snapshotCompact:r},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:eq(t.flags?.snapshotRaw?s:eK(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,n.set(e.name,e),l}function tm(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],i=/^\d+$/.test(t??""),r=te(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 th(e){let t=e.trim();return t.startsWith("@")||/^-?\d+(\.\d+)?$/.test(t)?t:JSON.stringify(t)}function tw(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}async function tg(e){let{req:t,sessionName:i,logPath:r,sessionStore:a}=e,n=t.command;if("snapshot"===n){let{session:e,device:n}=await tv(a,i,t.flags);if(!e$("snapshot",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is only supported on iOS simulators in v1"}};let o=e?.appBundleId,s=t.flags?.snapshotScope;if(s&&s.trim().startsWith("@")){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}};let t=eW(s.trim());if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${s}`}};let i=eJ(e.snapshot.nodes,t),r=i?eX(i,e.snapshot.nodes):void 0;if(!r)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no label`}};s=r}let l=await eC(n,"snapshot",[],t.flags?.out,{...eG(r,{...t.flags,snapshotScope:s},o,e?.trace?.outPath)}),c=l?.nodes??[],u=eq(t.flags?.snapshotRaw?c:eK(c)),d={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},f=e?{...e,snapshot:d}:{name:i,device:n,createdAt:Date.now(),appBundleId:o,snapshot:d,actions:[]};return ty(a,f,t,{nodes:u.length,truncated:l?.truncated??!1}),a.set(i,f),{ok:!0,data:{nodes:u,truncated:l?.truncated??!1,appName:f.appBundleId?f.appName??f.appBundleId:void 0,appBundleId:f.appBundleId}}}if("wait"===n){let e,n,{session:o,device:s}=await tv(a,i,t.flags),l=function(e){if(0===e.length)return null;let t=tw(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=tw(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=tw(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let i=tw(e[e.length-1]),r=te(null!==i?e.slice(0,-1):e.slice());if(r&&0===r.rest.length){let e=function(e){try{return e6(e)}catch{return null}}(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??[]);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}};if("sleep"===l.kind)return await new Promise(e=>setTimeout(e,l.durationMs)),ty(a,o,t,{waitedMs:l.durationMs}),{ok:!0,data:{waitedMs:l.durationMs}};if(!e$("wait",s))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}};if("selector"===l.kind){let e=l.timeoutMs??1e4,n=Date.now();for(;Date.now()-n<e;){let e=await eC(s,"snapshot",[],t.flags?.out,{...eG(r,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},o?.appBundleId,o?.trace?.outPath)}),c=e?.nodes??[],u=eq(t.flags?.snapshotRaw?c:eK(c));o&&(o.snapshot={nodes:u,truncated:e?.truncated,createdAt:Date.now(),backend:e?.backend},a.set(i,o));let d=e7(u,l.selector,{platform:s.platform});if(d)return ty(a,o,t,{selector:d.selector.raw,waitedMs:Date.now()-n}),{ok:!0,data:{selector:d.selector.raw,waitedMs:Date.now()-n}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${l.selectorExpression}`}}}if("ref"===l.kind){if(!o?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=eW(l.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${l.rawRef}`}};let i=eJ(o.snapshot.nodes,t),r=i?eX(i,o.snapshot.nodes):void 0;if(!r)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${l.rawRef} not found or has no label`}};e=r,n=l.timeoutMs}else e=l.text,n=l.timeoutMs;if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let c=n??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===s.platform&&"simulator"===s.kind){let i=await eg(s,{command:"findText",text:e,appBundleId:o?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:o?.trace?.outPath});if(i?.found)return ty(a,o,t,{text:e,waitedMs:Date.now()-u}),{ok:!0,data:{text:e,waitedMs:Date.now()-u}}}else if("android"===s.platform&&ez(eq((await q(s,{scope:e})).nodes??[]),e))return ty(a,o,t,{text:e,waitedMs:Date.now()-u}),{ok:!0,data:{text:e,waitedMs:Date.now()-u}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${e}`}}}if("alert"===n){let{session:e,device:n}=await tv(a,i,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();if(!e$("alert",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators in v1"}};if("wait"===o){let i=tw(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<i;){try{let i=await eg(n,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath});return ty(a,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 s=await eg(n,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath});return ty(a,e,t,s),{ok:!0,data:s}}if("settings"===n){let e=t.positionals?.[0],n=t.positionals?.[1];if(!e||!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"settings requires <wifi|airplane|location> <on|off>"}};let{session:o,device:s}=await tv(a,i,t.flags),l=o?.appBundleId,c=await eC(s,"settings",[e,n,l??""],t.flags?.out,{...eG(r,t.flags,l,o?.trace?.outPath)});return ty(a,o,t,c??{setting:e,state:n}),{ok:!0,data:c??{setting:e,state:n}}}return null}async function tv(e,t,i){let r=e.get(t),a=r?.device??await eR(i??{});return r||await eU(a),{session:r,device:a}}function ty(e,t,i,r){t&&e.recordAction(t,{command:i.command,positionals:i.positionals??[],flags:i.flags??{},result:r})}function tA(e,t,i,r={}){let a=tb(i);if(!a)return null;let n=null;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()).startsWith("ax")&&(t=t.replace(/^ax/,"")),t):""}(e??"");return i?i===t?2:+!!i.includes(t):0}(e.type,i);case"label":return tI(e.label,i);case"value":return tI(e.value,i);case"id":return tI(e.identifier,i);default:return Math.max(tI(e.label,i),tI(e.value,i),tI(e.identifier,i))}}(i,t,a);if(!(e<=0)&&(!n||e>n.score)&&(n={node:i,score:e},e>=2))break}return n?.node??null}function tI(e,t){let i=tb(e??"");return i?i===t?2:+!!i.includes(t):0}function tb(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function tN(e){let{req:t,sessionName:i,logPath:r,sessionStore:a,invoke:n}=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:c,action:u,value:d,timeoutMs:f}=function(e){let t="any",i=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],i=1);let r=e[i]??"",a=e.slice(i+1);if(0===a.length)return{locator:t,query:r,action:"click"};let n=a[0].toLowerCase();if("get"===n){let e=a[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 p("INVALID_ARGS","find get only supports text or attrs")}if("wait"===n)return{locator:t,query:r,action:"wait",timeoutMs:tw(a[1])??void 0};if("exists"===n)return{locator:t,query:r,action:"exists"};if("click"===n)return{locator:t,query:r,action:"click"};if("focus"===n)return{locator:t,query:r,action:"focus"};if("fill"===n)return{locator:t,query:r,action:"fill",value:a.slice(1).join(" ")};if("type"===n)return{locator:t,query:r,action:"type",value:a.slice(1).join(" ")};throw new p("INVALID_ARGS",`Unsupported find action: ${a[0]}`)}(s);if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=a.get(i);if(!m&&"exists"!==u&&"wait"!==u&&"get_text"!==u&&"get_attrs"!==u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await eR(t.flags??{});m||await eU(h);let w=m?.appBundleId,g="role"!==l?c:void 0,v="click"===u||"focus"===u||"fill"===u||"type"===u,y=0,A=null,I=async()=>{let e=Date.now();if(A&&e-y<750)return{nodes:A};let n=await eC(h,"snapshot",[],t.flags?.out,{...eG(r,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),o=n?.nodes??[],s=eq(t.flags?.snapshotRaw?o:eK(o));return y=e,A=s,m&&(m.snapshot={nodes:s,truncated:n?.truncated,createdAt:Date.now(),backend:n?.backend},a.set(i,m)),{nodes:s,truncated:n?.truncated,backend:n?.backend}};if("wait"===u){let e=f??1e4,i=Date.now();for(;Date.now()-i<e;){let{nodes:e}=await I();if(tA(e,l,c,{requireRect:!1}))return m&&a.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:b}=await I(),N=tA(b,l,c,{requireRect:v});if(!N)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let k="click"===u||"focus"===u||"fill"===u||"type"===u?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}(b,N)??N:N,S=`@${k.ref}`,D={...t.flags??{},noRecord:!0};if("exists"===u)return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===u){let e=e0(N);return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"get text",text:e}}),{ok:!0,data:{ref:S,text:e,node:N}}}if("get_attrs"===u)return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"get attrs"}}),{ok:!0,data:{ref:S,node:N}};if("click"===u){let e=await n({token:t.token,session:i,command:"click",positionals:[S],flags:D});return e.ok&&m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"click"}}),e}if("fill"===u){if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await n({token:t.token,session:i,command:"fill",positionals:[S,d],flags:D});return e.ok&&m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"fill"}}),e}if("focus"===u){let e=N.rect?eH(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let i=await eC(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...eG(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"focus"}}),{ok:!0,data:i??{ref:S}}}if("type"===u){if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=N.rect?eH(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await eC(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...eG(r,t.flags,m?.appBundleId,m?.trace?.outPath)});let i=await eC(h,"type",[d],t.flags?.out,{...eG(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"type"}}),{ok:!0,data:i??{ref:S}}}return null}async function tk(e){let{req:t,sessionName:i,sessionStore:r}=e,a=t.command;if("record"===a){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let o=r.get(i),s=o?.device??await eR(t.flags??{});o||await eU(s);let l=o??{name:i,device:s,createdAt:Date.now(),actions:[]};if("start"===e){if(l.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.positionals?.[1]??`./recording-${Date.now()}.mp4`,o=n.resolve(e),c=n.dirname(o);if(d.existsSync(c)||d.mkdirSync(c,{recursive:!0}),!e$("record",s))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is only supported on iOS simulators in v1"}};if("ios"===s.platform){let{child:e,wait:t}=u("xcrun",["simctl","io",s.id,"recordVideo",o],{allowFailure:!0});l.recording={platform:"ios",outPath:o,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:i}=u("adb",["-s",s.id,"shell","screenrecord",e],{allowFailure:!0});l.recording={platform:"android",outPath:o,remotePath:e,child:t,wait:i}}return r.set(i,l),r.recordAction(l,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:e}}}if(!l.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let c=l.recording;c.child.kill("SIGINT");try{await c.wait}catch{}if("android"===c.platform&&c.remotePath)try{await m("adb",["-s",s.id,"pull",c.remotePath,c.outPath],{allowFailure:!0}),await m("adb",["-s",s.id,"shell","rm","-f",c.remotePath],{allowFailure:!0})}catch{}return l.recording=void 0,r.recordAction(l,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:c.outPath}}),{ok:!0,data:{recording:"stopped",outPath:c.outPath}}}if("trace"===a){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(o.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??r.defaultTracePath(o),i=eB.expandHome(e);return d.mkdirSync(n.dirname(i),{recursive:!0}),d.appendFileSync(i,""),o.trace={outPath:i,startedAt:Date.now()},r.recordAction(o,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:i}}),{ok:!0,data:{trace:"started",outPath:i}}}if(!o.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let s=o.trace.outPath;if(t.positionals?.[1]){let e=eB.expandHome(t.positionals[1]);d.mkdirSync(n.dirname(e),{recursive:!0}),d.existsSync(s)?d.renameSync(s,e):d.appendFileSync(e,""),s=e}return o.trace=void 0,r.recordAction(o,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:s}}),{ok:!0,data:{trace:"stopped",outPath:s}}}return null}async function tS(e){let{req:t,sessionName:i,sessionStore:r,contextFromFlags:a}=e,n=t.command;if("click"===n){let e=r.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let o=t.positionals?.[0]??"";if(o.startsWith("@")){if(!e.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=eW(o);if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"click requires a ref like @e2"}};let s=eJ(e.snapshot.nodes,i);if(!s?.rect&&t.positionals.length>1){let i=t.positionals.slice(1).join(" ").trim();i.length>0&&(s=ez(e.snapshot.nodes,i))}if(!s?.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${o} not found or has no bounds`}};let l=eX(s,e.snapshot.nodes),c=tr(s,e.device.platform,{action:"click"}),{x:u,y:d}=eH(s.rect);return await eC(e.device,"press",[String(u),String(d)],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)}),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,x:u,y:d,refLabel:l,selectorChain:c}}),{ok:!0,data:{ref:i,x:u,y:d}}}let s=(t.positionals??[]).join(" ").trim();if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"click requires @ref or selector expression"}};let l=e6(s),c=await tD(e,t.flags,r,a,{interactiveOnly:!0}),u=e5(c.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:e9(l,u?.diagnostics??[],{unique:!0})}};let{x:d,y:f}=eH(u.node.rect);await eC(e.device,"press",[String(d),String(f)],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)});let p=tr(u.node,e.device.platform,{action:"click"}),m=eX(u.node,c.nodes);return r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{x:d,y:f,selector:u.selector.raw,selectorChain:p,refLabel:m}}),{ok:!0,data:{selector:u.selector.raw,x:d,y:f}}}if("fill"===n){let e=r.get(i);if(t.positionals?.[0]?.startsWith("@")){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=eW(t.positionals[0]);if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires a ref like @e2"}};let o=t.positionals.length>=3?t.positionals[1]:"",s=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let l=eJ(e.snapshot.nodes,i);if(!l?.rect&&o&&(l=ez(e.snapshot.nodes,o)),!l?.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let c=l.type??"",u=c&&!eQ(c,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${c}", attempting fill anyway.`:void 0,d=eX(l,e.snapshot.nodes),f=tr(l,e.device.platform,{action:"fill"}),{x:p,y:m}=eH(l.rect),h={...await eC(e.device,"fill",[String(p),String(m),s],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:i,x:p,y:m}};return u&&(h.warning=u),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{...h,refLabel:d,selectorChain:f}}),{ok:!0,data:h}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let o=te(t.positionals??[]);if(o){if(0===o.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let i=o.rest.join(" ").trim();if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let s=e6(o.selectorExpression),l=await tD(e,t.flags,r,a,{interactiveOnly:!0}),c=e5(l.nodes,s,{platform:e.device.platform,requireRect:!0,requireUnique:!0});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:e9(s,c?.diagnostics??[],{unique:!0})}};let u=c.node,d=u.type??"",f=d&&!eQ(d,e.device.platform)?`fill target ${c.selector.raw} resolved to "${d}", attempting fill anyway.`:void 0,{x:p,y:m}=eH(c.node.rect),h=await eC(e.device,"fill",[String(p),String(m),i],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)}),w=tr(u,e.device.platform,{action:"fill"}),g={...h??{x:p,y:m,text:i},selector:c.selector.raw,selectorChain:w,refLabel:eX(u,l.nodes)};return f&&(g.warning=f),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:g}),{ok:!0,data:g}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===n){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 o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=t.positionals?.[1]??"";if(s.startsWith("@")){if(!o.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=eW(s??"");if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"get text requires a ref like @e2"}};let a=eJ(o.snapshot.nodes,i);if(!a&&t.positionals.length>2){let e=t.positionals.slice(2).join(" ").trim();e.length>0&&(a=ez(o.snapshot.nodes,e))}if(!a)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found`}};let l=tr(a,o.device.platform,{action:"get"});if("attrs"===e)return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,selectorChain:l}}),{ok:!0,data:{ref:i,node:a}};let c=e0(a);return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,text:c,refLabel:c||void 0,selectorChain:l}}),{ok:!0,data:{ref:i,text:c,node:a}}}let l=t.positionals.slice(1).join(" ").trim();if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let c=e6(l),u=e5((await tD(o,t.flags,r,a,{interactiveOnly:!1})).nodes,c,{platform:o.device.platform,requireRect:!1,requireUnique:!0});if(!u)return{ok:!1,error:{code:"COMMAND_FAILED",message:e9(c,[],{unique:!0})}};let d=u.node,f=tr(d,o.device.platform,{action:"get"});if("attrs"===e)return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{selector:u.selector.raw,selectorChain:f}}),{ok:!0,data:{selector:u.selector.raw,node:d}};let p=e0(d);return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{text:p,refLabel:p||void 0,selector:u.selector.raw,selectorChain:f}}),{ok:!0,data:{selector:u.selector.raw,text:p,node:d}}}if("is"===n){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 o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!e$("is",o.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let s=te(t.positionals.slice(1));if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let l=s.rest.join(" ").trim();if("text"===e&&!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&s.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let c=e6(s.selectorExpression),u=await tD(o,t.flags,r,a,{interactiveOnly:!1});if("exists"===e){let i=e7(u.nodes,c,{platform:o.device.platform});return i?(r.recordAction(o,{command:n,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:e9(c,[],{unique:!1})}}}let d=e5(u.nodes,c,{platform:o.device.platform,requireUnique:!0});if(!d)return{ok:!1,error:{code:"COMMAND_FAILED",message:e9(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:i,expectedText:r,platform:a}=e,n=e0(i),o=!1;switch(t){case"visible":o=tt(i);break;case"hidden":o=!tt(i);break;case"editable":o=ti(i,a);break;case"selected":o=!0===i.selected;break;case"text":o=n===(r??"")}let s="text"===t?`expected="${r??""}" actual="${n}"`:`actual=${JSON.stringify({visible:tt(i),editable:ti(i,a),selected:!0===i.selected})}`;return{pass:o,actualText:n,details:s}}({predicate:e,node:d.node,expectedText:l,platform:o.device.platform});return f.pass?(r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:d.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:d.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${d.selector.raw}: ${f.details}`}}}return null}async function tD(e,t,i,r,a){let n=await eC(e.device,"snapshot",[],t?.out,{...r({...t??{},snapshotInteractiveOnly:a.interactiveOnly,snapshotCompact:a.interactiveOnly},e.appBundleId,e.trace?.outPath)}),o=n?.nodes??[];return e.snapshot={nodes:eq(t?.snapshotRaw?o:eK(o)),truncated:n?.truncated,createdAt:Date.now(),backend:n?.backend},i.set(e.name,e),e.snapshot}let tx=n.join(f.homedir(),".agent-device"),tL=n.join(tx,"daemon.json"),t_=n.join(tx,"daemon.log"),tO=new eB(n.join(tx,"sessions")),tP=function(){try{let e=function(){let e=n.dirname(c(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(d.existsSync(e))return t;t=n.dirname(t)}return e}();return JSON.parse(d.readFileSync(n.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),tM=i.randomBytes(24).toString("hex"),tR=new Set(["session_list","devices"]);function tC(e,t,i){return eG(t_,e,t,i)}async function tE(e){if(e.token!==tM)return{ok:!1,error:{code:"UNAUTHORIZED",message:"Invalid token"}};let t=e.command,i=function(e,t){var i;let r,a=e.session||"default";if(i=e,"string"==typeof(r=i.flags?.session)&&r.trim().length>0||"default"!==a||t.has(a))return a;let n=t.toArray();return 1===n.length?n[0].name:a}(e,tO),r=tO.get(i);r&&!tR.has(t)&&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}`),0!==i.length){var a;let t,r,n;throw new p("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,r=a.device.name.trim(),n=a.device.id,`${t} device "${r}" (${n})`)} and cannot be used with ${i.join(", ")}. Use a different --session name or close this session first.`)}}(r,e.flags);let a=await td({req:e,sessionName:i,logPath:t_,sessionStore:tO,invoke:tE});if(a)return a;let n=await tg({req:e,sessionName:i,logPath:t_,sessionStore:tO});if(n)return n;let o=await tk({req:e,sessionName:i,sessionStore:tO});if(o)return o;let s=await tN({req:e,sessionName:i,logPath:t_,sessionStore:tO,invoke:tE});if(s)return s;let l=await tS({req:e,sessionName:i,sessionStore:tO,contextFromFlags:tC});if(l)return l;let c=tO.get(i);if(!c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!e$(t,c.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}};let u=await eC(c.device,t,e.positionals??[],e.flags?.out,{...tC(e.flags,c.appBundleId,c.trace?.outPath)});return tO.recordAction(c,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:u??{}}),{ok:!0,data:u??{}}}(e=h.createServer(e=>{let t="";e.setEncoding("utf8"),e.on("data",async i=>{let r=(t+=i).indexOf("\n");for(;-1!==r;){let i,a=t.slice(0,r).trim();if(t=t.slice(r+1),0===a.length){r=t.indexOf("\n");continue}try{let e=JSON.parse(a);i=await tE(e)}catch(t){let e=l(t);i={ok:!1,error:{code:e.code,message:e.message,details:e.details}}}e.write(`${JSON.stringify(i)}
|
|
8
|
-
`),r=t.indexOf("\n")}})})).listen(0,"127.0.0.1",()=>{let t=e.address();if("object"==typeof t&&t?.port){var i;i=t.port,d.existsSync(
|
|
9
|
-
`)}}),t=async()=>{for(let e of
|
|
7
|
+
`))),0!==s.exitCode){let e,t,i=(s.stderr??"").toString(),r=(e=i.toLowerCase()).includes("accessibility permission")?" Enable Accessibility for your terminal in System Settings > Privacy & Security > Accessibility, or use --backend xctest (slower snapshots via XCTest).":e.includes("could not find ios app content")?" AX snapshot sometimes caches empty content. Try restarting the Simulator app.":"",a=!!((t=i.toLowerCase()).includes("could not find ios app content")||t.includes("timeout"));throw new p("COMMAND_FAILED","AX snapshot failed",{stderr:`${i}${r}`,stdout:s.stdout,retryable:a})}return s},{shouldRetry:e=>{var t;return(t=e)instanceof p&&"COMMAND_FAILED"===t.code&&t.details?.retryable===!0}});try{let e=JSON.parse(n.stdout);if(e&&"object"==typeof e&&"root"in e){if(!e.root)throw Error("AX snapshot missing root");i=e.root,r=e.windowFrame??void 0}else i=e}catch(e){throw new p("COMMAND_FAILED","Invalid AX snapshot JSON",{error:String(e)})}let o=i.frame??r,s=[],l=[],c=(e,t)=>{e.frame&&s.push(e.frame);let i=e.frame&&o?{x:e.frame.x-o.x,y:e.frame.y-o.y,width:e.frame.width,height:e.frame.height}:e.frame;for(let r of(l.push({...e,frame:i,children:void 0,depth:t}),e.children??[]))c(r,t+1)};return c(i,0),{nodes:(function(e,t,i){if(!t||0===i.length)return e;let r=1/0,a=1/0;for(let e of i)e.x<r&&(r=e.x),e.y<a&&(a=e.y);return r<=5&&a<=5?e.map(e=>({...e,frame:e.frame?{x:e.frame.x+t.x,y:e.frame.y+t.y,width:e.frame.width,height:e.frame.height}:void 0})):e})(l,o,s).map((e,t)=>({index:t,type:e.subrole??e.role,label:e.label,value:e.value,identifier:e.identifier,rect:e.frame?{x:e.frame.x,y:e.frame.y,width:e.frame.width,height:e.frame.height}:void 0,depth:e.depth}))}}async function ej(){let e=function(){let e=n.dirname(c(import.meta.url));for(let t=0;t<6;t+=1){let t=n.join(e,"package.json");if(d.existsSync(t))return e;e=n.dirname(e)}return process.cwd()}(),t=n.join(e,"ios-runner","AXSnapshot"),i=process.env.AGENT_DEVICE_AX_BINARY;if(i&&d.existsSync(i))return i;let r=n.join(e,"dist","bin","axsnapshot");if(d.existsSync(r))return r;let a=n.join(t,".build","release","axsnapshot");if(d.existsSync(a))return a;let o=await m("swift",["build","-c","release"],{cwd:t,allowFailure:!0});if(0!==o.exitCode||!d.existsSync(a))throw new p("COMMAND_FAILED","Failed to build AX snapshot tool",{stderr:o.stderr,stdout:o.stdout});return a}async function eG(e){let t={platform:e.platform,deviceName:e.device,udid:e.udid,serial:e.serial};if("android"===t.platform){await Y();let e=await v();return await g(e,t)}if("ios"===t.platform){let e=await el();return await g(e,t)}let i=[];try{i.push(...await v())}catch{}try{i.push(...await el())}catch{}return await g(i,t)}async function eU(e,t,i,r,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,i)=>E(e,t,i?.activity),openDevice:()=>$(e),close:t=>F(e,t),tap:(t,i)=>T(e,t,i),longPress:(t,i,r)=>G(e,t,i,r),focus:(t,i)=>q(e,t,i),type:t=>U(e,t),fill:(t,i,r)=>W(e,t,i,r),scroll:(t,i)=>J(e,t,i),scrollIntoView:t=>H(e,t),screenshot:t=>z(e,t)};case"ios":var i,r;let a;return{open:t=>ed(e,t),openDevice:()=>ef(e),close:t=>ep(e,t),screenshot:t=>em(e,t),...(i=e,a={verbose:(r=t).verbose,logPath:r.logPath,traceLogPath:r.traceLogPath},{tap:async(e,t)=>{await eN(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a)},longPress:async(e,t,n)=>{await eN(i,{command:"longPress",x:e,y:t,durationMs:n,appBundleId:r.appBundleId},a)},focus:async(e,t)=>{await eN(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a)},type:async e=>{await eN(i,{command:"type",text:e,appBundleId:r.appBundleId},a)},fill:async(e,t,n)=>{await eN(i,{command:"tap",x:e,y:t,appBundleId:r.appBundleId},a),await eN(i,{command:"type",text:n,clearFirst:!0,appBundleId:r.appBundleId},a)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new p("INVALID_ARGS",`Unknown direction: ${e}`);let n=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await eN(i,{command:"swipe",direction:n,appBundleId:r.appBundleId},a)},scrollIntoView:async e=>{for(let t=0;t<8;t+=1){let n=await eN(i,{command:"findText",text:e,appBundleId:r.appBundleId},a);if(n?.found)return{attempts:t+1};await eN(i,{command:"swipe",direction:"up",appBundleId:r.appBundleId},a),await new Promise(e=>setTimeout(e,300))}throw new p("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new p("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});switch(t){case"open":{let e=i[0];if(!e)return await o.openDevice(),{app:null};return await o.open(e,{activity:a?.activity}),{app:e}}case"close":{let e=i[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[e,t]=i.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new p("INVALID_ARGS","press requires x y");return await o.tap(e,t),{x:e,y:t}}case"long-press":{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 p("INVALID_ARGS","long-press 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 p("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 p("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 p("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 p("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 p("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":{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 p("INVALID_ARGS","pinch requires scale > 0");return await eN(e,{command:"pinch",scale:t,x:r,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{scale:t,x:r,y:n}}case"screenshot":{let e=i[0]??r??`./screenshot-${Date.now()}.png`;return await s.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e),{path:e}}case"back":if("ios"===e.platform)return await eN(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"back"};return await V(e),{action:"back"};case"home":if("ios"===e.platform)return await eN(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"home"};return await B(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await eN(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath}),{action:"app-switcher"};return await j(e),{action:"app-switcher"};case"settings":{let[t,r,n]=i;if("ios"===e.platform)return await eh(e,t,r,n??a?.appBundleId),{setting:t,state:r};return await X(e,t,r),{setting:t,state:r}}case"snapshot":{let t=a?.snapshotBackend??"xctest";if("ios"===e.platform){if("ax"===t)return{nodes:(await eB(e,{traceLogPath:a?.traceLogPath})).nodes??[],truncated:!1,backend:"ax"};let i=await eN(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}),r=i.nodes??[];if(0===r.length)try{return{nodes:(await eB(e,{traceLogPath:a?.traceLogPath})).nodes??[],truncated:!1,backend:"ax"}}catch{}return{nodes:r,truncated:i.truncated??!1,backend:"xctest"}}let i=await K(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw});return{nodes:i.nodes??[],truncated:i.truncated??!1,backend:"android"}}default:throw new p("INVALID_ARGS",`Unknown command: ${t}`)}}let eq={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},"long-press":{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}}};function eW(e,t){let i=eq[e];if(!i)return!0;let r=i[t.platform];return!!r&&!0===r[t.kind??"unknown"]}function eJ(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 eH(e){let t=new Set,i=[];for(let r of e)t.has(r)||(t.add(r),i.push(r));return i}function ez(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class eX{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),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:a,out:n,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:c,snapshotScope:u,snapshotRaw:d,snapshotBackend:f,appsMetadata:p,saveScript:m,noRecord:h}=e;return{platform:t,device:i,udid:r,serial:a,out:n,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:c,snapshotScope:u,snapshotRaw:d,snapshotBackend:f,appsMetadata:p,saveScript:m,noRecord:h}}(t.flags),result:t.result}))}writeSessionLog(e){try{if(!e.recordSession)return;d.existsSync(this.sessionsDir)||d.mkdirSync(this.sessionsDir,{recursive:!0});let t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),i=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-"),r=n.join(this.sessionsDir,`${t}-${i}.ad`),a=function(e,t){let i=[],r=e.device.name.replace(/"/g,'\\"'),a=e.device.kind?` kind=${e.device.kind}`:"";for(let n of(i.push(`context platform=${e.device.platform} device="${r}"${a} theme=unknown`),t))n.flags?.noRecord||i.push(function(e){let t=[e.command];if("click"===e.command){let i=e.positionals?.[0];if(i){if(t.push(eK(i)),i.startsWith("@")){let i=e.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push(eK(i))}return t.join(" ")}}if("fill"===e.command){let i=e.positionals?.[0];if(i&&i.startsWith("@")){t.push(eK(i));let r=e.result?.refLabel,a=e.positionals.slice(1).join(" ");return"string"==typeof r&&r.trim().length>0&&t.push(eK(r)),a&&t.push(eK(a)),t.join(" ")}}if("get"===e.command){let i=e.positionals?.[0],r=e.positionals?.[1];if(i&&r){if(t.push(eK(i)),t.push(eK(r)),r.startsWith("@")){let i=e.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push(eK(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",eK(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),e.flags?.snapshotBackend&&t.push("--backend",e.flags.snapshotBackend),t.join(" ");for(let i of e.positionals??[])t.push(eK(i));return t.join(" ")}(n));return`${i.join("\n")}
|
|
8
|
+
`}(e,this.buildOptimizedActions(e));d.writeFileSync(r,a)}catch{}}defaultTracePath(e){let t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),i=new Date().toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${i}.trace.log`)}static expandHome(e){return e.startsWith("~/")?n.join(f.homedir(),e.slice(2)):n.resolve(e)}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&&("click"===i.command||"fill"===i.command||"get"===i.command)){let e=r.join(" || ");if("click"===i.command){t.push({...i,positionals:[e]});continue}if("fill"===i.command){let r=eJ(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("click"===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}constructor(e){ez(this,"sessions",new Map),ez(this,"sessionsDir",void 0),this.sessionsDir=e}}function eK(e){let t=e.trim();return t.startsWith("@")||/^-?\d+(\.\d+)?$/.test(t)?t:JSON.stringify(t)}function eY(e,t,i,r){return{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,snapshotBackend:t?.snapshotBackend}}async function eZ(e){if("ios"===e.platform&&"simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:eg}));await t(e);return}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:A}));await t(e.id)}}function eQ(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function e0(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function e1(e,t){return e.find(e=>e.ref===t)??null}function e2(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function e3(e,t){let i=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),r=(e.value??"").toLowerCase(),a=(e.identifier??"").toLowerCase();return t.includes(i)||r.includes(i)||a.includes(i)})??null}function e4(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&&e8(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||!e8(t))continue;let a=Math.abs(e.rect.y+e.rect.height/2-i);(!r||a<r.distance)&&(r={label:t,distance:a})}return r?.label}(e,t)??(i&&e8(i)?i:void 0)}function e8(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function e5(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 a=e6(r.type??""),n=[r.label,r.value,r.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!n&&e8(n);if(("group"===a||"ioscontentgroup"===a)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);i.push({...r,depth:s})}return i}function e6(e){let t=e.replace(/XCUIElementType/gi,"").toLowerCase();return t.startsWith("ax")&&(t=t.replace(/^ax/,"")),t}function e7(e,t){let i=e6(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 e9(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}async function te(e,t,i,r){let a=tt(await eU(e,"snapshot",[],r?.out,{...eY(t,{...r,snapshotDepth:1,snapshotCompact:!0,snapshotBackend:"ax"},void 0,i)}));if(a?.appName||a?.appBundleId)return{appName:a.appName??a.appBundleId??"unknown",appBundleId:a.appBundleId,source:"snapshot-ax"};let n=tt(await eU(e,"snapshot",[],r?.out,{...eY(t,{...r,snapshotDepth:1,snapshotCompact:!0,snapshotBackend:"xctest"},void 0,i)}));return{appName:n?.appName??n?.appBundleId??"unknown",appBundleId:n?.appBundleId,source:"snapshot-xctest"}}function tt(e){let t=eQ(e?.nodes??[]),i=t.find(e=>"application"===e6(e.type??""))??t[0];if(!i)return null;let r=i.label?.trim(),a=i.identifier?.trim();return r||a?{appName:r||void 0,appBundleId:a||void 0}:null}let ti=new Set(["id","role","text","label","value"]),tr=new Set(["visible","hidden","editable","selected","enabled","hittable"]),ta=new Set([...ti,...tr]);function tn(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Selector expression cannot be empty");let i=function(e){let t=[],i="",r=null;for(let a=0;a<e.length;a+=1){let n=e[a];if(('"'===n||"'"===n)&&"\\"!==e[a-1]){r?r===n&&(r=null):r=n,i+=n;continue}if(!r&&"|"===n&&"|"===e[a+1]){let r=i.trim();if(!r)throw new p("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(r),i="",a+=1;continue}i+=n}let a=i.trim();if(!a)throw new p("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(a),t}(t);if(0===i.length)throw new p("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:i.map(e=>(function(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Selector segment cannot be empty");let i=function(e){let t=[],i="",r=null;for(let a=0;a<e.length;a+=1){let n=e[a];if(('"'===n||"'"===n)&&"\\"!==e[a-1]){r?r===n&&(r=null):r=n,i+=n;continue}if(!r&&/\s/.test(n)){i.trim().length>0&&t.push(i.trim()),i="";continue}i+=n}if(r)throw new p("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return i.trim().length>0&&t.push(i.trim()),t}(t);if(0===i.length)throw new p("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:i.map(tp)}})(e))}}function to(e,t,i){let r=i.requireRect??!1,a=i.requireUnique??!0,n=[];for(let o=0;o<t.selectors.length;o+=1){let s=t.selectors[o],l=e.filter(e=>(!r||!!e.rect)&&tm(e,s,i.platform));if((n.push({selector:s.raw,matches:l.length}),0!==l.length)&&(!a||1===l.length))return{node:l[0],selector:s,selectorIndex:o,matches:l.length,diagnostics:n}}return null}function ts(e,t,i){let r=i.requireRect??!1,a=[];for(let n=0;n<t.selectors.length;n+=1){let o=t.selectors[n],s=e.filter(e=>(!r||!!e.rect)&&tm(e,o,i.platform));if(a.push({selector:o.raw,matches:s.length}),s.length>0)return{selectorIndex:n,selector:o,matches:s.length,diagnostics:a}}return null}function tl(e,t,i){let r=i.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let a=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return r?`Selector did not resolve uniquely (${a})`:`Selector did not match (${a})`}function tc(e){if(0===e.length)return null;let t=0;for(;t<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 ta.has(e)}return ta.has(t.toLowerCase())}(e[t]);)t+=1;if(0===t)return null;let i=e.slice(0,t).join(" ").trim();return i?{selectorExpression:i,rest:e.slice(t)}:null}function tu(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function td(e,t){return e7(e.type??"",t)&&!1!==e.enabled}function tf(e,t,i={}){let r=[],a=e6(e.type??""),n=ty(e.identifier),o=ty(e.label),s=ty(e.value),l=ty(e9(e)),c="fill"===i.action;n&&r.push(`id=${tv(n)}`),a&&o&&r.push(c?`role=${tv(a)} label=${tv(o)} editable=true`:`role=${tv(a)} label=${tv(o)}`),o&&r.push(c?`label=${tv(o)} editable=true`:`label=${tv(o)}`),s&&r.push(c?`value=${tv(s)} editable=true`:`value=${tv(s)}`),l&&l!==o&&l!==s&&r.push(c?`text=${tv(l)} editable=true`:`text=${tv(l)}`),a&&c&&!r.some(e=>e.includes("editable=true"))&&r.push(`role=${tv(a)} editable=true`);let u=eH(r);return 0===u.length&&a&&u.push(c?`role=${tv(a)} editable=true`:`role=${tv(a)}`),0===u.length&&tu(e)&&u.push("visible=true"),u}function tp(e){let t=e.trim();if(!t)throw new p("INVALID_ARGS","Empty selector term");let i=t.indexOf("=");if(-1===i){let i=t.toLowerCase();if(!tr.has(i))throw new p("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:i,value:!0}}let r=t.slice(0,i).trim().toLowerCase(),a=t.slice(i+1).trim();if(!ta.has(r))throw new p("INVALID_ARGS",`Unknown selector key: ${r}`);if(!a)throw new p("INVALID_ARGS",`Missing selector value for key: ${r}`);if(tr.has(r)){let e,t="true"===(e=th(a).toLowerCase())||"false"!==e&&null;if(null===t)throw new p("INVALID_ARGS",`Invalid boolean value for ${r}: ${a}`);return{key:r,value:t}}return{key:r,value:th(a)}}function tm(e,t,i){return t.terms.every(t=>(function(e,t,i){switch(t.key){case"id":return tw(e.identifier,String(t.value));case"role":var r,a;return r=e.type,a=String(t.value),function(e){return e6(e)}(r??"")===function(e){return e6(e)}(a);case"label":return tw(e.label,String(t.value));case"value":return tw(e.value,String(t.value));case"text":{let i=tg(String(t.value));return tg(e9(e))===i}case"visible":return tu(e)===!!t.value;case"hidden":return!tu(e)==!!t.value;case"editable":return td(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 th(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function tw(e,t){return tg(e??"")===tg(t)}function tg(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function tv(e){return JSON.stringify(e)}function ty(e){if(!e)return null;let t=e.trim();return t||null}async function tA(e){let{req:t,sessionName:i,logPath:r,sessionStore:a,invoke:n,dispatch:o}=e,s=o??eU,c=t.command;if("session_list"===c)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"===c)try{let e=[];if(t.flags?.platform==="android"){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:v}));e.push(...await t())}else if(t.flags?.platform==="ios"){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:el}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:v})),{listIosDevices:i}=await Promise.resolve().then(()=>({listIosDevices:el}));try{e.push(...await t())}catch{}try{e.push(...await i())}catch{}}return{ok:!0,data:{devices:e}}}catch(t){let e=l(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===c){let e=a.get(i),r=t.flags??{};if(!e&&!r.platform&&!r.device&&!r.udid&&!r.serial)return{ok:!1,error:{code:"INVALID_ARGS",message:"apps requires an active session or an explicit device selector (e.g. --platform ios)."}};let n=e?.device??await eG(r);if(await eZ(n),!eW("apps",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};if("ios"===n.platform){let{listSimulatorApps:e}=await Promise.resolve().then(()=>({listSimulatorApps:ew})),i=await e(n);return t.flags?.appsMetadata?{ok:!0,data:{apps:i}}:{ok:!0,data:{apps:i.map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:o,listAndroidAppsMetadata:s}=await Promise.resolve().then(()=>({listAndroidApps:M,listAndroidAppsMetadata:R}));return t.flags?.appsMetadata?{ok:!0,data:{apps:await s(n,t.flags?.appsFilter)}}:{ok:!0,data:{apps:await o(n,t.flags?.appsFilter)}}}if("appstate"===c){let e=a.get(i),n=t.flags??{},o=e?.device??await eG(n);if(await eZ(o),"ios"===o.platform){if(e?.appBundleId)return{ok:!0,data:{platform:"ios",appBundleId:e.appBundleId,appName:e.appName??e.appBundleId,source:"session"}};let i=await te(o,r,e?.trace?.outPath,t.flags);return{ok:!0,data:{platform:"ios",appName:i.appName,appBundleId:i.appBundleId,source:i.source}}}let{getAndroidAppState:s}=await Promise.resolve().then(()=>({getAndroidAppState:P})),l=await s(o);return{ok:!0,data:{platform:"android",package:l.package,activity:l.activity}}}if("open"===c){let e;if(a.has(i)){let e,n=a.get(i),o=t.positionals?.[0];if(!n||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if("ios"===n.device.platform)try{let{resolveIosApp:t}=await Promise.resolve().then(()=>({resolveIosApp:eu}));e=await t(n.device,o)}catch{e=void 0}await s(n.device,"open",t.positionals??[],t.flags?.out,{...eY(r,t.flags,e)});let l={...n,appBundleId:e,appName:o,recordSession:n.recordSession||t.flags?.saveScript===!0,snapshot:void 0};return a.recordAction(l,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i,appName:o,appBundleId:e}}),a.set(i,l),{ok:!0,data:{session:i,appName:o,appBundleId:e}}}let n=await eG(t.flags??{});await eZ(n);let o=a.toArray().find(e=>e.device.id===n.id);if(o)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${o.name}".`,details:{session:o.name,deviceId:n.id,deviceName:n.name}}};let l=t.positionals?.[0];if("ios"===n.platform)try{let{resolveIosApp:i}=await Promise.resolve().then(()=>({resolveIosApp:eu}));e=await i(n,t.positionals?.[0]??"")}catch{e=void 0}await s(n,"open",t.positionals??[],t.flags?.out,{...eY(r,t.flags,e)});let u={name:i,device:n,createdAt:Date.now(),appBundleId:e,appName:l,recordSession:t.flags?.saveScript===!0,actions:[]};return a.recordAction(u,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i}}),a.set(i,u),{ok:!0,data:{session:i}}}if("replay"===c){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=eX.expandHome(e),l=d.readFileSync(o,"utf8"),c=l.trimStart()[0];if("{"===c||"["===c)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let u=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,a=!1;for(;r<e.length;){let t=e[r];if('"'===t&&!a)break;a="\\"===t&&!a,"\\"!==t&&(a=!1),r+=1}if(r>=e.length)throw new p("INVALID_ARGS",`Invalid replay script line: ${e}`);let n=e.slice(i,r+1);t.push(JSON.parse(n)),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,...a]=i;if("context"===r)return null;let n={ts:Date.now(),command:r,positionals:[],flags:{}};if("snapshot"===r){n.positionals=[];for(let e=0;e<a.length;e+=1){let t=a[e];if("-i"===t){n.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){n.flags.snapshotCompact=!0;continue}if("--raw"===t){n.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<a.length){let t=Number(a[e+1]);Number.isFinite(t)&&t>=0&&(n.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<a.length){n.flags.snapshotScope=a[e+1],e+=1;continue}if("--backend"===t&&e+1<a.length){let t=a[e+1];("ax"===t||"xctest"===t)&&(n.flags.snapshotBackend=t),e+=1}}return n}if("click"===r){if(0===a.length)return n;let e=a[0];return e.startsWith("@")?(n.positionals=[e],a[1]&&(n.result={refLabel:a[1]})):n.positionals=[a.join(" ")],n}if("fill"===r){if(a.length<2)return n.positionals=a,n;let e=a[0];return e.startsWith("@")?(a.length>=3?(n.positionals=[e,a.slice(2).join(" ")],n.result={refLabel:a[1]}):n.positionals=[e,a[1]],n):(n.positionals=[e,a.slice(1).join(" ")],n)}if("get"===r){if(a.length<2)return n.positionals=a,n;let e=a[0],t=a[1];return t.startsWith("@")?(n.positionals=[e,t],a[2]&&(n.result={refLabel:a[2]})):n.positionals=[e,a.slice(1).join(" ")],n}return n.positionals=a,n}(i);e&&t.push(e)}return t}(l),f=t.flags?.replayUpdate===!0,m=0;for(let e=0;e<u.length;e+=1){let o=u[e];if(!o||"replay"===o.command)continue;let l=await n({token:t.token,session:i,command:o.command,positionals:o.positionals??[],flags:o.flags??{}});if(l.ok)continue;if(!f)return l;let c=await tI({action:o,sessionName:i,logPath:r,sessionStore:a,dispatch:s});if(!c||(u[e]=c,!(l=await n({token:t.token,session:i,command:c.command,positionals:c.positionals??[],flags:c.flags??{}})).ok))return l;m+=1}if(f&&m>0){let e=a.get(i);!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",tk(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),e.flags?.snapshotBackend&&t.push("--backend",e.flags.snapshotBackend),t.join(" ");for(let i of e.positionals??[])t.push(tk(i));return t.join(" ")}(e));let a=`${r.join("\n")}
|
|
9
|
+
`,n=`${e}.tmp-${process.pid}-${Date.now()}`;d.writeFileSync(n,a),d.renameSync(n,e)}(o,u,e)}return{ok:!0,data:{replayed:u.length,healed:m,session:i}}}catch(t){let e=l(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("close"===c){let e=a.get(i);return e?(t.positionals&&t.positionals.length>0&&await s(e.device,"close",t.positionals??[],t.flags?.out,{...eY(r,t.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&"simulator"===e.device.kind&&await ex(e.device.id),a.recordAction(e,{command:c,positionals:t.positionals??[],flags:t.flags??{},result:{session:i}}),t.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 tI(e){let{action:t,sessionName:i,logPath:r,sessionStore:a,dispatch:n}=e;if(!["click","fill","get","is","wait"].includes(t.command))return null;let o=a.get(i);if(!o)return null;let s="click"===t.command||"fill"===t.command,l=await tb(o,t,r,s,n,a);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),"click"===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 i=tc(e.positionals.slice(1));i&&t.push(i.selectorExpression)}if("wait"===e.command){let{selectorExpression:i}=tN(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 eH(t).filter(e=>e.trim().length>0)}(t)){let i=tn(e),r=to(l.nodes,i,{platform:o.device.platform,requireRect:s,requireUnique:!0});if(!r)continue;let a=tf(r.node,o.device.platform,{action:"click"===t.command?"click":"fill"===t.command?"fill":"get"}).join(" || ");if("click"===t.command)return{...t,positionals:[a]};if("fill"===t.command){let e=eJ(t);if(!e)continue;return{...t,positionals:[a,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,a]}}if("is"===t.command){let e=t.positionals?.[0];if(!e)continue;let i=tc(t.positionals.slice(1)),r=i?.rest.join(" ").trim()??"",n=[e,a];return"text"===e&&r.length>0&&n.push(r),{...t,positionals:n}}if("wait"===t.command){let{selectorTimeout:e}=tN(t.positionals??[]),i=[a];return e&&i.push(e),{...t,positionals:i}}}return null}async function tb(e,t,i,r,a,n){let o=await a(e.device,"snapshot",[],t.flags?.out,{...eY(i,{...t.flags??{},snapshotInteractiveOnly:r,snapshotCompact:r},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:eQ(t.flags?.snapshotRaw?s:e5(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,n.set(e.name,e),l}function tN(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],i=/^\d+$/.test(t??""),r=tc(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 tk(e){let t=e.trim();return t.startsWith("@")||/^-?\d+(\.\d+)?$/.test(t)?t:JSON.stringify(t)}function tS(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}async function tD(e){let{req:t,sessionName:i,logPath:r,sessionStore:a}=e,n=t.command;if("snapshot"===n){let{session:e,device:n}=await tx(a,i,t.flags);if(!eW("snapshot",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is only supported on iOS simulators in v1"}};let o=e?.appBundleId,s=t.flags?.snapshotScope;if(s&&s.trim().startsWith("@")){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}};let t=e0(s.trim());if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${s}`}};let i=e1(e.snapshot.nodes,t),r=i?e4(i,e.snapshot.nodes):void 0;if(!r)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no label`}};s=r}let l=await eU(n,"snapshot",[],t.flags?.out,{...eY(r,{...t.flags,snapshotScope:s},o,e?.trace?.outPath)}),c=l?.nodes??[],u=eQ(t.flags?.snapshotRaw?c:e5(c)),d={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},f=e?{...e,snapshot:d}:{name:i,device:n,createdAt:Date.now(),appBundleId:o,snapshot:d,actions:[]};return tL(a,f,t,{nodes:u.length,truncated:l?.truncated??!1}),a.set(i,f),{ok:!0,data:{nodes:u,truncated:l?.truncated??!1,appName:f.appBundleId?f.appName??f.appBundleId:void 0,appBundleId:f.appBundleId}}}if("wait"===n){let e,n,{session:o,device:s}=await tx(a,i,t.flags),l=function(e){if(0===e.length)return null;let t=tS(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=tS(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=tS(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let i=tS(e[e.length-1]),r=tc(null!==i?e.slice(0,-1):e.slice());if(r&&0===r.rest.length){let e=function(e){try{return tn(e)}catch{return null}}(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??[]);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}};if("sleep"===l.kind)return await new Promise(e=>setTimeout(e,l.durationMs)),tL(a,o,t,{waitedMs:l.durationMs}),{ok:!0,data:{waitedMs:l.durationMs}};if(!eW("wait",s))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}};if("selector"===l.kind){let e=l.timeoutMs??1e4,n=Date.now();for(;Date.now()-n<e;){let e=await eU(s,"snapshot",[],t.flags?.out,{...eY(r,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},o?.appBundleId,o?.trace?.outPath)}),c=e?.nodes??[],u=eQ(t.flags?.snapshotRaw?c:e5(c));o&&(o.snapshot={nodes:u,truncated:e?.truncated,createdAt:Date.now(),backend:e?.backend},a.set(i,o));let d=ts(u,l.selector,{platform:s.platform});if(d)return tL(a,o,t,{selector:d.selector.raw,waitedMs:Date.now()-n}),{ok:!0,data:{selector:d.selector.raw,waitedMs:Date.now()-n}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${l.selectorExpression}`}}}if("ref"===l.kind){if(!o?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=e0(l.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${l.rawRef}`}};let i=e1(o.snapshot.nodes,t),r=i?e4(i,o.snapshot.nodes):void 0;if(!r)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${l.rawRef} not found or has no label`}};e=r,n=l.timeoutMs}else e=l.text,n=l.timeoutMs;if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let c=n??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===s.platform&&"simulator"===s.kind){let i=await eN(s,{command:"findText",text:e,appBundleId:o?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:o?.trace?.outPath});if(i?.found)return tL(a,o,t,{text:e,waitedMs:Date.now()-u}),{ok:!0,data:{text:e,waitedMs:Date.now()-u}}}else if("android"===s.platform&&e3(eQ((await K(s,{scope:e})).nodes??[]),e))return tL(a,o,t,{text:e,waitedMs:Date.now()-u}),{ok:!0,data:{text:e,waitedMs:Date.now()-u}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${e}`}}}if("alert"===n){let{session:e,device:n}=await tx(a,i,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();if(!eW("alert",n))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators in v1"}};if("wait"===o){let i=tS(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<i;){try{let i=await eN(n,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath});return tL(a,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 s=await eN(n,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:r,traceLogPath:e?.trace?.outPath});return tL(a,e,t,s),{ok:!0,data:s}}if("settings"===n){let e=t.positionals?.[0],n=t.positionals?.[1];if(!e||!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"settings requires <wifi|airplane|location> <on|off>"}};let{session:o,device:s}=await tx(a,i,t.flags),l=o?.appBundleId,c=await eU(s,"settings",[e,n,l??""],t.flags?.out,{...eY(r,t.flags,l,o?.trace?.outPath)});return tL(a,o,t,c??{setting:e,state:n}),{ok:!0,data:c??{setting:e,state:n}}}return null}async function tx(e,t,i){let r=e.get(t),a=r?.device??await eG(i??{});return r||await eZ(a),{session:r,device:a}}function tL(e,t,i,r){t&&e.recordAction(t,{command:i.command,positionals:i.positionals??[],flags:i.flags??{},result:r})}function t_(e,t,i,r={}){let a=tM(i);if(!a)return null;let n=null;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()).startsWith("ax")&&(t=t.replace(/^ax/,"")),t):""}(e??"");return i?i===t?2:+!!i.includes(t):0}(e.type,i);case"label":return tO(e.label,i);case"value":return tO(e.value,i);case"id":return tO(e.identifier,i);default:return Math.max(tO(e.label,i),tO(e.value,i),tO(e.identifier,i))}}(i,t,a);if(!(e<=0)&&(!n||e>n.score)&&(n={node:i,score:e},e>=2))break}return n?.node??null}function tO(e,t){let i=tM(e??"");return i?i===t?2:+!!i.includes(t):0}function tM(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function tR(e){let{req:t,sessionName:i,logPath:r,sessionStore:a,invoke:n}=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:c,action:u,value:d,timeoutMs:f}=function(e){let t="any",i=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],i=1);let r=e[i]??"",a=e.slice(i+1);if(0===a.length)return{locator:t,query:r,action:"click"};let n=a[0].toLowerCase();if("get"===n){let e=a[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 p("INVALID_ARGS","find get only supports text or attrs")}if("wait"===n)return{locator:t,query:r,action:"wait",timeoutMs:tS(a[1])??void 0};if("exists"===n)return{locator:t,query:r,action:"exists"};if("click"===n)return{locator:t,query:r,action:"click"};if("focus"===n)return{locator:t,query:r,action:"focus"};if("fill"===n)return{locator:t,query:r,action:"fill",value:a.slice(1).join(" ")};if("type"===n)return{locator:t,query:r,action:"type",value:a.slice(1).join(" ")};throw new p("INVALID_ARGS",`Unsupported find action: ${a[0]}`)}(s);if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=a.get(i);if(!m&&"exists"!==u&&"wait"!==u&&"get_text"!==u&&"get_attrs"!==u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await eG(t.flags??{});m||await eZ(h);let w=m?.appBundleId,g="role"!==l?c:void 0,v="click"===u||"focus"===u||"fill"===u||"type"===u,y=0,A=null,I=async()=>{let e=Date.now();if(A&&e-y<750)return{nodes:A};let n=await eU(h,"snapshot",[],t.flags?.out,{...eY(r,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),o=n?.nodes??[],s=eQ(t.flags?.snapshotRaw?o:e5(o));return y=e,A=s,m&&(m.snapshot={nodes:s,truncated:n?.truncated,createdAt:Date.now(),backend:n?.backend},a.set(i,m)),{nodes:s,truncated:n?.truncated,backend:n?.backend}};if("wait"===u){let e=f??1e4,i=Date.now();for(;Date.now()-i<e;){let{nodes:e}=await I();if(t_(e,l,c,{requireRect:!1}))return m&&a.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:b}=await I(),N=t_(b,l,c,{requireRect:v});if(!N)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let k="click"===u||"focus"===u||"fill"===u||"type"===u?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}(b,N)??N:N,S=`@${k.ref}`,D={...t.flags??{},noRecord:!0};if("exists"===u)return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===u){let e=e9(N);return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"get text",text:e}}),{ok:!0,data:{ref:S,text:e,node:N}}}if("get_attrs"===u)return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"get attrs"}}),{ok:!0,data:{ref:S,node:N}};if("click"===u){let e=await n({token:t.token,session:i,command:"click",positionals:[S],flags:D});return e.ok&&m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"click"}}),e}if("fill"===u){if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await n({token:t.token,session:i,command:"fill",positionals:[S,d],flags:D});return e.ok&&m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"fill"}}),e}if("focus"===u){let e=N.rect?e2(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let i=await eU(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...eY(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"focus"}}),{ok:!0,data:i??{ref:S}}}if("type"===u){if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=N.rect?e2(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await eU(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...eY(r,t.flags,m?.appBundleId,m?.trace?.outPath)});let i=await eU(h,"type",[d],t.flags?.out,{...eY(r,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&a.recordAction(m,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:S,action:"type"}}),{ok:!0,data:i??{ref:S}}}return null}async function tP(e){let{req:t,sessionName:i,sessionStore:r}=e,a=t.command;if("record"===a){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let o=r.get(i),s=o?.device??await eG(t.flags??{});o||await eZ(s);let l=o??{name:i,device:s,createdAt:Date.now(),actions:[]};if("start"===e){if(l.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.positionals?.[1]??`./recording-${Date.now()}.mp4`,o=n.resolve(e),c=n.dirname(o);if(d.existsSync(c)||d.mkdirSync(c,{recursive:!0}),!eW("record",s))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is only supported on iOS simulators in v1"}};if("ios"===s.platform){let{child:e,wait:t}=u("xcrun",["simctl","io",s.id,"recordVideo",o],{allowFailure:!0});l.recording={platform:"ios",outPath:o,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:i}=u("adb",["-s",s.id,"shell","screenrecord",e],{allowFailure:!0});l.recording={platform:"android",outPath:o,remotePath:e,child:t,wait:i}}return r.set(i,l),r.recordAction(l,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:e}}}if(!l.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let c=l.recording;c.child.kill("SIGINT");try{await c.wait}catch{}if("android"===c.platform&&c.remotePath)try{await m("adb",["-s",s.id,"pull",c.remotePath,c.outPath],{allowFailure:!0}),await m("adb",["-s",s.id,"shell","rm","-f",c.remotePath],{allowFailure:!0})}catch{}return l.recording=void 0,r.recordAction(l,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:c.outPath}}),{ok:!0,data:{recording:"stopped",outPath:c.outPath}}}if("trace"===a){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(o.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??r.defaultTracePath(o),i=eX.expandHome(e);return d.mkdirSync(n.dirname(i),{recursive:!0}),d.appendFileSync(i,""),o.trace={outPath:i,startedAt:Date.now()},r.recordAction(o,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:i}}),{ok:!0,data:{trace:"started",outPath:i}}}if(!o.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let s=o.trace.outPath;if(t.positionals?.[1]){let e=eX.expandHome(t.positionals[1]);d.mkdirSync(n.dirname(e),{recursive:!0}),d.existsSync(s)?d.renameSync(s,e):d.appendFileSync(e,""),s=e}return o.trace=void 0,r.recordAction(o,{command:a,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:s}}),{ok:!0,data:{trace:"stopped",outPath:s}}}return null}async function tC(e){let{req:t,sessionName:i,sessionStore:r,contextFromFlags:a}=e,n=t.command;if("click"===n){let e=r.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let o=t.positionals?.[0]??"";if(o.startsWith("@")){if(!e.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=e0(o);if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"click requires a ref like @e2"}};let s=e1(e.snapshot.nodes,i);if(!s?.rect&&t.positionals.length>1){let i=t.positionals.slice(1).join(" ").trim();i.length>0&&(s=e3(e.snapshot.nodes,i))}if(!s?.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${o} not found or has no bounds`}};let l=e4(s,e.snapshot.nodes),c=tf(s,e.device.platform,{action:"click"}),{x:u,y:d}=e2(s.rect);return await eU(e.device,"press",[String(u),String(d)],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)}),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,x:u,y:d,refLabel:l,selectorChain:c}}),{ok:!0,data:{ref:i,x:u,y:d}}}let s=(t.positionals??[]).join(" ").trim();if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"click requires @ref or selector expression"}};let l=tn(s),c=await tE(e,t.flags,r,a,{interactiveOnly:!0}),u=to(c.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:tl(l,u?.diagnostics??[],{unique:!0})}};let{x:d,y:f}=e2(u.node.rect);await eU(e.device,"press",[String(d),String(f)],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)});let p=tf(u.node,e.device.platform,{action:"click"}),m=e4(u.node,c.nodes);return r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{x:d,y:f,selector:u.selector.raw,selectorChain:p,refLabel:m}}),{ok:!0,data:{selector:u.selector.raw,x:d,y:f}}}if("fill"===n){let e=r.get(i);if(t.positionals?.[0]?.startsWith("@")){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=e0(t.positionals[0]);if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires a ref like @e2"}};let o=t.positionals.length>=3?t.positionals[1]:"",s=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let l=e1(e.snapshot.nodes,i);if(!l?.rect&&o&&(l=e3(e.snapshot.nodes,o)),!l?.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let c=l.type??"",u=c&&!e7(c,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${c}", attempting fill anyway.`:void 0,d=e4(l,e.snapshot.nodes),f=tf(l,e.device.platform,{action:"fill"}),{x:p,y:m}=e2(l.rect),h={...await eU(e.device,"fill",[String(p),String(m),s],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:i,x:p,y:m}};return u&&(h.warning=u),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{...h,refLabel:d,selectorChain:f}}),{ok:!0,data:h}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let o=tc(t.positionals??[]);if(o){if(0===o.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let i=o.rest.join(" ").trim();if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let s=tn(o.selectorExpression),l=await tE(e,t.flags,r,a,{interactiveOnly:!0}),c=to(l.nodes,s,{platform:e.device.platform,requireRect:!0,requireUnique:!0});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:tl(s,c?.diagnostics??[],{unique:!0})}};let u=c.node,d=u.type??"",f=d&&!e7(d,e.device.platform)?`fill target ${c.selector.raw} resolved to "${d}", attempting fill anyway.`:void 0,{x:p,y:m}=e2(c.node.rect),h=await eU(e.device,"fill",[String(p),String(m),i],t.flags?.out,{...a(t.flags,e.appBundleId,e.trace?.outPath)}),w=tf(u,e.device.platform,{action:"fill"}),g={...h??{x:p,y:m,text:i},selector:c.selector.raw,selectorChain:w,refLabel:e4(u,l.nodes)};return f&&(g.warning=f),r.recordAction(e,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:g}),{ok:!0,data:g}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===n){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 o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=t.positionals?.[1]??"";if(s.startsWith("@")){if(!o.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}};let i=e0(s??"");if(!i)return{ok:!1,error:{code:"INVALID_ARGS",message:"get text requires a ref like @e2"}};let a=e1(o.snapshot.nodes,i);if(!a&&t.positionals.length>2){let e=t.positionals.slice(2).join(" ").trim();e.length>0&&(a=e3(o.snapshot.nodes,e))}if(!a)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found`}};let l=tf(a,o.device.platform,{action:"get"});if("attrs"===e)return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,selectorChain:l}}),{ok:!0,data:{ref:i,node:a}};let c=e9(a);return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{ref:i,text:c,refLabel:c||void 0,selectorChain:l}}),{ok:!0,data:{ref:i,text:c,node:a}}}let l=t.positionals.slice(1).join(" ").trim();if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let c=tn(l),u=to((await tE(o,t.flags,r,a,{interactiveOnly:!1})).nodes,c,{platform:o.device.platform,requireRect:!1,requireUnique:!0});if(!u)return{ok:!1,error:{code:"COMMAND_FAILED",message:tl(c,[],{unique:!0})}};let d=u.node,f=tf(d,o.device.platform,{action:"get"});if("attrs"===e)return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{selector:u.selector.raw,selectorChain:f}}),{ok:!0,data:{selector:u.selector.raw,node:d}};let p=e9(d);return r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{text:p,refLabel:p||void 0,selector:u.selector.raw,selectorChain:f}}),{ok:!0,data:{selector:u.selector.raw,text:p,node:d}}}if("is"===n){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 o=r.get(i);if(!o)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!eW("is",o.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let s=tc(t.positionals.slice(1));if(!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let l=s.rest.join(" ").trim();if("text"===e&&!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&s.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let c=tn(s.selectorExpression),u=await tE(o,t.flags,r,a,{interactiveOnly:!1});if("exists"===e){let i=ts(u.nodes,c,{platform:o.device.platform});return i?(r.recordAction(o,{command:n,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:tl(c,[],{unique:!1})}}}let d=to(u.nodes,c,{platform:o.device.platform,requireUnique:!0});if(!d)return{ok:!1,error:{code:"COMMAND_FAILED",message:tl(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:i,expectedText:r,platform:a}=e,n=e9(i),o=!1;switch(t){case"visible":o=tu(i);break;case"hidden":o=!tu(i);break;case"editable":o=td(i,a);break;case"selected":o=!0===i.selected;break;case"text":o=n===(r??"")}let s="text"===t?`expected="${r??""}" actual="${n}"`:`actual=${JSON.stringify({visible:tu(i),editable:td(i,a),selected:!0===i.selected})}`;return{pass:o,actualText:n,details:s}}({predicate:e,node:d.node,expectedText:l,platform:o.device.platform});return f.pass?(r.recordAction(o,{command:n,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:d.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:d.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${d.selector.raw}: ${f.details}`}}}return null}async function tE(e,t,i,r,a){let n=await eU(e.device,"snapshot",[],t?.out,{...r({...t??{},snapshotInteractiveOnly:a.interactiveOnly,snapshotCompact:a.interactiveOnly},e.appBundleId,e.trace?.outPath)}),o=n?.nodes??[];return e.snapshot={nodes:eQ(t?.snapshotRaw?o:e5(o)),truncated:n?.truncated,createdAt:Date.now(),backend:n?.backend},i.set(e.name,e),e.snapshot}let t$=n.join(f.homedir(),".agent-device"),tF=n.join(t$,"daemon.json"),tT=n.join(t$,"daemon.log"),tV=new eX(n.join(t$,"sessions")),tB=function(){try{let e=function(){let e=n.dirname(c(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(d.existsSync(e))return t;t=n.dirname(t)}return e}();return JSON.parse(d.readFileSync(n.join(e,"package.json"),"utf8")).version??"0.0.0"}catch{return"0.0.0"}}(),tj=i.randomBytes(24).toString("hex"),tG=new Set(["session_list","devices"]);function tU(e,t,i){return eY(tT,e,t,i)}async function tq(e){if(e.token!==tj)return{ok:!1,error:{code:"UNAUTHORIZED",message:"Invalid token"}};let t=e.command,i=function(e,t){var i;let r,a=e.session||"default";if(i=e,"string"==typeof(r=i.flags?.session)&&r.trim().length>0||"default"!==a||t.has(a))return a;let n=t.toArray();return 1===n.length?n[0].name:a}(e,tV),r=tV.get(i);r&&!tG.has(t)&&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}`),0!==i.length){var a;let t,r,n;throw new p("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,r=a.device.name.trim(),n=a.device.id,`${t} device "${r}" (${n})`)} and cannot be used with ${i.join(", ")}. Use a different --session name or close this session first.`)}}(r,e.flags);let a=await tA({req:e,sessionName:i,logPath:tT,sessionStore:tV,invoke:tq});if(a)return a;let n=await tD({req:e,sessionName:i,logPath:tT,sessionStore:tV});if(n)return n;let o=await tP({req:e,sessionName:i,sessionStore:tV});if(o)return o;let s=await tR({req:e,sessionName:i,logPath:tT,sessionStore:tV,invoke:tq});if(s)return s;let l=await tC({req:e,sessionName:i,sessionStore:tV,contextFromFlags:tU});if(l)return l;let c=tV.get(i);if(!c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!eW(t,c.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}};let u=await eU(c.device,t,e.positionals??[],e.flags?.out,{...tU(e.flags,c.appBundleId,c.trace?.outPath)});return tV.recordAction(c,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:u??{}}),{ok:!0,data:u??{}}}(e=h.createServer(e=>{let t="";e.setEncoding("utf8"),e.on("data",async i=>{let r=(t+=i).indexOf("\n");for(;-1!==r;){let i,a=t.slice(0,r).trim();if(t=t.slice(r+1),0===a.length){r=t.indexOf("\n");continue}try{let e=JSON.parse(a);i=await tq(e)}catch(t){let e=l(t);i={ok:!1,error:{code:e.code,message:e.message,details:e.details}}}e.write(`${JSON.stringify(i)}
|
|
10
|
+
`),r=t.indexOf("\n")}})})).listen(0,"127.0.0.1",()=>{let t=e.address();if("object"==typeof t&&t?.port){var i;i=t.port,d.existsSync(t$)||d.mkdirSync(t$,{recursive:!0}),d.writeFileSync(tT,""),d.writeFileSync(tF,JSON.stringify({port:i,token:tj,pid:process.pid,version:tB},null,2),{mode:384}),process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${t.port}
|
|
11
|
+
`)}}),t=async()=>{for(let e of tV.toArray())"ios"===e.device.platform&&"simulator"===e.device.kind&&await ex(e.device.id),tV.writeSessionLog(e);e.close(()=>{d.existsSync(tF)&&d.unlinkSync(tF),process.exit(0)})},process.on("SIGINT",()=>{t()}),process.on("SIGTERM",()=>{t()}),process.on("SIGHUP",()=>{t()}),process.on("uncaughtException",e=>{let i=e instanceof p?e:l(e);process.stderr.write(`Daemon error: ${i.message}
|
|
10
12
|
`),t()});
|
|
@@ -704,7 +704,7 @@ final class RunnerTests: XCTestCase {
|
|
|
704
704
|
if options.interactiveOnly {
|
|
705
705
|
if interactiveTypes.contains(type) { return true }
|
|
706
706
|
if element.isHittable && type != .other { return true }
|
|
707
|
-
if hasContent
|
|
707
|
+
if hasContent { return true }
|
|
708
708
|
return false
|
|
709
709
|
}
|
|
710
710
|
if options.compact {
|
|
@@ -728,7 +728,7 @@ final class RunnerTests: XCTestCase {
|
|
|
728
728
|
if options.interactiveOnly {
|
|
729
729
|
if interactiveTypes.contains(type) { return true }
|
|
730
730
|
if snapshotHittable(snapshot) && type != .other { return true }
|
|
731
|
-
if hasContent
|
|
731
|
+
if hasContent { return true }
|
|
732
732
|
return false
|
|
733
733
|
}
|
|
734
734
|
if options.compact {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-device",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Unified control plane for physical and virtual devices via an agent-driven CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Callstack",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"prepack": "pnpm build:node && pnpm build:axsnapshot",
|
|
27
27
|
"typecheck": "tsc -p tsconfig.json",
|
|
28
28
|
"test": "node --test",
|
|
29
|
-
"test:unit": "node --test src/core/__tests__/*.test.ts src/daemon/__tests__/*.test.ts src/daemon/handlers/__tests__/*.test.ts",
|
|
29
|
+
"test:unit": "node --test src/core/__tests__/*.test.ts src/daemon/__tests__/*.test.ts src/daemon/handlers/__tests__/*.test.ts src/platforms/**/__tests__/*.test.ts",
|
|
30
30
|
"test:smoke": "node --test test/integration/smoke-*.test.ts",
|
|
31
31
|
"test:integration": "node --test test/integration/*.test.ts"
|
|
32
32
|
},
|