agent-device 0.18.1 → 0.18.3

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.
Files changed (50) hide show
  1. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.18.1.apk → agent-device-android-multitouch-helper-0.18.3.apk} +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.18.3.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.18.1.manifest.json → agent-device-android-multitouch-helper-0.18.3.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.18.1.apk → agent-device-android-snapshot-helper-0.18.3.apk} +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.18.3.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.18.1.manifest.json → agent-device-android-snapshot-helper-0.18.3.manifest.json} +6 -6
  7. package/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +2 -1
  8. package/dist/src/1986.js +1 -1
  9. package/dist/src/2948.js +16 -16
  10. package/dist/src/3340.js +8 -8
  11. package/dist/src/4428.js +3 -3
  12. package/dist/src/495.js +5 -5
  13. package/dist/src/6849.js +1 -1
  14. package/dist/src/7871.js +1 -1
  15. package/dist/src/8184.js +1 -1
  16. package/dist/src/8414.js +2 -2
  17. package/dist/src/8875.js +4 -1
  18. package/dist/src/9581.js +3 -3
  19. package/dist/src/9624.js +1 -1
  20. package/dist/src/9722.js +38 -37
  21. package/dist/src/android.js +1 -1
  22. package/dist/src/apps.js +9 -9
  23. package/dist/src/audio-probe.js +1 -1
  24. package/dist/src/batch.d.ts +1 -1
  25. package/dist/src/cli-help.js +15 -8
  26. package/dist/src/cli.js +23 -23
  27. package/dist/src/contracts.d.ts +1 -1
  28. package/dist/src/devices.js +1 -1
  29. package/dist/src/devices~1.js +1 -1
  30. package/dist/src/index.d.ts +61 -16
  31. package/dist/src/input-actions.js +1 -1
  32. package/dist/src/interaction.js +1 -1
  33. package/dist/src/interactor.js +1 -1
  34. package/dist/src/internal/bin.js +1 -1
  35. package/dist/src/lease.js +1 -1
  36. package/dist/src/linux.js +1 -1
  37. package/dist/src/record-trace-recording.js +3 -3
  38. package/dist/src/remote-config.d.ts +1 -1
  39. package/dist/src/selector-runtime.js +1 -1
  40. package/dist/src/selectors.d.ts +8 -4
  41. package/dist/src/session.js +11 -11
  42. package/dist/src/simulator.js +2 -2
  43. package/dist/src/snapshot.js +2 -2
  44. package/dist/src/web.js +1 -1
  45. package/package.json +1 -1
  46. package/server.json +2 -2
  47. package/skills/agent-device/SKILL.md +2 -0
  48. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.18.1.apk.sha256 +0 -1
  49. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.18.1.apk.sha256 +0 -1
  50. package/dist/src/432.js +0 -4
