agent-device 0.7.4 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/daemon.js +19 -19
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +381 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +30 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +258 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +174 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +121 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +263 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +359 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +220 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +124 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +30 -1855
- package/ios-runner/README.md +14 -0
- package/package.json +1 -1
package/dist/src/daemon.js
CHANGED
|
@@ -8,27 +8,27 @@ ${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await p("adb",ej(e,["shell","
|
|
|
8
8
|
${t}`,i=r.indexOf("<?xml"),n=i>=0?i:r.indexOf("<hierarchy");if(n<0)return null;let a=r.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=r.slice(n,a+12).trim();return o.length>0?o:null}function tA(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}function ty(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function tN(e,t){let r=eV(t);if("toggle"!==r)return r;let i=await p("adb",ej(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current Android appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
|
|
9
9
|
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"yes"===i?"dark":"no"===i?"light":"auto"===i?"auto":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current Android appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"auto"===n?"dark":"dark"===n?"light":"dark"}async function tS(e,t,r){let i=await t_(e),n=[];for(let a of null!==i&&i>=33?["android.permission.READ_MEDIA_IMAGES","android.permission.READ_EXTERNAL_STORAGE"]:["android.permission.READ_EXTERNAL_STORAGE","android.permission.READ_MEDIA_IMAGES"]){let i=await p("adb",ej(e,["shell","pm",r,t,a]),{allowFailure:!0});if(0===i.exitCode)return;n.push({permission:a,stderr:i.stderr,exitCode:i.exitCode})}throw new I("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function tb(e,t,r,i){"grant"===r?await p("adb",ej(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await p("adb",ej(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await p("adb",ej(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await p("adb",ej(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await p("adb",ej(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function t_(e){let t=await p("adb",ej(e,["shell","getprop","ro.build.version.sdk"]),{allowFailure:!0});if(0!==t.exitCode)return null;let r=Number.parseInt(t.stdout.trim(),10);return!Number.isFinite(r)||r<=0?null:r}async function tD(e,t,r,i){let n=Math.max(1,Math.floor(r)),a=Array.from(t);for(let t=0;t<a.length;t+=n){let r=a.slice(t,t+n).join("");await ti(e,r),i>0&&t+n<a.length&&await tT(i)}}function tE(e){for(let t of e){let e=t.codePointAt(0);if(void 0!==e&&(e<32||e>126))return!0}return!1}async function tk(e,t){let r=await p("adb",ej(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":tO(r.stdout,r.stderr)?"unsupported":0===(await p("adb",ej(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",ej(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}function tO(e,t){let r=`${e}
|
|
10
10
|
${t}`.toLowerCase();return r.includes("no shell command implementation")||r.includes("unknown command")}async function tM(e,t,r){let i=await p("adb",ej(e,t),{allowFailure:!0});if(tO(i.stdout,i.stderr))throw new I("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new I("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}async function tL(e,t){let r=Math.max(0,t);await p("adb",ej(e,["shell","input","keyevent","KEYCODE_MOVE_END"]),{allowFailure:!0});for(let t=0;t<r;t+=24){let i=Math.min(24,r-t);await p("adb",ej(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function tx(e,t,r){let i,n=await tg(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=eM(i[0]),n=eC(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!d)continue;let c=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(u&&tC(a)){(!o||c<=o.area)&&(o={text:d,area:c});continue}if(p&&tC(a)){(!s||c<=s.area)&&(s={text:d,area:c});continue}p&&(!l||c<=l.area)&&(l={text:d,area:c})}return o?.text??s?.text??l?.text??null}function tC(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function tT(e){await new Promise(t=>setTimeout(t,e))}function tR(e,t,r){if(!e)return t;let i=Number(e);return Number.isFinite(i)?Math.max(r,Math.floor(i)):t}function tP(e,t={}){let r=en(t.simulatorSetPath);return r?["simctl","--set",r,...e]:["simctl",...e]}function t$(e,t){return"ios"!==e.platform||"simulator"!==e.kind?["simctl",...t]:tP(t,{simulatorSetPath:e.simulatorSetPath})}let tF=tR(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),tV=/^(iphone|ipad|ipod|appletv)/i,tU=/^appletv/i,tG=["apple tv","appletv","tvos"];function tB(e){return(e??"").trim().toLowerCase()}function tq(e){return tB(e.hardwareProperties?.platform)}function tj(e){return e.includes("tvos")}function tW(e){let t=tB(e);return tG.some(e=>t.includes(e))}function tH(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function tJ(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function tz(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await v("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=en(e.simulatorSetPath),i=await p("xcrun",tP(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(function(e){let t=tB(e);return t.includes("ios")||t.includes("tvos")}(i))for(let e of n){var a;e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:(a=i,tj(tB(a))?"tv":"mobile"),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let o=null;try{o=n.join(F.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",o],{allowFailure:!0,timeoutMs:tF});if(0!==e.exitCode)return t;let r=await x.readFile(o,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=tq(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=tJ(e),!!tV.test(t.trim())||tH(e).some(tW))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return tj(tq(e))?"tv":(t=tJ(e),tU.test(t.trim())||tH(e).some(tW))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{o&&await x.rm(o,{force:!0}).catch(()=>{})}return t}let tK=tR(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,z,5e3),tX=tR(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,J,1e3),tY=tR(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),tZ=tR(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3);async function tQ(e,t){let r=["devicectl",...e],i=await p("xcrun",r,{allowFailure:!0,timeoutMs:tZ});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new I("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:t2(n,a)??t1})}async function t0(e,t){let r=n.join(F.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",r],a=await p("xcrun",i,{allowFailure:!0,timeoutMs:tZ});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new I("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:i,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:t2(t,r)??t1})}let n=await x.readFile(r,"utf8");return o=function(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let r=[];for(let e of t){if(!e||"object"!=typeof e)continue;let t="string"==typeof e.bundleIdentifier?e.bundleIdentifier.trim():"";if(!t)continue;let i="string"==typeof e.name&&e.name.trim().length>0?e.name.trim():t;r.push({bundleId:t,name:i})}return r}(JSON.parse(n)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof I)throw t;throw new I("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await x.unlink(r).catch(()=>{})}}let t1="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function t2(e,t){let r=`${e}
|
|
11
|
-
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}async function t3(e,t,r){let i=(e.get(t)??Promise.resolve()).catch(()=>{}).then(r);return e.set(t,i),i.finally(()=>{e.get(t)===i&&e.delete(t)})}let t4=new Set;function t8(e){return!!e&&t4.has(e)}function t5(e){return e?.trim()??""}function t6(e=process.env){return t5(e.AGENT_DEVICE_IOS_BUNDLE_ID)||t5(e.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID)||"com.callstack.agentdevice.runner"}function t9(e=process.env){let t=t5(e.AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID);return t||`${t6(e)}.uitests`}let t7=function(e=process.env){let t=t6(e),r=t9(e);return Array.from(new Set([t5(e.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID),`${r}.xctrunner`,t
|
|
12
|
-
${e}`.toLowerCase()).includes("failed registering bundle identifier")||r.includes("app identifier")&&r.includes("not available")?"Set AGENT_DEVICE_IOS_BUNDLE_ID to a unique reverse-DNS value (for example, com.yourname.agentdevice.runner), then retry.":r.includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new I("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:
|
|
11
|
+
${t}`.toLowerCase();return r.includes("device is busy")&&r.includes("connecting")?"iOS device is still connecting. Keep it unlocked and connected by cable until it is fully available in Xcode Devices, then retry.":r.includes("coredeviceservice")&&r.includes("timed out")?"CoreDevice service timed out. Reconnect the device and retry; if it persists restart Xcode and the iOS device.":null}async function t3(e,t,r){let i=(e.get(t)??Promise.resolve()).catch(()=>{}).then(r);return e.set(t,i),i.finally(()=>{e.get(t)===i&&e.delete(t)})}let t4=new Set;function t8(e){return!!e&&t4.has(e)}function t5(e){return e?.trim()??""}function t6(e=process.env){return t5(e.AGENT_DEVICE_IOS_BUNDLE_ID)||t5(e.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID)||"com.callstack.agentdevice.runner"}function t9(e=process.env){let t=t5(e.AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID);return t||`${t6(e)}.uitests`}let t7=function(e=process.env){let t=t6(e),r=t9(e);return Array.from(new Set([t5(e.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID),`${r}.xctrunner`,t].filter(e=>e.length>0)))}(process.env),re=new Map,rt=new Map,rr=new Map,ri=new Set,rn=tR(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),ra=tR(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),ro=tR(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),rs=tR(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),rl=tR(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),rd=tR(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),ru=tR(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),rc=tR(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5),rp=n.join(F.homedir(),".agent-device","ios-runner");async function rf(e,t,r={}){var i;return(function(e){if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`)}(e),rL(r.requestId),"snapshot"===(i=t.command)||"screenshot"===i||"findText"===i||"alert"===i)?Z(()=>(rL(r.requestId),rm(e,t,r)),{shouldRetry:e=>(rL(r.requestId),function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!(t.includes("xcodebuild exited early")||t.includes("device is busy")&&t.includes("connecting"))&&!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}(e))}):rm(e,t,r)}async function rm(e,t,r={}){let i;rL(r.requestId);try{let n=(i=await rS(e,r)).ready?ra:rn;return await rh(e,i,t,r.logPath,n)}catch(a){let n=a instanceof I?a:new I("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===n.code&&"string"==typeof n.message&&n.message.includes("Runner did not accept connection")&&rC(n)&&i?.ready){rL(r.requestId),i?await rA(i):await rg(e.id),i=await rS(e,r);let n=await rR(i.device,i.port,t,r.logPath,rn);return await rw(n,i,r.logPath)}throw a}}async function rh(e,t,r,i,n){let a=await rR(e,t.port,r,i,n,t);return await rw(a,t,i)}async function rw(e,t,r){let i=await e.text(),n={};try{n=JSON.parse(i)}catch{throw new I("COMMAND_FAILED","Invalid runner response",{text:i})}if(!n.ok)throw new I("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:r});return t.ready=!0,n.data??{}}async function rg(e){await t3(rt,e,async()=>{await ry(e)})}async function rI(){let e=Array.from(re.values()),t=Array.from(ri);await Promise.allSettled(e.map(async e=>{await rb(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await rb(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await rb(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await rb(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await rb(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await rb(e.pid,"SIGKILL"),ri.delete(e)}))}async function rv(){await rI();let e=Array.from(re.keys());await Promise.allSettled(e.map(async e=>{await rg(e)})),await rD()}async function rA(e){await t3(rt,e.deviceId,async()=>{await ry(e.deviceId,e)})}async function ry(e,t){let r=t??re.get(e);if(r){try{await rR(r.device,r.port,{command:"shutdown"},void 0,15e3)}catch{await rb(r.child.pid,"SIGTERM")}try{await Promise.race([r.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await rb(r.child.pid,"SIGKILL"),rB(r.xctestrunPath),rB(r.jsonPath),re.get(e)===r&&re.delete(e)}}async function rN(e){await p("xcrun",t$(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:rn})}async function rS(e,t){return await t3(rt,e.id,async()=>{var r,i,n;let a,o=re.get(e.id);if(o){if((r=o.child.pid)&&C(r))return o;await ry(e.id,o)}await ("simulator"!==(i=e).kind?Promise.resolve():rN(i));let s=await r_(e,t),l=await rU(),{xctestrunPath:u,jsonPath:c}=await rG(s,{AGENT_DEVICE_RUNNER_PORT:String(l)},`session-${e.id}-${l}`),{child:p,wait:f}=d("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-collect-test-diagnostics","never",rk(e),"1","-destination-timeout",String(rc),"-xctestrun",u,"-destination",(a=rE(n=e),"simulator"===n.kind?`platform=${a} Simulator,id=${n.id}`:`platform=${a},id=${n.id}`)],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(l)},detached:!0});p.stdout?.on("data",e=>{rM(e,t.logPath,t.traceLogPath,t.verbose)}),p.stderr?.on("data",e=>{rM(e,t.logPath,t.traceLogPath,t.verbose)});let m={device:e,deviceId:e.id,port:l,xctestrunPath:u,jsonPath:c,testPromise:f,child:p,ready:!1};return re.set(e.id,m),m})}async function rb(e,t){if(!e||e<=0)return;try{process.kill(-e,t)}catch{}try{process.kill(e,t)}catch{}let r="SIGINT"===t?"INT":"SIGTERM"===t?"TERM":"KILL";try{await p("pkill",[`-${r}`,"-P",String(e)],{allowFailure:!0})}catch{}}async function r_(e,t){var r;let i,a=(r=e.kind,(i=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?n.resolve(i):"simulator"===r?n.join(rp,"derived"):n.join(rp,"derived",r));return await t3(rr,a,async()=>{var r,i;if(H(process.env.AGENT_DEVICE_IOS_CLEAN_DERIVED)){!function(e,t=process.env){if(t.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim()&&!function(e=process.env){return H(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new I("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(a);try{R.rmSync(a,{recursive:!0,force:!0})}catch{}}let o=rO(a);if(o)return o;let s=function(){let e=n.dirname(y(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(R.existsSync(e))return t;t=n.dirname(t)}return e}(),l=n.join(s,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!R.existsSync(l))throw new I("COMMAND_FAILED","iOS runner project not found",{projectPath:l});let d=function(e=process.env){let t=t6(e),r=t9(e);return[`AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID=${t}`,`AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID=${r}`]}(process.env),u=function(e=process.env,t=!1){if(!t)return[];let r=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||"",i=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||"",n=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||"",a=["CODE_SIGN_STYLE=Automatic"];return r&&a.push(`DEVELOPMENT_TEAM=${r}`),i&&a.push(`CODE_SIGN_IDENTITY=${i}`),n&&a.push(`PROVISIONING_PROFILE_SPECIFIER=${n}`),a}(process.env,"device"===e.kind),c="device"===e.kind?["-allowProvisioningUpdates"]:[];try{let i;await N("xcodebuild",["build-for-testing","-project",l,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",rk(e),"1","-destination",(r=e,i=rE(r),"simulator"===r.kind?`platform=${i} Simulator,id=${r.id}`:`generic/platform=${i}`),"-derivedDataPath",a,"COMPILER_INDEX_STORE_ENABLE=NO",...d,...c,...u],{detached:!0,onSpawn:e=>{ri.add(e),e.on("close",()=>{ri.delete(e)})},onStdoutChunk:e=>{rM(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{rM(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(o){let e,r,n=o instanceof I?o:new I("COMMAND_FAILED",String(o)),a=(e=(i=n).details?JSON.stringify(i.details):"",(r=`${i.message}
|
|
12
|
+
${e}`.toLowerCase()).includes("failed registering bundle identifier")||r.includes("app identifier")&&r.includes("not available")?"Set AGENT_DEVICE_IOS_BUNDLE_ID to a unique reverse-DNS value (for example, com.yourname.agentdevice.runner), then retry.":r.includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new I("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:n.message,details:n.details,logPath:t.logPath,hint:a})}let p=rO(a);if(!p)throw new I("COMMAND_FAILED","Failed to locate .xctestrun after build");return p})}async function rD(){let e=Array.from(ri);await Promise.allSettled(e.map(async e=>{try{await rb(e.pid,"SIGTERM"),await rb(e.pid,"SIGKILL")}finally{ri.delete(e)}}))}function rE(e){if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"tv"===e.target?"tvOS":"iOS"}function rk(e){return"device"===e.kind?"-maximum-concurrent-test-device-destinations":"-maximum-concurrent-test-simulator-destinations"}function rO(e){if(!R.existsSync(e))return null;let t=[],r=[e];for(;r.length>0;){let e=r.pop();for(let i of R.readdirSync(e,{withFileTypes:!0})){let a=n.join(e,i.name);if(i.isDirectory()){r.push(a);continue}if(i.isFile()&&i.name.endsWith(".xctestrun"))try{let e=R.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 rM(e,t,r,i){t&&R.appendFileSync(t,e),r&&R.appendFileSync(r,e),i&&process.stderr.write(e)}function rL(e){if(t8(e))throw new I("COMMAND_FAILED","request canceled")}function rx(e){let{port:t,endpoints:r,logPath:i,lastError:n}=e,a="Runner did not accept connection";return new I("COMMAND_FAILED",a,{port:t,endpoints:r,logPath:i,lastError:n?String(n):void 0,reason:es({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:el("IOS_RUNNER_CONNECT_TIMEOUT")})}function rC(e){return!(e instanceof I)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}async function rT(e){var t,r;let i,{session:n,port:a,logPath:o}=e,s=await n.testPromise,l="Runner did not accept connection (xcodebuild exited early)",d=es({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new I("COMMAND_FAILED",l,{port:a,logPath:o,xcodebuild:{exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr},reason:d,hint:(t=s.stdout,r=s.stderr,(i=`${l}
|
|
13
13
|
${t}
|
|
14
|
-
${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":el("IOS_RUNNER_CONNECT_TIMEOUT"))})}async function
|
|
15
|
-
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",t$(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await
|
|
16
|
-
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:t2(n,a)??t1})}return{bundleId:r}}await
|
|
17
|
-
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function
|
|
14
|
+
${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":el("IOS_RUNNER_CONNECT_TIMEOUT"))})}async function rR(e,t,r,i,n=rn,a){let o=X.fromTimeoutMs(n),s=await rP(e,t,o.remainingMs()),l=null,d=Math.max(1,Math.ceil(n/ro));try{return await Y(async({deadline:o})=>{if(o?.isExpired())throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await rT({session:a,port:t,logPath:i});for(let i of("device"===e.kind&&(s=await rP(e,t,o?.remainingMs())),s))try{let e=o?.remainingMs()??n;if(e<=0)throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await r$(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)},Math.min(rd,e))}catch(e){l=e}throw new I("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:s,lastError:l?String(l):void 0})},{maxAttempts:d,baseDelayMs:rs,maxDelayMs:rl,jitter:.2,shouldRetry:rC},{deadline:o,phase:"ios_runner_connect"})}catch(e){l||(l=e)}if("simulator"===e.kind){let n=o.remainingMs();if(n<=0)throw rx({port:t,endpoints:s,logPath:i,lastError:l});let a=await rV(e,t,r,n);return new Response(a.body,{status:a.status})}throw rx({port:t,endpoints:s,logPath:i,lastError:l})}async function rP(e,t,r){let i=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return i;let n=await rF(e.id,r);return n&&i.unshift(`http://[${n}]:${t}/command`),i}async function r$(e,t,r){let i=new AbortController,n=setTimeout(()=>i.abort(),r);try{return await fetch(e,{...t,signal:i.signal})}finally{clearTimeout(n)}}async function rF(e,t){if("number"==typeof t&&t<=0)return null;let r="number"==typeof t?Math.max(1,Math.min(ru,t)):ru,i=n.join(F.tmpdir(),`agent-device-devicectl-info-${process.pid}-${Date.now()}.json`);try{let t=Math.max(1,Math.ceil(r/1e3)),n=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",i,"--timeout",String(t)],{allowFailure:!0,timeoutMs:r});if(0!==n.exitCode||!R.existsSync(i))return null;let a=JSON.parse(R.readFileSync(i,"utf8"));if(a.info?.outcome&&"success"!==a.info.outcome)return null;let o=(a.result?.connectionProperties?.tunnelIPAddress??a.result?.device?.connectionProperties?.tunnelIPAddress)?.trim();return o&&o.length>0?o:null}catch{return null}finally{rB(i)}}async function rV(e,t,r,i){let n=JSON.stringify(r),a=t$(e,["spawn",e.id,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`]),o=await p("xcrun",a,{allowFailure:!0,timeoutMs:i}),s=o.stdout;if(0!==o.exitCode){let e=es({message:"Runner did not accept connection (simctl spawn)",stdout:o.stdout,stderr:o.stderr,context:{platform:"ios",phase:"connect"}});throw new I("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode,reason:e,hint:el(e)})}return{status:200,body:s}}async function rU(){return await new Promise((e,t)=>{let r=V.createServer();r.listen(0,"127.0.0.1",()=>{let i=r.address();r.close(),"object"==typeof i&&i?.port?e(i.port):t(new I("COMMAND_FAILED","Failed to allocate port"))}),r.on("error",t)})}async function rG(e,t,r){let i,a=n.dirname(e),o=r.replace(/[^a-zA-Z0-9._-]/g,"_"),s=n.join(a,`AgentDeviceRunner.env.${o}.json`),l=n.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),d=await p("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==d.exitCode||!d.stdout.trim())throw new I("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:d.stderr});try{i=JSON.parse(d.stdout)}catch(t){throw new I("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}},c=i.TestConfigurations;if(Array.isArray(c))for(let e of c){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(i))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),i[e]=t);R.writeFileSync(s,JSON.stringify(i,null,2));let f=await p("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==f.exitCode)throw new I("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:f.stderr});return{xctestrunPath:l,jsonPath:s}}function rB(e){try{R.existsSync(e)&&R.unlinkSync(e)}catch{}}function rq(e,t){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function rj(e){let t,r;if("simulator"!==e.kind||"Booted"===await rW(e))return;let i=X.fromTimeoutMs(tK);try{await Y(async({deadline:i})=>{if(i?.isExpired())throw new I("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:tK});let n=Math.max(1e3,i?.remainingMs()??tK),a=await p("xcrun",t$(e,["boot",e.id]),{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
|
|
15
|
+
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",t$(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await rW(e);if("Booted"!==d)throw new I("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=es({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});return"IOS_BOOT_TIMEOUT"!==i&&"CI_RESOURCE_STARVATION_SUSPECTED"!==i}},{deadline:i,phase:"boot",classifyReason:e=>es({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=es({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new I("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:tK,elapsedMs:i.elapsedMs(),reason:n,hint:el(n),boot:t,bootstatus:r})}}async function rW(e){let t="string"==typeof e?e:e.id,r="string"==typeof e?tP(["list","devices","-j"]):t$(e,["list","devices","-j"]),i=await p("xcrun",r,{allowFailure:!0,timeoutMs:tX});if(0!==i.exitCode)return null;try{let e=JSON.parse(String(i.stdout??""));for(let r of Object.values(e.devices??{})){let e=r.find(e=>e.udid===t);if(e)return e.state}return null}catch{return null}}let rH={settings:"com.apple.Preferences"},rJ=null;function rz(e,t,r){return p("xcrun",t$(e,t),r)}function rK(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function rX(e,t){let r=t.trim();if(r.includes("."))return r;let i=rH[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await r7(e):await t0(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new I("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function rY(e,t,r){let i=r?.url?.trim();if(i){if(!ek(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await rj(e),await p("open",["-a","Simulator"],{allowFailure:!0}),await rz(e,["openurl",e.id,i]);return}let n=eO(r?.appBundleId??await rX(e,t),i);if(!n)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await iu(e,n,{payloadUrl:i});return}let n=t.trim();if(ek(n)){if("simulator"===e.kind){await rj(e),await p("open",["-a","Simulator"],{allowFailure:!0}),await rz(e,["openurl",e.id,n]);return}let t=eO(r?.appBundleId,n);if(!t)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await iu(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await rX(e,t);"simulator"===e.kind?await id(e,a):await iu(e,a)}async function rZ(e){"simulator"!==e.kind||"Booted"!==await rW(e)&&(await rj(e),await p("open",["-a","Simulator"],{allowFailure:!0}))}async function rQ(e,t){let r=await rX(e,t);if("simulator"===e.kind){await rj(e);let t=t$(e,["terminate",e.id,r]),i=await p("xcrun",t,{allowFailure:!0});if(0!==i.exitCode){if(i.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new I("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:t,stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return}await tQ(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function r0(e,t){let r=await rX(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await p("xcrun",t,{allowFailure:!0,timeoutMs:tZ});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!rK(`${n}
|
|
16
|
+
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:t2(n,a)??t1})}return{bundleId:r}}await rj(e);let i=await rz(e,["uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!rK(`${i.stdout}
|
|
17
|
+
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function r1(e,t){"simulator"!==e.kind?await tQ(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await rj(e),await rz(e,["install",e.id,t]))}async function r2(e,t,r){let{bundleId:i}=await r0(e,t);return await r1(e,r),{bundleId:i}}async function r3(e,t,r){if("simulator"===e.kind){await rj(e),await rz(e,["io",e.id,"screenshot",t]);return}try{await tQ(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(e){if(!function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
18
18
|
${r}
|
|
19
|
-
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(e))throw e}let i=(await
|
|
20
|
-
`,"utf8"),await
|
|
21
|
-
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let
|
|
22
|
-
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return
|
|
23
|
-
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}function is(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function il(e,t){await rq(e),await p("open",["-a","Simulator"],{allowFailure:!0});let r=X.fromTimeoutMs(tY);await Y(async({deadline:r})=>{if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tY});let i=t$(e,["launch",e.id,t]),n=await p("xcrun",i,{allowFailure:!0});if(0!==n.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${n.exitCode}`,{cmd:"xcrun",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:is},{deadline:r})}async function id(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tQ(i,{action:"launch iOS app",deviceId:e.id})}let iu=/^[A-Za-z0-9_.:-]{1,64}$/;function ic(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!R.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function ip(e){let t=q(e.platform),r=en(e.iosSimulatorDeviceSet),i=eo(e.androidDeviceAllowlist);return await O("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await th();let e=await eA({serialAllowlist:i});return await j(e,n)}if("ios"===n.platform){let e=await tz({simulatorSetPath:r});return await j(e,n)}let a=[];try{a.push(...await eA({serialAllowlist:i}))}catch{}try{a.push(...await tz({simulatorSetPath:r}))}catch{}return await j(a,n)},{platform:t,target:e.target})}async function im(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>e0(e,t,r?.activity),openDevice:()=>e2(e),close:t=>e3(e,t),tap:(t,r)=>e6(e,t,r),doubleTap:async(t,r)=>{await e6(e,t,r),await e6(e,t,r)},swipe:(t,r,i,n,a)=>e9(e,t,r,i,n,a),longPress:(t,r,i)=>tr(e,t,r,i),focus:(t,r)=>to(e,t,r),type:t=>ti(e,t),fill:(t,r,i)=>ts(e,t,r,i),scroll:(t,r)=>tl(e,t,r),scrollIntoView:t=>td(e,t),screenshot:(t,r)=>tu(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>rX(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rY(e),close:t=>rZ(e,t),screenshot:(t,r)=>r2(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(t8(i.requestId))throw new I("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await rp(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await rp(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await rp(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await rp(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await rp(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await rp(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await rp(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await rp(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await rp(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await rp(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await rp(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await rp(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await O("platform_command",async()=>{var s,l,d,u,c,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(ek(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!ek(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=iw(a?.count??1,"count",1,200),c=iw(a?.intervalMs??0,"interval-ms",0,1e4),p=iw(a?.holdMs??0,"hold-ms",0,1e4),f=iw(a?.jitterPx??0,"jitter-px",0,100),m=a?.doubleTap===!0;if(m&&p>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(m&&f>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,u=f,"ios"===s.platform&&l>1&&0===d&&0===u)return await rp(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:c,doubleTap:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m,timingMode:"runner-series"};return await iv(n,c,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=ih[e%ih.length];return[r*t,i*t]}(e,f),a=t+r,s=i+n;m?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=iw(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=iw(a?.count??1,"count",1,200),f=iw(a?.pauseMs??0,"pause-ms",0,1e4),m=a?.pattern??"one-way";if("one-way"!==m&&"ping-pong"!==m)throw new I("INVALID_ARGS",`Invalid pattern: ${m}`);if(c=e,p=u,"ios"===c.platform&&p>1)return await rp(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:f,pattern:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:f,pattern:m};return await iv(u,f,async e=>{"ping-pong"===m&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:f,pattern:m}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await rp(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!iu.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await rp(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await e7(e),{action:"back"};case"home":if("ios"===e.platform)return await rp(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await te(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await rp(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await tt(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await r3(e):await tn(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await r4(e,i):await ta(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await eZ(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await eY(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await r5(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await tc(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await ig(i);if("ios"===e.platform)return await r8(e,t,n),{platform:"ios",bundleId:t};let a=await tf(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await O("snapshot_capture",async()=>await rp(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await O("snapshot_capture",async()=>await tm(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let ih=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function iw(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function ig(e){let t=ic(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await iI(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function iI(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function iv(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await iA(t)}async function iA(e){await new Promise(t=>setTimeout(t,e))}let iy={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function iN(e,t){let r=iy[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function iS(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function ib(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let i_=/^-?\d+(\.\d+)?$/,iD=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),iE=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function ik(e){return"click"===e||"press"===e}function iO(e){let t=e.trim();return t.startsWith("@")||i_.test(t)?t:JSON.stringify(t)}function iM(e,t){let r=t.flags??{};if(ik(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function iL(e,t){let r=[],i={},n=ik(e)?iD:"swipe"===e?iE:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(ik(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class ix{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=ix.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}}(t.flags),result:t.result}),M({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=n.dirname(t);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(ik(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(iO(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(iO(i)),iM(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(iO(r)),iM(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(iO(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(iO(i)),n&&t.push(iO(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(iO(r)),t.push(iO(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(iO(r))}return t.join(" ")}}if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iO(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iO(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iO(r));return iM(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
24
|
-
`}(e,this.buildOptimizedActions(e));R.writeFileSync(t,i)}catch{}}defaultTracePath(e){let t=
|
|
25
|
-
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":t1)}function
|
|
26
|
-
`)}function
|
|
27
|
-
`)},flush:()=>{i&&(n(i),i="")}}}function nh(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function nw(e,t){let r=(await p("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function ng(e,t,r,i){let n="active",a=h("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=nm(t,{redactionPatterns:r});"number"==typeof a.pid&&nd(i,a.pid);let s=nh(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nu(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await np(s),a.killed||a.kill("SIGKILL"),await np(s),nu(i)}}}async function nI(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=nm(t,{redactionPatterns:r});"number"==typeof a.pid&&nd(i,a.pid);let s=nh(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nu(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await np(s),a.killed||a.kill("SIGKILL"),await np(s),nu(i)}}}async function nv(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await nw(e,t);if(!d){await nf(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=nm(r,{redactionPatterns:i});o=nh(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&nd(n,u.pid);let p=await o;if(nu(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await nf(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),nu(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await np(o),a&&!a.killed&&a.kill("SIGKILL"),await np(d),nu(n)}}}async function nA(e,t,r,i){nc(r);let n=R.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await nI(e.id,n,a,i):await ng(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new I("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await nv(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function ny(e){await e.stop(),await np(e.wait)}async function nN(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await p("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await p("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await p("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await p("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function nS(e){let t=n.dirname(e),r=n.basename(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),R.existsSync(e)?R.truncateSync(e,0):R.writeFileSync(e,"","utf8");let i=0;for(let e of R.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{R.unlinkSync(n.join(t,e)),i+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:i}}let nb=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),n_=/https?:\/\/[^\s"'<>\])]+/i,nD=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function nE(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function nk(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return nO(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function nO(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function nM(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function nL(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let nx='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nC=["platform","target","device","udid","serial","verbose","out"],nT=["platform","target","device","udid","serial","verbose","out"],nR=["path","start","stop","doctor","mark","clear"],nP=`logs requires ${nR.slice(0,-1).join(", ")}, or ${nR.at(-1)}`,n$="Not implemented for this platform in this release.",nF="open-command-roundtrip";function nV(e){let{sessionName:t,appName:r,appBundleId:i,startup:n}=e,a={session:t};return r&&(a.appName=r),i&&(a.appBundleId=i),n&&(a.startup=n),a}function nU(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:nF,appTarget:t,appBundleId:r}}let nG=["dump","log"],nB=`network requires ${nG.join(" or ")}`,nq=["summary","headers","body","all"],nj=`network include mode must be one of: ${nq.join(", ")}`;function nW(e,t,r){return t||nH(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nH(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nJ(e){let t=nH(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function nz(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let nK=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:eD}));return await i({avdName:e,serial:t,headless:r})};async function nX(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=nW(l,p,f);if(m)return m;let h=await nJ({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iN(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...iC(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let nY={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:r1}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e5}));return await i(e,t,r)}};async function nZ(e,t,r){if("ios"===e.platform&&t)return ek(t)?"device"===e.kind?eO(r,t):void 0:await nQ(e,t)}async function nQ(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rK}));return await r(e,t)}catch{return}}async function n0(e,t){if(!("android"!==e.platform||!t||ek(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eW})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function n1(e,t,r,i){return await nZ(e,t,r)??await i(e,t)??("android"===e.platform&&t&&ek(t)?r:void 0)}async function n2(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=q(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=nW("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nH(e))return!0;let r=q(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nx}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await nJ({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nx}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eX})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function n3(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=nW("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nJ({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iN("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...iC(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function n4(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a,dispatch:o,ensureReady:s,resolveTargetDevice:l,reinstallOps:d=nY,stopIosRunner:u,appLogOps:c={start:nA,stop:ny},ensureAndroidEmulatorBoot:p=nK,resolveAndroidPackageForOpen:f=n0}=e,m=o??im,h=s??iR,g=l??ip,v=t.command;if("session_list"===v)return{ok:!0,data:{sessions:n.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===v)try{let e=[],r=en(t.flags?.iosSimulatorDeviceSet),i=eo(t.flags?.androidDeviceAllowlist),n=q(t.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA}));e.push(...await t({serialAllowlist:i}))}else if("ios"===n){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tz}));e.push(...await t({simulatorSetPath:r}))}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:tz}));try{e.push(...await t({serialAllowlist:i}))}catch{}try{e.push(...await n({simulatorSetPath:r}))}catch{}}let a=(t.flags?.target?e.filter(e=>(e.target??"mobile")===t.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===v){let e=n.get(r),i=t.flags??{},a=nW(v,e,i);if(a)return a;let o=await nJ({session:e,flags:i,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!0});if(!iN("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=t.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:r6}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:eH}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===v){let e,i=n.get(r),a=t.flags??{},o=nW(v,i,a);if(o)return o;let s="android"===(q(a.platform)??i?.device.platform),l=!0===a.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=nz({flags:a,sessionDevice:i?.device}),u=s&&!!d,c=!1;try{e=await nJ({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1})}catch(r){let t=w(r);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw r;e=await p({avdName:d,serial:a.serial,headless:l}),c=!0}if(a.target&&(e.target??"mobile")!==a.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${a.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let t=nz({flags:a,sessionDevice:i?.device,resolvedDevice:e});if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await p({avdName:t,serial:a.serial,headless:!0})}await h(e)}else("android"!==e.platform||!0!==e.booted)&&await h(e);return iN("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===v)return await n2({req:t,sessionName:r,sessionStore:n,ensureReady:h,resolveDevice:g});if("clipboard"===v)return await n3({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m});if("keyboard"===v)return await nX({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"keyboard",positionals:t.positionals??[]});if("perf"===v){let e,t,i,a=n.get(r);return a?{ok:!0,data:(i=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===nF&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:nF,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(a.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:nF,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:nF},{session:a.name,platform:a.device.platform,device:a.device.name,deviceId:a.device.id,metrics:{startup:i,fps:{available:!1,reason:n$},memory:{available:!1,reason:n$},cpu:{available:!1,reason:n$}},sampling:{startup:{method:nF,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("reinstall"===v){let e,i=n.get(r),a=t.flags??{},o=nW(v,i,a);if(o)return o;let s=t.positionals?.[0]?.trim(),l=t.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let u=ix.expandHome(l);if(!R.existsSync(u))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${u}`}};let c=await nJ({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1});if(!iN("reinstall",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===c.platform){let t=await d.ios(c,s,u);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await d.android(c,s,u);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:u,...e};return i&&n.recordAction(i,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),{ok:!0,data:p}}if("push"===v){let e,a=t.positionals?.[0]?.trim(),o=t.positionals?.[1]?.trim();if(!a||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=ic(o,{subject:"Push payload",cwd:t.meta?.cwd,expandPath:(e,t)=>ix.expandHome(e,t)})).kind?e.path:e.text;return await nX({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"push",positionals:[a,s],recordPositionals:[a,o]})}if("trigger-app-event"===v)return await nX({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"trigger-app-event",positionals:t.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await n1(e.device,r,e.appBundleId,f)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===v){let e=t.flags?.relaunch===!0;if(n.has(r)){let a=n.get(r),o=t.positionals?.[0],s=o??(e?a?.appName:void 0);if(!a||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&ek(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await h(a.device);let l=await n1(a.device,s,a.appBundleId,f),d=o?t.positionals??[]:[s];if(e){let e=l??s;await m(a.device,"close",[e],t.flags?.out,{...iC(i,t.flags,l??a.appBundleId,a.trace?.outPath)})}let u=Date.now();await m(a.device,"open",d,t.flags?.out,{...iC(i,t.flags,l)});let c=nU(u,s,l),p={...a,appBundleId:l,appName:s,recordSession:a.recordSession||!!t.flags?.saveScript,snapshot:void 0},w=nV({sessionName:r,appName:s,appBundleId:l,startup:c});return n.recordAction(p,{command:v,positionals:d,flags:t.flags??{},result:w}),n.set(r,p),{ok:!0,data:w}}let a=t.positionals?.[0];if(e&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&a&&ek(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let o=await g(t.flags??{}),s=n.toArray().find(e=>e.device.id===o.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:o.id,deviceName:o.name}}};await h(o);let l=await n1(o,a,void 0,f);if(e&&a){let e=l??a;await m(o,"close",[e],t.flags?.out,{...iC(i,t.flags,l)})}let d=Date.now();await m(o,"open",t.positionals??[],t.flags?.out,{...iC(i,t.flags,l)});let u=a?nU(d,a,l):void 0,c={name:r,device:o,createdAt:Date.now(),appBundleId:l,appName:a,recordSession:!!t.flags?.saveScript,actions:[]},p=nV({sessionName:r,appName:a,appBundleId:l,startup:u});return n.recordAction(c,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),n.set(r,c),{ok:!0,data:p}}if("replay"===v){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=ix.expandHome(e,t.meta?.cwd),s=R.readFileSync(o,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(ik(i)){let e=iL(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return ar(r)&&ar(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=iL(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),u=t.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await a({token:t.token,session:r,command:s.command,positionals:s.positionals??[],flags:n9(t.flags,s.flags),meta:t.meta});if(l.ok)continue;if(!u)return n6(l,s,e,o);let p=await n7({action:s,sessionName:r,logPath:i,sessionStore:n,dispatch:m});if(!p)return n6(l,s,e,o);if(d[e]=p,!(l=await a({token:t.token,session:r,command:p.command,positionals:p.positionals??[],flags:n9(t.flags,p.flags),meta:t.meta})).ok)return n6(l,p,e,o);c+=1}if(u&&c>0){let e=n.get(r);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iO(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iO(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iO(r));return iM(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
28
|
-
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;R.writeFileSync(a,n),R.renameSync(a,e)}(o,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:r}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let i=(t.positionals?.[0]??"path").toLowerCase(),a=!!t.flags?.restart;if(!
|
|
29
|
-
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!iN("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await c.stop(e.appLog);let i=nS(t),a=n.resolveAppLogPidPath(r);try{let o=await c.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=b(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:nS(t)}}if("start"===i){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!iN("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await c.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await c.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!nG.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:nB}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!nq.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:nj}};let l=function(e,t){let r=nL(t?.maxEntries,25,1,200),i=t?.include??"summary",n=nL(t?.maxPayloadChars,2048,64,16384),a=nL(t?.maxScanLines,4e3,100,2e4);if(!R.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=R.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=nE(n,["method","httpMethod"]),o=nE(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=nb.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=n_.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of nD){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:nM(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return nO(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=nM(t,i))}if("body"===r||"all"===r){let t=nk(e,n,["requestBody","body","payload","request"]),r=nk(e,n,["responseBody","response"]);t&&(f.requestBody=nM(t,i)),r&&(f.responseBody=nM(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(n.resolveAppLogPath(r),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===v)return await n8(t,r,a);if("close"===v){let e=n.get(r);return e?(e.appLog&&await c.stop(e.appLog),t.positionals&&t.positionals.length>0&&await m(e.device,"close",t.positionals??[],t.flags?.out,{...iC(i,t.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??rw)(e.device.id),n.recordAction(e,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),{ok:!0,data:{session:r}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function n8(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??L;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await n5(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function n5(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of nC)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function n6(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>iO(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function n9(e,t){let r={...t??{}},i=e??{};for(let e of nT)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function n7(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(ik(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=ik(t.command)||"fill"===t.command,l=ik(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await ae(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),ik(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=i8(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=at(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return ib(t).filter(e=>e.trim().length>0)}(t)){let r=i0(e);if(!r)continue;let i=i1(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=i9(i.node,o.device.platform,{action:ik(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(ik(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=iS(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=i8(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=at(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=i0(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(iJ(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=iK(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(iJ(e.type??"")))});if(0===s.length||1!==ib(s.map(e=>iK(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=i9(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function ae(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...iC(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:iV(t.flags?.snapshotRaw?s:iH(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function at(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=i4(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function ar(e){return!!e&&!Number.isNaN(Number(e))}function ai(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function an(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function aa(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:an(e,0)})):A(e).map(e=>({text:e.text,comparable:an(e.node,e.depth)}))}function ao(e,t){return e.get(t)??0}async function as(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??im,o=t.command;if("snapshot"===o){let{session:e,device:o}=await au(n,r,t.flags);if(!iN("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=ad(t.flags?.snapshotScope,e);return s.ok?await ac(e,o,async()=>{let l=e?.appBundleId,d=await al({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return ap(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===o){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await au(n,r,t.flags);if(!iN("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=ad(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await ac(e,o,async()=>{let d=e?.appBundleId,u=(await al({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return aa(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return ap(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&ao(a,n-1)<ao(a,n+1)?ao(a,n+1):ao(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&ao(n,l-1)<ao(n,l+1)?l+1:l-1,u=ao(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(aa(e,r),aa(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return ap(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===o){let{session:e,device:o}=await au(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=ai(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=ai(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=ai(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=ai(e[e.length-1]),i=i4(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=i0(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),ap(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):iN("wait",o)?await ac(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...iC(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=iV(t.flags?.snapshotRaw?u:iH(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=i2(c,s.selector,{platform:o.platform});if(p)return ap(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=iU(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=iG(e.snapshot.nodes,t),i=r?ij(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await rp(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return ap(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&iq(iV((await tm(o,{scope:l})).nodes??[]),l))return ap(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===o){let{session:e,device:a}=await au(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return iN("alert",a)?await ac(e,a,async()=>{if("wait"===o){let r=ai(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await rp(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return ap(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r=await rp(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return ap(n,e,t,r),{ok:!0,data:r}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:u}};let{session:s,device:l}=await au(n,r,t.flags);return iN("settings",l)?await ac(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await im(l,"settings",d,t.flags?.out,{...iC(i,t.flags,r,s?.trace?.outPath)});return ap(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function al(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...iC(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:iV(n.flags?.snapshotRaw?l:iH(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function ad(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=iU(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=iG(t.snapshot.nodes,r),n=i?ij(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function au(e,t,r){let i=e.get(t),n=i?.device??await ip(r??{});return i||await iR(n),{session:i,device:n}}async function ac(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rw(t.id)}}function ap(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function af(e,t,r,i={}){let n=ah(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return am(e.label,r);case"value":return am(e.value,r);case"id":return am(e.identifier,r);default:return Math.max(am(e.label,r),am(e.value,r),am(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function am(e,t){let r=ah(e??"");return r?r===t?2:+!!r.includes(t):0}function ah(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function aw(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:u,value:c,timeoutMs:p}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:ai(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"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 m=f?.device??await ip(t.flags??{});f||await iR(m);let h=f?.appBundleId,w="role"!==l?d:void 0,g="click"===u||"focus"===u||"fill"===u||"type"===u,v=0,A=null,y=async()=>{let e=Date.now();if(A&&e-v<750)return{nodes:A};let a=await im(m,"snapshot",[],t.flags?.out,{...iC(i,{...t.flags,snapshotScope:w,snapshotInteractiveOnly:g,snapshotCompact:g},h,f?.trace?.outPath)}),o=a?.nodes??[],s=iV(t.flags?.snapshotRaw?o:iH(o));return v=e,A=s,f&&(f.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,f)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===u){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await y();if(af(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await y(),S=af(N,l,d,{requireRect:g});if(g&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=iK(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:S.matches.length,candidates:e}}}}let b=S.matches[0]??null;if(!b)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let _="click"===u||"focus"===u||"fill"===u||"type"===u?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,b)??b:b,D=`@${_.ref}`,E={...t.flags??{},noRecord:!0};if("exists"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===u){let e=iK(b);return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get text",text:e}}),{ok:!0,data:{ref:D,text:e,node:b}}}if("get_attrs"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get attrs"}}),{ok:!0,data:{ref:D,node:b}};if("click"===u){let e=await a({token:t.token,session:r,command:"click",positionals:[D],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"click"}}),e}if("fill"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[D,c],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"fill"}}),e}if("focus"===u){let e=b.rect?iB(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await im(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iC(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"focus"}}),{ok:!0,data:r??{ref:D}}}if("type"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=b.rect?iB(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await im(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iC(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await im(m,"type",[c],t.flags?.out,{...iC(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"type"}}),{ok:!0,data:r??{ref:D}}}return null}function ag(e){return e instanceof Error?e.message:String(e)}function aI(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function av(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function aA(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rp},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await ip(t.flags??{});d||await iR(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!iN("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?aI(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=ix.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=av(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await n()}catch(e){if(!ag(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ag(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ag(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${ag(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",t$(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=aI(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},av(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:ag(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of t7)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=ix.expandHome(e);return R.mkdirSync(n.dirname(r),{recursive:!0}),R.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=ix.expandHome(t.positionals[1]);R.mkdirSync(n.dirname(e),{recursive:!0}),R.existsSync(o)?R.renameSync(o,e):R.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function ay(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function aN(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function aS(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function ab(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??im,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iN("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=aE("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=ak({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=aO(p.rect);if(!m){let r=await a_(e,t.flags,i,n,{interactiveOnly:!0},a),o=iG(r.nodes,c),l=s.length>0?iq(r.nodes,s):null,d=aO(l?.rect),u=aO(o?.rect)?o:d?l:o??l,h=aO(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=ij(p,f),w=i9(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=iQ(u),p=await a_(e,t.flags,i,n,{interactiveOnly:!0},a),f=await O("selector_resolve",()=>i1(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i3(c,f?.diagnostics??[],{unique:!0})}};let m=aO(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=i9(f.node,e.device.platform,{action:l}),v=ij(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!iN("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=aE("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=ak({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!iz(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=ij(c,p),w=i9(c,e.device.platform,{action:"fill"}),{x:g,y:I}=iB(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=i4(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=iQ(s.selectorExpression),d=await a_(e,t.flags,i,n,{interactiveOnly:!0},a),u=await O("selector_resolve",()=>i1(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i3(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!iz(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=iB(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=i9(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:ij(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iN("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=aE("get",t.flags);if(r)return r;let n=ak({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=i9(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=iK(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=iQ(d),c=await a_(s,t.flags,i,n,{interactiveOnly:!1},a),p=await O("selector_resolve",()=>i1(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i3(u,[],{unique:!0})}};let f=p.node,m=i9(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=iK(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iN("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=i8(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=iQ(l.selectorExpression),c=await a_(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=i2(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:i3(u,[],{unique:!1})}}}let p=await O("selector_resolve",()=>i1(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i3(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=iK(r),o=!1;switch(t){case"visible":o=i5(r);break;case"hidden":o=!i5(r);break;case"editable":o=i6(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:i5(r),editable:i6(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iN("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=aE("scrollintoview",t.flags);if(l)return l;let d=ak({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=iB(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=aN(n.map(e=>e.rect).filter(e=>ay(e,r.x,r.y)));if(a)return a;let o=aN(n.map(e=>e.rect));if(o)return o;let s=aN(i.map(e=>e.rect).filter(e=>ay(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:aS(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:aS(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=ij(c,p),w=i9(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function a_(e,t,r,i,n,a=im){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:iV(t?.snapshotRaw?s:iH(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let aD=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function aE(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of aD)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function ak(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=iU(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=iG(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=iq(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function aO(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=iB(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function aM(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function aL(e){let{req:t,leaseRegistry:r}=e,i=aM(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let ax=new Set(["agent_device.command","agent-device.command"]),aC={"agent_device.lease.allocate":"lease_allocate","agent-device.lease.allocate":"lease_allocate","agent_device.lease.heartbeat":"lease_heartbeat","agent-device.lease.heartbeat":"lease_heartbeat","agent_device.lease.release":"lease_release","agent-device.lease.release":"lease_release"},aT=new Set([...ax,...Object.keys(aC)]);function aR(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function aP(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function a$(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function aF(e,t){let r="string"==typeof t.authorization?t.authorization:"",i=r.toLowerCase().startsWith("bearer ")?r.slice(7):void 0,n="string"==typeof t["x-agent-device-token"]?t["x-agent-device-token"]:void 0;return("string"==typeof e.token?e.token:void 0)??n??i??""}function aV(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function aU(e,t){if(!e)return{ok:!0};let r=await e(t);if(void 0===r||!0===r)return{ok:!0};if(!1===r){let e=b(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:aR(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:aR(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=c(r.tenantId);if(!e){let e=b(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:aR(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function aG(){let e,t=process.env.AGENT_DEVICE_HTTP_AUTH_HOOK;if(!t)return null;let r=process.env.AGENT_DEVICE_HTTP_AUTH_EXPORT||"default",i=n.isAbsolute(t)?t:n.resolve(t);try{e=await import(g(i).href)}catch(e){throw new I("COMMAND_FAILED","Failed to load AGENT_DEVICE_HTTP_AUTH_HOOK module",{hookPath:i,error:e instanceof Error?e.message:String(e)})}let a=e[r];if("function"!=typeof a)throw new I("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function aB(e){let t=await aG(),{handleRequest:r}=e;return i.createServer((e,i)=>{if("GET"===e.method&&"/health"===e.url){i.statusCode=200,i.setHeader("content-type","application/json"),i.end(JSON.stringify({ok:!0}));return}if("POST"!==e.method||"/rpc"!==e.url){i.statusCode=404,i.end("Not found");return}let n="";e.setEncoding("utf8"),e.on("data",t=>{(n+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{i.headersSent||aP(i,aR(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a;try{a=JSON.parse(n)}catch{aP(i,aR(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void aP(i,aR(a.id??null,-32600,"Invalid Request"),400);if(!aT.has(a.method))return void aP(i,aR(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void aP(i,aR(a.id??null,-32602,"Invalid params"),400);try{var o;let n=a.params,s=function(e,t,r){if(ax.has(e))return{token:aF(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=aC[e];if(i){let e;return{token:aF(t,r),session:aV(t,"session")??"default",command:i,positionals:[],meta:{tenantId:aV(t,"tenantId")??aV(t,"tenant"),runId:aV(t,"runId"),leaseId:aV(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:aV(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(o=a.method,ax.has(o)&&("string"!=typeof s.command||0===s.command.length))return void aP(i,aR(a.id??null,-32602,"Invalid params: command is required"),400);let l=await aU(t,{headers:e.headers,rpcRequest:a,daemonRequest:s});if(!l.ok)return void aP(i,l.response,l.statusCode);l.tenantId&&(s.meta={...s.meta,tenantId:l.tenantId,sessionIsolation:s.meta?.sessionIsolation??s.flags?.sessionIsolation??"tenant"});let d=await r(s);if(d.ok)return void aP(i,{jsonrpc:"2.0",id:a.id??null,result:d});aP(i,aR(a.id??null,-32e3,d.error.message,d.error),a$(d.error.code))}catch(t){let e=b(t);aP(i,aR(a.id??null,-32e3,e.message,e),a$(e.code))}})})}function aq(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function aj(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function aW(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class aH{leases=new Map;runBindings=new Map;maxActiveSimulatorLeases;defaultLeaseTtlMs;minLeaseTtlMs;maxLeaseTtlMs;now;constructor(e={}){this.maxActiveSimulatorLeases=Number.isInteger(e.maxActiveSimulatorLeases)?Math.max(0,Number(e.maxActiveSimulatorLeases)):0,this.defaultLeaseTtlMs=Number.isInteger(e.defaultLeaseTtlMs)?Math.max(1,Number(e.defaultLeaseTtlMs)):6e4,this.minLeaseTtlMs=Number.isInteger(e.minLeaseTtlMs)?Math.max(1,Number(e.minLeaseTtlMs)):5e3,this.maxLeaseTtlMs=Number.isInteger(e.maxLeaseTtlMs)?Math.max(this.minLeaseTtlMs,Number(e.maxLeaseTtlMs)):6e5,this.now=e.now??(()=>Date.now())}allocateLease(e){let t=aW(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=aq(e.runId);if(!i)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");this.cleanupExpiredLeases();let n=this.resolveLeaseTtlMs(e.ttlMs),a=this.bindingKey(r,i,t),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:f.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=aj(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});this.assertOptionalScopeMatch(r,e.tenantId,e.runId);let i=this.resolveLeaseTtlMs(e.ttlMs);return this.refreshLease(r,i)}releaseLease(e){let t=aj(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);return r?(this.assertOptionalScopeMatch(r,e.tenantId,e.runId),this.leases.delete(t),this.runBindings.delete(this.bindingKey(r.tenantId,r.runId,r.backend)),{released:!0}):{released:!1}}assertLeaseAdmission(e){let t=aW(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=aq(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=aj(e.leaseId);if(!n)throw new I("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}listActiveLeases(){return this.cleanupExpiredLeases(),Array.from(this.leases.values()).map(e=>({...e}))}cleanupExpiredLeases(){let e=this.now();for(let t of this.leases.values())t.expiresAt>e||(this.leases.delete(t.leaseId),this.runBindings.delete(this.bindingKey(t.tenantId,t.runId,t.backend)))}enforceCapacity(e){if("ios-simulator"!==e||this.maxActiveSimulatorLeases<=0)return;let t=Array.from(this.leases.values()).filter(e=>"ios-simulator"===e.backend).length;if(!(t<this.maxActiveSimulatorLeases))throw new I("COMMAND_FAILED","No simulator lease capacity available",{reason:"LEASE_CAPACITY_EXCEEDED",activeLeases:t,maxActiveLeases:this.maxActiveSimulatorLeases,backend:e,hint:"Retry after releasing another simulator lease."})}resolveLeaseTtlMs(e){if(!Number.isInteger(e))return this.defaultLeaseTtlMs;let t=Number(e);if(t<this.minLeaseTtlMs||t>this.maxLeaseTtlMs)throw new I("INVALID_ARGS",`Lease ttlMs must be between ${this.minLeaseTtlMs} and ${this.maxLeaseTtlMs}.`);return t}refreshLease(e,t){let r=this.now(),i={...e,heartbeatAt:r,expiresAt:r+t};return this.leases.set(i.leaseId,i),this.runBindings.set(this.bindingKey(i.tenantId,i.runId,i.backend),i.leaseId),{...i}}bindingKey(e,t,r){return`${e}:${t}:${r}`}assertOptionalScopeMatch(e,t,r){let i=c(t),n=aq(r);if(t&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(i&&e.tenantId!==i||n&&e.runId!==n)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}let{baseDir:aJ,infoPath:az,lockPath:aK,logPath:aX,sessionsDir:aY}=G(process.env.AGENT_DEVICE_STATE_DIR),aZ=U(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var aQ=aY;if(R.existsSync(aQ))for(let e of R.readdirSync(aQ,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(aQ,e.name,"app-log.pid");if(R.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}(R.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{nu(t)}}let a0=new ix(aY),a1=new aH({maxActiveSimulatorLeases:on(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:on(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:on(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:on(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),a2=D(),a3=f.randomBytes(24).toString("hex"),a4=new Set(["session_list","devices"]),a8=new Set(["session_list","devices","lease_allocate","lease_heartbeat","lease_release"]),a5=T(process.pid)??void 0,a6=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function a9(e,t,r){let i=k().requestId;return{...iC(aX,e,t,r,i),requestId:i}}async function a7(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:aX},async()=>{if(r.token!==a3)return{ok:!1,error:b(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=_(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=c(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(r);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=aM(e);a8.has(t)||e.meta?.sessionIsolation!=="tenant"||a1.assertLeaseAdmission({tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId,backend:i.leaseBackend});let n=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,a0),a=a0.get(n);a&&!a4.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=q(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=ea(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(a,e.flags);let o=await aL({req:e,leaseRegistry:a1});if(o)return oe(o);let s=await n4({req:e,sessionName:n,logPath:aX,sessionStore:a0,invoke:a7});if(s)return oe(s);let l=await as({req:e,sessionName:n,logPath:aX,sessionStore:a0});if(l)return oe(l);let d=await aA({req:e,sessionName:n,sessionStore:a0,logPath:aX});if(d)return oe(d);let u=await aw({req:e,sessionName:n,logPath:aX,sessionStore:a0,invoke:a7});if(u)return oe(u);let p=await ab({req:e,sessionName:n,sessionStore:a0,contextFromFlags:a9});if(p)return oe(p);let f=a0.get(n);if(!f)return oe({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!iN(t,f.device))return oe({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await im(f.device,t,e.positionals??[],e.flags?.out,{...a9(e.flags,f.appBundleId,f.trace?.outPath)});return a0.recordAction(f,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),oe({ok:!0,data:m??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=k(),t=$({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function oe(e){let t=k();if(!e.ok){M({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:b(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return M({level:"info",phase:"request_success"}),$(),e}function ot(){R.existsSync(az)&&R.unlinkSync(az)}function or(){if(!R.existsSync(aK))return null;try{let e=JSON.parse(R.readFileSync(aK,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function oi(){let e=or();if(!e||e.pid===process.pid)try{R.existsSync(aK)&&R.unlinkSync(aK)}catch{}}function on(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}(async function e(){let e,t;if(!function(){R.existsSync(aJ)||R.mkdirSync(aJ,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:a2,startedAt:Date.now(),processStartTime:a5},null,2),t=()=>{try{return R.writeFileSync(aK,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=or();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(aK)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===aZ||"dual"===aZ){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&t4.add(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await rg(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(i.add(s),t8(s)))throw new I("COMMAND_FAILED","request canceled");n=await a7(e)}catch(e){n={ok:!1,error:b(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&t4.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
30
|
-
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===
|
|
19
|
+
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(e))throw e}let i=(await rf(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new I("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");let n={exitCode:1,stdout:"",stderr:""};for(let r of t7)if(0===(n=await p("xcrun",["devicectl","device","copy","from","--device",e.id,"--source",i,"--destination",t,"--domain-type","appDataContainer","--domain-identifier",r],{allowFailure:!0})).exitCode)break;if(0!==n.exitCode){let e=n.stderr.trim()||n.stdout.trim()||`devicectl exited with code ${n.exitCode}`;throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${e}`)}}async function r4(e){rq(e,"clipboard"),await rj(e);let t=await rz(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to read iOS simulator clipboard",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return t.stdout.replace(/\r\n/g,"\n").replace(/\n$/,"")}async function r8(e,t){rq(e,"clipboard"),await rj(e);let r=await rz(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new I("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function r5(e,t,r){rq(e,"push"),await rj(e);let i=await x.mkdtemp(n.join(F.tmpdir(),"agent-device-ios-push-")),a=n.join(i,"payload.apns");try{await x.writeFile(a,`${JSON.stringify(r)}
|
|
20
|
+
`,"utf8"),await rz(e,["push",e.id,t,a])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function r6(e,t,r,i,n){rq(e,"settings"),await rj(e);let a=t.toLowerCase();switch(a){case"wifi":{let t=ie(r);await rz(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(ie(r)?await rz(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await rz(e,["status_bar",e.id,"clear"]));case"location":{let t=ie(r);if(!i)throw new I("INVALID_ARGS","location setting requires an active app in session");await rz(e,["privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":case"touchid":{let t=ir[a],i=function(e,t){let r=e.trim().toLowerCase();if("match"===r)return"match";if("nonmatch"===r)return"nonmatch";if("enroll"===r)return"enroll";if("unenroll"===r)return"unenroll";throw new I("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r,a);await is(e,i,{settingName:a,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await it(e,r);await rz(e,["ui",e.id,"appearance",t]);return}case"permission":{var o;if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(o=e$(r))?"revoke":o,a=function(e,t){let r=eF(e);if("photos"!==r&&t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return"camera";if("microphone"===r)return"microphone";if("contacts"===r)return"contacts";if("contacts-limited"===r)return"contacts-limited";if("notifications"===r)return"notifications";if("calendar"===r)return"calendar";if("location"===r)return"location";if("location-always"===r)return"location-always";if("media-library"===r)return"media-library";if("motion"===r)return"motion";if("reminders"===r)return"reminders";if("siri"===r)return"siri";if("photos"===r){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new I("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new I("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(n?.permissionTarget,n?.permissionMode);await ii(e,t,a,i);return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function r9(e,t="all"){var r;return"simulator"===e.kind?(r=await r7(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await t0(e,t)}async function r7(e){let t=(await rz(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let r=null;if(t.startsWith("{"))try{r=JSON.parse(t)}catch{r=null}if(!r&&t.startsWith("{"))try{let e=await p("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(r=JSON.parse(e.stdout))}catch{r=null}return r?Object.entries(r).map(([e,t])=>({bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e})):[]}function ie(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function it(e,t){let r=eV(t);if("toggle"!==r)return r;let i=await rz(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
|
|
21
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let ir={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function ii(e,t,r,i){let n=await io(e);if(!n.has(r))throw new I("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["privacy",e.id,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await rz(e,a);return}catch(t){if(!(o&&ia(t)))throw t;throw new I("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await rz(e,a);return}catch(e){if(!ia(e))throw e}try{await rz(e,["privacy",e.id,"reset","all",i])}catch(t){throw new I("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function ia(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return(t.includes("failed to grant access")||t.includes("failed to revoke access")||t.includes("failed to reset access"))&&t.includes("operation not permitted")}async function io(t){let r=en(t.simulatorSetPath),i=`${process.env.PATH??""}::${r??""}`;if(rJ&&e===i)return rJ;let n=await rz(t,["privacy","help"],{allowFailure:!0}),a=function(e){let t=new Set,r=!1;for(let i of e.split("\n")){let e=i.trim();if(!e)continue;if("service"===e){r=!0;continue}if(!r)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${n.stdout}
|
|
22
|
+
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return rJ=a,e=i,a}async function is(e,t,r){let i=function(e,t,r){let i=r.length>0?r:["face"];switch(t){case"match":return i.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return i.flatMap(t=>[["biometric",e,"nonmatch",t],["biometric",e,"nomatch",t],["biometric","nonmatch",e,t],["biometric","nomatch",e,t]]);case"enroll":return[["biometric",e,"enroll","yes"],["biometric",e,"enroll","1"],["biometric","enroll",e,"yes"],["biometric","enroll",e,"1"]];case"unenroll":return[["biometric",e,"enroll","no"],["biometric",e,"enroll","0"],["biometric","enroll",e,"no"],["biometric","enroll",e,"0"]]}}(e.id,t,r.modalityAliases),n=[];for(let t of i){let r=t$(e,t),i=await p("xcrun",r,{allowFailure:!0});if(0===i.exitCode)return;n.push({args:r,stderr:i.stderr,stdout:i.stdout,exitCode:i.exitCode})}let a=n.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(n.length>0&&n.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
23
|
+
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}function il(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function id(e,t){await rj(e),await p("open",["-a","Simulator"],{allowFailure:!0});let r=X.fromTimeoutMs(tY);await Y(async({deadline:r})=>{if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tY});let i=t$(e,["launch",e.id,t]),n=await p("xcrun",i,{allowFailure:!0});if(0!==n.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${n.exitCode}`,{cmd:"xcrun",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:il},{deadline:r})}async function iu(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tQ(i,{action:"launch iOS app",deviceId:e.id})}let ic=/^[A-Za-z0-9_.:-]{1,64}$/;function ip(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!R.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function im(e){let t=q(e.platform),r=en(e.iosSimulatorDeviceSet),i=eo(e.androidDeviceAllowlist);return await O("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await th();let e=await eA({serialAllowlist:i});return await j(e,n)}if("ios"===n.platform){let e=await tz({simulatorSetPath:r});return await j(e,n)}let a=[];try{a.push(...await eA({serialAllowlist:i}))}catch{}try{a.push(...await tz({simulatorSetPath:r}))}catch{}return await j(a,n)},{platform:t,target:e.target})}async function ih(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>e0(e,t,r?.activity),openDevice:()=>e2(e),close:t=>e3(e,t),tap:(t,r)=>e6(e,t,r),doubleTap:async(t,r)=>{await e6(e,t,r),await e6(e,t,r)},swipe:(t,r,i,n,a)=>e9(e,t,r,i,n,a),longPress:(t,r,i)=>tr(e,t,r,i),focus:(t,r)=>to(e,t,r),type:t=>ti(e,t),fill:(t,r,i)=>ts(e,t,r,i),scroll:(t,r)=>tl(e,t,r),scrollIntoView:t=>td(e,t),screenshot:(t,r)=>tu(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>rY(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rZ(e),close:t=>rQ(e,t),screenshot:(t,r)=>r3(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(t8(i.requestId))throw new I("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await rf(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await rf(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await rf(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await rf(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await rf(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await rf(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await rf(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await rf(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await rf(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await O("platform_command",async()=>{var s,l,d,u,c,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(ek(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!ek(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=ig(a?.count??1,"count",1,200),c=ig(a?.intervalMs??0,"interval-ms",0,1e4),p=ig(a?.holdMs??0,"hold-ms",0,1e4),f=ig(a?.jitterPx??0,"jitter-px",0,100),m=a?.doubleTap===!0;if(m&&p>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(m&&f>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,u=f,"ios"===s.platform&&l>1&&0===d&&0===u)return await rf(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:c,doubleTap:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m,timingMode:"runner-series"};return await iA(n,c,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=iw[e%iw.length];return[r*t,i*t]}(e,f),a=t+r,s=i+n;m?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=ig(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=ig(a?.count??1,"count",1,200),f=ig(a?.pauseMs??0,"pause-ms",0,1e4),m=a?.pattern??"one-way";if("one-way"!==m&&"ping-pong"!==m)throw new I("INVALID_ARGS",`Invalid pattern: ${m}`);if(c=e,p=u,"ios"===c.platform&&p>1)return await rf(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:f,pattern:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:f,pattern:m};return await iA(u,f,async e=>{"ping-pong"===m&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:f,pattern:m}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await rf(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!ic.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await rf(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await e7(e),{action:"back"};case"home":if("ios"===e.platform)return await rf(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await te(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await rf(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await tt(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await r4(e):await tn(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await r8(e,i):await ta(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await eZ(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await eY(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await r6(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await tc(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await iI(i);if("ios"===e.platform)return await r5(e,t,n),{platform:"ios",bundleId:t};let a=await tf(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await O("snapshot_capture",async()=>await rf(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await O("snapshot_capture",async()=>await tm(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let iw=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function ig(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function iI(e){let t=ip(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await iv(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function iv(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function iA(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await iy(t)}async function iy(e){await new Promise(t=>setTimeout(t,e))}let iN={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function iS(e,t){let r=iN[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function ib(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function i_(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let iD=/^-?\d+(\.\d+)?$/,iE=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),ik=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function iO(e){return"click"===e||"press"===e}function iM(e){let t=e.trim();return t.startsWith("@")||iD.test(t)?t:JSON.stringify(t)}function iL(e,t){let r=t.flags??{};if(iO(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function ix(e,t){let r=[],i={},n=iO(e)?iE:"swipe"===e?ik:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(iO(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class iC{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=iC.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}}(t.flags),result:t.result}),M({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=n.dirname(t);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(iO(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(iM(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(iM(i)),iL(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(iM(r)),iL(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(iM(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(iM(i)),n&&t.push(iM(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(iM(r)),t.push(iM(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(iM(r))}return t.join(" ")}}if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iM(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iM(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iM(r));return iL(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
24
|
+
`}(e,this.buildOptimizedActions(e));R.writeFileSync(t,i)}catch{}}defaultTracePath(e){let t=iC.safeSessionName(e.name),r=new Date().toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${r}.trace.log`)}resolveAppLogPath(e){return n.join(this.sessionsDir,iC.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return n.join(this.sessionsDir,iC.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?n.join(F.homedir(),e.slice(2)):t&&!n.isAbsolute(e)?n.resolve(t,e):n.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return iC.expandHome(e.saveScriptPath);R.existsSync(this.sessionsDir)||R.mkdirSync(this.sessionsDir,{recursive:!0});let t=iC.safeSessionName(e.name),r=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-");return n.join(this.sessionsDir,`${t}-${r}.ad`)}buildOptimizedActions(e){let t=[];for(let r of e.actions){if("snapshot"===r.command)continue;let i=Array.isArray(r.result?.selectorChain)&&r.result?.selectorChain.every(e=>"string"==typeof e)?r.result.selectorChain:[];if(i.length>0&&(iO(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(iO(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=ib(r);if(i.length>0){t.push({...r,positionals:[e,i]});continue}}if("get"===r.command){let i=r.positionals?.[0];if("text"===i||"attrs"===i){t.push({...r,positionals:[i,e]});continue}}}if(iO(r.command)||"fill"===r.command||"get"===r.command){let i=r.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push({ts:r.ts,command:"snapshot",positionals:[],flags:{platform:e.device.platform,snapshotInteractiveOnly:!0,snapshotCompact:!0,snapshotScope:i.trim()},result:{scope:i.trim()}})}t.push(r)}return t}}function iT(e,t,r,i,n){return{requestId:n??k().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let iR=tR(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function iP(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:rj}));await t(e);return}if("device"===e.kind)return void await i$(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:eE}));await t(e.id)}}async function i$(e){let t=n.join(F.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(iR/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:iR+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await iF(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:iV(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??iR),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?iV(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function iF(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function iV(e,t){let r=t2(e,t);return r||(`${e}
|
|
25
|
+
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":t1)}function iU(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function iG(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function iB(e,t){return e.find(e=>e.ref===t)??null}function iq(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function ij(e,t){let r=t.toLowerCase();return e.find(e=>{let t=(e.label??"").toLowerCase(),i=(e.value??"").toLowerCase(),n=(e.identifier??"").toLowerCase();return t.includes(r)||i.includes(r)||n.includes(r)})??null}function iW(e,t){let r=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);return r&&iH(r)?r:function(e,t){if(!e.rect)return;let r=e.rect.y+e.rect.height/2,i=null;for(let e of t){if(!e.rect)continue;let t=[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0);if(!t||!iH(t))continue;let n=Math.abs(e.rect.y+e.rect.height/2-r);(!i||n<i.distance)&&(i={label:t,distance:n})}return i?.label}(e,t)??(r&&iH(r)?r:void 0)}function iH(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function iJ(e){let t=[],r=[];for(let i of e){let e=i.depth??0;for(;t.length>0&&e<=t[t.length-1];)t.pop();let n=iz(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&iH(a);if(("group"===n||"ioscontentgroup"===n)&&!o){t.push(e);continue}let s=Math.max(0,e-t.length);r.push({...i,depth:s})}return r}function iz(e){let t=e.trim().replace(/XCUIElementType/gi,"").toLowerCase(),r=Math.max(t.lastIndexOf("."),t.lastIndexOf("/"));return -1!==r&&(t=t.slice(r+1)),t}function iK(e,t){let r=iz(e);return!r||("android"===t?r.includes("edittext")||r.includes("autocompletetextview"):r.includes("textfield")||r.includes("securetextfield")||r.includes("searchfield")||r.includes("textview")||r.includes("textarea")||"search"===r)}function iX(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let iY=new Set(["id","role","text","label","value"]),iZ=new Set(["visible","hidden","editable","selected","enabled","hittable"]),iQ=new Set([...iY,...iZ]);function i0(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!nl(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!nl(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(ne)}})(e))}}function i1(e){try{return i0(e)}catch{return null}}function i2(e,t,r){let i=r.requireRect??!1,n=r.requireUnique??!0,a=r.disambiguateAmbiguous??!1,o=[];for(let s=0;s<t.selectors.length;s+=1){let l=t.selectors[s],d=function(e,t,r){let i=0,n=null,a=null,o=!1;for(let s of e){if(r.requireRect&&!s.rect||!nt(s,t,r.platform))continue;if(i+=1,n||(n=s),!a){a=s;continue}let e=function(e,t){let r=e.depth??0,i=t.depth??0;if(r!==i)return r>i?1:-1;let n=ns(e),a=ns(t);return n!==a?n<a?1:-1:0}(s,a);if(e>0){a=s,o=!1;continue}0===e&&(o=!0)}return{count:i,firstNode:n,disambiguated:o?null:a}}(e,l,{platform:r.platform,requireRect:i});if(o.push({selector:l.raw,matches:d.count}),0!==d.count&&d.firstNode){if(n&&1!==d.count){if(!a)continue;let e=d.disambiguated;if(!e)continue;return{node:e,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}return{node:d.firstNode,selector:l,selectorIndex:s,matches:d.count,diagnostics:o}}}return null}function i3(e,t,r){let i=r.requireRect??!1,n=[];for(let a=0;a<t.selectors.length;a+=1){let o=t.selectors[a],s=function(e,t,r){let i=0;for(let n of e)(!r.requireRect||n.rect)&&nt(n,t,r.platform)&&(i+=1);return i}(e,o,{platform:r.platform,requireRect:i});if(n.push({selector:o.raw,matches:s}),s>0)return{selectorIndex:a,selector:o,matches:s,diagnostics:n}}return null}function i4(e,t,r){let i=r.unique??!0;if(0===t.length)return`Selector did not match: ${e.raw}`;let n=t.map(e=>`${e.selector} -> ${e.matches}`).join(", ");return i?`Selector did not resolve uniquely (${n})`:`Selector did not match (${n})`}function i8(e,t={}){if(0===e.length)return null;let r=t.preferTrailingValue??!1,i=0,n=[];for(;i<e.length&&function(e){let t=e.trim();if(!t)return!1;if("||"===t)return!0;let r=t.indexOf("=");if(-1!==r){let e=t.slice(0,r).trim().toLowerCase();return iQ.has(e)}return iQ.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&i1(t)&&n.push(i)}if(0===n.length)return null;let a=n[n.length-1];if(r){for(let t=n.length-1;t>=0;t-=1)if(n[t]<e.length){a=n[t];break}}let o=e.slice(0,a).join(" ").trim();return o?{selectorExpression:o,rest:e.slice(a)}:null}function i5(e){let t=e[0]??"",r=i8(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function i6(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function i9(e,t){return iK(e.type??"",t)&&!1!==e.enabled}function i7(e,t,r={}){let i=[],n=iz(e.type??""),a=no(e.identifier),o=no(e.label),s=no(e.value),l=no(iX(e)),d="fill"===r.action;a&&i.push(`id=${na(a)}`),n&&o&&i.push(d?`role=${na(n)} label=${na(o)} editable=true`:`role=${na(n)} label=${na(o)}`),o&&i.push(d?`label=${na(o)} editable=true`:`label=${na(o)}`),s&&i.push(d?`value=${na(s)} editable=true`:`value=${na(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${na(l)} editable=true`:`text=${na(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${na(n)} editable=true`);let u=i_(i);return 0===u.length&&n&&u.push(d?`role=${na(n)} editable=true`:`role=${na(n)}`),0===u.length&&i6(e)&&u.push("visible=true"),u}function ne(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!iZ.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!iQ.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(iZ.has(i)){let e,t="true"===(e=nr(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:nr(n)}}function nt(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return ni(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return iz(e)}(i??"")===function(e){return iz(e)}(n);case"label":return ni(e.label,String(t.value));case"value":return ni(e.value,String(t.value));case"text":{let r=nn(String(t.value));return nn(iX(e))===r}case"visible":return i6(e)===!!t.value;case"hidden":return!i6(e)==!!t.value;case"editable":return i9(e,r)===!!t.value;case"selected":return!0===e.selected==!!t.value;case"enabled":return!1!==e.enabled==!!t.value;case"hittable":return!0===e.hittable==!!t.value;default:return!1}})(e,t,r))}function nr(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function ni(e,t){return nn(e??"")===nn(t)}function nn(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function na(e){return JSON.stringify(e)}function no(e){if(!e)return null;let t=e.trim();return t||null}function ns(e){return e.rect?e.rect.width*e.rect.height:1/0}function nl(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}function nd(e,t){let r=process.env[e];if(!r)return t;let i=Number.parseInt(r,10);return Number.isInteger(i)&&i>0?i:t}function nu(e,t){if(!e)return;let r=n.dirname(e);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i={pid:t,startTime:T(t)??void 0,command:a(t)??void 0};R.writeFileSync(e,`${JSON.stringify(i)}
|
|
26
|
+
`)}function nc(e){if(e&&R.existsSync(e))try{R.unlinkSync(e)}catch{}}function np(e){let t=n.dirname(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),function(e,t){if(R.existsSync(e)&&!(R.statSync(e).size<t.maxBytes))for(let r=t.maxRotatedFiles;r>=1;r-=1){let t=1===r?e:`${e}.${r-1}`,i=`${e}.${r}`;R.existsSync(t)&&(R.existsSync(i)&&R.unlinkSync(i),R.renameSync(t,i))}}(e,{maxBytes:nd("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:nd("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function nf(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function nm(e){await new Promise(t=>setTimeout(t,e))}function nh(e,t){let r=t.includeTokens?.filter(e=>e.length>0)??[],i="",n=i=>{(!(r.length>0)||r.some(e=>i.includes(e)))&&e.write(function(e,t){if(0===t.length)return e;let r=e;for(let e of t)r=r.replace(e,"[REDACTED]");return r}(i,t.redactionPatterns))};return{onChunk:e=>{let t=`${i}${e}`.split("\n");for(let e of(i=t.pop()??"",t))n(`${e}
|
|
27
|
+
`)},flush:()=>{i&&(n(i),i="")}}}function nw(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function ng(e,t){let r=(await p("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function nI(e,t,r,i){let n="active",a=h("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=nh(t,{redactionPatterns:r});"number"==typeof a.pid&&nu(i,a.pid);let s=nw(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nc(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nf(s),a.killed||a.kill("SIGKILL"),await nf(s),nc(i)}}}async function nv(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=nh(t,{redactionPatterns:r});"number"==typeof a.pid&&nu(i,a.pid);let s=nw(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nc(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nf(s),a.killed||a.kill("SIGKILL"),await nf(s),nc(i)}}}async function nA(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await ng(e,t);if(!d){await nm(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=nh(r,{redactionPatterns:i});o=nw(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&nu(n,u.pid);let p=await o;if(nc(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await nm(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),nc(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await nf(o),a&&!a.killed&&a.kill("SIGKILL"),await nf(d),nc(n)}}}async function ny(e,t,r,i){np(r);let n=R.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await nv(e.id,n,a,i):await nI(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new I("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await nA(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function nN(e){await e.stop(),await nf(e.wait)}async function nS(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await p("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await p("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await p("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await p("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function nb(e){let t=n.dirname(e),r=n.basename(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),R.existsSync(e)?R.truncateSync(e,0):R.writeFileSync(e,"","utf8");let i=0;for(let e of R.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{R.unlinkSync(n.join(t,e)),i+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:i}}let n_=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),nD=/https?:\/\/[^\s"'<>\])]+/i,nE=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function nk(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function nO(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return nM(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function nM(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function nL(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function nx(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let nC='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nT=["platform","target","device","udid","serial","verbose","out"],nR=["platform","target","device","udid","serial","verbose","out"],nP=["path","start","stop","doctor","mark","clear"],n$=`logs requires ${nP.slice(0,-1).join(", ")}, or ${nP.at(-1)}`,nF="Not implemented for this platform in this release.",nV="open-command-roundtrip";function nU(e){let{sessionName:t,appName:r,appBundleId:i,startup:n}=e,a={session:t};return r&&(a.appName=r),i&&(a.appBundleId=i),n&&(a.startup=n),a}function nG(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:nV,appTarget:t,appBundleId:r}}let nB=["dump","log"],nq=`network requires ${nB.join(" or ")}`,nj=["summary","headers","body","all"],nW=`network include mode must be one of: ${nj.join(", ")}`;function nH(e,t,r){return t||nJ(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nJ(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nz(e){let t=nJ(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function nK(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let nX=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:eD}));return await i({avdName:e,serial:t,headless:r})};async function nY(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=nH(l,p,f);if(m)return m;let h=await nz({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iS(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...iT(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let nZ={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:r2}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e5}));return await i(e,t,r)}};async function nQ(e,t,r){if("ios"===e.platform&&t)return ek(t)?"device"===e.kind?eO(r,t):void 0:await n0(e,t)}async function n0(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rX}));return await r(e,t)}catch{return}}async function n1(e,t){if(!("android"!==e.platform||!t||ek(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eW})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function n2(e,t,r,i){return await nQ(e,t,r)??await i(e,t)??("android"===e.platform&&t&&ek(t)?r:void 0)}async function n3(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=q(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=nH("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nJ(e))return!0;let r=q(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nC}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await nz({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nC}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eX})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function n4(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=nH("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nz({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iS("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...iT(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function n8(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a,dispatch:o,ensureReady:s,resolveTargetDevice:l,reinstallOps:d=nZ,stopIosRunner:u,appLogOps:c={start:ny,stop:nN},ensureAndroidEmulatorBoot:p=nX,resolveAndroidPackageForOpen:f=n1}=e,m=o??ih,h=s??iP,g=l??im,v=t.command;if("session_list"===v)return{ok:!0,data:{sessions:n.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===v)try{let e=[],r=en(t.flags?.iosSimulatorDeviceSet),i=eo(t.flags?.androidDeviceAllowlist),n=q(t.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA}));e.push(...await t({serialAllowlist:i}))}else if("ios"===n){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tz}));e.push(...await t({simulatorSetPath:r}))}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:tz}));try{e.push(...await t({serialAllowlist:i}))}catch{}try{e.push(...await n({simulatorSetPath:r}))}catch{}}let a=(t.flags?.target?e.filter(e=>(e.target??"mobile")===t.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===v){let e=n.get(r),i=t.flags??{},a=nH(v,e,i);if(a)return a;let o=await nz({session:e,flags:i,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!0});if(!iS("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=t.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:r9}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:eH}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===v){let e,i=n.get(r),a=t.flags??{},o=nH(v,i,a);if(o)return o;let s="android"===(q(a.platform)??i?.device.platform),l=!0===a.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=nK({flags:a,sessionDevice:i?.device}),u=s&&!!d,c=!1;try{e=await nz({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1})}catch(r){let t=w(r);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw r;e=await p({avdName:d,serial:a.serial,headless:l}),c=!0}if(a.target&&(e.target??"mobile")!==a.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${a.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let t=nK({flags:a,sessionDevice:i?.device,resolvedDevice:e});if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await p({avdName:t,serial:a.serial,headless:!0})}await h(e)}else("android"!==e.platform||!0!==e.booted)&&await h(e);return iS("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===v)return await n3({req:t,sessionName:r,sessionStore:n,ensureReady:h,resolveDevice:g});if("clipboard"===v)return await n4({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m});if("keyboard"===v)return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"keyboard",positionals:t.positionals??[]});if("perf"===v){let e,t,i,a=n.get(r);return a?{ok:!0,data:(i=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===nV&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:nV,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(a.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:nV,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:nV},{session:a.name,platform:a.device.platform,device:a.device.name,deviceId:a.device.id,metrics:{startup:i,fps:{available:!1,reason:nF},memory:{available:!1,reason:nF},cpu:{available:!1,reason:nF}},sampling:{startup:{method:nV,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("reinstall"===v){let e,i=n.get(r),a=t.flags??{},o=nH(v,i,a);if(o)return o;let s=t.positionals?.[0]?.trim(),l=t.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let u=iC.expandHome(l);if(!R.existsSync(u))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${u}`}};let c=await nz({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1});if(!iS("reinstall",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===c.platform){let t=await d.ios(c,s,u);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await d.android(c,s,u);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:u,...e};return i&&n.recordAction(i,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),{ok:!0,data:p}}if("push"===v){let e,a=t.positionals?.[0]?.trim(),o=t.positionals?.[1]?.trim();if(!a||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=ip(o,{subject:"Push payload",cwd:t.meta?.cwd,expandPath:(e,t)=>iC.expandHome(e,t)})).kind?e.path:e.text;return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"push",positionals:[a,s],recordPositionals:[a,o]})}if("trigger-app-event"===v)return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"trigger-app-event",positionals:t.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await n2(e.device,r,e.appBundleId,f)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===v){let e=t.flags?.relaunch===!0;if(n.has(r)){let a=n.get(r),o=t.positionals?.[0],s=o??(e?a?.appName:void 0);if(!a||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&ek(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await h(a.device);let l=await n2(a.device,s,a.appBundleId,f),d=o?t.positionals??[]:[s];if(e){let e=l??s;await m(a.device,"close",[e],t.flags?.out,{...iT(i,t.flags,l??a.appBundleId,a.trace?.outPath)})}let u=Date.now();await m(a.device,"open",d,t.flags?.out,{...iT(i,t.flags,l)});let c=nG(u,s,l),p={...a,appBundleId:l,appName:s,recordSession:a.recordSession||!!t.flags?.saveScript,snapshot:void 0},w=nU({sessionName:r,appName:s,appBundleId:l,startup:c});return n.recordAction(p,{command:v,positionals:d,flags:t.flags??{},result:w}),n.set(r,p),{ok:!0,data:w}}let a=t.positionals?.[0];if(e&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&a&&ek(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let o=await g(t.flags??{}),s=n.toArray().find(e=>e.device.id===o.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:o.id,deviceName:o.name}}};await h(o);let l=await n2(o,a,void 0,f);if(e&&a){let e=l??a;await m(o,"close",[e],t.flags?.out,{...iT(i,t.flags,l)})}let d=Date.now();await m(o,"open",t.positionals??[],t.flags?.out,{...iT(i,t.flags,l)});let u=a?nG(d,a,l):void 0,c={name:r,device:o,createdAt:Date.now(),appBundleId:l,appName:a,recordSession:!!t.flags?.saveScript,actions:[]},p=nU({sessionName:r,appName:a,appBundleId:l,startup:u});return n.recordAction(c,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),n.set(r,c),{ok:!0,data:p}}if("replay"===v){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=iC.expandHome(e,t.meta?.cwd),s=R.readFileSync(o,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(iO(i)){let e=ix(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return ai(r)&&ai(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=ix(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),u=t.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await a({token:t.token,session:r,command:s.command,positionals:s.positionals??[],flags:n7(t.flags,s.flags),meta:t.meta});if(l.ok)continue;if(!u)return n9(l,s,e,o);let p=await ae({action:s,sessionName:r,logPath:i,sessionStore:n,dispatch:m});if(!p)return n9(l,s,e,o);if(d[e]=p,!(l=await a({token:t.token,session:r,command:p.command,positionals:p.positionals??[],flags:n7(t.flags,p.flags),meta:t.meta})).ok)return n9(l,p,e,o);c+=1}if(u&&c>0){let e=n.get(r);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iM(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iM(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iM(r));return iL(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
28
|
+
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;R.writeFileSync(a,n),R.renameSync(a,e)}(o,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:r}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let i=(t.positionals?.[0]??"path").toLowerCase(),a=!!t.flags?.restart;if(!nP.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:n$}};if(a&&"clear"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===i){let t=n.resolveAppLogPath(r),i=function(e){if(!R.existsSync(e))return{exists:!1,sizeBytes:0};let t=R.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),a=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:a,sizeBytes:i.sizeBytes,modifiedAt:i.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===i){let t=n.resolveAppLogPath(r),i=await nS(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:i.checks,notes:i.notes}}}if("mark"===i){let e,i=t.positionals?.slice(1).join(" ")??"",a=n.resolveAppLogPath(r);return np(a),e=`[agent-device][mark][${new Date().toISOString()}] ${i.trim()||"marker"}
|
|
29
|
+
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!iS("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await c.stop(e.appLog);let i=nb(t),a=n.resolveAppLogPidPath(r);try{let o=await c.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=b(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:nb(t)}}if("start"===i){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!iS("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await c.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await c.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!nB.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:nq}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!nj.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:nW}};let l=function(e,t){let r=nx(t?.maxEntries,25,1,200),i=t?.include??"summary",n=nx(t?.maxPayloadChars,2048,64,16384),a=nx(t?.maxScanLines,4e3,100,2e4);if(!R.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=R.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=nk(n,["method","httpMethod"]),o=nk(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=n_.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=nD.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of nE){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:nL(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return nM(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=nL(t,i))}if("body"===r||"all"===r){let t=nO(e,n,["requestBody","body","payload","request"]),r=nO(e,n,["responseBody","response"]);t&&(f.requestBody=nL(t,i)),r&&(f.responseBody=nL(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(n.resolveAppLogPath(r),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===v)return await n5(t,r,a);if("close"===v){let e=n.get(r);return e?(e.appLog&&await c.stop(e.appLog),t.positionals&&t.positionals.length>0&&await m(e.device,"close",t.positionals??[],t.flags?.out,{...iT(i,t.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??rg)(e.device.id),n.recordAction(e,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),{ok:!0,data:{session:r}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function n5(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??L;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await n6(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function n6(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of nT)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function n9(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>iM(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function n7(e,t){let r={...t??{}},i=e??{};for(let e of nR)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function ae(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(iO(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=iO(t.command)||"fill"===t.command,l=iO(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await at(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),iO(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=i5(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=ar(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return i_(t).filter(e=>e.trim().length>0)}(t)){let r=i1(e);if(!r)continue;let i=i2(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=i7(i.node,o.device.platform,{action:iO(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(iO(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ib(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=i5(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=ar(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=i1(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(iz(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=iX(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(iz(e.type??"")))});if(0===s.length||1!==i_(s.map(e=>iX(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=i7(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function at(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...iT(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:iU(t.flags?.snapshotRaw?s:iJ(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function ar(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=i8(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function ai(e){return!!e&&!Number.isNaN(Number(e))}function an(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function aa(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function ao(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:aa(e,0)})):A(e).map(e=>({text:e.text,comparable:aa(e.node,e.depth)}))}function as(e,t){return e.get(t)??0}async function al(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??ih,o=t.command;if("snapshot"===o){let{session:e,device:o}=await ac(n,r,t.flags);if(!iS("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=au(t.flags?.snapshotScope,e);return s.ok?await ap(e,o,async()=>{let l=e?.appBundleId,d=await ad({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return af(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===o){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await ac(n,r,t.flags);if(!iS("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=au(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await ap(e,o,async()=>{let d=e?.appBundleId,u=(await ad({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return ao(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return af(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&as(a,n-1)<as(a,n+1)?as(a,n+1):as(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&as(n,l-1)<as(n,l+1)?l+1:l-1,u=as(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(ao(e,r),ao(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return af(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===o){let{session:e,device:o}=await ac(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=an(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=an(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=an(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=an(e[e.length-1]),i=i8(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=i1(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),af(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):iS("wait",o)?await ap(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...iT(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=iU(t.flags?.snapshotRaw?u:iJ(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=i3(c,s.selector,{platform:o.platform});if(p)return af(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=iG(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=iB(e.snapshot.nodes,t),i=r?iW(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await rf(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return af(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&ij(iU((await tm(o,{scope:l})).nodes??[]),l))return af(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===o){let{session:e,device:a}=await ac(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return iS("alert",a)?await ap(e,a,async()=>{if("wait"===o){let r=an(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await rf(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return af(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r=await rf(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return af(n,e,t,r),{ok:!0,data:r}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:u}};let{session:s,device:l}=await ac(n,r,t.flags);return iS("settings",l)?await ap(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await ih(l,"settings",d,t.flags?.out,{...iT(i,t.flags,r,s?.trace?.outPath)});return af(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function ad(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...iT(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:iU(n.flags?.snapshotRaw?l:iJ(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function au(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=iG(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=iB(t.snapshot.nodes,r),n=i?iW(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function ac(e,t,r){let i=e.get(t),n=i?.device??await im(r??{});return i||await iP(n),{session:i,device:n}}async function ap(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rg(t.id)}}function af(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function am(e,t,r,i={}){let n=aw(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return ah(e.label,r);case"value":return ah(e.value,r);case"id":return ah(e.identifier,r);default:return Math.max(ah(e.label,r),ah(e.value,r),ah(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function ah(e,t){let r=aw(e??"");return r?r===t?2:+!!r.includes(t):0}function aw(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function ag(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:u,value:c,timeoutMs:p}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:an(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"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 m=f?.device??await im(t.flags??{});f||await iP(m);let h=f?.appBundleId,w="role"!==l?d:void 0,g="click"===u||"focus"===u||"fill"===u||"type"===u,v=0,A=null,y=async()=>{let e=Date.now();if(A&&e-v<750)return{nodes:A};let a=await ih(m,"snapshot",[],t.flags?.out,{...iT(i,{...t.flags,snapshotScope:w,snapshotInteractiveOnly:g,snapshotCompact:g},h,f?.trace?.outPath)}),o=a?.nodes??[],s=iU(t.flags?.snapshotRaw?o:iJ(o));return v=e,A=s,f&&(f.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,f)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===u){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await y();if(am(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await y(),S=am(N,l,d,{requireRect:g});if(g&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=iX(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:S.matches.length,candidates:e}}}}let b=S.matches[0]??null;if(!b)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let _="click"===u||"focus"===u||"fill"===u||"type"===u?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,b)??b:b,D=`@${_.ref}`,E={...t.flags??{},noRecord:!0};if("exists"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===u){let e=iX(b);return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get text",text:e}}),{ok:!0,data:{ref:D,text:e,node:b}}}if("get_attrs"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get attrs"}}),{ok:!0,data:{ref:D,node:b}};if("click"===u){let e=await a({token:t.token,session:r,command:"click",positionals:[D],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"click"}}),e}if("fill"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[D,c],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"fill"}}),e}if("focus"===u){let e=b.rect?iq(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await ih(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"focus"}}),{ok:!0,data:r??{ref:D}}}if("type"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=b.rect?iq(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await ih(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await ih(m,"type",[c],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"type"}}),{ok:!0,data:r??{ref:D}}}return null}function aI(e){return e instanceof Error?e.message:String(e)}function av(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function aA(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function ay(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rf},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await im(t.flags??{});d||await iP(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!iS("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?av(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=iC.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=aA(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await n()}catch(e){if(!aI(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${aI(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:aI(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${aI(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",t$(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=av(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},aA(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:aI(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of t7)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=iC.expandHome(e);return R.mkdirSync(n.dirname(r),{recursive:!0}),R.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=iC.expandHome(t.positionals[1]);R.mkdirSync(n.dirname(e),{recursive:!0}),R.existsSync(o)?R.renameSync(o,e):R.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function aN(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function aS(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function ab(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function a_(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??ih,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=ak("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=aO({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=aM(p.rect);if(!m){let r=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),o=iB(r.nodes,c),l=s.length>0?ij(r.nodes,s):null,d=aM(l?.rect),u=aM(o?.rect)?o:d?l:o??l,h=aM(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=iW(p,f),w=i7(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=i0(u),p=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),f=await O("selector_resolve",()=>i2(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(c,f?.diagnostics??[],{unique:!0})}};let m=aM(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=i7(f.node,e.device.platform,{action:l}),v=iW(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!iS("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=ak("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=aO({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!iK(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iW(c,p),w=i7(c,e.device.platform,{action:"fill"}),{x:g,y:I}=iq(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=i8(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=i0(s.selectorExpression),d=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),u=await O("selector_resolve",()=>i2(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!iK(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=iq(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=i7(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:iW(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=ak("get",t.flags);if(r)return r;let n=aO({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=i7(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=iX(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=i0(d),c=await aD(s,t.flags,i,n,{interactiveOnly:!1},a),p=await O("selector_resolve",()=>i2(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!0})}};let f=p.node,m=i7(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=iX(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=i5(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=i0(l.selectorExpression),c=await aD(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=i3(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!1})}}}let p=await O("selector_resolve",()=>i2(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=iX(r),o=!1;switch(t){case"visible":o=i6(r);break;case"hidden":o=!i6(r);break;case"editable":o=i9(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:i6(r),editable:i9(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=ak("scrollintoview",t.flags);if(l)return l;let d=aO({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=iq(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=aS(n.map(e=>e.rect).filter(e=>aN(e,r.x,r.y)));if(a)return a;let o=aS(n.map(e=>e.rect));if(o)return o;let s=aS(i.map(e=>e.rect).filter(e=>aN(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:ab(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:ab(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=iW(c,p),w=i7(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function aD(e,t,r,i,n,a=ih){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:iU(t?.snapshotRaw?s:iJ(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let aE=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function ak(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of aE)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function aO(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=iG(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=iB(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=ij(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function aM(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=iq(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function aL(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function ax(e){let{req:t,leaseRegistry:r}=e,i=aL(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let aC=new Set(["agent_device.command","agent-device.command"]),aT={"agent_device.lease.allocate":"lease_allocate","agent-device.lease.allocate":"lease_allocate","agent_device.lease.heartbeat":"lease_heartbeat","agent-device.lease.heartbeat":"lease_heartbeat","agent_device.lease.release":"lease_release","agent-device.lease.release":"lease_release"},aR=new Set([...aC,...Object.keys(aT)]);function aP(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function a$(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function aF(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function aV(e,t){let r="string"==typeof t.authorization?t.authorization:"",i=r.toLowerCase().startsWith("bearer ")?r.slice(7):void 0,n="string"==typeof t["x-agent-device-token"]?t["x-agent-device-token"]:void 0;return("string"==typeof e.token?e.token:void 0)??n??i??""}function aU(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function aG(e,t){if(!e)return{ok:!0};let r=await e(t);if(void 0===r||!0===r)return{ok:!0};if(!1===r){let e=b(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:aP(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:aP(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=c(r.tenantId);if(!e){let e=b(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:aP(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function aB(){let e,t=process.env.AGENT_DEVICE_HTTP_AUTH_HOOK;if(!t)return null;let r=process.env.AGENT_DEVICE_HTTP_AUTH_EXPORT||"default",i=n.isAbsolute(t)?t:n.resolve(t);try{e=await import(g(i).href)}catch(e){throw new I("COMMAND_FAILED","Failed to load AGENT_DEVICE_HTTP_AUTH_HOOK module",{hookPath:i,error:e instanceof Error?e.message:String(e)})}let a=e[r];if("function"!=typeof a)throw new I("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function aq(e){let t=await aB(),{handleRequest:r}=e;return i.createServer((e,i)=>{if("GET"===e.method&&"/health"===e.url){i.statusCode=200,i.setHeader("content-type","application/json"),i.end(JSON.stringify({ok:!0}));return}if("POST"!==e.method||"/rpc"!==e.url){i.statusCode=404,i.end("Not found");return}let n="";e.setEncoding("utf8"),e.on("data",t=>{(n+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{i.headersSent||a$(i,aP(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a;try{a=JSON.parse(n)}catch{a$(i,aP(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void a$(i,aP(a.id??null,-32600,"Invalid Request"),400);if(!aR.has(a.method))return void a$(i,aP(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void a$(i,aP(a.id??null,-32602,"Invalid params"),400);try{var o;let n=a.params,s=function(e,t,r){if(aC.has(e))return{token:aV(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=aT[e];if(i){let e;return{token:aV(t,r),session:aU(t,"session")??"default",command:i,positionals:[],meta:{tenantId:aU(t,"tenantId")??aU(t,"tenant"),runId:aU(t,"runId"),leaseId:aU(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:aU(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(o=a.method,aC.has(o)&&("string"!=typeof s.command||0===s.command.length))return void a$(i,aP(a.id??null,-32602,"Invalid params: command is required"),400);let l=await aG(t,{headers:e.headers,rpcRequest:a,daemonRequest:s});if(!l.ok)return void a$(i,l.response,l.statusCode);l.tenantId&&(s.meta={...s.meta,tenantId:l.tenantId,sessionIsolation:s.meta?.sessionIsolation??s.flags?.sessionIsolation??"tenant"});let d=await r(s);if(d.ok)return void a$(i,{jsonrpc:"2.0",id:a.id??null,result:d});a$(i,aP(a.id??null,-32e3,d.error.message,d.error),aF(d.error.code))}catch(t){let e=b(t);a$(i,aP(a.id??null,-32e3,e.message,e),aF(e.code))}})})}function aj(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function aW(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function aH(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class aJ{leases=new Map;runBindings=new Map;maxActiveSimulatorLeases;defaultLeaseTtlMs;minLeaseTtlMs;maxLeaseTtlMs;now;constructor(e={}){this.maxActiveSimulatorLeases=Number.isInteger(e.maxActiveSimulatorLeases)?Math.max(0,Number(e.maxActiveSimulatorLeases)):0,this.defaultLeaseTtlMs=Number.isInteger(e.defaultLeaseTtlMs)?Math.max(1,Number(e.defaultLeaseTtlMs)):6e4,this.minLeaseTtlMs=Number.isInteger(e.minLeaseTtlMs)?Math.max(1,Number(e.minLeaseTtlMs)):5e3,this.maxLeaseTtlMs=Number.isInteger(e.maxLeaseTtlMs)?Math.max(this.minLeaseTtlMs,Number(e.maxLeaseTtlMs)):6e5,this.now=e.now??(()=>Date.now())}allocateLease(e){let t=aH(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=aj(e.runId);if(!i)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");this.cleanupExpiredLeases();let n=this.resolveLeaseTtlMs(e.ttlMs),a=this.bindingKey(r,i,t),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:f.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=aW(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});this.assertOptionalScopeMatch(r,e.tenantId,e.runId);let i=this.resolveLeaseTtlMs(e.ttlMs);return this.refreshLease(r,i)}releaseLease(e){let t=aW(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);return r?(this.assertOptionalScopeMatch(r,e.tenantId,e.runId),this.leases.delete(t),this.runBindings.delete(this.bindingKey(r.tenantId,r.runId,r.backend)),{released:!0}):{released:!1}}assertLeaseAdmission(e){let t=aH(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=aj(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=aW(e.leaseId);if(!n)throw new I("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}listActiveLeases(){return this.cleanupExpiredLeases(),Array.from(this.leases.values()).map(e=>({...e}))}cleanupExpiredLeases(){let e=this.now();for(let t of this.leases.values())t.expiresAt>e||(this.leases.delete(t.leaseId),this.runBindings.delete(this.bindingKey(t.tenantId,t.runId,t.backend)))}enforceCapacity(e){if("ios-simulator"!==e||this.maxActiveSimulatorLeases<=0)return;let t=Array.from(this.leases.values()).filter(e=>"ios-simulator"===e.backend).length;if(!(t<this.maxActiveSimulatorLeases))throw new I("COMMAND_FAILED","No simulator lease capacity available",{reason:"LEASE_CAPACITY_EXCEEDED",activeLeases:t,maxActiveLeases:this.maxActiveSimulatorLeases,backend:e,hint:"Retry after releasing another simulator lease."})}resolveLeaseTtlMs(e){if(!Number.isInteger(e))return this.defaultLeaseTtlMs;let t=Number(e);if(t<this.minLeaseTtlMs||t>this.maxLeaseTtlMs)throw new I("INVALID_ARGS",`Lease ttlMs must be between ${this.minLeaseTtlMs} and ${this.maxLeaseTtlMs}.`);return t}refreshLease(e,t){let r=this.now(),i={...e,heartbeatAt:r,expiresAt:r+t};return this.leases.set(i.leaseId,i),this.runBindings.set(this.bindingKey(i.tenantId,i.runId,i.backend),i.leaseId),{...i}}bindingKey(e,t,r){return`${e}:${t}:${r}`}assertOptionalScopeMatch(e,t,r){let i=c(t),n=aj(r);if(t&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(i&&e.tenantId!==i||n&&e.runId!==n)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}let{baseDir:az,infoPath:aK,lockPath:aX,logPath:aY,sessionsDir:aZ}=G(process.env.AGENT_DEVICE_STATE_DIR),aQ=U(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var a0=aZ;if(R.existsSync(a0))for(let e of R.readdirSync(a0,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(a0,e.name,"app-log.pid");if(R.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}(R.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{nc(t)}}let a1=new iC(aZ),a2=new aJ({maxActiveSimulatorLeases:oa(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),a3=D(),a4=f.randomBytes(24).toString("hex"),a8=new Set(["session_list","devices"]),a5=new Set(["session_list","devices","lease_allocate","lease_heartbeat","lease_release"]),a6=T(process.pid)??void 0,a9=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function a7(e,t,r){let i=k().requestId;return{...iT(aY,e,t,r,i),requestId:i}}async function oe(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:aY},async()=>{if(r.token!==a4)return{ok:!1,error:b(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=_(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=c(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(r);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=aL(e);a5.has(t)||e.meta?.sessionIsolation!=="tenant"||a2.assertLeaseAdmission({tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId,backend:i.leaseBackend});let n=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,a1),a=a1.get(n);a&&!a8.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=q(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=ea(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(a,e.flags);let o=await ax({req:e,leaseRegistry:a2});if(o)return ot(o);let s=await n8({req:e,sessionName:n,logPath:aY,sessionStore:a1,invoke:oe});if(s)return ot(s);let l=await al({req:e,sessionName:n,logPath:aY,sessionStore:a1});if(l)return ot(l);let d=await ay({req:e,sessionName:n,sessionStore:a1,logPath:aY});if(d)return ot(d);let u=await ag({req:e,sessionName:n,logPath:aY,sessionStore:a1,invoke:oe});if(u)return ot(u);let p=await a_({req:e,sessionName:n,sessionStore:a1,contextFromFlags:a7});if(p)return ot(p);let f=a1.get(n);if(!f)return ot({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!iS(t,f.device))return ot({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await ih(f.device,t,e.positionals??[],e.flags?.out,{...a7(e.flags,f.appBundleId,f.trace?.outPath)});return a1.recordAction(f,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),ot({ok:!0,data:m??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=k(),t=$({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function ot(e){let t=k();if(!e.ok){M({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:b(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return M({level:"info",phase:"request_success"}),$(),e}function or(){R.existsSync(aK)&&R.unlinkSync(aK)}function oi(){if(!R.existsSync(aX))return null;try{let e=JSON.parse(R.readFileSync(aX,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function on(){let e=oi();if(!e||e.pid===process.pid)try{R.existsSync(aX)&&R.unlinkSync(aX)}catch{}}function oa(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}(async function e(){let e,t;if(!function(){R.existsSync(az)||R.mkdirSync(az,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:a3,startedAt:Date.now(),processStartTime:a6},null,2),t=()=>{try{return R.writeFileSync(aX,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=oi();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(aX)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===aQ||"dual"===aQ){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&t4.add(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await rI(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(i.add(s),t8(s)))throw new I("COMMAND_FAILED","request canceled");n=await oe(e)}catch(e){n={ok:!1,error:b(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&t4.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
30
|
+
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===aQ||"dual"===aQ){let e=await aq({handleRequest:oe});r.push(e),t=await new Promise((t,r)=>{e.once("error",r),e.listen(0,"127.0.0.1",()=>{e.off("error",r);let i=e.address();"object"==typeof i&&i?.port?t(i.port):r(new I("COMMAND_FAILED","Failed to bind HTTP server"))})})}i={socketPort:e,httpPort:t},R.existsSync(az)||R.mkdirSync(az,{recursive:!0}),R.writeFileSync(aY,""),n=i.httpPort&&i.socketPort?"dual":i.httpPort?"http":"socket",R.writeFileSync(aK,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:a4,pid:process.pid,version:a3,codeSignature:a9,processStartTime:a6,stateDir:az},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
31
31
|
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
32
32
|
`)}catch(t){let e=w(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|
|
33
|
-
`),r))try{t.close(()=>{})}catch{}
|
|
33
|
+
`),r))try{t.close(()=>{})}catch{}or(),on(),process.exit(1);return}let n=!1,a=async()=>{await Promise.all(r.map(async e=>{await new Promise(t=>{try{e.close(()=>t())}catch{t()}})}))},o=async()=>{if(!n){for(let e of(n=!0,await a(),a1.toArray()))a1.writeSessionLog(e);await rv(),or(),on(),process.exit(0)}};process.on("SIGINT",()=>{o()}),process.on("SIGTERM",()=>{o()}),process.on("SIGHUP",()=>{o()}),process.on("uncaughtException",e=>{let t=e instanceof I?e:w(e);process.stderr.write(`Daemon error: ${t.message}
|
|
34
34
|
`),o()})})();
|