agent-device 0.7.5 → 0.7.9
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 +14 -3
- package/dist/src/bin.js +47 -45
- package/dist/src/daemon.js +33 -29
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +5 -5
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +2 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -2
- package/package.json +1 -1
- package/skills/agent-device/SKILL.md +35 -7
- package/skills/agent-device/references/permissions.md +27 -0
- package/skills/agent-device/references/remote-tenancy.md +15 -5
- package/skills/agent-device/references/session-management.md +4 -0
- package/skills/agent-device/references/snapshot-refs.md +10 -0
- package/skills/dogfood/SKILL.md +1 -1
package/dist/src/daemon.js
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
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,runCmdDetached as l,runCmdBackground as d,SETTINGS_INVALID_ARGS_MESSAGE as u,normalizeTenantId as c,runCmd as p,node_crypto as f,displayLabel as m,spawn as h,asAppError as w,pathToFileURL as g,AppError as I,whichCmd as v,buildSnapshotDisplayLines as A,fileURLToPath as y,runCmdStreaming as N,formatRole as S,normalizeError as
|
|
2
|
-
|
|
3
|
-
${e.stderr}`}function ec(e,t){return["-s",e,...t]}function ep(e){return e.startsWith("emulator-")}function ef(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function em(e,t=K){return p("adb",ec(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function eh(e,t){let r=t.replace(/_/g," ").trim();if(!ep(e))return r||e;let i=await ew(e);return i?i.replace(/_/g," "):r||e}async function ew(e){for(let t of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let r=await p("adb",ec(e,["shell","getprop",t]),{allowFailure:!0,timeoutMs:1500}),i=r.stdout.trim();if(0===r.exitCode&&i.length>0)return i}let t=await p("adb",ec(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:1500}),r=t.stdout.trim();if(0===t.exitCode&&r.length>0)return r}async function eg(e,t){let r=eu(await p("adb",ec(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:K})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function eI(e){return(await Promise.all(ed.map(async t=>await eg(e,t)))).some(e=>!0===e)}async function ev(e){var t;let r;return"tv"===((r=eu(await p("adb",ec(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:K})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await eI(e)?"tv":(t=eu(await p("adb",ec(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:K})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function eA(e={}){if(!await v("adb"))throw new I("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??eo(void 0),r=(await ey()).filter(e=>!t||t.has(e.serial));return await Promise.all(r.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([eh(e,t),e_(e),ev(e)]);return{platform:"android",id:e,name:r,kind:ep(e)?"emulator":"device",target:n,booted:i}}))}async function ey(){return(await p("adb",["devices","-l"],{timeoutMs:K})).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:","")}))}async function eN(){let e=await p("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:K});if(0!==e.exitCode)throw new I("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function eS(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await eb(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await new Promise(e=>setTimeout(e,1e3))}throw new I("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function eb(e,t){let r=ef(e);for(let e of(await ey()).filter(e=>(!t||e.serial===t)&&ep(e.serial)))if(ef(e.rawModel)===r||ef(await eh(e.serial,e.rawModel))===r)return e.serial}async function e_(e){try{let t=await em(e);return"1"===t.stdout.trim()}catch{return!1}}async function eD(e){var t,r;let i,n=e.avdName.trim();if(!n)throw new I("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let a=e.timeoutMs??12e4;if(!await v("adb"))throw new I("TOOL_MISSING","adb not found in PATH");if(!await v("emulator"))throw new I("TOOL_MISSING","emulator not found in PATH");let o=await eN(),s=function(e,t){let r=e.find(e=>e===t);if(r)return r;let i=ef(t);return e.find(e=>ef(e)===i)}(o,n);if(!s)throw new I("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:n,availableAvds:o,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let d=Date.now(),u=(t=await eA(),r=e.serial,i=ef(s),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!r||e.id===r)&&ef(e.name)===i));if(!u){let t=["-avd",s];e.headless&&t.push("-no-window","-no-audio"),l("emulator",t)}let c=u??await eS({avdName:s,serial:e.serial,timeoutMs:a}),p=Math.max(1e3,a-(Date.now()-d));await eE(c.id,p);let f=(await eA()).find(e=>e.id===c.id);return f?{...f,name:s,booted:!0}:{...c,name:s,booted:!0}}async function eE(e,t=6e4){let r,i=X.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await Y(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new I("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 em(e,Math.min(o,K));if(r=s,"1"!==s.stdout.trim())throw new I("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=es({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=>es({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(c){let n=w(c),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=es({error:c,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 u={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:el(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new I("COMMAND_FAILED","Android device did not finish booting in time",u);if("TOOL_MISSING"===n.code)throw new I("TOOL_MISSING",n.message,{...u,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new I("COMMAND_FAILED",n.message,{...u,...n.details??{}});throw new I(n.code,n.message,{...u,...n.details??{}},n.cause)}}function ek(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 eO(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 eM(e){let t=eL(e),r=e=>{let r=ex(t,e);if(null!==r)return"true"===r};return{text:ex(t,"text"),desc:ex(t,"content-desc"),resourceId:ex(t,"resource-id"),className:ex(t,"class"),bounds:ex(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused")}}function eL(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 ex(e,t){return e.get(t)??null}function eC(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 eT(e){return e?e.toLowerCase():""}function eR(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}let eP=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function e$(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new I("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function eF(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new I("INVALID_ARGS",`permission setting requires a target: ${eP.join("|")}`)}function eV(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new I("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}let eU={settings:{type:"intent",value:"android.settings.SETTINGS"}},eG="android.intent.category.LAUNCHER",eB="android.intent.category.LEANBACK_LAUNCHER",eq="android.intent.category.DEFAULT";function ej(e,t){return["-s",e.id,...t]}async function eW(e,t){let r=t.trim();if(r.includes("."))return{type:"package",value:r};let i=eU[r.toLowerCase()];if(i)return i;let n=(await p("adb",ej(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 I("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function eH(e,t="all"){let r=await eJ(e);return("user-installed"===t?(await eK(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 eJ(e){let t=new Set;for(let r of ez(e,{includeFallbackWhenUnknown:!0})){let i=await p("adb",ej(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 ez(e,t={}){return"tv"===e.target?[eB]:"mobile"===e.target?[eG]:t.includeFallbackWhenUnknown?[eG,eB]:[eG]}async function eK(e){return(await p("adb",ej(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function eX(e){let t=await eQ(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let r=await eQ(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return r||{}}async function eY(e){let t=await p("adb",ej(e,["shell","dumpsys","input_method"]),{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t=function(e){let t=new Map;for(let r of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=r[1],i=r[2]?.toLowerCase();e&&("true"===i||"false"===i)&&t.set(e,"true"===i)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),r=t??!1;if(null===t){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(r=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),n=i.length>0?i[i.length-1]?.[1]:void 0,a=n?`0x${n.toLowerCase()}`:void 0;return{visible:r,inputType:a,type:a?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let r=15&t;if(2===r)return"number";if(3===r)return"phone";if(4===r)return"datetime";if(1!==r)return"unknown";let i=4080&t;return 32===i||208===i?"email":128===i||224===i||144===i?"password":"text"}(a):void 0}}(t.stdout)}async function eZ(e){let t=await eY(e),r=t,i=0;for(;r.visible&&i<2;)await e7(e),i+=1,await tT(120),r=await eY(e);return{attempts:i,wasVisible:t.visible,dismissed:t.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type}}async function eQ(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",ej(e,r),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function e0(e,t,r){var i,n;let a;e.booted||await eE(e.id);let o=t.trim();if(ek(o)){if(r)throw new I("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await p("adb",ej(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await eW(e,t),l=ez(e)[0]??eG;if("intent"===s.type){if(r)throw new I("INVALID_ARGS","Activity override requires a package name, not an intent");await p("adb",ej(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",ej(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eq,"-c",l,"-n",t]));return}let d=await p("adb",ej(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eq,"-c",l,"-p",s.value]),{allowFailure:!0});if(0===d.exitCode&&(i=d.stdout,n=d.stderr,a=`${i}
|
|
4
|
-
${
|
|
5
|
-
${i.
|
|
6
|
-
${
|
|
7
|
-
${i}`,a=/dumped to:\s*(\S+)/i.exec(n),a?.[1]??t),u=await p("adb",
|
|
8
|
-
${t}`,i=r.indexOf("<?xml"),n=i>=0?i:r.indexOf("<hierarchy");if(n<0)return null;let a=r.lastIndexOf("</hierarchy>");if(a<0||a<n)return null;let o=r.slice(n,a+12).trim();return o.length>0?o:null}function tA(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}function ty(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function tN(e,t){let r=eV(t);if("toggle"!==r)return r;let i=await p("adb",ej(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current Android appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
|
|
9
|
-
${
|
|
10
|
-
${t}
|
|
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}
|
|
12
|
-
${
|
|
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,runCmdDetached as l,runCmdBackground as d,SETTINGS_INVALID_ARGS_MESSAGE as u,normalizeTenantId as c,runCmd as p,node_crypto as f,displayLabel as m,spawn as h,asAppError as w,pathToFileURL as g,AppError as I,whichCmd as v,buildSnapshotDisplayLines as A,fileURLToPath as y,runCmdStreaming as N,formatRole as S,normalizeError as _,resolveSessionIsolationMode as b,readVersion as D,findProjectRoot as E,getDiagnosticsMeta as O,withDiagnosticTimer as k,emitDiagnostic as M,DEFAULT_BATCH_MAX_STEPS as L,promises as x,isProcessAlive as C,readProcessStartTime as T,node_fs as R,withDiagnosticsScope as P,flushDiagnosticsToSessionFile as $,node_os as F,node_net as V,resolveDaemonServerMode as U,resolveDaemonPaths as G,formatSnapshotLine as B}from"./678.js";function j(e,t){return["-s",e.id,...t]}async function q(){if(!await v("adb"))throw new I("TOOL_MISSING","adb not found in PATH")}function W(e,t){let r=`${e}
|
|
2
|
+
${t}`.toLowerCase();return r.includes("no shell command implementation")||r.includes("unknown command")}async function H(e){await new Promise(t=>setTimeout(t,e))}function J(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 z(e,t){let r,i=e?.trim();return i?i:"http"===(r=t.trim().split(":")[0]?.toLowerCase())||"https"===r?"com.apple.mobilesafari":void 0}let K=X(process.env.AGENT_DEVICE_RETRY_LOGS);function X(e){return["1","true","yes","on"].includes((e??"").toLowerCase())}let Y=2e4,Z=12e4,Q=1e4;class ee{startedAtMs;expiresAtMs;constructor(e,t){this.startedAtMs=e,this.expiresAtMs=e+Math.max(0,t)}static fromTimeoutMs(e,t=Date.now()){return new ee(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 et(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()}),ei({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),ei(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),ei(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),ei(a),i)throw i;throw new I("COMMAND_FAILED","retry failed")}async function er(e,t={}){return et(()=>e(),{maxAttempts:t.attempts,baseDelayMs:t.baseDelayMs,maxDelayMs:t.maxDelayMs,jitter:t.jitter,shouldRetry:t.shouldRetry})}function ei(e){M({level:"attempt_failed"===e.event||"exhausted"===e.event?"warn":"debug",phase:"retry",data:{...e}}),K&&process.stderr.write(`[agent-device][retry] ${JSON.stringify(e)}
|
|
3
|
+
`)}let en=["AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET","IOS_SIMULATOR_DEVICE_SET"],ea=["AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST","ANDROID_DEVICE_ALLOWLIST"];function eo(e){return e?.trim()||void 0}function es(e,t){for(let r of e){let e=eo(t[r]);if(e)return e}}function el(e,t=process.env){return eo(e)??es(en,t)}function ed(e){return new Set(e.split(/[\s,]+/).map(e=>e.trim()).filter(Boolean))}function eu(e,t=process.env){let r=eo(e)??es(ea,t);if(r)return ed(r)}function ec(e){let t=e.error?w(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,u=[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&&(u.includes("runner did not accept connection")||"connect"===i&&(u.includes("timed out")||u.includes("timeout")||u.includes("econnrefused")||u.includes("connection refused")||u.includes("fetch failed")||u.includes("socket hang up")))?"IOS_RUNNER_CONNECT_TIMEOUT":"ios"===r&&"boot"===i&&(u.includes("timed out")||u.includes("timeout"))?"IOS_BOOT_TIMEOUT":"android"===r&&"boot"===i&&(u.includes("timed out")||u.includes("timeout"))?"ANDROID_BOOT_TIMEOUT":u.includes("resource temporarily unavailable")||u.includes("killed: 9")||u.includes("cannot allocate memory")||u.includes("system is low on memory")?"CI_RESOURCE_STARVATION_SUSPECTED":"android"===r&&(u.includes("device not found")||u.includes("no devices")||u.includes("device offline")||u.includes("offline")||u.includes("unauthorized")||u.includes("not authorized")||u.includes("unable to locate device")||u.includes("invalid device"))?"ADB_TRANSPORT_UNAVAILABLE":t?.code==="COMMAND_FAILED"||u.length>0?"BOOT_COMMAND_FAILED":"UNKNOWN"}function ep(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 ef=["android.software.leanback","android.software.leanback_only","android.hardware.type.television"];function em(e){return`${e.stdout}
|
|
4
|
+
${e.stderr}`}function eh(e,t){return["-s",e,...t]}function ew(e){return e.startsWith("emulator-")}function eg(e){return e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim()}async function eI(e,t=Q){return p("adb",eh(e,["shell","getprop","sys.boot_completed"]),{allowFailure:!0,timeoutMs:t})}async function ev(e,t){let r=t.replace(/_/g," ").trim();if(!ew(e))return r||e;let i=await eA(e);return i?i.replace(/_/g," "):r||e}async function eA(e){for(let t of["ro.boot.qemu.avd_name","persist.sys.avd_name"]){let r=await p("adb",eh(e,["shell","getprop",t]),{allowFailure:!0,timeoutMs:1500}),i=r.stdout.trim();if(0===r.exitCode&&i.length>0)return i}let t=await p("adb",eh(e,["emu","avd","name"]),{allowFailure:!0,timeoutMs:1500}),r=t.stdout.trim();if(0===t.exitCode&&r.length>0)return r}async function ey(e,t){let r=em(await p("adb",eh(e,["shell","cmd","package","has-feature",t]),{allowFailure:!0,timeoutMs:Q})).toLowerCase();return!!r.includes("true")||!r.includes("false")&&null}async function eN(e){return(await Promise.all(ef.map(async t=>await ey(e,t)))).some(e=>!0===e)}async function eS(e){var t;let r;return"tv"===((r=em(await p("adb",eh(e,["shell","getprop","ro.build.characteristics"]),{allowFailure:!0,timeoutMs:Q})).toLowerCase()).includes("tv")||r.includes("leanback")?"tv":null)||await eN(e)?"tv":(t=em(await p("adb",eh(e,["shell","pm","list","features"]),{allowFailure:!0,timeoutMs:Q})),/feature:android\.(software\.leanback(_only)?|hardware\.type\.television)\b/i.test(t))?"tv":"mobile"}async function e_(e={}){if(!await v("adb"))throw new I("TOOL_MISSING","adb not found in PATH");let t=e.serialAllowlist??eu(void 0),r=(await eb()).filter(e=>!t||t.has(e.serial));return await Promise.all(r.map(async({serial:e,rawModel:t})=>{let[r,i,n]=await Promise.all([ev(e,t),ek(e),eS(e)]);return{platform:"android",id:e,name:r,kind:ew(e)?"emulator":"device",target:n,booted:i}}))}async function eb(){return(await p("adb",["devices","-l"],{timeoutMs:Q})).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:","")}))}async function eD(){let e=await p("emulator",["-list-avds"],{allowFailure:!0,timeoutMs:Q});if(0!==e.exitCode)throw new I("COMMAND_FAILED","Failed to list Android emulator AVDs",{stdout:e.stdout,stderr:e.stderr,exitCode:e.exitCode,hint:"Verify Android emulator tooling is installed and available in PATH."});return e.stdout.split("\n").map(e=>e.trim()).filter(e=>e.length>0)}async function eE(e){let t=Date.now();for(;Date.now()-t<e.timeoutMs;){try{let t=await eO(e.avdName,e.serial);if(t)return{platform:"android",id:t,name:e.avdName,kind:"emulator",target:"mobile",booted:!1}}catch{}await new Promise(e=>setTimeout(e,1e3))}throw new I("COMMAND_FAILED","Android emulator did not appear in time",{avdName:e.avdName,serial:e.serial,timeoutMs:e.timeoutMs,hint:"Check emulator logs and verify the AVD can start from command line."})}async function eO(e,t){let r=eg(e);for(let e of(await eb()).filter(e=>(!t||e.serial===t)&&ew(e.serial)))if(eg(e.rawModel)===r||eg(await ev(e.serial,e.rawModel))===r)return e.serial}async function ek(e){try{let t=await eI(e);return"1"===t.stdout.trim()}catch{return!1}}async function eM(e){var t,r;let i,n=e.avdName.trim();if(!n)throw new I("INVALID_ARGS","Android emulator boot requires a non-empty AVD name.");let a=e.timeoutMs??12e4;if(!await v("adb"))throw new I("TOOL_MISSING","adb not found in PATH");if(!await v("emulator"))throw new I("TOOL_MISSING","emulator not found in PATH");let o=await eD(),s=function(e,t){let r=e.find(e=>e===t);if(r)return r;let i=eg(t);return e.find(e=>eg(e)===i)}(o,n);if(!s)throw new I("DEVICE_NOT_FOUND",`No Android emulator AVD named ${e.avdName}`,{requestedAvdName:n,availableAvds:o,hint:"Run `emulator -list-avds` and pass an existing AVD name to --device."});let d=Date.now(),u=(t=await e_(),r=e.serial,i=eg(s),t.find(e=>"android"===e.platform&&"emulator"===e.kind&&(!r||e.id===r)&&eg(e.name)===i));if(!u){let t=["-avd",s];e.headless&&t.push("-no-window","-no-audio"),l("emulator",t)}let c=u??await eE({avdName:s,serial:e.serial,timeoutMs:a}),p=Math.max(1e3,a-(Date.now()-d));await eL(c.id,p);let f=(await e_()).find(e=>e.id===c.id);return f?{...f,name:s,booted:!0}:{...c,name:s,booted:!0}}async function eL(e,t=6e4){let r,i=ee.fromTimeoutMs(t),n=Math.max(1,Math.ceil(t/1e3)),a=!1;try{await et(async({deadline:n})=>{if(n?.isExpired())throw a=!0,new I("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 eI(e,Math.min(o,Q));if(r=s,"1"!==s.stdout.trim())throw new I("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=ec({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=>ec({error:e,stdout:r?.stdout,stderr:r?.stderr,context:{platform:"android",phase:"boot"}})})}catch(c){let n=w(c),o=r?.stdout,s=r?.stderr,l=r?.exitCode,d=ec({error:c,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 u={serial:e,timeoutMs:t,elapsedMs:i.elapsedMs(),reason:d,hint:ep(d),stdout:o,stderr:s,exitCode:l};if(a||"ANDROID_BOOT_TIMEOUT"===d)throw new I("COMMAND_FAILED","Android device did not finish booting in time",u);if("TOOL_MISSING"===n.code)throw new I("TOOL_MISSING",n.message,{...u,...n.details??{}});if("ADB_TRANSPORT_UNAVAILABLE"===d)throw new I("COMMAND_FAILED",n.message,{...u,...n.details??{}});throw new I(n.code,n.message,{...u,...n.details??{}},n.cause)}}let ex={settings:{type:"intent",value:"android.settings.SETTINGS"}},eC="android.intent.category.LAUNCHER",eT="android.intent.category.LEANBACK_LAUNCHER",eR="android.intent.category.DEFAULT";async function eP(e,t){let r=t.trim();if(r.includes("."))return{type:"package",value:r};let i=ex[r.toLowerCase()];if(i)return i;let n=(await p("adb",j(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 I("INVALID_ARGS",`Multiple packages matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No package found matching "${t}"`)}async function e$(e,t="all"){let r=await eF(e);return("user-installed"===t?(await eU(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 eF(e){let t=new Set;for(let r of eV(e,{includeFallbackWhenUnknown:!0})){let i=await p("adb",j(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 eV(e,t={}){return"tv"===e.target?[eT]:"mobile"===e.target?[eC]:t.includeFallbackWhenUnknown?[eC,eT]:[eC]}async function eU(e){return(await p("adb",j(e,["shell","pm","list","packages","-3"]))).stdout.split("\n").map(e=>e.replace("package:","").trim()).filter(Boolean)}async function eG(e){let t=await eB(e,[["shell","dumpsys","window","windows"],["shell","dumpsys","window"]]);if(t)return t;let r=await eB(e,[["shell","dumpsys","activity","activities"],["shell","dumpsys","activity"]]);return r||{}}async function eB(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",j(e,r),{allowFailure:!0})).stdout??"");if(t)return t}return null}async function ej(e,t,r){var i,n;let a;e.booted||await eL(e.id);let o=t.trim();if(J(o)){if(r)throw new I("INVALID_ARGS","Activity override is not supported when opening a deep link URL");await p("adb",j(e,["shell","am","start","-W","-a","android.intent.action.VIEW","-d",o]));return}let s=await eP(e,t),l=eV(e)[0]??eC;if("intent"===s.type){if(r)throw new I("INVALID_ARGS","Activity override requires a package name, not an intent");await p("adb",j(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",j(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eR,"-c",l,"-n",t]));return}let d=await p("adb",j(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eR,"-c",l,"-p",s.value]),{allowFailure:!0});if(0===d.exitCode&&(i=d.stdout,n=d.stderr,a=`${i}
|
|
5
|
+
${n}`,!/Error:.*(?:Activity not started|unable to resolve Intent)/i.test(a)))return;let u=await eq(e,s.value);if(!u)throw new I("COMMAND_FAILED",`Failed to launch ${s.value}`,{stdout:d.stdout,stderr:d.stderr});await p("adb",j(e,["shell","am","start","-W","-a","android.intent.action.MAIN","-c",eR,"-c",l,"-n",u]))}async function eq(e,t){for(let r of Array.from(new Set(eV(e,{includeFallbackWhenUnknown:!0})))){let i=await p("adb",j(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 eW(e){e.booted||await eL(e.id)}async function eH(e,t){if("settings"===t.trim().toLowerCase())return void await p("adb",j(e,["shell","am","force-stop","com.android.settings"]));let r=await eP(e,t);if("intent"===r.type)throw new I("INVALID_ARGS","Close requires a package name, not an intent");await p("adb",j(e,["shell","am","force-stop",r.value]))}async function eJ(e,t){let r=await eP(e,t);if("intent"===r.type)throw new I("INVALID_ARGS","App uninstall requires a package name, not an intent");let i=await p("adb",j(e,["uninstall",r.value]),{allowFailure:!0});if(0!==i.exitCode){let e=`${i.stdout}
|
|
6
|
+
${i.stderr}`.toLowerCase();if(!e.includes("unknown package")&&!e.includes("not installed"))throw new I("COMMAND_FAILED",`adb uninstall failed for ${r.value}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return{package:r.value}}let ez=null;async function eK(){let e=`${process.env.PATH??""}::${process.env.AGENT_DEVICE_BUNDLETOOL_JAR??""}`;if(ez?.key===e)return ez.invocation;if(await v("bundletool")){let t={cmd:"bundletool",prefixArgs:[]};return ez={key:e,invocation:t},t}let t=process.env.AGENT_DEVICE_BUNDLETOOL_JAR?.trim();if(!t)throw new I("TOOL_MISSING","bundletool not found in PATH. Install bundletool or set AGENT_DEVICE_BUNDLETOOL_JAR to a bundletool-all.jar path.");try{await x.access(t)}catch{throw new I("TOOL_MISSING",`AGENT_DEVICE_BUNDLETOOL_JAR points to a missing file: ${t}`)}let r={cmd:"java",prefixArgs:["-jar",t]};return ez={key:e,invocation:r},r}async function eX(e){let t=await eK();await p(t.cmd,[...t.prefixArgs,...e])}async function eY(e,t){let r,i=await x.mkdtemp(n.join(F.tmpdir(),"agent-device-aab-")),a=n.join(i,"bundle.apks"),o=(r=process.env.AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE?.trim())&&r.length>0?r:"universal";try{await eX(["build-apks","--bundle",t,"--output",a,"--mode",o]),await eX(["install-apks","--apks",a,"--device-id",e.id])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function eZ(e,t){".aab"===n.extname(t).toLowerCase()?await eY(e,t):await p("adb",j(e,["install","-r",t]))}async function eQ(e,t){e.booted||await eL(e.id),await eZ(e,t)}async function e0(e,t,r){e.booted||await eL(e.id);let{package:i}=await eJ(e,t);return await eZ(e,r),{package:i}}function e1(e){let t=e2(e),r=e=>{let r=e3(t,e);if(null!==r)return"true"===r};return{text:e3(t,"text"),desc:e3(t,"content-desc"),resourceId:e3(t,"resource-id"),className:e3(t,"class"),bounds:e3(t,"bounds"),clickable:r("clickable"),enabled:r("enabled"),focusable:r("focusable"),focused:r("focused")}}function e2(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 e3(e,t){return e.get(t)??null}function e4(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 e8(e){return e?e.toLowerCase():""}function e5(e){let t=e.trim();return!!t&&/^[\w.]+:id\/[\w.-]+$/i.test(t)}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=e1(t),o=e4(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,u=e=>{let t=d.get(e);if(void 0!==t)return t;for(let t of e.children)if(t.hittable||u(t))return d.set(e,!0),!0;return d.set(e,!1),!1},c=(e,t,i,s=!1,l=!1)=>{var d,p,f,m,h,w;let g,I,v,A,y,N,S,_;if(n.length>=800){a=!0;return}if(t>o)return;let b=!!r.raw||(d=e,p=r,f=s,m=u(e),h=l,I=e8(d.type),v=!!(d.label&&d.label.trim().length>0),A=!!(d.identifier&&d.identifier.trim().length>0),y=v&&!e5(d.label??""),N=A&&!e5(d.identifier??""),S=(g=(w=I).split(".").pop()??w).includes("layout")||"viewgroup"===g||"view"===g,_="imageview"===I||"imagebutton"===I,p.interactiveOnly?!!d.hittable||!!(y||N)&&!_&&(!S||!!h)&&(f||m||h):p.compact?y||N||!!d.hittable:!S&&!_||!!d.hittable||!!y||!!N&&!!m||m),D=i;b&&(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 E=s||!!e.hittable,O=l||function(e){if(!e)return!1;let t=e8(e);return t.includes("recyclerview")||t.includes("listview")||t.includes("gridview")}(e.type);for(let r of e.children)if(c(r,t+1,D,E,O),a)return};for(let e of l)if(c(e,0,void 0,!1,!1),a)break;return a?{nodes:n,truncated:a}:{nodes:n}}(await te(e),0,t)}let e9=Buffer.from([137,80,78,71,13,10,26,10]);async function e7(e,t){let r=await p("adb",j(e,["exec-out","screencap","-p"]),{binaryStdout:!0});if(!r.stdoutBuffer)throw new I("COMMAND_FAILED","Failed to capture screenshot");let i=r.stdoutBuffer.indexOf(e9);if(i<0)throw new I("COMMAND_FAILED","Screenshot data does not contain a valid PNG header");let n=function(e,t){let r=t+e9.length;for(;r+8<=e.length;){let t=e.readUInt32BE(r),i=r+4,n=e.toString("ascii",i,i+4),a=r+12+t;if(a>e.length)break;if("IEND"===n)return a;r=a}return null}(r.stdoutBuffer,i);if(!n)throw new I("COMMAND_FAILED","Screenshot data does not contain a complete PNG payload");await x.writeFile(t,r.stdoutBuffer.subarray(i,n))}async function te(e){return er(()=>tt(e),{shouldRetry:ti})}async function tt(e){var t,r,i;let n,a,o=await p("adb",j(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",j(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),u=await p("adb",j(e,["shell","cat",d])),c=tr(u.stdout,u.stderr);if(!c)throw new I("COMMAND_FAILED","uiautomator dump did not return XML",{stdout:u.stdout,stderr:u.stderr});return c}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 I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.details?.stderr??""}`.toLowerCase();return!!(t.includes("device offline")||t.includes("device not found")||t.includes("transport error")||t.includes("connection reset")||t.includes("broken pipe")||t.includes("timed out")||t.includes("no such file or directory"))}async function tn(e,t,r){await p("adb",j(e,["shell","input","tap",String(t),String(r)]))}async function ta(e,t,r,i,n,a=250){await p("adb",j(e,["shell","input","swipe",String(t),String(r),String(i),String(n),String(a)]))}async function to(e){await p("adb",j(e,["shell","input","keyevent","4"]))}async function ts(e){await p("adb",j(e,["shell","input","keyevent","3"]))}async function tl(e){await p("adb",j(e,["shell","input","keyevent","187"]))}async function td(e,t,r,i=800){await p("adb",j(e,["shell","input","swipe",String(t),String(r),String(t),String(r),String(i)]))}async function tu(e,t){let r=tg(t);if(!r||"ok"!==await tI(e,t))try{let r=t.replace(/ /g,"%s");await p("adb",j(e,["shell","input","text",r]))}catch(e){if(r&&function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return!!(t.includes("exception occurred while executing 'text'")||t.includes("nullpointerexception")&&t.includes("inputshellcommand.sendtext"))}(e))throw new I("COMMAND_FAILED","Non-ASCII text input is not supported on this Android shell. Install an ADB keyboard IME or use ASCII input.",{textPreview:t.slice(0,32)},e instanceof Error?e:void 0);throw e}}async function tc(e,t,r){await tn(e,t,r)}async function tp(e,t,r,i){let n=Array.from(i).length,a=tg(i),o=[{strategy:"input_text",clearPadding:12,minClear:8,maxClear:48}];a||(o.push({strategy:"clipboard_paste",clearPadding:12,minClear:8,maxClear:48}),o.push({strategy:"chunked_input",clearPadding:24,minClear:16,maxClear:96}));let s=null;for(let a of o){var l,d;await tc(e,t,r);let o=(l=n+a.clearPadding,d=a.minClear,Math.max(d,Math.min(a.maxClear,l)));if(await tv(e,o),"input_text"===a.strategy)await tu(e,i);else if("clipboard_paste"===a.strategy){if("ok"!==await tI(e,i))continue}else await tw(e,i,1,15);if((s=await tA(e,t,r))===i)return}throw new I("COMMAND_FAILED","Android fill verification failed",{expected:i,actual:s??null})}async function tf(e,t,r=.6){let{width:i,height:n}=await th(e),a=Math.floor(i*r),o=Math.floor(n*r),s=Math.floor(i/2),l=Math.floor(n/2),d=s,u=l,c=s,f=l;switch(t){case"up":u=l-Math.floor(o/2),f=l+Math.floor(o/2);break;case"down":u=l+Math.floor(o/2),f=l-Math.floor(o/2);break;case"left":d=s-Math.floor(a/2),c=s+Math.floor(a/2);break;case"right":d=s+Math.floor(a/2),c=s-Math.floor(a/2);break;default:throw new I("INVALID_ARGS",`Unknown direction: ${t}`)}await p("adb",j(e,["shell","input","swipe",String(d),String(u),String(c),String(f),"300"]))}async function tm(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 I("UNSUPPORTED_OPERATION",`uiautomator dump failed: ${e}`)}if(function(e,t){let r=t.toLowerCase(),i=/<node[^>]+>/g,n=i.exec(e);for(;n;){let t=e2(n[0]),a=(e3(t,"text")??"").toLowerCase(),o=(e3(t,"content-desc")??"").toLowerCase();if(a.includes(r)||o.includes(r)){let e=e4(e3(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 tf(e,"down",.5)}throw new I("COMMAND_FAILED",`Could not find element containing "${t}" after scrolling`)}async function th(e){let t=(await p("adb",j(e,["shell","wm","size"]))).stdout.match(/Physical size:\s*(\d+)x(\d+)/);if(!t)throw new I("COMMAND_FAILED","Unable to read screen size");return{width:Number(t[1]),height:Number(t[2])}}async function tw(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 tu(e,r),i>0&&t+n<a.length&&await H(i)}}function tg(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 tI(e,t){let r=await p("adb",j(e,["shell","cmd","clipboard","set","text",t]),{allowFailure:!0});return 0!==r.exitCode?"failed":W(r.stdout,r.stderr)?"unsupported":0===(await p("adb",j(e,["shell","input","keyevent","KEYCODE_PASTE"]),{allowFailure:!0})).exitCode||0===(await p("adb",j(e,["shell","input","keyevent","279"]),{allowFailure:!0})).exitCode?"ok":"failed"}async function tv(e,t){let r=Math.max(0,t);await p("adb",j(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",j(e,["shell","input","keyevent",...Array(i).fill("KEYCODE_DEL")]),{allowFailure:!0})}}async function tA(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=e1(i[0]),n=e4(e.bounds);if(!n)continue;let a=e.className??"",d=(e.text??"").replace(/"/g,'"').replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&"),u=e.focused??!1;if(!d)continue;let c=Math.max(1,n.width*n.height),p=t>=n.x&&t<=n.x+n.width&&r>=n.y&&r<=n.y+n.height;if(u&&ty(a)){(!o||c<=o.area)&&(o={text:d,area:c});continue}if(p&&ty(a)){(!s||c<=s.area)&&(s={text:d,area:c});continue}p&&(!l||c<=l.area)&&(l={text:d,area:c})}return o?.text??s?.text??l?.text??null}function ty(e){let t=e.toLowerCase();return t.includes("edittext")||t.includes("textfield")}async function tN(e){let t=await p("adb",j(e,["shell","dumpsys","input_method"]),{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to query Android keyboard state",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return function(e){let t=function(e){let t=new Map;for(let r of e.matchAll(/\b(mInputShown|mIsInputViewShown|isInputViewShown)=([a-zA-Z]+)\b/g)){let e=r[1],i=r[2]?.toLowerCase();e&&("true"===i||"false"===i)&&t.set(e,"true"===i)}if(0===t.size)return null;for(let e of t.values())if(e)return!0;return!1}(e),r=t??!1;if(null===t){let t=e.match(/\bmImeWindowVis=0x([0-9a-fA-F]+)\b/);if(t?.[1]){let e=Number.parseInt(t[1],16);Number.isNaN(e)||(r=(1&e)!=0)}}let i=Array.from(e.matchAll(/\binputType=0x([0-9a-fA-F]+)\b/gi)),n=i.length>0?i[i.length-1]?.[1]:void 0,a=n?`0x${n.toLowerCase()}`:void 0;return{visible:r,inputType:a,type:a?function(e){let t=Number.parseInt(e.replace(/^0x/i,""),16);if(Number.isNaN(t))return"unknown";let r=15&t;if(2===r)return"number";if(3===r)return"phone";if(4===r)return"datetime";if(1!==r)return"unknown";let i=4080&t;return 32===i||208===i?"email":128===i||224===i||144===i?"password":"text"}(a):void 0}}(t.stdout)}async function tS(e){let t=await tN(e),r=t,i=0;for(;r.visible&&i<2;)await to(e),i+=1,await H(120),r=await tN(e);return{attempts:i,wasVisible:t.visible,dismissed:t.visible&&!r.visible,visible:r.visible,inputType:r.inputType,type:r.type}}async function t_(e){let t,r;return(r=(t=(await tD(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 tb(e,t){await tD(e,["shell","cmd","clipboard","set","text",t],"write")}async function tD(e,t,r){let i=await p("adb",j(e,t),{allowFailure:!0});if(W(i.stdout,i.stderr))throw new I("UNSUPPORTED_OPERATION",`Android shell clipboard ${r} is not supported on this device.`);if(0!==i.exitCode)throw new I("COMMAND_FAILED",`Failed to ${r} Android clipboard text`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return i.stdout}let tE=["camera","microphone","photos","contacts","contacts-limited","notifications","calendar","location","location-always","media-library","motion","reminders","siri"];function tO(e){let t=e.trim().toLowerCase();if("grant"===t)return"grant";if("deny"===t)return"deny";if("reset"===t)return"reset";throw new I("INVALID_ARGS",`Invalid permission action: ${e}. Use grant|deny|reset.`)}function tk(e){let t=e?.trim().toLowerCase();if("camera"===t||"microphone"===t||"photos"===t||"contacts"===t||"contacts-limited"===t||"notifications"===t||"calendar"===t||"location"===t||"location-always"===t||"media-library"===t||"motion"===t||"reminders"===t||"siri"===t)return t;throw new I("INVALID_ARGS",`permission setting requires a target: ${tE.join("|")}`)}function tM(e){let t=e.trim().toLowerCase();if("light"===t)return"light";if("dark"===t)return"dark";if("toggle"===t)return"toggle";throw new I("INVALID_ARGS",`Invalid appearance state: ${e}. Use light|dark|toggle.`)}async function tL(e,t,r,i,n){switch(t.toLowerCase()){case"wifi":{let t=tC(r);await p("adb",j(e,["shell","svc","wifi",t?"enable":"disable"]));return}case"airplane":{let t=tC(r);await p("adb",j(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"])),await p("adb",j(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]));return}case"location":{let t=tC(r);await p("adb",j(e,["shell","settings","put","secure","location_mode",t?"3":"0"]));return}case"appearance":{let t=await tT(e,r);await p("adb",j(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]));return}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new I("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await tx(e,t);return}case"permission":{if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t=tO(r),a=function(e,t){let r=tk(e);if(t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return{kind:"pm",value:"android.permission.CAMERA",type:"camera"};if("microphone"===r)return{kind:"pm",value:"android.permission.RECORD_AUDIO",type:"microphone"};if("photos"===r)return{kind:"pm",value:"android.permission.READ_MEDIA_IMAGES",type:"photos"};if("contacts"===r)return{kind:"pm",value:"android.permission.READ_CONTACTS",type:"contacts"};if("notifications"===r)return{kind:"notifications",appOps:"POST_NOTIFICATION",permission:"android.permission.POST_NOTIFICATIONS"};throw new I("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(n?.permissionTarget,n?.permissionMode);if("notifications"===a.kind)return void await tP(e,i,t,a);let o="grant"===t?"grant":"revoke";if("photos"===a.type)return void await tR(e,i,o);await p("adb",j(e,["shell","pm",o,i,a.value]));return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function tx(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",j(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}
|
|
9
|
+
${r}`.toLowerCase()).includes("unknown command")||i.includes("can't find service: fingerprint")||i.includes("service fingerprint was not found")||i.includes("fingerprint cmd unavailable")||i.includes("emu command is not supported")||i.includes("emulator console is not running")||i.includes("fingerprint")&&i.includes("not found")}))throw new I("UNSUPPORTED_OPERATION","Android fingerprint simulation is not supported on this target/runtime.",{deviceId:e.id,action:t,hint:"Use an Android emulator with biometric support, or a device/runtime that exposes cmd fingerprint.",attempts:s});throw new I("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:s})}function tC(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function tT(e,t){let r=tM(t);if("toggle"!==r)return r;let i=await p("adb",j(e,["shell","cmd","uimode","night"]),{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current Android appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
|
|
10
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"yes"===i?"dark":"no"===i?"light":"auto"===i?"auto":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current Android appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"auto"===n?"dark":"dark"===n?"light":"dark"}async function tR(e,t,r){let i=await t$(e),n=[];for(let a of null!==i&&i>=33?["android.permission.READ_MEDIA_IMAGES","android.permission.READ_EXTERNAL_STORAGE"]:["android.permission.READ_EXTERNAL_STORAGE","android.permission.READ_MEDIA_IMAGES"]){let i=await p("adb",j(e,["shell","pm",r,t,a]),{allowFailure:!0});if(0===i.exitCode)return;n.push({permission:a,stderr:i.stderr,exitCode:i.exitCode})}throw new I("COMMAND_FAILED",`Failed to ${r} Android photos permission`,{appPackage:t,sdkInt:i,attempts:n})}async function tP(e,t,r,i){"grant"===r?await p("adb",j(e,["shell","pm","grant",t,i.permission]),{allowFailure:!0}):(await p("adb",j(e,["shell","pm","revoke",t,i.permission]),{allowFailure:!0}),"reset"===r&&(await p("adb",j(e,["shell","pm","clear-permission-flags",t,i.permission,"user-set"]),{allowFailure:!0}),await p("adb",j(e,["shell","pm","clear-permission-flags",t,i.permission,"user-fixed"]),{allowFailure:!0}))),await p("adb",j(e,["shell","appops","set",t,i.appOps,"grant"===r?"allow":"deny"===r?"deny":"default"]))}async function t$(e){let t=await p("adb",j(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 tF(e,t,r){let i="string"==typeof r.action&&r.action.trim()?r.action.trim():`${t}.TEST_PUSH`,n=["shell","am","broadcast","-a",i,"-p",t],a="string"==typeof r.receiver?r.receiver.trim():"";a&&n.push("-n",a);let o=r.extras;if(void 0!==o&&("object"!=typeof o||null===o||Array.isArray(o)))throw new I("INVALID_ARGS","Android push payload extras must be an object");let s=0;for(let[e,t]of Object.entries(o??{}))e&&(function(e,t,r){if("string"==typeof r)return e.push("--es",t,r);if("boolean"==typeof r)return e.push("--ez",t,r?"true":"false");if("number"==typeof r&&Number.isFinite(r))return Number.isInteger(r)?e.push("--ei",t,String(r)):e.push("--ef",t,String(r));throw new I("INVALID_ARGS",`Unsupported Android broadcast extra type for "${t}". Use string, boolean, or number.`)}(n,e,t),s+=1);return await p("adb",j(e,n)),{action:i,extrasCount:s}}function tV(e,t,r){if(!e)return t;let i=Number(e);return Number.isFinite(i)?Math.max(r,Math.floor(i)):t}let tU=tV(process.env.AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS,Z,5e3),tG=tV(process.env.AGENT_DEVICE_IOS_SIMCTL_LIST_TIMEOUT_MS,Y,1e3),tB=tV(process.env.AGENT_DEVICE_IOS_APP_LAUNCH_TIMEOUT_MS,3e4,5e3),tj=tV(process.env.AGENT_DEVICE_IOS_DEVICECTL_TIMEOUT_MS,2e4,1e3),tq=tV(process.env.AGENT_DEVICE_IOS_SIMULATOR_SCREENSHOT_TIMEOUT_MS,2e4,1e3),tW=tV(process.env.AGENT_DEVICE_IOS_RUNNER_SCREENSHOT_COPY_TIMEOUT_MS,2e4,1e3);async function tH(e,t){let r=["devicectl",...e],i=await p("xcrun",r,{allowFailure:!0,timeoutMs:tj});if(0===i.exitCode)return;let n=String(i.stdout??""),a=String(i.stderr??"");throw new I("COMMAND_FAILED",`Failed to ${t.action}`,{cmd:"xcrun",args:r,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:t.deviceId,hint:tK(n,a)??tz})}async function tJ(e,t){let r=n.join(F.tmpdir(),`agent-device-ios-apps-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),i=["devicectl","device","info","apps","--device",e.id,"--include-all-apps","--json-output",r],a=await p("xcrun",i,{allowFailure:!0,timeoutMs:tj});try{var o,s;if(0!==a.exitCode){let t=String(a.stdout??""),r=String(a.stderr??"");throw new I("COMMAND_FAILED","Failed to list iOS apps",{cmd:"xcrun",args:i,exitCode:a.exitCode,stdout:t,stderr:r,deviceId:e.id,hint:tK(t,r)??tz})}let n=await x.readFile(r,"utf8");return o=function(e){let t=e?.result?.apps;if(!Array.isArray(t))return[];let r=[];for(let e of t){if(!e||"object"!=typeof e)continue;let t="string"==typeof e.bundleIdentifier?e.bundleIdentifier.trim():"";if(!t)continue;let i="string"==typeof e.name&&e.name.trim().length>0?e.name.trim():t;r.push({bundleId:t,name:i})}return r}(JSON.parse(n)),s=t,"user-installed"===s?o.filter(e=>!e.bundleId.startsWith("com.apple.")):o}catch(t){if(t instanceof I)throw t;throw new I("COMMAND_FAILED","Failed to parse iOS apps list",{deviceId:e.id,cause:String(t)})}finally{await x.unlink(r).catch(()=>{})}}let tz="Ensure the iOS device is unlocked, trusted, and available in Xcode > Devices, then retry.";function tK(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}function tX(e,t={}){let r=el(t.simulatorSetPath);return r?["simctl","--set",r,...e]:["simctl",...e]}function tY(e,t){return"ios"!==e.platform||"simulator"!==e.kind?["simctl",...t]:tX(t,{simulatorSetPath:e.simulatorSetPath})}function tZ(e,t){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`${t} is only supported on iOS simulators`)}async function tQ(){await p("open",["-a","Simulator"],{allowFailure:!0})}async function t0(e){let t,r;if("simulator"!==e.kind||"Booted"===await t2(e))return;let i=ee.fromTimeoutMs(tU);try{await et(async({deadline:i})=>{if(i?.isExpired())throw new I("COMMAND_FAILED","iOS simulator boot deadline exceeded",{timeoutMs:tU});let n=Math.max(1e3,i?.remainingMs()??tU),a=await p("xcrun",tY(e,["boot",e.id]),{allowFailure:!0,timeoutMs:n});t={stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode};let o=`${t.stdout}
|
|
12
|
+
${t.stderr}`.toLowerCase(),s=o.includes("already booted")||o.includes("current state: booted");if(0!==t.exitCode&&!s)throw new I("COMMAND_FAILED","simctl boot failed",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});let l=await p("xcrun",tY(e,["bootstatus",e.id,"-b"]),{allowFailure:!0,timeoutMs:n});if(r={stdout:String(l.stdout??""),stderr:String(l.stderr??""),exitCode:l.exitCode},0!==r.exitCode)throw new I("COMMAND_FAILED","simctl bootstatus failed",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode});let d=await t2(e);if("Booted"!==d)throw new I("COMMAND_FAILED","Simulator is still booting",{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let i=ec({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=>ec({error:e,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}})})}catch(a){let n=ec({error:a,stdout:r?.stdout??t?.stdout,stderr:r?.stderr??t?.stderr,context:{platform:"ios",phase:"boot"}});throw new I("COMMAND_FAILED","iOS simulator failed to boot",{platform:"ios",deviceId:e.id,timeoutMs:tU,elapsedMs:i.elapsedMs(),reason:n,hint:ep(n),boot:t,bootstatus:r})}}async function t1(e){let t=tY(e,["shutdown",e.id]),r=await p("xcrun",t,{allowFailure:!0,timeoutMs:15e3});return{success:0===r.exitCode,exitCode:r.exitCode,stdout:String(r.stdout??""),stderr:String(r.stderr??"")}}async function t2(e){let t="string"==typeof e?e:e.id,r="string"==typeof e?tX(["list","devices","-j"]):tY(e,["list","devices","-j"]),i=await p("xcrun",r,{allowFailure:!0,timeoutMs:tG});if(0!==i.exitCode)return null;try{let e=JSON.parse(String(i.stdout??""));for(let r of Object.values(e.devices??{})){let e=r.find(e=>e.udid===t);if(e)return e.state}return null}catch{return null}}let t3=new Set;function t4(e){return!!e&&t3.has(e)}function t8(e){return!(e instanceof I)||"COMMAND_FAILED"!==e.code||!String(e.message??"").toLowerCase().includes("xcodebuild exited early")}function t5(e){let{port:t,endpoints:r,logPath:i,lastError:n}=e,a="Runner did not accept connection";return new I("COMMAND_FAILED",a,{port:t,endpoints:r,logPath:i,lastError:n?String(n):void 0,reason:ec({error:n,message:a,context:{platform:"ios",phase:"connect"}}),hint:ep("IOS_RUNNER_CONNECT_TIMEOUT")})}async function t6(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=ec({message:l,stdout:s.stdout,stderr:s.stderr,context:{platform:"ios",phase:"connect"}});return new I("COMMAND_FAILED",l,{port:a,logPath:o,xcodebuild:{exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr},reason:d,hint:(t=s.stdout,r=s.stderr,(i=`${l}
|
|
13
13
|
${t}
|
|
14
|
-
${r}`.toLowerCase()).includes("device is busy")&&i.includes("connecting")?"Target iOS device is still connecting. Keep it unlocked, wait for device trust/connection to settle, then retry.":
|
|
15
|
-
${
|
|
16
|
-
${
|
|
17
|
-
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function r1(e,t){"simulator"!==e.kind?await tQ(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await rj(e),await rz(e,["install",e.id,t]))}async function r2(e,t,r){let{bundleId:i}=await r0(e,t);return await r1(e,r),{bundleId:i}}async function r3(e,t,r){if("simulator"===e.kind){await rj(e),await rz(e,["io",e.id,"screenshot",t]);return}try{await tQ(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(e){if(!function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
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.":ep("IOS_RUNNER_CONNECT_TIMEOUT"))})}function t9(e){if(t4(e))throw new I("COMMAND_FAILED","request canceled")}let t7=tV(process.env.AGENT_DEVICE_RUNNER_STARTUP_TIMEOUT_MS,45e3,5e3),re=tV(process.env.AGENT_DEVICE_RUNNER_COMMAND_TIMEOUT_MS,45e3,1e3),rt=tV(process.env.AGENT_DEVICE_RUNNER_CONNECT_ATTEMPT_INTERVAL_MS,250,50),rr=tV(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_BASE_DELAY_MS,300,10),ri=tV(process.env.AGENT_DEVICE_RUNNER_CONNECT_RETRY_MAX_DELAY_MS,2e3,10),rn=tV(process.env.AGENT_DEVICE_RUNNER_CONNECT_REQUEST_TIMEOUT_MS,2e4,250),ra=tV(process.env.AGENT_DEVICE_IOS_DEVICE_INFO_TIMEOUT_MS,1e4,500),ro=tV(process.env.AGENT_DEVICE_RUNNER_DESTINATION_TIMEOUT_SECONDS,20,5);async function rs(e,t,r,i,n=t7,a){let o=ee.fromTimeoutMs(n),s=await rl(e,t,o.remainingMs()),l=null,d=Math.max(1,Math.ceil(n/rt));try{return await et(async({deadline:o})=>{if(o?.isExpired())throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});if(a&&null!==a.child.exitCode&&void 0!==a.child.exitCode)throw await t6({session:a,port:t,logPath:i});for(let i of("device"===e.kind&&(s=await rl(e,t,o?.remainingMs())),s))try{let e=o?.remainingMs()??n;if(e<=0)throw new I("COMMAND_FAILED","Runner connection deadline exceeded",{port:t,timeoutMs:n});return await rd(i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)},Math.min(rn,e))}catch(e){l=e}throw new I("COMMAND_FAILED","Runner endpoint probe failed",{port:t,endpoints:s,lastError:l?String(l):void 0})},{maxAttempts:d,baseDelayMs:rr,maxDelayMs:ri,jitter:.2,shouldRetry:t8},{deadline:o,phase:"ios_runner_connect"})}catch(e){l||(l=e)}if("simulator"===e.kind){let n=o.remainingMs();if(n<=0)throw t5({port:t,endpoints:s,logPath:i,lastError:l});let a=await rc(e,t,r,n);return new Response(a.body,{status:a.status})}throw t5({port:t,endpoints:s,logPath:i,lastError:l})}async function rl(e,t,r){let i=[`http://127.0.0.1:${t}/command`];if("device"!==e.kind)return i;let n=await ru(e.id,r);return n&&i.unshift(`http://[${n}]:${t}/command`),i}async function rd(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 ru(e,t){if("number"==typeof t&&t<=0)return null;let r="number"==typeof t?Math.max(1,Math.min(ra,t)):ra,i=n.join(F.tmpdir(),`agent-device-devicectl-info-${process.pid}-${Date.now()}.json`);try{let t=Math.max(1,Math.ceil(r/1e3)),n=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",i,"--timeout",String(t)],{allowFailure:!0,timeoutMs:r});if(0!==n.exitCode||!R.existsSync(i))return null;let a=JSON.parse(R.readFileSync(i,"utf8"));if(a.info?.outcome&&"success"!==a.info.outcome)return null;let o=(a.result?.connectionProperties?.tunnelIPAddress??a.result?.device?.connectionProperties?.tunnelIPAddress)?.trim();return o&&o.length>0?o:null}catch{return null}finally{rm(i)}}async function rc(e,t,r,i){let n=JSON.stringify(r),a=tY(e,["spawn",e.id,"/usr/bin/curl","-s","-X","POST","-H","Content-Type: application/json","--data",n,`http://127.0.0.1:${t}/command`]),o=await p("xcrun",a,{allowFailure:!0,timeoutMs:i}),s=o.stdout;if(0!==o.exitCode){let e=ec({message:"Runner did not accept connection (simctl spawn)",stdout:o.stdout,stderr:o.stderr,context:{platform:"ios",phase:"connect"}});throw new I("COMMAND_FAILED","Runner did not accept connection (simctl spawn)",{port:t,stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode,reason:e,hint:ep(e)})}return{status:200,body:s}}async function rp(){return await new Promise((e,t)=>{let r=V.createServer();r.listen(0,"127.0.0.1",()=>{let i=r.address();r.close(),"object"==typeof i&&i?.port?e(i.port):t(new I("COMMAND_FAILED","Failed to allocate port"))}),r.on("error",t)})}function rf(e,t,r,i){t&&R.appendFileSync(t,e),r&&R.appendFileSync(r,e),i&&process.stderr.write(e)}function rm(e){try{R.existsSync(e)&&R.unlinkSync(e)}catch{}}async function rh(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)})}function rw(e){return"apple"===e?"ios":e}async function rg(e,i,n={}){let a=e,o=e=>e.toLowerCase().replace(/_/g," ").replace(/\s+/g," ").trim();if(i.platform&&(a=a.filter(e=>e.platform===i.platform)),i.target&&(a=a.filter(e=>(e.target??"mobile")===i.target)),i.udid){let e=a.find(e=>e.id===i.udid&&"ios"===e.platform);if(!e)throw new I("DEVICE_NOT_FOUND",`No iOS device with UDID ${i.udid}`);return e}if(i.serial){let e=a.find(e=>e.id===i.serial&&"android"===e.platform);if(!e)throw new I("DEVICE_NOT_FOUND",`No Android device with serial ${i.serial}`);return e}if(i.deviceName){let e=o(i.deviceName),t=a.find(t=>o(t.name)===e);if(!t)throw new I("DEVICE_NOT_FOUND",`No device named ${i.deviceName}`);return t}if(1===a.length)return a[0];if(0===a.length){let e=n.simulatorSetPath;if(e&&(!i.platform||"ios"===i.platform))throw new I("DEVICE_NOT_FOUND","No devices found in the scoped simulator set",{simulatorSetPath:e,hint:`The simulator set at "${e}" appears to be empty. Create a simulator first:
|
|
15
|
+
xcrun simctl --set "${e}" create "iPhone 16" com.apple.CoreSimulator.SimDeviceType.iPhone-16 com.apple.CoreSimulator.SimRuntime.iOS-18-0`,selector:i});throw new I("DEVICE_NOT_FOUND","No devices found",{selector:i})}let s=a.filter(e=>e.booted);if(1===s.length)return s[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:(s.length>0?s:a).map(e=>({label:`${e.name} (${e.platform}${e.kind?`, ${e.kind}`:""}${e.booted?", booted":""})`,value:e.id}))});if(t(e))throw new I("INVALID_ARGS","Device selection cancelled");if(e){let t=a.find(t=>t.id===e);if(t)return t}}return s[0]??a[0]}let rI=n.join(F.homedir(),".agent-device","ios-runner"),rv=new Map,rA=new Set;function ry(e){return e?.trim()??""}function rN(e=process.env){return ry(e.AGENT_DEVICE_IOS_BUNDLE_ID)||ry(e.AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID)||"com.callstack.agentdevice.runner"}function rS(e=process.env){let t=ry(e.AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID);return t||`${rN(e)}.uitests`}let r_=function(e=process.env){let t=rN(e),r=rS(e);return Array.from(new Set([ry(e.AGENT_DEVICE_IOS_RUNNER_CONTAINER_BUNDLE_ID),`${r}.xctrunner`,t].filter(e=>e.length>0)))}(process.env);async function rb(e,t){var r;let i,a=(r=e.kind,(i=process.env.AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH?.trim())?n.resolve(i):"simulator"===r?n.join(rI,"derived"):n.join(rI,"derived",r));return await rh(rv,a,async()=>{if(X(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 X(e.AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN)}(t))throw new I("COMMAND_FAILED","Refusing to clean AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH automatically",{derivedPath:e,hint:"Unset AGENT_DEVICE_IOS_CLEAN_DERIVED, or set AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1 if you trust this path."})}(a);try{R.rmSync(a,{recursive:!0,force:!0})}catch{}}let r=rD(a);if(r)return r;let i=function(){let e=n.dirname(y(import.meta.url)),t=e;for(let e=0;e<6;e+=1){let e=n.join(t,"package.json");if(R.existsSync(e))return t;t=n.dirname(t)}return e}(),o=n.join(i,"ios-runner","AgentDeviceRunner","AgentDeviceRunner.xcodeproj");if(!R.existsSync(o))throw new I("COMMAND_FAILED","iOS runner project not found",{projectPath:o});let s=function(e=process.env){let t=rN(e),r=rS(e);return[`AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID=${t}`,`AGENT_DEVICE_IOS_RUNNER_TEST_BUNDLE_ID=${r}`]}(process.env),l=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),d="device"===e.kind?["-allowProvisioningUpdates"]:[];try{var u;let r;await N("xcodebuild",["build-for-testing","-project",o,"-scheme","AgentDeviceRunner","-parallel-testing-enabled","NO",rk(e),"1","-destination",(u=e,r=rO(u),"simulator"===u.kind?`platform=${r} Simulator,id=${u.id}`:`generic/platform=${r}`),"-derivedDataPath",a,"COMPILER_INDEX_STORE_ENABLE=NO",...s,...d,...l],{detached:!0,onSpawn:e=>{rA.add(e),e.on("close",()=>{rA.delete(e)})},onStdoutChunk:e=>{rf(e,t.logPath,t.traceLogPath,t.verbose)},onStderrChunk:e=>{rf(e,t.logPath,t.traceLogPath,t.verbose)}})}catch(a){let e,r,i=a instanceof I?a:new I("COMMAND_FAILED",String(a)),n=(e=i.details?JSON.stringify(i.details):"",(r=`${i.message}
|
|
16
|
+
${e}`.toLowerCase()).includes("failed registering bundle identifier")||r.includes("app identifier")&&r.includes("not available")?"Set AGENT_DEVICE_IOS_BUNDLE_ID to a unique reverse-DNS value (for example, com.yourname.agentdevice.runner), then retry.":r.includes("requires a development team")?"Configure signing in Xcode or set AGENT_DEVICE_IOS_TEAM_ID for physical-device runs.":r.includes("no profiles for")||r.includes("provisioning profile")?"Install/select a valid iOS provisioning profile, or set AGENT_DEVICE_IOS_PROVISIONING_PROFILE.":r.includes("code signing")?"Enable Automatic Signing in Xcode or provide AGENT_DEVICE_IOS_TEAM_ID and optional AGENT_DEVICE_IOS_SIGNING_IDENTITY.":void 0);throw new I("COMMAND_FAILED","xcodebuild build-for-testing failed",{error:i.message,details:i.details,logPath:t.logPath,hint:n})}let c=rD(a);if(!c)throw new I("COMMAND_FAILED","Failed to locate .xctestrun after build");return c})}function rD(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)}async function rE(e,t,r){let i,a=n.dirname(e),o=r.replace(/[^a-zA-Z0-9._-]/g,"_"),s=n.join(a,`AgentDeviceRunner.env.${o}.json`),l=n.join(a,`AgentDeviceRunner.env.${o}.xctestrun`),d=await p("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==d.exitCode||!d.stdout.trim())throw new I("COMMAND_FAILED","Failed to read xctestrun plist",{xctestrunPath:e,stderr:d.stderr});try{i=JSON.parse(d.stdout)}catch(t){throw new I("COMMAND_FAILED","Failed to parse xctestrun JSON",{xctestrunPath:e,error:String(t)})}let u=e=>{e.EnvironmentVariables={...e.EnvironmentVariables??{},...t},e.UITestEnvironmentVariables={...e.UITestEnvironmentVariables??{},...t},e.UITargetAppEnvironmentVariables={...e.UITargetAppEnvironmentVariables??{},...t},e.TestingEnvironmentVariables={...e.TestingEnvironmentVariables??{},...t}},c=i.TestConfigurations;if(Array.isArray(c))for(let e of c){if(!e||"object"!=typeof e)continue;let t=e.TestTargets;if(Array.isArray(t))for(let e of t)e&&"object"==typeof e&&u(e)}for(let[e,t]of Object.entries(i))t&&"object"==typeof t&&t.TestBundlePath&&(u(t),i[e]=t);R.writeFileSync(s,JSON.stringify(i,null,2));let f=await p("plutil",["-convert","xml1","-o",l,s],{allowFailure:!0});if(0!==f.exitCode)throw new I("COMMAND_FAILED","Failed to write xctestrun plist",{tmpXctestrunPath:l,stderr:f.stderr});return{xctestrunPath:l,jsonPath:s}}function rO(e){if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);return"tv"===e.target?"tvOS":"iOS"}function rk(e){return"device"===e.kind?"-maximum-concurrent-test-device-destinations":"-maximum-concurrent-test-simulator-destinations"}let rM=new Map,rL=new Map;async function rx(e,t){return await rh(rL,e.id,async()=>{var r,i;let n,a=rM.get(e.id);if(a){if((r=a.child.pid)&&C(r))return a;await rT(e.id,a)}await ("simulator"!==(i=e).kind?Promise.resolve():rV(i));let o=await rb(e,t),s=await rp(),{xctestrunPath:l,jsonPath:u}=await rE(o,{AGENT_DEVICE_RUNNER_PORT:String(s)},`session-${e.id}-${s}`),{child:c,wait:p}=d("xcodebuild",["test-without-building","-only-testing","AgentDeviceRunnerUITests/RunnerTests/testCommand","-parallel-testing-enabled","NO","-test-timeouts-enabled","NO","-collect-test-diagnostics","never",rk(e),"1","-destination-timeout",String(ro),"-xctestrun",l,"-destination",(n=rO(e),"simulator"===e.kind?`platform=${n} Simulator,id=${e.id}`:`platform=${n},id=${e.id}`)],{allowFailure:!0,env:{...process.env,AGENT_DEVICE_RUNNER_PORT:String(s)},detached:!0});c.stdout?.on("data",e=>{rf(e,t.logPath,t.traceLogPath,t.verbose)}),c.stderr?.on("data",e=>{rf(e,t.logPath,t.traceLogPath,t.verbose)});let f={device:e,deviceId:e.id,port:s,xctestrunPath:l,jsonPath:u,testPromise:p,child:c,ready:!1};return rM.set(e.id,f),f})}async function rC(e){await rh(rL,e.deviceId,async()=>{await rT(e.deviceId,e)})}async function rT(e,t){let r=t??rM.get(e);if(r){try{await rs(r.device,r.port,{command:"shutdown"},void 0,15e3)}catch{await rF(r.child.pid,"SIGTERM")}try{await Promise.race([r.testPromise,new Promise(e=>setTimeout(e,1e4))])}catch{}await rF(r.child.pid,"SIGKILL"),rm(r.xctestrunPath),rm(r.jsonPath),rM.get(e)===r&&rM.delete(e)}}async function rR(e){await rh(rL,e,async()=>{await rT(e)})}async function rP(){let e=Array.from(rM.values()),t=Array.from(rA);await Promise.allSettled(e.map(async e=>{await rF(e.child.pid,"SIGINT")})),await Promise.allSettled(t.map(async e=>{await rF(e.pid,"SIGINT")})),await Promise.allSettled(e.map(async e=>{await rF(e.child.pid,"SIGTERM")})),await Promise.allSettled(t.map(async e=>{await rF(e.pid,"SIGTERM")})),await Promise.allSettled(e.map(async e=>{await rF(e.child.pid,"SIGKILL")})),await Promise.allSettled(t.map(async e=>{await rF(e.pid,"SIGKILL"),rA.delete(e)}))}async function r$(){await rP();let e=Array.from(rM.keys());await Promise.allSettled(e.map(async e=>{await rR(e)}));let t=Array.from(rA);await Promise.allSettled(t.map(async e=>{try{await rF(e.pid,"SIGTERM"),await rF(e.pid,"SIGKILL")}finally{rA.delete(e)}}))}async function rF(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 rV(e){await p("xcrun",tY(e,["bootstatus",e.id,"-b"]),{timeoutMs:t7})}async function rU(e,t,r,i,n){let a=await rs(e,t.port,r,i,n,t);return await rG(a,t,i)}async function rG(e,t,r){let i=await e.text(),n={};try{n=JSON.parse(i)}catch{throw new I("COMMAND_FAILED","Invalid runner response",{text:i})}if(!n.ok)throw new I("COMMAND_FAILED",n.error?.message??"Runner error",{runner:n,xcodebuild:{exitCode:1,stdout:"",stderr:""},logPath:r});return t.ready=!0,n.data??{}}async function rB(e,t,r={}){var i;if("ios"!==e.platform)throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform for iOS runner: ${e.platform}`);if("simulator"!==e.kind&&"device"!==e.kind)throw new I("UNSUPPORTED_OPERATION",`Unsupported iOS device kind for runner: ${e.kind}`);return(t9(r.requestId),"snapshot"===(i=t.command)||"screenshot"===i||"findText"===i||"alert"===i)?er(()=>(t9(r.requestId),rj(e,t,r)),{shouldRetry:e=>{t9(r.requestId);if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=`${e.message??""}`.toLowerCase();return!(t.includes("xcodebuild exited early")||t.includes("device is busy")&&t.includes("connecting"))&&!!(t.includes("runner did not accept connection")||t.includes("fetch failed")||t.includes("econnrefused")||t.includes("socket hang up"))}}):rj(e,t,r)}async function rj(e,t,r={}){let i;t9(r.requestId);try{let n=(i=await rx(e,r)).ready?re:t7;return await rU(e,i,t,r.logPath,n)}catch(a){let n=a instanceof I?a:new I("COMMAND_FAILED",String(a));if("COMMAND_FAILED"===n.code&&"string"==typeof n.message&&n.message.includes("Runner did not accept connection")&&t8(n)&&i?.ready){t9(r.requestId),i?await rC(i):await rR(e.id),i=await rx(e,r);let n=await rs(i.device,i.port,t,r.logPath,t7);return await rG(n,i,r.logPath)}throw a}}function rq(e,t,r){return p("xcrun",tY(e,t),r)}let rW={ensureBooted:t0,captureWithRetry:rz,captureWithRunner:rK,shouldFallbackToRunner:r0};async function rH(e,t,r){if("simulator"===e.kind)return void await rJ(e,t,r);try{await tH(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(t){if(!function(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=`${e.message}
|
|
18
17
|
${r}
|
|
19
|
-
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(e))throw e}let i=(await
|
|
20
|
-
|
|
21
|
-
${
|
|
22
|
-
${n
|
|
23
|
-
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}function il(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function id(e,t){await rj(e),await p("open",["-a","Simulator"],{allowFailure:!0});let r=X.fromTimeoutMs(tY);await Y(async({deadline:r})=>{if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tY});let i=t$(e,["launch",e.id,t]),n=await p("xcrun",i,{allowFailure:!0});if(0!==n.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${n.exitCode}`,{cmd:"xcrun",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:il},{deadline:r})}async function iu(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tQ(i,{action:"launch iOS app",deviceId:e.id})}let ic=/^[A-Za-z0-9_.:-]{1,64}$/;function ip(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!R.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function im(e){let t=q(e.platform),r=en(e.iosSimulatorDeviceSet),i=eo(e.androidDeviceAllowlist);return await O("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await th();let e=await eA({serialAllowlist:i});return await j(e,n)}if("ios"===n.platform){let e=await tz({simulatorSetPath:r});return await j(e,n)}let a=[];try{a.push(...await eA({serialAllowlist:i}))}catch{}try{a.push(...await tz({simulatorSetPath:r}))}catch{}return await j(a,n)},{platform:t,target:e.target})}async function ih(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>e0(e,t,r?.activity),openDevice:()=>e2(e),close:t=>e3(e,t),tap:(t,r)=>e6(e,t,r),doubleTap:async(t,r)=>{await e6(e,t,r),await e6(e,t,r)},swipe:(t,r,i,n,a)=>e9(e,t,r,i,n,a),longPress:(t,r,i)=>tr(e,t,r,i),focus:(t,r)=>to(e,t,r),type:t=>ti(e,t),fill:(t,r,i)=>ts(e,t,r,i),scroll:(t,r)=>tl(e,t,r),scrollIntoView:t=>td(e,t),screenshot:(t,r)=>tu(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>rY(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>rZ(e),close:t=>rQ(e,t),screenshot:(t,r)=>r3(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(t8(i.requestId))throw new I("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await rf(r,{command:"tapSeries",x:e,y:t,count:1,intervalMs:0,doubleTap:!0,appBundleId:i.appBundleId},n)},swipe:async(e,t,a,o,s)=>{await rf(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await rf(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await rf(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await rf(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await rf(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await rf(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await rf(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(t?.found)return{attempts:1};for(let t=0;t<12;t+=1){for(let e=0;e<4;e+=1)a(),await rf(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await rf(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await O("platform_command",async()=>{var s,l,d,u,c,p;switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(ek(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!ek(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=ig(a?.count??1,"count",1,200),c=ig(a?.intervalMs??0,"interval-ms",0,1e4),p=ig(a?.holdMs??0,"hold-ms",0,1e4),f=ig(a?.jitterPx??0,"jitter-px",0,100),m=a?.doubleTap===!0;if(m&&p>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(m&&f>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if(s=e,l=n,d=p,u=f,"ios"===s.platform&&l>1&&0===d&&0===u)return await rf(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:c,doubleTap:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m,timingMode:"runner-series"};return await iA(n,c,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=iw[e%iw.length];return[r*t,i*t]}(e,f),a=t+r,s=i+n;m?await o.doubleTap(a,s):p>0?await o.longPress(a,s,p):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:c,holdMs:p,jitterPx:f,doubleTap:m}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=ig(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=ig(a?.count??1,"count",1,200),f=ig(a?.pauseMs??0,"pause-ms",0,1e4),m=a?.pattern??"one-way";if("one-way"!==m&&"ping-pong"!==m)throw new I("INVALID_ARGS",`Invalid pattern: ${m}`);if(c=e,p=u,"ios"===c.platform&&p>1)return await rf(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:f,pattern:m,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:f,pattern:m};return await iA(u,f,async e=>{"ping-pong"===m&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:f,pattern:m}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await rf(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!ic.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await rf(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await e7(e),{action:"back"};case"home":if("ios"===e.platform)return await rf(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await te(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await rf(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await tt(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await r4(e):await tn(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await r8(e,i):await ta(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await eZ(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await eY(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await r6(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await tc(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await iI(i);if("ios"===e.platform)return await r5(e,t,n),{platform:"ios",bundleId:t};let a=await tf(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await O("snapshot_capture",async()=>await rf(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await O("snapshot_capture",async()=>await tm(e,{interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw}),{backend:"android"});return{nodes:t.nodes??[],truncated:t.truncated??!1,backend:"android"}}default:throw new I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let iw=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function ig(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function iI(e){let t=ip(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await iv(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function iv(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}async function iA(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await iy(t)}async function iy(e){await new Promise(t=>setTimeout(t,e))}let iN={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function iS(e,t){let r=iN[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function ib(e){let t=e.result?.text;if("string"==typeof t&&t.trim().length>0)return t;let r=e.positionals??[];return 0===r.length?"":r[0].startsWith("@")?r.length>=3?r.slice(2).join(" ").trim():r.slice(1).join(" ").trim():!(r.length>=3)||Number.isNaN(Number(r[0]))||Number.isNaN(Number(r[1]))?r.slice(1).join(" ").trim():r.slice(2).join(" ").trim()}function i_(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let iD=/^-?\d+(\.\d+)?$/,iE=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),ik=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function iO(e){return"click"===e||"press"===e}function iM(e){let t=e.trim();return t.startsWith("@")||iD.test(t)?t:JSON.stringify(t)}function iL(e,t){let r=t.flags??{};if(iO(t.command)){"number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.intervalMs&&e.push("--interval-ms",String(r.intervalMs)),"number"==typeof r.holdMs&&e.push("--hold-ms",String(r.holdMs)),"number"==typeof r.jitterPx&&e.push("--jitter-px",String(r.jitterPx)),!0===r.doubleTap&&e.push("--double-tap");return}"swipe"===t.command&&("number"==typeof r.count&&e.push("--count",String(r.count)),"number"==typeof r.pauseMs&&e.push("--pause-ms",String(r.pauseMs)),("one-way"===r.pattern||"ping-pong"===r.pattern)&&e.push("--pattern",r.pattern))}function ix(e,t){let r=[],i={},n=iO(e)?iE:"swipe"===e?ik:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(iO(e)&&"--double-tap"===o){i.doubleTap=!0;continue}let s=n?.get(o);if(s&&a+1<t.length){let e=function(e){if(!e)return null;let t=Number(e);return!Number.isFinite(t)||t<0?null:Math.floor(t)}(t[a+1]);null!==e&&(i[s]=e),a+=1;continue}if("swipe"===e&&"--pattern"===o&&a+1<t.length){let e=t[a+1];("one-way"===e||"ping-pong"===e)&&(i.pattern=e),a+=1;continue}r.push(o)}return{positionals:r,flags:i}}class iC{sessions=new Map;sessionsDir;constructor(e){this.sessionsDir=e}get(e){return this.sessions.get(e)}has(e){return this.sessions.has(e)}set(e,t){this.sessions.set(e,t)}delete(e){return this.sessions.delete(e)}values(){return this.sessions.values()}toArray(){return Array.from(this.sessions.values())}recordAction(e,t){t.flags?.noRecord||(t.flags?.saveScript&&(e.recordSession=!0,"string"==typeof t.flags.saveScript&&(e.saveScriptPath=iC.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}}(t.flags),result:t.result}),M({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=n.dirname(t);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(iO(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(iM(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(iM(i)),iL(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(iM(r)),iL(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(iM(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(iM(i)),n&&t.push(iM(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(iM(r)),t.push(iM(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(iM(r))}return t.join(" ")}}if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iM(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iM(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iM(r));return iL(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
`)
|
|
27
|
-
`)},flush:()=>{i&&(n(i),i="")}}}function nw(e,t,r){let i=e.stdout,n=e.stderr;return i&&n?(i.setEncoding("utf8"),n.setEncoding("utf8"),i.on("data",r.writer.onChunk),n.on("data",r.writer.onChunk),t.on("error",()=>{e.killed||e.kill("SIGKILL")}),e.on("error",()=>t.destroy()),new Promise(i=>{e.on("close",e=>{r.writer.flush(),r.endStreamOnClose&&t.end(),i({stdout:"",stderr:"",exitCode:e??1})})})):Promise.resolve({stdout:"",stderr:"missing stdio pipes",exitCode:1})}async function ng(e,t){let r=(await p("adb",["-s",e,"shell","pidof",t],{allowFailure:!0})).stdout.trim().split(/\s+/)[0];return r&&/^\d+$/.test(r)?r:null}async function nI(e,t,r,i){let n="active",a=h("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=nh(t,{redactionPatterns:r});"number"==typeof a.pid&&nu(i,a.pid);let s=nw(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nc(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nf(s),a.killed||a.kill("SIGKILL"),await nf(s),nc(i)}}}async function nv(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=nh(t,{redactionPatterns:r});"number"==typeof a.pid&&nu(i,a.pid);let s=nw(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nc(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nf(s),a.killed||a.kill("SIGKILL"),await nf(s),nc(i)}}}async function nA(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await ng(e,t);if(!d){await nm(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=nh(r,{redactionPatterns:i});o=nw(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&nu(n,u.pid);let p=await o;if(nc(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await nm(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),nc(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await nf(o),a&&!a.killed&&a.kill("SIGKILL"),await nf(d),nc(n)}}}async function ny(e,t,r,i){np(r);let n=R.createWriteStream(r,{flags:"a"}),a=function(){let e=process.env.AGENT_DEVICE_APP_LOG_REDACT_PATTERNS;if(!e)return[];let t=e.split(",").map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of t)try{r.push(RegExp(e,"gi"))}catch{}return r}();if("ios"===e.platform)return"device"===e.kind?await nv(e.id,n,a,i):await nI(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new I("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await nA(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function nN(e){await e.stop(),await nf(e.wait)}async function nS(e,t){let r={},i=[];if(t||i.push("No app bundle is tracked in this session. Run open <app> first for app-scoped logs."),"android"===e.platform){try{let e=await p("adb",["version"],{allowFailure:!0});r.adbAvailable=0===e.exitCode}catch{r.adbAvailable=!1}if(t)try{r.androidPidVisible=(await p("adb",["-s",e.id,"shell","pidof",t],{allowFailure:!0})).stdout.trim().length>0}catch{r.androidPidVisible=!1}}if("ios"===e.platform&&"simulator"===e.kind)try{let e=await p("xcrun",["simctl","help"],{allowFailure:!0});r.simctlAvailable=0===e.exitCode}catch{r.simctlAvailable=!1}if("ios"===e.platform&&"device"===e.kind)try{let e=await p("xcrun",["devicectl","--version"],{allowFailure:!0});r.devicectlAvailable=0===e.exitCode}catch{r.devicectlAvailable=!1}return{checks:r,notes:i}}function nb(e){let t=n.dirname(e),r=n.basename(e);R.existsSync(t)||R.mkdirSync(t,{recursive:!0}),R.existsSync(e)?R.truncateSync(e,0):R.writeFileSync(e,"","utf8");let i=0;for(let e of R.readdirSync(t)){if(!e.startsWith(`${r}.`))continue;let a=e.slice(r.length+1);if(/^\d+$/.test(a))try{R.unlinkSync(n.join(t,e)),i+=1}catch{}}return{path:e,cleared:!0,removedRotatedFiles:i}}let n_=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),nD=/https?:\/\/[^\s"'<>\])]+/i,nE=[/\bstatus(?:Code)?["'=: ]+([1-5]\d{2})\b/i,/\bresponse(?:\s+code)?["'=: ]+([1-5]\d{2})\b/i,/\bHTTP\/[0-9.]+\s+([1-5]\d{2})\b/i];function nk(e,t){if(e)for(let r of t){let t=e[r];if("string"==typeof t&&t.trim().length>0)return t.trim()}}function nO(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return nM(t[e])}for(let t of r){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=RegExp(`\\b${r}["'=: ]+(.+)$`,"i").exec(e);if(i?.[1])return i[1].trim()}}function nM(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function nL(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function nx(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}let nC='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',nT=["platform","target","device","udid","serial","verbose","out"],nR=["platform","target","device","udid","serial","verbose","out"],nP=["path","start","stop","doctor","mark","clear"],n$=`logs requires ${nP.slice(0,-1).join(", ")}, or ${nP.at(-1)}`,nF="Not implemented for this platform in this release.",nV="open-command-roundtrip";function nU(e){let{sessionName:t,appName:r,appBundleId:i,startup:n}=e,a={session:t};return r&&(a.appName=r),i&&(a.appBundleId=i),n&&(a.startup=n),a}function nG(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:nV,appTarget:t,appBundleId:r}}let nB=["dump","log"],nq=`network requires ${nB.join(" or ")}`,nj=["summary","headers","body","all"],nW=`network include mode must be one of: ${nj.join(", ")}`;function nH(e,t,r){return t||nJ(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function nJ(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}async function nz(e){let t=nJ(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function nK(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let nX=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:eD}));return await i({avdName:e,serial:t,headless:r})};async function nY(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=nH(l,p,f);if(m)return m;let h=await nz({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iS(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...iT(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let nZ={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:r2}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e5}));return await i(e,t,r)}};async function nQ(e,t,r){if("ios"===e.platform&&t)return ek(t)?"device"===e.kind?eO(r,t):void 0:await n0(e,t)}async function n0(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:rX}));return await r(e,t)}catch{return}}async function n1(e,t){if(!("android"!==e.platform||!t||ek(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eW})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function n2(e,t,r,i){return await nQ(e,t,r)??await i(e,t)??("android"===e.platform&&t&&ek(t)?r:void 0)}async function n3(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=q(s.platform);if(!o&&"string"==typeof s?.session&&s.session.trim().length>0)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"ios"===l?`No active session "${r}". Run open with --session ${r} first.`:`No active session "${r}". Run open with --session ${r} first, or omit --session to query by device selector.`}};let d=nH("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!nJ(e))return!0;let r=q(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nC}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session"}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await nz({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:nC}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eX})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function n4(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=nH("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await nz({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iS("clipboard",p))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"clipboard is not supported on this device"}};let f=await s(p,"clipboard",t.positionals??[],t.flags?.out,{...iT(i,t.flags,l?.appBundleId,l?.trace?.outPath)});return l&&n.recordAction(l,{command:t.command,positionals:t.positionals??[],flags:t.flags??{},result:f??{}}),{ok:!0,data:{platform:p.platform,...f??{}}}}async function n8(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a,dispatch:o,ensureReady:s,resolveTargetDevice:l,reinstallOps:d=nZ,stopIosRunner:u,appLogOps:c={start:ny,stop:nN},ensureAndroidEmulatorBoot:p=nX,resolveAndroidPackageForOpen:f=n1}=e,m=o??ih,h=s??iP,g=l??im,v=t.command;if("session_list"===v)return{ok:!0,data:{sessions:n.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt}))}};if("devices"===v)try{let e=[],r=en(t.flags?.iosSimulatorDeviceSet),i=eo(t.flags?.androidDeviceAllowlist),n=q(t.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA}));e.push(...await t({serialAllowlist:i}))}else if("ios"===n){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:tz}));e.push(...await t({simulatorSetPath:r}))}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:eA})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:tz}));try{e.push(...await t({serialAllowlist:i}))}catch{}try{e.push(...await n({simulatorSetPath:r}))}catch{}}let a=(t.flags?.target?e.filter(e=>(e.target??"mobile")===t.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===v){let e=n.get(r),i=t.flags??{},a=nH(v,e,i);if(a)return a;let o=await nz({session:e,flags:i,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!0});if(!iS("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=t.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:r9}));return{ok:!0,data:{apps:(await e(o,s)).map(e=>e.name&&e.name!==e.bundleId?`${e.name} (${e.bundleId})`:e.bundleId)}}}let{listAndroidApps:l}=await Promise.resolve().then(()=>({listAndroidApps:eH}));return{ok:!0,data:{apps:(await l(o,s)).map(e=>e.name&&e.name!==e.package?`${e.name} (${e.package})`:e.package)}}}if("boot"===v){let e,i=n.get(r),a=t.flags??{},o=nH(v,i,a);if(o)return o;let s="android"===(q(a.platform)??i?.device.platform),l=!0===a.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=nK({flags:a,sessionDevice:i?.device}),u=s&&!!d,c=!1;try{e=await nz({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1})}catch(r){let t=w(r);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw r;e=await p({avdName:d,serial:a.serial,headless:l}),c=!0}if(a.target&&(e.target??"mobile")!==a.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${a.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let t=nK({flags:a,sessionDevice:i?.device,resolvedDevice:e});if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await p({avdName:t,serial:a.serial,headless:!0})}await h(e)}else("android"!==e.platform||!0!==e.booted)&&await h(e);return iS("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===v)return await n3({req:t,sessionName:r,sessionStore:n,ensureReady:h,resolveDevice:g});if("clipboard"===v)return await n4({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m});if("keyboard"===v)return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"keyboard",positionals:t.positionals??[]});if("perf"===v){let e,t,i,a=n.get(r);return a?{ok:!0,data:(i=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===nV&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:nV,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(a.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:nV,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:nV},{session:a.name,platform:a.device.platform,device:a.device.name,deviceId:a.device.id,metrics:{startup:i,fps:{available:!1,reason:nF},memory:{available:!1,reason:nF},cpu:{available:!1,reason:nF}},sampling:{startup:{method:nV,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("reinstall"===v){let e,i=n.get(r),a=t.flags??{},o=nH(v,i,a);if(o)return o;let s=t.positionals?.[0]?.trim(),l=t.positionals?.[1]?.trim();if(!s||!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"reinstall requires: reinstall <app> <path-to-app-binary>"}};let u=iC.expandHome(l);if(!R.existsSync(u))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${u}`}};let c=await nz({session:i,flags:a,ensureReadyFn:h,resolveTargetDeviceFn:g,ensureReady:!1});if(!iS("reinstall",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"reinstall is not supported on this device"}};if("ios"===c.platform){let t=await d.ios(c,s,u);e={platform:"ios",appId:t.bundleId,bundleId:t.bundleId}}else{let t=await d.android(c,s,u);e={platform:"android",appId:t.package,package:t.package}}let p={app:s,appPath:u,...e};return i&&n.recordAction(i,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),{ok:!0,data:p}}if("push"===v){let e,a=t.positionals?.[0]?.trim(),o=t.positionals?.[1]?.trim();if(!a||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=ip(o,{subject:"Push payload",cwd:t.meta?.cwd,expandPath:(e,t)=>iC.expandHome(e,t)})).kind?e.path:e.text;return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"push",positionals:[a,s],recordPositionals:[a,o]})}if("trigger-app-event"===v)return await nY({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:h,resolveDevice:g,dispatch:m,command:"trigger-app-event",positionals:t.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await n2(e.device,r,e.appBundleId,f)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===v){let e=t.flags?.relaunch===!0;if(n.has(r)){let a=n.get(r),o=t.positionals?.[0],s=o??(e?a?.appName:void 0);if(!a||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&ek(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await h(a.device);let l=await n2(a.device,s,a.appBundleId,f),d=o?t.positionals??[]:[s];if(e){let e=l??s;await m(a.device,"close",[e],t.flags?.out,{...iT(i,t.flags,l??a.appBundleId,a.trace?.outPath)})}let u=Date.now();await m(a.device,"open",d,t.flags?.out,{...iT(i,t.flags,l)});let c=nG(u,s,l),p={...a,appBundleId:l,appName:s,recordSession:a.recordSession||!!t.flags?.saveScript,snapshot:void 0},w=nU({sessionName:r,appName:s,appBundleId:l,startup:c});return n.recordAction(p,{command:v,positionals:d,flags:t.flags??{},result:w}),n.set(r,p),{ok:!0,data:w}}let a=t.positionals?.[0];if(e&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&a&&ek(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let o=await g(t.flags??{}),s=n.toArray().find(e=>e.device.id===o.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:o.id,deviceName:o.name}}};await h(o);let l=await n2(o,a,void 0,f);if(e&&a){let e=l??a;await m(o,"close",[e],t.flags?.out,{...iT(i,t.flags,l)})}let d=Date.now();await m(o,"open",t.positionals??[],t.flags?.out,{...iT(i,t.flags,l)});let u=a?nG(d,a,l):void 0,c={name:r,device:o,createdAt:Date.now(),appBundleId:l,appName:a,recordSession:!!t.flags?.saveScript,actions:[]},p=nU({sessionName:r,appName:a,appBundleId:l,startup:u});return n.recordAction(c,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:p}),n.set(r,c),{ok:!0,data:p}}if("replay"===v){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=iC.expandHome(e,t.meta?.cwd),s=R.readFileSync(o,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(iO(i)){let e=ix(i,n);if(Object.assign(a.flags,e.flags),0===e.positionals.length)return a;let t=e.positionals[0];if(t.startsWith("@"))return a.positionals=[t],e.positionals[1]&&(a.result={refLabel:e.positionals[1]}),a;let r=e.positionals[0],o=e.positionals[1];return ai(r)&&ai(o)&&e.positionals.length>=2?a.positionals=[r,o]:a.positionals=[e.positionals.join(" ")],a}if("fill"===i){if(n.length<2)return a.positionals=n,a;let e=n[0];return e.startsWith("@")?(n.length>=3?(a.positionals=[e,n.slice(2).join(" ")],a.result={refLabel:n[1]}):a.positionals=[e,n[1]],a):(a.positionals=[e,n.slice(1).join(" ")],a)}if("get"===i){if(n.length<2)return a.positionals=n,a;let e=n[0],t=n[1];return t.startsWith("@")?(a.positionals=[e,t],n[2]&&(a.result={refLabel:n[2]})):a.positionals=[e,n.slice(1).join(" ")],a}if("swipe"===i){let e=ix(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),u=t.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await a({token:t.token,session:r,command:s.command,positionals:s.positionals??[],flags:n7(t.flags,s.flags),meta:t.meta});if(l.ok)continue;if(!u)return n9(l,s,e,o);let p=await ae({action:s,sessionName:r,logPath:i,sessionStore:n,dispatch:m});if(!p)return n9(l,s,e,o);if(d[e]=p,!(l=await a({token:t.token,session:r,command:p.command,positionals:p.positionals??[],flags:n7(t.flags,p.flags),meta:t.meta})).ok)return n9(l,p,e,o);c+=1}if(u&&c>0){let e=n.get(r);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iM(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iM(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iM(r));return iL(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
28
|
-
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;R.writeFileSync(a,n),R.renameSync(a,e)}(o,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:r}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let i=(t.positionals?.[0]??"path").toLowerCase(),a=!!t.flags?.restart;if(!nP.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:n$}};if(a&&"clear"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===i){let t=n.resolveAppLogPath(r),i=function(e){if(!R.existsSync(e))return{exists:!1,sizeBytes:0};let t=R.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),a=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:a,sizeBytes:i.sizeBytes,modifiedAt:i.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===i){let t=n.resolveAppLogPath(r),i=await nS(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:i.checks,notes:i.notes}}}if("mark"===i){let e,i=t.positionals?.slice(1).join(" ")??"",a=n.resolveAppLogPath(r);return np(a),e=`[agent-device][mark][${new Date().toISOString()}] ${i.trim()||"marker"}
|
|
29
|
-
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!iS("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await c.stop(e.appLog);let i=nb(t),a=n.resolveAppLogPidPath(r);try{let o=await c.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=b(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:nb(t)}}if("start"===i){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!iS("logs",e.device))return{ok:!1,error:b(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await c.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:b(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await c.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===v){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!nB.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:nq}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!nj.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:nW}};let l=function(e,t){let r=nx(t?.maxEntries,25,1,200),i=t?.include??"summary",n=nx(t?.maxPayloadChars,2048,64,16384),a=nx(t?.maxScanLines,4e3,100,2e4);if(!R.existsSync(e))return{path:e,exists:!1,scannedLines:0,matchedLines:0,entries:[],include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}};let o=R.readFileSync(e,"utf8").split("\n"),s=Math.max(0,o.length-a),l=o.slice(s),d=[];for(let e=l.length-1;e>=0&&d.length<r;e-=1){let t=l[e]?.trim();if(!t)continue;let r=function(e,t,r,i){let n=function(e){let t=e.indexOf("{");if(t<0)return null;let r=e.lastIndexOf("}");if(r<=t)return null;let i=e.slice(t,r+1);try{let e=JSON.parse(i);return e&&"object"==typeof e?e:null}catch{return null}}(e),a=nk(n,["method","httpMethod"]),o=nk(n,["url","requestUrl"]),s=function(e,t){if(!e)return null;for(let r of t){let t=e[r];if("number"==typeof t&&Number.isInteger(t))return t;if("string"==typeof t&&/^\d{3}$/.test(t.trim()))return Number.parseInt(t.trim(),10)}return null}(n,["status","statusCode","responseCode"]),l=n_.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=nD.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of nE){let r=t.exec(e);if(!r)continue;let i=Number.parseInt(r[1]??"",10);if(Number.isInteger(i))return i}return null}(e)??void 0,timestamp:function(e){let t=/\b\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z)?\b/.exec(e);return t?.[0]}(e),raw:nL(e,i),line:t};if("headers"===r||"all"===r){let t=function(e,t){if(t){let e=t.headers??t.requestHeaders??t.responseHeaders;if(void 0!==e)return nM(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=nL(t,i))}if("body"===r||"all"===r){let t=nO(e,n,["requestBody","body","payload","request"]),r=nO(e,n,["responseBody","response"]);t&&(f.requestBody=nL(t,i)),r&&(f.responseBody=nL(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(n.resolveAppLogPath(r),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===v)return await n5(t,r,a);if("close"===v){let e=n.get(r);return e?(e.appLog&&await c.stop(e.appLog),t.positionals&&t.positionals.length>0&&await m(e.device,"close",t.positionals??[],t.flags?.out,{...iT(i,t.flags,e.appBundleId,e.trace?.outPath)}),"ios"===e.device.platform&&await (u??rg)(e.device.id),n.recordAction(e,{command:v,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),{ok:!0,data:{session:r}}):{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}}}return null}async function n5(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??L;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await n6(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function n6(e,t,r,i,n){let a=Date.now(),o=await i({token:e.token,session:t,command:r.command,positionals:r.positionals,flags:function(e,t){let r={...t??{}};delete r.batchSteps,delete r.batchOnError,delete r.batchMaxSteps;let i=e??{};for(let e of nT)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}(e.flags,r.flags),meta:e.meta}),s=Date.now()-a;return o.ok?{ok:!0,step:n,result:{step:n,command:r.command,ok:!0,data:o.data??{},durationMs:s}}:{ok:!1,step:n,error:o.error}}function n9(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>iM(e)),[e.command,...t].join(" ")}(t),o={...e.error.details??{},replayPath:i,step:n,action:t.command,positionals:t.positionals??[]};return{ok:!1,error:{code:e.error.code,message:`Replay failed at step ${n} (${a}): ${e.error.message}`,hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath,details:o}}}function n7(e,t){let r={...t??{}},i=e??{};for(let e of nR)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function ae(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(iO(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=iO(t.command)||"fill"===t.command,l=iO(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await at(o,t,i,s,a,n);for(let e of function(e){let t=[],r=Array.isArray(e.result?.selectorChain)&&e.result?.selectorChain.every(e=>"string"==typeof e)?e.result.selectorChain:[];if(t.push(...r),iO(e.command)){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&t.push(e.positionals.join(" "))}if("fill"===e.command){let r=e.positionals?.[0]??"";r&&!r.startsWith("@")&&Number.isNaN(Number(r))&&t.push(r)}if("get"===e.command){let r=e.positionals?.[1]??"";r&&!r.startsWith("@")&&t.push(e.positionals.slice(1).join(" "))}if("is"===e.command){let{split:r}=i5(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=ar(e.positionals??[]);r&&t.push(r)}let i="string"==typeof e.result?.refLabel?e.result.refLabel.trim():"";if(i.length>0){let r=JSON.stringify(i);"fill"===e.command?(t.push(`id=${r} editable=true`),t.push(`label=${r} editable=true`),t.push(`text=${r} editable=true`),t.push(`value=${r} editable=true`)):(t.push(`id=${r}`),t.push(`label=${r}`),t.push(`text=${r}`),t.push(`value=${r}`))}return i_(t).filter(e=>e.trim().length>0)}(t)){let r=i1(e);if(!r)continue;let i=i2(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=i7(i.node,o.device.platform,{action:iO(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(iO(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=ib(t);if(!e)continue;return{...t,positionals:[n,e]}}if("get"===t.command){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)continue;return{...t,positionals:[e,n]}}if("is"===t.command){let{predicate:e,split:r}=i5(t.positionals);if(!e)continue;let i=r?.rest.join(" ").trim()??"",a=[e,n];return"text"===e&&i.length>0&&a.push(i),{...t,positionals:a}}if("wait"===t.command){let{selectorTimeout:e}=ar(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=i1(i);if(!n)return null;let a=new Set,o=!1;for(let e of n.selectors)for(let t of e.terms)"role"===t.key&&"string"==typeof t.value&&a.add(iz(t.value)),("text"===t.key||"label"===t.key||"value"===t.key)&&"string"==typeof t.value&&/^\d+$/.test(t.value.trim())&&(o=!0);if(!o)return null;let s=t.nodes.filter(e=>{let t=iX(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(iz(e.type??"")))});if(0===s.length||1!==i_(s.map(e=>iX(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=i7(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function at(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...iT(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:iU(t.flags?.snapshotRaw?s:iJ(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function ar(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=i8(r?e.slice(0,-1):e.slice());return!i||i.rest.length>0?{selectorExpression:null,selectorTimeout:null}:{selectorExpression:i.selectorExpression,selectorTimeout:r?t:null}}function ai(e){return!!e&&!Number.isNaN(Number(e))}function an(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function aa(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function ao(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:aa(e,0)})):A(e).map(e=>({text:e.text,comparable:aa(e.node,e.depth)}))}function as(e,t){return e.get(t)??0}async function al(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??ih,o=t.command;if("snapshot"===o){let{session:e,device:o}=await ac(n,r,t.flags);if(!iS("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=au(t.flags?.snapshotScope,e);return s.ok?await ap(e,o,async()=>{let l=e?.appBundleId,d=await ad({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return af(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===o){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await ac(n,r,t.flags);if(!iS("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=au(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await ap(e,o,async()=>{let d=e?.appBundleId,u=(await ad({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return ao(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return af(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&as(a,n-1)<as(a,n+1)?as(a,n+1):as(a,n-1)+1,d=l-n;for(;l<r&&d<i&&e[l].comparable===t[d].comparable;)l+=1,d+=1;if(a.set(n,l),l>=r&&d>=i)return function(e,t,r,i,n){let a=[],o=i,s=n;for(let i=e.length-1;i>=0;i-=1){let n=e[i],l=o-s,d=l===-i||l!==i&&as(n,l-1)<as(n,l+1)?l+1:l-1,u=as(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(ao(e,r),ao(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return af(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===o){let{session:e,device:o}=await ac(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=an(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=an(e[e.length-1]);return{kind:"text",text:(null!==t?e.slice(1,-1).join(" "):e.slice(1).join(" ")).trim(),timeoutMs:t}}if(e[0].startsWith("@")){let t=an(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=an(e[e.length-1]),i=i8(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=i1(i.selectorExpression);if(e)return{kind:"selector",selector:e,selectorExpression:i.selectorExpression,timeoutMs:r}}return{kind:"text",text:(null!==r?e.slice(0,-1).join(" "):e.join(" ")).trim(),timeoutMs:r}}(t.positionals??[]);return s?"sleep"===s.kind?(await new Promise(e=>setTimeout(e,s.durationMs)),af(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):iS("wait",o)?await ap(e,o,async()=>{let l,d;if("selector"===s.kind){let l=s.timeoutMs??1e4,d=Date.now();for(;Date.now()-d<l;){let l=await a(o,"snapshot",[],t.flags?.out,{...iT(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=iU(t.flags?.snapshotRaw?u:iJ(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=i3(c,s.selector,{platform:o.platform});if(p)return af(n,e,t,{selector:p.selector.raw,waitedMs:Date.now()-d}),{ok:!0,data:{selector:p.selector.raw,waitedMs:Date.now()-d}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for selector: ${s.selectorExpression}`}}}if("ref"===s.kind){if(!e?.snapshot)return{ok:!1,error:{code:"INVALID_ARGS",message:"Ref wait requires an existing snapshot in session."}};let t=iG(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=iB(e.snapshot.nodes,t),i=r?iW(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await rf(o,{command:"findText",text:l,appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});if(r?.found)return af(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&ij(iU((await tm(o,{scope:l})).nodes??[]),l))return af(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===o){let{session:e,device:a}=await ac(n,r,t.flags),o=(t.positionals?.[0]??"get").toLowerCase();return iS("alert",a)?await ap(e,a,async()=>{if("wait"===o){let r=an(t.positionals?.[1])??1e4,o=Date.now();for(;Date.now()-o<r;){try{let r=await rf(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return af(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r=await rf(a,{command:"alert",action:"accept"===o||"dismiss"===o?o:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return af(n,e,t,r),{ok:!0,data:r}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===o){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:u}};let{session:s,device:l}=await ac(n,r,t.flags);return iS("settings",l)?await ap(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await ih(l,"settings",d,t.flags?.out,{...iT(i,t.flags,r,s?.trace?.outPath)});return af(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function ad(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...iT(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:iU(n.flags?.snapshotRaw?l:iJ(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function au(e,t){if(!e||!e.trim().startsWith("@"))return{ok:!0,scope:e};if(!t?.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"Ref scope requires an existing snapshot in session."}}};let r=iG(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=iB(t.snapshot.nodes,r),n=i?iW(i,t.snapshot.nodes):void 0;return n?{ok:!0,scope:n}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${e} not found or has no label`}}}}async function ac(e,t,r){let i=e.get(t),n=i?.device??await im(r??{});return i||await iP(n),{session:i,device:n}}async function ap(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rg(t.id)}}function af(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function am(e,t,r,i={}){let n=aw(r);if(!n)return{matches:[],score:0};let a=0,o=[];for(let r of e){if(i.requireRect&&!r.rect)continue;let e=function(e,t,r){switch(t){case"role":return function(e,t){let r=function(e){let t=e.trim();return t?t=(t.split(".").pop()??t).replace(/XCUIElementType/gi,"").toLowerCase():""}(e??"");return r?r===t?2:+!!r.includes(t):0}(e.type,r);case"label":return ah(e.label,r);case"value":return ah(e.value,r);case"id":return ah(e.identifier,r);default:return Math.max(ah(e.label,r),ah(e.value,r),ah(e.identifier,r))}}(r,t,n);if(!(e<=0)){if(e>a){a=e,o.length=0,o.push(r);continue}e===a&&o.push(r)}}return{matches:o,score:a}}function ah(e,t){let r=aw(e??"");return r?r===t?2:+!!r.includes(t):0}function aw(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function ag(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=t.command;if("find"!==o)return null;let s=t.positionals??[];if(0===s.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:l,query:d,action:u,value:c,timeoutMs:p}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:an(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(s);if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let f=n.get(r);if(!f&&"exists"!==u&&"wait"!==u&&"get_text"!==u&&"get_attrs"!==u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let m=f?.device??await im(t.flags??{});f||await iP(m);let h=f?.appBundleId,w="role"!==l?d:void 0,g="click"===u||"focus"===u||"fill"===u||"type"===u,v=0,A=null,y=async()=>{let e=Date.now();if(A&&e-v<750)return{nodes:A};let a=await ih(m,"snapshot",[],t.flags?.out,{...iT(i,{...t.flags,snapshotScope:w,snapshotInteractiveOnly:g,snapshotCompact:g},h,f?.trace?.outPath)}),o=a?.nodes??[],s=iU(t.flags?.snapshotRaw?o:iJ(o));return v=e,A=s,f&&(f.snapshot={nodes:s,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,f)),{nodes:s,truncated:a?.truncated,backend:a?.backend}};if("wait"===u){let e=p??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await y();if(am(e,l,d,{requireRect:!1}).matches[0])return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:N}=await y(),S=am(N,l,d,{requireRect:g});if(g&&S.matches.length>1){let e=S.matches.slice(0,8).map(e=>{let t=iX(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${S.matches.length} elements for ${l} "${d}". Use a more specific locator or selector.`,details:{locator:l,query:d,matches:S.matches.length,candidates:e}}}}let b=S.matches[0]??null;if(!b)return{ok:!1,error:{code:"COMMAND_FAILED",message:"find did not match any element"}};let _="click"===u||"focus"===u||"fill"===u||"type"===u?function(e,t){if(t.hittable)return t;let r=t,i=new Set;for(;void 0!==r.parentIndex&&!i.has(r.ref);){i.add(r.ref);let t=e[r.parentIndex];if(!t)break;if(t.hittable)return t;r=t}return null}(N,b)??b:b,D=`@${_.ref}`,E={...t.flags??{},noRecord:!0};if("exists"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===u){let e=iX(b);return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get text",text:e}}),{ok:!0,data:{ref:D,text:e,node:b}}}if("get_attrs"===u)return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"get attrs"}}),{ok:!0,data:{ref:D,node:b}};if("click"===u){let e=await a({token:t.token,session:r,command:"click",positionals:[D],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"click"}}),e}if("fill"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[D,c],flags:E});return e.ok&&f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"fill"}}),e}if("focus"===u){let e=b.rect?iq(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await ih(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"focus"}}),{ok:!0,data:r??{ref:D}}}if("type"===u){if(!c)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=b.rect?iq(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await ih(m,"focus",[String(e.x),String(e.y)],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});let r=await ih(m,"type",[c],t.flags?.out,{...iT(i,t.flags,f?.appBundleId,f?.trace?.outPath)});return f&&n.recordAction(f,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:D,action:"type"}}),{ok:!0,data:r??{ref:D}}}return null}function aI(e){return e instanceof Error?e.message:String(e)}function av(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function aA(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function ay(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rf},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await im(t.flags??{});d||await iP(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!iS("record",c))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"record is not supported on this device"}};let f="ios"===c.platform&&"device"===c.kind?av(p):void 0;if("ios"===c.platform&&"device"===c.kind&&!f)return{ok:!1,error:{code:"INVALID_ARGS",message:"record on physical iOS devices requires an active app session; run open <app> first"}};let m=iC.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=aA(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await n()}catch(e){if(!aI(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${aI(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:aI(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${aI(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",t$(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=av(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},aA(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:aI(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of t7)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=iC.expandHome(e);return R.mkdirSync(n.dirname(r),{recursive:!0}),R.appendFileSync(r,""),a.trace={outPath:r,startedAt:Date.now()},i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start",outPath:r}}),{ok:!0,data:{trace:"started",outPath:r}}}if(!a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active trace"}};let o=a.trace.outPath;if(t.positionals?.[1]){let e=iC.expandHome(t.positionals[1]);R.mkdirSync(n.dirname(e),{recursive:!0}),R.existsSync(o)?R.renameSync(o,e):R.appendFileSync(e,""),o=e}return a.trace=void 0,i.recordAction(a,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:o}}),{ok:!0,data:{trace:"stopped",outPath:o}}}return null}function aN(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function aS(e){let t=null,r=-1;for(let i of e){let e=i.width*i.height;e>r&&(t=i,r=e)}return t}function ab(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function a_(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??ih,o=t.command;if("press"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("press",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"press is not supported on this device"}};let s=function(e){if(e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return Number.isFinite(t)&&Number.isFinite(r)?{x:t,y:r}:null}(t.positionals??[]);if(s){let r=await a(e.device,"press",[String(s.x),String(s.y)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[String(s.x),String(s.y)],flags:t.flags??{},result:r??{x:s.x,y:s.y}}),{ok:!0,data:r??{x:s.x,y:s.y}}}let l="click",d=t.positionals?.[0]??"";if(d.startsWith("@")){let r=ak("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=aO({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=aM(p.rect);if(!m){let r=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),o=iB(r.nodes,c),l=s.length>0?ij(r.nodes,s):null,d=aM(l?.rect),u=aM(o?.rect)?o:d?l:o??l,h=aM(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=iW(p,f),w=i7(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=i0(u),p=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),f=await O("selector_resolve",()=>i2(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(c,f?.diagnostics??[],{unique:!0})}};let m=aM(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=i7(f.node,e.device.platform,{action:l}),v=iW(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!iS("fill",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"fill is not supported on this device"}};if(t.positionals?.[0]?.startsWith("@")){if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let r=ak("fill",t.flags);if(r)return r;let s=t.positionals.length>=3?t.positionals[1]:"",l=t.positionals.length>=3?t.positionals.slice(2).join(" "):t.positionals.slice(1).join(" ");if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after ref"}};let d=aO({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!iK(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=iW(c,p),w=i7(c,e.device.platform,{action:"fill"}),{x:g,y:I}=iq(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=i8(t.positionals??[],{preferTrailingValue:!0});if(s){if(0===s.rest.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let r=s.rest.join(" ").trim();if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires text after selector"}};let l=i0(s.selectorExpression),d=await aD(e,t.flags,i,n,{interactiveOnly:!0},a),u=await O("selector_resolve",()=>i2(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!iK(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=iq(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=i7(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:iW(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("get",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"get is not supported on this device"}};let l=t.positionals?.[1]??"";if(l.startsWith("@")){let r=ak("get",t.flags);if(r)return r;let n=aO({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=i7(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=iX(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=i0(d),c=await aD(s,t.flags,i,n,{interactiveOnly:!1},a),p=await O("selector_resolve",()=>i2(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!0})}};let f=p.node,m=i7(f,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,node:f}};let h=iX(f);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{text:h,refLabel:h||void 0,selector:p.selector.raw,selectorChain:m}}),{ok:!0,data:{selector:p.selector.raw,text:h,node:f}}}if("is"===o){let e=(t.positionals?.[0]??"").toLowerCase();if(!["visible","hidden","exists","editable","selected","text"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires predicate: visible|hidden|exists|editable|selected|text"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=i5(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=i0(l.selectorExpression),c=await aD(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=i3(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!1})}}}let p=await O("selector_resolve",()=>i2(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:i4(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=iX(r),o=!1;switch(t){case"visible":o=i6(r);break;case"hidden":o=!i6(r);break;case"editable":o=i9(r,n);break;case"selected":o=!0===r.selected;break;case"text":o=a===(i??"")}let s="text"===t?`expected="${i??""}" actual="${a}"`:`actual=${JSON.stringify({visible:i6(r),editable:i9(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iS("scrollintoview",e.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"scrollintoview is not supported on this device"}};let s=t.positionals?.[0]??"";if(!s.startsWith("@"))return null;let l=ak("scrollintoview",t.flags);if(l)return l;let d=aO({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=iq(t),i=e.filter(e=>{var t;return!!(t=e.rect)&&Number.isFinite(t.x)&&Number.isFinite(t.y)&&Number.isFinite(t.width)&&Number.isFinite(t.height)}),n=i.filter(e=>{let t=(e.type??"").toLowerCase();return t.includes("application")||t.includes("window")}),a=aS(n.map(e=>e.rect).filter(e=>aN(e,r.x,r.y)));if(a)return a;let o=aS(n.map(e=>e.rect));if(o)return o;let s=aS(i.map(e=>e.rect).filter(e=>aN(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:ab(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:ab(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=iW(c,p),w=i7(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function aD(e,t,r,i,n,a=ih){let o=await a(e.device,"snapshot",[],t?.out,{...i({...t??{},snapshotInteractiveOnly:n.interactiveOnly,snapshotCompact:n.interactiveOnly},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[];return e.snapshot={nodes:iU(t?.snapshotRaw?s:iJ(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let aE=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function ak(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of aE)void 0!==e[r]&&t.push(i);return t}(t);return 0===r.length?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} @ref does not support ${r.join(", ")}.`}}}function aO(e){let{session:t,refInput:r,fallbackLabel:i,requireRect:n,invalidRefMessage:a,notFoundMessage:o}=e;if(!t.snapshot)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:"No snapshot in session. Run snapshot first."}}};let s=iG(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=iB(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=ij(t.snapshot.nodes,i)),l&&(!n||l.rect))?{ok:!0,target:{ref:s,node:l,snapshotNodes:t.snapshot.nodes}}:{ok:!1,response:{ok:!1,error:{code:"COMMAND_FAILED",message:o}}}}function aM(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=iq(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function aL(e){return{tenantId:e.meta?.tenantId??e.flags?.tenant,runId:e.meta?.runId??e.flags?.runId,leaseId:e.meta?.leaseId??e.flags?.leaseId,leaseTtlMs:e.meta?.leaseTtlMs,leaseBackend:e.meta?.leaseBackend}}async function ax(e){let{req:t,leaseRegistry:r}=e,i=aL(t);switch(t.command){case"lease_allocate":return{ok:!0,data:{lease:r.allocateLease({tenantId:i.tenantId??"",runId:i.runId??"",backend:i.leaseBackend,ttlMs:i.leaseTtlMs})}};case"lease_heartbeat":return{ok:!0,data:{lease:r.heartbeatLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId,ttlMs:i.leaseTtlMs})}};case"lease_release":return{ok:!0,data:r.releaseLease({leaseId:i.leaseId??"",tenantId:i.tenantId,runId:i.runId})};default:return null}}let aC=new Set(["agent_device.command","agent-device.command"]),aT={"agent_device.lease.allocate":"lease_allocate","agent-device.lease.allocate":"lease_allocate","agent_device.lease.heartbeat":"lease_heartbeat","agent-device.lease.heartbeat":"lease_heartbeat","agent_device.lease.release":"lease_release","agent-device.lease.release":"lease_release"},aR=new Set([...aC,...Object.keys(aT)]);function aP(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function a$(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function aF(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function aV(e,t){let r="string"==typeof t.authorization?t.authorization:"",i=r.toLowerCase().startsWith("bearer ")?r.slice(7):void 0,n="string"==typeof t["x-agent-device-token"]?t["x-agent-device-token"]:void 0;return("string"==typeof e.token?e.token:void 0)??n??i??""}function aU(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function aG(e,t){if(!e)return{ok:!0};let r=await e(t);if(void 0===r||!0===r)return{ok:!0};if(!1===r){let e=b(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:aP(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=b(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:aP(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=c(r.tenantId);if(!e){let e=b(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:aP(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function aB(){let e,t=process.env.AGENT_DEVICE_HTTP_AUTH_HOOK;if(!t)return null;let r=process.env.AGENT_DEVICE_HTTP_AUTH_EXPORT||"default",i=n.isAbsolute(t)?t:n.resolve(t);try{e=await import(g(i).href)}catch(e){throw new I("COMMAND_FAILED","Failed to load AGENT_DEVICE_HTTP_AUTH_HOOK module",{hookPath:i,error:e instanceof Error?e.message:String(e)})}let a=e[r];if("function"!=typeof a)throw new I("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function aq(e){let t=await aB(),{handleRequest:r}=e;return i.createServer((e,i)=>{if("GET"===e.method&&"/health"===e.url){i.statusCode=200,i.setHeader("content-type","application/json"),i.end(JSON.stringify({ok:!0}));return}if("POST"!==e.method||"/rpc"!==e.url){i.statusCode=404,i.end("Not found");return}let n="";e.setEncoding("utf8"),e.on("data",t=>{(n+=t).length>1048576&&e.destroy(Error("request too large"))}),e.on("error",()=>{i.headersSent||a$(i,aP(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a;try{a=JSON.parse(n)}catch{a$(i,aP(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void a$(i,aP(a.id??null,-32600,"Invalid Request"),400);if(!aR.has(a.method))return void a$(i,aP(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void a$(i,aP(a.id??null,-32602,"Invalid params"),400);try{var o;let n=a.params,s=function(e,t,r){if(aC.has(e))return{token:aV(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=aT[e];if(i){let e;return{token:aV(t,r),session:aU(t,"session")??"default",command:i,positionals:[],meta:{tenantId:aU(t,"tenantId")??aU(t,"tenant"),runId:aU(t,"runId"),leaseId:aU(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:aU(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(o=a.method,aC.has(o)&&("string"!=typeof s.command||0===s.command.length))return void a$(i,aP(a.id??null,-32602,"Invalid params: command is required"),400);let l=await aG(t,{headers:e.headers,rpcRequest:a,daemonRequest:s});if(!l.ok)return void a$(i,l.response,l.statusCode);l.tenantId&&(s.meta={...s.meta,tenantId:l.tenantId,sessionIsolation:s.meta?.sessionIsolation??s.flags?.sessionIsolation??"tenant"});let d=await r(s);if(d.ok)return void a$(i,{jsonrpc:"2.0",id:a.id??null,result:d});a$(i,aP(a.id??null,-32e3,d.error.message,d.error),aF(d.error.code))}catch(t){let e=b(t);a$(i,aP(a.id??null,-32e3,e.message,e),aF(e.code))}})})}function aj(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function aW(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function aH(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class aJ{leases=new Map;runBindings=new Map;maxActiveSimulatorLeases;defaultLeaseTtlMs;minLeaseTtlMs;maxLeaseTtlMs;now;constructor(e={}){this.maxActiveSimulatorLeases=Number.isInteger(e.maxActiveSimulatorLeases)?Math.max(0,Number(e.maxActiveSimulatorLeases)):0,this.defaultLeaseTtlMs=Number.isInteger(e.defaultLeaseTtlMs)?Math.max(1,Number(e.defaultLeaseTtlMs)):6e4,this.minLeaseTtlMs=Number.isInteger(e.minLeaseTtlMs)?Math.max(1,Number(e.minLeaseTtlMs)):5e3,this.maxLeaseTtlMs=Number.isInteger(e.maxLeaseTtlMs)?Math.max(this.minLeaseTtlMs,Number(e.maxLeaseTtlMs)):6e5,this.now=e.now??(()=>Date.now())}allocateLease(e){let t=aH(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=aj(e.runId);if(!i)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");this.cleanupExpiredLeases();let n=this.resolveLeaseTtlMs(e.ttlMs),a=this.bindingKey(r,i,t),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:f.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=aW(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});this.assertOptionalScopeMatch(r,e.tenantId,e.runId);let i=this.resolveLeaseTtlMs(e.ttlMs);return this.refreshLease(r,i)}releaseLease(e){let t=aW(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);return r?(this.assertOptionalScopeMatch(r,e.tenantId,e.runId),this.leases.delete(t),this.runBindings.delete(this.bindingKey(r.tenantId,r.runId,r.backend)),{released:!0}):{released:!1}}assertLeaseAdmission(e){let t=aH(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=aj(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=aW(e.leaseId);if(!n)throw new I("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}listActiveLeases(){return this.cleanupExpiredLeases(),Array.from(this.leases.values()).map(e=>({...e}))}cleanupExpiredLeases(){let e=this.now();for(let t of this.leases.values())t.expiresAt>e||(this.leases.delete(t.leaseId),this.runBindings.delete(this.bindingKey(t.tenantId,t.runId,t.backend)))}enforceCapacity(e){if("ios-simulator"!==e||this.maxActiveSimulatorLeases<=0)return;let t=Array.from(this.leases.values()).filter(e=>"ios-simulator"===e.backend).length;if(!(t<this.maxActiveSimulatorLeases))throw new I("COMMAND_FAILED","No simulator lease capacity available",{reason:"LEASE_CAPACITY_EXCEEDED",activeLeases:t,maxActiveLeases:this.maxActiveSimulatorLeases,backend:e,hint:"Retry after releasing another simulator lease."})}resolveLeaseTtlMs(e){if(!Number.isInteger(e))return this.defaultLeaseTtlMs;let t=Number(e);if(t<this.minLeaseTtlMs||t>this.maxLeaseTtlMs)throw new I("INVALID_ARGS",`Lease ttlMs must be between ${this.minLeaseTtlMs} and ${this.maxLeaseTtlMs}.`);return t}refreshLease(e,t){let r=this.now(),i={...e,heartbeatAt:r,expiresAt:r+t};return this.leases.set(i.leaseId,i),this.runBindings.set(this.bindingKey(i.tenantId,i.runId,i.backend),i.leaseId),{...i}}bindingKey(e,t,r){return`${e}:${t}:${r}`}assertOptionalScopeMatch(e,t,r){let i=c(t),n=aj(r);if(t&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(i&&e.tenantId!==i||n&&e.runId!==n)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}let{baseDir:az,infoPath:aK,lockPath:aX,logPath:aY,sessionsDir:aZ}=G(process.env.AGENT_DEVICE_STATE_DIR),aQ=U(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var a0=aZ;if(R.existsSync(a0))for(let e of R.readdirSync(a0,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(a0,e.name,"app-log.pid");if(R.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}(R.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{nc(t)}}let a1=new iC(aZ),a2=new aJ({maxActiveSimulatorLeases:oa(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:oa(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),a3=D(),a4=f.randomBytes(24).toString("hex"),a8=new Set(["session_list","devices"]),a5=new Set(["session_list","devices","lease_allocate","lease_heartbeat","lease_release"]),a6=T(process.pid)??void 0,a9=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function a7(e,t,r){let i=k().requestId;return{...iT(aY,e,t,r,i),requestId:i}}async function oe(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:aY},async()=>{if(r.token!==a4)return{ok:!1,error:b(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=_(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=c(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(r);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=aL(e);a5.has(t)||e.meta?.sessionIsolation!=="tenant"||a2.assertLeaseAdmission({tenantId:i.tenantId,runId:i.runId,leaseId:i.leaseId,backend:i.leaseBackend});let n=function(e,t){var r;let i,n=e.session||"default";if(r=e,i=r.flags?.session,"string"==typeof i&&i.trim().length>0||"default"!==n||t.has(n))return n;let a=t.toArray();return 1===a.length?a[0].name:n}(e,a1),a=a1.get(n);a&&!a8.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=q(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=ea(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(a,e.flags);let o=await ax({req:e,leaseRegistry:a2});if(o)return ot(o);let s=await n8({req:e,sessionName:n,logPath:aY,sessionStore:a1,invoke:oe});if(s)return ot(s);let l=await al({req:e,sessionName:n,logPath:aY,sessionStore:a1});if(l)return ot(l);let d=await ay({req:e,sessionName:n,sessionStore:a1,logPath:aY});if(d)return ot(d);let u=await ag({req:e,sessionName:n,logPath:aY,sessionStore:a1,invoke:oe});if(u)return ot(u);let p=await a_({req:e,sessionName:n,sessionStore:a1,contextFromFlags:a7});if(p)return ot(p);let f=a1.get(n);if(!f)return ot({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!iS(t,f.device))return ot({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await ih(f.device,t,e.positionals??[],e.flags?.out,{...a7(e.flags,f.appBundleId,f.trace?.outPath)});return a1.recordAction(f,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),ot({ok:!0,data:m??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=k(),t=$({force:!0})??void 0;return{ok:!1,error:b(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function ot(e){let t=k();if(!e.ok){M({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:b(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return M({level:"info",phase:"request_success"}),$(),e}function or(){R.existsSync(aK)&&R.unlinkSync(aK)}function oi(){if(!R.existsSync(aX))return null;try{let e=JSON.parse(R.readFileSync(aX,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function on(){let e=oi();if(!e||e.pid===process.pid)try{R.existsSync(aX)&&R.unlinkSync(aX)}catch{}}function oa(e){if(void 0===e)return;let t=Number(e);if(Number.isInteger(t))return t}(async function e(){let e,t;if(!function(){R.existsSync(az)||R.mkdirSync(az,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:a3,startedAt:Date.now(),processStartTime:a6},null,2),t=()=>{try{return R.writeFileSync(aX,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=oi();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(aX)}catch{}return t()}()){process.stderr.write("Daemon lock is held by another process; exiting.\n"),process.exit(0);return}let r=[];try{var i;let n;if("socket"===aQ||"dual"===aQ){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&t4.add(e);M({level:"warn",phase:"request_client_disconnected",data:{inFlightRequests:r}}),(async()=>{let e=Date.now()+15e3;for(;r>0&&Date.now()<e&&(await rI(),!(r<=0));)await new Promise(e=>setTimeout(e,200))})()}};e.setEncoding("utf8"),e.on("close",a),e.on("error",a),e.on("data",async n=>{let a=(t+=n).indexOf("\n");for(;-1!==a;){let n,s,l=t.slice(0,a).trim();if(t=t.slice(a+1),0===l.length){a=t.indexOf("\n");continue}r+=1;try{let e=JSON.parse(l);if((s=e.meta?.requestId)&&(i.add(s),t8(s)))throw new I("COMMAND_FAILED","request canceled");n=await oe(e)}catch(e){n={ok:!1,error:b(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&t4.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
30
|
-
`)
|
|
18
|
+
${i}`.toLowerCase();return n.includes("unknown option '--device'")||n.includes("unknown subcommand")&&n.includes("screenshot")||n.includes("unrecognized subcommand")&&n.includes("screenshot")}(t))throw t;rQ(e,"devicectl_screenshot",t)}await rK(e,t,r)}async function rJ(e,t,r,i=rW){if("simulator"!==e.kind)throw new I("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");await i.ensureBooted(e);try{await i.captureWithRetry(e,t);return}catch(t){if(!i.shouldFallbackToRunner(t))throw t;rQ(e,"simctl_screenshot",t)}await i.captureWithRunner(e,t,r)}async function rz(e,t){let r=ee.fromTimeoutMs(tq);await tQ(),await et(async({attempt:r,deadline:i})=>{r>1&&await tQ(),await rq(e,["io",e.id,"screenshot",t],{timeoutMs:Math.max(1e3,i?.remainingMs()??tq)})},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>r0(e)},{deadline:r,phase:"ios_simulator_screenshot"})}async function rK(e,t,r){let i=(await rB(e,{command:"screenshot",appBundleId:r})).message;if(!i)throw new I("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");"simulator"===e.kind?await rY(e,i,t):await rX(e,i,t)}async function rX(e,t,r){let i=ee.fromTimeoutMs(tW),n={exitCode:1,stdout:"",stderr:""};for(let a of r_)if(0===(n=await p("xcrun",["devicectl","device","copy","from","--device",e.id,"--source",t,"--destination",r,"--domain-type","appDataContainer","--domain-identifier",a],{allowFailure:!0,timeoutMs:rZ(i,tW,"runner screenshot copy")})).exitCode)return;let a=n.stderr.trim()||n.stdout.trim()||`devicectl exited with code ${n.exitCode}`;throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}async function rY(e,t,r){let i=ee.fromTimeoutMs(tW),a="Unable to locate runner container for simulator screenshot";for(let o of r_){let s=await rq(e,["get_app_container",e.id,o,"data"],{allowFailure:!0,timeoutMs:rZ(i,tW,"runner screenshot container lookup")});if(0!==s.exitCode){let e=s.stderr.trim();e&&(a=e);continue}let l=s.stdout.trim();if(!l){a="simctl get_app_container returned empty output";continue}for(let e of function(e,t){let r=n.resolve(e),i=t.trim();if(!i)return[];let a=[],o=new Set,s=e=>{let t=n.normalize(e);o.has(t)||(o.add(t),a.push(t))},l=i.replace(/^\/+/,""),d=l.replace(/\\/g,"/");if(l&&s(n.join(r,l)),n.isAbsolute(i)&&s(n.normalize(i)),d.startsWith("tmp/"))s(n.join(r,d));else{let e=d.lastIndexOf("/tmp/");if(e>=0){let t=d.slice(e+1);s(n.join(r,t))}}let u=n.basename(i);return u&&s(n.join(r,"tmp",u)),a}(l,t))try{await x.copyFile(e,r);return}catch(e){a=e instanceof Error?e.message:String(e)}}throw new I("COMMAND_FAILED",`Failed to capture iOS screenshot: ${a}`)}function rZ(e,t,r){let i=e.remainingMs();if(i>0)return i;throw new I("COMMAND_FAILED",`iOS ${r} timed out after ${t}ms`,{timeoutMs:t,step:r})}function rQ(e,t,r){let i=function(e){if(!(e instanceof I))return{reason:e instanceof Error?e.message:String(e)};let t=e.details??{},r=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):void 0;return{errorCode:e.code,reason:e.message,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:void 0,exitCode:"number"==typeof t.exitCode?t.exitCode:void 0,stderr:"string"==typeof t.stderr&&t.stderr.trim()?t.stderr:void 0,stdout:"string"==typeof t.stdout&&t.stdout.trim()?t.stdout:void 0,commandArgs:r}}(r);M({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...i}})}function r0(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{},r="string"==typeof t.stdout?t.stdout:"",i="string"==typeof t.stderr?t.stderr:"",n=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):"",a=`${e.message}
|
|
19
|
+
${r}
|
|
20
|
+
${i}
|
|
21
|
+
${n}`.toLowerCase();return a.includes("timeout waiting for screen surfaces")||a.includes("nsposixerrordomain")&&a.includes("code=60")&&a.includes("screenshot")||a.includes("timed out")&&a.includes("screenshot")}let r1={settings:"com.apple.Preferences"},r2=null;function r3(e,t,r){return p("xcrun",tY(e,t),r)}function r4(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function r8(e){let t=n.join(e,"Info.plist");try{let e=await p("plutil",["-extract","CFBundleIdentifier","raw","-o","-",t],{allowFailure:!0});if(0!==e.exitCode)return;let r=String(e.stdout??"").trim();return r.length>0?r:void 0}catch{return}}function r5(e){return e.bundleId?`${e.bundleName}.app (${e.bundleId})`:`${e.bundleName}.app`}async function r6(e){await Promise.all(e.map(async e=>{void 0===e.bundleId&&(e.bundleId=await r8(e.installPath))}))}async function r9(e,t){if(".ipa"!==n.extname(e).toLowerCase())return{installPath:e,cleanup:async()=>{}};let r=await x.mkdtemp(n.join(F.tmpdir(),"agent-device-ios-ipa-")),i=async()=>{await x.rm(r,{recursive:!0,force:!0})};try{await p("ditto",["-x","-k",e,r]);let a=n.join(r,"Payload"),o=(await x.readdir(a,{withFileTypes:!0}).catch(()=>{throw new I("INVALID_ARGS","Invalid IPA: missing Payload directory")})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(".app")).map(e=>({installPath:n.join(a,e.name),bundleName:e.name.replace(/\.app$/i,"")}));if(1===o.length)return{installPath:o[0].installPath,cleanup:i};if(0===o.length)throw new I("INVALID_ARGS","Invalid IPA: expected at least one .app under Payload, found 0");await r6(o);let s=t?.appIdentifierHint?.trim();if(s){let e=s.toLowerCase(),t=o.filter(t=>t.bundleName.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i};if(t.length>1)throw new I("INVALID_ARGS",`Invalid IPA: multiple app bundles matched "${s}" by name. Use a bundle id hint instead.`);if(s.includes(".")){let t=o.filter(t=>t.bundleId?.toLowerCase()===e);if(1===t.length)return{installPath:t[0].installPath,cleanup:i}}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload and none matched "${s}". Available bundles: ${o.map(r5).join(", ")}`)}throw new I("INVALID_ARGS",`Invalid IPA: found ${o.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${o.map(r5).join(", ")}`)}catch(e){throw await i(),e}}async function r7(e,t){let r=t.trim();if(r.includes("."))return r;let i=r1[r.toLowerCase()];if(i)return i;let n=("simulator"===e.kind?await ip(e):await tJ(e,"all")).filter(e=>e.name.toLowerCase()===r.toLowerCase());if(1===n.length)return n[0].bundleId;if(n.length>1)throw new I("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:n});throw new I("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function ie(e,t,r){let i=r?.url?.trim();if(i){if(!J(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){await t0(e),await tQ(),await r3(e,["openurl",e.id,i]);return}let n=z(r?.appBundleId??await r7(e,t),i);if(!n)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await iS(e,n,{payloadUrl:i});return}let n=t.trim();if(J(n)){if("simulator"===e.kind){await t0(e),await tQ(),await r3(e,["openurl",e.id,n]);return}let t=z(r?.appBundleId,n);if(!t)throw new I("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await iS(e,t,{payloadUrl:n});return}let a=r?.appBundleId??await r7(e,t);"simulator"===e.kind?await iN(e,a):await iS(e,a)}async function it(e){"simulator"!==e.kind||"Booted"!==await t2(e)&&(await t0(e),await tQ())}async function ir(e,t){let r=await r7(e,t);if("simulator"===e.kind){await t0(e);let t=tY(e,["terminate",e.id,r]),i=await p("xcrun",t,{allowFailure:!0});if(0!==i.exitCode){if(i.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new I("COMMAND_FAILED",`xcrun exited with code ${i.exitCode}`,{cmd:"xcrun",args:t,stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}return}await tH(["device","process","terminate","--device",e.id,r],{action:"terminate iOS app",deviceId:e.id})}async function ii(e,t){let r=await r7(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,r],i=await p("xcrun",t,{allowFailure:!0,timeoutMs:tj});if(0!==i.exitCode){let n=String(i.stdout??""),a=String(i.stderr??"");if(!r4(`${n}
|
|
22
|
+
${a}`.toLowerCase()))throw new I("COMMAND_FAILED",`Failed to uninstall iOS app ${r}`,{cmd:"xcrun",args:t,exitCode:i.exitCode,stdout:n,stderr:a,deviceId:e.id,hint:tK(n,a)??tz})}return{bundleId:r}}await t0(e);let i=await r3(e,["uninstall",e.id,r],{allowFailure:!0});if(0!==i.exitCode&&!r4(`${i.stdout}
|
|
23
|
+
${i.stderr}`.toLowerCase()))throw new I("COMMAND_FAILED",`simctl uninstall failed for ${r}`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{bundleId:r}}async function ia(e,t,r){let{installPath:i,cleanup:n}=await r9(t,r);try{if("simulator"!==e.kind)return void await tH(["device","install","app","--device",e.id,i],{action:"install iOS app",deviceId:e.id});await t0(e),await r3(e,["install",e.id,i])}finally{await n()}}async function io(e,t,r){let{bundleId:i}=await ii(e,t);return await ia(e,r,{appIdentifierHint:t}),{bundleId:i}}async function is(e){tZ(e,"clipboard"),await t0(e);let t=await r3(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new I("COMMAND_FAILED","Failed to read iOS simulator clipboard",{stdout:t.stdout,stderr:t.stderr,exitCode:t.exitCode});return t.stdout.replace(/\r\n/g,"\n").replace(/\n$/,"")}async function il(e,t){tZ(e,"clipboard"),await t0(e);let r=await r3(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==r.exitCode)throw new I("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}async function id(e,t,r){tZ(e,"push"),await t0(e);let i=await x.mkdtemp(n.join(F.tmpdir(),"agent-device-ios-push-")),a=n.join(i,"payload.apns");try{await x.writeFile(a,`${JSON.stringify(r)}
|
|
24
|
+
`,"utf8"),await r3(e,["push",e.id,t,a])}finally{await x.rm(i,{recursive:!0,force:!0})}}async function iu(e,t,r,i,n){tZ(e,"settings"),await t0(e);let a=t.toLowerCase();switch(a){case"wifi":{let t=im(r);await r3(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(im(r)?await r3(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await r3(e,["status_bar",e.id,"clear"]));case"location":{let t=im(r);if(!i)throw new I("INVALID_ARGS","location setting requires an active app in session");await r3(e,["privacy",e.id,t?"grant":"revoke","location",i]);return}case"faceid":case"touchid":{let t=iw[a],i=function(e,t){let r=e.trim().toLowerCase();if("match"===r)return"match";if("nonmatch"===r)return"nonmatch";if("enroll"===r)return"enroll";if("unenroll"===r)return"unenroll";throw new I("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(r,a);await iA(e,i,{settingName:a,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await ih(e,r);await r3(e,["ui",e.id,"appearance",t]);return}case"permission":{var o;if(!i)throw new I("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(o=tO(r))?"revoke":o,a=function(e,t){let r=tk(e);if("photos"!==r&&t?.trim())throw new I("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===r)return"camera";if("microphone"===r)return"microphone";if("contacts"===r)return"contacts";if("contacts-limited"===r)return"contacts-limited";if("notifications"===r)return"notifications";if("calendar"===r)return"calendar";if("location"===r)return"location";if("location-always"===r)return"location-always";if("media-library"===r)return"media-library";if("motion"===r)return"motion";if("reminders"===r)return"reminders";if("siri"===r)return"siri";if("photos"===r){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new I("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new I("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(n?.permissionTarget,n?.permissionMode);await ig(e,t,a,i);return}default:throw new I("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function ic(e,t="all"){var r;return"simulator"===e.kind?(r=await ip(e),"user-installed"===t?r.filter(e=>!e.bundleId.startsWith("com.apple.")):r):await tJ(e,t)}async function ip(e){let t=(await r3(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let r=null;if(t.startsWith("{"))try{r=JSON.parse(t)}catch{r=null}if(!r&&t.startsWith("{"))try{let e=await p("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(r=JSON.parse(e.stdout))}catch{r=null}return r?Object.entries(r).map(([e,t])=>({bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e})):[]}function im(e){let t=e.toLowerCase();if("on"===t||"true"===t||"1"===t)return!0;if("off"===t||"false"===t||"0"===t)return!1;throw new I("INVALID_ARGS",`Invalid setting state: ${e}`)}async function ih(e,t){let r=tM(t);if("toggle"!==r)return r;let i=await r3(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==i.exitCode)throw new I("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});let n=function(e,t){let r=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
|
|
25
|
+
${t}`);if(!r)return null;let i=r[1].toLowerCase();return"dark"===i?"dark":"light"===i?"light":null}(i.stdout,i.stderr);if(!n)throw new I("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:i.stdout,stderr:i.stderr});return"dark"===n?"light":"dark"}let iw={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function ig(e,t,r,i){let n=await iv(e);if(!n.has(r))throw new I("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(n).sort().join(", ")}`});let a=["privacy",e.id,t,r,i],o="notifications"===r;if(!("reset"===t&&o))try{await r3(e,a);return}catch(t){if(!(o&&iI(t)))throw t;throw new I("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:i,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await r3(e,a);return}catch(e){if(!iI(e))throw e}try{await r3(e,["privacy",e.id,"reset","all",i])}catch(t){throw new I("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:i,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function iI(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=String(e.details?.stderr??"").toLowerCase();return(t.includes("failed to grant access")||t.includes("failed to revoke access")||t.includes("failed to reset access"))&&t.includes("operation not permitted")}async function iv(t){let r=el(t.simulatorSetPath),i=`${process.env.PATH??""}::${r??""}`;if(r2&&e===i)return r2;let n=await r3(t,["privacy","help"],{allowFailure:!0}),a=function(e){let t=new Set,r=!1;for(let i of e.split("\n")){let e=i.trim();if(!e)continue;if("service"===e){r=!0;continue}if(!r)continue;if(e.startsWith("bundle identifier"))break;let n=/^([a-z-]+)\s+-\s+/.exec(e);n&&t.add(n[1])}return t}(`${n.stdout}
|
|
26
|
+
${n.stderr}`);if(0===a.size)throw new I("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return r2=a,e=i,a}async function iA(e,t,r){let i=function(e,t,r){let i=r.length>0?r:["face"];switch(t){case"match":return i.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return i.flatMap(t=>[["biometric",e,"nonmatch",t],["biometric",e,"nomatch",t],["biometric","nonmatch",e,t],["biometric","nomatch",e,t]]);case"enroll":return[["biometric",e,"enroll","yes"],["biometric",e,"enroll","1"],["biometric","enroll",e,"yes"],["biometric","enroll",e,"1"]];case"unenroll":return[["biometric",e,"enroll","no"],["biometric",e,"enroll","0"],["biometric","enroll",e,"no"],["biometric","enroll",e,"0"]]}}(e.id,t,r.modalityAliases),n=[];for(let t of i){let r=tY(e,t),i=await p("xcrun",r,{allowFailure:!0});if(0===i.exitCode)return;n.push({args:r,stderr:i.stderr,stdout:i.stdout,exitCode:i.exitCode})}let a=n.map(e=>({args:e.args.join(" "),exitCode:e.exitCode,stderr:e.stderr.slice(0,400)}));if(n.length>0&&n.every(e=>{var t,r;let i;return t=e.stdout,r=e.stderr,(i=`${t}
|
|
27
|
+
${r}`.toLowerCase()).includes("unrecognized subcommand")||i.includes("unknown subcommand")||i.includes("not supported")||i.includes("unavailable")||i.includes("biometric")&&i.includes("invalid")}))throw new I("UNSUPPORTED_OPERATION",`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a});throw new I("COMMAND_FAILED",`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:t,setting:r.settingName,attempts:a})}function iy(e){if(!(e instanceof I)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let r=String(t.stderr??"").toLowerCase();return r.includes("fbsopenapplicationserviceerrordomain")&&r.includes("the request to open")}async function iN(e,t){await t0(e),await tQ();let r=ee.fromTimeoutMs(tB);await et(async({deadline:r})=>{if(r?.isExpired())throw new I("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:tB});let i=tY(e,["launch",e.id,t]),n=await p("xcrun",i,{allowFailure:!0});if(0!==n.exitCode)throw new I("COMMAND_FAILED",`xcrun exited with code ${n.exitCode}`,{cmd:"xcrun",args:i,stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode})},{maxAttempts:30,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:iy},{deadline:r})}async function iS(e,t,r){let i=["device","process","launch","--device",e.id,t];r?.payloadUrl&&i.push("--payload-url",r.payloadUrl),await tH(i,{action:"launch iOS app",deviceId:e.id})}let i_=/^[A-Za-z0-9_.:-]{1,64}$/,ib=[[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[1,-1],[-1,-1]];function iD(e,t,r,i){if(!Number.isFinite(e)||!Number.isInteger(e)||e<r||e>i)throw new I("INVALID_ARGS",`${t} must be an integer between ${r} and ${i}`);return e}async function iE(e,t,r){for(let i=0;i<e;i+=1)await r(i),i<e-1&&t>0&&await iO(t)}async function iO(e){await new Promise(t=>setTimeout(t,e))}function ik(e,t){let r,i=t?.subject??"Payload",n=e.trim();if(!n)throw new I("INVALID_ARGS",`${i} cannot be empty`);let a=t?.expandPath?t.expandPath(n,t.cwd):n;try{if(!R.statSync(a).isFile())throw new I("INVALID_ARGS",`${i} path is not a file: ${a}`);return{kind:"file",path:a}}catch(t){if(t instanceof I)throw t;let e=t.code;if("EACCES"===e||"EPERM"===e)throw new I("INVALID_ARGS",`${i} file is not readable: ${a}`);if(e&&"ENOENT"!==e)throw new I("COMMAND_FAILED",`Unable to read ${i} file: ${a}`,{cause:String(t)})}if((r=n.trim()).startsWith("{")&&r.endsWith("}")||r.startsWith("[")&&r.endsWith("]"))return{kind:"inline",text:n};throw new I("INVALID_ARGS",`${i} file not found: ${a}`)}async function iM(e){let t=ik(e,{subject:"Push payload"}),r="inline"===t.kind?t.text:await iL(t.path);try{let e=JSON.parse(r);if(!e||"object"!=typeof e||Array.isArray(e))throw new I("INVALID_ARGS","push payload must be a JSON object");return e}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid push payload JSON: ${e}`)}}async function iL(e){try{return await x.readFile(e,"utf8")}catch(r){let t=r.code;if("ENOENT"===t)throw new I("INVALID_ARGS",`Push payload file not found: ${e}`);if("EISDIR"===t)throw new I("INVALID_ARGS",`Push payload path is not a file: ${e}`);if("EACCES"===t||"EPERM"===t)throw new I("INVALID_ARGS",`Push payload file is not readable: ${e}`);throw new I("COMMAND_FAILED",`Unable to read push payload file: ${e}`,{cause:String(r)})}}let ix=tV(process.env.AGENT_DEVICE_IOS_DEVICECTL_LIST_TIMEOUT_MS,8e3,500),iC=/^(iphone|ipad|ipod|appletv)/i,iT=/^appletv/i,iR=["apple tv","appletv","tvos"];function iP(e){return(e??"").trim().toLowerCase()}function i$(e){return iP(e.hardwareProperties?.platform)}function iF(e){return e.includes("tvos")}function iV(e){let t=iP(e);return iR.some(e=>t.includes(e))}function iU(e){return[e.name??"",e.deviceProperties?.name??"",e.deviceProperties?.deviceType??""]}function iG(e){return e.hardwareProperties?.productType??e.deviceProperties?.productType??""}async function iB(e={}){if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","iOS tools are only available on macOS");if(!await v("xcrun"))throw new I("TOOL_MISSING","xcrun not found in PATH");let t=[],r=el(e.simulatorSetPath),i=await p("xcrun",tX(["list","devices","-j"],{simulatorSetPath:r}));try{let e=JSON.parse(i.stdout);for(let[i,n]of Object.entries(e.devices))if(function(e){let t=iP(e);return t.includes("ios")||t.includes("tvos")}(i))for(let e of n){var a;e.isAvailable&&t.push({platform:"ios",id:e.udid,name:e.name,kind:"simulator",target:(a=i,iF(iP(a))?"tv":"mobile"),booted:"Booted"===e.state,...r?{simulatorSetPath:r}:{}})}}catch(e){throw new I("COMMAND_FAILED","Failed to parse simctl devices JSON",void 0,e)}if(r)return t;let o=null;try{o=n.join(F.tmpdir(),`agent-device-devicectl-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);let e=await p("xcrun",["devicectl","list","devices","--json-output",o],{allowFailure:!0,timeoutMs:ix});if(0!==e.exitCode)return t;let r=await x.readFile(o,"utf8"),i=JSON.parse(r);for(let e of i.result?.devices??[])if(function(e){var t;let r=i$(e);return!!(r.includes("ios")||r.includes("tvos"))||(t=iG(e),!!iC.test(t.trim())||iU(e).some(iV))}(e)){let r=e.hardwareProperties?.udid??e.identifier??"",i=e.name??e.deviceProperties?.name??r;if(!r)continue;t.push({platform:"ios",id:r,name:i,kind:"device",target:function(e){var t;return iF(i$(e))?"tv":(t=iG(e),iT.test(t.trim())||iU(e).some(iV))?"tv":"mobile"}(e),booted:!0})}}catch{}finally{o&&await x.rm(o,{force:!0}).catch(()=>{})}return t}async function ij(e){let t=rw(e.platform),r=el(e.iosSimulatorDeviceSet),i=eu(e.androidDeviceAllowlist);return await k("resolve_target_device",async()=>{let n={platform:t,target:e.target,deviceName:e.device,udid:e.udid,serial:e.serial};if(n.target&&!n.platform)throw new I("INVALID_ARGS","Device target selector requires --platform. Use --platform ios|android|apple with --target mobile|tv.");if("android"===n.platform){await q();let e=await e_({serialAllowlist:i});return await rg(e,n)}if("ios"===n.platform){let e=await iB({simulatorSetPath:r});return await rg(e,n,{simulatorSetPath:r})}let a=[];try{a.push(...await e_({serialAllowlist:i}))}catch{}try{a.push(...await iB({simulatorSetPath:r}))}catch{}return await rg(a,n,{simulatorSetPath:r})},{platform:t,target:e.target})}async function iq(e,t,r,i,a){let o=function(e,t){switch(e.platform){case"android":return{open:(t,r)=>ej(e,t,r?.activity),openDevice:()=>eW(e),close:t=>eH(e,t),tap:(t,r)=>tn(e,t,r),doubleTap:async(t,r)=>{await tn(e,t,r),await tn(e,t,r)},swipe:(t,r,i,n,a)=>ta(e,t,r,i,n,a),longPress:(t,r,i)=>td(e,t,r,i),focus:(t,r)=>tc(e,t,r),type:t=>tu(e,t),fill:(t,r,i)=>tp(e,t,r,i),scroll:(t,r)=>tf(e,t,r),scrollIntoView:t=>tm(e,t),screenshot:(t,r)=>e7(e,t)};case"ios":var r,i;let n,a;return{open:(t,r)=>ie(e,t,{appBundleId:r?.appBundleId,url:r?.url}),openDevice:()=>it(e),close:t=>ir(e,t),screenshot:(t,r)=>rH(e,t,r),...(r=e,n={verbose:(i=t).verbose,logPath:i.logPath,traceLogPath:i.traceLogPath,requestId:i.requestId},a=()=>{if(t4(i.requestId))throw new I("COMMAND_FAILED","request canceled")},{tap:async(e,t)=>{await rB(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},doubleTap:async(e,t)=>{await rB(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 rB(r,{command:"drag",x:e,y:t,x2:a,y2:o,durationMs:s,appBundleId:i.appBundleId},n)},longPress:async(e,t,a)=>{await rB(r,{command:"longPress",x:e,y:t,durationMs:a,appBundleId:i.appBundleId},n)},focus:async(e,t)=>{await rB(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n)},type:async e=>{await rB(r,{command:"type",text:e,appBundleId:i.appBundleId},n)},fill:async(e,t,a)=>{await rB(r,{command:"tap",x:e,y:t,appBundleId:i.appBundleId},n),await rB(r,{command:"type",text:a,clearFirst:!0,appBundleId:i.appBundleId},n)},scroll:async(e,t)=>{if(!["up","down","left","right"].includes(e))throw new I("INVALID_ARGS",`Unknown direction: ${e}`);let a=function(e){switch(e){case"up":return"down";case"down":return"up";case"left":return"right";case"right":return"left"}}(e);await rB(r,{command:"swipe",direction:a,appBundleId:i.appBundleId},n)},scrollIntoView:async e=>{let t=await rB(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 rB(r,{command:"swipe",direction:"up",appBundleId:i.appBundleId},n),await new Promise(e=>setTimeout(e,80));a();let o=await rB(r,{command:"findText",text:e,appBundleId:i.appBundleId},n);if(o?.found)return{attempts:t+2}}throw new I("COMMAND_FAILED",`scrollintoview could not find text: ${e}`)}})};default:throw new I("UNSUPPORTED_PLATFORM",`Unsupported platform: ${e.platform}`)}}(e,{requestId:a?.requestId,appBundleId:a?.appBundleId,verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath});return M({level:"debug",phase:"platform_command_prepare",data:{command:t,platform:e.platform,kind:e.kind}}),await k("platform_command",async()=>{switch(t){case"open":{let t=r[0],i=r[1];if(r.length>2)throw new I("INVALID_ARGS","open accepts at most two arguments: <app|url> [url]");if(!t)return await o.openDevice(),{app:null};if(void 0!==i){if("ios"!==e.platform)throw new I("INVALID_ARGS","open <app> <url> is supported only on iOS");if(J(t))throw new I("INVALID_ARGS","open <app> <url> requires an app target as the first argument");if(!J(i))throw new I("INVALID_ARGS","open <app> <url> requires a valid URL target");return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId,url:i}),{app:t,url:i}}return await o.open(t,{activity:a?.activity,appBundleId:a?.appBundleId}),{app:t}}case"close":{let e=r[0];if(!e)return{closed:"session"};return await o.close(e),{app:e}}case"press":{let[t,i]=r.map(Number);if(Number.isNaN(t)||Number.isNaN(i))throw new I("INVALID_ARGS","press requires x y");let n=iD(a?.count??1,"count",1,200),s=iD(a?.intervalMs??0,"interval-ms",0,1e4),l=iD(a?.holdMs??0,"hold-ms",0,1e4),d=iD(a?.jitterPx??0,"jitter-px",0,100),u=a?.doubleTap===!0;if(u&&l>0)throw new I("INVALID_ARGS","double-tap cannot be combined with hold-ms");if(u&&d>0)throw new I("INVALID_ARGS","double-tap cannot be combined with jitter-px");if("ios"===e.platform&&n>1&&0===l&&0===d)return await rB(e,{command:"tapSeries",x:t,y:i,count:n,intervalMs:s,doubleTap:u,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u,timingMode:"runner-series"};return await iE(n,s,async e=>{let[r,n]=function(e,t){if(t<=0)return[0,0];let[r,i]=ib[e%ib.length];return[r*t,i*t]}(e,d),a=t+r,s=i+n;u?await o.doubleTap(a,s):l>0?await o.longPress(a,s,l):await o.tap(a,s)}),{x:t,y:i,count:n,intervalMs:s,holdMs:l,jitterPx:d,doubleTap:u}}case"swipe":{let t=Number(r[0]),i=Number(r[1]),n=Number(r[2]),s=Number(r[3]);if([t,i,n,s].some(Number.isNaN))throw new I("INVALID_ARGS","swipe requires x1 y1 x2 y2 [durationMs]");let l=iD(r[4]?Number(r[4]):250,"durationMs",16,1e4),d="ios"===e.platform?Math.min(60,Math.max(16,Math.round(l))):l,u=iD(a?.count??1,"count",1,200),c=iD(a?.pauseMs??0,"pause-ms",0,1e4),p=a?.pattern??"one-way";if("one-way"!==p&&"ping-pong"!==p)throw new I("INVALID_ARGS",`Invalid pattern: ${p}`);if("ios"===e.platform&&u>1)return await rB(e,{command:"dragSeries",x:t,y:i,x2:n,y2:s,durationMs:d,count:u,pauseMs:c,pattern:p,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"runner-series",count:u,pauseMs:c,pattern:p};return await iE(u,c,async e=>{"ping-pong"===p&&e%2==1?await o.swipe(n,s,t,i,d):await o.swipe(t,i,n,s,d)}),{x1:t,y1:i,x2:n,y2:s,durationMs:l,effectiveDurationMs:d,timingMode:"ios"===e.platform?"safe-normalized":"direct",count:u,pauseMs:c,pattern:p}}case"longpress":{let e=Number(r[0]),t=Number(r[1]),i=r[2]?Number(r[2]):void 0;if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","longpress requires x y [durationMs]");return await o.longPress(e,t,i),{x:e,y:t,durationMs:i}}case"focus":{let[e,t]=r.map(Number);if(Number.isNaN(e)||Number.isNaN(t))throw new I("INVALID_ARGS","focus requires x y");return await o.focus(e,t),{x:e,y:t}}case"type":{let e=r.join(" ");if(!e)throw new I("INVALID_ARGS","type requires text");return await o.type(e),{text:e}}case"fill":{let e=Number(r[0]),t=Number(r[1]),i=r.slice(2).join(" ");if(Number.isNaN(e)||Number.isNaN(t)||!i)throw new I("INVALID_ARGS","fill requires x y text");return await o.fill(e,t,i),{x:e,y:t,text:i}}case"scroll":{let e=r[0],t=r[1]?Number(r[1]):void 0;if(!e)throw new I("INVALID_ARGS","scroll requires direction");return await o.scroll(e,t),{direction:e,amount:t}}case"scrollintoview":{let e=r.join(" ").trim();if(!e)throw new I("INVALID_ARGS","scrollintoview requires text");let t=await o.scrollIntoView(e);if(t?.attempts)return{text:e,attempts:t.attempts};return{text:e}}case"pinch":{if("android"===e.platform)throw new I("UNSUPPORTED_OPERATION","Android pinch is not supported in current adb backend; requires instrumentation-based backend.");let t=Number(r[0]),i=r[1]?Number(r[1]):void 0,n=r[2]?Number(r[2]):void 0;if(Number.isNaN(t)||t<=0)throw new I("INVALID_ARGS","pinch requires scale > 0");return await rB(e,{command:"pinch",scale:t,x:i,y:n,appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{scale:t,x:i,y:n}}case"trigger-app-event":{let{eventName:t,payload:i}=function(e){let t=e[0]?.trim(),r=e[1]?.trim();if(!t)throw new I("INVALID_ARGS","trigger-app-event requires <event> [payloadJson]");if(!i_.test(t))throw new I("INVALID_ARGS",`Invalid trigger-app-event event name: ${t}`,{hint:"Use 1-64 chars: letters, numbers, underscore, dot, colon, or dash."});if(e.length>2)throw new I("INVALID_ARGS","trigger-app-event accepts at most two arguments: <event> [payloadJson]");let i=function(e,t){if(e)try{let r=JSON.parse(e);if(!r||"object"!=typeof r||Array.isArray(r))throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" must be a JSON object`);let i=JSON.stringify(r);if(Buffer.byteLength(i,"utf8")>8192)throw new I("INVALID_ARGS",`trigger-app-event payload for "${t}" exceeds 8192 bytes`);return r}catch(t){if(t instanceof I)throw t;throw new I("INVALID_ARGS",`Invalid trigger-app-event payload JSON: ${e}`)}}(r,t);return{eventName:t,payload:i}}(r),n=function(e,t,r){let i,n=(i=("ios"===e?process.env.AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE:process.env.AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE)??process.env.AGENT_DEVICE_APP_EVENT_URL_TEMPLATE,i?.trim()||void 0);if(!n)throw new I("UNSUPPORTED_OPERATION",`No app event URL template configured for ${e}.`,{hint:`Set AGENT_DEVICE_${e.toUpperCase()}_APP_EVENT_URL_TEMPLATE or AGENT_DEVICE_APP_EVENT_URL_TEMPLATE, for example "myapp://agent-device/event?name={event}&payload={payload}".`});let a=r?JSON.stringify(r):"",o=n.replaceAll("{event}",encodeURIComponent(t)).replaceAll("{payload}",encodeURIComponent(a)).replaceAll("{platform}",encodeURIComponent(e));if(o.length>4096)throw new I("INVALID_ARGS","trigger-app-event URL exceeds maximum supported length",{hint:"Reduce payload size or shorten AGENT_DEVICE_*_APP_EVENT_URL_TEMPLATE.",length:o.length,maxLength:4096});return o}(e.platform,t,i);return await o.open(n,{appBundleId:a?.appBundleId}),{event:t,eventUrl:n,transport:"deep-link"}}case"screenshot":{let e=r[0]??i??`./screenshot-${Date.now()}.png`;return await x.mkdir(n.dirname(e),{recursive:!0}),await o.screenshot(e,a?.appBundleId),{path:e}}case"back":if("ios"===e.platform)return await rB(e,{command:"back",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"back"};return await to(e),{action:"back"};case"home":if("ios"===e.platform)return await rB(e,{command:"home",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"home"};return await ts(e),{action:"home"};case"app-switcher":if("ios"===e.platform)return await rB(e,{command:"appSwitcher",appBundleId:a?.appBundleId},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{action:"app-switcher"};return await tl(e),{action:"app-switcher"};case"clipboard":{let t=(r[0]??"").toLowerCase();if("read"!==t&&"write"!==t)throw new I("INVALID_ARGS","clipboard requires a subcommand: read or write");if("read"===t){if(1!==r.length)throw new I("INVALID_ARGS","clipboard read does not accept additional arguments");return{action:t,text:"ios"===e.platform?await is(e):await t_(e)}}if(r.length<2)throw new I("INVALID_ARGS",'clipboard write requires text (use "" to clear clipboard)');let i=r.slice(1).join(" ");return"ios"===e.platform?await il(e,i):await tb(e,i),{action:t,textLength:Array.from(i).length}}case"keyboard":{if("android"!==e.platform)throw new I("UNSUPPORTED_OPERATION","keyboard is currently supported only on Android");let t=(r[0]??"status").toLowerCase();if("status"!==t&&"get"!==t&&"dismiss"!==t)throw new I("INVALID_ARGS","keyboard requires a subcommand: status, get, or dismiss");if(r.length>1)throw new I("INVALID_ARGS","keyboard accepts at most one subcommand argument");if("dismiss"===t){let t=await tS(e);return{platform:"android",action:"dismiss",attempts:t.attempts,wasVisible:t.wasVisible,dismissed:t.dismissed,visible:t.visible,inputType:t.inputType,type:t.type}}let i=await tN(e);return{platform:"android",action:"status",visible:i.visible,inputType:i.inputType,type:i.type}}case"settings":{let[t,i,n,o,s]=r,l="permission"===t?{permissionTarget:n,permissionMode:o}:void 0;if(M({level:"debug",phase:"settings_apply",data:{setting:t,state:i,target:n,mode:o,platform:e.platform}}),"ios"===e.platform)return await iu(e,t,i,s??a?.appBundleId,l),{setting:t,state:i};return await tL(e,t,i,s??a?.appBundleId,l),{setting:t,state:i}}case"push":{let t=r[0]?.trim(),i=r[1]?.trim();if(!t||!i)throw new I("INVALID_ARGS","push requires <bundle|package> <payload.json|inline-json>");let n=await iM(i);if("ios"===e.platform)return await id(e,t,n),{platform:"ios",bundleId:t};let a=await tF(e,t,n);return{platform:"android",package:t,action:a.action,extrasCount:a.extrasCount}}case"snapshot":{if("ios"===e.platform){let t=await k("snapshot_capture",async()=>await rB(e,{command:"snapshot",appBundleId:a?.appBundleId,interactiveOnly:a?.snapshotInteractiveOnly,compact:a?.snapshotCompact,depth:a?.snapshotDepth,scope:a?.snapshotScope,raw:a?.snapshotRaw},{verbose:a?.verbose,logPath:a?.logPath,traceLogPath:a?.traceLogPath,requestId:a?.requestId}),{backend:"xctest"}),r=t.nodes??[];if(0===r.length&&"simulator"===e.kind)throw new I("COMMAND_FAILED","XCTest snapshot returned 0 nodes on iOS simulator.");return{nodes:r,truncated:t.truncated??!1,backend:"xctest"}}let t=await k("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 I("INVALID_ARGS",`Unknown command: ${t}`)}},{command:t,platform:e.platform})}let iW={alert:{ios:{simulator:!0},android:{}},pinch:{ios:{simulator:!0},android:{}},"app-switcher":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},apps:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},back:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},boot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},click:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},clipboard:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},keyboard:{ios:{},android:{emulator:!0,device:!0,unknown:!0}},close:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},fill:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},diff:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},find:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},focus:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},get:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},is:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},home:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},logs:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},network:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},longpress:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},open:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},perf:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},install:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},reinstall:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},press:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},push:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},record:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},screenshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scroll:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},scrollintoview:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},swipe:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},settings:{ios:{simulator:!0},android:{emulator:!0,device:!0,unknown:!0}},snapshot:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},"trigger-app-event":{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},type:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}},wait:{ios:{simulator:!0,device:!0},android:{emulator:!0,device:!0,unknown:!0}}};function iH(e,t){let r=iW[e];if(!r)return!0;let i=r[t.platform];return!!i&&!0===i[t.kind??"unknown"]}function iJ(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 iz(e){let t=new Set,r=[];for(let i of e)t.has(i)||(t.add(i),r.push(i));return r}let iK=/^-?\d+(\.\d+)?$/,iX=new Map([["--count","count"],["--interval-ms","intervalMs"],["--hold-ms","holdMs"],["--jitter-px","jitterPx"]]),iY=new Map([["--count","count"],["--pause-ms","pauseMs"]]);function iZ(e){return"click"===e||"press"===e}function iQ(e){let t=e.trim();return t.startsWith("@")||iK.test(t)?t:JSON.stringify(t)}function i0(e,t){let r=t.flags??{};if(iZ(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 i1(e,t){let r=[],i={},n=iZ(e)?iX:"swipe"===e?iY:void 0;for(let a=0;a<t.length;a+=1){let o=t[a];if(iZ(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 i2{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=i2.expandHome(t.flags.saveScript))),e.actions.push({ts:Date.now(),command:t.command,positionals:t.positionals,flags:function(e){if(!e)return{};let{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}=e;return{platform:t,device:r,udid:i,serial:n,out:a,verbose:o,snapshotInteractiveOnly:s,snapshotCompact:l,snapshotDepth:d,snapshotScope:u,snapshotRaw:c,relaunch:p,saveScript:f,noRecord:m,count:h,intervalMs:w,holdMs:g,jitterPx:I,doubleTap:v,pauseMs:A,pattern:y}}(t.flags),result:t.result}),M({level:"debug",phase:"record_action",data:{command:t.command,session:e.name}}))}writeSessionLog(e){try{if(!e.recordSession)return;let t=this.resolveScriptPath(e),r=n.dirname(t);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i=function(e,t){let r=[],i=e.device.name.replace(/"/g,'\\"'),n=e.device.kind?` kind=${e.device.kind}`:"";for(let a of(r.push(`context platform=${e.device.platform} device="${i}"${n} theme=unknown`),t))a.flags?.noRecord||r.push(function(e){let t=[e.command];if(iZ(e.command)){let r=e.positionals?.[0];if(r){if(r.startsWith("@")){t.push(iQ(r));let i=e.result?.refLabel;return"string"==typeof i&&i.trim().length>0&&t.push(iQ(i)),i0(t,e),t.join(" ")}if(1===e.positionals.length)return t.push(iQ(r)),i0(t,e),t.join(" ")}}if("fill"===e.command){let r=e.positionals?.[0];if(r&&r.startsWith("@")){t.push(iQ(r));let i=e.result?.refLabel,n=e.positionals.slice(1).join(" ");return"string"==typeof i&&i.trim().length>0&&t.push(iQ(i)),n&&t.push(iQ(n)),t.join(" ")}}if("get"===e.command){let r=e.positionals?.[0],i=e.positionals?.[1];if(r&&i){if(t.push(iQ(r)),t.push(iQ(i)),i.startsWith("@")){let r=e.result?.refLabel;"string"==typeof r&&r.trim().length>0&&t.push(iQ(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",iQ(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iQ(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iQ(r));return i0(t,e),t.join(" ")}(a));return`${r.join("\n")}
|
|
28
|
+
`}(e,this.buildOptimizedActions(e));R.writeFileSync(t,i)}catch{}}defaultTracePath(e){let t=i2.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,i2.safeSessionName(e),"app.log")}resolveAppLogPidPath(e){return n.join(this.sessionsDir,i2.safeSessionName(e),"app-log.pid")}static safeSessionName(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_")}static expandHome(e,t){return e.startsWith("~/")?n.join(F.homedir(),e.slice(2)):t&&!n.isAbsolute(e)?n.resolve(t,e):n.resolve(e)}resolveScriptPath(e){if(e.saveScriptPath)return i2.expandHome(e.saveScriptPath);R.existsSync(this.sessionsDir)||R.mkdirSync(this.sessionsDir,{recursive:!0});let t=i2.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&&(iZ(r.command)||"fill"===r.command||"get"===r.command)){let e=i.join(" || ");if(iZ(r.command)){t.push({...r,positionals:[e]});continue}if("fill"===r.command){let i=iJ(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(iZ(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 i3(e,t,r,i,n){return{requestId:n??O().requestId,appBundleId:r,activity:t?.activity,verbose:t?.verbose,logPath:e,traceLogPath:i,snapshotInteractiveOnly:t?.snapshotInteractiveOnly,snapshotCompact:t?.snapshotCompact,snapshotDepth:t?.snapshotDepth,snapshotScope:t?.snapshotScope,snapshotRaw:t?.snapshotRaw,count:t?.count,intervalMs:t?.intervalMs,holdMs:t?.holdMs,jitterPx:t?.jitterPx,doubleTap:t?.doubleTap,pauseMs:t?.pauseMs,pattern:t?.pattern}}let i4=tV(process.env.AGENT_DEVICE_IOS_DEVICE_READY_TIMEOUT_MS,15e3,1e3);async function i8(e){if("ios"===e.platform){if("simulator"===e.kind){let{ensureBootedSimulator:t}=await Promise.resolve().then(()=>({ensureBootedSimulator:t0}));await t(e);return}if("device"===e.kind)return void await i5(e.id)}if("android"===e.platform){let{waitForAndroidBoot:t}=await Promise.resolve().then(()=>({waitForAndroidBoot:eL}));await t(e.id)}}async function i5(e){let t=n.join(F.tmpdir(),`agent-device-ready-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`),r=Math.max(1,Math.ceil(i4/1e3));try{let i=await p("xcrun",["devicectl","device","info","details","--device",e,"--json-output",t,"--timeout",String(r)],{allowFailure:!0,timeoutMs:i4+3e3}),n=String(i.stdout??""),a=String(i.stderr??""),o=await i6(t);if(0===i.exitCode){if(!o.parsed)throw new I("COMMAND_FAILED","iOS device readiness probe failed",{kind:"probe_inconclusive",deviceId:e,stdout:n,stderr:a,hint:"CoreDevice returned success but readiness JSON output was missing or invalid. Retry; if it persists restart Xcode and the iOS device."});let t=o?.tunnelState?.toLowerCase();if("connecting"===t)throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,tunnelState:t,hint:"Device tunnel is still connecting. Keep the device unlocked and connected by cable until it is fully available in Xcode Devices, then retry."});return}throw new I("COMMAND_FAILED","iOS device is not ready for automation",{kind:"not_ready",deviceId:e,stdout:n,stderr:a,exitCode:i.exitCode,tunnelState:o?.tunnelState,hint:i9(n,a)})}catch(t){if(t instanceof I&&"COMMAND_FAILED"===t.code){if("not_ready"===("string"==typeof t.details?.kind?t.details.kind:""))throw t;let r=t.details??{},i=String(r.stdout??""),n=String(r.stderr??""),a=Number(r.timeoutMs??i4),o=`CoreDevice did not respond within ${a}ms. Keep the device unlocked and trusted, then retry; if it persists restart Xcode and the iOS device.`;throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,cause:t.message,timeoutMs:a,stdout:i,stderr:n,hint:i||n?i9(i,n):o},t)}throw new I("COMMAND_FAILED","iOS device readiness probe failed",{deviceId:e,hint:"Reconnect the device, keep it unlocked, and retry."},t instanceof Error?t:void 0)}finally{await x.rm(t,{force:!0}).catch(()=>{})}}async function i6(e){try{let t=await x.readFile(e,"utf8"),r=JSON.parse(t),i=function(e){let t=e?.result;if(!t||"object"!=typeof t)return{};let r=t.connectionProperties?.tunnelState,i=t.device?.connectionProperties?.tunnelState,n="string"==typeof r?r:"string"==typeof i?i:void 0;return n?{tunnelState:n}:{}}(r);return{parsed:!0,tunnelState:i.tunnelState}}catch{return{parsed:!1}}}function i9(e,t){let r=tK(e,t);return r||(`${e}
|
|
29
|
+
${t}`.toLowerCase().includes("timed out waiting for all destinations")?"Xcode destination did not become available in time. Keep device unlocked and retry.":tz)}function i7(e){return e.map((e,t)=>({...e,ref:`e${t+1}`}))}function ne(e){let t=e.trim();return t.startsWith("@")?t.slice(1)||null:t.startsWith("e")?t:null}function nt(e,t){return e.find(e=>e.ref===t)??null}function nr(e){return{x:Math.round(e.x+e.width/2),y:Math.round(e.y+e.height/2)}}function ni(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 nn(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&&na(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||!na(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&&na(r)?r:void 0)}function na(e){let t=e.trim();return!(!t||/^(true|false)$/i.test(t)||/^\d+$/.test(t))}function no(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=ns(i.type??""),a=[i.label,i.value,i.identifier].map(e=>"string"==typeof e?e.trim():"").find(e=>e&&e.length>0),o=!!a&&na(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 ns(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 nl(e,t){let r=ns(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 nd(e){return[e.label,e.value,e.identifier].map(e=>"string"==typeof e?e.trim():"").filter(e=>e.length>0)[0]??""}let nu=new Set(["id","role","text","label","value"]),nc=new Set(["visible","hidden","editable","selected","enabled","hittable"]),np=new Set([...nu,...nc]);function nf(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector expression cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!nL(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&"|"===a&&"|"===e[n+1]){let i=r.trim();if(!i)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);t.push(i),r="",n+=1;continue}r+=a}let n=r.trim();if(!n)throw new I("INVALID_ARGS",`Invalid selector fallback expression: ${e}`);return t.push(n),t}(t);if(0===r.length)throw new I("INVALID_ARGS","Selector expression cannot be empty");return{raw:t,selectors:r.map(e=>(function(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Selector segment cannot be empty");let r=function(e){let t=[],r="",i=null;for(let n=0;n<e.length;n+=1){let a=e[n];if(('"'===a||"'"===a)&&!nL(e,n)){i?i===a&&(i=null):i=a,r+=a;continue}if(!i&&/\s/.test(a)){r.trim().length>0&&t.push(r.trim()),r="";continue}r+=a}if(i)throw new I("INVALID_ARGS",`Unclosed quote in selector: ${e}`);return r.trim().length>0&&t.push(r.trim()),t}(t);if(0===r.length)throw new I("INVALID_ARGS",`Invalid selector segment: ${e}`);return{raw:t,terms:r.map(nS)}})(e))}}function nm(e){try{return nf(e)}catch{return null}}function nh(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||!n_(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=nM(e),a=nM(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 nw(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)&&n_(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 ng(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 nI(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 np.has(e)}return np.has(t.toLowerCase())}(e[i]);){i+=1;let t=e.slice(0,i).join(" ").trim();t&&nm(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 nv(e){let t=e[0]??"",r=nI(e.slice(1),{preferTrailingValue:"text"===t});return{predicate:t,split:r}}function nA(e){return!0===e.hittable||!!e.rect&&e.rect.width>0&&e.rect.height>0}function ny(e,t){return nl(e.type??"",t)&&!1!==e.enabled}function nN(e,t,r={}){let i=[],n=ns(e.type??""),a=nk(e.identifier),o=nk(e.label),s=nk(e.value),l=nk(nd(e)),d="fill"===r.action;a&&i.push(`id=${nO(a)}`),n&&o&&i.push(d?`role=${nO(n)} label=${nO(o)} editable=true`:`role=${nO(n)} label=${nO(o)}`),o&&i.push(d?`label=${nO(o)} editable=true`:`label=${nO(o)}`),s&&i.push(d?`value=${nO(s)} editable=true`:`value=${nO(s)}`),l&&l!==o&&l!==s&&i.push(d?`text=${nO(l)} editable=true`:`text=${nO(l)}`),n&&d&&!i.some(e=>e.includes("editable=true"))&&i.push(`role=${nO(n)} editable=true`);let u=iz(i);return 0===u.length&&n&&u.push(d?`role=${nO(n)} editable=true`:`role=${nO(n)}`),0===u.length&&nA(e)&&u.push("visible=true"),u}function nS(e){let t=e.trim();if(!t)throw new I("INVALID_ARGS","Empty selector term");let r=t.indexOf("=");if(-1===r){let r=t.toLowerCase();if(!nc.has(r))throw new I("INVALID_ARGS",`Invalid selector term "${e}", expected key=value`);return{key:r,value:!0}}let i=t.slice(0,r).trim().toLowerCase(),n=t.slice(r+1).trim();if(!np.has(i))throw new I("INVALID_ARGS",`Unknown selector key: ${i}`);if(!n)throw new I("INVALID_ARGS",`Missing selector value for key: ${i}`);if(nc.has(i)){let e,t="true"===(e=nb(n).toLowerCase())||"false"!==e&&null;if(null===t)throw new I("INVALID_ARGS",`Invalid boolean value for ${i}: ${n}`);return{key:i,value:t}}return{key:i,value:nb(n)}}function n_(e,t,r){return t.terms.every(t=>(function(e,t,r){switch(t.key){case"id":return nD(e.identifier,String(t.value));case"role":var i,n;return i=e.type,n=String(t.value),function(e){return ns(e)}(i??"")===function(e){return ns(e)}(n);case"label":return nD(e.label,String(t.value));case"value":return nD(e.value,String(t.value));case"text":{let r=nE(String(t.value));return nE(nd(e))===r}case"visible":return nA(e)===!!t.value;case"hidden":return!nA(e)==!!t.value;case"editable":return ny(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 nb(e){let t=e.trim();return t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1).replace(/\\(["'])/g,"$1"):t}function nD(e,t){return nE(e??"")===nE(t)}function nE(e){return e.trim().toLowerCase().replace(/\s+/g," ")}function nO(e){return JSON.stringify(e)}function nk(e){if(!e)return null;let t=e.trim();return t||null}function nM(e){return e.rect?e.rect.width*e.rect.height:1/0}function nL(e,t){let r=0;for(let i=t-1;i>=0&&"\\"===e[i];i-=1)r+=1;return r%2==1}function nx(e,t){if(!e)return;let r=n.dirname(e);R.existsSync(r)||R.mkdirSync(r,{recursive:!0});let i={pid:t,startTime:T(t)??void 0,command:a(t)??void 0};R.writeFileSync(e,`${JSON.stringify(i)}
|
|
30
|
+
`)}function nC(e){if(e&&R.existsSync(e))try{R.unlinkSync(e)}catch{}}async function nT(e,t=2e3){await Promise.race([e.then(()=>void 0).catch(()=>void 0),new Promise(e=>setTimeout(e,t))])}async function nR(e){await new Promise(t=>setTimeout(t,e))}function nP(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}
|
|
31
|
+
`)},flush:()=>{i&&(n(i),i="")}}}function n$(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 nF(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 nV(e,t,r,i,n){let a,o,s="active",l=!1,d=(async()=>{try{for(;!l;){let d=await nF(e,t);if(!d){await nR(1e3);continue}let u=h("adb",["-s",e,"logcat","-v","time","--pid",d],{stdio:["ignore","pipe","pipe"]});a=u;let c=nP(r,{redactionPatterns:i});o=n$(u,r,{endStreamOnClose:!1,writer:c}),"number"==typeof u.pid&&nx(n,u.pid);let p=await o;if(nC(n),a=void 0,o=void 0,l)break;0!==p.exitCode&&(s="failed"),await nR(500)}return{stdout:"",stderr:"",exitCode:0}}finally{r.end(),nC(n)}})();return{backend:"android",getState:()=>s,startedAt:Date.now(),wait:d,stop:async()=>{l=!0,a&&!a.killed&&a.kill("SIGINT"),o&&await nT(o),a&&!a.killed&&a.kill("SIGKILL"),await nT(d),nC(n)}}}async function nU(e,t,r,i){let n="active",a=h("log",["stream","--style","compact","--predicate",`subsystem == "${e}" OR processImagePath ENDSWITH[c] "/${e}" OR senderImagePath ENDSWITH[c] "/${e}" OR eventMessage CONTAINS[c] "${e}"`],{stdio:["ignore","pipe","pipe"]}),o=nP(t,{redactionPatterns:r});"number"==typeof a.pid&&nx(i,a.pid);let s=n$(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nC(i),e));return{backend:"ios-simulator",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nT(s),a.killed||a.kill("SIGKILL"),await nT(s),nC(i)}}}async function nG(e,t,r,i){let n="active",a=h("xcrun",["devicectl","device","log","stream","--device",e],{stdio:["ignore","pipe","pipe"]}),o=nP(t,{redactionPatterns:r});"number"==typeof a.pid&&nx(i,a.pid);let s=n$(a,t,{endStreamOnClose:!0,writer:o}).then(e=>(0!==e.exitCode&&(n="failed"),nC(i),e));return{backend:"ios-device",getState:()=>n,startedAt:Date.now(),wait:s,stop:async()=>{a.killed||a.kill("SIGINT"),await nT(s),a.killed||a.kill("SIGKILL"),await nT(s),nC(i)}}}function nB(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 nj(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:nB("AGENT_DEVICE_APP_LOG_MAX_BYTES",5242880),maxRotatedFiles:nB("AGENT_DEVICE_APP_LOG_MAX_FILES",1)})}async function nq(e,t,r,i){nj(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 nG(e.id,n,a,i):await nU(t,n,a,i);if("android"===e.platform){if(!/^[a-zA-Z0-9._:-]+$/.test(t))throw new I("INVALID_ARGS",`Invalid Android package name for logs: ${t}`);return await nV(e.id,t,n,a,i)}throw n.end(),new I("UNSUPPORTED_PLATFORM",`unsupported platform: ${e.platform}`)}async function nW(e){await e.stop(),await nT(e.wait)}async function nH(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 nJ(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 nz=RegExp("\\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b","i"),nK=/https?:\/\/[^\s"'<>\])]+/i,nX=[/\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 nY(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 nZ(e,t,r){if(t){for(let e of r)if(void 0!==t[e])return nQ(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 nQ(e){if("string"==typeof e)return e;try{return JSON.stringify(e)}catch{return String(e)}}function n0(e,t){return e.length<=t?e:`${e.slice(0,t)}...<truncated>`}function n1(e,t,r,i){return void 0!==e&&Number.isInteger(e)?Math.max(r,Math.min(i,e)):t}function n2(e){if(0===e.length)return{selectorExpression:null,selectorTimeout:null};let t=e[e.length-1],r=/^\d+$/.test(t??""),i=nI(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 n3(e){return!!e&&!Number.isNaN(Number(e))}async function n4(e){let t,r,i,{deviceName:n,runtime:a,simulatorSetPath:o,reuseExisting:s,boot:l,ensureReady:d}=e;if("darwin"!==process.platform)throw new I("UNSUPPORTED_PLATFORM","ensure-simulator is only available on macOS");let u={simulatorSetPath:o??void 0};if(s){let e=await n8({deviceName:n,runtime:a,simctlOpts:u});e?(t=e.udid,r=e.runtime,i=!1):(t=(await n5({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await n6(t,u),i=!0)}else t=(await n5({deviceName:n,runtime:a,simctlOpts:u})).udid,r=await n6(t,u),i=!0;let c=!1;if(l){let e={platform:"ios",id:t,name:n,kind:"simulator",target:"mobile",...o?{simulatorSetPath:o}:{}};await d(e),c=!0}return{udid:t,device:n,runtime:r,created:i,booted:c}}async function n8(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=await p("xcrun",tX(["list","devices","-j"],i),{allowFailure:!0,timeoutMs:tG});if(0!==n.exitCode)return null;try{let e=JSON.parse(String(n.stdout??""));for(let[i,n]of Object.entries(e.devices??{}))if(!r||n9(i).includes(n9(r))){for(let e of n)if(e.isAvailable&&e.name.toLowerCase()===t.toLowerCase())return{udid:e.udid,runtime:i}}return null}catch{return null}}async function n5(e){let{deviceName:t,runtime:r,simctlOpts:i}=e,n=r?["create",t,t,r]:["create",t,t],a=await p("xcrun",tX(n,i),{allowFailure:!0});if(0!==a.exitCode)throw new I("COMMAND_FAILED","Failed to create iOS simulator",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??""),exitCode:a.exitCode,hint:"Ensure the device type and runtime identifiers are valid. Run `xcrun simctl list devicetypes` and `xcrun simctl list runtimes` to see available options."});let o=String(a.stdout??"").trim();if(!o)throw new I("COMMAND_FAILED","simctl create returned no UDID",{deviceName:t,runtime:r,stdout:String(a.stdout??""),stderr:String(a.stderr??"")});return{udid:o}}async function n6(e,t){let r=await p("xcrun",tX(["list","devices","-j"],t),{allowFailure:!0,timeoutMs:tG});if(0!==r.exitCode)return"";try{let t=JSON.parse(String(r.stdout??""));for(let[r,i]of Object.entries(t.devices??{}))if(i.some(t=>t.udid===e))return r;return""}catch{return""}}function n9(e){return e.toLowerCase().replace(/[._-]/g,"")}let n7='iOS appstate requires an active session on the target device. Run open first (for example: open --session sim --platform ios --device "<name>" <app>).',ae=["platform","target","device","udid","serial","verbose","out"],at=["platform","target","device","udid","serial","verbose","out"],ar=["path","start","stop","doctor","mark","clear"],ai=`logs requires ${ar.slice(0,-1).join(", ")}, or ${ar.at(-1)}`,an="Not implemented for this platform in this release.",aa="open-command-roundtrip",ao=tV(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_CLOSE_SETTLE_MS,300,0),as=tV(process.env.AGENT_DEVICE_IOS_SIMULATOR_POST_OPEN_SETTLE_MS,300,0);function al(e){let{sessionName:t,appName:r,appBundleId:i,startup:n,device:a}=e,o={session:t};return r&&(o.appName=r),i&&(o.appBundleId=i),n&&(o.startup=n),a?.platform==="ios"&&(o.device_udid=a.id,o.ios_simulator_device_set=a.simulatorSetPath??null),o}function ad(e,t,r){return{durationMs:Math.max(0,Date.now()-e),measuredAt:new Date().toISOString(),method:aa,appTarget:t,appBundleId:r}}let au=["dump","log"],ac=`network requires ${au.join(" or ")}`,ap=["summary","headers","body","all"],af=`network include mode must be one of: ${ap.join(", ")}`;function am(e,t,r){return t||ah(r)?null:{ok:!1,error:{code:"INVALID_ARGS",message:`${e} requires an active session or an explicit device selector (e.g. --platform ios).`}}}function ah(e){return!!(e?.platform||e?.target||e?.device||e?.udid||e?.serial)}function aw(e){return"ios"===e.platform&&"simulator"===e.kind}async function ag(e,t){aw(e)&&!(t<=0)&&await new Promise(e=>setTimeout(e,t))}async function aI(e){let{device:t,closeTarget:r,stopIosRunner:i,dispatch:n,outFlag:a,context:o,settleSimulator:s}=e;"ios"===t.platform&&await i(t.id),await n(t,"close",[r],a,o),await s(t,ao)}async function av(e){let t=ah(e.flags)||!e.session?await e.resolveTargetDeviceFn(e.flags??{}):e.session.device;return!1!==e.ensureReady&&await e.ensureReadyFn(t),t}function aA(e){let t=e.flags?.device?.trim();return t||(e.resolvedDevice?.platform==="android"&&"emulator"===e.resolvedDevice.kind?e.resolvedDevice.name:e.sessionDevice?.platform==="android"&&"emulator"===e.sessionDevice.kind?e.sessionDevice.name:void 0)}let ay=async({avdName:e,serial:t,headless:r})=>{let{ensureAndroidEmulatorBooted:i}=await Promise.resolve().then(()=>({ensureAndroidEmulatorBooted:eM}));return await i({avdName:e,serial:t,headless:r})};async function aN(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s,command:l,positionals:d,recordPositionals:u,deriveNextSession:c}=e,p=n.get(r),f=t.flags??{},m=am(l,p,f);if(m)return m;let h=await av({session:p,flags:f,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iH(l,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${l} is not supported on this device`}};let w=await s(h,l,d,t.flags?.out,{...i3(i,t.flags,p?.appBundleId,p?.trace?.outPath)});if(p){let e=c?await c(p,w,h):p;n.recordAction(e,{command:l,positionals:u??d,flags:t.flags??{},result:w??{}}),e!==p&&n.set(r,e)}return{ok:!0,data:w??{}}}let aS={ios:async(e,t,r)=>{let{reinstallIosApp:i}=await Promise.resolve().then(()=>({reinstallIosApp:io}));return await i(e,t,r)},android:async(e,t,r)=>{let{reinstallAndroidApp:i}=await Promise.resolve().then(()=>({reinstallAndroidApp:e0}));return await i(e,t,r)}},a_={ios:async(e,t,r)=>{let{installIosApp:i}=await Promise.resolve().then(()=>({installIosApp:ia}));await i(e,r,{appIdentifierHint:t});let{bundleId:n}=await ak(e,t);return n?{bundleId:n}:{}},android:async(e,t,r)=>{let{installAndroidApp:i}=await Promise.resolve().then(()=>({installAndroidApp:eQ}));await i(e,r);let{package:n}=await ak(e,t);return n?{package:n}:{}}};async function ab(e){let t,{req:r,command:i,sessionName:n,sessionStore:a,ensureReady:o,resolveDevice:s,deployOps:l}=e,d=a.get(n),u=r.flags??{},c=am(i,d,u);if(c)return c;let p=r.positionals?.[0]?.trim(),f=r.positionals?.[1]?.trim();if(!p||!f)return{ok:!1,error:{code:"INVALID_ARGS",message:`${i} requires: ${i} <app> <path-to-app-binary>`}};let m=i2.expandHome(f);if(!R.existsSync(m))return{ok:!1,error:{code:"INVALID_ARGS",message:`App binary not found: ${m}`}};let h=await av({session:d,flags:u,ensureReadyFn:o,resolveTargetDeviceFn:s,ensureReady:!1});if(!iH(i,h))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${i} is not supported on this device`}};if("ios"===h.platform){let e=(await l.ios(h,p,m)).bundleId;t=e?{app:p,appPath:m,platform:"ios",appId:e,bundleId:e}:{app:p,appPath:m,platform:"ios"}}else{let e=(await l.android(h,p,m)).package;t=e?{app:p,appPath:m,platform:"android",appId:e,package:e}:{app:p,appPath:m,platform:"android"}}return d&&a.recordAction(d,{command:i,positionals:r.positionals??[],flags:r.flags??{},result:t}),{ok:!0,data:t}}async function aD(e,t,r){if("ios"===e.platform&&t)return J(t)?"device"===e.kind?z(r,t):void 0:await aE(e,t)}async function aE(e,t){try{let{resolveIosApp:r}=await Promise.resolve().then(()=>({resolveIosApp:r7}));return await r(e,t)}catch{return}}async function aO(e,t){if(!("android"!==e.platform||!t||J(t)))try{let{resolveAndroidApp:r}=await Promise.resolve().then(()=>({resolveAndroidApp:eP})),i=await r(e,t);return"package"===i.type?i.value:void 0}catch{return}}async function ak(e,t){return"ios"===e.platform?{bundleId:await aE(e,t)}:{package:await aO(e,t)}}async function aM(e,t,r,i){return await aD(e,t,r)??await i(e,t)??("android"===e.platform&&t&&J(t)?r:void 0)}async function aL(e){let{req:t,sessionName:r,sessionStore:i,ensureReady:n,resolveDevice:a}=e,o=i.get(r),s=t.flags??{},l=rw(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=am("appstate",o,s);if(d)return d;let u=o?.device.platform==="ios"&&function(e,t){if(!t)return!1;if(!ah(e))return!0;let r=rw(e?.platform);return!(r&&r!==t.device.platform||e?.target&&e.target!==(t.device.target??"mobile")||e?.udid&&e.udid!==t.device.id||e?.serial&&e.serial!==t.device.id)&&(!e?.device||e.device.trim().toLowerCase()===t.device.name.trim().toLowerCase())}(s,o);if("ios"===l&&!u)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:n7}};if(u){let e=o.appName??o.appBundleId;return o.appName||o.appBundleId?{ok:!0,data:{platform:"ios",appName:e??"unknown",appBundleId:o.appBundleId,source:"session",device_udid:o.device.id,ios_simulator_device_set:o.device.simulatorSetPath??null}}:{ok:!1,error:{code:"COMMAND_FAILED",message:"No foreground app is tracked for this iOS session. Open an app in the session, then retry appstate."}}}let c=await av({session:o,flags:s,ensureReadyFn:n,resolveTargetDeviceFn:a,ensureReady:!0});if("ios"===c.platform)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:n7}};let{getAndroidAppState:p}=await Promise.resolve().then(()=>({getAndroidAppState:eG})),f=await p(c);return{ok:!0,data:{platform:"android",package:f.package,activity:f.activity}}}async function ax(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:a,resolveDevice:o,dispatch:s}=e,l=n.get(r),d=t.flags??{},u=am("clipboard",l,d);if(u)return u;let c=(t.positionals?.[0]??"").toLowerCase();if("read"!==c&&"write"!==c)return{ok:!1,error:{code:"INVALID_ARGS",message:"clipboard requires a subcommand: read or write"}};let p=await av({session:l,flags:d,ensureReadyFn:a,resolveTargetDeviceFn:o,ensureReady:!0});if(!iH("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,{...i3(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 aC(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a,dispatch:o,ensureReady:s,resolveTargetDevice:l,installOps:d=a_,reinstallOps:u=aS,stopIosRunner:c,appLogOps:p={start:nq,stop:nW},ensureAndroidEmulatorBoot:f=ay,resolveAndroidPackageForOpen:m=aO,settleSimulator:h,shutdownSimulator:g}=e,v=o??iq,A=s??i8,y=l??ij,N=c??rR,S=h??ag,b=t.command;if("session_list"===b)return{ok:!0,data:{sessions:n.toArray().map(e=>({name:e.name,platform:e.device.platform,target:e.device.target??"mobile",device:e.device.name,id:e.device.id,createdAt:e.createdAt,..."ios"===e.device.platform&&{device_udid:e.device.id,ios_simulator_device_set:e.device.simulatorSetPath??null}}))}};if("ensure-simulator"===b)try{let e=t.flags??{},r=e.device,i=e.runtime,n=el(e.iosSimulatorDeviceSet);if(!r)return{ok:!1,error:{code:"INVALID_ARGS",message:"ensure-simulator requires --device <name>"}};let a=!0===e.boot,o=!1!==e.reuseExisting,s=await n4({deviceName:r,runtime:i,simulatorSetPath:n,reuseExisting:o,boot:a,ensureReady:A});return{ok:!0,data:{udid:s.udid,device:s.device,runtime:s.runtime,ios_simulator_device_set:n??null,created:s.created,booted:s.booted}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("devices"===b)try{let e=[],r=el(t.flags?.iosSimulatorDeviceSet),i=eu(t.flags?.androidDeviceAllowlist),n=rw(t.flags?.platform);if("android"===n){let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:e_}));e.push(...await t({serialAllowlist:i}))}else if("ios"===n){let{listIosDevices:t}=await Promise.resolve().then(()=>({listIosDevices:iB}));e.push(...await t({simulatorSetPath:r}))}else{let{listAndroidDevices:t}=await Promise.resolve().then(()=>({listAndroidDevices:e_})),{listIosDevices:n}=await Promise.resolve().then(()=>({listIosDevices:iB}));try{e.push(...await t({serialAllowlist:i}))}catch{}try{e.push(...await n({simulatorSetPath:r}))}catch{}}let a=(t.flags?.target?e.filter(e=>(e.target??"mobile")===t.flags?.target):e).map(({simulatorSetPath:e,...t})=>t);return{ok:!0,data:{devices:a}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}if("apps"===b){let e=n.get(r),i=t.flags??{},a=am(b,e,i);if(a)return a;let o=await av({session:e,flags:i,ensureReadyFn:A,resolveTargetDeviceFn:y,ensureReady:!0});if(!iH("apps",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"apps is not supported on this device"}};let s=t.flags?.appsFilter??"all";if("ios"===o.platform){let{listIosApps:e}=await Promise.resolve().then(()=>({listIosApps:ic}));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:e$}));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"===b){let e,i=n.get(r),a=t.flags??{},o=am(b,i,a);if(o)return o;let s="android"===(rw(a.platform)??i?.device.platform),l=!0===a.headless;if(l&&!s)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};let d=aA({flags:a,sessionDevice:i?.device}),u=s&&!!d,c=!1;try{e=await av({session:i,flags:a,ensureReadyFn:A,resolveTargetDeviceFn:y,ensureReady:!1})}catch(r){let t=w(r);if(s&&l&&!d&&"DEVICE_NOT_FOUND"===t.code)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};if(!u||"DEVICE_NOT_FOUND"!==t.code||!d)throw r;e=await f({avdName:d,serial:a.serial,headless:l}),c=!0}if(a.target&&(e.target??"mobile")!==a.target)return{ok:!1,error:{code:"DEVICE_NOT_FOUND",message:`No ${e.platform} device found matching --target ${a.target}.`}};if(s&&l){if("android"!==e.platform||"emulator"!==e.kind)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless is supported only for Android emulators."}};if(!c){let t=aA({flags:a,sessionDevice:i?.device,resolvedDevice:e});if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:"boot --headless requires --device <avd-name> (or an Android emulator session target)."}};e=await f({avdName:t,serial:a.serial,headless:!0})}await A(e)}else("android"!==e.platform||!0!==e.booted)&&await A(e);return iH("boot",e)?{ok:!0,data:{platform:e.platform,target:e.target??"mobile",device:e.name,id:e.id,kind:e.kind,booted:!0}}:{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"boot is not supported on this device"}}}if("appstate"===b)return await aL({req:t,sessionName:r,sessionStore:n,ensureReady:A,resolveDevice:y});if("clipboard"===b)return await ax({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v});if("keyboard"===b)return await aN({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"keyboard",positionals:t.positionals??[]});if("perf"===b){let e,t,i,a=n.get(r);return a?{ok:!0,data:(i=(t=(e=function(e){let t=[];for(let r of e){if("open"!==r.command)continue;let e=r.result?.startup;e&&"object"==typeof e&&"number"==typeof e.durationMs&&Number.isFinite(e.durationMs)&&"string"==typeof e.measuredAt&&0!==e.measuredAt.trim().length&&e.method===aa&&t.push({durationMs:Math.max(0,Math.round(e.durationMs)),measuredAt:e.measuredAt,method:aa,appTarget:"string"==typeof e.appTarget&&e.appTarget.length>0?e.appTarget:void 0,appBundleId:"string"==typeof e.appBundleId&&e.appBundleId.length>0?e.appBundleId:void 0})}return t.slice(-20)}(a.actions)).at(-1))?{available:!0,lastDurationMs:t.durationMs,lastMeasuredAt:t.measuredAt,method:aa,sampleCount:e.length,samples:e}:{available:!1,reason:"No startup sample captured yet. Run open <app|url> in this session first.",method:aa},{session:a.name,platform:a.device.platform,device:a.device.name,deviceId:a.device.id,metrics:{startup:i,fps:{available:!1,reason:an},memory:{available:!1,reason:an},cpu:{available:!1,reason:an}},sampling:{startup:{method:aa,description:"Elapsed wall-clock time around dispatching the open command for the active session app target.",unit:"ms"}}})}:{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"perf requires an active session. Run open first."}}}if("install"===b||"reinstall"===b)return await ab({req:t,command:b,sessionName:r,sessionStore:n,ensureReady:A,resolveDevice:y,deployOps:"install"===b?d:u});if("push"===b){let e,a=t.positionals?.[0]?.trim(),o=t.positionals?.[1]?.trim();if(!a||!o)return{ok:!1,error:{code:"INVALID_ARGS",message:"push requires <bundle|package> <payload.json|inline-json>"}};let s="file"===(e=ik(o,{subject:"Push payload",cwd:t.meta?.cwd,expandPath:(e,t)=>i2.expandHome(e,t)})).kind?e.path:e.text;return await aN({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"push",positionals:[a,s],recordPositionals:[a,o]})}if("trigger-app-event"===b)return await aN({req:t,sessionName:r,logPath:i,sessionStore:n,ensureReady:A,resolveDevice:y,dispatch:v,command:"trigger-app-event",positionals:t.positionals??[],deriveNextSession:async(e,t)=>{let r="string"==typeof t?.eventUrl?t.eventUrl:void 0,i=r?await aM(e.device,r,e.appBundleId,m)??e.appBundleId:e.appBundleId;return{...e,appBundleId:i}}});if("open"===b){let e=t.flags?.relaunch===!0;if(n.has(r)){let a=n.get(r),o=t.positionals?.[0],s=o??(e?a?.appName:void 0);if(!a||!s)return e?{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app name or an active session app."}}:{ok:!1,error:{code:"INVALID_ARGS",message:"Session already active. Close it first or pass a new --session name."}};if(e&&J(s))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};await A(a.device);let l=await aM(a.device,s,a.appBundleId,m),d=o?t.positionals??[]:[s];if(e){let e=l??s;await aI({device:a.device,closeTarget:e,stopIosRunner:N,dispatch:v,outFlag:t.flags?.out,context:{...i3(i,t.flags,l??a.appBundleId,a.trace?.outPath)},settleSimulator:S})}let u=Date.now();await v(a.device,"open",d,t.flags?.out,{...i3(i,t.flags,l)});let c=ad(u,s,l);await S(a.device,as);let p={...a,appBundleId:l,appName:s,recordSession:a.recordSession||!!t.flags?.saveScript,snapshot:void 0},f=al({sessionName:r,appName:s,appBundleId:l,startup:c,device:a.device});return n.recordAction(p,{command:b,positionals:d,flags:t.flags??{},result:f}),n.set(r,p),{ok:!0,data:f}}let a=t.positionals?.[0];if(e&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch requires an app argument."}};if(e&&a&&J(a))return{ok:!1,error:{code:"INVALID_ARGS",message:"open --relaunch does not support URL targets."}};let o=await y(t.flags??{}),s=n.toArray().find(e=>e.device.id===o.id);if(s)return{ok:!1,error:{code:"DEVICE_IN_USE",message:`Device is already in use by session "${s.name}".`,details:{session:s.name,deviceId:o.id,deviceName:o.name}}};await A(o);let l=await aM(o,a,void 0,m);if(e&&a){let e=l??a;await aI({device:o,closeTarget:e,stopIosRunner:N,dispatch:v,outFlag:t.flags?.out,context:{...i3(i,t.flags,l)},settleSimulator:S})}let d=Date.now();await v(o,"open",t.positionals??[],t.flags?.out,{...i3(i,t.flags,l)});let u=a?ad(d,a,l):void 0;await S(o,as);let c={name:r,device:o,createdAt:Date.now(),appBundleId:l,appName:a,recordSession:!!t.flags?.saveScript,actions:[]},p=al({sessionName:r,appName:a,appBundleId:l,startup:u,device:o});return n.recordAction(c,{command:b,positionals:t.positionals??[],flags:t.flags??{},result:p}),n.set(r,c),{ok:!0,data:p}}if("replay"===b){let e=t.positionals?.[0];if(!e)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay requires a path"}};try{let o=i2.expandHome(e,t.meta?.cwd),s=R.readFileSync(o,"utf8"),l=s.trimStart()[0];if("{"===l||"["===l)return{ok:!1,error:{code:"INVALID_ARGS",message:"replay accepts .ad script files. JSON replay payloads are no longer supported."}};let d=function(e){let t=[];for(let r of e.split(/\r?\n/)){let e=function(e){let t=e.trim();if(0===t.length||t.startsWith("#"))return null;let r=function(e){let t=[],r=0;for(;r<e.length;){for(;r<e.length&&/\s/.test(e[r]);)r+=1;if(r>=e.length)break;if('"'===e[r]){let i=r+1,n=!1;for(;i<e.length;){let t=e[i];if('"'===t&&!n)break;n="\\"===t&&!n,"\\"!==t&&(n=!1),i+=1}if(i>=e.length)throw new I("INVALID_ARGS",`Invalid replay script line: ${e}`);let a=e.slice(r,i+1);t.push(JSON.parse(a)),r=i+1;continue}let i=r;for(;i<e.length&&!/\s/.test(e[i]);)i+=1;t.push(e.slice(r,i)),r=i}return t}(t);if(0===r.length)return null;let[i,...n]=r;if("context"===i)return null;let a={ts:Date.now(),command:i,positionals:[],flags:{}};if("snapshot"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("-i"===t){a.flags.snapshotInteractiveOnly=!0;continue}if("-c"===t){a.flags.snapshotCompact=!0;continue}if("--raw"===t){a.flags.snapshotRaw=!0;continue}if(("-d"===t||"--depth"===t)&&e+1<n.length){let t=Number(n[e+1]);Number.isFinite(t)&&t>=0&&(a.flags.snapshotDepth=Math.floor(t)),e+=1;continue}if(("-s"===t||"--scope"===t)&&e+1<n.length){a.flags.snapshotScope=n[e+1],e+=1;continue}if("--backend"===t&&e+1<n.length){e+=1;continue}}return a}if("open"===i){a.positionals=[];for(let e=0;e<n.length;e+=1){let t=n[e];if("--relaunch"===t){a.flags.relaunch=!0;continue}a.positionals.push(t)}return a}if(iZ(i)){let e=i1(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 n3(r)&&n3(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=i1(i,n);return Object.assign(a.flags,e.flags),a.positionals=e.positionals,a}return a.positionals=n,a}(r);e&&t.push(e)}return t}(s),u=t.flags?.replayUpdate===!0,c=0;for(let e=0;e<d.length;e+=1){let s=d[e];if(!s||"replay"===s.command)continue;let l=await a({token:t.token,session:r,command:s.command,positionals:s.positionals??[],flags:a$(t.flags,s.flags),meta:t.meta});if(l.ok)continue;if(!u)return aP(l,s,e,o);let p=await aF({action:s,sessionName:r,logPath:i,sessionStore:n,dispatch:v});if(!p)return aP(l,s,e,o);if(d[e]=p,!(l=await a({token:t.token,session:r,command:p.command,positionals:p.positionals??[],flags:a$(t.flags,p.flags),meta:t.meta})).ok)return aP(l,p,e,o);c+=1}if(u&&c>0){let e=n.get(r);!function(e,t,r){let i=[];if(r){let e=r.device.name.replace(/"/g,'\\"'),t=r.device.kind?` kind=${r.device.kind}`:"",n=r.device.target?` target=${r.device.target}`:"";i.push(`context platform=${r.device.platform}${n} device="${e}"${t} theme=unknown`)}for(let e of t)i.push(function(e){let t=[e.command];if("snapshot"===e.command)return e.flags?.snapshotInteractiveOnly&&t.push("-i"),e.flags?.snapshotCompact&&t.push("-c"),"number"==typeof e.flags?.snapshotDepth&&t.push("-d",String(e.flags.snapshotDepth)),e.flags?.snapshotScope&&t.push("-s",iQ(e.flags.snapshotScope)),e.flags?.snapshotRaw&&t.push("--raw"),t.join(" ");if("open"===e.command){for(let r of e.positionals??[])t.push(iQ(r));return e.flags?.relaunch&&t.push("--relaunch"),t.join(" ")}for(let r of e.positionals??[])t.push(iQ(r));return i0(t,e),t.join(" ")}(e));let n=`${i.join("\n")}
|
|
32
|
+
`,a=`${e}.tmp-${process.pid}-${Date.now()}`;R.writeFileSync(a,n),R.renameSync(a,e)}(o,d,e)}return{ok:!0,data:{replayed:d.length,healed:c,session:r}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message}}}}if("logs"===b){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"logs requires an active session"}};let i=(t.positionals?.[0]??"path").toLowerCase(),a=!!t.flags?.restart;if(!ar.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:ai}};if(a&&"clear"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs --restart is only supported with logs clear"}};if("path"===i){let t=n.resolveAppLogPath(r),i=function(e){if(!R.existsSync(e))return{exists:!1,sizeBytes:0};let t=R.statSync(e);return{exists:!0,sizeBytes:t.size,modifiedAt:t.mtime.toISOString()}}(t),a=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android");return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:a,sizeBytes:i.sizeBytes,modifiedAt:i.modifiedAt,startedAt:e.appLog?.startedAt?new Date(e.appLog.startedAt).toISOString():void 0,hint:'Grep the file for token-efficient debugging, e.g. grep -n "Error\\|Exception" <path>'}}}if("doctor"===i){let t=n.resolveAppLogPath(r),i=await nH(e.device,e.appBundleId);return{ok:!0,data:{path:t,active:!!e.appLog,state:e.appLog?.getState()??"inactive",checks:i.checks,notes:i.notes}}}if("mark"===i){let e,i=t.positionals?.slice(1).join(" ")??"",a=n.resolveAppLogPath(r);return nj(a),e=`[agent-device][mark][${new Date().toISOString()}] ${i.trim()||"marker"}
|
|
33
|
+
`,R.appendFileSync(a,e,"utf8"),{ok:!0,data:{path:a,marked:!0}}}if("clear"===i){if(e.appLog&&!a)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear requires logs to be stopped first; run logs stop"}};if(a){if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs clear --restart requires an app session; run open <app> first"}};if(!iH("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))}}let t=n.resolveAppLogPath(r);if(a){e.appLog&&await p.stop(e.appLog);let i=nJ(t),a=n.resolveAppLogPidPath(r);try{let o=await p.start(e.device,e.appBundleId,t,a),s={...e,appLog:{platform:e.device.platform,backend:o.backend,outPath:t,startedAt:o.startedAt,getState:o.getState,stop:o.stop,wait:o.wait}};return n.set(r,s),{ok:!0,data:{...i,restarted:!0}}}catch(i){let t=_(i);return n.set(r,{...e,appLog:void 0}),{ok:!1,error:t}}}return{ok:!0,data:nJ(t)}}if("start"===i){if(e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"app log already streaming; run logs stop first"}};if(!e.appBundleId)return{ok:!1,error:{code:"INVALID_ARGS",message:"logs start requires an app session; run open <app> first"}};if(!iH("logs",e.device))return{ok:!1,error:_(new I("UNSUPPORTED_OPERATION","logs is not supported on this device"))};let t=n.resolveAppLogPath(r),i=n.resolveAppLogPidPath(r);try{let a=await p.start(e.device,e.appBundleId,t,i),o={...e,appLog:{platform:e.device.platform,backend:a.backend,outPath:t,startedAt:a.startedAt,getState:a.getState,stop:a.stop,wait:a.wait}};return n.set(r,o),{ok:!0,data:{path:t,started:!0}}}catch(e){return{ok:!1,error:_(e)}}}if("stop"===i){if(!e.appLog)return{ok:!1,error:{code:"INVALID_ARGS",message:"no app log stream active"}};let t=e.appLog.outPath;return await p.stop(e.appLog),n.set(r,{...e,appLog:void 0}),{ok:!0,data:{path:t,stopped:!0}}}}if("network"===b){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"network requires an active session"}};let i=(t.positionals?.[0]??"dump").toLowerCase();if(!au.includes(i))return{ok:!1,error:{code:"INVALID_ARGS",message:ac}};let a=t.positionals?.[1],o=a?Number.parseInt(a,10):25;if(!Number.isInteger(o)||o<1||o>200)return{ok:!1,error:{code:"INVALID_ARGS",message:"network dump limit must be an integer in range 1..200"}};let s=(t.positionals?.[2]??"summary").toLowerCase();if(!ap.includes(s))return{ok:!1,error:{code:"INVALID_ARGS",message:af}};let l=function(e,t){let r=n1(t?.maxEntries,25,1,200),i=t?.include??"summary",n=n1(t?.maxPayloadChars,2048,64,16384),a=n1(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=nY(n,["method","httpMethod"]),o=nY(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=nz.exec(e),d=/\bmethod["'=: ]+([A-Z]+)\b/i.exec(e),u=(a??d?.[1]??l?.[1])?.toUpperCase(),c=nK.exec(e),p=o??c?.[0];if(!p)return null;let f={method:u,url:p,status:s??function(e){for(let t of nX){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:n0(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 nQ(e)}let r=/\bheaders?["'=: ]+(\{.*\})/i.exec(e);return r?.[1]?.trim()}(e,n);t&&(f.headers=n0(t,i))}if("body"===r||"all"===r){let t=nZ(e,n,["requestBody","body","payload","request"]),r=nZ(e,n,["responseBody","response"]);t&&(f.requestBody=n0(t,i)),r&&(f.responseBody=n0(r,i))}return f}(t,s+e+1,i,n);r&&d.push(r)}return{path:e,exists:!0,scannedLines:l.length,matchedLines:d.length,entries:d,include:i,limits:{maxEntries:r,maxPayloadChars:n,maxScanLines:a}}}(n.resolveAppLogPath(r),{maxEntries:o,include:s,maxPayloadChars:2048,maxScanLines:4e3}),d=e.appLog?.backend??("ios"===e.device.platform?"device"===e.device.kind?"ios-device":"ios-simulator":"android"),u=[];return e.appLog||u.push("Capture uses the session app log file. For fresh traffic, run logs clear --restart before reproducing requests."),0===l.entries.length&&u.push("No HTTP(s) entries were found in recent session app logs."),{ok:!0,data:{...l,active:!!e.appLog,state:e.appLog?.getState()??"inactive",backend:d,notes:u}}}if("batch"===b)return await aT(t,r,a);if("close"===b){let e=n.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if(e.appLog&&await p.stop(e.appLog),t.positionals&&t.positionals.length>0&&("ios"===e.device.platform&&await N(e.device.id),await v(e.device,"close",t.positionals,t.flags?.out,{...i3(i,t.flags,e.appBundleId,e.trace?.outPath)}),await S(e.device,ao)),"ios"===e.device.platform&&await N(e.device.id),n.recordAction(e,{command:b,positionals:t.positionals??[],flags:t.flags??{},result:{session:r}}),t.flags?.saveScript&&(e.recordSession=!0),n.writeSessionLog(e),n.delete(r),t.flags?.shutdown&&aw(e.device)){let t;try{t=await (g??t1)(e.device)}catch(r){let e=_(r);t={success:!1,exitCode:-1,stdout:"",stderr:e.message,error:e}}return{ok:!0,data:{session:r,shutdown:t}}}return{ok:!0,data:{session:r}}}return null}async function aT(e,t,r){let i=e.flags?.batchOnError??"stop";if("stop"!==i)return{ok:!1,error:{code:"INVALID_ARGS",message:`Unsupported batch on-error mode: ${i}.`}};let n=e.flags?.batchMaxSteps??L;if(!Number.isInteger(n)||n<1||n>1e3)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid batch max-steps: ${String(e.flags?.batchMaxSteps)}`}};try{let i=o(e.flags?.batchSteps,n),a=Date.now(),s=[];for(let n=0;n<i.length;n+=1){let a=i[n],o=await aR(e,t,a,r,n+1);if(!o.ok)return{ok:!1,error:{code:o.error.code,message:`Batch failed at step ${o.step} (${a.command}): ${o.error.message}`,hint:o.error.hint,diagnosticId:o.error.diagnosticId,logPath:o.error.logPath,details:{...o.error.details??{},step:o.step,command:a.command,positionals:a.positionals,executed:n,total:i.length,partialResults:s}}};s.push(o.result)}return{ok:!0,data:{total:i.length,executed:i.length,totalDurationMs:Date.now()-a,results:s}}}catch(t){let e=w(t);return{ok:!1,error:{code:e.code,message:e.message,details:e.details}}}}async function aR(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 ae)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 aP(e,t,r,i){if(e.ok)return e;let n=r+1,a=function(e){let t;return t=(e.positionals??[]).map(e=>iQ(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 a$(e,t){let r={...t??{}},i=e??{};for(let e of at)void 0===r[e]&&void 0!==i[e]&&(r[e]=i[e]);return r}async function aF(e){let{action:t,sessionName:r,logPath:i,sessionStore:n,dispatch:a}=e;if(!(iZ(t.command)||["fill","get","is","wait"].includes(t.command)))return null;let o=n.get(r);if(!o)return null;let s=iZ(t.command)||"fill"===t.command,l=iZ(t.command)||"fill"===t.command||"get"===t.command&&t.positionals?.[0]==="text",d=await aV(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),iZ(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}=nv(e.positionals);r&&t.push(r.selectorExpression)}if("wait"===e.command){let{selectorExpression:r}=n2(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 iz(t).filter(e=>e.trim().length>0)}(t)){let r=nm(e);if(!r)continue;let i=nh(d.nodes,r,{platform:o.device.platform,requireRect:s,requireUnique:!0,disambiguateAmbiguous:l});if(!i)continue;let n=nN(i.node,o.device.platform,{action:iZ(t.command)?"click":"fill"===t.command?"fill":"get"}).join(" || ");if(iZ(t.command))return{...t,positionals:[n]};if("fill"===t.command){let e=iJ(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}=nv(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}=n2(t.positionals??[]),r=[n];return e&&r.push(e),{...t,positionals:r}}}let u=function(e,t,r){if("get"!==e.command||e.positionals?.[0]!=="text")return null;let i=e.positionals?.[1];if(!i)return null;let n=nm(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(ns(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=nd(e).trim();return!!/^\d+$/.test(t)&&(0===a.size||a.has(ns(e.type??"")))});if(0===s.length||1!==iz(s.map(e=>nd(e).trim())).length)return null;let l=s[0];if(!l)return null;let d=nN(l,r.device.platform,{action:"get"});return 0===d.length?null:{...e,positionals:["text",d.join(" || ")]}}(t,d,o);return u||null}async function aV(e,t,r,i,n,a){let o=await n(e.device,"snapshot",[],t.flags?.out,{...i3(r,{...t.flags??{},snapshotInteractiveOnly:i,snapshotCompact:i},e.appBundleId,e.trace?.outPath)}),s=o?.nodes??[],l={nodes:i7(t.flags?.snapshotRaw?s:no(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend};return e.snapshot=l,a.set(e.name,e),l}function aU(e){if(!e)return null;let t=Number(e);return Number.isFinite(t)?t:null}function aG(e,t){let r=S(e.type??"Element"),i=m(e,r),n=!1===e.enabled?"disabled":"enabled",a=!0===e.selected?"selected":"unselected",o=!0===e.hittable?"hittable":"not-hittable";return[String(t??e.depth??0),r,i,n,a,o].join("|")}function aB(e,t){return t.flatten?e.map(e=>({text:B(e,0,!1),comparable:aG(e,0)})):A(e).map(e=>({text:e.text,comparable:aG(e.node,e.depth)}))}function aj(e,t){return e.get(t)??0}async function aq(e){let{req:t,sessionName:r,logPath:i,sessionStore:n}=e,a=e.dispatchSnapshotCommand??iq,o=e.runnerCommand??rB,s=t.command;if("snapshot"===s){let{session:e,device:o}=await aJ(n,r,t.flags);if(!iH("snapshot",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"snapshot is not supported on this device"}};let s=aH(t.flags?.snapshotScope,e);return s.ok?await az(e,o,async()=>{let l=e?.appBundleId,d=await aW({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope}),u=e?{...e,snapshot:d.snapshot}:{name:r,device:o,createdAt:Date.now(),appBundleId:l,snapshot:d.snapshot,actions:[]};return aK(n,u,t,{nodes:d.snapshot.nodes.length,truncated:d.snapshot.truncated??!1}),n.set(r,u),{ok:!0,data:{nodes:d.snapshot.nodes,truncated:d.snapshot.truncated??!1,appName:u.appBundleId?u.appName??u.appBundleId:void 0,appBundleId:u.appBundleId}}}):s.response}if("diff"===s){if(t.positionals?.[0]!=="snapshot")return{ok:!1,error:{code:"INVALID_ARGS",message:"diff currently supports only: diff snapshot"}};let{session:e,device:o}=await aJ(n,r,t.flags);if(!iH("diff",o))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"diff is not supported on this device"}};let s=aH(t.flags?.snapshotScope,e);if(!s.ok)return s.response;let l=t.flags?.snapshotInteractiveOnly===!0;return await az(e,o,async()=>{let d=e?.appBundleId,u=(await aW({dispatchSnapshotCommand:a,device:o,session:e,req:t,logPath:i,snapshotScope:s.scope})).snapshot;if(!e?.snapshot){let i=function(e,t={}){return aB(e,t).length}(u.nodes,{flatten:l}),a=e?{...e,snapshot:u}:{name:r,device:o,createdAt:Date.now(),appBundleId:d,snapshot:u,actions:[]};return aK(n,a,t,{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i}}),n.set(r,a),{ok:!0,data:{mode:"snapshot",baselineInitialized:!0,summary:{additions:0,removals:0,unchanged:i},lines:[]}}}let c=function(e,t,r={}){let i=function(e,t){let r=e.length,i=t.length,n=r+i,a=new Map,o=[];a.set(1,0);for(let s=0;s<=n;s+=1){o.push(new Map(a));for(let n=-s;n<=s;n+=2){let l=n===-s||n!==s&&aj(a,n-1)<aj(a,n+1)?aj(a,n+1):aj(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&&aj(n,l-1)<aj(n,l+1)?l+1:l-1,u=aj(n,d),c=u-d;for(;o>u&&s>c;)a.push({kind:"unchanged",text:r[s-1].text}),o-=1,s-=1;if(0===i)break;o===u?(a.push({kind:"added",text:r[c].text}),s=c):(a.push({kind:"removed",text:t[u].text}),o=u)}return a.reverse(),a}(o,e,t,r,i)}}return[]}(aB(e,r),aB(t,r)),n={additions:0,removals:0,unchanged:0};for(let e of i)"added"===e.kind&&(n.additions+=1),"removed"===e.kind&&(n.removals+=1),"unchanged"===e.kind&&(n.unchanged+=1);return{summary:n,lines:i}}(e.snapshot.nodes,u.nodes,{flatten:l}),p={...e,snapshot:u};return aK(n,p,t,{mode:"snapshot",baselineInitialized:!1,summary:c.summary}),n.set(r,p),{ok:!0,data:{mode:"snapshot",baselineInitialized:!1,summary:c.summary,lines:c.lines}}})}if("wait"===s){let{session:e,device:o}=await aJ(n,r,t.flags),s=function(e){if(0===e.length)return null;let t=aU(e[0]);if(null!==t)return{kind:"sleep",durationMs:t};if("text"===e[0]){let t=aU(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=aU(e[e.length-1]);return{kind:"ref",rawRef:e[0],timeoutMs:t}}let r=aU(e[e.length-1]),i=nI(null!==r?e.slice(0,-1):e.slice());if(i&&0===i.rest.length){let e=nm(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)),aK(n,e,t,{waitedMs:s.durationMs}),{ok:!0,data:{waitedMs:s.durationMs}}):iH("wait",o)?await az(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,{...i3(i,{...t.flags,snapshotInteractiveOnly:!1,snapshotCompact:!1},e?.appBundleId,e?.trace?.outPath)}),u=l?.nodes??[],c=i7(t.flags?.snapshotRaw?u:no(u));e&&(e.snapshot={nodes:c,truncated:l?.truncated,createdAt:Date.now(),backend:l?.backend},n.set(r,e));let p=nw(c,s.selector,{platform:o.platform});if(p)return aK(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=ne(s.rawRef);if(!t)return{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref: ${s.rawRef}`}};let r=nt(e.snapshot.nodes,t),i=r?nn(r,e.snapshot.nodes):void 0;if(!i)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s.rawRef} not found or has no label`}};l=i,d=s.timeoutMs}else l=s.text,d=s.timeoutMs;if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires text"}};let u=d??1e4,c=Date.now();for(;Date.now()-c<u;){if("ios"===o.platform){let r=await rB(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 aK(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}}}else if("android"===o.platform&&ni(i7((await e6(o,{scope:l})).nodes??[]),l))return aK(n,e,t,{text:l,waitedMs:Date.now()-c}),{ok:!0,data:{text:l,waitedMs:Date.now()-c}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:`wait timed out for text: ${l}`}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"wait is not supported on this device"}}:{ok:!1,error:{code:"INVALID_ARGS",message:"wait requires a duration or text"}}}if("alert"===s){let{session:e,device:a}=await aJ(n,r,t.flags),s=(t.positionals?.[0]??"get").toLowerCase();return iH("alert",a)?await az(e,a,async()=>{if("wait"===s){let r=aU(t.positionals?.[1])??1e4,s=Date.now();for(;Date.now()-s<r;){try{let r=await o(a,{command:"alert",action:"get",appBundleId:e?.appBundleId},{verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId});return aK(n,e,t,r),{ok:!0,data:r}}catch{}await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"alert wait timed out"}}}let r="accept"===s||"dismiss"===s?s:"get",l={verbose:t.flags?.verbose,logPath:i,traceLogPath:e?.trace?.outPath,requestId:t.meta?.requestId};if("accept"===r||"dismiss"===r){let i,s=Date.now();for(;Date.now()-s<2e3;){try{let i=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return aK(n,e,t,i),{ok:!0,data:i}}catch(t){i=t;let e=String(t?.message??"").toLowerCase();if(!e.includes("alert not found")&&!e.includes("no alert"))break}await new Promise(e=>setTimeout(e,300))}throw i}let d=await o(a,{command:"alert",action:r,appBundleId:e?.appBundleId},l);return aK(n,e,t,d),{ok:!0,data:d}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"alert is only supported on iOS simulators"}}}if("settings"===s){let e=t.positionals?.[0]?.toLowerCase(),a=t.positionals?.[1]?.toLowerCase(),o=t.positionals?.[2]?.toLowerCase();if(!e||!a||"permission"===e&&!o)return{ok:!1,error:{code:"INVALID_ARGS",message:u}};let{session:s,device:l}=await aJ(n,r,t.flags);return iH("settings",l)?await az(s,l,async()=>{let r=s?.appBundleId,d="permission"===e?[e,a,o,t.positionals?.[3]??"",r??""]:[e,a,r??""],u=await iq(l,"settings",d,t.flags?.out,{...i3(i,t.flags,r,s?.trace?.outPath)});return aK(n,s,t,u??{setting:e,state:a}),{ok:!0,data:u??{setting:e,state:a}}}):{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"settings is not supported on this device"}}}return null}async function aW(e){let{dispatchSnapshotCommand:t,device:r,session:i,req:n,logPath:a,snapshotScope:o}=e,s=await t(r,"snapshot",[],n.flags?.out,{...i3(a,{...n.flags,snapshotScope:o},i?.appBundleId,i?.trace?.outPath)}),l=s?.nodes??[];return{snapshot:{nodes:i7(n.flags?.snapshotRaw?l:no(l)),truncated:s?.truncated,createdAt:Date.now(),backend:s?.backend}}}function aH(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=ne(e.trim());if(!r)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:`Invalid ref scope: ${e}`}}};let i=nt(t.snapshot.nodes,r),n=i?nn(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 aJ(e,t,r){let i=e.get(t),n=i?.device??await ij(r??{});return i||await i8(n),{session:i,device:n}}async function az(e,t,r){let i=!e&&"ios"===t.platform;try{return await r()}finally{i&&await rR(t.id)}}function aK(e,t,r,i){t&&e.recordAction(t,{command:r.command,positionals:r.positionals??[],flags:r.flags??{},result:i})}function aX(e,t,r,i={}){let n=aZ(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 aY(e.label,r);case"value":return aY(e.value,r);case"id":return aY(e.identifier,r);default:return Math.max(aY(e.label,r),aY(e.value,r),aY(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 aY(e,t){let r=aZ(e??"");return r?r===t?2:+!!r.includes(t):0}function aZ(e){return e.trim().toLowerCase().replace(/\s+/g," ")}async function aQ(e){let{req:t,sessionName:r,logPath:i,sessionStore:n,invoke:a}=e,o=e.dispatch??iq,s=t.command;if("find"!==s)return null;let l=t.positionals??[];if(0===l.length)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a locator or text"}};let{locator:d,query:u,action:c,value:p,timeoutMs:f}=function(e){let t="any",r=0;["text","label","value","role","id"].includes(e[0])&&(t=e[0],r=1);let i=e[r]??"",n=e.slice(r+1);if(0===n.length)return{locator:t,query:i,action:"click"};let a=n[0].toLowerCase();if("get"===a){let e=n[1]?.toLowerCase();if("text"===e)return{locator:t,query:i,action:"get_text"};if("attrs"===e)return{locator:t,query:i,action:"get_attrs"};throw new I("INVALID_ARGS","find get only supports text or attrs")}if("wait"===a)return{locator:t,query:i,action:"wait",timeoutMs:aU(n[1])??void 0};if("exists"===a)return{locator:t,query:i,action:"exists"};if("click"===a)return{locator:t,query:i,action:"click"};if("focus"===a)return{locator:t,query:i,action:"focus"};if("fill"===a)return{locator:t,query:i,action:"fill",value:n.slice(1).join(" ")};if("type"===a)return{locator:t,query:i,action:"type",value:n.slice(1).join(" ")};throw new I("INVALID_ARGS",`Unsupported find action: ${n[0]}`)}(l);if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:"find requires a value"}};let m=n.get(r);if(!m&&"exists"!==c&&"wait"!==c&&"get_text"!==c&&"get_attrs"!==c)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let h=m?.device??await ij(t.flags??{});m||await i8(h);let w=m?.appBundleId,g="role"!==d?u:void 0,v="click"===c||"focus"===c||"fill"===c||"type"===c,A=0,y=null,N=async()=>{let e=Date.now();if(y&&e-A<750)return{nodes:y};let a=await o(h,"snapshot",[],t.flags?.out,{...i3(i,{...t.flags,snapshotScope:g,snapshotInteractiveOnly:v,snapshotCompact:v},w,m?.trace?.outPath)}),s=a?.nodes??[],l=i7(t.flags?.snapshotRaw?s:no(s));return A=e,y=l,m&&(m.snapshot={nodes:l,truncated:a?.truncated,createdAt:Date.now(),backend:a?.backend},n.set(r,m)),{nodes:l,truncated:a?.truncated,backend:a?.backend}};if("wait"===c){let e=f??1e4,r=Date.now();for(;Date.now()-r<e;){let{nodes:e}=await N();if(aX(e,d,u,{requireRect:!1}).matches[0])return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0,waitedMs:Date.now()-r}}),{ok:!0,data:{found:!0,waitedMs:Date.now()-r}};await new Promise(e=>setTimeout(e,300))}return{ok:!1,error:{code:"COMMAND_FAILED",message:"find wait timed out"}}}let{nodes:S}=await N(),_=aX(S,d,u,{requireRect:v});if(v&&_.matches.length>1){let e=_.matches.slice(0,8).map(e=>{let t=nd(e)||e.label||e.identifier||e.type||"";return`@${e.ref}${t?`(${t})`:""}`});return{ok:!1,error:{code:"AMBIGUOUS_MATCH",message:`find matched ${_.matches.length} elements for ${d} "${u}". Use a more specific locator or selector.`,details:{locator:d,query:u,matches:_.matches.length,candidates:e}}}}let b=_.matches[0]??null;if(!b)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,b)??b:b,E=`@${D.ref}`,O={...t.flags??{},noRecord:!0};if("exists"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{found:!0}}),{ok:!0,data:{found:!0}};if("get_text"===c){let e=nd(b);return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get text",text:e}}),{ok:!0,data:{ref:E,text:e,node:b}}}if("get_attrs"===c)return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"get attrs"}}),{ok:!0,data:{ref:E,node:b}};if("click"===c){let e=await a({token:t.token,session:r,command:"click",positionals:[E],flags:O});if(!e.ok)return e;let i=D.rect?nr(D.rect):null,o={ref:E,locator:d,query:u};return i&&(o.x=i.x,o.y=i.y),m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"click",locator:d,query:u}}),{ok:!0,data:o}}if("fill"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find fill requires text"}};let e=await a({token:t.token,session:r,command:"fill",positionals:[E,p],flags:O});return e.ok&&m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"fill"}}),e}if("focus"===c){let e=b.rect?nr(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};let r=await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...i3(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"focus"}}),{ok:!0,data:r??{ref:E}}}if("type"===c){if(!p)return{ok:!1,error:{code:"INVALID_ARGS",message:"find type requires text"}};let e=b.rect?nr(b.rect):null;if(!e)return{ok:!1,error:{code:"COMMAND_FAILED",message:"matched element has no bounds"}};await o(h,"focus",[String(e.x),String(e.y)],t.flags?.out,{...i3(i,t.flags,m?.appBundleId,m?.trace?.outPath)});let r=await o(h,"type",[p],t.flags?.out,{...i3(i,t.flags,m?.appBundleId,m?.trace?.outPath)});return m&&n.recordAction(m,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{ref:E,action:"type"}}),{ok:!0,data:r??{ref:E}}}return null}function a0(e){return e instanceof Error?e.message:String(e)}function a1(e){let t=e.appBundleId?.trim();return t&&t.length>0?t:void 0}function a2(e,t,r){return{verbose:e.flags?.verbose,logPath:t,traceLogPath:r.trace?.outPath}}async function a3(e){let{req:t,sessionName:r,sessionStore:i,logPath:a}=e,o=e.deps??{runCmd:p,runCmdBackground:d,runIosRunnerCommand:rB},s=t.command;if("record"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"record requires start|stop"}};let d=i.get(r),c=d?.device??await ij(t.flags??{});d||await i8(c);let p=d??{name:r,device:c,createdAt:Date.now(),actions:[]};if("start"===e){if(p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"recording already in progress"}};let e=t.flags?.fps;if(void 0!==e&&(!Number.isInteger(e)||e<1||e>120))return{ok:!1,error:{code:"INVALID_ARGS",message:"fps must be an integer between 1 and 120"}};let d=t.positionals?.[1]??`./recording-${Date.now()}.mp4`;if(!iH("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?a1(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=i2.expandHome(d,t.meta?.cwd);R.mkdirSync(n.dirname(m),{recursive:!0});let h=a2(t,a,p);if("ios"===c.platform&&"device"===c.kind){let t=`agent-device-recording-${Date.now()}.mp4`,r=`tmp/${t}`,n=async()=>{await o.runIosRunnerCommand(c,{command:"recordStart",outPath:t,fps:e,appBundleId:f},h)};try{await n()}catch(e){if(!a0(e).toLowerCase().includes("recording already in progress"))return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${a0(e)}`}};{var l,u;M({level:"warn",phase:"record_start_runner_desynced",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:a0(e)}});let t=(l=c.id,u=p.name,i.toArray().find(e=>e.name!==u&&"ios"===e.device.platform&&"device"===e.device.kind&&e.device.id===l&&e.recording?.platform==="ios-device-runner"));if(t)return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: recording already in progress in session '${t.name}'`}};try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:f},h)}catch{}try{await n()}catch(e){return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to start recording: ${a0(e)}`}}}}}p.recording={platform:"ios-device-runner",outPath:m,remotePath:r}}else if("ios"===c.platform){let{child:e,wait:t}=o.runCmdBackground("xcrun",tY(c,["io",c.id,"recordVideo",m]),{allowFailure:!0});p.recording={platform:"ios",outPath:m,child:e,wait:t}}else{let e=`/sdcard/agent-device-recording-${Date.now()}.mp4`,{child:t,wait:r}=o.runCmdBackground("adb",["-s",c.id,"shell","screenrecord",e],{allowFailure:!0});p.recording={platform:"android",outPath:m,remotePath:e,child:t,wait:r}}return i.set(r,p),i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"start"}}),{ok:!0,data:{recording:"started",outPath:d}}}if(!p.recording)return{ok:!1,error:{code:"INVALID_ARGS",message:"no active recording"}};let f=p.recording;if("ios-device-runner"===f.platform){let e=a1(p);try{await o.runIosRunnerCommand(c,{command:"recordStop",appBundleId:e},a2(t,a,p))}catch(e){M({level:"warn",phase:"record_stop_runner_failed",data:{platform:c.platform,kind:c.kind,deviceId:c.id,session:p.name,error:a0(e)}})}let r={stdout:"",stderr:"",exitCode:1};for(let e of r_)if(0===(r=await o.runCmd("xcrun",["devicectl","device","copy","from","--device",c.id,"--source",f.remotePath,"--destination",f.outPath,"--domain-type","appDataContainer","--domain-identifier",e],{allowFailure:!0})).exitCode)break;if(p.recording=void 0,0!==r.exitCode){let e=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;return{ok:!1,error:{code:"COMMAND_FAILED",message:`failed to copy recording from device: ${e}`}}}}else{f.child.kill("SIGINT");try{await f.wait}catch{}if("android"===f.platform&&f.remotePath)try{await o.runCmd("adb",["-s",c.id,"pull",f.remotePath,f.outPath],{allowFailure:!0}),await o.runCmd("adb",["-s",c.id,"shell","rm","-f",f.remotePath],{allowFailure:!0})}catch{}p.recording=void 0}return i.recordAction(p,{command:s,positionals:t.positionals??[],flags:t.flags??{},result:{action:"stop",outPath:f.outPath}}),{ok:!0,data:{recording:"stopped",outPath:f.outPath}}}if("trace"===s){let e=(t.positionals?.[0]??"").toLowerCase();if(!["start","stop"].includes(e))return{ok:!1,error:{code:"INVALID_ARGS",message:"trace requires start|stop"}};let a=i.get(r);if(!a)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session"}};if("start"===e){if(a.trace)return{ok:!1,error:{code:"INVALID_ARGS",message:"trace already in progress"}};let e=t.positionals?.[1]??i.defaultTracePath(a),r=i2.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=i2.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 a4(e,t,r){return t>=e.x&&t<=e.x+e.width&&r>=e.y&&r<=e.y+e.height}function a8(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 a5(e,t,r){return Math.min(r,Math.max(t,Math.round(e)))}async function a6(e){let{req:t,sessionName:r,sessionStore:i,contextFromFlags:n}=e,a=e.dispatch??iq,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(!iH("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=oe("press",t.flags);if(r)return r;let s=t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",u=ot({session:e,refInput:d,fallbackLabel:s,requireRect:!0,invalidRefMessage:`${o} requires a ref like @e2`,notFoundMessage:`Ref ${d} not found or has no bounds`});if(!u.ok)return u.response;let{ref:c}=u.target,p=u.target.node,f=u.target.snapshotNodes,m=or(p.rect);if(!m){let r=await a9(e,t.flags,i,n,{interactiveOnly:!0},a),o=nt(r.nodes,c),l=s.length>0?ni(r.nodes,s):null,d=or(l?.rect),u=or(o?.rect)?o:d?l:o??l,h=or(u?.rect);u&&h&&(p=u,f=r.nodes,m=h)}if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${d} not found or has invalid bounds`}};let h=nn(p,f),w=nN(p,e.device.platform,{action:l}),{x:g,y:I}=m,v=await a(e.device,"press",[String(g),String(I)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:c,x:g,y:I,refLabel:h,selectorChain:w}}),{ok:!0,data:{...v??{},ref:c,x:g,y:I}}}let u=(t.positionals??[]).join(" ").trim();if(!u)return{ok:!1,error:{code:"INVALID_ARGS",message:`${o} requires @ref, selector expression, or x y coordinates`}};let c=nf(u),p=await a9(e,t.flags,i,n,{interactiveOnly:!0},a),f=await k("selector_resolve",()=>nh(p.nodes,c,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!f||!f.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:ng(c,f?.diagnostics??[],{unique:!0})}};let m=or(f.node.rect);if(!m)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Selector ${f.selector.raw} resolved to invalid bounds`}};let{x:h,y:w}=m,g=await a(e.device,"press",[String(h),String(w)],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),I=nN(f.node,e.device.platform,{action:l}),v=nn(f.node,p.nodes);return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{x:h,y:w,selector:f.selector.raw,selectorChain:I,refLabel:v}}),{ok:!0,data:{...g??{},selector:f.selector.raw,x:h,y:w}}}if("fill"===o){let e=i.get(r);if(e&&!iH("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=oe("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=ot({session:e,refInput:t.positionals[0],fallbackLabel:s,requireRect:!0,invalidRefMessage:"fill requires a ref like @e2",notFoundMessage:`Ref ${t.positionals[0]} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${t.positionals[0]} not found or has no bounds`}};let f=c.type??"",m=f&&!nl(f,e.device.platform)?`fill target ${t.positionals[0]} resolved to "${f}", attempting fill anyway.`:void 0,h=nn(c,p),w=nN(c,e.device.platform,{action:"fill"}),{x:g,y:I}=nr(c.rect),v={...await a(e.device,"fill",[String(g),String(I),l],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)})??{ref:u,x:g,y:I}};return m&&(v.warning=m),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...v,refLabel:h,selectorChain:w}}),{ok:!0,data:v}}if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};let s=nI(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=nf(s.selectorExpression),d=await a9(e,t.flags,i,n,{interactiveOnly:!0},a),u=await k("selector_resolve",()=>nh(d.nodes,l,{platform:e.device.platform,requireRect:!0,requireUnique:!0,disambiguateAmbiguous:!0}),{command:o});if(!u||!u.node.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:ng(l,u?.diagnostics??[],{unique:!0})}};let c=u.node,p=c.type??"",f=p&&!nl(p,e.device.platform)?`fill target ${u.selector.raw} resolved to "${p}", attempting fill anyway.`:void 0,{x:m,y:h}=nr(u.node.rect),w=await a(e.device,"fill",[String(m),String(h),r],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath)}),g=nN(c,e.device.platform,{action:"fill"}),I={...w??{x:m,y:h,text:r},selector:u.selector.raw,selectorChain:g,refLabel:nn(c,d.nodes)};return f&&(I.warning=f),i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:I}),{ok:!0,data:I}}return{ok:!1,error:{code:"INVALID_ARGS",message:"fill requires x y text, @ref text, or selector text"}}}if("get"===o){let e=t.positionals?.[0];if("text"!==e&&"attrs"!==e)return{ok:!1,error:{code:"INVALID_ARGS",message:"get only supports text or attrs"}};let s=i.get(r);if(!s)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iH("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=oe("get",t.flags);if(r)return r;let n=ot({session:s,refInput:l,fallbackLabel:t.positionals.length>2?t.positionals.slice(2).join(" ").trim():"",requireRect:!1,invalidRefMessage:"get text requires a ref like @e2",notFoundMessage:`Ref ${l} not found`});if(!n.ok)return n.response;let{ref:a,node:d}=n.target,u=nN(d,s.device.platform,{action:"get"});if("attrs"===e)return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,selectorChain:u}}),{ok:!0,data:{ref:a,node:d}};let c=nd(d);return i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:a,text:c,refLabel:c||void 0,selectorChain:u}}),{ok:!0,data:{ref:a,text:c,node:d}}}let d=t.positionals.slice(1).join(" ").trim();if(!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"get requires @ref or selector expression"}};let u=nf(d),c=await a9(s,t.flags,i,n,{interactiveOnly:!1},a),p=await k("selector_resolve",()=>nh(c.nodes,u,{platform:s.device.platform,requireRect:!1,requireUnique:!0,disambiguateAmbiguous:"text"===e}),{command:o});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:ng(u,[],{unique:!0})}};let f=p.node,m=nN(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=nd(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(!iH("is",s.device))return{ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:"is is not supported on this device"}};let{split:l}=nv(t.positionals);if(!l)return{ok:!1,error:{code:"INVALID_ARGS",message:"is requires a selector expression"}};let d=l.rest.join(" ").trim();if("text"===e&&!d)return{ok:!1,error:{code:"INVALID_ARGS",message:"is text requires expected text value"}};if("text"!==e&&l.rest.length>0)return{ok:!1,error:{code:"INVALID_ARGS",message:`is ${e} does not accept trailing values`}};let u=nf(l.selectorExpression),c=await a9(s,t.flags,i,n,{interactiveOnly:!1},a);if("exists"===e){let r=nw(c.nodes,u,{platform:s.device.platform});return r?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:r.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,matches:r.matches}}),{ok:!0,data:{predicate:e,pass:!0,selector:r.selector.raw,matches:r.matches}}):{ok:!1,error:{code:"COMMAND_FAILED",message:ng(u,[],{unique:!1})}}}let p=await k("selector_resolve",()=>nh(c.nodes,u,{platform:s.device.platform,requireUnique:!0}),{command:"is",predicate:e});if(!p)return{ok:!1,error:{code:"COMMAND_FAILED",message:ng(u,[],{unique:!0})}};let f=function(e){let{predicate:t,node:r,expectedText:i,platform:n}=e,a=nd(r),o=!1;switch(t){case"visible":o=nA(r);break;case"hidden":o=!nA(r);break;case"editable":o=ny(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:nA(r),editable:ny(r,n),selected:!0===r.selected})}`;return{pass:o,actualText:a,details:s}}({predicate:e,node:p.node,expectedText:d,platform:s.device.platform});return f.pass?(i.recordAction(s,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{predicate:e,selector:p.selector.raw,selectorChain:u.selectors.map(e=>e.raw),pass:!0,text:"text"===e?f.actualText:void 0}}),{ok:!0,data:{predicate:e,pass:!0,selector:p.selector.raw}}):{ok:!1,error:{code:"COMMAND_FAILED",message:`is ${e} failed for selector ${p.selector.raw}: ${f.details}`}}}if("scrollintoview"===o){let e=i.get(r);if(!e)return{ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}};if(!iH("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=oe("scrollintoview",t.flags);if(l)return l;let d=ot({session:e,refInput:s,fallbackLabel:t.positionals&&t.positionals.length>1?t.positionals.slice(1).join(" ").trim():"",requireRect:!0,invalidRefMessage:"scrollintoview requires a ref like @e2",notFoundMessage:`Ref ${s} not found or has no bounds`});if(!d.ok)return d.response;let{ref:u,node:c,snapshotNodes:p}=d.target;if(!c.rect)return{ok:!1,error:{code:"COMMAND_FAILED",message:`Ref ${s} not found or has no bounds`}};let f=function(e,t){let r=nr(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=a8(n.map(e=>e.rect).filter(e=>a4(e,r.x,r.y)));if(a)return a;let o=a8(n.map(e=>e.rect));if(o)return o;let s=a8(i.map(e=>e.rect).filter(e=>a4(e,r.x,r.y)));return s||null}(p,c.rect);if(!f)return{ok:!1,error:{code:"COMMAND_FAILED",message:`scrollintoview could not infer viewport for ${s}`}};let m=function(e,t){var r,i;let n=Math.max(1,t.height),a=Math.max(1,t.width),o=t.y,s=t.y+n,l=t.x,d=t.x+a,u=o+.25*n,c=s-.25*n,p=Math.max(8,.1*a),f=e.y+e.height/2,m=e.x+e.width/2;if(f>=u&&f<=c)return null;let h=Math.round((r=m,i=l+p,Math.min(d-p,Math.max(i,r)))),w=Math.round(o+.86*n),g=Math.round(o+.14*n),I=Math.max(1,Math.abs(w-g));return f>c?{x:h,startY:w,endY:g,count:a5(Math.ceil((f-c)/I),1,50),direction:"down"}:{x:h,startY:g,endY:w,count:a5(Math.ceil((u-f)/I),1,50),direction:"up"}}(c.rect,f),h=nn(c,p),w=nN(c,e.device.platform,{action:"get"});if(!m)return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{ref:u,attempts:0,alreadyVisible:!0,refLabel:h,selectorChain:w}}),{ok:!0,data:{ref:u,attempts:0,alreadyVisible:!0}};let g=await a(e.device,"swipe",[String(m.x),String(m.startY),String(m.x),String(m.endY),"16"],t.flags?.out,{...n(t.flags,e.appBundleId,e.trace?.outPath),count:m.count,pauseMs:0,pattern:"one-way"});return i.recordAction(e,{command:o,positionals:t.positionals??[],flags:t.flags??{},result:{...g??{},ref:u,attempts:m.count,direction:m.direction,refLabel:h,selectorChain:w}}),{ok:!0,data:{...g??{},ref:u,attempts:m.count,direction:m.direction}}}return null}async function a9(e,t,r,i,n,a=iq){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:i7(t?.snapshotRaw?s:no(s)),truncated:o?.truncated,createdAt:Date.now(),backend:o?.backend},r.set(e.name,e),e.snapshot}let a7=[["snapshotDepth","--depth"],["snapshotScope","--scope"],["snapshotRaw","--raw"]];function oe(e,t){let r=function(e){if(!e)return[];let t=[];for(let[r,i]of a7)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 ot(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=ne(r);if(!s)return{ok:!1,response:{ok:!1,error:{code:"INVALID_ARGS",message:a}}};let l=nt(t.snapshot.nodes,s);return((!l||n&&!l.rect)&&i.length>0&&(l=ni(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 or(e){let t=function(e){if(!e)return null;let t=Number(e.x),r=Number(e.y),i=Number(e.width),n=Number(e.height);return Number.isFinite(t)&&Number.isFinite(r)&&Number.isFinite(i)&&Number.isFinite(n)&&!(i<0)&&!(n<0)?{x:t,y:r,width:i,height:n}:null}(e);if(!t)return null;let r=nr(t);return Number.isFinite(r.x)&&Number.isFinite(r.y)?r:null}function oi(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 on(e){let{req:t,leaseRegistry:r}=e,i=oi(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 oa=new Set(["agent_device.command","agent-device.command"]),oo={"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"},os=new Set([...oa,...Object.keys(oo)]);function ol(e,t,r,i){return{jsonrpc:"2.0",id:e,error:{code:t,message:r,data:i}}}function od(e,t,r=200){e.statusCode=r,e.setHeader("content-type","application/json"),e.end(JSON.stringify(t))}function ou(e){switch(e){case"INVALID_ARGS":return 400;case"UNAUTHORIZED":return 401;case"SESSION_NOT_FOUND":return 404;default:return 500}}function oc(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 op(e,t){let r=e[t];return"string"==typeof r?r:void 0}async function of(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=_(new I("UNAUTHORIZED","Request rejected by auth hook"));return{ok:!1,statusCode:401,response:ol(t.rpcRequest.id??null,-32001,e.message,e)}}if(!1===r.ok){let e=_(new I(r.code??"UNAUTHORIZED",r.message??"Request rejected by auth hook",r.details));return{ok:!1,statusCode:401,response:ol(t.rpcRequest.id??null,-32001,e.message,e)}}if("string"==typeof r.tenantId&&r.tenantId.length>0){let e=c(r.tenantId);if(!e){let e=_(new I("INVALID_ARGS","Auth hook returned invalid tenantId"));return{ok:!1,statusCode:500,response:ol(t.rpcRequest.id??null,-32e3,e.message,e)}}return{ok:!0,tenantId:e}}return{ok:!0}}async function om(){let e,t=process.env.AGENT_DEVICE_HTTP_AUTH_HOOK;if(!t)return null;let r=process.env.AGENT_DEVICE_HTTP_AUTH_EXPORT||"default",i=n.isAbsolute(t)?t:n.resolve(t);try{e=await import(g(i).href)}catch(e){throw new I("COMMAND_FAILED","Failed to load AGENT_DEVICE_HTTP_AUTH_HOOK module",{hookPath:i,error:e instanceof Error?e.message:String(e)})}let a=e[r];if("function"!=typeof a)throw new I("INVALID_ARGS",`Auth hook export ${r} is not a function`,{hookPath:i,exportName:r});return a}async function oh(e){let t=await om(),{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||od(i,ol(null,-32700,"Parse error"),400)}),e.on("end",async()=>{let a;try{a=JSON.parse(n)}catch{od(i,ol(null,-32700,"Parse error"),400);return}if("2.0"!==a.jsonrpc||"string"!=typeof a.method)return void od(i,ol(a.id??null,-32600,"Invalid Request"),400);if(!os.has(a.method))return void od(i,ol(a.id??null,-32601,`Method not found: ${a.method}`),404);if(!a.params||"object"!=typeof a.params)return void od(i,ol(a.id??null,-32602,"Invalid params"),400);try{var o;let n=a.params,s=function(e,t,r){if(oa.has(e))return{token:oc(t,r),session:t.session??"default",command:t.command??"",positionals:Array.isArray(t.positionals)?t.positionals:[],flags:t.flags,meta:t.meta};let i=oo[e];if(i){let e;return{token:oc(t,r),session:op(t,"session")??"default",command:i,positionals:[],meta:{tenantId:op(t,"tenantId")??op(t,"tenant"),runId:op(t,"runId"),leaseId:op(t,"leaseId"),leaseTtlMs:(e=t.ttlMs,Number.isInteger(e)?Number(e):void 0),leaseBackend:op(t,"backend")}}}throw new I("INVALID_ARGS",`Method not found: ${e}`)}(a.method,n,e.headers);if(o=a.method,oa.has(o)&&("string"!=typeof s.command||0===s.command.length))return void od(i,ol(a.id??null,-32602,"Invalid params: command is required"),400);let l=await of(t,{headers:e.headers,rpcRequest:a,daemonRequest:s});if(!l.ok)return void od(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 od(i,{jsonrpc:"2.0",id:a.id??null,result:d});od(i,ol(a.id??null,-32e3,d.error.message,d.error),ou(d.error.code))}catch(t){let e=_(t);od(i,ol(a.id??null,-32e3,e.message,e),ou(e.code))}})})}function ow(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}function og(e){if(!e)return;let t=e.trim();if(t&&/^[a-f0-9]{16,128}$/i.test(t))return t.toLowerCase()}function oI(e){let t=(e??"").trim().toLowerCase();if(!t||"ios-simulator"===t)return"ios-simulator";throw new I("INVALID_ARGS",`Unsupported lease backend: ${e??""}`)}class ov{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=oI(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");let i=ow(e.runId);if(!i)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");this.cleanupExpiredLeases();let n=this.resolveLeaseTtlMs(e.ttlMs),a=this.bindingKey(r,i,t),o=this.runBindings.get(a);if(o){let e=this.leases.get(o);if(e)return this.refreshLease(e,n);this.runBindings.delete(a)}this.enforceCapacity(t);let s=this.now(),l={leaseId:f.randomBytes(16).toString("hex"),tenantId:r,runId:i,backend:t,createdAt:s,heartbeatAt:s,expiresAt:s+n};return this.leases.set(l.leaseId,l),this.runBindings.set(a,l.leaseId),{...l}}heartbeatLease(e){let t=og(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);if(!r)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});this.assertOptionalScopeMatch(r,e.tenantId,e.runId);let i=this.resolveLeaseTtlMs(e.ttlMs);return this.refreshLease(r,i)}releaseLease(e){let t=og(e.leaseId);if(!t)throw new I("INVALID_ARGS","Invalid lease id.");this.cleanupExpiredLeases();let r=this.leases.get(t);return r?(this.assertOptionalScopeMatch(r,e.tenantId,e.runId),this.leases.delete(t),this.runBindings.delete(this.bindingKey(r.tenantId,r.runId,r.backend)),{released:!0}):{released:!1}}assertLeaseAdmission(e){let t=oI(e.backend),r=c(e.tenantId);if(!r)throw new I("INVALID_ARGS","tenant isolation requires tenant id.");let i=ow(e.runId);if(!i)throw new I("INVALID_ARGS","tenant isolation requires run id.");let n=og(e.leaseId);if(!n)throw new I("INVALID_ARGS","tenant isolation requires lease id.");this.cleanupExpiredLeases();let a=this.leases.get(n);if(!a)throw new I("UNAUTHORIZED","Lease is not active",{reason:"LEASE_NOT_FOUND"});if(a.backend!==t||a.tenantId!==r||a.runId!==i)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}listActiveLeases(){return this.cleanupExpiredLeases(),Array.from(this.leases.values()).map(e=>({...e}))}cleanupExpiredLeases(){let e=this.now();for(let t of this.leases.values())t.expiresAt>e||(this.leases.delete(t.leaseId),this.runBindings.delete(this.bindingKey(t.tenantId,t.runId,t.backend)))}enforceCapacity(e){if("ios-simulator"!==e||this.maxActiveSimulatorLeases<=0)return;let t=Array.from(this.leases.values()).filter(e=>"ios-simulator"===e.backend).length;if(!(t<this.maxActiveSimulatorLeases))throw new I("COMMAND_FAILED","No simulator lease capacity available",{reason:"LEASE_CAPACITY_EXCEEDED",activeLeases:t,maxActiveLeases:this.maxActiveSimulatorLeases,backend:e,hint:"Retry after releasing another simulator lease."})}resolveLeaseTtlMs(e){if(!Number.isInteger(e))return this.defaultLeaseTtlMs;let t=Number(e);if(t<this.minLeaseTtlMs||t>this.maxLeaseTtlMs)throw new I("INVALID_ARGS",`Lease ttlMs must be between ${this.minLeaseTtlMs} and ${this.maxLeaseTtlMs}.`);return t}refreshLease(e,t){let r=this.now(),i={...e,heartbeatAt:r,expiresAt:r+t};return this.leases.set(i.leaseId,i),this.runBindings.set(this.bindingKey(i.tenantId,i.runId,i.backend),i.leaseId),{...i}}bindingKey(e,t,r){return`${e}:${t}:${r}`}assertOptionalScopeMatch(e,t,r){let i=c(t),n=ow(r);if(t&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(r&&!n)throw new I("INVALID_ARGS","Invalid run id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if(i&&e.tenantId!==i||n&&e.runId!==n)throw new I("UNAUTHORIZED","Lease does not match tenant/run scope",{reason:"LEASE_SCOPE_MISMATCH"})}}let{baseDir:oA,infoPath:oy,lockPath:oN,logPath:oS,sessionsDir:o_}=G(process.env.AGENT_DEVICE_STATE_DIR),ob=U(process.env.AGENT_DEVICE_DAEMON_SERVER_MODE);var oD=o_;if(R.existsSync(oD))for(let e of R.readdirSync(oD,{withFileTypes:!0})){if(!e.isDirectory())continue;let t=n.join(oD,e.name,"app-log.pid");if(R.existsSync(t))try{let e=function(e){let t=e.trim();if(!t)return null;if(/^\d+$/.test(t))return{pid:Number.parseInt(t,10)};try{let e=JSON.parse(t);if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}(R.readFileSync(t,"utf8"));if(e&&function(e){let t,r=T(e.pid);if(!r||e.startTime&&r!==e.startTime)return!1;let i=a(e.pid);return!!i&&!!((t=i.toLowerCase().replaceAll("\\","/")).includes("log stream")||t.includes("logcat")||t.includes("devicectl device log stream"))&&(!e.command||i===e.command)}(e))try{process.kill(e.pid,"SIGTERM")}catch{}}catch{}finally{nC(t)}}let oE=new i2(o_),oO=new ov({maxActiveSimulatorLeases:oG(process.env.AGENT_DEVICE_MAX_SIMULATOR_LEASES),defaultLeaseTtlMs:oG(process.env.AGENT_DEVICE_LEASE_TTL_MS),minLeaseTtlMs:oG(process.env.AGENT_DEVICE_LEASE_MIN_TTL_MS),maxLeaseTtlMs:oG(process.env.AGENT_DEVICE_LEASE_MAX_TTL_MS)}),ok=D(),oM=f.randomBytes(24).toString("hex"),oL=new Set(["session_list","devices","ensure-simulator"]),ox=new Set(["session_list","devices","ensure-simulator","lease_allocate","lease_heartbeat","lease_release"]),oC=T(process.pid)??void 0,oT=function(){let e=process.argv[1];if(!e)return"unknown";try{let t=R.statSync(e),r=E(),i=n.relative(r,e)||e;return`${i}:${t.size}:${Math.trunc(t.mtimeMs)}`}catch{return"unknown"}}();function oR(e,t,r){let i=O().requestId;return{...i3(oS,e,t,r,i),requestId:i}}async function oP(e){var t;let r="click"===(t=e).command?{...t,command:"press"}:t,i=!!(r.meta?.debug||r.flags?.verbose);return await P({session:r.session,requestId:r.meta?.requestId,command:r.command,debug:i,logPath:oS},async()=>{if(r.token!==oM)return{ok:!1,error:_(new I("UNAUTHORIZED","Invalid token"))};try{let e=function(e){let t=b(e.meta?.sessionIsolation??e.flags?.sessionIsolation),r=e.meta?.tenantId??e.flags?.tenant,i=c(r);if(r&&!i)throw new I("INVALID_ARGS","Invalid tenant id. Use 1-128 chars: letters, numbers, dot, underscore, hyphen.");if("tenant"!==t)return e;if(!i)throw new I("INVALID_ARGS","session isolation mode tenant requires --tenant (or meta.tenantId).");return{...e,session:`${i}:${e.session||"default"}`,meta:{...e.meta,tenantId:i,sessionIsolation:t}}}(r);M({level:"info",phase:"request_start",data:{session:e.session,command:e.command,tenant:e.meta?.tenantId,isolation:e.meta?.sessionIsolation}});let t=e.command,i=oi(e);ox.has(t)||e.meta?.sessionIsolation!=="tenant"||oO.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,oE),a=oE.get(n);a&&!oL.has(t)&&function(e,t){if(!t)return;let r=[],i=e.device,n=rw(t.platform);if(n&&n!==i.platform&&r.push(`--platform=${t.platform}`),t.target&&t.target!==(i.target??"mobile")&&r.push(`--target=${t.target}`),t.udid&&("ios"!==i.platform||t.udid!==i.id)&&r.push(`--udid=${t.udid}`),t.serial&&("android"!==i.platform||t.serial!==i.id)&&r.push(`--serial=${t.serial}`),t.device&&t.device.trim().toLowerCase()!==i.name.trim().toLowerCase()&&r.push(`--device=${t.device}`),t.iosSimulatorDeviceSet){let e=t.iosSimulatorDeviceSet.trim(),n=i.simulatorSetPath?.trim();("ios"!==i.platform||"simulator"!==i.kind||e!==n)&&r.push(`--ios-simulator-device-set=${t.iosSimulatorDeviceSet}`)}if(t.androidDeviceAllowlist){let e=ed(t.androidDeviceAllowlist);"android"===i.platform&&e.has(i.id)||r.push(`--android-device-allowlist=${t.androidDeviceAllowlist}`)}if(0!==r.length){var a;let t,i,n;throw new I("INVALID_ARGS",`Session "${e.name}" is bound to ${(t=(a=e).device.platform,i=a.device.name.trim(),n=a.device.id,`${t} device "${i}" (${n})`)} and cannot be used with ${r.join(", ")}. Use a different --session name or close this session first.`)}}(a,e.flags);let o=await on({req:e,leaseRegistry:oO});if(o)return o$(o);let s=await aC({req:e,sessionName:n,logPath:oS,sessionStore:oE,invoke:oP});if(s)return o$(s);let l=await aq({req:e,sessionName:n,logPath:oS,sessionStore:oE});if(l)return o$(l);let d=await a3({req:e,sessionName:n,sessionStore:oE,logPath:oS});if(d)return o$(d);let u=await aQ({req:e,sessionName:n,logPath:oS,sessionStore:oE,invoke:oP});if(u)return o$(u);let p=await a6({req:e,sessionName:n,sessionStore:oE,contextFromFlags:oR});if(p)return o$(p);let f=oE.get(n);if(!f)return o$({ok:!1,error:{code:"SESSION_NOT_FOUND",message:"No active session. Run open first."}});if(!iH(t,f.device))return o$({ok:!1,error:{code:"UNSUPPORTED_OPERATION",message:`${t} is not supported on this device`}});let m=await iq(f.device,t,e.positionals??[],e.flags?.out,{...oR(e.flags,f.appBundleId,f.trace?.outPath)});return oE.recordAction(f,{command:t,positionals:e.positionals??[],flags:e.flags??{},result:m??{}}),o$({ok:!0,data:m??{}})}catch(r){M({level:"error",phase:"request_failed",data:{error:r instanceof Error?r.message:String(r)}});let e=O(),t=$({force:!0})??void 0;return{ok:!1,error:_(r,{diagnosticId:e.diagnosticId,logPath:t})}}})}function o$(e){let t=O();if(!e.ok){M({level:"error",phase:"request_failed",data:{code:e.error.code,message:e.error.message}});let r=$({force:!0})??void 0;return{ok:!1,error:_(new I(e.error.code,e.error.message,{...e.error.details??{},hint:e.error.hint,diagnosticId:e.error.diagnosticId,logPath:e.error.logPath}),{diagnosticId:t.diagnosticId,logPath:r})}}return M({level:"info",phase:"request_success"}),$(),e}function oF(){R.existsSync(oy)&&R.unlinkSync(oy)}function oV(){if(!R.existsSync(oN))return null;try{let e=JSON.parse(R.readFileSync(oN,"utf8"));if(!Number.isInteger(e.pid)||e.pid<=0)return null;return e}catch{return null}}function oU(){let e=oV();if(!e||e.pid===process.pid)try{R.existsSync(oN)&&R.unlinkSync(oN)}catch{}}function oG(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(oA)||R.mkdirSync(oA,{recursive:!0});let e=JSON.stringify({pid:process.pid,version:ok,startedAt:Date.now(),processStartTime:oC},null,2),t=()=>{try{return R.writeFileSync(oN,e,{flag:"wx",mode:384}),!0}catch(e){if("EEXIST"===e.code)return!1;throw e}};if(t())return!0;let r=oV();if(r?.pid&&r.pid!==process.pid&&s(r.pid,r.processStartTime))return!1;try{R.unlinkSync(oN)}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"===ob||"dual"===ob){let t=V.createServer(e=>{let t="",r=0,i=new Set,n=!1,a=()=>{if(!n&&0!==r){for(let e of(n=!0,i))e&&t3.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 rP(),!(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),t4(s)))throw new I("COMMAND_FAILED","request canceled");n=await oP(e)}catch(e){n={ok:!1,error:_(e)}}finally{if(r-=1,s){var o;i.delete(s),(o=s)&&t3.delete(o)}}e.destroyed||e.write(`${JSON.stringify(n)}
|
|
34
|
+
`),a=t.indexOf("\n")}})});r.push(t),e=await new Promise((e,r)=>{t.once("error",r),t.listen(0,"127.0.0.1",()=>{t.off("error",r);let i=t.address();"object"==typeof i&&i?.port?e(i.port):r(new I("COMMAND_FAILED","Failed to bind socket server"))})})}if("http"===ob||"dual"===ob){let e=await oh({handleRequest:oP});r.push(e),t=await new Promise((t,r)=>{e.once("error",r),e.listen(0,"127.0.0.1",()=>{e.off("error",r);let i=e.address();"object"==typeof i&&i?.port?t(i.port):r(new I("COMMAND_FAILED","Failed to bind HTTP server"))})})}i={socketPort:e,httpPort:t},R.existsSync(oA)||R.mkdirSync(oA,{recursive:!0}),R.writeFileSync(oS,""),n=i.httpPort&&i.socketPort?"dual":i.httpPort?"http":"socket",R.writeFileSync(oy,JSON.stringify({port:i.socketPort,httpPort:i.httpPort,transport:n,token:oM,pid:process.pid,version:ok,codeSignature:oT,processStartTime:oC,stateDir:oA},null,2),{mode:384}),e&&process.stdout.write(`AGENT_DEVICE_DAEMON_PORT=${e}
|
|
31
35
|
`),t&&process.stdout.write(`AGENT_DEVICE_DAEMON_HTTP_PORT=${t}
|
|
32
36
|
`)}catch(t){let e=w(t);for(let t of(process.stderr.write(`Daemon error: ${e.message}
|
|
33
|
-
`),r))try{t.close(()=>{})}catch{}
|
|
37
|
+
`),r))try{t.close(()=>{})}catch{}oF(),oU(),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(),oE.toArray()))oE.writeSessionLog(e);await r$(),oF(),oU(),process.exit(0)}};process.on("SIGINT",()=>{o()}),process.on("SIGTERM",()=>{o()}),process.on("SIGHUP",()=>{o()}),process.on("uncaughtException",e=>{let t=e instanceof I?e:w(e);process.stderr.write(`Daemon error: ${t.message}
|
|
34
38
|
`),o()})})();
|