@@ -1,4 +1,4 @@
1
- import e from"node:crypto";import t from"node:fs/promises";import r from"node:path";import{promises as a}from"node:fs";import{normalizeError as i,AppError as n}from"./485.js";import{withDiagnosticTimer as o,emitDiagnostic as s}from"./432.js";import{readVersion as d,findProjectRoot as l}from"./1404.js";import{openAndroidDevice as u,runAndroidAdb as c,resolveAndroidApp as p,resolveAndroidTouchInjector as m,closeAndroidApp as h,openAndroidApp as f,resolveAndroidAdbProvider as w,resolveAndroidAdbExecutor as _,installAndroidAdbPackage as A}from"./3340.js";import{appSwitcherAndroid as g,homeAndroid as y,scrollAndroid as N,longPressAndroid as v,typeAndroid as I,getAndroidScreenSize as M,pressAndroid as C,focusAndroid as k,swipeAndroid as x,rotateAndroid as S,fillAndroid as D,backAndroid as E}from"./input-actions.js";import{parseInstrumentationRecords as R,readAndroidHelperManifestInteger as b,readInstrumentationResultNumber as F,snapshotAndroid as L,readAndroidHelperManifestLiteral as O}from"./9722.js";import{requireLocationCoordinates as P,snapshotCaptureAnnotationsFrom as T}from"./2948.js";import{parseAppearanceAction as U,summarizeCommandAttemptFailures as $,parseSettingState as G,parsePermissionTarget as K,parsePermissionAction as V}from"./8225.js";import{writeAndroidClipboardText as H,readAndroidClipboardText as B}from"./9624.js";import{sleep as q}from"./5560.js";let j="android-multitouch-helper-v1",z="ANDROID_MULTITOUCH_HELPER_NO_FINAL_RESULT",J="ANDROID_MULTITOUCH_HELPER_REPORTED_FAILURE";async function X(e,t){let r=await et(e,{kind:"swipe",...t});if(r)return r;try{return await er(e,{kind:"swipe",...t})}catch(r){return s({level:"warn",phase:"android_swipe_helper_fallback",data:{error:i(r).message}}),await x(e,t.x1,t.y1,t.x2,t.y2,t.durationMs),{backend:"adb-input-swipe-fallback"}}}async function Q(e,t){if(!Number.isFinite(t.scale)||t.scale<=0)throw new n("INVALID_ARGS","gesture pinch requires scale > 0");let r=await Z(e,t.x,t.y);return await ee(e,{kind:"pinch",x:r.x,y:r.y,scale:t.scale,durationMs:t.durationMs})}async function W(e,t){if(!Number.isFinite(t.degrees))throw new n("INVALID_ARGS","gesture rotate requires finite degrees");if(void 0!==t.velocity&&(!Number.isFinite(t.velocity)||0===t.velocity))throw new n("INVALID_ARGS","gesture rotate velocity must be a non-zero number");let r=await Z(e,t.x,t.y),a=t.degrees;return await ee(e,{kind:"rotate",x:r.x,y:r.y,degrees:a,durationMs:t.durationMs})}async function Y(e,t){if(!Number.isFinite(t.scale)||t.scale<=0)throw new n("INVALID_ARGS","gesture transform requires scale > 0");if(!Number.isFinite(t.degrees))throw new n("INVALID_ARGS","gesture transform requires finite degrees");if(![t.x,t.y,t.dx,t.dy].every(Number.isFinite))throw new n("INVALID_ARGS","gesture transform requires finite x y dx dy");return await ee(e,{kind:"transform",x:t.x,y:t.y,dx:t.dx,dy:t.dy,scale:t.scale,degrees:t.degrees,durationMs:t.durationMs})}async function Z(e,t,r){if(void 0!==t&&void 0!==r)return{x:t,y:r};let a=await M(e);return{x:Math.round(a.width/2),y:Math.round(a.height/2)}}async function ee(e,t){let r=await et(e,t);return r||await er(e,t)}async function et(e,t){let r=m(e);if(r)return{backend:"provider-native-touch",...await r(t)??{}}}async function er(e,t){let r=_(e),a=await ei(),i=w(e),n=await o("android_multitouch_helper_install",async()=>{var t;return await en({adb:r,adbProvider:i,artifact:a,deviceKey:(t=e,`${t.platform}:${t.id}`)})},{packageName:a.manifest.packageName,versionCode:a.manifest.versionCode});s({phase:"android_multitouch_helper_install_decision",data:n});let d=await o("android_multitouch_helper_gesture",async()=>await ea({adb:r,request:function(e){var t;let r=Math.round(void 0!==(t=e).durationMs?t.durationMs:"swipe"===t.kind||"pinch"===t.kind?300:Math.min(Math.max(300,16*Math.ceil(Math.abs(t.degrees)/3)),2400));switch(e.kind){case"swipe":return{kind:"swipe",x1:Math.round(e.x1),y1:Math.round(e.y1),x2:Math.round(e.x2),y2:Math.round(e.y2),durationMs:r};case"pinch":return{kind:"pinch",x:Math.round(e.x),y:Math.round(e.y),scale:e.scale,radius:160,durationMs:r};case"rotate":return{kind:"rotate",x:Math.round(e.x),y:Math.round(e.y),degrees:e.degrees,radius:160,durationMs:r};case"transform":return{kind:"transform",x:Math.round(e.x),y:Math.round(e.y),dx:Math.round(e.dx),dy:Math.round(e.dy),scale:e.scale,degrees:e.degrees,durationMs:r}}}(t),packageName:a.manifest.packageName,instrumentationRunner:a.manifest.instrumentationRunner}),{packageName:a.manifest.packageName,version:a.manifest.version});return{backend:"android-multitouch-helper",helperVersion:a.manifest.version,installReason:n.reason,...d}}async function ea(e){let t,r=Buffer.from(JSON.stringify({protocol:j,...e.request})).toString("base64"),a=await e.adb(["shell","am","instrument","-w","-e","payloadBase64",r,e.instrumentationRunner],{allowFailure:!0,timeoutMs:45e3});try{t=function(e){let t=R(e).results.find(e=>e.agentDeviceProtocol===j);if(!t)throw new n(z,"Android multi-touch helper did not return a final result");if("true"!==t.ok){var r;throw new n(J,(r=t).message&&"null"!==r.message?r.message:r.errorType||"Android multi-touch helper returned an error",{errorType:t.errorType,helper:t})}return{kind:t.kind,helperApiVersion:t.helperApiVersion,injectedEvents:F(t.injectedEvents),elapsedMs:F(t.elapsedMs)}}(`${a.stdout}
1
+ import e from"node:crypto";import t from"node:fs/promises";import r from"node:path";import{promises as a}from"node:fs";import{normalizeError as i,AppError as n}from"./485.js";import{withDiagnosticTimer as o,emitDiagnostic as s}from"./8875.js";import{readVersion as d,findProjectRoot as l}from"./1404.js";import{openAndroidDevice as u,runAndroidAdb as c,resolveAndroidApp as p,resolveAndroidTouchInjector as m,closeAndroidApp as h,openAndroidApp as f,resolveAndroidAdbProvider as w,resolveAndroidAdbExecutor as _,installAndroidAdbPackage as A}from"./3340.js";import{appSwitcherAndroid as g,homeAndroid as y,scrollAndroid as N,longPressAndroid as v,typeAndroid as I,getAndroidScreenSize as M,pressAndroid as C,focusAndroid as k,swipeAndroid as x,rotateAndroid as S,fillAndroid as D,backAndroid as E}from"./input-actions.js";import{parseInstrumentationRecords as R,readAndroidHelperManifestInteger as b,readInstrumentationResultNumber as F,snapshotAndroid as L,readAndroidHelperManifestLiteral as O}from"./9722.js";import{requireLocationCoordinates as P,snapshotCaptureAnnotationsFrom as T}from"./2948.js";import{parseAppearanceAction as U,summarizeCommandAttemptFailures as $,parseSettingState as G,parsePermissionTarget as K,parsePermissionAction as V}from"./8225.js";import{writeAndroidClipboardText as H,readAndroidClipboardText as B}from"./9624.js";import{sleep as q}from"./5560.js";let j="android-multitouch-helper-v1",z="ANDROID_MULTITOUCH_HELPER_NO_FINAL_RESULT",J="ANDROID_MULTITOUCH_HELPER_REPORTED_FAILURE";async function X(e,t){let r=await et(e,{kind:"swipe",...t});if(r)return r;try{return await er(e,{kind:"swipe",...t})}catch(r){return s({level:"warn",phase:"android_swipe_helper_fallback",data:{error:i(r).message}}),await x(e,t.x1,t.y1,t.x2,t.y2,t.durationMs),{backend:"adb-input-swipe-fallback"}}}async function Q(e,t){if(!Number.isFinite(t.scale)||t.scale<=0)throw new n("INVALID_ARGS","gesture pinch requires scale > 0");let r=await Z(e,t.x,t.y);return await ee(e,{kind:"pinch",x:r.x,y:r.y,scale:t.scale,durationMs:t.durationMs})}async function W(e,t){if(!Number.isFinite(t.degrees))throw new n("INVALID_ARGS","gesture rotate requires finite degrees");if(void 0!==t.velocity&&(!Number.isFinite(t.velocity)||0===t.velocity))throw new n("INVALID_ARGS","gesture rotate velocity must be a non-zero number");let r=await Z(e,t.x,t.y),a=t.degrees;return await ee(e,{kind:"rotate",x:r.x,y:r.y,degrees:a,durationMs:t.durationMs})}async function Y(e,t){if(!Number.isFinite(t.scale)||t.scale<=0)throw new n("INVALID_ARGS","gesture transform requires scale > 0");if(!Number.isFinite(t.degrees))throw new n("INVALID_ARGS","gesture transform requires finite degrees");if(![t.x,t.y,t.dx,t.dy].every(Number.isFinite))throw new n("INVALID_ARGS","gesture transform requires finite x y dx dy");return await ee(e,{kind:"transform",x:t.x,y:t.y,dx:t.dx,dy:t.dy,scale:t.scale,degrees:t.degrees,durationMs:t.durationMs})}async function Z(e,t,r){if(void 0!==t&&void 0!==r)return{x:t,y:r};let a=await M(e);return{x:Math.round(a.width/2),y:Math.round(a.height/2)}}async function ee(e,t){let r=await et(e,t);return r||await er(e,t)}async function et(e,t){let r=m(e);if(r)return{backend:"provider-native-touch",...await r(t)??{}}}async function er(e,t){let r=_(e),a=await ei(),i=w(e),n=await o("android_multitouch_helper_install",async()=>{var t;return await en({adb:r,adbProvider:i,artifact:a,deviceKey:(t=e,`${t.platform}:${t.id}`)})},{packageName:a.manifest.packageName,versionCode:a.manifest.versionCode});s({phase:"android_multitouch_helper_install_decision",data:n});let d=await o("android_multitouch_helper_gesture",async()=>await ea({adb:r,request:function(e){var t;let r=Math.round(void 0!==(t=e).durationMs?t.durationMs:"swipe"===t.kind||"pinch"===t.kind?300:Math.min(Math.max(300,16*Math.ceil(Math.abs(t.degrees)/3)),2400));switch(e.kind){case"swipe":return{kind:"swipe",x1:Math.round(e.x1),y1:Math.round(e.y1),x2:Math.round(e.x2),y2:Math.round(e.y2),durationMs:r};case"pinch":return{kind:"pinch",x:Math.round(e.x),y:Math.round(e.y),scale:e.scale,radius:160,durationMs:r};case"rotate":return{kind:"rotate",x:Math.round(e.x),y:Math.round(e.y),degrees:e.degrees,radius:160,durationMs:r};case"transform":return{kind:"transform",x:Math.round(e.x),y:Math.round(e.y),dx:Math.round(e.dx),dy:Math.round(e.dy),scale:e.scale,degrees:e.degrees,durationMs:r}}}(t),packageName:a.manifest.packageName,instrumentationRunner:a.manifest.instrumentationRunner}),{packageName:a.manifest.packageName,version:a.manifest.version});return{backend:"android-multitouch-helper",helperVersion:a.manifest.version,installReason:n.reason,...d}}async function ea(e){let t,r=Buffer.from(JSON.stringify({protocol:j,...e.request})).toString("base64"),a=await e.adb(["shell","am","instrument","-w","-e","payloadBase64",r,e.instrumentationRunner],{allowFailure:!0,timeoutMs:45e3});try{t=function(e){let t=R(e).results.find(e=>e.agentDeviceProtocol===j);if(!t)throw new n(z,"Android multi-touch helper did not return a final result");if("true"!==t.ok){var r;throw new n(J,(r=t).message&&"null"!==r.message?r.message:r.errorType||"Android multi-touch helper returned an error",{errorType:t.errorType,helper:t})}return{kind:t.kind,helperApiVersion:t.helperApiVersion,injectedEvents:F(t.injectedEvents),elapsedMs:F(t.elapsedMs)}}(`${a.stdout}
2
2
  ${a.stderr}`)}catch(e){if(e instanceof n){if(e.code===J)throw new n("COMMAND_FAILED",e.message,e.details,e);if(e.code!==z)throw e}throw new n("COMMAND_FAILED",0===a.exitCode?"Android multi-touch helper output could not be parsed":"Android multi-touch helper failed before returning parseable output",{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode},e)}if(0!==a.exitCode)throw new n("COMMAND_FAILED","Android multi-touch helper failed",{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode,helper:t});return t}async function ei(){let e=d(),a=r.join(l(),"android-multitouch-helper","dist"),o=r.join(a,`agent-device-android-multitouch-helper-${e}.manifest.json`);try{let e=function(e){var t,r;if(!e||"object"!=typeof e||Array.isArray(e))throw new n("INVALID_ARGS","Android multi-touch helper manifest must be an object.");return{name:ec(e.name,"name","android-multitouch-helper"),version:eu(e.version,"version"),assetName:eu(e.assetName,"assetName"),sha256:function(e){let t=eu(e,"sha256").trim().toLowerCase();if(64!==t.length||!/^[0-9a-f]+$/.test(t))throw new n("INVALID_ARGS","Android multi-touch helper manifest sha256 must be a 64-character hex string.");return t}(e.sha256),packageName:ec(e.packageName,"packageName","com.callstack.agentdevice.multitouchhelper"),versionCode:(t=e.versionCode,r="versionCode",b(t,r,"multi-touch helper")),instrumentationRunner:ec(e.instrumentationRunner,"instrumentationRunner","com.callstack.agentdevice.multitouchhelper/.MultiTouchInstrumentation"),statusProtocol:ec(e.statusProtocol,"statusProtocol",j)}}(JSON.parse(await t.readFile(o,"utf8"))),i=r.join(a,e.assetName);return await t.access(i),{apkPath:i,manifest:e}}catch(e){throw new n("UNSUPPORTED_OPERATION","Android touch gestures require the bundled Android touch helper artifact, but it was not found or could not be read",{manifestPath:o,error:i(e).message},e)}}async function en(e){let{adb:t,artifact:r}=e,a=r.manifest.packageName,i=r.manifest.versionCode,o=`${e.deviceKey}\0${a}\0${i}`;if(eo.has(o))return{packageName:a,versionCode:i,installed:!1,reason:"current"};let s=await es(t,a);if(void 0!==s&&s>=i)return eo.add(o),{packageName:a,versionCode:i,installedVersionCode:s,installed:!1,reason:"current"};await ed(r);let d=await A(r.apkPath,{provider:e.adbProvider,replace:!0,allowTestPackages:!0,allowFailure:!0,timeoutMs:3e4});if(0!==d.exitCode)throw new n("COMMAND_FAILED","Failed to install Android multi-touch helper",{packageName:a,versionCode:i,stdout:d.stdout,stderr:d.stderr,exitCode:d.exitCode});return eo.add(o),{packageName:a,versionCode:i,installedVersionCode:s,installed:!0,reason:void 0===s?"missing":"outdated"}}let eo=new Set;async function es(e,t){let r=await e(["shell","cmd","package","list","packages","--show-versioncode",t],{allowFailure:!0,timeoutMs:5e3});if(0!==r.exitCode)return;let a=RegExp(`package:${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(?:\\s|$).*versionCode:(\\d+)`).exec(`${r.stdout}
3
3
  ${r.stderr}`);return a?Number(a[1]):void 0}async function ed(e){let t=await el(e.apkPath);if(t!==e.manifest.sha256)throw new n("COMMAND_FAILED","Android multi-touch helper APK checksum mismatch",{apkPath:e.apkPath,expectedSha256:e.manifest.sha256,actualSha256:t})}async function el(r){let a=e.createHash("sha256");return a.update(await t.readFile(r)),a.digest("hex")}function eu(e,t){if("string"!=typeof e||0===e.length)throw new n("INVALID_ARGS",`Android multi-touch helper manifest ${t} is required.`);return e}function ec(e,t,r){return O(e,t,r,"multi-touch helper")}let ep=["window_animation_scale","transition_animation_scale","animator_duration_scale"];async function em(e,t,r,a,i){switch(t.toLowerCase()){case"wifi":{let t=G(r);await c(e,["shell","svc","wifi",t?"enable":"disable"]);return}case"airplane":{let t=G(r);await c(e,["shell","settings","put","global","airplane_mode_on",t?"1":"0"]),await c(e,["shell","am","broadcast","-a","android.intent.action.AIRPLANE_MODE","--ez","state",t?"true":"false"]);return}case"location":{if("set"===r.toLowerCase()){if("emulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Android precise location coordinates are supported only on emulators.",{deviceId:e.id,hint:"Use an Android emulator for adb emu geo fix, or configure location through device/provider tooling."});let{latitude:t,longitude:r}=P(i);return await c(e,["emu","geo","fix",String(r),String(t)]),{latitude:t,longitude:r}}let t=G(r);await c(e,["shell","settings","put","secure","location_mode",t?"3":"0"]);return}case"animations":{let t=G(r)?"1":"0";for(let r of ep)await c(e,["shell","settings","put","global",r,t]);return{scale:t,keys:[...ep]}}case"appearance":{let t=await ef(e,r);await c(e,["shell","cmd","uimode","night","dark"===t?"yes":"no"]);return}case"clear-app-state":{if("clear"!==r.toLowerCase())throw new n("INVALID_ARGS","settings clear-app-state only supports clear.");if(!a)throw new n("INVALID_ARGS","settings clear-app-state requires an app id or an active app session.");let t=await p(e,a);if("intent"===t.type)throw new n("INVALID_ARGS","settings clear-app-state requires a package name, not an intent.");await c(e,["shell","am","force-stop",t.value],{allowFailure:!0});let i=await c(e,["shell","pm","clear",t.value],{allowFailure:!0});if(0!==i.exitCode||!/\bSuccess\b/i.test(i.stdout))throw new n("COMMAND_FAILED",`Failed to clear Android app data for ${t.value}`,{package:t.value,stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode});return{package:t.value,cleared:!0}}case"fingerprint":{let t=function(e){let t=e.trim().toLowerCase();if("match"===t)return"match";if("nonmatch"===t)return"nonmatch";throw new n("INVALID_ARGS",`Invalid fingerprint state: ${e}. Use match|nonmatch.`)}(r);await eh(e,t);return}case"permission":{if(!a)throw new n("INVALID_ARGS","permission setting requires an active app in session");let t=V(r),o=function(e,t){let r=K(e);if(t?.trim())throw new n("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 n("INVALID_ARGS",`Unsupported permission target on Android: ${e}. Use camera|microphone|photos|contacts|notifications.`)}(i?.permissionTarget,i?.permissionMode);if("notifications"===o.kind)return void await e_(e,a,t,o);let s="grant"===t?"grant":"revoke";if("photos"===o.type)return void await ew(e,a,s);await c(e,["shell","pm",s,a,o.value]);return}default:throw new n("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function eh(e,t){var r;let a,i,o=(r=e,i=[["shell","cmd","fingerprint","touch",a="match"===t?"1":"9999"],["shell","cmd","fingerprint","finger",a]],"emulator"===r.kind&&i.push(["emu","finger","touch",a]),i),s=[];for(let t of o){let r=await c(e,t,{allowFailure:!0});if(0===r.exitCode)return;s.push({args:t,stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode})}let d=$(s);if(s.length>0&&s.every(e=>{var t,r;let a;return t=e.stdout,r=e.stderr,(a=`${t}
4
4
  ${r}`.toLowerCase()).includes("unknown command")||a.includes("can't find service: fingerprint")||a.includes("service fingerprint was not found")||a.includes("fingerprint cmd unavailable")||a.includes("emu command is not supported")||a.includes("emulator console is not running")||a.includes("fingerprint")&&a.includes("not found")}))throw new n("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:d});throw new n("COMMAND_FAILED","Failed to simulate Android fingerprint.",{deviceId:e.id,action:t,attempts:d})}async function ef(e,t){let r=U(t);if("toggle"!==r)return r;let a=await c(e,["shell","cmd","uimode","night"],{allowFailure:!0});if(0!==a.exitCode)throw new n("COMMAND_FAILED","Failed to read current Android appearance",{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});let i=function(e,t){let r=/night mode:\s*(yes|no|auto)\b/i.exec(`${e}
package/dist/src/apps.js CHANGED
@@ -1,11 +1,11 @@
1
- let e;import{promises as t}from"node:fs";import i from"node:os";import a from"node:path";import{fileURLToPath as r}from"node:url";import{AppError as n}from"./485.js";import{runXcrun as o,resolveIosDevicectlHint as l,LAUNCH_CONSOLE_DIRECT_APP_ONLY_MESSAGE as s,resolveAppleToolProvider as d,runSimctlForDevice as u,IOS_DEVICECTL_DEFAULT_HINT as c,readInfoPlistString as p,buildSimctlArgsForDevice as f,runAppleRunnerCommand as w,runMacOsPermissionAction as m,runIosDevicectl as h,filterAppleAppsByBundlePrefix as y,runAppleToolCommand as A,listIosDeviceApps as I,quitMacOsApp as _,LAUNCH_CONSOLE_IOS_SIMULATOR_ONLY_MESSAGE as C,IOS_RUNNER_CONTAINER_BUNDLE_IDS as v}from"./9722.js";import{runCmd as g}from"./8875.js";import{materializeInstallablePath as b,isTrustedInstallSourceUrl as N}from"./5484.js";import{parseAppearanceAction as S,summarizeCommandAttemptFailures as L,parseSettingState as D,parsePermissionTarget as M,parsePermissionAction as O}from"./8225.js";import{isWebUrl as P,createAppResolutionCache as F,isDeepLinkTarget as R,resolveIosSimulatorDeviceSetPath as x,resolveIosDeviceDeepLinkBundleId as $,retryWithPolicy as k,Deadline as E}from"./3340.js";import{emitDiagnostic as T}from"./432.js";import{requireSimulatorDevice as U,ensureBootedSimulator as B,getSimulatorState as G}from"./simulator.js";import{getUnsupportedMacOsSettingMessage as V,requireLocationCoordinates as j}from"./2948.js";function W(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let i=String(t.stderr??"").toLowerCase();return i.includes("fbsopenapplicationserviceerrordomain")&&i.includes("the request to open")}async function K(e,t){let i=await o(f(e,["get_app_container",e.id,t]),{allowFailure:!0});if(0!==i.exitCode)return{installed:!1};let a=i.stdout.trim();if(!a)return{installed:!1};let r=await A("plutil",["-extract","CFBundleExecutable","raw","-o","-",`${a}/Info.plist`],{allowFailure:!0});if(0!==r.exitCode||!r.stdout.trim())return{installed:!0};let n=r.stdout.trim(),l=`${a}/${n}`,s=await A("otool",["-l",l],{allowFailure:!0});if(0!==s.exitCode)return{installed:!0};let d=s.stdout.toLowerCase();return{installed:!0,simulatorCompatible:d.includes("iossimulator")||d.includes("platform 7")}}async function H(e,t){let i;if("url"===e.kind&&!N(e.url))throw new n("INVALID_ARGS","iOS install_from_source URL sources are only supported for trusted artifact services such as GitHub Actions and EAS. Use a path source for other hosts.");let a=await b({source:e,isInstallablePath:(e,t)=>t.isDirectory()&&e.toLowerCase().endsWith(".app")||t.isFile()&&e.toLowerCase().endsWith(".ipa"),installableLabel:"iOS installable (.app or .ipa)",allowArchiveExtraction:"url"!==e.kind||N(e.url),signal:t?.signal});try{let e=i=await q(a.installablePath,t),r=await z(e.installPath);return{archivePath:a.archivePath??(a.installablePath.toLowerCase().endsWith(".ipa")?a.installablePath:void 0),installablePath:e.installPath,bundleId:r.bundleId,appName:r.appName,cleanup:async()=>{await e.cleanup(),await a.cleanup()}}}catch(e){try{await i?.cleanup()}finally{await a.cleanup()}throw e}}async function z(e){let t=a.join(e,"Info.plist"),[i,r,n]=await Promise.all([p(t,"CFBundleIdentifier"),p(t,"CFBundleDisplayName"),p(t,"CFBundleName")]);return{bundleId:i,appName:r??n}}async function q(e,r){if(!e.toLowerCase().endsWith(".ipa"))return{installPath:e,cleanup:async()=>{}};let o=await t.mkdtemp(a.join(i.tmpdir(),"agent-device-ios-ipa-")),l=async()=>{await t.rm(o,{recursive:!0,force:!0})};try{await g("unzip",["-q",e,"-d",o]);let i=a.join(o,"Payload"),s=(await t.readdir(i,{withFileTypes:!0}).catch(()=>{throw new n("INVALID_ARGS","Invalid IPA: missing Payload directory")})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(".app")).map(e=>({installPath:a.join(i,e.name),bundleName:e.name.replace(/\.app$/i,"")})),d=s[0];if(void 0!==d&&1===s.length)return{installPath:d.installPath,cleanup:l};if(0===s.length)throw new n("INVALID_ARGS","Invalid IPA: expected at least one .app under Payload, found 0");await J(s);let u=r?.appIdentifierHint?.trim();if(u){let e=function(e,t){let i=t.toLowerCase(),a=e.filter(e=>e.bundleName.toLowerCase()===i);if(1===a.length)return a[0];if(a.length>1)throw new n("INVALID_ARGS",`Invalid IPA: multiple app bundles matched "${t}" by name. Use a bundle id hint instead.`);if(t.includes(".")){let t=e.filter(e=>e.bundleId?.toLowerCase()===i);if(1===t.length)return t[0]}}(s,u);if(e)return{installPath:e.installPath,cleanup:l};throw new n("INVALID_ARGS",`Invalid IPA: found ${s.length} .app bundles under Payload and none matched "${u}". Available bundles: ${s.map(Z).join(", ")}`)}throw new n("INVALID_ARGS",`Invalid IPA: found ${s.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${s.map(Z).join(", ")}`)}catch(e){throw await l(),e}}async function J(e){await Promise.all(e.map(async e=>{if(e.bundleId&&e.appName)return;let t=await z(e.installPath);e.bundleId=e.bundleId??t.bundleId,e.appName=e.appName??t.appName}))}function Z(e){let t=e.bundleId??e.appName;return t?`${e.bundleName}.app (${t})`:`${e.bundleName}.app`}let Q={settings:"com.apple.systempreferences"},X=/^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/,Y={platform:"macos",deviceId:"host",variant:"all"},ee=F();async function et(e){let t=e.trim(),i=Q[t.toLowerCase()];if(i)return i;if(X.test(t))return t;let a=ee.get(Y,t);if(a)return a;let r=(await es("all")).filter(e=>e.name.toLowerCase()===t.toLowerCase()),o=r[0];if(void 0!==o&&1===r.length)return ee.set(Y,t,o.bundleId);if(r.length>1)throw new n("INVALID_ARGS",`Multiple apps matched "${e}"`,{matches:r});throw new n("APP_NOT_INSTALLED",`No app found matching "${e}"`)}async function ei(e,t,i){let a=i?.url?.trim();if(a){if(!R(a))throw new n("INVALID_ARGS","open <app> <url> requires a valid URL target");let e=i?.appBundleId??await et(t);await ed().openBundle(e,a);return}let r=t.trim();if(R(r))return void await ed().openTarget(r);let o=i?.appBundleId??await et(r);await ed().openBundle(o)}async function ea(e,t){let i=await et(t),a=await _(i);if(a.running&&!a.terminated&&!a.forceTerminated)throw new n("COMMAND_FAILED",`Failed to close macOS app ${t}`,{bundleId:i,running:a.running,terminated:a.terminated,forceTerminated:a.forceTerminated})}async function er(){return await ed().readClipboard()}async function en(e){await ed().writeClipboard(e)}async function eo(){return await ed().readDarkMode()}async function el(e){let t=S(e),i="toggle"===t?!await eo():"dark"===t;await ed().setDarkMode(i)}async function es(e){return await ed().listApps(e)}function ed(){let e=d().macosHost;if(!e)throw new n("UNSUPPORTED_OPERATION","macOS host provider is not available");return e}function eu(e){if(!(e instanceof n))return{reason:e instanceof Error?e.message:String(e)};let t=e.details??{},i=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:i}}let ec=["--time","9:41","--dataNetwork","wifi","--wifiMode","active","--wifiBars","3","--batteryState","charged","--batteryLevel","100"],ep={0:"hide",1:"wifi",6:"3g",7:"4g",8:"lte",9:"lte-a",10:"lte+",11:"5g",12:"5g+",13:"5g-uwb",14:"5g-uc"},ef={1:"searching",2:"failed",3:"active"},ew={0:"notSupported",1:"searching",2:"failed",3:"active"},em=new Set;async function eh(e){var t;let i=null,a=!1;if(t=e,em.has(eI(t)))a=!0;else try{i=await e_(e),a=!0}catch(t){eg(e,"snapshot_failed",t)}try{(!a||i)&&await eC(e),await ev(e,ec)}catch(t){eg(e,"prepare_failed",t)}return async()=>{await ey(e,a?i:null)}}async function ey(e,t){var i,a,r;let n;(await eC(e),t)?(await ev(e,(n=[],(i=t).dataNetwork&&n.push("--dataNetwork",i.dataNetwork),i.wifiMode&&n.push("--wifiMode",i.wifiMode),void 0!==i.wifiBars&&("wifi"===i.dataNetwork||i.wifiMode)&&n.push("--wifiBars",i.wifiBars),i.cellularMode&&n.push("--cellularMode",i.cellularMode),void 0!==i.cellularBars&&(i.cellularMode||(a=i.dataNetwork)&&"hide"!==a&&"wifi"!==a||void 0!==i.operatorName)&&n.push("--cellularBars",i.cellularBars),void 0!==i.operatorName&&n.push("--operatorName",i.operatorName),n)),eA(e)):(r=e,em.add(eI(r)))}function eA(e){em.delete(eI(e))}function eI(e){return`${e.platform}:${e.kind}:${e.id}`}async function e_(e){var t;let i=await (t=["status_bar",e.id,"list"],u(e,t,{allowFailure:!0}));if(0!==i.exitCode)throw new n("COMMAND_FAILED","Failed to read simulator status bar overrides",{exitCode:i.exitCode,stdout:i.stdout,stderr:i.stderr});return function(e){let t={};for(let i of e.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&"Current Status Bar Overrides:"!==e&&!/^=+$/.test(e))){let e=/^DataNetworkType:\s+(\d+)$/.exec(i);if(e){let i=Number(e[1]),a=ep[i];if(!a)throw new n("COMMAND_FAILED",`Unsupported simulator data network type: ${i}`);t.dataNetwork=a;continue}let a=/^WiFi Mode:\s+(\d+),\s+WiFi Bars:\s+(\d+)$/.exec(i);if(a){let e=ef[Number(a[1])];e&&(t.wifiMode=e),t.wifiBars=a[2];continue}let r=/^Cell Mode:\s+(\d+),\s+Cell Bars:\s+(\d+)$/.exec(i);if(r){let e=Number(r[1]),i=ew[e];if(!i)throw new n("COMMAND_FAILED",`Unsupported simulator cellular mode: ${e}`);t.cellularMode=i,t.cellularBars=r[2];continue}let o=/^Operator Name:\s*(.*)$/.exec(i);if(o){t.operatorName=o[1]??"";continue}}return 0===Object.keys(t).length?null:t}(i.stdout)}async function eC(e){await u(e,["status_bar",e.id,"clear"],void 0)}async function ev(e,t){0!==t.length&&await u(e,["status_bar",e.id,"override",...t],void 0)}function eg(e,t,i){T({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...eu(i)}})}let eb={ensureBooted:B,prepareStatusBarForScreenshot:eh,captureWithRetry:eL,captureWithRunner:eD,shouldFallbackToRunner:ex};async function eN(e,t,i={}){if("macos"===e.platform)return void await eD(e,t,i.appBundleId,i.fullscreen,i.runnerOptions);if("simulator"===e.kind)return void await eS(e,t,i);try{await h(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(t){if(!function(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=e$(e);return t.includes("unknown option '--device'")||t.includes("unknown subcommand")&&t.includes("screenshot")||t.includes("unrecognized subcommand")&&t.includes("screenshot")}(t))throw t;eF(e,"devicectl_screenshot",t)}await eD(e,t,i.appBundleId,i.fullscreen,i.runnerOptions)}async function eS(e,t,i={}){if("simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");let a=i.deps??eb;i.skipIosSimulatorBootCheck||await a.ensureBooted(e);let r=async()=>{};if(!0===i.normalizeStatusBar)try{r=await a.prepareStatusBarForScreenshot(e)}catch(t){eR(e,"prepare_failed",t)}try{try{await a.captureWithRetry(e,t);return}catch(o){let r=o;if(i.skipIosSimulatorBootCheck&&function(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=e$(e);return t.includes("not booted")||t.includes("current state: shutdown")||t.includes("current state is shutdown")||t.includes("current state=shutdown")||t.includes("state: shutdown")||t.includes("state=shutdown")}(o)){await a.ensureBooted(e);try{await a.captureWithRetry(e,t);return}catch(e){r=e}}if(!a.shouldFallbackToRunner(r))throw r;eF(e,"simctl_screenshot",r)}await a.captureWithRunner(e,t,i.appBundleId,i.fullscreen,i.runnerOptions)}finally{await r().catch(t=>eR(e,"restore_failed",t))}}async function eL(e,t){let i=E.fromTimeoutMs(2e4);await k(async({deadline:i})=>{var a;await (a=["io",e.id,"screenshot",t],u(e,a,{timeoutMs:Math.max(1e3,i?.remainingMs()??2e4)}))},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>ex(e)},{deadline:i,phase:"ios_simulator_screenshot"})}async function eD(e,i,a,r,o){let l=(await w(e,{command:"screenshot",appBundleId:a,fullscreen:r},o)).message;if(!l)throw new n("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");"macos"===e.platform?await t.copyFile(l,i):"simulator"===e.kind?await eO(e,l,i):await eM(e,l,i)}async function eM(e,t,i){let a=E.fromTimeoutMs(2e4),r={exitCode:1,stdout:"",stderr:""};for(let n of v)if(0===(r=await o(["devicectl","device","copy","from","--device",e.id,"--source",t,"--destination",i,"--domain-type","appDataContainer","--domain-identifier",n],{allowFailure:!0,timeoutMs:eP(a,2e4,"runner screenshot copy")})).exitCode)return;let l=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;throw new n("COMMAND_FAILED",`Failed to capture iOS screenshot: ${l}`)}async function eO(e,i,r){let o=E.fromTimeoutMs(2e4),l="Unable to locate runner container for simulator screenshot";for(let n of v){var s;let d=await (s=["get_app_container",e.id,n,"data"],u(e,s,{allowFailure:!0,timeoutMs:eP(o,2e4,"runner screenshot container lookup")}));if(0!==d.exitCode){let e=d.stderr.trim();e&&(l=e);continue}let c=d.stdout.trim();if(!c){l="simctl get_app_container returned empty output";continue}for(let e of function(e,t){let i=a.resolve(e),r=t.trim();if(!r)return[];let n=[],o=new Set,l=e=>{let t=a.normalize(e);o.has(t)||(o.add(t),n.push(t))},s=r.replace(/^\/+/,""),d=s.replace(/\\/g,"/");if(s&&l(a.join(i,s)),a.isAbsolute(r)&&l(a.normalize(r)),d.startsWith("tmp/"))l(a.join(i,d));else{let e=d.lastIndexOf("/tmp/");if(e>=0){let t=d.slice(e+1);l(a.join(i,t))}}let u=a.basename(r);return u&&l(a.join(i,"tmp",u)),n}(c,i))try{await t.copyFile(e,r);return}catch(e){l=e instanceof Error?e.message:String(e)}}throw new n("COMMAND_FAILED",`Failed to capture iOS screenshot: ${l}`)}function eP(e,t,i){let a=e.remainingMs();if(a>0)return a;throw new n("COMMAND_FAILED",`iOS ${i} timed out after ${t}ms`,{timeoutMs:t,step:i})}function eF(e,t,i){let a=eu(i);T({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...a}})}function eR(e,t,i){T({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...eu(i)}})}function ex(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=e$(e);return t.includes("timeout waiting for screen surfaces")||t.includes("nsposixerrordomain")&&t.includes("code=60")&&t.includes("screenshot")||t.includes("timed out")&&t.includes("screenshot")}function e$(e){let t=e.details??{},i="string"==typeof t.stdout?t.stdout:"",a="string"==typeof t.stderr?t.stderr:"",r=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):"";return`${e.message}
1
+ let e;import{promises as t}from"node:fs";import i from"node:os";import a from"node:path";import{fileURLToPath as r}from"node:url";import{AppError as n}from"./485.js";import{runXcrun as o,resolveIosDevicectlHint as s,LAUNCH_CONSOLE_DIRECT_APP_ONLY_MESSAGE as l,resolveAppleToolProvider as d,runSimctlForDevice as u,IOS_DEVICECTL_DEFAULT_HINT as c,readInfoPlistString as p,buildSimctlArgsForDevice as f,runAppleRunnerCommand as w,runMacOsPermissionAction as m,runIosDevicectl as h,filterAppleAppsByBundlePrefix as y,runAppleToolCommand as A,listIosDeviceApps as I,quitMacOsApp as _,LAUNCH_CONSOLE_IOS_SIMULATOR_ONLY_MESSAGE as g,IOS_RUNNER_CONTAINER_BUNDLE_IDS as C}from"./9722.js";import{emitDiagnostic as v,runCmd as b}from"./8875.js";import{materializeInstallablePath as N,isTrustedInstallSourceUrl as S}from"./5484.js";import{parseAppearanceAction as L,summarizeCommandAttemptFailures as D,parseSettingState as M,parsePermissionTarget as O,parsePermissionAction as P}from"./8225.js";import{isWebUrl as R,createAppResolutionCache as F,isDeepLinkTarget as x,resolveIosSimulatorDeviceSetPath as $,resolveIosDeviceDeepLinkBundleId as k,retryWithPolicy as E,Deadline as T}from"./3340.js";import{isIosFamily as U,isMacOs as B}from"./6849.js";import{requireSimulatorDevice as G,ensureBootedSimulator as V,getSimulatorState as j}from"./simulator.js";import{getUnsupportedMacOsSettingMessage as W,requireLocationCoordinates as K}from"./2948.js";function H(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=e.details??{};if(4!==t.exitCode)return!1;let i=String(t.stderr??"").toLowerCase();return i.includes("fbsopenapplicationserviceerrordomain")&&i.includes("the request to open")}async function z(e,t){let i=await o(f(e,["get_app_container",e.id,t]),{allowFailure:!0});if(0!==i.exitCode)return{installed:!1};let a=i.stdout.trim();if(!a)return{installed:!1};let r=await A("plutil",["-extract","CFBundleExecutable","raw","-o","-",`${a}/Info.plist`],{allowFailure:!0});if(0!==r.exitCode||!r.stdout.trim())return{installed:!0};let n=r.stdout.trim(),s=`${a}/${n}`,l=await A("otool",["-l",s],{allowFailure:!0});if(0!==l.exitCode)return{installed:!0};let d=l.stdout.toLowerCase();return{installed:!0,simulatorCompatible:d.includes("iossimulator")||d.includes("platform 7")}}async function q(e,t){let i;if("url"===e.kind&&!S(e.url))throw new n("INVALID_ARGS","iOS install_from_source URL sources are only supported for trusted artifact services such as GitHub Actions and EAS. Use a path source for other hosts.");let a=await N({source:e,isInstallablePath:(e,t)=>t.isDirectory()&&e.toLowerCase().endsWith(".app")||t.isFile()&&e.toLowerCase().endsWith(".ipa"),installableLabel:"iOS installable (.app or .ipa)",allowArchiveExtraction:"url"!==e.kind||S(e.url),signal:t?.signal});try{let e=i=await Z(a.installablePath,t),r=await J(e.installPath);return{archivePath:a.archivePath??(a.installablePath.toLowerCase().endsWith(".ipa")?a.installablePath:void 0),installablePath:e.installPath,bundleId:r.bundleId,appName:r.appName,cleanup:async()=>{await e.cleanup(),await a.cleanup()}}}catch(e){try{await i?.cleanup()}finally{await a.cleanup()}throw e}}async function J(e){let t=a.join(e,"Info.plist"),[i,r,n]=await Promise.all([p(t,"CFBundleIdentifier"),p(t,"CFBundleDisplayName"),p(t,"CFBundleName")]);return{bundleId:i,appName:r??n}}async function Z(e,r){if(!e.toLowerCase().endsWith(".ipa"))return{installPath:e,cleanup:async()=>{}};let o=await t.mkdtemp(a.join(i.tmpdir(),"agent-device-ios-ipa-")),s=async()=>{await t.rm(o,{recursive:!0,force:!0})};try{await b("unzip",["-q",e,"-d",o]);let i=a.join(o,"Payload"),l=(await t.readdir(i,{withFileTypes:!0}).catch(()=>{throw new n("INVALID_ARGS","Invalid IPA: missing Payload directory")})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(".app")).map(e=>({installPath:a.join(i,e.name),bundleName:e.name.replace(/\.app$/i,"")})),d=l[0];if(void 0!==d&&1===l.length)return{installPath:d.installPath,cleanup:s};if(0===l.length)throw new n("INVALID_ARGS","Invalid IPA: expected at least one .app under Payload, found 0");await Q(l);let u=r?.appIdentifierHint?.trim();if(u){let e=function(e,t){let i=t.toLowerCase(),a=e.filter(e=>e.bundleName.toLowerCase()===i);if(1===a.length)return a[0];if(a.length>1)throw new n("INVALID_ARGS",`Invalid IPA: multiple app bundles matched "${t}" by name. Use a bundle id hint instead.`);if(t.includes(".")){let t=e.filter(e=>e.bundleId?.toLowerCase()===i);if(1===t.length)return t[0]}}(l,u);if(e)return{installPath:e.installPath,cleanup:s};throw new n("INVALID_ARGS",`Invalid IPA: found ${l.length} .app bundles under Payload and none matched "${u}". Available bundles: ${l.map(X).join(", ")}`)}throw new n("INVALID_ARGS",`Invalid IPA: found ${l.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${l.map(X).join(", ")}`)}catch(e){throw await s(),e}}async function Q(e){await Promise.all(e.map(async e=>{if(e.bundleId&&e.appName)return;let t=await J(e.installPath);e.bundleId=e.bundleId??t.bundleId,e.appName=e.appName??t.appName}))}function X(e){let t=e.bundleId??e.appName;return t?`${e.bundleName}.app (${t})`:`${e.bundleName}.app`}let Y={settings:"com.apple.systempreferences"},ee=/^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/,et={platform:"macos",deviceId:"host",variant:"all"},ei=F();async function ea(e){let t=e.trim(),i=Y[t.toLowerCase()];if(i)return i;if(ee.test(t))return t;let a=ei.get(et,t);if(a)return a;let r=(await eu("all")).filter(e=>e.name.toLowerCase()===t.toLowerCase()),o=r[0];if(void 0!==o&&1===r.length)return ei.set(et,t,o.bundleId);if(r.length>1)throw new n("INVALID_ARGS",`Multiple apps matched "${e}"`,{matches:r});throw new n("APP_NOT_INSTALLED",`No app found matching "${e}"`)}async function er(e,t,i){let a=i?.url?.trim();if(a){if(!x(a))throw new n("INVALID_ARGS","open <app> <url> requires a valid URL target");let e=i?.appBundleId??await ea(t);await ec().openBundle(e,a);return}let r=t.trim();if(x(r))return void await ec().openTarget(r);let o=i?.appBundleId??await ea(r);await ec().openBundle(o)}async function en(e,t){let i=await ea(t),a=await _(i);if(a.running&&!a.terminated&&!a.forceTerminated)throw new n("COMMAND_FAILED",`Failed to close macOS app ${t}`,{bundleId:i,running:a.running,terminated:a.terminated,forceTerminated:a.forceTerminated})}async function eo(){return await ec().readClipboard()}async function es(e){await ec().writeClipboard(e)}async function el(){return await ec().readDarkMode()}async function ed(e){let t=L(e),i="toggle"===t?!await el():"dark"===t;await ec().setDarkMode(i)}async function eu(e){return await ec().listApps(e)}function ec(){let e=d().macosHost;if(!e)throw new n("UNSUPPORTED_OPERATION","macOS host provider is not available");return e}function ep(e){if(!(e instanceof n))return{reason:e instanceof Error?e.message:String(e)};let t=e.details??{},i=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:i}}let ef=["--time","9:41","--dataNetwork","wifi","--wifiMode","active","--wifiBars","3","--batteryState","charged","--batteryLevel","100"],ew={0:"hide",1:"wifi",6:"3g",7:"4g",8:"lte",9:"lte-a",10:"lte+",11:"5g",12:"5g+",13:"5g-uwb",14:"5g-uc"},em={1:"searching",2:"failed",3:"active"},eh={0:"notSupported",1:"searching",2:"failed",3:"active"},ey=new Set;async function eA(e){var t;let i=null,a=!1;if(t=e,ey.has(eg(t)))a=!0;else try{i=await eC(e),a=!0}catch(t){eN(e,"snapshot_failed",t)}try{(!a||i)&&await ev(e),await eb(e,ef)}catch(t){eN(e,"prepare_failed",t)}return async()=>{await eI(e,a?i:null)}}async function eI(e,t){var i,a,r;let n;(await ev(e),t)?(await eb(e,(n=[],(i=t).dataNetwork&&n.push("--dataNetwork",i.dataNetwork),i.wifiMode&&n.push("--wifiMode",i.wifiMode),void 0!==i.wifiBars&&("wifi"===i.dataNetwork||i.wifiMode)&&n.push("--wifiBars",i.wifiBars),i.cellularMode&&n.push("--cellularMode",i.cellularMode),void 0!==i.cellularBars&&(i.cellularMode||(a=i.dataNetwork)&&"hide"!==a&&"wifi"!==a||void 0!==i.operatorName)&&n.push("--cellularBars",i.cellularBars),void 0!==i.operatorName&&n.push("--operatorName",i.operatorName),n)),e_(e)):(r=e,ey.add(eg(r)))}function e_(e){ey.delete(eg(e))}function eg(e){return`${e.platform}:${e.kind}:${e.id}`}async function eC(e){var t;let i=await (t=["status_bar",e.id,"list"],u(e,t,{allowFailure:!0}));if(0!==i.exitCode)throw new n("COMMAND_FAILED","Failed to read simulator status bar overrides",{exitCode:i.exitCode,stdout:i.stdout,stderr:i.stderr});return function(e){let t={};for(let i of e.split("\n").map(e=>e.trim()).filter(e=>e.length>0&&"Current Status Bar Overrides:"!==e&&!/^=+$/.test(e))){let e=/^DataNetworkType:\s+(\d+)$/.exec(i);if(e){let i=Number(e[1]),a=ew[i];if(!a)throw new n("COMMAND_FAILED",`Unsupported simulator data network type: ${i}`);t.dataNetwork=a;continue}let a=/^WiFi Mode:\s+(\d+),\s+WiFi Bars:\s+(\d+)$/.exec(i);if(a){let e=em[Number(a[1])];e&&(t.wifiMode=e),t.wifiBars=a[2];continue}let r=/^Cell Mode:\s+(\d+),\s+Cell Bars:\s+(\d+)$/.exec(i);if(r){let e=Number(r[1]),i=eh[e];if(!i)throw new n("COMMAND_FAILED",`Unsupported simulator cellular mode: ${e}`);t.cellularMode=i,t.cellularBars=r[2];continue}let o=/^Operator Name:\s*(.*)$/.exec(i);if(o){t.operatorName=o[1]??"";continue}}return 0===Object.keys(t).length?null:t}(i.stdout)}async function ev(e){await u(e,["status_bar",e.id,"clear"],void 0)}async function eb(e,t){0!==t.length&&await u(e,["status_bar",e.id,"override",...t],void 0)}function eN(e,t,i){v({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...ep(i)}})}let eS={ensureBooted:V,prepareStatusBarForScreenshot:eA,captureWithRetry:eM,captureWithRunner:eO,shouldFallbackToRunner:ek};async function eL(e,t,i={}){if(B(e))return void await eO(e,t,i.appBundleId,i.fullscreen,i.runnerOptions);if("simulator"===e.kind)return void await eD(e,t,i);try{await h(["device","screenshot","--device",e.id,t],{action:"capture iOS screenshot",deviceId:e.id});return}catch(t){if(!function(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=eE(e);return t.includes("unknown option '--device'")||t.includes("unknown subcommand")&&t.includes("screenshot")||t.includes("unrecognized subcommand")&&t.includes("screenshot")}(t))throw t;ex(e,"devicectl_screenshot",t)}await eO(e,t,i.appBundleId,i.fullscreen,i.runnerOptions)}async function eD(e,t,i={}){if("simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");let a=i.deps??eS;i.skipIosSimulatorBootCheck||await a.ensureBooted(e);let r=async()=>{};if(!0===i.normalizeStatusBar)try{r=await a.prepareStatusBarForScreenshot(e)}catch(t){e$(e,"prepare_failed",t)}try{try{await a.captureWithRetry(e,t);return}catch(o){let r=o;if(i.skipIosSimulatorBootCheck&&function(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=eE(e);return t.includes("not booted")||t.includes("current state: shutdown")||t.includes("current state is shutdown")||t.includes("current state=shutdown")||t.includes("state: shutdown")||t.includes("state=shutdown")}(o)){await a.ensureBooted(e);try{await a.captureWithRetry(e,t);return}catch(e){r=e}}if(!a.shouldFallbackToRunner(r))throw r;ex(e,"simctl_screenshot",r)}await a.captureWithRunner(e,t,i.appBundleId,i.fullscreen,i.runnerOptions)}finally{await r().catch(t=>e$(e,"restore_failed",t))}}async function eM(e,t){let i=T.fromTimeoutMs(2e4);await E(async({deadline:i})=>{var a;await (a=["io",e.id,"screenshot",t],u(e,a,{timeoutMs:Math.max(1e3,i?.remainingMs()??2e4)}))},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>ek(e)},{deadline:i,phase:"ios_simulator_screenshot"})}async function eO(e,i,a,r,o){let s=(await w(e,{command:"screenshot",appBundleId:a,fullscreen:r},o)).message;if(!s)throw new n("COMMAND_FAILED","Failed to capture iOS screenshot: runner returned no file path");B(e)?await t.copyFile(s,i):"simulator"===e.kind?await eR(e,s,i):await eP(e,s,i)}async function eP(e,t,i){let a=T.fromTimeoutMs(2e4),r={exitCode:1,stdout:"",stderr:""};for(let n of C)if(0===(r=await o(["devicectl","device","copy","from","--device",e.id,"--source",t,"--destination",i,"--domain-type","appDataContainer","--domain-identifier",n],{allowFailure:!0,timeoutMs:eF(a,2e4,"runner screenshot copy")})).exitCode)return;let s=r.stderr.trim()||r.stdout.trim()||`devicectl exited with code ${r.exitCode}`;throw new n("COMMAND_FAILED",`Failed to capture iOS screenshot: ${s}`)}async function eR(e,i,r){let o=T.fromTimeoutMs(2e4),s="Unable to locate runner container for simulator screenshot";for(let n of C){var l;let d=await (l=["get_app_container",e.id,n,"data"],u(e,l,{allowFailure:!0,timeoutMs:eF(o,2e4,"runner screenshot container lookup")}));if(0!==d.exitCode){let e=d.stderr.trim();e&&(s=e);continue}let c=d.stdout.trim();if(!c){s="simctl get_app_container returned empty output";continue}for(let e of function(e,t){let i=a.resolve(e),r=t.trim();if(!r)return[];let n=[],o=new Set,s=e=>{let t=a.normalize(e);o.has(t)||(o.add(t),n.push(t))},l=r.replace(/^\/+/,""),d=l.replace(/\\/g,"/");if(l&&s(a.join(i,l)),a.isAbsolute(r)&&s(a.normalize(r)),d.startsWith("tmp/"))s(a.join(i,d));else{let e=d.lastIndexOf("/tmp/");if(e>=0){let t=d.slice(e+1);s(a.join(i,t))}}let u=a.basename(r);return u&&s(a.join(i,"tmp",u)),n}(c,i))try{await t.copyFile(e,r);return}catch(e){s=e instanceof Error?e.message:String(e)}}throw new n("COMMAND_FAILED",`Failed to capture iOS screenshot: ${s}`)}function eF(e,t,i){let a=e.remainingMs();if(a>0)return a;throw new n("COMMAND_FAILED",`iOS ${i} timed out after ${t}ms`,{timeoutMs:t,step:i})}function ex(e,t,i){let a=ep(i);v({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...a}})}function e$(e,t,i){v({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...ep(i)}})}function ek(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;let t=eE(e);return t.includes("timeout waiting for screen surfaces")||t.includes("nsposixerrordomain")&&t.includes("code=60")&&t.includes("screenshot")||t.includes("timed out")&&t.includes("screenshot")}function eE(e){let t=e.details??{},i="string"==typeof t.stdout?t.stdout:"",a="string"==typeof t.stderr?t.stderr:"",r=Array.isArray(t.args)?t.args.filter(e=>"string"==typeof e).join(" "):"";return`${e.message}
2
2
  ${i}
3
3
  ${a}
4
- ${r}`.toLowerCase()}let ek={settings:"com.apple.Preferences"},eE=F(),eT=null;function eU(e){return{platform:"ios",deviceId:e.id,variant:e.kind}}function eB(e,t,i){return o(f(e,t),i)}function eG(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function eV(e,t){if("macos"===e.platform)return await et(t);let i=t.trim();if(i.includes("."))return i;let a=ek[i.toLowerCase()];if(a)return a;let r=eU(e),o=eE.get(r,i);if(o)return o;let l=("simulator"===e.kind?await e3(e):await I(e,"all")).filter(e=>e.name.toLowerCase()===i.toLowerCase()),s=l[0];if(void 0!==s&&1===l.length)return eE.set(r,i,s.bundleId);if(l.length>1)throw new n("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:l});throw new n("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function ej(e,t){var i;let r;if("ios"!==e.platform||"simulator"!==e.kind)return;let n=(i=t,r=/^([A-Za-z][A-Za-z0-9+.-]*):/.exec(i.trim()),r?.[1]?.toLowerCase());if(!n)return;let o=await e5(e),l=[];for(let e of o)!e.bundleId.startsWith("com.callstack.agentdevice.runner")&&e.path&&(await e8(a.join(e.path,"Info.plist"))).has(n)&&l.push(e);let s=l.filter(e=>"User"===e.applicationType);return 1===s.length?s[0]?.bundleId:s.length>1?void 0:1===l.length?l[0]?.bundleId:void 0}async function eW(e,t,i){let a=i?.launchConsole?.trim(),r=i?.launchArgs;if(a&&("ios"!==e.platform||"simulator"!==e.kind))throw new n("UNSUPPORTED_OPERATION",C);if("macos"===e.platform){if(r&&r.length>0)throw new n("UNSUPPORTED_OPERATION","--launch-args is not supported on macOS; launch arguments are currently iOS-only.");await ei(e,t,i);return}let o=i?.url?.trim();if(o){if(a)throw new n("INVALID_ARGS",s);if(!R(o))throw new n("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){if(r||P(o)){let a=i?.appBundleId??await eV(e,t);await ta(e,a,{...r?{launchArgs:r}:{}})}await eK(e,o,void 0);return}let l=$(i?.appBundleId??await eV(e,t),o);if(!l)throw new n("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await to(e,l,{payloadUrl:o,launchArgs:r});return}let l=t.trim();if(R(l)){if(a)throw new n("INVALID_ARGS",s);if("simulator"===e.kind)return void await eK(e,l,r);let t=$(i?.appBundleId,l);if(!t)throw new n("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");return void await to(e,t,{payloadUrl:l,launchArgs:r})}let d=i?.appBundleId??await eV(e,t);"simulator"===e.kind?await ta(e,d,{...a?{launchConsole:a}:{},...r?{launchArgs:r}:{}}):await to(e,d,{launchArgs:r})}async function eK(e,t,i){if(i&&i.length>0)throw new n("INVALID_ARGS","--launch-args is not supported with iOS simulator URL opens (simctl openurl ignores launch args). Launch the app first with --launch-args, then issue the URL open in a separate call.");await B(e),await eB(e,["openurl",e.id,t])}async function eH(e){"macos"===e.platform||"simulator"!==e.kind||"Booted"!==await G(e)&&await B(e)}async function ez(e,t){if("macos"===e.platform)return void await ea(e,t);let i=await eV(e,t);if("simulator"===e.kind){await B(e);let t=f(e,["terminate",e.id,i]),a=await o(t,{allowFailure:!0,timeoutMs:15e3});if(0!==a.exitCode){if(a.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new n("COMMAND_FAILED",`xcrun exited with code ${a.exitCode}`,{cmd:"xcrun",args:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode})}return}await h(["device","process","terminate","--device",e.id,i],{action:"terminate iOS app",deviceId:e.id})}async function eq(e,i){if("ios"!==e.platform||"simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Clearing app state is currently supported only on iOS simulators.");let r=await eV(e,i);await B(e),await ez(e,r);let o=await eB(e,["get_app_container",e.id,r,"data"],{allowFailure:!0});if(0!==o.exitCode)throw new n("COMMAND_FAILED",`simctl get_app_container failed for ${r}`,{stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode});let l=o.stdout.trim();if(!l)throw new n("COMMAND_FAILED",`simctl get_app_container returned an empty data container path for ${r}`);let s=await t.readdir(l);return await Promise.all(s.map(e=>t.rm(a.join(l,e),{recursive:!0,force:!0}))),{bundleId:r,containerPath:l}}async function eJ(e,t){return await eE.invalidateWhile(eU(e),async()=>{let i=await eV(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,i],a=await o(t,{allowFailure:!0,timeoutMs:2e4});if(0!==a.exitCode){let r=String(a.stdout??""),o=String(a.stderr??"");if(!eG(`${r}
5
- ${o}`.toLowerCase()))throw new n("COMMAND_FAILED",`Failed to uninstall iOS app ${i}`,{cmd:"xcrun",args:t,exitCode:a.exitCode,stdout:r,stderr:o,deviceId:e.id,hint:l(r,o)??c})}return{bundleId:i}}await B(e);let a=await eB(e,["uninstall",e.id,i],{allowFailure:!0});if(0!==a.exitCode&&!eG(`${a.stdout}
6
- ${a.stderr}`.toLowerCase()))throw new n("COMMAND_FAILED",`simctl uninstall failed for ${i}`,{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});return{bundleId:i}})}async function eZ(e,t,i){let a=await H({kind:"path",path:t},i);try{return await eX(e,a.installablePath),{archivePath:a.archivePath,installablePath:a.installablePath,bundleId:a.bundleId,appName:a.appName,launchTarget:a.bundleId}}finally{await a.cleanup()}}async function eQ(e,t,i){return await eE.invalidateWhile(eU(e),async()=>{let{bundleId:a}=await eJ(e,t);return await eZ(e,i,{appIdentifierHint:t}),{bundleId:a}})}async function eX(e,t){await eE.invalidateWhile(eU(e),async()=>{"simulator"!==e.kind?await h(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id},{timeoutMs:12e4}):(await B(e),await eB(e,["install",e.id,t]))})}async function eY(e){if("macos"===e.platform)return await er();U(e,"clipboard"),await B(e);let t=await eB(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new n("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 e0(e,t){if("macos"===e.platform)return void await en(t);U(e,"clipboard"),await B(e);let i=await eB(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==i.exitCode)throw new n("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}async function e1(e,r,n){U(e,"push"),await B(e);let o=await t.mkdtemp(a.join(i.tmpdir(),"agent-device-ios-push-")),l=a.join(o,"payload.apns");try{await t.writeFile(l,`${JSON.stringify(n)}
7
- `,"utf8"),await eB(e,["push",e.id,r,l])}finally{await t.rm(o,{recursive:!0,force:!0})}}async function e2(e,t,i,a,r){if("macos"===e.platform){let e=t.toLowerCase();if("appearance"===e)return void await el(i);if("permission"===e){let e=O(i);if("deny"===e)throw new n("INVALID_ARGS",V("permission"));let t=function(e){let t=e?.trim().toLowerCase();if("accessibility"===t||"screen-recording"===t||"input-monitoring"===t)return t;throw new n("INVALID_ARGS","Unsupported macOS permission target. Use accessibility|screen-recording|input-monitoring.")}(r?.permissionTarget);return await m(e,t)}throw new n("INVALID_ARGS",V(t))}U(e,"settings"),await B(e);let o=t.toLowerCase();switch(o){case"clear-app-state":{if("clear"!==i.toLowerCase())throw new n("INVALID_ARGS","settings clear-app-state only supports clear.");if(!a)throw new n("INVALID_ARGS","settings clear-app-state requires an app id or an active app session.");let t=await eq(e,a);return{bundleId:t.bundleId,containerPath:t.containerPath,cleared:!0}}case"wifi":{let t=D(i);await eB(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]),eA(e);return}case"airplane":if(D(i))await eB(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]),eA(e);else await eB(e,["status_bar",e.id,"clear"]),em.add(eI(e));return;case"location":{if("set"===i.toLowerCase()){let{latitude:t,longitude:i}=j(r);return await eB(e,["location",e.id,"set",`${t},${i}`]),{latitude:t,longitude:i}}let t=D(i);if(!a)throw new n("INVALID_ARGS","location setting requires an active app in session");await eB(e,["privacy",e.id,t?"grant":"revoke","location",a]);return}case"faceid":case"touchid":{let t=e6[o],a=function(e,t){let i=e.trim().toLowerCase();if("match"===i)return"match";if("nonmatch"===i)return"nonmatch";if("enroll"===i)return"enroll";if("unenroll"===i)return"unenroll";throw new n("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(i,o);await ti(e,a,{settingName:o,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await e9(e,i);await eB(e,["ui",e.id,"appearance",t]);return}case"permission":{var l;if(!a)throw new n("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(l=O(i))?"revoke":l,o=function(e,t){let i=M(e);if("photos"!==i&&t?.trim())throw new n("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===i)return"camera";if("microphone"===i)return"microphone";if("contacts"===i)return"contacts";if("contacts-limited"===i)return"contacts-limited";if("notifications"===i)return"notifications";if("calendar"===i)return"calendar";if("location"===i)return"location";if("location-always"===i)return"location-always";if("media-library"===i)return"media-library";if("motion"===i)return"motion";if("reminders"===i)return"reminders";if("siri"===i)return"siri";if("photos"===i){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new n("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new n("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(r?.permissionTarget,r?.permissionMode);await e7(e,t,o,a);return}default:throw new n("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function e4(e,t){return"macos"===e.platform?await es(t):"simulator"===e.kind?y(await e3(e),t):await I(e,t)}async function e3(e){return(await e5(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function e5(e){let t=(await eB(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let i=null;if(t.startsWith("{"))try{i=JSON.parse(t)}catch{i=null}if(!i&&t.startsWith("{"))try{let e=await A("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(i=JSON.parse(e.stdout))}catch{i=null}return i?Object.entries(i).map(([e,t])=>{let i=function(e){if(e.Path)return e.Path;if(e.Bundle)try{return r(e.Bundle)}catch{return}}(t);return{bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e,...i?{path:i}:{},...t.ApplicationType?{applicationType:t.ApplicationType}:{}}}):[]}async function e8(e){let t=await A("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==t.exitCode)return new Set;try{let e=JSON.parse(t.stdout),i=new Set;for(let t of e.CFBundleURLTypes??[])if(Array.isArray(t.CFBundleURLSchemes))for(let e of t.CFBundleURLSchemes)"string"==typeof e&&e.trim()&&i.add(e.trim().toLowerCase());return i}catch{return new Set}}async function e9(e,t){let i=S(t);if("toggle"!==i)return i;let a=await eB(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==a.exitCode)throw new n("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});let r=function(e,t){let i=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
8
- ${t}`);if(!i)return null;let a=i[1]?.toLowerCase();return"dark"===a?"dark":"light"===a?"light":null}(a.stdout,a.stderr);if(!r)throw new n("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:a.stdout,stderr:a.stderr});return"dark"===r?"light":"dark"}let e6={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function e7(e,t,i,a){let r=await tt(e);if(!r.has(i))throw new n("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${i}" on this runtime.`,{deviceId:e.id,appBundleId:a,hint:`Supported services: ${Array.from(r).sort().join(", ")}`});let o=["privacy",e.id,t,i,a],l="notifications"===i;if(!("reset"===t&&l))try{await eB(e,o);return}catch(t){if(!(l&&te(t)))throw t;throw new n("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:a,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await eB(e,o);return}catch(e){if(!te(e))throw e}try{await eB(e,["privacy",e.id,"reset","all",a])}catch(t){throw new n("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:a,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function te(e){if(!(e instanceof n)||"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 tt(t){let i=x(t.simulatorSetPath),a=`${process.env.PATH??""}::${i??""}`;if(eT&&e===a)return eT;let r=await eB(t,["privacy","help"],{allowFailure:!0}),o=function(e){let t=new Set,i=!1;for(let a of e.split("\n")){let e=a.trim();if(!e)continue;if("service"===e){i=!0;continue}if(!i)continue;if(e.startsWith("bundle identifier"))break;let r=/^([a-z-]+)\s+-\s+/.exec(e),n=r?.[1];void 0!==n&&t.add(n)}return t}(`${r.stdout}
9
- ${r.stderr}`);if(0===o.size)throw new n("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return eT=o,e=a,o}async function ti(e,t,i){let a=function(e,t,i){let a=i.length>0?i:["face"];switch(t){case"match":return a.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return a.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,i.modalityAliases),r=[];for(let t of a){let i=f(e,t),a=await o(i,{allowFailure:!0});if(0===a.exitCode)return;r.push({args:i,stderr:a.stderr,stdout:a.stdout,exitCode:a.exitCode})}let l=L(r);if(r.length>0&&r.every(e=>{var t,i;let a;return t=e.stdout,i=e.stderr,(a=`${t}
10
- ${i}`.toLowerCase()).includes("unrecognized subcommand")||a.includes("unknown subcommand")||a.includes("not supported")||a.includes("unavailable")||a.includes("biometric")&&a.includes("invalid")}))throw new n("UNSUPPORTED_OPERATION",`${i.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:i.settingName,attempts:l});throw new n("COMMAND_FAILED",`Failed to simulate ${i.settingName}.`,{deviceId:e.id,action:t,setting:i.settingName,attempts:l})}async function ta(e,t,i){await B(e);let a=0,r=E.fromTimeoutMs(6e4);try{await k(async({deadline:a})=>{var r,l,s,d;let u;if(a?.isExpired())throw new n("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:6e4});let c=(l=e.id,s=t,d=i,u=["launch"],d?.launchConsole&&u.push("--console-pty"),u.push(l,s),d?.launchArgs&&d.launchArgs.length>0&&u.push(...d.launchArgs),r=u,f(e,r)),p=i?.launchConsole?await tr(c,i.launchConsole):await o(c,{allowFailure:!0});if(0!==p.exitCode)throw new n("COMMAND_FAILED",`xcrun exited with code ${p.exitCode}`,{cmd:"xcrun",args:c,stdout:p.stdout,stderr:p.stderr,exitCode:p.exitCode})},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>!!W(e)&&(a+=1)<3},{deadline:r})}catch(i){if(W(i)){var l;let a=(l=await K(e,t)).installed?!1===l.simulatorCompatible?"ARCH_MISMATCH":"PERSISTENT_LAUNCH_FAIL":"APP_NOT_INSTALLED";i.details={...i.details,hint:function(e){switch(e){case"ARCH_MISMATCH":return"The app binary was not built for the simulator platform. Rebuild with a simulator destination or use a physical device.";case"APP_NOT_INSTALLED":return"The app bundle is not installed on this simulator. Run install before open.";case"PERSISTENT_LAUNCH_FAIL":return"The simulator repeatedly refused to launch the app. Inspect crash logs in Console.app or ~/Library/Logs/DiagnosticReports/ and consider reinstalling the app.";default:return"The simulator failed to launch the app. Retry with --debug and inspect diagnostics log for details."}}(a)}}throw i}}async function tr(e,i){await t.mkdir(a.dirname(i),{recursive:!0});try{let t=await o(e,{allowFailure:!0,timeoutMs:25e3});return await tn(i,t.stdout,t.stderr),t}catch(t){let e=(t instanceof n?t:void 0)?.details;if(e?.timeoutMs===25e3){let t="string"==typeof e.stdout?e.stdout:"",a="string"==typeof e.stderr?e.stderr:"";return await tn(i,t,a),T({level:"warn",phase:"ios_simulator_launch_console_capture_timeout",data:{timeoutMs:25e3,logPath:i,stdoutBytes:Buffer.byteLength(t),stderrBytes:Buffer.byteLength(a)}}),{stdout:t,stderr:a,exitCode:0}}throw t}}async function tn(e,i,a){var r,n;await t.writeFile(e,(r=i,n=a,!r||!n||r.endsWith("\n")||r.endsWith("\r")?`${r}${n}`:`${r}
11
- ${n}`),"utf8")}async function to(e,t,i){let a=["device","process","launch","--device",e.id,t];i?.payloadUrl&&a.push("--payload-url",i.payloadUrl),i?.launchArgs&&i.launchArgs.length>0&&a.push("--",...i.launchArgs),await h(a,{action:"launch iOS app",deviceId:e.id})}export{ez as closeIosApp,eZ as installIosApp,eX as installIosInstallablePath,e4 as listIosApps,eW as openIosApp,eH as openIosDevice,H as prepareIosInstallArtifact,e1 as pushIosNotification,eY as readIosClipboardText,eQ as reinstallIosApp,eV as resolveIosApp,ej as resolveIosSimulatorDeepLinkBundleId,eN as screenshotIos,e2 as setIosSetting,e0 as writeIosClipboardText};
4
+ ${r}`.toLowerCase()}let eT={settings:"com.apple.Preferences"},eU=F(),eB=null;function eG(e){return{platform:"ios",deviceId:e.id,variant:e.kind}}function eV(e,t,i){return o(f(e,t),i)}function ej(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function eW(e,t){if(B(e))return await ea(t);let i=t.trim();if(i.includes("."))return i;let a=eT[i.toLowerCase()];if(a)return a;let r=eG(e),o=eU.get(r,i);if(o)return o;let s=("simulator"===e.kind?await e8(e):await I(e,"all")).filter(e=>e.name.toLowerCase()===i.toLowerCase()),l=s[0];if(void 0!==l&&1===s.length)return eU.set(r,i,l.bundleId);if(s.length>1)throw new n("INVALID_ARGS",`Multiple apps matched "${t}"`,{matches:s});throw new n("APP_NOT_INSTALLED",`No app found matching "${t}"`)}async function eK(e,t){var i;let r;if(!U(e)||"simulator"!==e.kind)return;let n=(i=t,r=/^([A-Za-z][A-Za-z0-9+.-]*):/.exec(i.trim()),r?.[1]?.toLowerCase());if(!n)return;let o=await e9(e),s=[];for(let e of o)!e.bundleId.startsWith("com.callstack.agentdevice.runner")&&e.path&&(await e6(a.join(e.path,"Info.plist"))).has(n)&&s.push(e);let l=s.filter(e=>"User"===e.applicationType);return 1===l.length?l[0]?.bundleId:l.length>1?void 0:1===s.length?s[0]?.bundleId:void 0}async function eH(e,t,i){let a=i?.launchConsole?.trim(),r=i?.launchArgs;if(a&&(!U(e)||"simulator"!==e.kind))throw new n("UNSUPPORTED_OPERATION",g);if(B(e)){if(r&&r.length>0)throw new n("UNSUPPORTED_OPERATION","--launch-args is not supported on macOS; launch arguments are currently iOS-only.");await er(e,t,i);return}let o=i?.url?.trim();if(o){if(a)throw new n("INVALID_ARGS",l);if(!x(o))throw new n("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){if(r||R(o)){let a=i?.appBundleId??await eW(e,t);await tn(e,a,{...r?{launchArgs:r}:{}})}await ez(e,o,void 0);return}let s=k(i?.appBundleId??await eW(e,t),o);if(!s)throw new n("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");await tl(e,s,{payloadUrl:o,launchArgs:r});return}let s=t.trim();if(x(s)){if(a)throw new n("INVALID_ARGS",l);if("simulator"===e.kind)return void await ez(e,s,r);let t=k(i?.appBundleId,s);if(!t)throw new n("INVALID_ARGS","Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.");return void await tl(e,t,{payloadUrl:s,launchArgs:r})}let d=i?.appBundleId??await eW(e,t);"simulator"===e.kind?await tn(e,d,{...a?{launchConsole:a}:{},...r?{launchArgs:r}:{},...i?.terminateRunningApp?{terminateRunningApp:!0}:{}}):await tl(e,d,{launchArgs:r})}async function ez(e,t,i){if(i&&i.length>0)throw new n("INVALID_ARGS","--launch-args is not supported with iOS simulator URL opens (simctl openurl ignores launch args). Launch the app first with --launch-args, then issue the URL open in a separate call.");await V(e),await eV(e,["openurl",e.id,t])}async function eq(e){B(e)||"simulator"!==e.kind||"Booted"!==await j(e)&&await V(e)}async function eJ(e,t){if(B(e))return void await en(e,t);let i=await eW(e,t);if("simulator"===e.kind){await V(e);let t=f(e,["terminate",e.id,i]),a=await o(t,{allowFailure:!0,timeoutMs:15e3});if(0!==a.exitCode){if(a.stderr.toLowerCase().includes("found nothing to terminate"))return;throw new n("COMMAND_FAILED",`xcrun exited with code ${a.exitCode}`,{cmd:"xcrun",args:t,stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode})}return}await h(["device","process","terminate","--device",e.id,i],{action:"terminate iOS app",deviceId:e.id})}async function eZ(e,i){if(!U(e)||"simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Clearing app state is currently supported only on iOS simulators.");let r=await eW(e,i);await V(e),await eJ(e,r);let o=await eV(e,["get_app_container",e.id,r,"data"],{allowFailure:!0});if(0!==o.exitCode)throw new n("COMMAND_FAILED",`simctl get_app_container failed for ${r}`,{stdout:o.stdout,stderr:o.stderr,exitCode:o.exitCode});let s=o.stdout.trim();if(!s)throw new n("COMMAND_FAILED",`simctl get_app_container returned an empty data container path for ${r}`);let l=await t.readdir(s);return await Promise.all(l.map(e=>t.rm(a.join(s,e),{recursive:!0,force:!0}))),{bundleId:r,containerPath:s}}async function eQ(e,t){return await eU.invalidateWhile(eG(e),async()=>{let i=await eW(e,t);if("simulator"!==e.kind){let t=["devicectl","device","uninstall","app","--device",e.id,i],a=await o(t,{allowFailure:!0,timeoutMs:2e4});if(0!==a.exitCode){let r=String(a.stdout??""),o=String(a.stderr??"");if(!ej(`${r}
5
+ ${o}`.toLowerCase()))throw new n("COMMAND_FAILED",`Failed to uninstall iOS app ${i}`,{cmd:"xcrun",args:t,exitCode:a.exitCode,stdout:r,stderr:o,deviceId:e.id,hint:s(r,o)??c})}return{bundleId:i}}await V(e);let a=await eV(e,["uninstall",e.id,i],{allowFailure:!0});if(0!==a.exitCode&&!ej(`${a.stdout}
6
+ ${a.stderr}`.toLowerCase()))throw new n("COMMAND_FAILED",`simctl uninstall failed for ${i}`,{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});return{bundleId:i}})}async function eX(e,t,i){let a=await q({kind:"path",path:t},i);try{return await e0(e,a.installablePath),{archivePath:a.archivePath,installablePath:a.installablePath,bundleId:a.bundleId,appName:a.appName,launchTarget:a.bundleId}}finally{await a.cleanup()}}async function eY(e,t,i){return await eU.invalidateWhile(eG(e),async()=>{let{bundleId:a}=await eQ(e,t);return await eX(e,i,{appIdentifierHint:t}),{bundleId:a}})}async function e0(e,t){await eU.invalidateWhile(eG(e),async()=>{"simulator"!==e.kind?await h(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id},{timeoutMs:12e4}):(await V(e),await eV(e,["install",e.id,t]))})}async function e1(e){if(B(e))return await eo();G(e,"clipboard"),await V(e);let t=await eV(e,["pbpaste",e.id],{allowFailure:!0});if(0!==t.exitCode)throw new n("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 e2(e,t){if(B(e))return void await es(t);G(e,"clipboard"),await V(e);let i=await eV(e,["pbcopy",e.id],{allowFailure:!0,stdin:t});if(0!==i.exitCode)throw new n("COMMAND_FAILED","Failed to write iOS simulator clipboard",{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode})}async function e4(e,r,n){G(e,"push"),await V(e);let o=await t.mkdtemp(a.join(i.tmpdir(),"agent-device-ios-push-")),s=a.join(o,"payload.apns");try{await t.writeFile(s,`${JSON.stringify(n)}
7
+ `,"utf8"),await eV(e,["push",e.id,r,s])}finally{await t.rm(o,{recursive:!0,force:!0})}}async function e3(e,t,i,a,r){if(B(e)){let e=t.toLowerCase();if("appearance"===e)return void await ed(i);if("permission"===e){let e=P(i);if("deny"===e)throw new n("INVALID_ARGS",W("permission"));let t=function(e){let t=e?.trim().toLowerCase();if("accessibility"===t||"screen-recording"===t||"input-monitoring"===t)return t;throw new n("INVALID_ARGS","Unsupported macOS permission target. Use accessibility|screen-recording|input-monitoring.")}(r?.permissionTarget);return await m(e,t)}throw new n("INVALID_ARGS",W(t))}G(e,"settings"),await V(e);let o=t.toLowerCase();switch(o){case"clear-app-state":{if("clear"!==i.toLowerCase())throw new n("INVALID_ARGS","settings clear-app-state only supports clear.");if(!a)throw new n("INVALID_ARGS","settings clear-app-state requires an app id or an active app session.");let t=await eZ(e,a);return{bundleId:t.bundleId,containerPath:t.containerPath,cleared:!0}}case"wifi":{let t=M(i);await eV(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]),e_(e);return}case"airplane":if(M(i))await eV(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]),e_(e);else await eV(e,["status_bar",e.id,"clear"]),ey.add(eg(e));return;case"location":{if("set"===i.toLowerCase()){let{latitude:t,longitude:i}=K(r);return await eV(e,["location",e.id,"set",`${t},${i}`]),{latitude:t,longitude:i}}let t=M(i);if(!a)throw new n("INVALID_ARGS","location setting requires an active app in session");await eV(e,["privacy",e.id,t?"grant":"revoke","location",a]);return}case"faceid":case"touchid":{let t=te[o],a=function(e,t){let i=e.trim().toLowerCase();if("match"===i)return"match";if("nonmatch"===i)return"nonmatch";if("enroll"===i)return"enroll";if("unenroll"===i)return"unenroll";throw new n("INVALID_ARGS",`Invalid ${t} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}(i,o);await tr(e,a,{settingName:o,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await e7(e,i);await eV(e,["ui",e.id,"appearance",t]);return}case"permission":{var s;if(!a)throw new n("INVALID_ARGS","permission setting requires an active app in session");let t="deny"===(s=P(i))?"revoke":s,o=function(e,t){let i=O(e);if("photos"!==i&&t?.trim())throw new n("INVALID_ARGS",`Permission mode is only supported for photos. Received: ${t}.`);if("camera"===i)return"camera";if("microphone"===i)return"microphone";if("contacts"===i)return"contacts";if("contacts-limited"===i)return"contacts-limited";if("notifications"===i)return"notifications";if("calendar"===i)return"calendar";if("location"===i)return"location";if("location-always"===i)return"location-always";if("media-library"===i)return"media-library";if("motion"===i)return"motion";if("reminders"===i)return"reminders";if("siri"===i)return"siri";if("photos"===i){let e=t?.trim().toLowerCase();if(!e||"full"===e)return"photos";if("limited"===e)return"photos-add";throw new n("INVALID_ARGS",`Invalid photos mode: ${t}. Use full|limited.`)}throw new n("INVALID_ARGS",`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}(r?.permissionTarget,r?.permissionMode);await tt(e,t,o,a);return}default:throw new n("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function e5(e,t){return B(e)?await eu(t):"simulator"===e.kind?y(await e8(e),t):await I(e,t)}async function e8(e){return(await e9(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function e9(e){let t=(await eV(e,["listapps",e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let i=null;if(t.startsWith("{"))try{i=JSON.parse(t)}catch{i=null}if(!i&&t.startsWith("{"))try{let e=await A("plutil",["-convert","json","-o","-","-"],{allowFailure:!0,stdin:t});0===e.exitCode&&e.stdout.trim().startsWith("{")&&(i=JSON.parse(e.stdout))}catch{i=null}return i?Object.entries(i).map(([e,t])=>{let i=function(e){if(e.Path)return e.Path;if(e.Bundle)try{return r(e.Bundle)}catch{return}}(t);return{bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e,...i?{path:i}:{},...t.ApplicationType?{applicationType:t.ApplicationType}:{}}}):[]}async function e6(e){let t=await A("plutil",["-convert","json","-o","-",e],{allowFailure:!0});if(0!==t.exitCode)return new Set;try{let e=JSON.parse(t.stdout),i=new Set;for(let t of e.CFBundleURLTypes??[])if(Array.isArray(t.CFBundleURLSchemes))for(let e of t.CFBundleURLSchemes)"string"==typeof e&&e.trim()&&i.add(e.trim().toLowerCase());return i}catch{return new Set}}async function e7(e,t){let i=L(t);if("toggle"!==i)return i;let a=await eV(e,["ui",e.id,"appearance"],{allowFailure:!0});if(0!==a.exitCode)throw new n("COMMAND_FAILED","Failed to read current iOS appearance",{stdout:a.stdout,stderr:a.stderr,exitCode:a.exitCode});let r=function(e,t){let i=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}
8
+ ${t}`);if(!i)return null;let a=i[1]?.toLowerCase();return"dark"===a?"dark":"light"===a?"light":null}(a.stdout,a.stderr);if(!r)throw new n("COMMAND_FAILED","Unable to determine current iOS appearance for toggle",{stdout:a.stdout,stderr:a.stderr});return"dark"===r?"light":"dark"}let te={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function tt(e,t,i,a){let r=await ta(e);if(!r.has(i))throw new n("UNSUPPORTED_OPERATION",`iOS simctl privacy does not support service "${i}" on this runtime.`,{deviceId:e.id,appBundleId:a,hint:`Supported services: ${Array.from(r).sort().join(", ")}`});let o=["privacy",e.id,t,i,a],s="notifications"===i;if(!("reset"===t&&s))try{await eV(e,o);return}catch(t){if(!(s&&ti(t)))throw t;throw new n("UNSUPPORTED_OPERATION","iOS simulator does not support setting notifications permission via simctl privacy on this runtime.",{deviceId:e.id,appBundleId:a,hint:"Use reset notifications for reprompt behavior, or toggle notifications manually in Settings."})}try{await eV(e,o);return}catch(e){if(!ti(e))throw e}try{await eV(e,["privacy",e.id,"reset","all",a])}catch(t){throw new n("COMMAND_FAILED","iOS simulator blocked direct notifications reset. Fallback reset-all also failed.",{deviceId:e.id,appBundleId:a,hint:"Use reinstall to force a fresh notifications prompt, or reset simulator content and settings."},t instanceof Error?t:void 0)}}function ti(e){if(!(e instanceof n)||"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 ta(t){let i=$(t.simulatorSetPath),a=`${process.env.PATH??""}::${i??""}`;if(eB&&e===a)return eB;let r=await eV(t,["privacy","help"],{allowFailure:!0}),o=function(e){let t=new Set,i=!1;for(let a of e.split("\n")){let e=a.trim();if(!e)continue;if("service"===e){i=!0;continue}if(!i)continue;if(e.startsWith("bundle identifier"))break;let r=/^([a-z-]+)\s+-\s+/.exec(e),n=r?.[1];void 0!==n&&t.add(n)}return t}(`${r.stdout}
9
+ ${r.stderr}`);if(0===o.size)throw new n("COMMAND_FAILED","Unable to determine supported simctl privacy services",{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return eB=o,e=a,o}async function tr(e,t,i){let a=function(e,t,i){let a=i.length>0?i:["face"];switch(t){case"match":return a.flatMap(t=>[["biometric",e,"match",t],["biometric","match",e,t]]);case"nonmatch":return a.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,i.modalityAliases),r=[];for(let t of a){let i=f(e,t),a=await o(i,{allowFailure:!0});if(0===a.exitCode)return;r.push({args:i,stderr:a.stderr,stdout:a.stdout,exitCode:a.exitCode})}let s=D(r);if(r.length>0&&r.every(e=>{var t,i;let a;return t=e.stdout,i=e.stderr,(a=`${t}
10
+ ${i}`.toLowerCase()).includes("unrecognized subcommand")||a.includes("unknown subcommand")||a.includes("not supported")||a.includes("unavailable")||a.includes("biometric")&&a.includes("invalid")}))throw new n("UNSUPPORTED_OPERATION",`${i.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:t,setting:i.settingName,attempts:s});throw new n("COMMAND_FAILED",`Failed to simulate ${i.settingName}.`,{deviceId:e.id,action:t,setting:i.settingName,attempts:s})}async function tn(e,t,i){await V(e);let a=0,r=T.fromTimeoutMs(6e4);try{await E(async({deadline:a})=>{var r,s,l,d;let u;if(a?.isExpired())throw new n("COMMAND_FAILED","App launch deadline exceeded",{timeoutMs:6e4});let c=(s=e.id,l=t,d=i,u=["launch"],d?.launchConsole&&u.push("--console-pty"),d?.terminateRunningApp&&u.push("--terminate-running-process"),u.push(s,l),d?.launchArgs&&d.launchArgs.length>0&&u.push(...d.launchArgs),r=u,f(e,r)),p=i?.launchConsole?await to(c,i.launchConsole):await o(c,{allowFailure:!0});if(0!==p.exitCode)throw new n("COMMAND_FAILED",`xcrun exited with code ${p.exitCode}`,{cmd:"xcrun",args:c,stdout:p.stdout,stderr:p.stderr,exitCode:p.exitCode})},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>!!H(e)&&(a+=1)<3},{deadline:r})}catch(i){if(H(i)){var s;let a=(s=await z(e,t)).installed?!1===s.simulatorCompatible?"ARCH_MISMATCH":"PERSISTENT_LAUNCH_FAIL":"APP_NOT_INSTALLED";i.details={...i.details,hint:function(e){switch(e){case"ARCH_MISMATCH":return"The app binary was not built for the simulator platform. Rebuild with a simulator destination or use a physical device.";case"APP_NOT_INSTALLED":return"The app bundle is not installed on this simulator. Run install before open.";case"PERSISTENT_LAUNCH_FAIL":return"The simulator repeatedly refused to launch the app. Inspect crash logs in Console.app or ~/Library/Logs/DiagnosticReports/ and consider reinstalling the app.";default:return"The simulator failed to launch the app. Retry with --debug and inspect diagnostics log for details."}}(a)}}throw i}}async function to(e,i){await t.mkdir(a.dirname(i),{recursive:!0});try{let t=await o(e,{allowFailure:!0,timeoutMs:25e3});return await ts(i,t.stdout,t.stderr),t}catch(t){let e=(t instanceof n?t:void 0)?.details;if(e?.timeoutMs===25e3){let t="string"==typeof e.stdout?e.stdout:"",a="string"==typeof e.stderr?e.stderr:"";return await ts(i,t,a),v({level:"warn",phase:"ios_simulator_launch_console_capture_timeout",data:{timeoutMs:25e3,logPath:i,stdoutBytes:Buffer.byteLength(t),stderrBytes:Buffer.byteLength(a)}}),{stdout:t,stderr:a,exitCode:0}}throw t}}async function ts(e,i,a){var r,n;await t.writeFile(e,(r=i,n=a,!r||!n||r.endsWith("\n")||r.endsWith("\r")?`${r}${n}`:`${r}
11
+ ${n}`),"utf8")}async function tl(e,t,i){let a=["device","process","launch","--device",e.id,t];i?.payloadUrl&&a.push("--payload-url",i.payloadUrl),i?.launchArgs&&i.launchArgs.length>0&&a.push("--",...i.launchArgs),await h(a,{action:"launch iOS app",deviceId:e.id})}export{eJ as closeIosApp,eX as installIosApp,e0 as installIosInstallablePath,e5 as listIosApps,eH as openIosApp,eq as openIosDevice,q as prepareIosInstallArtifact,e4 as pushIosNotification,e1 as readIosClipboardText,eY as reinstallIosApp,eW as resolveIosApp,eK as resolveIosSimulatorDeepLinkBundleId,eL as screenshotIos,e3 as setIosSetting,e2 as writeIosClipboardText};
@@ -1 +1 @@
1
- import{startMacOsAudioProbeProcess as e}from"./9722.js";let t={platform:"host-system-audio",source:"system-audio",backend:"macos-screencapturekit",sourceCount:1,start:e,notes:function(e){let t="ios"===e.platform?"iOS simulator":"android"===e.platform?"Android emulator":"macOS session";return[`Audio probe samples host system audio through ScreenCaptureKit for this ${t}; it is not app-instrumented audio.`,"Screen Recording permission is required for host system audio capture.","Other audible host apps can contribute to the measured buckets."]}};export{t as macOsScreenCaptureKitAudioProbeBackend};
1
+ import{isIosFamily as e}from"./6849.js";import{startMacOsAudioProbeProcess as t}from"./9722.js";let o={platform:"host-system-audio",source:"system-audio",backend:"macos-screencapturekit",sourceCount:1,start:t,notes:function(t){let o=e(t)?"iOS simulator":"android"===t.platform?"Android emulator":"macOS session";return[`Audio probe samples host system audio through ScreenCaptureKit for this ${o}; it is not app-instrumented audio.`,"Screen Recording permission is required for host system audio capture.","Other audible host apps can contribute to the measured buckets."]}};export{o as macOsScreenCaptureKitAudioProbeBackend};
@@ -146,7 +146,7 @@ declare const LEASE_BACKENDS: readonly ['ios-simulator', 'ios-instance', 'androi
146
146
 
147
147
  declare type LeaseBackend = (typeof LEASE_BACKENDS)[number];
148
148
 
149
- declare const PLATFORM_SELECTORS: readonly ["ios", "macos", "android", "linux", "web", "apple"];
149
+ declare const PLATFORM_SELECTORS: readonly ["apple", "android", "linux", "web", "ios", "macos"];
150
150
 
151
151
  declare type PlatformSelector = (typeof PLATFORM_SELECTORS)[number];
152
152
 
@@ -5,6 +5,9 @@ Version-matched operating guide for normal agent-device work.
5
5
  Core loop:
6
6
  devices/apps -> open -> snapshot or snapshot -i -> get/is/find/wait or press/fill/scroll/back -> verify -> close
7
7
 
8
+ Fresh machine or first iOS run:
9
+ Run agent-device doctor --platform ios first. Besides preflight checks it warms the iOS XCTest runner build cache in the background, so the first open skips the runner build (~10s). To block until fully warm instead, run agent-device prepare ios-runner.
10
+
8
11
  Command shape:
9
12
  Plans should use agent-device commands, not raw platform tools, pseudo commands, package-manager aliases, or helper prose.
10
13
  If the user asks for a command plan, final output should be command lines only: no intro sentence, numbered list, Markdown fence, shell pipe, grep/head/tail helper, or explanatory bullets.
@@ -207,6 +210,7 @@ Logs:
207
210
  Do not cat a full stale log into agent context. Open or grep only the relevant window when needed.
208
211
  logs clear --restart is the compact command to clear old logs and start a fresh capture; do not split it into logs stop, logs clear, logs start.
209
212
  On iOS simulators, logs scope by bundle id and resolved app executable, so use this instead of raw simctl log stream predicates.
213
+ On iOS physical devices, logs clear --restart relaunches the session app through devicectl process launch --console so stdout/stderr can be captured.
210
214
  For iOS simulator launch-time stdout/stderr, use --launch-console on the direct app launch:
211
215
  agent-device open MyApp --platform ios --relaunch --launch-console ./artifacts/app.console.log
212
216
  --launch-console is only for direct iOS simulator app launches, not URL opens.
@@ -255,7 +259,9 @@ Alerts:
255
259
 
256
260
  Diagnostics and traces:
257
261
  Use --debug for CLI/daemon diagnostic ids and log paths.
262
+ Use AGENT_DEVICE_EXEC_TRACE=1 when you need host-tool spawn timing without full debug streaming; it flushes the full request diagnostics file on successful requests that spawn host tools.
258
263
  Open output includes Session state; JSON also includes runnerLogPath and requestLogPath.
264
+ For open timing under --debug, run open --debug --json and inspect requestLogPath for the open_timing event.
259
265
  Session requests/<request-id>.ndjson holds daemon request diagnostics; session runner.log holds Apple runner/xcodebuild output.
260
266
  daemon.log is global daemon lifecycle evidence, not the primary per-run log.
261
267
  Use trace for low-level session diagnostics around one repro:
@@ -423,7 +429,7 @@ Choose the next help topic:
423
429
  Remote/cloud config, leases, and local service tunnels: help remote.
424
430
 
425
431
  React Native dev loop:
426
- Before QA/dogfood runs, use doctor to separate environment setup from app failures:
432
+ Before QA/dogfood runs, use doctor to separate environment setup from app failures (on iOS simulators doctor also warms the runner build cache in the background):
427
433
  agent-device doctor --platform android
428
434
  agent-device doctor --platform ios
429
435
  agent-device doctor --platform android --app com.example.app
@@ -541,6 +547,7 @@ Direct proxy flow for a remote Mac/simulator:
541
547
  agent-device devices --platform ios
542
548
  agent-device open Maps --platform ios --device "iPhone 17 Pro"
543
549
  agent-device snapshot -i --platform ios --device "iPhone 17 Pro"
550
+ agent-device artifacts --json
544
551
  agent-device close
545
552
  agent-device disconnect
546
553
 
@@ -729,10 +736,10 @@ Rules:
729
736
  Prefer refs for exploration and selectors for deterministic replay.
730
737
  Use logs, network, screenshot --overlay-refs, trace, perf metrics, perf frames, or react-devtools only when they add evidence to a specific issue.
731
738
  Never delete screenshots, videos, traces, or report artifacts during a session.
732
- Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function h(e){let t=e.endsWith("?"),a=t?e.slice(0,-1):e;return t?`[${a}]`:`<${a}>`}function m(){let a,o,p,h,m,b,w,y,k;return a=`agent-device <command> [args] [--json]
739
+ Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function h(e){let t=e.endsWith("?"),a=t?e.slice(0,-1):e;return t?`[${a}]`:`<${a}>`}function u(){let a,o,p,h,u,b,w,y,k;return a=`agent-device <command> [args] [--json]
733
740
 
734
741
  CLI to automate supported app, device, desktop, and web targets for AI agents.
735
- `,o=g("Commands:",e().map(e=>{let a=t(e);return{name:e,schema:a,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let a=(t.positionalArgs??[]).map(a=>{var o,s,n;let r,i,c,d;return o=e,s=t,i=(r=(n=a).endsWith("?"))?n.slice(0,-1):n,d=(c=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${o} ${i}`),r?c?`[${i}]`:d?i:`[${i}]`:d?i:`<${i}>`});return[e,...a].join(" ")}(e,a)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),p=f("Global Flags:",u(s)),h=v("Agent Starting Point:",r),m=v("Agent Quickstart:",i),b=g("Agent Workflows:",n),w=v("Configuration:",c),y=g("Environment:",d),k=v("Examples:",l),`${a}
742
+ `,o=g("Commands:",e().map(e=>{let a=t(e);return{name:e,schema:a,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let a=(t.positionalArgs??[]).map(a=>{var o,s,n;let r,i,c,d;return o=e,s=t,i=(r=(n=a).endsWith("?"))?n.slice(0,-1):n,d=(c=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${o} ${i}`),r?c?`[${i}]`:d?i:`[${i}]`:d?i:`<${i}>`});return[e,...a].join(" ")}(e,a)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),p=f("Global Flags:",m(s)),h=v("Agent Starting Point:",r),u=v("Agent Quickstart:",i),b=g("Agent Workflows:",n),w=v("Configuration:",c),y=g("Environment:",d),k=v("Examples:",l),`${a}
736
743
  ${h}
737
744
 
738
745
  ${b}
@@ -741,14 +748,14 @@ ${o}
741
748
 
742
749
  ${p}
743
750
 
744
- ${m}
751
+ ${u}
745
752
 
746
753
  ${w}
747
754
 
748
755
  ${y}
749
756
 
750
757
  ${k}
751
- `}function u(e){return o().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function f(e,t){return g(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function g(e,t){if(0===t.length)return`${e}
758
+ `}function m(e){return o().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function f(e,t){return g(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function g(e,t){if(0===t.length)return`${e}
752
759
  (none)`;let a=Math.max(...t.map(e=>e.label.length))+2,o=[e];for(let e of t)o.push(` ${e.label.padEnd(a)}${e.description}`);return o.join("\n")}function v(e,t){return 0===t.length?`${e}
753
760
  (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}function b(e){var t,s;let n,r=(n=p[e])?`${n.body}
754
761
 
@@ -756,12 +763,12 @@ Related:
756
763
  agent-device help command list and global flags
757
764
  agent-device help <command> command-specific flags
758
765
  agent-device help workflow normal app automation loop
759
- `:null;if(r)return r;let i=a(e);if(!i)return null;let c=(t=e,(s=i).usageOverride?s.usageOverride:[t,...(s.positionalArgs??[]).map(h),...(s.allowedFlags??[]).flatMap(e=>{var t;return(t=e,o().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=u(new Set(i.allowedFlags??[])),l=[];d.length>0&&l.push(f("Command flags:",d));let m=l.length>0?`
766
+ `:null;if(r)return r;let i=a(e);if(!i)return null;let c=(t=e,(s=i).usageOverride?s.usageOverride:[t,...(s.positionalArgs??[]).map(h),...(s.allowedFlags??[]).flatMap(e=>{var t;return(t=e,o().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=m(new Set(i.allowedFlags??[])),l=[];d.length>0&&l.push(f("Command flags:",d));let u=l.length>0?`
760
767
 
761
768
  ${l.join("\n\n")}`:"";return`agent-device ${c}
762
769
 
763
770
  ${i.helpDescription}
764
771
 
765
772
  Usage:
766
- agent-device ${c}${m}
767
- `}export{b as buildCommandUsageText,m as buildUsageText};
773
+ agent-device ${c}${u}
774
+ `}export{b as buildCommandUsageText,u as buildUsageText};