agent-device 0.7.0 → 0.7.1
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/README.md +24 -3
- package/dist/src/678.js +3 -0
- package/dist/src/bin.js +49 -49
- package/dist/src/daemon.js +32 -28
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +1 -1
- package/dist/src/735.js +0 -3
package/dist/src/daemon.js
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
let e;import{isCancel as t,select as r}from"@clack/prompts";import{
|
|
2
|
-
`)}function
|
|
3
|
-
${e.stderr}`}function
|
|
4
|
-
${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let
|
|
5
|
-
${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new
|
|
6
|
-
${i}
|
|
7
|
-
${
|
|
8
|
-
${t}
|
|
9
|
-
${t}
|
|
10
|
-
${t}`.toLowerCase();return r.includes("
|
|
11
|
-
${
|
|
1
|
+
let e;import{isCancel as t,select as r}from"@clack/prompts";import{node_http as i,node_path as n,readProcessCommand as a,validateAndNormalizeBatchSteps as o,isAgentDeviceDaemonProcess as s,normalizeTenantId as l,runCmdBackground as d,SETTINGS_INVALID_ARGS_MESSAGE as c,node_crypto as u,runCmd as p,displayLabel as f,spawn as m,asAppError as h,pathToFileURL as w,AppError as g,whichCmd as I,buildSnapshotDisplayLines as v,fileURLToPath as A,runCmdStreaming as y,formatRole as S,normalizeError as b,resolveSessionIsolationMode as N,readVersion as _,findProjectRoot as D,getDiagnosticsMeta as k,withDiagnosticTimer as E,emitDiagnostic as M,DEFAULT_BATCH_MAX_STEPS as x,promises as O,isProcessAlive as L,readProcessStartTime as C,node_fs as R,withDiagnosticsScope as T,flushDiagnosticsToSessionFile as P,node_os as $,node_net as F,resolveDaemonServerMode as G,resolveDaemonPaths as U,formatSnapshotLine as V}from"./678.js";function B(e){return"apple"===e?"ios":e}async function q(e,i){let n=e,a=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(i.platform&&(n=n.filter(e=>e.platform===i.platform)),i.target&&(n=n.filter(e=>(e.target??"mobile")===i.target)),i.udid){let e=n.find(e=>e.id===i.udid&&"ios"===e.platform);if(!e)throw new g("DEVICE_NOT_FOUND",`No iOS device with UDID ${i.udid}`);return e}if(i.serial){let e=n.find(e=>e.id===i.serial&&"android"===e.platform);if(!e)throw new g("DEVICE_NOT_FOUND",`No Android device with serial ${i.serial}`);return e}if(i.deviceName){let e=a(i.deviceName),t=n.find(t=>a(t.name)===e);if(!t)throw new g("DEVICE_NOT_FOUND",`No device named ${i.deviceName}`);return t}if(1===n.length)return n[0];if(0===n.length)throw new g("DEVICE_NOT_FOUND","No devices found",{selector:i});let o=n.filter(e=>e.booted);if(1===o.length)return o[0];if(!process.env.CI&&process.stdin.isTTY&&process.stdout.isTTY){let e=await r({message:"Multiple devices available. Choose a device to continue:",options:(o.length>0?o:n).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(t(e))throw new g("INVALID_ARGS","Device selection cancelled");if(e){let t=n.find(t=>t.id===e);if(t)return t}}return o[0]??n[0]}let j=W(process.env.AGENT_DEVICE_RETRY_LOGS);function W(e){return["1","true","yes","on"].includes((e??"").toLowerCase())}let H=2e4,J=12e4,z=1e4;class K{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new K(t,e)}remainingMs(e=Date.now()){return Math.max(0,this.expiresAtMs-e)}elapsedMs(e=Date.now()){return Math.max(0,e-this.startedAtMs)}isExpired(e=Date.now()){return 0>=this.remainingMs(e)}}async function X(e,t={},r={}){let i,n={maxAttempts:t.maxAttempts??3,baseDelayMs:t.baseDelayMs??200,maxDelayMs:t.maxDelayMs??2e3,jitter:t.jitter??.2,shouldRetry:t.shouldRetry};for(let t=1;t<=n.maxAttempts&&(!r.deadline?.isExpired()||!(t>1));t+=1)try{let i=await e({attempt:t,maxAttempts:n.maxAttempts,deadline:r.deadline});return r.onEvent?.({phase:r.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs()}),Z({phase:r.phase,event:"succeeded",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs()}),i}catch(d){i=d;let e=r.classifyReason?.(d),a={phase:r.phase,event:"attempt_failed",attempt:t,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:e};if(r.onEvent?.(a),Z(a),t>=n.maxAttempts||n.shouldRetry&&!n.shouldRetry(d,t))break;let o=function(e,t,r,i){let n=Math.min(t,e*2**(i-1));return Math.max(0,n+n*r*(2*Math.random()-1))}(n.baseDelayMs,n.maxDelayMs,n.jitter,t),s=r.deadline?Math.min(o,r.deadline.remainingMs()):o;if(s<=0)break;let l={phase:r.phase,event:"retry_scheduled",attempt:t,maxAttempts:n.maxAttempts,delayMs:s,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:e};r.onEvent?.(l),Z(l),await function(e){return new Promise(t=>setTimeout(t,e))}(s)}let a={phase:r.phase,event:"exhausted",attempt:n.maxAttempts,maxAttempts:n.maxAttempts,elapsedMs:r.deadline?.elapsedMs(),remainingMs:r.deadline?.remainingMs(),reason:r.classifyReason?.(i)};if(r.onEvent?.(a),Z(a),i)throw i;throw new g("COMMAND_FAILED","retry failed")}async function Y(e,t={}){return X(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function Z(e){M({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}}),j&&process.stderr.write(`[agent-device][retry] ${JSON.stringify(e)}
|
|
2
|
+
`)}function Q(e){let t=e.error?h(e.error):null,r=e.context?.platform,i=e.context?.phase;if(t?.code==="TOOL_MISSING")return"android"===r?"ADB_TRANSPORT_UNAVAILABLE":"IOS_TOOL_MISSING";let n=t?.details??{},a="string"==typeof n.message?n.message:void 0,o="string"==typeof n.stdout?n.stdout:void 0,s="string"==typeof n.stderr?n.stderr:void 0,l=n.boot&&"object"==typeof n.boot?n.boot:null,d=n.bootstatus&&"object"==typeof n.bootstatus?n.bootstatus:null,c=[e.message,t?.message,e.stdout,e.stderr,a,o,s,"string"==typeof l?.stdout?l.stdout:void 0,"string"==typeof l?.stderr?l.stderr:void 0,"string"==typeof d?.stdout?d.stdout:void 0,"string"==typeof d?.stderr?d.stderr:void 0].filter(Boolean).join("\n").toLowerCase();return"ios"===r&&(c.includes("runner did not accept connection")||"connect"===i&&(c.includes("timed out")||c.includes("timeout")||c.includes("econnrefused")||c.includes("connection refused")||c.includes("fetch failed")||c.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===r&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===r&&"boot"===i&&(c.includes("timed out")||c.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":c.includes("resource temporarily unavailable")||c.includes("killed: 9")||c.includes("cannot allocate memory")||c.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===r&&(c.includes("device not found")||c.includes("no devices")||c.includes("device offline")||c.includes("offline")||c.includes("unauthorized")||c.includes("not authorized")||c.includes("unable to locate device")||c.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||c.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function ee(e){switch(e){case"IOS_BOOT_TIMEOUT":return"Retry simulator boot and inspect simctl bootstatus logs; in CI consider increasing AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS.";case"IOS_RUNNER_CONNECT_TIMEOUT":return"Retry runner startup, inspect xcodebuild logs, and verify simulator responsiveness before command execution.";case"ANDROID_BOOT_TIMEOUT":return"Retry emulator startup and verify sys.boot_completed reaches 1; consider increasing startup budget in CI.";case"ADB_TRANSPORT_UNAVAILABLE":return"Check adb server/device transport (adb devices -l), restart adb, and ensure the target device is online and authorized.";case"CI_RESOURCE_STARVATION_SUSPECTED":return"CI machine may be resource constrained; reduce parallel jobs or use a larger runner.";case"IOS_TOOL_MISSING":return"Xcode command-line tools are missing or not in PATH; run xcode-select --install and verify xcrun works.";case"BOOT_COMMAND_FAILED":return"Inspect command stderr/stdout for the failing boot phase and retry after environment validation.";default:return"Retry once and inspect verbose logs for the failing phase."}}let et=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];function er(e){return`${e.stdout}
|
|
3
|
+
${e.stderr}`}function ei(e,t){return["-s",e,...t]}function en(e){return e.startsWith("emulator-")}async function ea(e,t=z){return p("adb",ei(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function eo(e,t){let r=t.replace(/_/g," ").trim();if(!en(e))return r||e;let i=await p("adb",ei(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:z}),n=i.stdout.trim();return 0===i.exitCode&&n?n.replace(/_/g," "):r||e}async function es(e,t){let r=er(await p("adb",ei(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:z})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function el(e){return(await Promise.all(et.map(async t=>await es(e,t)))).some(e=>!0===e)}async function ed(e){var t;let r;return"tv"===((r=er(await p("adb",ei(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:z})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await el(e)?"tv":(t=er(await p("adb",ei(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:z})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function ec(){if(!await I("adb"))throw new g("TOOL_MISSING","adb not found in PATH");let e=(await p("adb",["devices","-l"],{timeoutMs:z})).stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith("List of devices")).map(e=>e.split(/\s+/)).filter(e=>"device"===e[1]).map(e=>({serial:e[0],rawModel:(e.find(e=>e.startsWith("model:"))??"").replace("model:","")}));return await Promise.all(e.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([eo(e,t),eu(e),ed(e)]);return{platform:"android",id:e,name:r,kind:en(e)?"emulator":"device",target:n,booted:i}}))}async function eu(e){try{let t=await ea(e);return"1"===t.stdout.trim()}catch{return!1}}async function ep(e,t=6e4){let r,i=K.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await X(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new g("COMMAND_FAILED","Android boot deadline exceeded",{serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),message:"timeout"});let o=Math.max(1e3,n?.remainingMs()??t),s=await ea(e,Math.min(o,z));if(r=s,"1"!==s.stdout.trim())throw new g("COMMAND_FAILED","Android device is still booting",{serial:e,stdout:s.stdout,stderr:s.stderr,exitCode:s.exitCode})},{maxAttempts:n,baseDelayMs:1e3,maxDelayMs:1e3,jitter:0,shouldRetry:e=>{let t=Q({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}});return"ADB_TRANSPORT_UNAVAILABLE"!==t&&"ANDROID_BOOT_TIMEOUT"!==t}},{deadline:i,phase:"boot",classifyReason:e=>Q({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(u){let n=h(u),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=Q({error:u,stdout:o,stderr:s,context:{platform:"android",phase:"boot"}});"BOOT_COMMAND_FAILED"===d&&"Android device is still booting"===n.message&&(d="ANDROID_BOOT_TIMEOUT");let c={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:ee(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new g("COMMAND_FAILED","Android device did not finish booting in time",c);if("TOOL_MISSING"===n.code)throw new g("TOOL_MISSING",n.message,{...c,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new g("COMMAND_FAILED",n.message,{...c,...n.details??{}});throw new g(n.code,n.message,{...c,...n.details??{}},n.cause)}}function ef(e){let t=e.trim();if(!t||/\s/.test(t))return!1;let r=/^([A-Za-z][A-Za-z0-9+.-]*):(.+)$/.exec(t);if(!r)return!1;let i=r[1]?.toLowerCase(),n=r[2]??"";return"http"!==i&&"https"!==i&&"ws"!==i&&"wss"!==i&&"ftp"!==i&&"ftps"!==i||n.startsWith("//")}function em(e,t){let r,i=e?.trim();return i?i:"http"===(r=t.trim().split(":")[0]?.toLowerCase())||"https"===r?"com.apple.mobilesafari":void 0}function eh(e){let t=ew(e),r=e=>{let r=eg(t,e);if(null!==r)return"true"===r};return{text:eg(t,"text"),desc:eg(t,"content-desc"),resourceId:eg(t,"resource-id"),className:eg(t,"class"),bounds:eg(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused")}}function ew(e){let t=new Map,r=e.indexOf(" "),i=e.lastIndexOf(">");if(r<0||i<=r)return t;let n=/([^\s=/>]+)\s*=\s*(["'])([\s\S]*?)\2/y,a=r;for(;a<i;){for(;a<i;){let t=e[a];if(" "!==t&&"\n"!==t&&"\r"!==t&&" "!==t)break;a+=1}if(a>=i)break;let r=e[a];if("/"===r||">"===r)break;n.lastIndex=a;let o=n.exec(e);if(!o)break;t.set(o[1],o[3]),a=n.lastIndex}return t}function eg(e,t){return e.get(t)??null}function eI(e){if(!e)return;let t=/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/.exec(e);if(!t)return;let r=Number(t[1]),i=Number(t[2]);return{x:r,y:i,width:Math.max(0,Number(t[3])-r),height:Math.max(0,Number(t[4])-i)}}function ev(e){return e?e.toLowerCase():""}function eA(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}let ey=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function eS(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new g("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function eb(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new g("INVALID_ARGS",`permission setting requires a target: ${ey.join("|")}`)}function eN(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new g("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}let e_={settings:{type:"intent",value:"android.settings.SETTINGS"}},eD="android.intent.category.LAUNCHER",ek="android.intent.category.LEANBACK_LAUNCHER",eE="android.intent.category.DEFAULT";function eM(e,t){return["-s",e.id,...t]}async function ex(e,t){let r=t.trim();if(r.includes("."))return{type:"package",value:r};let i=e_[r.toLowerCase()];if(i)return i;let n=(await p("adb",eM(e,["shell","pm","list","packages"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean).filter(e=>e.toLowerCase().includes(r.toLowerCase()));if(1===n.length)return{type:"package",value:n[0]};if(n.length>1)throw new g("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new g("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function eO(e,t="all"){let r=await eL(e);return("user-installed"===t?(await eR(e)).filter(e=>r.has(e)):Array.from(r)).sort((e,t)=>e.localeCompare(t)).map(e=>({package:e,name:function(e){let t=new Set(["com","android","google","app","apps","service","services","mobile","client"]),r=e.split(".").flatMap(e=>e.split(/[_-]+/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0),i=r[r.length-1]??e;for(let e=r.length-1;e>=0;e-=1){let n=r[e];if(!t.has(n)){i=n;break}}return i.split(/[^a-z0-9]+/i).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}(e)}))}async function eL(e){let t=new Set;for(let r of eC(e,{includeFallbackWhenUnknown:!0})){let i=await p("adb",eM(e,["shell","cmd","package","query-activities","--brief","-a","android.intent.action.MAIN","-c",r]),{allowFailure:!0});if(0===i.exitCode&&0!==i.stdout.trim().length)for(let e of i.stdout.split("\n")){let r=e.trim();if(!r)continue;let i=r.split(/\s+/)[0],n=i.includes("/")?i.split("/")[0]:i;n&&t.add(n)}}return t}function eC(e,t={}){return"tv"===e.target?[ek]:"mobile"===e.target?[eD]:t.includeFallbackWhenUnknown?[eD,ek]:[eD]}async function eR(e){return(await p("adb",eM(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function eT(e){let t=await eP(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let r=await eP(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return r||{}}async function eP(e,t){for(let r of t){let t=function(e){for(let t of[/mCurrentFocus=Window\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mFocusedApp=AppWindowToken\{[^}]*\s([\w.]+)\/([\w.$]+)/,/mResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/,/ResumedActivity:.*?\s([\w.]+)\/([\w.$]+)/]){let r=t.exec(e);if(r)return{package:r[1],activity:r[2]}}return null}((await p("adb",eM(e,r),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function e$(e,t,r){var i,n;let a;e.booted||await ep(e.id);let o=t.trim();if(ef(o)){if(r)throw new g("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await p("adb",eM(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await ex(e,t),l=eC(e)[0]??eD;if("intent"===s.type){if(r)throw new g("INVALID_ARGS","Activity override requires a package name, not an intent");await p("adb",eM(e,["shell","am","start","-W","-a",s.value]));return}if(r){let t=r.includes("/")?r:`${s.value}/${r.startsWith(".")?r:`.${r}`}`;await p("adb",eM(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eE,"-c",l,"-n",t]));return}let d=await p("adb",eM(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eE,"-c",l,"-p",s.value]),{allowFailure:!0});if(0===d.exitCode&&(i=d.stdout,n=d.stderr,a=`${i}
|
|
4
|
+
${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let c=await eF(e,s.value);if(!c)throw new g("COMMAND_FAILED",`Failed to launch ${s.value}`,{stdout:d.stdout,stderr:d.stderr});await p("adb",eM(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eE,"-c",l,"-n",c]))}async function eF(e,t){for(let r of Array.from(new Set(eC(e,{includeFallbackWhenUnknown:!0})))){let i=await p("adb",eM(e,["shell","cmd","package","resolve-activity","--brief","-a","android.intent.action.MAIN","-c",r,t]),{allowFailure:!0});if(0!==i.exitCode)continue;let n=function(e){let t=e.split("\n").map(e=>e.trim()).filter(Boolean);for(let e=t.length-1;e>=0;e-=1){let r=t[e];if(r.includes("/"))return r.split(/\s+/)[0]}return null}(i.stdout);if(n)return n}return null}async function eG(e){e.booted||await ep(e.id)}async function eU(e,t){if("settings"===t.trim().toLowerCase())return void await p("adb",eM(e,["shell","am","force-stop","com.android.settings"]));let r=await ex(e,t);if("intent"===r.type)throw new g("INVALID_ARGS","Close requires a package name, not an intent");await p("adb",eM(e,["shell","am","force-stop",r.value]))}async function eV(e,t){let r=await ex(e,t);if("intent"===r.type)throw new g("INVALID_ARGS","reinstall requires a package name, not an intent");let i=await p("adb",eM(e,["uninstall",r.value]),{allowFailure:!0});if(0!==i.exitCode){let e=`${i.stdout}
|
|
5
|
+
${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new g("COMMAND_FAILED",`adb uninstall failed for ${r.value}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return{package:r.value}}async function eB(e,t){await p("adb",eM(e,["install",t]))}async function eq(e,t,r){e.booted||await ep(e.id);let{package:i}=await eV(e,t);return await eB(e,r),{package:i}}async function ej(e,t,r){await p("adb",eM(e,["shell","input","tap",String(t),String(r)]))}async function eW(e,t,r,i,n,a=250){await p("adb",eM(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function eH(e){await p("adb",eM(e,["shell","input","keyevent","4"]))}async function eJ(e){await p("adb",eM(e,["shell","input","keyevent","3"]))}async function ez(e){await p("adb",eM(e,["shell","input","keyevent","187"]))}async function eK(e,t,r,i=800){await p("adb",eM(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function eX(e,t){if(!tc(t)||"ok"!==await tu(e,t))try{let r=t.replace(/ /g,"%s");await p("adb",eM(e,["shell","input","text",r]))}catch(e){if(tc(t)&&function(e){if(!(e instanceof g)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return!!(t.includes("exception occurred while executing 'text'")||t.includes("nullpointerexception")&&t.includes("inputshellcommand.sendtext"))}(e))throw new g("COMMAND_FAILED","Non-ASCII text input is not supported on this Android shell. Install an ADB keyboard IME or use ASCII input.",{textPreview:t.slice(0,32)},e instanceof Error?e:void 0);throw e}}async function eY(e){let t,r;return(r=(t=(await tf(e,["shell","cmd","clipboard","get","text"],"read")).replace(/\r\n/g,"\n").replace(/\n$/,"")).match(/^clipboard text:\s*(.*)$/i))?r[1]??"":"null"===t.trim().toLowerCase()?"":t}async function eZ(e,t){await tf(e,["shell","cmd","clipboard","set","text",t],"write")}async function eQ(e,t,r){await ej(e,t,r)}async function e0(e,t,r,i){let n=Array.from(i).length;await eQ(e,t,r);let a=null;for(let l of[{clearPadding:12,minClear:8,maxClear:48,chunkSize:4,delayMs:0},{clearPadding:24,minClear:16,maxClear:96,chunkSize:1,delayMs:15}]){var o,s;let d=(o=n+l.clearPadding,s=l.minClear,Math.max(s,Math.min(l.maxClear,o)));if(await tm(e,d),await td(e,i,l.chunkSize,l.delayMs),(a=await th(e,t,r))===i)return}throw new g("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:a??null})}async function e1(e,t,r=.6){let{width:i,height:n}=await e7(e),a=Math.floor(i*r),o=Math.floor(n*r),s=Math.floor(i/2),l=Math.floor(n/2),d=s,c=l,u=s,f=l;switch(t){case"up":c=l-Math.floor(o/2),f=l+Math.floor(o/2);break;case"down":c=l+Math.floor(o/2),f=l-Math.floor(o/2);break;case"left":d=s-Math.floor(a/2),u=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),u=s-Math.floor(a/2);break;default:throw new g("INVALID_ARGS",`Unknown direction: ${t}`)}await p("adb",eM(e,["shell","input","swipe",String(d),String(c),String(u),String(f),"300"]))}async function e2(e,t){for(let r=0;r<8;r+=1){let r="";try{r=await te(e)}catch(t){let e=t instanceof Error?t.message:String(t);throw new g("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let r=t.toLowerCase(),i=/<node[^>]+>/g,n=i.exec(e);for(;n;){let t=ew(n[0]),a=(eg(t,"text")??"").toLowerCase(),o=(eg(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=eI(eg(t,"bounds"));if(e)return{x:Math.floor(e.x+e.width/2),y:Math.floor(e.y+e.height/2)};return{x:0,y:0}}n=i.exec(e)}return null}(r,t))return;await e1(e,"down",.5)}throw new g("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function e3(e,t){let r=await p("adb",eM(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!r.stdoutBuffer)throw new g("COMMAND_FAILED","Failed to capture screenshot");await O.writeFile(t,r.stdoutBuffer)}async function e4(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=tn(r);await p("adb",eM(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=tn(r);await p("adb",eM(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await p("adb",eM(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=tn(r);await p("adb",eM(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await ta(e,r);await p("adb",eM(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new g("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await e8(e,t);return}case"permission":{if(!i)throw new g("INVALID_ARGS","permission setting requires an active app in session");let t=eS(r),a=function(e,t){let r=eb(e);if(t?.trim())throw new g("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===r)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===r)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===r)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===r)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new g("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(n?.permissionTarget,n?.permissionMode);if("notifications"===a.kind)return void await ts(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await to(e,i,o);await p("adb",eM(e,["shell","pm",o,i,a.value]));return}default:throw new g("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function e8(e,t){var r;let i,n,a=(r=e,n=[["shell","cmd","fingerprint","touch",i="match"===t?"1":"9999"],["shell","cmd","fingerprint","finger",i]],"emulator"===r.kind&&n.push(["emu","finger","touch",i]),n),o=[];for(let t of a){let r=await p("adb",eM(e,t),{allowFailure:!0});if(0===r.exitCode)return;o.push({args:t,stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}let s=o.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(o.length>0&&o.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
6
|
+
${r}`.toLowerCase()).includes("unknown command")||i.includes("can't find service: fingerprint")||i.includes("service fingerprint was not found")||i.includes("fingerprint cmd unavailable")||i.includes("emu command is not supported")||i.includes("emulator console is not running")||i.includes("fingerprint")&&i.includes("not found")}))throw new g("UNSUPPORTED_OPERATION","Android fingerprint simulation is not supported on this target/runtime.",{deviceId:e.id,action:t,hint:"Use an Android emulator with biometric support, or a device/runtime that exposes cmd fingerprint.",attempts:s});throw new g("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:s})}async function e5(e,t,r){let i="string"==typeof r.action&&r.action.trim()?r.action.trim():`${t}.TEST_PUSH`,n=["shell","am","broadcast","-a",i,"-p",t],a="string"==typeof r.receiver?r.receiver.trim():"";a&&n.push("-n",a);let o=r.extras;if(void 0!==o&&("object"!=typeof o||null===o||Array.isArray(o)))throw new g("INVALID_ARGS","Android push payload extras must be an object");let s=0;for(let[e,t]of Object.entries(o??{}))e&&(function(e,t,r){if("string"==typeof r)return e.push("--es",t,r);if("boolean"==typeof r)return e.push("--ez",t,r?"true":"false");if("number"==typeof r&&Number.isFinite(r))return Number.isInteger(r)?e.push("--ei",t,String(r)):e.push("--ef",t,String(r));throw new g("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(n,e,t),s+=1);return await p("adb",eM(e,n)),{action:i,extrasCount:s}}async function e6(e,t={}){return function(e,t,r){let i=function(e){let t={type:null,label:null,value:null,identifier:null,depth:-1,children:[]},r=[t],i=/<node\b[^>]*>|<\/node>/g,n=i.exec(e);for(;n;){let t=n[0];if(t.startsWith("</node")){r.length>1&&r.pop(),n=i.exec(e);continue}let a=eh(t),o=eI(a.bounds),s=r[r.length-1],l={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,rect:o,enabled:a.enabled,hittable:a.clickable??a.focusable,depth:s.depth+1,parentIndex:void 0,children:[]};s.children.push(l),t.endsWith("/>")||r.push(l),n=i.exec(e)}return t}(e),n=[],a=!1,o=r.depth??1/0,s=r.scope?function(e,t){let r=t.toLowerCase(),i=[...e.children];for(;i.length>0;){let e=i.shift(),t=e.label?.toLowerCase()??"",n=e.value?.toLowerCase()??"",a=e.identifier?.toLowerCase()??"";if(t.includes(r)||n.includes(r)||a.includes(r))return e;i.push(...e.children)}return null}(i,r.scope):null,l=s?[s]:i.children,d=new Map,c=e=>{let t=d.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||c(t))return d.set(e,!0),!0;return d.set(e,!1),!1},u=(e,t,i,s=!1,l=!1)=>{var d,p,f,m,h,w;let g,I,v,A,y,S,b,N;if(n.length>=800){a=!0;return}if(t>o)return;let _=!!r.raw||(d=e,p=r,f=s,m=c(e),h=l,I=ev(d.type),v=!!(d.label&&d.label.trim().length>0),A=!!(d.identifier&&d.identifier.trim().length>0),y=v&&!eA(d.label??""),S=A&&!eA(d.identifier??""),b=(g=(w=I).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,N="imageview"===I||"imagebutton"===I,p.interactiveOnly?!!d.hittable||!!(y||S)&&!N&&(!b||!!h)&&(f||m||h):p.compact?y||S||!!d.hittable:!b&&!N||!!d.hittable||!!y||!!S&&!!m||m),D=i;_&&(D=n.length,n.push({index:D,type:e.type??void 0,label:e.label??void 0,value:e.value??void 0,identifier:e.identifier??void 0,rect:e.rect,enabled:e.enabled,hittable:e.hittable,depth:t,parentIndex:i}));let k=s||!!e.hittable,E=l||function(e){if(!e)return!1;let t=ev(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let r of e.children)if(u(r,t+1,D,k,E),a)return};for(let e of l)if(u(e,0,void 0,!1,!1),a)break;return a?{nodes:n,truncated:a}:{nodes:n}}(await te(e),0,t)}async function e9(){if(!await I("adb"))throw new g("TOOL_MISSING","adb not found in PATH")}async function e7(e){let t=(await p("adb",eM(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new g("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function te(e){return Y(()=>tt(e),{shouldRetry:ti})}async function tt(e){var t,r,i;let n,a,o=await p("adb",eM(e,["exec-out","uiautomator","dump","/dev/tty"]),{allowFailure:!0});if(0===o.exitCode){let e=tr(o.stdout,o.stderr);if(e)return e}let s="/sdcard/window_dump.xml",l=await p("adb",eM(e,["shell","uiautomator","dump",s])),d=(t=s,r=l.stdout,i=l.stderr,n=`${r}
|
|
7
|
+
${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),c=await p("adb",eM(e,["shell","cat",d])),u=tr(c.stdout,c.stderr);if(!u)throw new g("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:c.stdout,stderr:c.stderr});return u}function tr(e,t){let r=`${e}
|
|
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 ti(e){if(!(e instanceof g)||"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 tn(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 g("INVALID_ARGS",`Invalid setting state: ${e}`)}async function ta(e,t){let r=eN(t);if("toggle"!==r)return r;let i=await p("adb",eM(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new g("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
|
+
${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 g("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 to(e,t,r){let i=await tl(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",eM(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 g("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function ts(e,t,r,i){"grant"===r?await p("adb",eM(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await p("adb",eM(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await p("adb",eM(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await p("adb",eM(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await p("adb",eM(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function tl(e){let t=await p("adb",eM(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 eX(e,r),i>0&&t+n<a.length&&await tg(i)}}function tc(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 tu(e,t){let r=await p("adb",eM(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":tp(r.stdout,r.stderr)?"unsupported":0===(await p("adb",eM(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",eM(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}function tp(e,t){let r=`${e}
|
|
10
|
+
${t}`.toLowerCase();return r.includes("no shell command implementation")||r.includes("unknown command")}async function tf(e,t,r){let i=await p("adb",eM(e,t),{allowFailure:!0});if(tp(i.stdout,i.stderr))throw new g("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new g("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}async function tm(e,t){let r=Math.max(0,t);await p("adb",eM(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",eM(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function th(e,t,r){let i,n=await te(e),a=/<node\b[^>]*>/g,o=null,s=null,l=null;for(;null!==(i=a.exec(n));){let e=eh(i[0]),n=eI(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),c=e.focused??!1;if(!d)continue;let u=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(c&&tw(a)){(!o||u<=o.area)&&(o={text:d,area:u});continue}if(p&&tw(a)){(!s||u<=s.area)&&(s={text:d,area:u});continue}p&&(!l||u<=l.area)&&(l={text:d,area:u})}return o?.text??s?.text??l?.text??null}function tw(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function tg(e){await new Promise(t=>setTimeout(t,e))}function tI(e,t,r){if(!e)return t;let i=Number(e);return Number.isFinite(i)?Math.max(r,Math.floor(i)):t}let tv=tI(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),tA=/^(iphone|ipad|ipod|appletv)/i,ty=/^appletv/i,tS=["apple tv","appletv","tvos"];function tb(e){return(e??"").trim().toLowerCase()}function tN(e){return tb(e.hardwareProperties?.platform)}function t_(e){return e.includes("tvos")}function tD(e){let t=tb(e);return tS.some(e=>t.includes(e))}function tk(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function tE(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function tM(){if("darwin"!==process.platform)throw new g("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await I("xcrun"))throw new g("TOOL_MISSING","xcrun not found in PATH");let e=[],t=await p("xcrun",["simctl","list","devices","-j"]);try{let i=JSON.parse(t.stdout);for(let[t,n]of Object.entries(i.devices))if(function(e){let t=tb(e);return t.includes("ios")||t.includes("tvos")}(t))for(let i of n){var r;i.isAvailable&&e.push({platform:"ios",id:i.udid,name:i.name,kind:"simulator",target:(r=t,t_(tb(r))?"tv":"mobile"),booted:"Booted"===i.state})}}catch(e){throw new g("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}let i=null;try{i=n.join($.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let t=await p("xcrun",["devicectl","list","devices","--json-output",i],{allowFailure:!0,timeoutMs:tv});if(0!==t.exitCode)return e;let r=await O.readFile(i,"utf8"),a=JSON.parse(r);for(let t of a.result?.devices??[])if(function(e){var t;let r=tN(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=tE(e),!!tA.test(t.trim())||tk(e).some(tD))}(t)){let r=t.hardwareProperties?.udid??t.identifier??"",i=t.name??t.deviceProperties?.name??r;if(!r)continue;e.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return t_(tN(e))?"tv":(t=tE(e),ty.test(t.trim())||tk(e).some(tD))?"tv":"mobile"}(t),booted:!0})}}catch{}finally{i&&await O.rm(i,{force:!0}).catch(()=>{})}return e}let tx=tI(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,J,5e3),tO=tI(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,H,1e3),tL=tI(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),tC=tI(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3);async function tR(e,t){let r=["devicectl",...e],i=await p("xcrun",r,{allowFailure:!0,timeoutMs:tC});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new g("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:t$(n,a)??tP})}async function tT(e,t){let r=n.join($.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:tC});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new g("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:i,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:t$(t,r)??tP})}let n=await O.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 g)throw t;throw new g("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await O.unlink(r).catch(()=>{})}}let tP="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function t$(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 tF(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 tG=new Set;function tU(e){return!!e&&tG.has(e)}let tV=Array.from(new Set([process.env.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID,process.env.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID,"com.myapp.AgentDeviceRunnerUITests.xctrunner","com.myapp.AgentDeviceRunner"].map(e=>e?.trim()??"").filter(e=>e.length>0))),tB=new Map,tq=new Map,tj=new Set,tW=tI(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),tH=tI(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),tJ=tI(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),tz=tI(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),tK=tI(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),tX=tI(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),tY=tI(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),tZ=tI(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5),tQ=n.join($.homedir(),".agent-device","ios-runner");async function t0(e,t,r={}){var i;return(function(e){if("ios"!==e.platform)throw new g("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new g("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`)}(e),rl(r.requestId),"snapshot"===(i=t.command)||"screenshot"===i||"findText"===i||"alert"===i)?Y(()=>(rl(r.requestId),t1(e,t,r)),{shouldRetry:e=>(rl(r.requestId),function(e){if(!(e instanceof g)||"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))}):t1(e,t,r)}async function t1(e,t,r={}){let i;rl(r.requestId);try{let n=(i=await re(e,r)).ready?tH:tW;return await t2(e,i,t,r.logPath,n)}catch(a){let n=a instanceof g?a:new g("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 t6(i):await t4(e.id),i=await re(e,r);let n=await rp(i.device,i.port,t,r.logPath,tW);return await t3(n,i,r.logPath)}throw a}}async function t2(e,t,r,i,n){let a=await rp(e,t.port,r,i,n,t);return await t3(a,t,i)}async function t3(e,t,r){let i=await e.text(),n={};try{n=JSON.parse(i)}catch{throw new g("COMMAND_FAILED","Invalid runner response",{text:i})}if(!n.ok)throw new g("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:r});return t.ready=!0,n.data??{}}async function t4(e){await tF(tq,e,async()=>{await t9(e)})}async function t8(){let e=Array.from(tB.values()),t=Array.from(tj);await Promise.allSettled(e.map(async e=>{await rt(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await rt(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await rt(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await rt(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await rt(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await rt(e.pid,"SIGKILL"),tj.delete(e)}))}async function t5(){await t8();let e=Array.from(tB.keys());await Promise.allSettled(e.map(async e=>{await t4(e)})),await ri()}async function t6(e){await tF(tq,e.deviceId,async()=>{await t9(e.deviceId,e)})}async function t9(e,t){let r=t??tB.get(e);if(r){try{await rp(r.device,r.port,{command:"shutdown"},void 0,15e3)}catch{await rt(r.child.pid,"SIGTERM")}try{await Promise.race([r.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await rt(r.child.pid,"SIGKILL"),rv(r.xctestrunPath),rv(r.jsonPath),tB.get(e)===r&&tB.delete(e)}}async function t7(e){await p("xcrun",["simctl","bootstatus",e,"-b"],{allowFailure:!0,timeoutMs:tW})}async function re(e,t){return await tF(tq,e.id,async()=>{var r,i,n;let a,o=tB.get(e.id);if(o){if((r=o.child.pid)&&L(r))return o;await t9(e.id,o)}await ("simulator"!==(i=e).kind?Promise.resolve():t7(i.id));let s=await rr(e,t),l=await rg(),{xctestrunPath:c,jsonPath:u}=await rI(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",ra(e),"1","-destination-timeout",String(tZ),"-xctestrun",c,"-destination",(a=rn(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=>{rs(e,t.logPath,t.traceLogPath,t.verbose)}),p.stderr?.on("data",e=>{rs(e,t.logPath,t.traceLogPath,t.verbose)});let m={device:e,deviceId:e.id,port:l,xctestrunPath:c,jsonPath:u,testPromise:f,child:p,ready:!1};return tB.set(e.id,m),m})}async function rt(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 rr(e,t){var r,i,a;let o,s=(r=e.kind,(o=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?n.resolve(o):"simulator"===r?n.join(tQ,"derived"):n.join(tQ,"derived",r));if(W(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 W(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new g("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(s);try{R.rmSync(s,{recursive:!0,force:!0})}catch{}}let l=ro(s);if(l)return l;let d=function(){let e=n.dirname(A(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}(),c=n.join(d,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!R.existsSync(c))throw new g("COMMAND_FAILED","iOS runner project not found",{projectPath:c});let u=function(e=process.env,t=!1){if(!t)return[];let r=e.AGENT_DEVICE_IOS_TEAM_ID?.trim()||"",i=e.AGENT_DEVICE_IOS_SIGNING_IDENTITY?.trim()||"",n=e.AGENT_DEVICE_IOS_PROVISIONING_PROFILE?.trim()||"",a=["CODE_SIGN_STYLE=Automatic"];return r&&a.push(`DEVELOPMENT_TEAM=${r}`),i&&a.push(`CODE_SIGN_IDENTITY=${i}`),n&&a.push(`PROVISIONING_PROFILE_SPECIFIER=${n}`),a}(process.env,"device"===e.kind),p="device"===e.kind?["-allowProvisioningUpdates"]:[];try{let r;await y("xcodebuild",["build-for-testing","-project",c,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",ra(e),"1","-destination",(i=e,r=rn(i),"simulator"===i.kind?`platform=${r} Simulator,id=${i.id}`:`generic/platform=${r}`),"-derivedDataPath",s,...p,...u],{detached:!0,onSpawn:e=>{tj.add(e),e.on("close",()=>{tj.delete(e)})},onStdoutChunk:e=>{rs(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{rs(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(o){let e,r,i=o instanceof g?o:new g("COMMAND_FAILED",String(o)),n=(e=(a=i).details?JSON.stringify(a.details):"",(r=`${a.message}
|
|
12
|
+
${e}`.toLowerCase()).includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new g("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:i.message,details:i.details,logPath:t.logPath,hint:n})}let f=ro(s);if(!f)throw new g("COMMAND_FAILED","Failed to locate .xctestrun after build");return f}async function ri(){let e=Array.from(tj);await Promise.allSettled(e.map(async e=>{try{await rt(e.pid,"SIGTERM"),await rt(e.pid,"SIGKILL")}finally{tj.delete(e)}}))}function rn(e){if("ios"!==e.platform)throw new g("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"tv"===e.target?"tvOS":"iOS"}function ra(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 rs(e,t,r,i){t&&R.appendFileSync(t,e),r&&R.appendFileSync(r,e),i&&process.stderr.write(e)}function rl(e){if(tU(e))throw new g("COMMAND_FAILED","request canceled")}function rd(e){let{port:t,endpoints:r,logPath:i,lastError:n}=e,a="Runner did not accept connection";return new g("COMMAND_FAILED",a,{port:t,endpoints:r,logPath:i,lastError:n?String(n):void 0,reason:Q({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:ee("IOS_RUNNER_CONNECT_TIMEOUT")})}function rc(e){return!(e instanceof g)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}async function ru(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=Q({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new g("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}
|
|
12
13
|
${t}
|
|
13
|
-
${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":
|
|
14
|
-
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new
|
|
15
|
-
${a}`.toLowerCase()))throw new
|
|
16
|
-
${i.stderr}`.toLowerCase()))throw new
|
|
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.":ee("IOS_RUNNER_CONNECT_TIMEOUT"))})}async function rp(e,t,r,i,n=tW,a){let o=K.fromTimeoutMs(n),s=await rf(e,t,o.remainingMs()),l=null,d=Math.max(1,Math.ceil(n/tJ));try{return await X(async({deadline:o})=>{if(o?.isExpired())throw new g("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await ru({session:a,port:t,logPath:i});for(let i of("device"===e.kind&&(s=await rf(e,t,o?.remainingMs())),s))try{let e=o?.remainingMs()??n;if(e<=0)throw new g("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await rm(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)},Math.min(tX,e))}catch(e){l=e}throw new g("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:s,lastError:l?String(l):void 0})},{maxAttempts:d,baseDelayMs:tz,maxDelayMs:tK,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 rd({port:t,endpoints:s,logPath:i,lastError:l});let a=await rw(e.id,t,r,n);return new Response(a.body,{status:a.status})}throw rd({port:t,endpoints:s,logPath:i,lastError:l})}async function rf(e,t,r){let i=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return i;let n=await rh(e.id,r);return n&&i.unshift(`http://[${n}]:${t}/command`),i}async function rm(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 rh(e,t){if("number"==typeof t&&t<=0)return null;let r="number"==typeof t?Math.max(1,Math.min(tY,t)):tY,i=n.join($.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{rv(i)}}async function rw(e,t,r,i){let n=JSON.stringify(r),a=await p("xcrun",["simctl","spawn",e,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`],{allowFailure:!0,timeoutMs:i}),o=a.stdout;if(0!==a.exitCode){let e=Q({message:"Runner did not accept connection (simctl spawn)",stdout:a.stdout,stderr:a.stderr,context:{platform:"ios",phase:"connect"}});throw new g("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,reason:e,hint:ee(e)})}return{status:200,body:o}}async function rg(){return await new Promise((e,t)=>{let r=F.createServer();r.listen(0,"127.0.0.1",()=>{let i=r.address();r.close(),"object"==typeof i&&i?.port?e(i.port):t(new g("COMMAND_FAILED","Failed to allocate port"))}),r.on("error",t)})}async function rI(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 g("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:d.stderr});try{i=JSON.parse(d.stdout)}catch(t){throw new g("COMMAND_FAILED","Failed to parse xctestrun JSON",{xctestrunPath:e,error:String(t)})}let c=e=>{e.EnvironmentVariables={...e.EnvironmentVariables??{},...t},e.UITestEnvironmentVariables={...e.UITestEnvironmentVariables??{},...t},e.UITargetAppEnvironmentVariables={...e.UITargetAppEnvironmentVariables??{},...t},e.TestingEnvironmentVariables={...e.TestingEnvironmentVariables??{},...t}},u=i.TestConfigurations;if(Array.isArray(u))for(let e of u){if(!e||"object"!=typeof e)continue;let t=e.TestTargets;if(Array.isArray(t))for(let e of t)e&&"object"==typeof e&&c(e)}for(let[e,t]of Object.entries(i))t&&"object"==typeof t&&t.TestBundlePath&&(c(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 g("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:f.stderr});return{xctestrunPath:l,jsonPath:s}}function rv(e){try{R.existsSync(e)&&R.unlinkSync(e)}catch{}}function rA(e,t){if("simulator"!==e.kind)throw new g("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function ry(e){let t,r;if("simulator"!==e.kind||"Booted"===await rS(e.id))return;let i=K.fromTimeoutMs(tx);try{await X(async({deadline:i})=>{if(i?.isExpired())throw new g("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:tx});let n=Math.max(1e3,i?.remainingMs()??tx),a=await p("xcrun",["simctl","boot",e.id],{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
|
|
15
|
+
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new g("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",["simctl","bootstatus",e.id,"-b"],{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new g("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await rS(e.id);if("Booted"!==d)throw new g("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=Q({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=>Q({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=Q({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new g("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:tx,elapsedMs:i.elapsedMs(),reason:n,hint:ee(n),boot:t,bootstatus:r})}}async function rS(e){let t=await p("xcrun",["simctl","list","devices","-j"],{allowFailure:!0,timeoutMs:tO});if(0!==t.exitCode)return null;try{let r=JSON.parse(String(t.stdout??""));for(let t of Object.values(r.devices??{})){let r=t.find(t=>t.udid===e);if(r)return r.state}return null}catch{return null}}let rb={settings:"com.apple.Preferences"},rN=null;function r_(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function rD(e,t){let r=t.trim();if(r.includes("."))return r;let i=rb[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await rG(e):await tT(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new g("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new g("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function rk(e,t,r){let i=r?.url?.trim();if(i){if(!ef(i))throw new g("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await ry(e),await p("open",["-a","Simulator"],{allowFailure:!0}),await p("xcrun",["simctl","openurl",e.id,i]);return}let n=em(r?.appBundleId??await rD(e,t),i);if(!n)throw new g("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await rK(e,n,{payloadUrl:i});return}let n=t.trim();if(ef(n)){if("simulator"===e.kind){await ry(e),await p("open",["-a","Simulator"],{allowFailure:!0}),await p("xcrun",["simctl","openurl",e.id,n]);return}let t=em(r?.appBundleId,n);if(!t)throw new g("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await rK(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await rD(e,t);"simulator"===e.kind?await rz(e,a):await rK(e,a)}async function rE(e){"simulator"!==e.kind||"Booted"!==await rS(e.id)&&(await ry(e),await p("open",["-a","Simulator"],{allowFailure:!0}))}async function rM(e,t){let r=await rD(e,t);if("simulator"===e.kind){await ry(e);let t=await p("xcrun",["simctl","terminate",e.id,r],{allowFailure:!0});if(0!==t.exitCode){if(t.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new g("COMMAND_FAILED",`xcrun exited with code ${t.exitCode}`,{cmd:"xcrun",args:["simctl","terminate",e.id,r],stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode})}return}await tR(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function rx(e,t){let r=await rD(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await p("xcrun",t,{allowFailure:!0,timeoutMs:tC});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!r_(`${n}
|
|
16
|
+
${a}`.toLowerCase()))throw new g("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:t$(n,a)??tP})}return{bundleId:r}}await ry(e);let i=await p("xcrun",["simctl","uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!r_(`${i.stdout}
|
|
17
|
+
${i.stderr}`.toLowerCase()))throw new g("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function rO(e,t){"simulator"!==e.kind?await tR(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await ry(e),await p("xcrun",["simctl","install",e.id,t]))}async function rL(e,t,r){let{bundleId:i}=await rx(e,t);return await rO(e,r),{bundleId:i}}async function rC(e,t,r){if("simulator"===e.kind){await ry(e),await p("xcrun",["simctl","io",e.id,"screenshot",t]);return}try{await tR(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(e){if(!function(e){if(!(e instanceof g)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
17
18
|
${r}
|
|
18
|
-
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(e))throw e}let i=(await
|
|
19
|
-
`,"utf8"),await
|
|
20
|
-
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new
|
|
21
|
-
${r.stderr}`);if(0===i.size)throw new m("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return rg=i,e=t,i}async function rF(e,t){let r=function(e,t){switch(t){case"match":return[["simctl","biometric",e,"match","face"],["simctl","biometric","match",e,"face"]];case"nonmatch":return[["simctl","biometric",e,"nonmatch","face"],["simctl","biometric",e,"nomatch","face"],["simctl","biometric","nonmatch",e,"face"],["simctl","biometric","nomatch",e,"face"]];case"enroll":return[["simctl","biometric",e,"enroll","yes"],["simctl","biometric",e,"enroll","1"],["simctl","biometric","enroll",e,"yes"],["simctl","biometric","enroll",e,"1"]];case"unenroll":return[["simctl","biometric",e,"enroll","no"],["simctl","biometric",e,"enroll","0"],["simctl","biometric","enroll",e,"no"],["simctl","biometric","enroll",e,"0"]]}}(e,t),i=[];for(let e of r){let t=await c("xcrun",e,{allowFailure:!0});if(0===t.exitCode)return;i.push({args:e,stderr:t.stderr,stdout:t.stdout,exitCode:t.exitCode})}throw new m("COMMAND_FAILED","simctl biometric command failed. Ensure your Xcode Simulator runtime supports Face ID control.",{deviceId:e,action:t,attempts:i.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}))})}function rG(e){if(!(e instanceof m)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function rV(e,t){await rm(e),await c("open",["-a","Simulator"],{allowFailure:!0});let r=j.fromTimeoutMs(tD);await q(async({deadline:r})=>{if(r?.isExpired())throw new m("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tD});let i=await c("xcrun",["simctl","launch",e.id,t],{allowFailure:!0});if(0!==i.exitCode)throw new m("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:["simctl","launch",e.id,t],stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:rG},{deadline:r})}async function rU(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tk(i,{action:"launch iOS app",deviceId:e.id})}function rB(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new m("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!E.statSync(a).isFile())throw new m("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof m)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new m("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new m("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new m("INVALID_ARGS",`${i} file not found: ${a}`)}async function rj(e){let t=P(e.platform);return await N("resolve_target_device",async()=>{let r={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(r.target&&!r.platform)throw new m("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===r.platform){await e1();let e=await en();return await $(e,r)}if("ios"===r.platform){let e=await tS();return await $(e,r)}let i=[];try{i.push(...await en())}catch{}try{i.push(...await tS())}catch{}return await $(i,r)},{platform:t,target:e.target})}async function rq(e,t,r,n,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>eM(e,t,r?.activity),openDevice:()=>eC(e),close:t=>eR(e,t),tap:(t,r)=>eF(e,t,r),doubleTap:async(t,r)=>{await eF(e,t,r),await eF(e,t,r)},swipe:(t,r,i,n,a)=>eG(e,t,r,i,n,a),longPress:(t,r,i)=>ej(e,t,r,i),focus:(t,r)=>ez(e,t,r),type:t=>eq(e,t),fill:(t,r,i)=>eH(e,t,r,i),scroll:(t,r)=>eX(e,t,r),scrollIntoView:t=>eY(e,t),screenshot:(t,r)=>eK(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>ry(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rA(e),close:t=>rS(e,t),screenshot:(t,r)=>r_(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(tC(i.requestId))throw new m("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await tz(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await tz(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await tz(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await tz(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await tz(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await tz(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new m("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await tz(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await tz(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await tz(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await tz(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new m("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new m("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return D({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await N("platform_command",async()=>{var s,l,d,c,u,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new m("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new m("INVALID_ARGS","open <app> <url> is supported only on iOS");if(es(t))throw new m("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!es(i))throw new m("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new m("INVALID_ARGS","press requires x y");let n=rJ(a?.count??1,"count",1,200),u=rJ(a?.intervalMs??0,"interval-ms",0,1e4),p=rJ(a?.holdMs??0,"hold-ms",0,1e4),f=rJ(a?.jitterPx??0,"jitter-px",0,100),h=a?.doubleTap===!0;if(h&&p>0)throw new m("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(h&&f>0)throw new m("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,c=f,"ios"===s.platform&&l>1&&0===d&&0===c)return await tz(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:u,doubleTap:h,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:u,holdMs:p,jitterPx:f,doubleTap:h,timingMode:"runner-series"};return await rX(n,u,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=rW[e%rW.length];return[r*t,i*t]}(e,f),a=t+r,s=i+n;h?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:u,holdMs:p,jitterPx:f,doubleTap:h}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new m("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=rJ(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,c=rJ(a?.count??1,"count",1,200),f=rJ(a?.pauseMs??0,"pause-ms",0,1e4),h=a?.pattern??"one-way";if("one-way"!==h&&"ping-pong"!==h)throw new m("INVALID_ARGS",`Invalid pattern: ${h}`);if(u=e,p=c,"ios"===u.platform&&p>1)return await tz(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:c,pauseMs:f,pattern:h,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:c,pauseMs:f,pattern:h};return await rX(c,f,async e=>{"ping-pong"===h&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:c,pauseMs:f,pattern:h}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new m("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new m("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new m("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new m("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new m("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new m("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new m("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new m("INVALID_ARGS","pinch requires scale > 0");return await tz(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"screenshot":{let e=r[0]??n??`./screenshot-${Date.now()}.png`;return await _.mkdir(i.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await tz(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await eV(e),{action:"back"};case"home":if("ios"===e.platform)return await tz(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await eU(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await tz(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await eB(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new m("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new m("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await rk(e):await eW(e)}}if(r.length<2)throw new m("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await rx(e,i):await eJ(e,i),{action:t,textLength:Array.from(i).length}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(D({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await rE(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await eZ(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new m("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await rz(i);if("ios"===e.platform)return await rO(e,t,n),{platform:"ios",bundleId:t};let a=await eQ(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await N("snapshot_capture",async()=>await tz(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new m("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await N("snapshot_capture",async()=>await e0(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new m("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let rW=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function rJ(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new m("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function rz(e){let t=rB(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await rH(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new m("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof m)throw t;throw new m("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function rH(e){try{return await _.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new m("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new m("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new m("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new m("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function rX(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await rY(t)}async function rY(e){await new Promise(t=>setTimeout(t,e))}let rK={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function rZ(e,t){let r=rK[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function rQ(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function r0(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let r1=/^-?\d+(\.\d+)?$/,r2=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),r3=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function r4(e){return"click"===e||"press"===e}function r5(e){let t=e.trim();return t.startsWith("@")||r1.test(t)?t:JSON.stringify(t)}function r8(e,t){let r=t.flags??{};if(r4(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function r6(e,t){let r=[],i={},n=r4(e)?r2:"swipe"===e?r3:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(r4(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class r9{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=r9.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:v,doubleTap:I,pauseMs:y,pattern:A}}(t.flags),result:t.result}),D({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=i.dirname(t);E.existsSync(r)||E.mkdirSync(r,{recursive:!0});let n=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(r4(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(r5(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(r5(i)),r8(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(r5(r)),r8(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(r5(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(r5(i)),n&&t.push(r5(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(r5(r)),t.push(r5(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(r5(r))}return t.join(" ")}}if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",r5(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(r5(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(r5(r));return r8(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
22
|
-
`}(e,this.buildOptimizedActions(e));E.writeFileSync(t,n)}catch{}}defaultTracePath(e){let t=r9.safeSessionName(e.name),r=new Date().toISOString().replace(/[:.]/g,"-");return i.join(this.sessionsDir,`${t}-${r}.trace.log`)}resolveAppLogPath(e){return i.join(this.sessionsDir,r9.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return i.join(this.sessionsDir,r9.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?i.join(C.homedir(),e.slice(2)):t&&!i.isAbsolute(e)?i.resolve(t,e):i.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return r9.expandHome(e.saveScriptPath);E.existsSync(this.sessionsDir)||E.mkdirSync(this.sessionsDir,{recursive:!0});let t=r9.safeSessionName(e.name),r=new Date(e.createdAt).toISOString().replace(/[:.]/g,"-");return i.join(this.sessionsDir,`${t}-${r}.ad`)}buildOptimizedActions(e){let t=[];for(let r of e.actions){if("snapshot"===r.command)continue;let i=Array.isArray(r.result?.selectorChain)&&r.result?.selectorChain.every(e=>"string"==typeof e)?r.result.selectorChain:[];if(i.length>0&&(r4(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(r4(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=rQ(r);if(i.length>0){t.push({...r,positionals:[e,i]});continue}}if("get"===r.command){let i=r.positionals?.[0];if("text"===i||"attrs"===i){t.push({...r,positionals:[i,e]});continue}}}if(r4(r.command)||"fill"===r.command||"get"===r.command){let i=r.result?.refLabel;"string"==typeof i&&i.trim().length>0&&t.push({ts:r.ts,command:"snapshot",positionals:[],flags:{platform:e.device.platform,snapshotInteractiveOnly:!0,snapshotCompact:!0,snapshotScope:i.trim()},result:{scope:i.trim()}})}t.push(r)}return t}}function r7(e,t,r,i,n){return{requestId:n??b().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let ie=tu(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function it(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:rm}));await t(e);return}if("device"===e.kind)return void await ir(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:eo}));await t(e.id)}}async function ir(e){let t=i.join(C.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(ie/1e3));try{let i=await c("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:ie+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await ii(t);if(0===i.exitCode){if(!o.parsed)throw new m("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new m("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new m("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:ia(n,a)})}catch(t){if(t instanceof m&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??ie),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new m("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?ia(i,n):o},t)}throw new m("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await _.rm(t,{force:!0}).catch(()=>{})}}async function ii(e){try{let t=await _.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function ia(e,t){let r=tE(e,t);return r||(`${e}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`)},flush:()=>{i&&(n(i),i="")}}}function iz(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function iH(e,t){let r=(await c("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function iX(e,t,r,i){let n="active",a=p("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=iJ(t,{redactionPatterns:r});"number"==typeof a.pid&&iU(i,a.pid);let s=iz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iB(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iq(s),a.killed||a.kill("SIGKILL"),await iq(s),iB(i)}}}async function iY(e,t,r,i){let n="active",a=p("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=iJ(t,{redactionPatterns:r});"number"==typeof a.pid&&iU(i,a.pid);let s=iz(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iB(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iq(s),a.killed||a.kill("SIGKILL"),await iq(s),iB(i)}}}async function iK(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await iH(e,t);if(!d){await iW(1e3);continue}let c=p("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=c;let u=iJ(r,{redactionPatterns:i});o=iz(c,r,{endStreamOnClose:!1,writer:u}),"number"==typeof c.pid&&iU(n,c.pid);let f=await o;if(iB(n),a=void 0,o=void 0,l)break;0!==f.exitCode&&(s="failed"),await iW(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),iB(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await iq(o),a&&!a.killed&&a.kill("SIGKILL"),await iq(d),iB(n)}}}async function iZ(e,t,r,i){ij(r);let n=E.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await iY(e.id,n,a,i):await iX(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new m("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await iK(e.id,t,n,a,i)}throw n.end(),new m("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function iQ(e){await e.stop(),await iq(e.wait)}async function i0(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await c("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await c("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await c("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await c("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function i1(e){let t=i.dirname(e),r=i.basename(e);E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),E.existsSync(e)?E.truncateSync(e,0):E.writeFileSync(e,"","utf8");let n=0;for(let e of E.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{E.unlinkSync(i.join(t,e)),n+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:n}}let i2=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),i3=/https?:\/\/[^\s"'<>\])]+/i,i4=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function i5(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function i8(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return i6(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function i6(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function i9(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function i7(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let ne='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nt=["platform","target","device","udid","serial","verbose","out"],nr=["platform","target","device","udid","serial","verbose","out"],ni=["path","start","stop","doctor","mark","clear"],nn=`logs requires ${ni.slice(0,-1).join(", ")}, or ${ni.at(-1)}`,na="Not implemented for this platform in this release.",no="open-command-roundtrip";function ns(e){let{sessionName:t,appName:r,appBundleId:i,startup:n}=e,a={session:t};return r&&(a.appName=r),i&&(a.appBundleId=i),n&&(a.startup=n),a}function nl(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:no,appTarget:t,appBundleId:r}}let nd=["dump","log"],nc=`network requires ${nd.join(" or ")}`,nu=["summary","headers","body","all"],np=`network include mode must be one of: ${nu.join(", ")}`;function nf(e,t,r){return t||nm(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nm(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nh(e){let t=nm(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}let nw={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:rD}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e$}));return await i(e,t,r)}};async function ng(e,t,r){if("ios"===e.platform&&t)return es(t)?"device"===e.kind?el(r,t):void 0:await nv(e,t)}async function nv(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rI}));return await r(e,t)}catch{return}}async function nI(e,t){if(!("android"!==e.platform||!t||es(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eN})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function ny(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=P(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=nf("appstate",o,s);if(d)return d;let c=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nm(e))return!0;let r=P(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:ne}};if(c){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let u=await nh({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===u.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:ne}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eO})),f=await p(u);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function nA(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},c=nf("clipboard",l,d);if(c)return c;let u=(t.positionals?.[0]??"").toLowerCase();if("read"!==u&&"write"!==u)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nh({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!rZ("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...r7(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function nS(e){var t;let{req:r,sessionName:i,logPath:n,sessionStore:a,invoke:o,dispatch:s,ensureReady:l,resolveTargetDevice:d,reinstallOps:c=nw,stopIosRunner:u,appLogOps:p={start:iZ,stop:iQ},resolveAndroidPackageForOpen:h=nI}=e,w=s??rq,g=l??it,v=d??rj,I=r.command;if("session_list"===I)return{ok:!0,data:{sessions:a.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===I)try{let e=[],t=P(r.flags?.platform);if("android"===t){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:en}));e.push(...await t())}else if("ios"===t){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tS}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:en})),{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:tS}));try{e.push(...await t())}catch{}try{e.push(...await r())}catch{}}let i=r.flags?.target?e.filter(e=>(e.target??"mobile")===r.flags?.target):e;return{ok:!0,data:{devices:i}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===I){let e=a.get(i),t=r.flags??{},n=nf(I,e,t);if(n)return n;let o=await nh({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});if(!rZ("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=r.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:rM}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:eD}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===I){let e=a.get(i),t=r.flags??{},n=nf(I,e,t);if(n)return n;let o=await nh({session:e,flags:t,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});return rZ("boot",o)?{ok:!0,data:{platform:o.platform,target:o.target??"mobile",device:o.name,id:o.id,kind:o.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===I)return await ny({req:r,sessionName:i,sessionStore:a,ensureReady:g,resolveDevice:v});if("clipboard"===I)return await nA({req:r,sessionName:i,logPath:n,sessionStore:a,ensureReady:g,resolveDevice:v,dispatch:w});if("perf"===I){let e,t,r,n=a.get(i);return n?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===no&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:no,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(n.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:no,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:no},{session:n.name,platform:n.device.platform,device:n.device.name,deviceId:n.device.id,metrics:{startup:r,fps:{available:!1,reason:na},memory:{available:!1,reason:na},cpu:{available:!1,reason:na}},sampling:{startup:{method:no,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("reinstall"===I){let e,t=a.get(i),n=r.flags??{},o=nf(I,t,n);if(o)return o;let s=r.positionals?.[0]?.trim(),l=r.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let d=r9.expandHome(l);if(!E.existsSync(d))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${d}`}};let u=await nh({session:t,flags:n,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!1});if(!rZ("reinstall",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===u.platform){let t=await c.ios(u,s,d);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await c.android(u,s,d);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:d,...e};return t&&a.recordAction(t,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:p}),{ok:!0,data:p}}if("push"===I){let e,t=a.get(i),o=r.flags??{},s=nf(I,t,o);if(s)return s;let l=r.positionals?.[0]?.trim(),d=r.positionals?.[1]?.trim();if(!l||!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let c="file"===(e=rB(d,{subject:"Push payload",cwd:r.meta?.cwd,expandPath:(e,t)=>r9.expandHome(e,t)})).kind?e.path:e.text,u=await nh({session:t,flags:o,ensureReadyFn:g,resolveTargetDeviceFn:v,ensureReady:!0});if(!rZ("push",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"push is not supported on this device"}};let p=await w(u,"push",[l,c],r.flags?.out,{...r7(n,r.flags,t?.appBundleId,t?.trace?.outPath)});return t&&a.recordAction(t,{command:I,positionals:[l,d],flags:r.flags??{},result:p??{}}),{ok:!0,data:p??{}}}if("open"===I){let e=r.flags?.relaunch===!0;if(a.has(i)){let o=a.get(i),s=r.positionals?.[0],l=s??(e?o?.appName:void 0);if(!o||!l)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&es(l))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await g(o.device);let d=await ng(o.device,l,o.appBundleId)??await h(o.device,l)??((t=o.device,"android"===t.platform&&l&&es(l))?o.appBundleId:void 0),c=s?r.positionals??[]:[l];if(e){let e=d??l;await w(o.device,"close",[e],r.flags?.out,{...r7(n,r.flags,d??o.appBundleId,o.trace?.outPath)})}let u=Date.now();await w(o.device,"open",c,r.flags?.out,{...r7(n,r.flags,d)});let p=nl(u,l,d),f={...o,appBundleId:d,appName:l,recordSession:o.recordSession||!!r.flags?.saveScript,snapshot:void 0},m=ns({sessionName:i,appName:l,appBundleId:d,startup:p});return a.recordAction(f,{command:I,positionals:c,flags:r.flags??{},result:m}),a.set(i,f),{ok:!0,data:m}}let o=r.positionals?.[0];if(e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&o&&es(o))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let s=await v(r.flags??{}),l=a.toArray().find(e=>e.device.id===s.id);if(l)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${l.name}".`,details:{session:l.name,deviceId:s.id,deviceName:s.name}}};await g(s);let d=await ng(s,o)??await h(s,o);if(e&&o){let e=d??o;await w(s,"close",[e],r.flags?.out,{...r7(n,r.flags,d)})}let c=Date.now();await w(s,"open",r.positionals??[],r.flags?.out,{...r7(n,r.flags,d)});let u=o?nl(c,o,d):void 0,p={name:i,device:s,createdAt:Date.now(),appBundleId:d,appName:o,recordSession:!!r.flags?.saveScript,actions:[]},f=ns({sessionName:i,appName:o,appBundleId:d,startup:u});return a.recordAction(p,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:f}),a.set(i,p),{ok:!0,data:f}}if("replay"===I){let e=r.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=r9.expandHome(e,r.meta?.cwd),s=E.readFileSync(t,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new m("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(r4(i)){let e=r6(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return nE(r)&&nE(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=r6(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),c=r.flags?.replayUpdate===!0,u=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await o({token:r.token,session:i,command:s.command,positionals:s.positionals??[],flags:n_(r.flags,s.flags),meta:r.meta});if(l.ok)continue;if(!c)return nD(l,s,e,t);let p=await nk({action:s,sessionName:i,logPath:n,sessionStore:a,dispatch:w});if(!p)return nD(l,s,e,t);if(d[e]=p,!(l=await o({token:r.token,session:i,command:p.command,positionals:p.positionals??[],flags:n_(r.flags,p.flags),meta:r.meta})).ok)return nD(l,p,e,t);u+=1}if(c&&u>0){let e=a.get(i);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",r5(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(r5(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(r5(r));return r8(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
26
|
-
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;E.writeFileSync(a,n),E.renameSync(a,e)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:u,session:i}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===I){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(r.positionals?.[0]??"path").toLowerCase(),n=!!r.flags?.restart;if(!ni.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:nn}};if(n&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=a.resolveAppLogPath(i),r=function(e){if(!E.existsSync(e))return{exists:!1,sizeBytes:0};let t=E.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),n=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:n,sizeBytes:r.sizeBytes,modifiedAt:r.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===t){let t=a.resolveAppLogPath(i),r=await i0(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:r.checks,notes:r.notes}}}if("mark"===t){let e,t=r.positionals?.slice(1).join(" ")??"",n=a.resolveAppLogPath(i);return ij(n),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
|
|
27
|
-
`,E.appendFileSync(n,e,"utf8"),{ok:!0,data:{path:n,marked:!0}}}if("clear"===t){if(e.appLog&&!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(n){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!rZ("logs",e.device))return{ok:!1,error:y(new m("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=a.resolveAppLogPath(i);if(n){e.appLog&&await p.stop(e.appLog);let r=i1(t),n=a.resolveAppLogPidPath(i);try{let o=await p.start(e.device,e.appBundleId,t,n),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return a.set(i,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=y(r);return a.set(i,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:i1(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!rZ("logs",e.device))return{ok:!1,error:y(new m("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=a.resolveAppLogPath(i),r=a.resolveAppLogPidPath(i);try{let n=await p.start(e.device,e.appBundleId,t,r),o={...e,appLog:{platform:e.device.platform,backend:n.backend,outPath:t,startedAt:n.startedAt,getState:n.getState,stop:n.stop,wait:n.wait}};return a.set(i,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:y(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await p.stop(e.appLog),a.set(i,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===I){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(r.positionals?.[0]??"dump").toLowerCase();if(!nd.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:nc}};let n=r.positionals?.[1],o=n?Number.parseInt(n,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(r.positionals?.[2]??"summary").toLowerCase();if(!nu.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:np}};let l=function(e,t){let r=i7(t?.maxEntries,25,1,200),i=t?.include??"summary",n=i7(t?.maxPayloadChars,2048,64,16384),a=i7(t?.maxScanLines,4e3,100,2e4);if(!E.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=E.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=i5(n,["method","httpMethod"]),o=i5(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=i2.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),c=(a??d?.[1]??l?.[1])?.toUpperCase(),u=i3.exec(e),p=o??u?.[0];if(!p)return null;let f={method:c,url:p,status:s??function(e){for(let t of i4){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:i9(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return i6(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=i9(t,i))}if("body"===r||"all"===r){let t=i8(e,n,["requestBody","body","payload","request"]),r=i8(e,n,["responseBody","response"]);t&&(f.requestBody=i9(t,i)),r&&(f.responseBody=i9(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(a.resolveAppLogPath(i),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),c=[];return e.appLog||c.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&c.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:c}}}if("batch"===I)return await nb(r,i,o);if("close"===I){let e=a.get(i);return e?(e.appLog&&await p.stop(e.appLog),r.positionals&&r.positionals.length>0&&await w(e.device,"close",r.positionals??[],r.flags?.out,{...r7(n,r.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??tK)(e.device.id),a.recordAction(e,{command:I,positionals:r.positionals??[],flags:r.flags??{},result:{session:i}}),r.flags?.saveScript&&(e.recordSession=!0),a.writeSessionLog(e),a.delete(i),{ok:!0,data:{session:i}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function nb(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??k;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=a(e.flags?.batchSteps,n),o=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await nN(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-o,results:s}}}catch(t){let e=f(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function nN(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of nt)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function nD(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>r5(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function n_(e,t){let r={...t??{}},i=e??{};for(let e of nr)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function nk(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(r4(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=r4(t.command)||"fill"===t.command,l=r4(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await nx(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),r4(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=ik(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=nO(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return r0(t).filter(e=>e.trim().length>0)}(t)){let r=iS(e);if(!r)continue;let i=ib(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=iE(i.node,o.device.platform,{action:r4(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(r4(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=rQ(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=ik(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=nO(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let c=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=iS(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(ih(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=ig(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(ih(e.type??"")))});if(0===s.length||1!==r0(s.map(e=>ig(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=iE(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return c||null}async function nx(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...r7(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:io(t.flags?.snapshotRaw?s:im(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function nO(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=i_(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function nE(e){return!!e&&!Number.isNaN(Number(e))}function nM(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function nL(e,t){let r=I(e.type??"Element"),i=u(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function nC(e,t){return t.flatten?e.map(e=>({text:T(e,0,!1),comparable:nL(e,0)})):w(e).map(e=>({text:e.text,comparable:nL(e.node,e.depth)}))}function nR(e,t){return e.get(t)??0}async function nT(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??rq,o=t.command;if("snapshot"===o){let{session:e,device:o}=await nF(n,r,t.flags);if(!rZ("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=n$(t.flags?.snapshotScope,e);return s.ok?await nG(e,o,async()=>{let l=e?.appBundleId,d=await nP({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),c=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return nV(n,c,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,c),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:c.appBundleId?c.appName??c.appBundleId:void 0,appBundleId:c.appBundleId}}}):s.response}if("diff"===o){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await nF(n,r,t.flags);if(!rZ("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=n$(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await nG(e,o,async()=>{let d=e?.appBundleId,c=(await nP({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return nC(e,t).length}(c.nodes,{flatten:l}),a=e?{...e,snapshot:c}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:c,actions:[]};return nV(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let u=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&nR(a,n-1)<nR(a,n+1)?nR(a,n+1):nR(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&nR(n,l-1)<nR(n,l+1)?l+1:l-1,c=nR(n,d),u=c-d;for(;o>c&&s>u;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===c?(a.push({kind:"added",text:r[u].text}),s=u):(a.push({kind:"removed",text:t[c].text}),o=c)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(nC(e,r),nC(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,c.nodes,{flatten:l}),p={...e,snapshot:c};return nV(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:u.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:u.summary,lines:u.lines}}})}if("wait"===o){let{session:e,device:o}=await nF(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=nM(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=nM(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=nM(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=nM(e[e.length-1]),i=i_(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=iS(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),nV(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):rZ("wait",o)?await nG(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...r7(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),c=l?.nodes??[],u=io(t.flags?.snapshotRaw?c:im(c));e&&(e.snapshot={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=iN(u,s.selector,{platform:o.platform});if(p)return nV(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=is(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=il(e.snapshot.nodes,t),i=r?iu(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let c=d??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===o.platform){let r=await tz(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return nV(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}}}else if("android"===o.platform&&ic(io((await e0(o,{scope:l})).nodes??[]),l))return nV(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===o){let{session:e,device:a}=await nF(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return rZ("alert",a)?await nG(e,a,async()=>{if("wait"===o){let r=nM(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await tz(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return nV(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r=await tz(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return nV(n,e,t,r),{ok:!0,data:r}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:l}};let{session:s,device:d}=await nF(n,r,t.flags);return rZ("settings",d)?await nG(s,d,async()=>{let r=s?.appBundleId,l="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],c=await rq(d,"settings",l,t.flags?.out,{...r7(i,t.flags,r,s?.trace?.outPath)});return nV(n,s,t,c??{setting:e,state:a}),{ok:!0,data:c??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function nP(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...r7(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:io(n.flags?.snapshotRaw?l:im(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function n$(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=is(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=il(t.snapshot.nodes,r),n=i?iu(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function nF(e,t,r){let i=e.get(t),n=i?.device??await rj(r??{});return i||await it(n),{session:i,device:n}}async function nG(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await tK(t.id)}}function nV(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function nU(e,t,r,i={}){let n=nj(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return nB(e.label,r);case"value":return nB(e.value,r);case"id":return nB(e.identifier,r);default:return Math.max(nB(e.label,r),nB(e.value,r),nB(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function nB(e,t){let r=nj(e??"");return r?r===t?2:+!!r.includes(t):0}function nj(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function nq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:c,value:u,timeoutMs:p}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new m("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:nM(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new m("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=f?.device??await rj(t.flags??{});f||await it(h);let w=f?.appBundleId,g="role"!==l?d:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,I=0,y=null,A=async()=>{let e=Date.now();if(y&&e-I<750)return{nodes:y};let a=await rq(h,"snapshot",[],t.flags?.out,{...r7(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,f?.trace?.outPath)}),o=a?.nodes??[],s=io(t.flags?.snapshotRaw?o:im(o));return I=e,y=s,f&&(f.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,f)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await A();if(nU(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:S}=await A(),b=nU(S,l,d,{requireRect:v});if(v&&b.matches.length>1){let e=b.matches.slice(0,8).map(e=>{let t=ig(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${b.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:b.matches.length,candidates:e}}}}let N=b.matches[0]??null;if(!N)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let D="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(S,N)??N:N,_=`@${D.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=ig(N);return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"get text",text:e}}),{ok:!0,data:{ref:_,text:e,node:N}}}if("get_attrs"===c)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"get attrs"}}),{ok:!0,data:{ref:_,node:N}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[_],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"click"}}),e}if("fill"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[_,u],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"fill"}}),e}if("focus"===c){let e=N.rect?id(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await rq(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"focus"}}),{ok:!0,data:r??{ref:_}}}if("type"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=N.rect?id(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await rq(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await rq(h,"type",[u],t.flags?.out,{...r7(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:_,action:"type"}}),{ok:!0,data:r??{ref:_}}}return null}function nW(e){return e instanceof Error?e.message:String(e)}function nJ(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function nz(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function nH(e){let{req:t,sessionName:r,sessionStore:n,logPath:a}=e,o=e.deps??{runCmd:c,runCmdBackground:s,runIosRunnerCommand:tz},l=t.command;if("record"===l){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let s=n.get(r),c=s?.device??await rj(t.flags??{});s||await it(c);let p=s??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let s=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!rZ("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?nJ(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=r9.expandHome(s,t.meta?.cwd);E.mkdirSync(i.dirname(m),{recursive:!0});let h=nz(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,i=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await i()}catch(e){if(!nW(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nW(e)}`}};{var d,u;D({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:nW(e)}});let t=(d=c.id,u=p.name,n.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===d&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},h)}catch{}try{await i()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nW(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",["simctl","io",c.id,"recordVideo",m],{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:r}}return n.set(r,p),n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:s}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=nJ(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},nz(t,a,p))}catch(e){D({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:nW(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of tR)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return n.recordAction(p,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===l){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=n.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??n.defaultTracePath(a),r=r9.expandHome(e);return E.mkdirSync(i.dirname(r),{recursive:!0}),E.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},n.recordAction(a,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=r9.expandHome(t.positionals[1]);E.mkdirSync(i.dirname(e),{recursive:!0}),E.existsSync(o)?E.renameSync(o,e):E.appendFileSync(e,""),o=e}return a.trace=void 0,n.recordAction(a,{command:l,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function nX(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function nY(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function nK(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function nZ(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??rq,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!rZ("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=n1("press",t.flags);if(r)return r;let s=n2({session:e,refInput:d,fallbackLabel:t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!s.ok)return s.response;let{ref:c,node:u,snapshotNodes:p}=s.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has no bounds`}};let f=iu(u,p),m=iE(u,e.device.platform,{action:l}),{x:h,y:w}=id(u.rect),g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:h,y:w,refLabel:f,selectorChain:m}}),{ok:!0,data:{...g??{},ref:c,x:h,y:w}}}let c=(t.positionals??[]).join(" ").trim();if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let u=iA(c),p=await nQ(e,t.flags,i,n,{interactiveOnly:!0},a),f=await N("selector_resolve",()=>ib(p.nodes,u,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(u,f?.diagnostics??[],{unique:!0})}};let{x:m,y:h}=id(f.node.rect),w=await a(e.device,"press",[String(m),String(h)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=iE(f.node,e.device.platform,{action:l}),v=iu(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:m,y:h,selector:f.selector.raw,selectorChain:g,refLabel:v}}),{ok:!0,data:{...w??{},selector:f.selector.raw,x:m,y:h}}}if("fill"===o){let e=i.get(r);if(e&&!rZ("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=n1("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=n2({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=u.type??"",m=f&&!iw(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iu(u,p),w=iE(u,e.device.platform,{action:"fill"}),{x:g,y:v}=id(u.rect),I={...await a(e.device,"fill",[String(g),String(v),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:c,x:g,y:v}};return m&&(I.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...I,refLabel:h,selectorChain:w}}),{ok:!0,data:I}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=i_(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=iA(s.selectorExpression),d=await nQ(e,t.flags,i,n,{interactiveOnly:!0},a),c=await N("selector_resolve",()=>ib(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(l,c?.diagnostics??[],{unique:!0})}};let u=c.node,p=u.type??"",f=p&&!iw(p,e.device.platform)?`fill target ${c.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=id(c.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=iE(u,e.device.platform,{action:"fill"}),v={...w??{x:m,y:h,text:r},selector:c.selector.raw,selectorChain:g,refLabel:iu(u,d.nodes)};return f&&(v.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:v}),{ok:!0,data:v}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!rZ("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=n1("get",t.flags);if(r)return r;let n=n2({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,c=iE(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:c}}),{ok:!0,data:{ref:a,node:d}};let u=ig(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:u,refLabel:u||void 0,selectorChain:c}}),{ok:!0,data:{ref:a,text:u,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let c=iA(d),u=await nQ(s,t.flags,i,n,{interactiveOnly:!1},a),p=await N("selector_resolve",()=>ib(u.nodes,c,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(c,[],{unique:!0})}};let f=p.node,m=iE(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=ig(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!rZ("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=ik(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let c=iA(l.selectorExpression),u=await nQ(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=iN(u.nodes,c,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:c.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:iD(c,[],{unique:!1})}}}let p=await N("selector_resolve",()=>ib(u.nodes,c,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iD(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=ig(r),o=!1;switch(t){case"visible":o=ix(r);break;case"hidden":o=!ix(r);break;case"editable":o=iO(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:ix(r),editable:iO(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:c.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!rZ("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=n1("scrollintoview",t.flags);if(l)return l;let d=n2({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=id(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=nY(n.map(e=>e.rect).filter(e=>nX(e,r.x,r.y)));if(a)return a;let o=nY(n.map(e=>e.rect));if(o)return o;let s=nY(i.map(e=>e.rect).filter(e=>nX(e,r.x,r.y)));return s||null}(p,u.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,c=o+.25*n,u=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=c&&f<=u)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),v=Math.max(1,Math.abs(w-g));return f>u?{x:h,startY:w,endY:g,count:nK(Math.ceil((f-u)/v),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:nK(Math.ceil((c-f)/v),1,50),direction:"up"}}(u.rect,f),h=iu(u,p),w=iE(u,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:c,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:c,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:c,attempts:m.count,direction:m.direction}}}return null}async function nQ(e,t,r,i,n,a=rq){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:io(t?.snapshotRaw?s:im(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let n0=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function n1(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of n0)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function n2(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=is(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=il(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=ic(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}let n3=i.join(C.homedir(),".agent-device"),n4=i.join(n3,"daemon.json"),n5=i.join(n3,"daemon.lock"),n8=i.join(n3,"daemon.log"),n6=i.join(n3,"sessions");var n9=n6;if(E.existsSync(n9))for(let e of E.readdirSync(n9,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=i.join(n9,e.name,"app-log.pid");if(E.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}(E.readFileSync(t,"utf8"));if(e&&function(e){let t,r=O(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=n(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{iB(t)}}let n7=new r9(n6),ae=A(),at=d.randomBytes(24).toString("hex"),ar=new Set(["session_list","devices"]),ai=O(process.pid)??void 0,an=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=E.statSync(e),r=S(),n=i.relative(r,e)||e;return`${n}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function aa(e,t,r){let i=b().requestId;return{...r7(n8,e,t,r,i),requestId:i}}async function ao(e){let t=!!(e.meta?.debug||e.flags?.verbose);return await M({session:e.session,requestId:e.meta?.requestId,command:e.command,debug:t,logPath:n8},async()=>{if(e.token!==at)return{ok:!1,error:y(new m("UNAUTHORIZED","Invalid token"))};D({level:"info",phase:"request_start",data:{session:e.session,command:e.command}});try{var t;let r=(t=e,"click"!==t.command?t:{...t,command:"press"}),i=r.command,n=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(r,n7),a=n7.get(n);a&&!ar.has(i)&&function(e,t){if(!t)return;let r=[],i=e.device,n=P(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),0!==r.length){var a;let t,i,n;throw new m("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(a,r.flags);let o=await nS({req:r,sessionName:n,logPath:n8,sessionStore:n7,invoke:ao});if(o)return as(o);let s=await nT({req:r,sessionName:n,logPath:n8,sessionStore:n7});if(s)return as(s);let l=await nH({req:e,sessionName:n,sessionStore:n7,logPath:n8});if(l)return as(l);let d=await nq({req:r,sessionName:n,logPath:n8,sessionStore:n7,invoke:ao});if(d)return as(d);let c=await nZ({req:r,sessionName:n,sessionStore:n7,contextFromFlags:aa});if(c)return as(c);let u=n7.get(n);if(!u)return as({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!rZ(i,u.device))return as({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${i} is not supported on this device`}});let p=await rq(u.device,i,r.positionals??[],r.flags?.out,{...aa(r.flags,u.appBundleId,u.trace?.outPath)});return n7.recordAction(u,{command:i,positionals:r.positionals??[],flags:r.flags??{},result:p??{}}),as({ok:!0,data:p??{}})}catch(r){D({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=b(),t=L({force:!0})??void 0;return{ok:!1,error:y(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function as(e){let t=b();if(!e.ok){D({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=L({force:!0})??void 0;return{ok:!1,error:y(new m(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return D({level:"info",phase:"request_success"}),L(),e}function al(){if(!E.existsSync(n5))return null;try{let e=JSON.parse(E.readFileSync(n5,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}!function(){if(!function(){E.existsSync(n3)||E.mkdirSync(n3,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:ae,startedAt:Date.now(),processStartTime:ai},null,2),t=()=>{try{return E.writeFileSync(n5,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=al();if(r?.pid&&r.pid!==process.pid&&o(r.pid,r.processStartTime))return!1;try{E.unlinkSync(n5)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let e=R.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&tL.add(e);D({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await tZ(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(i.add(s),tC(s)))throw new m("COMMAND_FAILED","request canceled");n=await ao(e)}catch(e){n={ok:!1,error:y(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&tL.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
28
|
-
`),a=t.indexOf("\n")}})});e.listen(0,"127.0.0.1",()=>{let t=e.address();if("object"==typeof t&&t?.port){var r;r=t.port,E.existsSync(n3)||E.mkdirSync(n3,{recursive:!0}),E.writeFileSync(n8,""),E.writeFileSync(n4,JSON.stringify({port:r,token:at,pid:process.pid,version:ae,codeSignature:an,processStartTime:ai},null,2),{mode:384}),process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${t.port}
|
|
29
|
-
`)}});
|
|
30
|
-
`),
|
|
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 t0(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new g("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");let n={exitCode:1,stdout:"",stderr:""};for(let r of tV)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 g("COMMAND_FAILED",`Failed to capture iOS screenshot: ${e}`)}}async function rR(e){rA(e,"clipboard"),await ry(e);let t=await p("xcrun",["simctl","pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new g("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 rT(e,t){rA(e,"clipboard"),await ry(e);let r=await p("xcrun",["simctl","pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new g("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function rP(e,t,r){rA(e,"push"),await ry(e);let i=await O.mkdtemp(n.join($.tmpdir(),"agent-device-ios-push-")),a=n.join(i,"payload.apns");try{await O.writeFile(a,`${JSON.stringify(r)}
|
|
20
|
+
`,"utf8"),await p("xcrun",["simctl","push",e.id,t,a])}finally{await O.rm(i,{recursive:!0,force:!0})}}async function r$(e,t,r,i,n){rA(e,"settings"),await ry(e);let a=t.toLowerCase();switch(a){case"wifi":{let t=rU(r);await p("xcrun",["simctl","status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(rU(r)?await p("xcrun",["simctl","status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await p("xcrun",["simctl","status_bar",e.id,"clear"]));case"location":{let t=rU(r);if(!i)throw new g("INVALID_ARGS","location setting requires an active app in session");await p("xcrun",["simctl","privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":case"touchid":{let t=rB[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 g("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r,a);await rH(e.id,i,{settingName:a,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await rV(e.id,r);await p("xcrun",["simctl","ui",e.id,"appearance",t]);return}case"permission":{var o;if(!i)throw new g("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(o=eS(r))?"revoke":o,a=function(e,t){let r=eb(e);if("photos"!==r&&t?.trim())throw new g("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 g("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new g("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 rq(e.id,t,a,i);return}default:throw new g("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function rF(e,t="all"){var r;return"simulator"===e.kind?(r=await rG(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await tT(e,t)}async function rG(e){let t=(await p("xcrun",["simctl","listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let r=null;if(t.startsWith("{"))try{r=JSON.parse(t)}catch{r=null}if(!r&&t.startsWith("{"))try{let e=await 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 rU(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 g("INVALID_ARGS",`Invalid setting state: ${e}`)}async function rV(e,t){let r=eN(t);if("toggle"!==r)return r;let i=await p("xcrun",["simctl","ui",e,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new g("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 g("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let rB={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function rq(e,t,r,i){let n=await rW();if(!n.has(r))throw new g("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["simctl","privacy",e,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await p("xcrun",a);return}catch(t){if(!(o&&rj(t)))throw t;throw new g("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await p("xcrun",a);return}catch(e){if(!rj(e))throw e}try{await p("xcrun",["simctl","privacy",e,"reset","all",i])}catch(t){throw new g("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function rj(e){if(!(e instanceof g)||"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 rW(){let t=process.env.PATH;if(rN&&e===t)return rN;let r=await p("xcrun",["simctl","privacy","help"],{allowFailure:!0}),i=function(e){let t=new Set,r=!1;for(let i of e.split("\n")){let e=i.trim();if(!e)continue;if("service"===e){r=!0;continue}if(!r)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${r.stdout}
|
|
22
|
+
${r.stderr}`);if(0===i.size)throw new g("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return rN=i,e=t,i}async function rH(e,t,r){let i=function(e,t,r){let i=r.length>0?r:["face"];switch(t){case"match":return i.flatMap(t=>[["simctl","biometric",e,"match",t],["simctl","biometric","match",e,t]]);case"nonmatch":return i.flatMap(t=>[["simctl","biometric",e,"nonmatch",t],["simctl","biometric",e,"nomatch",t],["simctl","biometric","nonmatch",e,t],["simctl","biometric","nomatch",e,t]]);case"enroll":return[["simctl","biometric",e,"enroll","yes"],["simctl","biometric",e,"enroll","1"],["simctl","biometric","enroll",e,"yes"],["simctl","biometric","enroll",e,"1"]];case"unenroll":return[["simctl","biometric",e,"enroll","no"],["simctl","biometric",e,"enroll","0"],["simctl","biometric","enroll",e,"no"],["simctl","biometric","enroll",e,"0"]]}}(e,t,r.modalityAliases),n=[];for(let e of i){let t=await p("xcrun",e,{allowFailure:!0});if(0===t.exitCode)return;n.push({args:e,stderr:t.stderr,stdout:t.stdout,exitCode:t.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 g("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e,action:t,setting:r.settingName,attempts:a});throw new g("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e,action:t,setting:r.settingName,attempts:a})}function rJ(e){if(!(e instanceof g)||"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 rz(e,t){await ry(e),await p("open",["-a","Simulator"],{allowFailure:!0});let r=K.fromTimeoutMs(tL);await X(async({deadline:r})=>{if(r?.isExpired())throw new g("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tL});let i=await p("xcrun",["simctl","launch",e.id,t],{allowFailure:!0});if(0!==i.exitCode)throw new g("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:["simctl","launch",e.id,t],stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:rJ},{deadline:r})}async function rK(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tR(i,{action:"launch iOS app",deviceId:e.id})}function rX(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new g("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!R.statSync(a).isFile())throw new g("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof g)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new g("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new g("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 g("INVALID_ARGS",`${i} file not found: ${a}`)}async function rY(e){let t=B(e.platform);return await E("resolve_target_device",async()=>{let r={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(r.target&&!r.platform)throw new g("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===r.platform){await e9();let e=await ec();return await q(e,r)}if("ios"===r.platform){let e=await tM();return await q(e,r)}let i=[];try{i.push(...await ec())}catch{}try{i.push(...await tM())}catch{}return await q(i,r)},{platform:t,target:e.target})}async function rZ(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>e$(e,t,r?.activity),openDevice:()=>eG(e),close:t=>eU(e,t),tap:(t,r)=>ej(e,t,r),doubleTap:async(t,r)=>{await ej(e,t,r),await ej(e,t,r)},swipe:(t,r,i,n,a)=>eW(e,t,r,i,n,a),longPress:(t,r,i)=>eK(e,t,r,i),focus:(t,r)=>eQ(e,t,r),type:t=>eX(e,t),fill:(t,r,i)=>e0(e,t,r,i),scroll:(t,r)=>e1(e,t,r),scrollIntoView:t=>e2(e,t),screenshot:(t,r)=>e3(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>rk(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rE(e),close:t=>rM(e,t),screenshot:(t,r)=>rC(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(tU(i.requestId))throw new g("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await t0(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await t0(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 t0(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await t0(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await t0(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await t0(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await t0(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await t0(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new g("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 t0(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await t0(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 t0(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await t0(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new g("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new g("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 E("platform_command",async()=>{var s,l,d,c,u,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new g("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 g("INVALID_ARGS","open <app> <url> is supported only on iOS");if(ef(t))throw new g("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!ef(i))throw new g("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 g("INVALID_ARGS","press requires x y");let n=r0(a?.count??1,"count",1,200),u=r0(a?.intervalMs??0,"interval-ms",0,1e4),p=r0(a?.holdMs??0,"hold-ms",0,1e4),f=r0(a?.jitterPx??0,"jitter-px",0,100),m=a?.doubleTap===!0;if(m&&p>0)throw new g("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(m&&f>0)throw new g("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,c=f,"ios"===s.platform&&l>1&&0===d&&0===c)return await t0(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:u,doubleTap:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:u,holdMs:p,jitterPx:f,doubleTap:m,timingMode:"runner-series"};return await r3(n,u,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=rQ[e%rQ.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:u,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 g("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=r0(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,c=r0(a?.count??1,"count",1,200),f=r0(a?.pauseMs??0,"pause-ms",0,1e4),m=a?.pattern??"one-way";if("one-way"!==m&&"ping-pong"!==m)throw new g("INVALID_ARGS",`Invalid pattern: ${m}`);if(u=e,p=c,"ios"===u.platform&&p>1)return await t0(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:c,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:c,pauseMs:f,pattern:m};return await r3(c,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:c,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 g("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 g("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 g("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 g("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 g("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 g("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 g("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 g("INVALID_ARGS","pinch requires scale > 0");return await t0(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await O.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await t0(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await eH(e),{action:"back"};case"home":if("ios"===e.platform)return await t0(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await eJ(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await t0(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await ez(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new g("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new g("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await rR(e):await eY(e)}}if(r.length<2)throw new g("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await rT(e,i):await eZ(e,i),{action:t,textLength:Array.from(i).length}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await r$(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await e4(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 g("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await r1(i);if("ios"===e.platform)return await rP(e,t,n),{platform:"ios",bundleId:t};let a=await e5(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await E("snapshot_capture",async()=>await t0(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 g("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await E("snapshot_capture",async()=>await e6(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 g("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let rQ=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function r0(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new g("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function r1(e){let t=rX(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await r2(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new g("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof g)throw t;throw new g("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function r2(e){try{return await O.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new g("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new g("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new g("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new g("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function r3(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await r4(t)}async function r4(e){await new Promise(t=>setTimeout(t,e))}let r8={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function r5(e,t){let r=r8[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function r6(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 r9(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let r7=/^-?\d+(\.\d+)?$/,ie=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),it=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function ir(e){return"click"===e||"press"===e}function ii(e){let t=e.trim();return t.startsWith("@")||r7.test(t)?t:JSON.stringify(t)}function ia(e,t){let r=t.flags??{};if(ir(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 io(e,t){let r=[],i={},n=ir(e)?ie:"swipe"===e?it:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(ir(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 is{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=is.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:c,snapshotRaw:u,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx: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:c,snapshotRaw:u,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(ir(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(ii(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(ii(i)),ia(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(ii(r)),ia(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(ii(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(ii(i)),n&&t.push(ii(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(ii(r)),t.push(ii(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(ii(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",ii(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(ii(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(ii(r));return ia(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
24
|
+
`}(e,this.buildOptimizedActions(e));R.writeFileSync(t,i)}catch{}}defaultTracePath(e){let t=is.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,is.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return n.join(this.sessionsDir,is.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($.homedir(),e.slice(2)):t&&!n.isAbsolute(e)?n.resolve(t,e):n.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return is.expandHome(e.saveScriptPath);R.existsSync(this.sessionsDir)||R.mkdirSync(this.sessionsDir,{recursive:!0});let t=is.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&&(ir(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(ir(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=r6(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(ir(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 il(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 id=tI(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function ic(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:ry}));await t(e);return}if("device"===e.kind)return void await iu(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:ep}));await t(e.id)}}async function iu(e){let t=n.join($.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(id/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:id+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await ip(t);if(0===i.exitCode){if(!o.parsed)throw new g("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 g("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 g("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:im(n,a)})}catch(t){if(t instanceof g&&"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??id),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 g("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?im(i,n):o},t)}throw new g("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 O.rm(t,{force:!0}).catch(()=>{})}}async function ip(e){try{let t=await O.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 im(e,t){let r=t$(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.":tP)}function ih(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function iw(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function ig(e,t){return e.find(e=>e.ref===t)??null}function iI(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function iv(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 iA(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&&iy(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||!iy(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&&iy(r)?r:void 0)}function iy(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function iS(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=ib(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&iy(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 ib(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 iN(e,t){let r=ib(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 i_(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let iD=new Set(["id","role","text","label","value"]),ik=new Set(["visible","hidden","editable","selected","enabled","hittable"]),iE=new Set([...iD,...ik]);function iM(e){let t=e.trim();if(!t)throw new g("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)&&!iJ(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 g("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new g("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new g("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new g("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)&&!iJ(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 g("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new g("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(iG)}})(e))}}function ix(e){try{return iM(e)}catch{return null}}function iO(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||!iU(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=iH(e),a=iH(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 iL(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)&&iU(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 iC(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 iR(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 iE.has(e)}return iE.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&ix(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 iT(e){let t=e[0]??"",r=iR(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function iP(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function i$(e,t){return iN(e.type??"",t)&&!1!==e.enabled}function iF(e,t,r={}){let i=[],n=ib(e.type??""),a=iW(e.identifier),o=iW(e.label),s=iW(e.value),l=iW(i_(e)),d="fill"===r.action;a&&i.push(`id=${ij(a)}`),n&&o&&i.push(d?`role=${ij(n)} label=${ij(o)} editable=true`:`role=${ij(n)} label=${ij(o)}`),o&&i.push(d?`label=${ij(o)} editable=true`:`label=${ij(o)}`),s&&i.push(d?`value=${ij(s)} editable=true`:`value=${ij(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${ij(l)} editable=true`:`text=${ij(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${ij(n)} editable=true`);let c=r9(i);return 0===c.length&&n&&c.push(d?`role=${ij(n)} editable=true`:`role=${ij(n)}`),0===c.length&&iP(e)&&c.push("visible=true"),c}function iG(e){let t=e.trim();if(!t)throw new g("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!ik.has(r))throw new g("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(!iE.has(i))throw new g("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new g("INVALID_ARGS",`Missing selector value for key: ${i}`);if(ik.has(i)){let e,t="true"===(e=iV(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new g("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:iV(n)}}function iU(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return iB(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return ib(e)}(i??"")===function(e){return ib(e)}(n);case"label":return iB(e.label,String(t.value));case"value":return iB(e.value,String(t.value));case"text":{let r=iq(String(t.value));return iq(i_(e))===r}case"visible":return iP(e)===!!t.value;case"hidden":return!iP(e)==!!t.value;case"editable":return i$(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 iV(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function iB(e,t){return iq(e??"")===iq(t)}function iq(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function ij(e){return JSON.stringify(e)}function iW(e){if(!e)return null;let t=e.trim();return t||null}function iH(e){return e.rect?e.rect.width*e.rect.height:1/0}function iJ(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}function iz(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 iK(e,t){if(!e)return;let r=n.dirname(e);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i={pid:t,startTime:C(t)??void 0,command:a(t)??void 0};R.writeFileSync(e,`${JSON.stringify(i)}
|
|
26
|
+
`)}function iX(e){if(e&&R.existsSync(e))try{R.unlinkSync(e)}catch{}}function iY(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:iz("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:iz("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function iZ(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function iQ(e){await new Promise(t=>setTimeout(t,e))}function i0(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 i1(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 i2(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 i3(e,t,r,i){let n="active",a=m("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=i0(t,{redactionPatterns:r});"number"==typeof a.pid&&iK(i,a.pid);let s=i1(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iX(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iZ(s),a.killed||a.kill("SIGKILL"),await iZ(s),iX(i)}}}async function i4(e,t,r,i){let n="active",a=m("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=i0(t,{redactionPatterns:r});"number"==typeof a.pid&&iK(i,a.pid);let s=i1(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),iX(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await iZ(s),a.killed||a.kill("SIGKILL"),await iZ(s),iX(i)}}}async function i8(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await i2(e,t);if(!d){await iQ(1e3);continue}let c=m("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=c;let u=i0(r,{redactionPatterns:i});o=i1(c,r,{endStreamOnClose:!1,writer:u}),"number"==typeof c.pid&&iK(n,c.pid);let p=await o;if(iX(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await iQ(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),iX(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await iZ(o),a&&!a.killed&&a.kill("SIGKILL"),await iZ(d),iX(n)}}}async function i5(e,t,r,i){iY(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 i4(e.id,n,a,i):await i3(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new g("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await i8(e.id,t,n,a,i)}throw n.end(),new g("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function i6(e){await e.stop(),await iZ(e.wait)}async function i9(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 i7(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 ne=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),nt=/https?:\/\/[^\s"'<>\])]+/i,nr=[/\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 ni(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 nn(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return na(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 na(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function no(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function ns(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let nl='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nd=["platform","target","device","udid","serial","verbose","out"],nc=["platform","target","device","udid","serial","verbose","out"],nu=["path","start","stop","doctor","mark","clear"],np=`logs requires ${nu.slice(0,-1).join(", ")}, or ${nu.at(-1)}`,nf="Not implemented for this platform in this release.",nm="open-command-roundtrip";function nh(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 nw(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:nm,appTarget:t,appBundleId:r}}let ng=["dump","log"],nI=`network requires ${ng.join(" or ")}`,nv=["summary","headers","body","all"],nA=`network include mode must be one of: ${nv.join(", ")}`;function ny(e,t,r){return t||nS(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nS(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nb(e){let t=nS(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}let nN={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:rL}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:eq}));return await i(e,t,r)}};async function n_(e,t,r){if("ios"===e.platform&&t)return ef(t)?"device"===e.kind?em(r,t):void 0:await nD(e,t)}async function nD(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rD}));return await r(e,t)}catch{return}}async function nk(e,t){if(!("android"!==e.platform||!t||ef(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:ex})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function nE(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=B(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=ny("appstate",o,s);if(d)return d;let c=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nS(e))return!0;let r=B(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nl}};if(c){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let u=await nb({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===u.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nl}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eT})),f=await p(u);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function nM(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},c=ny("clipboard",l,d);if(c)return c;let u=(t.positionals?.[0]??"").toLowerCase();if("read"!==u&&"write"!==u)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nb({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!r5("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,{...il(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 nx(e){var t;let{req:r,sessionName:i,logPath:n,sessionStore:a,invoke:o,dispatch:s,ensureReady:l,resolveTargetDevice:d,reinstallOps:c=nN,stopIosRunner:u,appLogOps:p={start:i5,stop:i6},resolveAndroidPackageForOpen:f=nk}=e,m=s??rZ,w=l??ic,I=d??rY,v=r.command;if("session_list"===v)return{ok:!0,data:{sessions:a.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===v)try{let e=[],t=B(r.flags?.platform);if("android"===t){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:ec}));e.push(...await t())}else if("ios"===t){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tM}));e.push(...await t())}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:ec})),{listIosDevices:r}=await Promise.resolve().then(()=>({listIosDevices:tM}));try{e.push(...await t())}catch{}try{e.push(...await r())}catch{}}let i=r.flags?.target?e.filter(e=>(e.target??"mobile")===r.flags?.target):e;return{ok:!0,data:{devices:i}}}catch(t){let e=h(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===v){let e=a.get(i),t=r.flags??{},n=ny(v,e,t);if(n)return n;let o=await nb({session:e,flags:t,ensureReadyFn:w,resolveTargetDeviceFn:I,ensureReady:!0});if(!r5("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=r.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:rF}));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:eO}));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=a.get(i),t=r.flags??{},n=ny(v,e,t);if(n)return n;let o=await nb({session:e,flags:t,ensureReadyFn:w,resolveTargetDeviceFn:I,ensureReady:!0});return r5("boot",o)?{ok:!0,data:{platform:o.platform,target:o.target??"mobile",device:o.name,id:o.id,kind:o.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===v)return await nE({req:r,sessionName:i,sessionStore:a,ensureReady:w,resolveDevice:I});if("clipboard"===v)return await nM({req:r,sessionName:i,logPath:n,sessionStore:a,ensureReady:w,resolveDevice:I,dispatch:m});if("perf"===v){let e,t,r,n=a.get(i);return n?{ok:!0,data:(r=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===nm&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:nm,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(n.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:nm,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:nm},{session:n.name,platform:n.device.platform,device:n.device.name,deviceId:n.device.id,metrics:{startup:r,fps:{available:!1,reason:nf},memory:{available:!1,reason:nf},cpu:{available:!1,reason:nf}},sampling:{startup:{method:nm,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,t=a.get(i),n=r.flags??{},o=ny(v,t,n);if(o)return o;let s=r.positionals?.[0]?.trim(),l=r.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let d=is.expandHome(l);if(!R.existsSync(d))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${d}`}};let u=await nb({session:t,flags:n,ensureReadyFn:w,resolveTargetDeviceFn:I,ensureReady:!1});if(!r5("reinstall",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===u.platform){let t=await c.ios(u,s,d);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await c.android(u,s,d);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:d,...e};return t&&a.recordAction(t,{command:v,positionals:r.positionals??[],flags:r.flags??{},result:p}),{ok:!0,data:p}}if("push"===v){let e,t=a.get(i),o=r.flags??{},s=ny(v,t,o);if(s)return s;let l=r.positionals?.[0]?.trim(),d=r.positionals?.[1]?.trim();if(!l||!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let c="file"===(e=rX(d,{subject:"Push payload",cwd:r.meta?.cwd,expandPath:(e,t)=>is.expandHome(e,t)})).kind?e.path:e.text,u=await nb({session:t,flags:o,ensureReadyFn:w,resolveTargetDeviceFn:I,ensureReady:!0});if(!r5("push",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"push is not supported on this device"}};let p=await m(u,"push",[l,c],r.flags?.out,{...il(n,r.flags,t?.appBundleId,t?.trace?.outPath)});return t&&a.recordAction(t,{command:v,positionals:[l,d],flags:r.flags??{},result:p??{}}),{ok:!0,data:p??{}}}if("open"===v){let e=r.flags?.relaunch===!0;if(a.has(i)){let o=a.get(i),s=r.positionals?.[0],l=s??(e?o?.appName:void 0);if(!o||!l)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&ef(l))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await w(o.device);let d=await n_(o.device,l,o.appBundleId)??await f(o.device,l)??((t=o.device,"android"===t.platform&&l&&ef(l))?o.appBundleId:void 0),c=s?r.positionals??[]:[l];if(e){let e=d??l;await m(o.device,"close",[e],r.flags?.out,{...il(n,r.flags,d??o.appBundleId,o.trace?.outPath)})}let u=Date.now();await m(o.device,"open",c,r.flags?.out,{...il(n,r.flags,d)});let p=nw(u,l,d),h={...o,appBundleId:d,appName:l,recordSession:o.recordSession||!!r.flags?.saveScript,snapshot:void 0},g=nh({sessionName:i,appName:l,appBundleId:d,startup:p});return a.recordAction(h,{command:v,positionals:c,flags:r.flags??{},result:g}),a.set(i,h),{ok:!0,data:g}}let o=r.positionals?.[0];if(e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&o&&ef(o))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let s=await I(r.flags??{}),l=a.toArray().find(e=>e.device.id===s.id);if(l)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${l.name}".`,details:{session:l.name,deviceId:s.id,deviceName:s.name}}};await w(s);let d=await n_(s,o)??await f(s,o);if(e&&o){let e=d??o;await m(s,"close",[e],r.flags?.out,{...il(n,r.flags,d)})}let c=Date.now();await m(s,"open",r.positionals??[],r.flags?.out,{...il(n,r.flags,d)});let u=o?nw(c,o,d):void 0,p={name:i,device:s,createdAt:Date.now(),appBundleId:d,appName:o,recordSession:!!r.flags?.saveScript,actions:[]},h=nh({sessionName:i,appName:o,appBundleId:d,startup:u});return a.recordAction(p,{command:v,positionals:r.positionals??[],flags:r.flags??{},result:h}),a.set(i,p),{ok:!0,data:h}}if("replay"===v){let e=r.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let t=is.expandHome(e,r.meta?.cwd),s=R.readFileSync(t,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new g("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(ir(i)){let e=io(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 nF(r)&&nF(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=io(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),c=r.flags?.replayUpdate===!0,u=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await o({token:r.token,session:i,command:s.command,positionals:s.positionals??[],flags:nR(r.flags,s.flags),meta:r.meta});if(l.ok)continue;if(!c)return nC(l,s,e,t);let p=await nT({action:s,sessionName:i,logPath:n,sessionStore:a,dispatch:m});if(!p)return nC(l,s,e,t);if(d[e]=p,!(l=await o({token:r.token,session:i,command:p.command,positionals:p.positionals??[],flags:nR(r.flags,p.flags),meta:r.meta})).ok)return nC(l,p,e,t);u+=1}if(c&&u>0){let e=a.get(i);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",ii(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(ii(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(ii(r));return ia(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)}(t,d,e)}return{ok:!0,data:{replayed:d.length,healed:u,session:i}}}catch(t){let e=h(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===v){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let t=(r.positionals?.[0]??"path").toLowerCase(),n=!!r.flags?.restart;if(!nu.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:np}};if(n&&"clear"!==t)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===t){let t=a.resolveAppLogPath(i),r=function(e){if(!R.existsSync(e))return{exists:!1,sizeBytes:0};let t=R.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),n=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:n,sizeBytes:r.sizeBytes,modifiedAt:r.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===t){let t=a.resolveAppLogPath(i),r=await i9(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:r.checks,notes:r.notes}}}if("mark"===t){let e,t=r.positionals?.slice(1).join(" ")??"",n=a.resolveAppLogPath(i);return iY(n),e=`[agent-device][mark][${new Date().toISOString()}] ${t.trim()||"marker"}
|
|
29
|
+
`,R.appendFileSync(n,e,"utf8"),{ok:!0,data:{path:n,marked:!0}}}if("clear"===t){if(e.appLog&&!n)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(n){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!r5("logs",e.device))return{ok:!1,error:b(new g("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=a.resolveAppLogPath(i);if(n){e.appLog&&await p.stop(e.appLog);let r=i7(t),n=a.resolveAppLogPidPath(i);try{let o=await p.start(e.device,e.appBundleId,t,n),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return a.set(i,s),{ok:!0,data:{...r,restarted:!0}}}catch(r){let t=b(r);return a.set(i,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:i7(t)}}if("start"===t){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!r5("logs",e.device))return{ok:!1,error:b(new g("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=a.resolveAppLogPath(i),r=a.resolveAppLogPidPath(i);try{let n=await p.start(e.device,e.appBundleId,t,r),o={...e,appLog:{platform:e.device.platform,backend:n.backend,outPath:t,startedAt:n.startedAt,getState:n.getState,stop:n.stop,wait:n.wait}};return a.set(i,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===t){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await p.stop(e.appLog),a.set(i,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===v){let e=a.get(i);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let t=(r.positionals?.[0]??"dump").toLowerCase();if(!ng.includes(t))return{ok:!1,error:{code:"INVALID_ARGS",message:nI}};let n=r.positionals?.[1],o=n?Number.parseInt(n,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(r.positionals?.[2]??"summary").toLowerCase();if(!nv.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:nA}};let l=function(e,t){let r=ns(t?.maxEntries,25,1,200),i=t?.include??"summary",n=ns(t?.maxPayloadChars,2048,64,16384),a=ns(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=ni(n,["method","httpMethod"]),o=ni(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=ne.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),c=(a??d?.[1]??l?.[1])?.toUpperCase(),u=nt.exec(e),p=o??u?.[0];if(!p)return null;let f={method:c,url:p,status:s??function(e){for(let t of nr){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:no(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 na(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=no(t,i))}if("body"===r||"all"===r){let t=nn(e,n,["requestBody","body","payload","request"]),r=nn(e,n,["responseBody","response"]);t&&(f.requestBody=no(t,i)),r&&(f.responseBody=no(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(a.resolveAppLogPath(i),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),c=[];return e.appLog||c.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&c.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:c}}}if("batch"===v)return await nO(r,i,o);if("close"===v){let e=a.get(i);return e?(e.appLog&&await p.stop(e.appLog),r.positionals&&r.positionals.length>0&&await m(e.device,"close",r.positionals??[],r.flags?.out,{...il(n,r.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??t4)(e.device.id),a.recordAction(e,{command:v,positionals:r.positionals??[],flags:r.flags??{},result:{session:i}}),r.flags?.saveScript&&(e.recordSession=!0),a.writeSessionLog(e),a.delete(i),{ok:!0,data:{session:i}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function nO(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??x;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 nL(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=h(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function nL(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 nd)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 nC(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>ii(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 nR(e,t){let r={...t??{}},i=e??{};for(let e of nc)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function nT(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(ir(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=ir(t.command)||"fill"===t.command,l=ir(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await nP(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),ir(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}=iT(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=n$(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 r9(t).filter(e=>e.trim().length>0)}(t)){let r=ix(e);if(!r)continue;let i=iO(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=iF(i.node,o.device.platform,{action:ir(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(ir(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=r6(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}=iT(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}=n$(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let c=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=ix(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(ib(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=i_(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(ib(e.type??"")))});if(0===s.length||1!==r9(s.map(e=>i_(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=iF(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return c||null}async function nP(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...il(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:ih(t.flags?.snapshotRaw?s:iS(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function n$(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=iR(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 nF(e){return!!e&&!Number.isNaN(Number(e))}function nG(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function nU(e,t){let r=S(e.type??"Element"),i=f(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 nV(e,t){return t.flatten?e.map(e=>({text:V(e,0,!1),comparable:nU(e,0)})):v(e).map(e=>({text:e.text,comparable:nU(e.node,e.depth)}))}function nB(e,t){return e.get(t)??0}async function nq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??rZ,o=t.command;if("snapshot"===o){let{session:e,device:o}=await nH(n,r,t.flags);if(!r5("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=nW(t.flags?.snapshotScope,e);return s.ok?await nJ(e,o,async()=>{let l=e?.appBundleId,d=await nj({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),c=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return nz(n,c,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,c),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:c.appBundleId?c.appName??c.appBundleId:void 0,appBundleId:c.appBundleId}}}):s.response}if("diff"===o){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await nH(n,r,t.flags);if(!r5("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=nW(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await nJ(e,o,async()=>{let d=e?.appBundleId,c=(await nj({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return nV(e,t).length}(c.nodes,{flatten:l}),a=e?{...e,snapshot:c}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:c,actions:[]};return nz(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let u=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&nB(a,n-1)<nB(a,n+1)?nB(a,n+1):nB(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&&nB(n,l-1)<nB(n,l+1)?l+1:l-1,c=nB(n,d),u=c-d;for(;o>c&&s>u;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===c?(a.push({kind:"added",text:r[u].text}),s=u):(a.push({kind:"removed",text:t[c].text}),o=c)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(nV(e,r),nV(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,c.nodes,{flatten:l}),p={...e,snapshot:c};return nz(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:u.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:u.summary,lines:u.lines}}})}if("wait"===o){let{session:e,device:o}=await nH(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=nG(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=nG(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=nG(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=nG(e[e.length-1]),i=iR(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=ix(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)),nz(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):r5("wait",o)?await nJ(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,{...il(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),c=l?.nodes??[],u=ih(t.flags?.snapshotRaw?c:iS(c));e&&(e.snapshot={nodes:u,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=iL(u,s.selector,{platform:o.platform});if(p)return nz(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=iw(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?iA(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let c=d??1e4,u=Date.now();for(;Date.now()-u<c;){if("ios"===o.platform){let r=await t0(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 nz(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}}}else if("android"===o.platform&&iv(ih((await e6(o,{scope:l})).nodes??[]),l))return nz(n,e,t,{text:l,waitedMs:Date.now()-u}),{ok:!0,data:{text:l,waitedMs:Date.now()-u}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===o){let{session:e,device:a}=await nH(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return r5("alert",a)?await nJ(e,a,async()=>{if("wait"===o){let r=nG(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await t0(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return nz(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 t0(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 nz(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:c}};let{session:s,device:l}=await nH(n,r,t.flags);return r5("settings",l)?await nJ(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],c=await rZ(l,"settings",d,t.flags?.out,{...il(i,t.flags,r,s?.trace?.outPath)});return nz(n,s,t,c??{setting:e,state:a}),{ok:!0,data:c??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function nj(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...il(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:ih(n.flags?.snapshotRaw?l:iS(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function nW(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=iw(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?iA(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 nH(e,t,r){let i=e.get(t),n=i?.device??await rY(r??{});return i||await ic(n),{session:i,device:n}}async function nJ(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await t4(t.id)}}function nz(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function nK(e,t,r,i={}){let n=nY(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 nX(e.label,r);case"value":return nX(e.value,r);case"id":return nX(e.identifier,r);default:return Math.max(nX(e.label,r),nX(e.value,r),nX(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 nX(e,t){let r=nY(e??"");return r?r===t?2:+!!r.includes(t):0}function nY(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function nZ(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:c,value:u,timeoutMs:p}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new g("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:nG(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 g("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let m=f?.device??await rY(t.flags??{});f||await ic(m);let h=f?.appBundleId,w="role"!==l?d:void 0,I="click"===c||"focus"===c||"fill"===c||"type"===c,v=0,A=null,y=async()=>{let e=Date.now();if(A&&e-v<750)return{nodes:A};let a=await rZ(m,"snapshot",[],t.flags?.out,{...il(i,{...t.flags,snapshotScope:w,snapshotInteractiveOnly:I,snapshotCompact:I},h,f?.trace?.outPath)}),o=a?.nodes??[],s=ih(t.flags?.snapshotRaw?o:iS(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"===c){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await y();if(nK(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:S}=await y(),b=nK(S,l,d,{requireRect:I});if(I&&b.matches.length>1){let e=b.matches.slice(0,8).map(e=>{let t=i_(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${b.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:b.matches.length,candidates:e}}}}let N=b.matches[0]??null;if(!N)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let _="click"===c||"focus"===c||"fill"===c||"type"===c?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(S,N)??N:N,D=`@${_.ref}`,k={...t.flags??{},noRecord:!0};if("exists"===c)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=i_(N);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:N}}}if("get_attrs"===c)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:N}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[D],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"click"}}),e}if("fill"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[D,u],flags:k});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"fill"}}),e}if("focus"===c){let e=N.rect?iI(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await rZ(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...il(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"===c){if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=N.rect?iI(N.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await rZ(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...il(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await rZ(m,"type",[u],t.flags?.out,{...il(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 nQ(e){return e instanceof Error?e.message:String(e)}function n0(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function n1(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function n2(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:t0},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),u=d?.device??await rY(t.flags??{});d||await ic(u);let p=d??{name:r,device:u,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(!r5("record",u))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===u.platform&&"device"===u.kind?n0(p):void 0;if("ios"===u.platform&&"device"===u.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=is.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=n1(t,a,p);if("ios"===u.platform&&"device"===u.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(u,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await n()}catch(e){if(!nQ(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nQ(e)}`}};{var l,c;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:u.platform,kind:u.kind,deviceId:u.id,session:p.name,error:nQ(e)}});let t=(l=u.id,c=p.name,i.toArray().find(e=>e.name!==c&&"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(u,{command:"recordStop",appBundleId:f},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${nQ(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===u.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",["simctl","io",u.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",u.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=n0(p);try{await o.runIosRunnerCommand(u,{command:"recordStop",appBundleId:e},n1(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:u.platform,kind:u.kind,deviceId:u.id,session:p.name,error:nQ(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of tV)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",u.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",u.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",u.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=is.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=is.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 n3(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function n4(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 n8(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function n5(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??rZ,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(!r5("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=n7("press",t.flags);if(r)return r;let s=ae({session:e,refInput:d,fallbackLabel:t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!s.ok)return s.response;let{ref:c,node:u,snapshotNodes:p}=s.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has no bounds`}};let f=iA(u,p),m=iF(u,e.device.platform,{action:l}),{x:h,y:w}=iI(u.rect),g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:h,y:w,refLabel:f,selectorChain:m}}),{ok:!0,data:{...g??{},ref:c,x:h,y:w}}}let c=(t.positionals??[]).join(" ").trim();if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let u=iM(c),p=await n6(e,t.flags,i,n,{interactiveOnly:!0},a),f=await E("selector_resolve",()=>iO(p.nodes,u,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iC(u,f?.diagnostics??[],{unique:!0})}};let{x:m,y:h}=iI(f.node.rect),w=await a(e.device,"press",[String(m),String(h)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=iF(f.node,e.device.platform,{action:l}),I=iA(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:m,y:h,selector:f.selector.raw,selectorChain:g,refLabel:I}}),{ok:!0,data:{...w??{},selector:f.selector.raw,x:m,y:h}}}if("fill"===o){let e=i.get(r);if(e&&!r5("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=n7("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=ae({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=u.type??"",m=f&&!iN(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iA(u,p),w=iF(u,e.device.platform,{action:"fill"}),{x:g,y:I}=iI(u.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:c,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=iR(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=iM(s.selectorExpression),d=await n6(e,t.flags,i,n,{interactiveOnly:!0},a),c=await E("selector_resolve",()=>iO(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!c||!c.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:iC(l,c?.diagnostics??[],{unique:!0})}};let u=c.node,p=u.type??"",f=p&&!iN(p,e.device.platform)?`fill target ${c.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=iI(c.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=iF(u,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:c.selector.raw,selectorChain:g,refLabel:iA(u,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(!r5("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=n7("get",t.flags);if(r)return r;let n=ae({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,c=iF(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:c}}),{ok:!0,data:{ref:a,node:d}};let u=i_(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:u,refLabel:u||void 0,selectorChain:c}}),{ok:!0,data:{ref:a,text:u,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let c=iM(d),u=await n6(s,t.flags,i,n,{interactiveOnly:!1},a),p=await E("selector_resolve",()=>iO(u.nodes,c,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iC(c,[],{unique:!0})}};let f=p.node,m=iF(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=i_(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(!r5("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=iT(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let c=iM(l.selectorExpression),u=await n6(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=iL(u.nodes,c,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:c.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:iC(c,[],{unique:!1})}}}let p=await E("selector_resolve",()=>iO(u.nodes,c,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:iC(c,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=i_(r),o=!1;switch(t){case"visible":o=iP(r);break;case"hidden":o=!iP(r);break;case"editable":o=i$(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:iP(r),editable:i$(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:c.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!r5("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=n7("scrollintoview",t.flags);if(l)return l;let d=ae({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:c,node:u,snapshotNodes:p}=d.target;if(!u.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=iI(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=n4(n.map(e=>e.rect).filter(e=>n3(e,r.x,r.y)));if(a)return a;let o=n4(n.map(e=>e.rect));if(o)return o;let s=n4(i.map(e=>e.rect).filter(e=>n3(e,r.x,r.y)));return s||null}(p,u.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,c=o+.25*n,u=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=c&&f<=u)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>u?{x:h,startY:w,endY:g,count:n8(Math.ceil((f-u)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:n8(Math.ceil((c-f)/I),1,50),direction:"up"}}(u.rect,f),h=iA(u,p),w=iF(u,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:c,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:c,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:c,attempts:m.count,direction:m.direction}}}return null}async function n6(e,t,r,i,n,a=rZ){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:ih(t?.snapshotRaw?s:iS(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let n9=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function n7(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of n9)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 ae(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=iw(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=iv(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 at(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 ar(e){let{req:t,leaseRegistry:r}=e,i=at(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 ai=new Set(["agent_device.command","agent-device.command"]),an={"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"},aa=new Set([...ai,...Object.keys(an)]);function ao(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function as(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function al(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function ad(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 ac(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 g("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:ao(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new g(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:ao(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=l(r.tenantId);if(!e){let e=b(new g("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:ao(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function ap(){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(w(i).href)}catch(e){throw new g("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 g("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function af(e){let t=await ap(),{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||as(i,ao(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a;try{a=JSON.parse(n)}catch{as(i,ao(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void as(i,ao(a.id??null,-32600,"Invalid Request"),400);if(!aa.has(a.method))return void as(i,ao(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void as(i,ao(a.id??null,-32602,"Invalid params"),400);try{var o;let n=a.params,s=function(e,t,r){if(ai.has(e))return{token:ad(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=an[e];if(i){let e;return{token:ad(t,r),session:ac(t,"session")??"default",command:i,positionals:[],meta:{tenantId:ac(t,"tenantId")??ac(t,"tenant"),runId:ac(t,"runId"),leaseId:ac(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:ac(t,"backend")}}}throw new g("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(o=a.method,ai.has(o)&&("string"!=typeof s.command||0===s.command.length))return void as(i,ao(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 as(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 as(i,{jsonrpc:"2.0",id:a.id??null,result:d});as(i,ao(a.id??null,-32e3,d.error.message,d.error),al(d.error.code))}catch(t){let e=b(t);as(i,ao(a.id??null,-32e3,e.message,e),al(e.code))}})})}function am(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function ah(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 g("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class ag{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=l(e.tenantId);if(!r)throw new g("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=am(e.runId);if(!i)throw new g("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(),d={leaseId:u.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(d.leaseId,d),this.runBindings.set(a,d.leaseId),{...d}}heartbeatLease(e){let t=ah(e.leaseId);if(!t)throw new g("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new g("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=ah(e.leaseId);if(!t)throw new g("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=l(e.tenantId);if(!r)throw new g("INVALID_ARGS","tenant isolation requires tenant id.");let i=am(e.runId);if(!i)throw new g("INVALID_ARGS","tenant isolation requires run id.");let n=ah(e.leaseId);if(!n)throw new g("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new g("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new g("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 g("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 g("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=l(t),n=am(r);if(t&&!i)throw new g("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new g("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 g("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}let{baseDir:aI,infoPath:av,lockPath:aA,logPath:ay,sessionsDir:aS}=U(process.env.AGENT_DEVICE_STATE_DIR),ab=G(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var aN=aS;if(R.existsSync(aN))for(let e of R.readdirSync(aN,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(aN,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=C(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{iX(t)}}let a_=new is(aS),aD=new ag({maxActiveSimulatorLeases:aG(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:aG(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:aG(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:aG(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),ak=_(),aE=u.randomBytes(24).toString("hex"),aM=new Set(["session_list","devices"]),ax=new Set(["session_list","devices","lease_allocate","lease_heartbeat","lease_release"]),aO=C(process.pid)??void 0,aL=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=D(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function aC(e,t,r){let i=k().requestId;return{...il(ay,e,t,r,i),requestId:i}}async function aR(e){var t;let r="click"!==(t=e).command?t:{...t,command:"press"},i=!!(r.meta?.debug||r.flags?.verbose);return await T({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:ay},async()=>{if(r.token!==aE)return{ok:!1,error:b(new g("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=N(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=l(r);if(r&&!i)throw new g("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new g("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=at(e);ax.has(t)||e.meta?.sessionIsolation!=="tenant"||aD.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,a_),a=a_.get(n);a&&!aM.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=B(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),0!==r.length){var a;let t,i,n;throw new g("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 ar({req:e,leaseRegistry:aD});if(o)return aT(o);let s=await nx({req:e,sessionName:n,logPath:ay,sessionStore:a_,invoke:aR});if(s)return aT(s);let d=await nq({req:e,sessionName:n,logPath:ay,sessionStore:a_});if(d)return aT(d);let c=await n2({req:e,sessionName:n,sessionStore:a_,logPath:ay});if(c)return aT(c);let u=await nZ({req:e,sessionName:n,logPath:ay,sessionStore:a_,invoke:aR});if(u)return aT(u);let p=await n5({req:e,sessionName:n,sessionStore:a_,contextFromFlags:aC});if(p)return aT(p);let f=a_.get(n);if(!f)return aT({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!r5(t,f.device))return aT({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await rZ(f.device,t,e.positionals??[],e.flags?.out,{...aC(e.flags,f.appBundleId,f.trace?.outPath)});return a_.recordAction(f,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),aT({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=P({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function aT(e){let t=k();if(!e.ok){M({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=P({force:!0})??void 0;return{ok:!1,error:b(new g(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"}),P(),e}function aP(){R.existsSync(av)&&R.unlinkSync(av)}function a$(){if(!R.existsSync(aA))return null;try{let e=JSON.parse(R.readFileSync(aA,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function aF(){let e=a$();if(!e||e.pid===process.pid)try{R.existsSync(aA)&&R.unlinkSync(aA)}catch{}}function aG(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(aI)||R.mkdirSync(aI,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:ak,startedAt:Date.now(),processStartTime:aO},null,2),t=()=>{try{return R.writeFileSync(aA,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=a$();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(aA)}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"===ab||"dual"===ab){let t=F.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&tG.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 t8(),!(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),tU(s)))throw new g("COMMAND_FAILED","request canceled");n=await aR(e)}catch(e){n={ok:!1,error:b(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&tG.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 g("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===ab||"dual"===ab){let e=await af({handleRequest:aR});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 g("COMMAND_FAILED","Failed to bind HTTP server"))})})}i={socketPort:e,httpPort:t},R.existsSync(aI)||R.mkdirSync(aI,{recursive:!0}),R.writeFileSync(ay,""),n=i.httpPort&&i.socketPort?"dual":i.httpPort?"http":"socket",R.writeFileSync(av,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:aE,pid:process.pid,version:ak,codeSignature:aL,processStartTime:aO,stateDir:aI},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
31
|
+
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
32
|
+
`)}catch(t){let e=h(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|
|
33
|
+
`),r))try{t.close(()=>{})}catch{}aP(),aF(),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(),a_.toArray()))a_.writeSessionLog(e);await t5(),aP(),aF(),process.exit(0)}};process.on("SIGINT",()=>{o()}),process.on("SIGTERM",()=>{o()}),process.on("SIGHUP",()=>{o()}),process.on("uncaughtException",e=>{let t=e instanceof g?e:h(e);process.stderr.write(`Daemon error: ${t.message}
|
|
34
|
+
`),o()})})();
|