agent-device 0.17.2 → 0.17.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 (83) hide show
  1. package/README.md +2 -2
  2. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.apk → agent-device-android-multitouch-helper-0.17.3.apk} +0 -0
  3. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.3.apk.sha256 +1 -0
  4. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.2.manifest.json → agent-device-android-multitouch-helper-0.17.3.manifest.json} +4 -4
  5. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.apk → agent-device-android-snapshot-helper-0.17.3.apk} +0 -0
  6. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.3.apk.sha256 +1 -0
  7. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.2.manifest.json → agent-device-android-snapshot-helper-0.17.3.manifest.json} +6 -6
  8. package/dist/src/123.js +1 -1
  9. package/dist/src/1231.js +1 -1
  10. package/dist/src/1352.js +1 -1
  11. package/dist/src/221.js +2 -2
  12. package/dist/src/2403.js +3 -3
  13. package/dist/src/2415.js +36 -29
  14. package/dist/src/5611.js +1 -0
  15. package/dist/src/5827.js +1 -0
  16. package/dist/src/6088.js +1 -0
  17. package/dist/src/6133.js +1 -0
  18. package/dist/src/7847.js +1 -1
  19. package/dist/src/9471.js +1 -1
  20. package/dist/src/9542.js +6 -3
  21. package/dist/src/9616.js +2 -1
  22. package/dist/src/9818.js +1 -1
  23. package/dist/src/android-snapshot-helper.d.ts +0 -1
  24. package/dist/src/android.js +5 -5
  25. package/dist/src/apple.js +1 -1
  26. package/dist/src/apps.js +10 -10
  27. package/dist/src/args.js +53 -14
  28. package/dist/src/batch.js +1 -1
  29. package/dist/src/cli-output.js +29 -0
  30. package/dist/src/cli.js +15 -16
  31. package/dist/src/command-surface.js +1 -1
  32. package/dist/src/contracts.d.ts +52 -0
  33. package/dist/src/contracts.js +1 -1
  34. package/dist/src/find.js +1 -1
  35. package/dist/src/generic.js +5 -5
  36. package/dist/src/index.d.ts +111 -8
  37. package/dist/src/index.js +1 -1
  38. package/dist/src/input-actions.js +1 -1
  39. package/dist/src/interaction.js +1 -1
  40. package/dist/src/react-native.js +1 -1
  41. package/dist/src/record-trace-recording.js +3 -3
  42. package/dist/src/selector-runtime.js +1 -1
  43. package/dist/src/selectors.d.ts +14 -0
  44. package/dist/src/selectors.js +1 -1
  45. package/dist/src/server.js +2 -2
  46. package/dist/src/session.js +8 -10
  47. package/dist/src/snapshot.js +2 -2
  48. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests-Bridging-Header.h +1 -0
  49. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +14 -0
  50. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +297 -0
  51. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +328 -0
  52. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +121 -172
  53. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +153 -5
  54. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +171 -0
  55. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -10
  56. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +64 -18
  57. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +200 -0
  58. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +406 -0
  59. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +82 -169
  60. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +425 -0
  61. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +77 -6
  62. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +10 -1
  63. package/ios-runner/README.md +5 -5
  64. package/ios-runner/RUNNER_PROTOCOL.md +0 -1
  65. package/package.json +3 -3
  66. package/server.json +2 -2
  67. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.2.apk.sha256 +0 -1
  68. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.2.apk.sha256 +0 -1
  69. package/dist/src/1534.js +0 -1
  70. package/dist/src/1620.js +0 -1
  71. package/dist/src/1644.js +0 -2
  72. package/dist/src/2284.js +0 -1
  73. package/dist/src/2474.js +0 -1
  74. package/dist/src/2672.js +0 -1
  75. package/dist/src/3393.js +0 -1
  76. package/dist/src/5898.js +0 -1
  77. package/dist/src/695.js +0 -1
  78. package/dist/src/7455.js +0 -1
  79. package/dist/src/8173.js +0 -27
  80. package/dist/src/8407.js +0 -1
  81. package/dist/src/8699.js +0 -1
  82. package/dist/src/9673.js +0 -1
  83. package/dist/src/9974.js +0 -1
package/dist/src/apps.js CHANGED
@@ -1,13 +1,13 @@
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"./9152.js";import{runXcrun as o,IOS_RUNNER_CONTAINER_BUNDLE_IDS as l,resolveIosDevicectlHint as s,LAUNCH_CONSOLE_DIRECT_APP_ONLY_MESSAGE as d,runIosRunnerCommand as u,resolveAppleToolProvider as c,runSimctlForDevice as p,IOS_DEVICECTL_DEFAULT_HINT as f,requireSimulatorDevice as w,buildSimctlArgsForDevice as m,runMacOsPermissionAction as h,parseXmlDocumentSync as y,runIosDevicectl as A,filterAppleAppsByBundlePrefix as I,runAppleToolCommand as g,listIosDeviceApps as v,quitMacOsApp as _,visitXmlPlistEntries as C,ensureBootedSimulator as b,readApplePlistJson as N,LAUNCH_CONSOLE_IOS_SIMULATOR_ONLY_MESSAGE as S,getSimulatorState as L}from"./2415.js";import{runCmd as D}from"./9818.js";import{materializeInstallablePath as M,isTrustedInstallSourceUrl as O}from"./989.js";import{parseAppearanceAction as P,summarizeCommandAttemptFailures as x,parseSettingState as F,parsePermissionTarget as R,parsePermissionAction as $}from"./6629.js";import{createAppResolutionCache as E,isDeepLinkTarget as k,resolveIosSimulatorDeviceSetPath as T,resolveIosDeviceDeepLinkBundleId as U,retryWithPolicy as B,Deadline as G}from"./8806.js";import{emitDiagnostic as V}from"./7599.js";import{requireLocationCoordinates as j}from"./9673.js";import{getUnsupportedMacOsSettingMessage as W}from"./1352.js";function K(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 H(e,t){let i=await o(m(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 g("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 g("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 z(e,i){try{let t=await N(e),a=t?.[i];if("string"==typeof a&&a.length>0)return a}catch{}try{let t=await g("plutil",["-extract",i,"raw","-o","-",e],{allowFailure:!0});if(0===t.exitCode){let e=String(t.stdout??"").trim();if(e.length>0)return e}}catch{}try{var a,r;let n;return a=await t.readFile(e,"utf8"),r=i,C(y(a),(e,t)=>{void 0===n&&e===r&&"string"===t.name&&(n=t.text??void 0)}),n}catch{return}}async function q(e,t){let i;if("url"===e.kind&&!O(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 M({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||O(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([z(t,"CFBundleIdentifier"),z(t,"CFBundleDisplayName"),z(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-")),l=async()=>{await t.rm(o,{recursive:!0,force:!0})};try{await D("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 Q(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(X).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(X).join(", ")}`)}catch(e){throw await l(),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=E();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(!k(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(k(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 el(e){await ec().writeClipboard(e)}async function es(){return await ec().readDarkMode()}async function ed(e){let t=P(e),i="toggle"===t?!await es():"dark"===t;await ec().setDarkMode(i)}async function eu(e){return await ec().listApps(e)}function ec(){let e=c().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"};async function ey(e){let t=null,i=!1;try{t=await eI(e),i=!0}catch(t){e_(e,"snapshot_failed",t)}try{await eg(e),await ev(e,ef)}catch(t){e_(e,"prepare_failed",t)}return async()=>{await eA(e,i?t:null)}}async function eA(e,t){var i,a;let r;await eg(e),t&&await ev(e,(r=[],(i=t).dataNetwork&&r.push("--dataNetwork",i.dataNetwork),i.wifiMode&&r.push("--wifiMode",i.wifiMode),void 0!==i.wifiBars&&("wifi"===i.dataNetwork||i.wifiMode)&&r.push("--wifiBars",i.wifiBars),i.cellularMode&&r.push("--cellularMode",i.cellularMode),void 0!==i.cellularBars&&(i.cellularMode||(a=i.dataNetwork)&&"hide"!==a&&"wifi"!==a||void 0!==i.operatorName)&&r.push("--cellularBars",i.cellularBars),void 0!==i.operatorName&&r.push("--operatorName",i.operatorName),r))}async function eI(e){var t;let i=await (t=["status_bar",e.id,"list"],p(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 eg(e){await p(e,["status_bar",e.id,"clear"],void 0)}async function ev(e,t){0!==t.length&&await p(e,["status_bar",e.id,"override",...t],void 0)}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)}})}let eC={ensureBooted:b,prepareStatusBarForScreenshot:ey,captureWithRetry:eS,captureWithRunner:eL,shouldFallbackToRunner:eF};async function eb(e,t,i,a,r){if("macos"===e.platform)return void await eL(e,t,i,a,r);if("simulator"===e.kind)return void await eN(e,t,i,a,void 0,r);try{await A(["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.details??{},i="string"==typeof t.stdout?t.stdout:"",a="string"==typeof t.stderr?t.stderr:"",r=`${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"./9152.js";import{runXcrun as o,IOS_RUNNER_CONTAINER_BUNDLE_IDS as l,resolveIosDevicectlHint as s,LAUNCH_CONSOLE_DIRECT_APP_ONLY_MESSAGE as d,runIosRunnerCommand as u,resolveAppleToolProvider as c,runSimctlForDevice as p,IOS_DEVICECTL_DEFAULT_HINT as f,readInfoPlistString as w,requireSimulatorDevice as m,buildSimctlArgsForDevice as h,runMacOsPermissionAction as y,runIosDevicectl as A,filterAppleAppsByBundlePrefix as I,runAppleToolCommand as v,listIosDeviceApps as g,quitMacOsApp as _,ensureBootedSimulator as C,LAUNCH_CONSOLE_IOS_SIMULATOR_ONLY_MESSAGE as b,getSimulatorState as N}from"./2415.js";import{runCmd as S}from"./9818.js";import{materializeInstallablePath as L,isTrustedInstallSourceUrl as D}from"./989.js";import{parseAppearanceAction as M,summarizeCommandAttemptFailures as O,parseSettingState as P,parsePermissionTarget as F,parsePermissionAction as x}from"./6629.js";import{isWebUrl as R,createAppResolutionCache as $,isDeepLinkTarget as E,resolveIosSimulatorDeviceSetPath as k,resolveIosDeviceDeepLinkBundleId as T,retryWithPolicy as U,Deadline as B}from"./8806.js";import{emitDiagnostic as G}from"./7599.js";import{getUnsupportedMacOsSettingMessage as V,requireLocationCoordinates as j}from"./6133.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 H(e,t){let i=await o(h(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 v("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 v("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 K(e,t){let i;if("url"===e.kind&&!D(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 L({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||D(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([w(t,"CFBundleIdentifier"),w(t,"CFBundleDisplayName"),w(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 S("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=$();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(!E(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(E(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=M(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=c().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"};async function em(e){let t=null,i=!1;try{t=await ey(e),i=!0}catch(t){ev(e,"snapshot_failed",t)}try{await eA(e),await eI(e,ec)}catch(t){ev(e,"prepare_failed",t)}return async()=>{await eh(e,i?t:null)}}async function eh(e,t){var i,a;let r;await eA(e),t&&await eI(e,(r=[],(i=t).dataNetwork&&r.push("--dataNetwork",i.dataNetwork),i.wifiMode&&r.push("--wifiMode",i.wifiMode),void 0!==i.wifiBars&&("wifi"===i.dataNetwork||i.wifiMode)&&r.push("--wifiBars",i.wifiBars),i.cellularMode&&r.push("--cellularMode",i.cellularMode),void 0!==i.cellularBars&&(i.cellularMode||(a=i.dataNetwork)&&"hide"!==a&&"wifi"!==a||void 0!==i.operatorName)&&r.push("--cellularBars",i.cellularBars),void 0!==i.operatorName&&r.push("--operatorName",i.operatorName),r))}async function ey(e){var t;let i=await (t=["status_bar",e.id,"list"],p(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 eA(e){await p(e,["status_bar",e.id,"clear"],void 0)}async function eI(e,t){0!==t.length&&await p(e,["status_bar",e.id,"override",...t],void 0)}function ev(e,t,i){G({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...eu(i)}})}let eg={ensureBooted:C,prepareStatusBarForScreenshot:em,captureWithRetry:eb,captureWithRunner:eN,shouldFallbackToRunner:eP};async function e_(e,t,i,a,r){if("macos"===e.platform)return void await eN(e,t,i,a,r);if("simulator"===e.kind)return void await eC(e,t,i,a,void 0,r);try{await A(["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.details??{},i="string"==typeof t.stdout?t.stdout:"",a="string"==typeof t.stderr?t.stderr:"",r=`${e.message}
2
2
  ${i}
3
- ${a}`.toLowerCase();return r.includes("unknown option '--device'")||r.includes("unknown subcommand")&&r.includes("screenshot")||r.includes("unrecognized subcommand")&&r.includes("screenshot")}(t))throw t;eP(e,"devicectl_screenshot",t)}await eL(e,t,i,a,r)}async function eN(e,t,i,a,r=eC,o){if("simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");let l="object"==typeof a&&null!==a?a:r;await l.ensureBooted(e);let s=async()=>{};try{s=await l.prepareStatusBarForScreenshot(e)}catch(t){ex(e,"prepare_failed",t)}try{try{await l.captureWithRetry(e,t);return}catch(t){if(!l.shouldFallbackToRunner(t))throw t;eP(e,"simctl_screenshot",t)}await l.captureWithRunner(e,t,i,"boolean"==typeof a?a:void 0,o)}finally{await s().catch(t=>ex(e,"restore_failed",t))}}async function eS(e,t){let i=G.fromTimeoutMs(2e4);await B(async({deadline:i})=>{var a;await (a=["io",e.id,"screenshot",t],p(e,a,{timeoutMs:Math.max(1e3,i?.remainingMs()??2e4)}))},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>eF(e)},{deadline:i,phase:"ios_simulator_screenshot"})}async function eL(e,i,a,r,o){let l=(await u(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 eM(e,l,i):await eD(e,l,i)}async function eD(e,t,i){let a=G.fromTimeoutMs(2e4),r={exitCode:1,stdout:"",stderr:""};for(let n of l)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:eO(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 eM(e,i,r){let o=G.fromTimeoutMs(2e4),s="Unable to locate runner container for simulator screenshot";for(let n of l){var d;let l=await (d=["get_app_container",e.id,n,"data"],p(e,d,{allowFailure:!0,timeoutMs:eO(o,2e4,"runner screenshot container lookup")}));if(0!==l.exitCode){let e=l.stderr.trim();e&&(s=e);continue}let u=l.stdout.trim();if(!u){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,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}(u,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 eO(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 eP(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 ex(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 eF(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;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(" "):"",o=`${e.message}
3
+ ${a}`.toLowerCase();return r.includes("unknown option '--device'")||r.includes("unknown subcommand")&&r.includes("screenshot")||r.includes("unrecognized subcommand")&&r.includes("screenshot")}(t))throw t;eM(e,"devicectl_screenshot",t)}await eN(e,t,i,a,r)}async function eC(e,t,i,a,r=eg,o){if("simulator"!==e.kind)throw new n("UNSUPPORTED_OPERATION","Simulator screenshot fallback flow supports only iOS simulators");let l="object"==typeof a&&null!==a?a:r;await l.ensureBooted(e);let s=async()=>{};try{s=await l.prepareStatusBarForScreenshot(e)}catch(t){eO(e,"prepare_failed",t)}try{try{await l.captureWithRetry(e,t);return}catch(t){if(!l.shouldFallbackToRunner(t))throw t;eM(e,"simctl_screenshot",t)}await l.captureWithRunner(e,t,i,"boolean"==typeof a?a:void 0,o)}finally{await s().catch(t=>eO(e,"restore_failed",t))}}async function eb(e,t){let i=B.fromTimeoutMs(2e4);await U(async({deadline:i})=>{var a;await (a=["io",e.id,"screenshot",t],p(e,a,{timeoutMs:Math.max(1e3,i?.remainingMs()??2e4)}))},{maxAttempts:5,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry:e=>eP(e)},{deadline:i,phase:"ios_simulator_screenshot"})}async function eN(e,i,a,r,o){let l=(await u(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 eL(e,l,i):await eS(e,l,i)}async function eS(e,t,i){let a=B.fromTimeoutMs(2e4),r={exitCode:1,stdout:"",stderr:""};for(let n of l)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:eD(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 eL(e,i,r){let o=B.fromTimeoutMs(2e4),s="Unable to locate runner container for simulator screenshot";for(let n of l){var d;let l=await (d=["get_app_container",e.id,n,"data"],p(e,d,{allowFailure:!0,timeoutMs:eD(o,2e4,"runner screenshot container lookup")}));if(0!==l.exitCode){let e=l.stderr.trim();e&&(s=e);continue}let u=l.stdout.trim();if(!u){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,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}(u,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 eD(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 eM(e,t,i){let a=eu(i);G({level:"warn",phase:"ios_screenshot_fallback",data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:"runner",...a}})}function eO(e,t,i){G({level:"warn",phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...eu(i)}})}function eP(e){if(!(e instanceof n)||"COMMAND_FAILED"!==e.code)return!1;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(" "):"",o=`${e.message}
4
4
  ${i}
5
5
  ${a}
6
- ${r}`.toLowerCase();return o.includes("timeout waiting for screen surfaces")||o.includes("nsposixerrordomain")&&o.includes("code=60")&&o.includes("screenshot")||o.includes("timed out")&&o.includes("screenshot")}let eR={settings:"com.apple.Preferences"},e$=E(),eE=null;function ek(e){return{platform:"ios",deviceId:e.id,variant:e.kind}}function eT(e,t,i){return o(m(e,t),i)}function eU(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function eB(e,t){if("macos"===e.platform)return await ea(t);let i=t.trim();if(i.includes("."))return i;let a=eR[i.toLowerCase()];if(a)return a;let r=ek(e),o=e$.get(r,i);if(o)return o;let l=("simulator"===e.kind?await e2(e):await v(e,"all")).filter(e=>e.name.toLowerCase()===i.toLowerCase()),s=l[0];if(void 0!==s&&1===l.length)return e$.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 eG(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 e3(e),l=[];for(let e of o)!e.bundleId.startsWith("com.callstack.agentdevice.runner")&&e.path&&(await e5(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 eV(e,t,i){let a=i?.launchConsole?.trim(),r=i?.launchArgs;if(a&&("ios"!==e.platform||"simulator"!==e.kind))throw new n("UNSUPPORTED_OPERATION",S);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 er(e,t,i);return}let o=i?.url?.trim();if(o){if(a)throw new n("INVALID_ARGS",d);if(!k(o))throw new n("INVALID_ARGS","open <app> <url> requires a valid URL target");if("simulator"===e.kind){let a=i?.appBundleId??await eB(e,t);await tt(e,a,{...r?{launchArgs:r}:{}}),await ej(e,o,void 0);return}let l=U(i?.appBundleId??await eB(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 tr(e,l,{payloadUrl:o,launchArgs:r});return}let l=t.trim();if(k(l)){if(a)throw new n("INVALID_ARGS",d);if("simulator"===e.kind)return void await ej(e,l,r);let t=U(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 tr(e,t,{payloadUrl:l,launchArgs:r})}let s=i?.appBundleId??await eB(e,t);"simulator"===e.kind?await tt(e,s,{...a?{launchConsole:a}:{},...r?{launchArgs:r}:{}}):await tr(e,s,{launchArgs:r})}async function ej(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 eT(e,["openurl",e.id,t])}async function eW(e){"macos"===e.platform||"simulator"!==e.kind||"Booted"!==await L(e)&&await b(e)}async function eK(e,t){if("macos"===e.platform)return void await en(e,t);let i=await eB(e,t);if("simulator"===e.kind){await b(e);let t=m(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 A(["device","process","terminate","--device",e.id,i],{action:"terminate iOS app",deviceId:e.id})}async function eH(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 eB(e,i);await b(e),await eK(e,r);let o=await eT(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 ez(e,t){return await e$.invalidateWhile(ek(e),async()=>{let i=await eB(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(!eU(`${r}
7
- ${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)??f})}return{bundleId:i}}await b(e);let a=await eT(e,["uninstall",e.id,i],{allowFailure:!0});if(0!==a.exitCode&&!eU(`${a.stdout}
8
- ${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 eq(e,t,i){let a=await q({kind:"path",path:t},i);try{return await eZ(e,a.installablePath),{archivePath:a.archivePath,installablePath:a.installablePath,bundleId:a.bundleId,appName:a.appName,launchTarget:a.bundleId}}finally{await a.cleanup()}}async function eJ(e,t,i){return await e$.invalidateWhile(ek(e),async()=>{let{bundleId:a}=await ez(e,t);return await eq(e,i,{appIdentifierHint:t}),{bundleId:a}})}async function eZ(e,t){await e$.invalidateWhile(ek(e),async()=>{"simulator"!==e.kind?await A(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await b(e),await eT(e,["install",e.id,t]))})}async function eQ(e){if("macos"===e.platform)return await eo();w(e,"clipboard"),await b(e);let t=await eT(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 eX(e,t){if("macos"===e.platform)return void await el(t);w(e,"clipboard"),await b(e);let i=await eT(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 eY(e,r,n){w(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)}
9
- `,"utf8"),await eT(e,["push",e.id,r,l])}finally{await t.rm(o,{recursive:!0,force:!0})}}async function e0(e,t,i,a,r){if("macos"===e.platform){let e=t.toLowerCase();if("appearance"===e)return void await ed(i);if("permission"===e){let e=$(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 h(e,t)}throw new n("INVALID_ARGS",W(t))}w(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 eH(e,a);return{bundleId:t.bundleId,containerPath:t.containerPath,cleared:!0}}case"wifi":{let t=F(i);await eT(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(F(i)?await eT(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await eT(e,["status_bar",e.id,"clear"]));case"location":{if("set"===i.toLowerCase()){let{latitude:t,longitude:i}=j(r);return await eT(e,["location",e.id,"set",`${t},${i}`]),{latitude:t,longitude:i}}let t=F(i);if(!a)throw new n("INVALID_ARGS","location setting requires an active app in session");await eT(e,["privacy",e.id,t?"grant":"revoke","location",a]);return}case"faceid":case"touchid":{let t=e9[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 te(e,a,{settingName:o,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await e4(e,i);await eT(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=$(i))?"revoke":l,o=function(e,t){let i=R(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 e8(e,t,o,a);return}default:throw new n("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function e1(e,t){return"macos"===e.platform?await eu(t):"simulator"===e.kind?I(await e2(e),t):await v(e,t)}async function e2(e){return(await e3(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function e3(e){let t=(await eT(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 g("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 e5(e){let t=await g("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 e4(e,t){let i=P(t);if("toggle"!==i)return i;let a=await eT(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}
10
- ${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 e9={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function e8(e,t,i,a){let r=await e7(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 eT(e,o);return}catch(t){if(!(l&&e6(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 eT(e,o);return}catch(e){if(!e6(e))throw e}try{await eT(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 e6(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 e7(t){let i=T(t.simulatorSetPath),a=`${process.env.PATH??""}::${i??""}`;if(eE&&e===a)return eE;let r=await eT(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}
11
- ${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 eE=o,e=a,o}async function te(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=m(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=x(r);if(r.length>0&&r.every(e=>{var t,i;let a;return t=e.stdout,i=e.stderr,(a=`${t}
12
- ${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 tt(e,t,i){await b(e);let a=0,r=G.fromTimeoutMs(6e4);try{await B(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,m(e,r)),p=i?.launchConsole?await ti(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=>!!K(e)&&(a+=1)<3},{deadline:r})}catch(i){if(K(i)){var l;let a=(l=await H(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 ti(e,i){await t.mkdir(a.dirname(i),{recursive:!0});try{let t=await o(e,{allowFailure:!0,timeoutMs:25e3});return await ta(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 ta(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 ta(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}
13
- ${n}`),"utf8")}async function tr(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 A(a,{action:"launch iOS app",deviceId:e.id})}export{eK as closeIosApp,eq as installIosApp,eZ as installIosInstallablePath,e1 as listIosApps,eV as openIosApp,eW as openIosDevice,q as prepareIosInstallArtifact,eY as pushIosNotification,z as readInfoPlistString,eQ as readIosClipboardText,eJ as reinstallIosApp,eB as resolveIosApp,eG as resolveIosSimulatorDeepLinkBundleId,eb as screenshotIos,e0 as setIosSetting,eX as writeIosClipboardText};
6
+ ${r}`.toLowerCase();return o.includes("timeout waiting for screen surfaces")||o.includes("nsposixerrordomain")&&o.includes("code=60")&&o.includes("screenshot")||o.includes("timed out")&&o.includes("screenshot")}let eF={settings:"com.apple.Preferences"},ex=$(),eR=null;function e$(e){return{platform:"ios",deviceId:e.id,variant:e.kind}}function eE(e,t,i){return o(h(e,t),i)}function ek(e){return e.includes("not installed")||e.includes("not found")||e.includes("no such file")}async function eT(e,t){if("macos"===e.platform)return await et(t);let i=t.trim();if(i.includes("."))return i;let a=eF[i.toLowerCase()];if(a)return a;let r=e$(e),o=ex.get(r,i);if(o)return o;let l=("simulator"===e.kind?await e0(e):await g(e,"all")).filter(e=>e.name.toLowerCase()===i.toLowerCase()),s=l[0];if(void 0!==s&&1===l.length)return ex.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 eU(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 e1(e),l=[];for(let e of o)!e.bundleId.startsWith("com.callstack.agentdevice.runner")&&e.path&&(await e2(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 eB(e,t,i){let a=i?.launchConsole?.trim(),r=i?.launchArgs;if(a&&("ios"!==e.platform||"simulator"!==e.kind))throw new n("UNSUPPORTED_OPERATION",b);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",d);if(!E(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 eT(e,t);await e7(e,a,{...r?{launchArgs:r}:{}})}await eG(e,o,void 0);return}let l=T(i?.appBundleId??await eT(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 ti(e,l,{payloadUrl:o,launchArgs:r});return}let l=t.trim();if(E(l)){if(a)throw new n("INVALID_ARGS",d);if("simulator"===e.kind)return void await eG(e,l,r);let t=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 ti(e,t,{payloadUrl:l,launchArgs:r})}let s=i?.appBundleId??await eT(e,t);"simulator"===e.kind?await e7(e,s,{...a?{launchConsole:a}:{},...r?{launchArgs:r}:{}}):await ti(e,s,{launchArgs:r})}async function eG(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 C(e),await eE(e,["openurl",e.id,t])}async function eV(e){"macos"===e.platform||"simulator"!==e.kind||"Booted"!==await N(e)&&await C(e)}async function ej(e,t){if("macos"===e.platform)return void await ea(e,t);let i=await eT(e,t);if("simulator"===e.kind){await C(e);let t=h(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 A(["device","process","terminate","--device",e.id,i],{action:"terminate iOS app",deviceId:e.id})}async function eW(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 eT(e,i);await C(e),await ej(e,r);let o=await eE(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 eH(e,t){return await ex.invalidateWhile(e$(e),async()=>{let i=await eT(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(!ek(`${r}
7
+ ${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)??f})}return{bundleId:i}}await C(e);let a=await eE(e,["uninstall",e.id,i],{allowFailure:!0});if(0!==a.exitCode&&!ek(`${a.stdout}
8
+ ${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 eK(e,t,i){let a=await K({kind:"path",path:t},i);try{return await eq(e,a.installablePath),{archivePath:a.archivePath,installablePath:a.installablePath,bundleId:a.bundleId,appName:a.appName,launchTarget:a.bundleId}}finally{await a.cleanup()}}async function ez(e,t,i){return await ex.invalidateWhile(e$(e),async()=>{let{bundleId:a}=await eH(e,t);return await eK(e,i,{appIdentifierHint:t}),{bundleId:a}})}async function eq(e,t){await ex.invalidateWhile(e$(e),async()=>{"simulator"!==e.kind?await A(["device","install","app","--device",e.id,t],{action:"install iOS app",deviceId:e.id}):(await C(e),await eE(e,["install",e.id,t]))})}async function eJ(e){if("macos"===e.platform)return await er();m(e,"clipboard"),await C(e);let t=await eE(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 eZ(e,t){if("macos"===e.platform)return void await en(t);m(e,"clipboard"),await C(e);let i=await eE(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 eQ(e,r,n){m(e,"push"),await C(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)}
9
+ `,"utf8"),await eE(e,["push",e.id,r,l])}finally{await t.rm(o,{recursive:!0,force:!0})}}async function eX(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=x(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 y(e,t)}throw new n("INVALID_ARGS",V(t))}m(e,"settings"),await C(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 eW(e,a);return{bundleId:t.bundleId,containerPath:t.containerPath,cleared:!0}}case"wifi":{let t=P(i);await eE(e,["status_bar",e.id,"override","--wifiMode",t?"active":"failed"]);return}case"airplane":return void(P(i)?await eE(e,["status_bar",e.id,"override","--dataNetwork","hide","--wifiMode","failed","--wifiBars","0","--cellularMode","failed","--cellularBars","0","--operatorName",""]):await eE(e,["status_bar",e.id,"clear"]));case"location":{if("set"===i.toLowerCase()){let{latitude:t,longitude:i}=j(r);return await eE(e,["location",e.id,"set",`${t},${i}`]),{latitude:t,longitude:i}}let t=P(i);if(!a)throw new n("INVALID_ARGS","location setting requires an active app in session");await eE(e,["privacy",e.id,t?"grant":"revoke","location",a]);return}case"faceid":case"touchid":{let t=e4[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 e8(e,a,{settingName:o,label:t.label,modalityAliases:t.modalityAliases});return}case"appearance":{let t=await e3(e,i);await eE(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=x(i))?"revoke":l,o=function(e,t){let i=F(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 e5(e,t,o,a);return}default:throw new n("INVALID_ARGS",`Unsupported setting: ${t}`)}}async function eY(e,t){return"macos"===e.platform?await es(t):"simulator"===e.kind?I(await e0(e),t):await g(e,t)}async function e0(e){return(await e1(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function e1(e){let t=(await eE(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 v("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 e2(e){let t=await v("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 e3(e,t){let i=M(t);if("toggle"!==i)return i;let a=await eE(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}
10
+ ${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 e4={faceid:{label:"Face ID",modalityAliases:["face"]},touchid:{label:"Touch ID",modalityAliases:["finger","touch"]}};async function e5(e,t,i,a){let r=await e6(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 eE(e,o);return}catch(t){if(!(l&&e9(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 eE(e,o);return}catch(e){if(!e9(e))throw e}try{await eE(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 e9(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 e6(t){let i=k(t.simulatorSetPath),a=`${process.env.PATH??""}::${i??""}`;if(eR&&e===a)return eR;let r=await eE(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}
11
+ ${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 eR=o,e=a,o}async function e8(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=h(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=O(r);if(r.length>0&&r.every(e=>{var t,i;let a;return t=e.stdout,i=e.stderr,(a=`${t}
12
+ ${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 e7(e,t,i){await C(e);let a=0,r=B.fromTimeoutMs(6e4);try{await U(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,h(e,r)),p=i?.launchConsole?await te(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 H(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 te(e,i){await t.mkdir(a.dirname(i),{recursive:!0});try{let t=await o(e,{allowFailure:!0,timeoutMs:25e3});return await tt(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 tt(i,t,a),G({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 tt(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}
13
+ ${n}`),"utf8")}async function ti(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 A(a,{action:"launch iOS app",deviceId:e.id})}export{ej as closeIosApp,eK as installIosApp,eq as installIosInstallablePath,eY as listIosApps,eB as openIosApp,eV as openIosDevice,K as prepareIosInstallArtifact,eQ as pushIosNotification,eJ as readIosClipboardText,ez as reinstallIosApp,eT as resolveIosApp,eU as resolveIosSimulatorDeepLinkBundleId,e_ as screenshotIos,eX as setIosSetting,eZ as writeIosClipboardText};
package/dist/src/args.js CHANGED
@@ -1,4 +1,4 @@
1
- import{listCliCommandNames as e}from"./5898.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a,GLOBAL_FLAG_KEYS as s,getFlagDefinition as n,getFlagDefinitions as r}from"./1352.js";import{parseSourceValue as i,buildPrimaryEnvVarName as l}from"./1010.js";import{AppError as c}from"./9152.js";function d(e,t){for(let[o,a]of Object.entries(t))void 0!==a&&(e[o]=a);return e}let p=[{label:"help workflow",description:"Normal bootstrap, exploration, and validation loop"},{label:"help debugging",description:"Logs, network, alerts, diagnostics, and traces"},{label:"help react-native",description:"React Native app automation hazards, overlays, Metro, and routing"},{label:"help react-devtools",description:"React Native performance, profiling, component tree, and renders"},{label:"help physical-device",description:"Connected phone/tablet setup and iOS signing prerequisites"},{label:"help remote",description:"Remote/cloud config, tenants, leases, and local service tunnels"},{label:"help macos",description:"Desktop, frontmost-app, and menu bar surfaces"},{label:"help dogfood",description:"Exploratory QA report workflow"}],u=["Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify -> close.",'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',"Plain snapshot reads state; snapshot -i refreshes current interactive refs only.","Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.","Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.","Anti-pattern: snapshot -i followed by snapshot -i | grep ...; prior refs stay valid until app state changes, and --force-full is the explicit full re-read.","Truncated text/input preview: expand first with snapshot -s @e12, not get text.","React Native apps: read help react-native for Metro, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.","Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability.",'Expo Go/dev clients: use the provided URL when given; on iOS prefer open "Expo Go" <url>; Android URL opens infer the foreground package for logs/perf when possible.',"Install flows: install/install-from-source first, then open the installed id with --relaunch.",'Text: fill \'id="field-email"\' "qa@example.com" replaces; type appends after press.','Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.',"Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.","Implicit default sessions are scoped to the current worktree; use --session only when intentionally sharing a named session.","Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.","Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.","After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known.","Raw coordinates are fallback-only: use snapshot -i -c --json rects when iOS refs no-op or child refs are missing.",'Batch JSON steps use "command" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.',"Navigation: app-owned back uses back; system back uses back --system.","Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.","Debug evidence: Session state contains request diagnostics and runner.log; use logs clear --restart/mark/path, trace, and network dump --include headers for app evidence.","Use agent-device commands in final plans; raw platform tools, pseudo commands, and helper prose are wrong.","Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood."],f=["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."],h=[{label:"AGENT_DEVICE_SESSION",description:"Explicit session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"},{label:"AGENT_DEVICE_DAEMON_AUTH_TOKEN",description:"Remote daemon service/API token"},{label:"AGENT_DEVICE_CLOUD_BASE_URL",description:"Bridge/control-plane API origin for cloud auth and /api-keys"}],g=["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"],m={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
1
+ import{listCliCommandNames as e}from"./6088.js";import{getCliCommandSchema as t,getCommandSchema as o,applyCommandDefaults as a}from"./1352.js";import{parseSourceValue as s,buildPrimaryEnvVarName as n}from"./1010.js";import{AppError as r}from"./9152.js";import{GLOBAL_FLAG_KEYS as i,getFlagDefinition as l,getFlagDefinitions as c}from"./6133.js";function d(e,t){for(let[o,a]of Object.entries(t))void 0!==a&&(e[o]=a);return e}let p=[{label:"help workflow",description:"Normal bootstrap, exploration, and validation loop"},{label:"help debugging",description:"Logs, network, perf memory, and traces"},{label:"help react-native",description:"React Native app automation hazards, overlays, Metro, and routing"},{label:"help react-devtools",description:"React Native performance, profiling, component tree, and renders"},{label:"help physical-device",description:"Connected phone/tablet setup and iOS signing prerequisites"},{label:"help remote",description:"Remote/cloud config, tenants, leases, and local service tunnels"},{label:"help macos",description:"Desktop, frontmost-app, and menu bar surfaces"},{label:"help dogfood",description:"Exploratory QA report workflow"}],u=["Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify -> close.",'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',"Plain snapshot reads state; snapshot -i refreshes current interactive refs only.","Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.","Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.","Anti-pattern: snapshot -i followed by snapshot -i | grep ...; prior refs stay valid until app state changes, and --force-full is the explicit full re-read.","Truncated text/input preview: expand first with snapshot -s @e12, not get text.","React Native apps: read help react-native for Metro, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.","Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability.",'Expo Go/dev clients: use the provided URL when given; on iOS prefer open "Expo Go" <url>; Android URL opens infer the foreground package for logs/perf when possible.',"Install flows: install/install-from-source first, then open the installed id with --relaunch.",'Text: fill \'id="field-email"\' "qa@example.com" replaces; type appends after press.','Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.',"Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.","Implicit default sessions are scoped to the current worktree; use --session only when intentionally sharing a named session.","Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.","Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.","After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known.","Raw coordinates are fallback-only: use snapshot -i --json rects when iOS refs no-op or child refs are missing.",'Batch JSON steps use "command" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.',"Navigation: app-owned back uses back; system back uses back --system.","Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.","Debug evidence: Session state contains request diagnostics and runner.log; use logs clear --restart/mark/path, trace, and network dump --include headers for app evidence.","Use agent-device commands in final plans; raw platform tools, pseudo commands, and helper prose are wrong.","Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood."],f=["Default config files: ~/.agent-device/config.json, ./agent-device.json","Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file."],h=[{label:"AGENT_DEVICE_SESSION",description:"Explicit session name"},{label:"AGENT_DEVICE_PLATFORM",description:"Default platform binding"},{label:"AGENT_DEVICE_SESSION_LOCK",description:"Bound-session conflict mode"},{label:"AGENT_DEVICE_DAEMON_BASE_URL",description:"Connect to remote daemon"},{label:"AGENT_DEVICE_DAEMON_AUTH_TOKEN",description:"Remote daemon service/API token"},{label:"AGENT_DEVICE_CLOUD_BASE_URL",description:"Bridge/control-plane API origin for cloud auth and /api-keys"}],m=["agent-device open Settings --platform ios","agent-device open TextEdit --platform macos","agent-device snapshot -i","agent-device react-devtools get tree --depth 3",'agent-device fill @e3 "test@example.com"',"agent-device replay ./session.ad","agent-device test ./suite --platform android"],g={workflow:{summary:"Normal agent-device bootstrap, exploration, and validation loop",body:`agent-device help workflow
2
2
 
3
3
  Version-matched operating guide for normal agent-device work.
4
4
 
@@ -47,7 +47,7 @@ Snapshots and refs:
47
47
  Off-screen summaries are scroll hints; use scroll, not swipe, then snapshot -i.
48
48
  Missing target in a long list: use a short manual scroll + snapshot loop with a max attempt count. If a named target is summarized as off-screen below/above, use scroll down/up, then snapshot -i; do not use scroll bottom/top because the target may appear before the absolute list edge. Use scroll bottom/top only when the task explicitly asks for the list edge. Edge scrolls verify hidden content with snapshots and stop when no matching hidden content remains.
49
49
  Truncated text/input previews: do not use get text first; expand with snapshot -s @ref (for example snapshot -s @e7), then read the scoped output.
50
- Rare iOS accessibility gaps: if a row ref is shown disabled/hittable:false and press @ref reports success but no UI change, or a horizontal tab/filter bar is collapsed into one composite/seekbar with no child refs, run agent-device snapshot -i -c --json to read rects, compute the target center, press x y, then diff snapshot -i. Coordinates are fallback-only; document why you used them.
50
+ Rare iOS accessibility gaps: if a row ref is shown disabled/hittable:false and press @ref reports success but no UI change, or a horizontal tab/filter bar is collapsed into one composite/seekbar with no child refs, run agent-device snapshot -i --json to read rects, compute the target center, press x y, then diff snapshot -i. Coordinates are fallback-only; document why you used them.
51
51
 
52
52
  Selectors:
53
53
  Use selectors as positional targets: id="field-email" or label="Allow".
@@ -66,7 +66,7 @@ Text entry:
66
66
  Empty replacement is not a supported clear-field command: do not plan fill <target> "" or fill <target> ''. Prefer a visible clear/reset control; if the app exposes none, report the tool gap instead of inventing a clear command.
67
67
  Debounced field with no result selector: agent-device wait 1000. Keyboard read-only: keyboard status/get. Blocked control: try keyboard dismiss when supported.
68
68
  On iOS, prefer keyboard dismiss before manually pressing visible Done; the runner can use safe native keyboard controls and still reports unsupported layouts explicitly. If it returns UNSUPPORTED_OPERATION, prefer a visible app dismiss control, or use back --system only when system navigation is an acceptable side effect.
69
- Search-as-you-type fields on iOS can drop characters when driven too fast; use --delay-ms on fill/type before trying clipboard paste.
69
+ Use plain fill/type first for ordinary login and form fields. If an iOS debounced or search-as-you-type field actually drops characters, or must receive incremental updates, retry with --delay-ms before trying clipboard paste; --delay-ms intentionally paces character entry.
70
70
  iOS Allow Paste prompt cannot be exercised under XCUITest. To test paste-driven app behavior, prefill first with agent-device clipboard write "some text"; test the system prompt manually.
71
71
  Android Gboard handwriting/stylus UI can capture text in an IME-owned input instead of the app field. If fill reports that input was captured by the keyboard/IME, use the diagnostic targetInput/actualInput details, inspect keyboard status/get if needed, and switch or disable handwriting outside the command plan before retrying. Do not keep retrying fill/type against the same field while the IME owns focus.
72
72
  Android text entry is owned by agent-device: provider-native text injection when available, then chunk-safe ASCII shell input. Do not switch to raw adb, clipboard, or paste as an agent fallback. If non-ASCII is unsupported in the current backend, report the tool/device gap.
@@ -114,7 +114,7 @@ Validation and evidence:
114
114
  If task says snapshot, use snapshot. If it asks visual evidence, use screenshot.
115
115
  Icon/tappable visual proof: screenshot --overlay-refs. Flag is --overlay-refs.
116
116
  If snapshot returns a sparse/AX-unavailable state, refs are not reliable. Use plain screenshot, not screenshot --overlay-refs, navigate with coordinates if needed, then retry snapshot -i after reaching another screen; the AX failure may be screen-specific.
117
- Startup/CPU/memory/frame first pass: perf metrics --json (bare perf and metrics are aliases). Focused frame/jank health: perf frames --json. Replay maintenance: replay -u ./flow.ad.
117
+ Startup/CPU/memory/frame first pass: perf metrics --json (bare perf and metrics are aliases). Focused frame/jank health: perf frames --json. Memory-only sample: perf memory sample --json returns compact JSON with bounded top offenders. Heap/memgraph artifact escalation: perf memory snapshot --out heap.artifact; use --kind android-hprof on Android or --kind memgraph on supported Apple simulator/macOS app sessions. Android native profiling: perf cpu profile start|stop|report --kind simpleperf --out <path>; Android native traces: perf trace start|stop --kind perfetto --out <path>. Artifact collectors return compact state/path/size metadata only; raw heap/profile/trace files stay on disk. Treat native perf output as the agent evidence: for example, a Perfetto stop can return state=stopped, outPath=/tmp/app.perfetto-trace, sizeBytes=5392410, and method=adb-shell-perfetto while the 5.3 MB raw trace stays in the artifact. This is better than raw dumps for agents because it is stable, bounded, and keeps large artifacts out of context. heapprofd is deferred until Perfetto plumbing is available. Replay maintenance: replay -u ./flow.ad.
118
118
  Recording: record start/stop. By default, stop burns touch overlays into the video; use record start --hide-touches for the fastest raw recording. Android adb screenrecord has a 180s platform limit, so longer Android recordings are returned as multiple MP4 chunks. For gesture-heavy iOS simulator proof videos, prefer --hide-touches because overlay timing depends on a stable runner session while gestures are executing. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
119
119
  Stable known flow: batch ./steps.json, not workflow batch.
120
120
  Inline batch JSON example:
@@ -176,6 +176,18 @@ Network:
176
176
  Use this instead of logs path when the question is request/response metadata.
177
177
  network log is a supported alias, but network dump --include headers is the clearest plan form. Do not write network log headers.
178
178
 
179
+ Crash symbolication:
180
+ Crash routing:
181
+ Use logs when you need the lead-up timeline before a failure.
182
+ Use debug symbols when you have crash.ips/crash.log plus a matching dSYM/build directory and need the failing frame.
183
+ Use Xcode/LLDB when you need live state, breakpoints, variables, memory, or stepping.
184
+ Use debug symbols when you already have an Apple crash artifact and local dSYMs and need the failing code path, not a full log dump:
185
+ agent-device debug symbols --artifact crash.log --dsym MyApp.dSYM --out crash-symbolicated.log
186
+ agent-device debug symbols --artifact crash.ips --search-path ./build --out crash-symbolicated.ips
187
+ debug is intentionally narrow. Do not use it for logs, network evidence, performance samples, recordings, traces, or React Native internals.
188
+ Apple support matches crash Binary Images / IPS usedImages UUIDs against dwarfdump --uuid output from .dSYM bundles, then writes a symbolicated artifact path and compact crash report: app/thread, exception or termination, top symbolicated frames, and first-frame finding. This is better than pasting crash logs because it keeps agent context small while preserving the artifact on disk for inspection.
189
+ Android Java/R8 mapping.txt and native ndk-stack/addr2line symbolication are not in this first debug symbols workflow; capture crash evidence with logs and use the Android toolchain externally for now.
190
+
179
191
  Alerts:
180
192
  Native and platform dialogs:
181
193
  agent-device alert wait 3000
@@ -197,6 +209,33 @@ Diagnostics and traces:
197
209
  agent-device press 'id="load-diagnostics"'
198
210
  agent-device trace stop ./traces/diagnostics.trace
199
211
  The trace path is positional. Do not use --path for trace start or trace stop.
212
+ Use perf xctrace only for Apple native CPU/profile or Animation Hitches artifacts:
213
+ agent-device perf cpu profile start --kind xctrace --template "Time Profiler" --out ./artifacts/app.trace
214
+ agent-device perf cpu profile stop --kind xctrace --out ./artifacts/app.trace
215
+ agent-device perf cpu profile report --kind xctrace --out ./artifacts/app-profile.json
216
+ agent-device perf trace start --kind xctrace --template "Animation Hitches" --out ./artifacts/hitches.trace
217
+ agent-device perf trace stop --kind xctrace --out ./artifacts/hitches.trace
218
+ perf xctrace returns artifact paths and compact metadata only. Do not dump .trace contents into context.
219
+ For Android native CPU/trace evidence, use perf artifacts instead of raw adb/simpleperf/perfetto output:
220
+ agent-device perf cpu profile start --kind simpleperf --out /tmp/cpu.perf.data
221
+ agent-device perf cpu profile stop --kind simpleperf
222
+ agent-device perf cpu profile report --kind simpleperf --out /tmp/cpu-report.json
223
+ agent-device perf trace start --kind perfetto --out /tmp/app.perfetto-trace
224
+ agent-device perf trace stop --kind perfetto
225
+ Treat native perf output as the agent evidence: for example, state=stopped, outPath=/tmp/app.perfetto-trace, sizeBytes=5392410, method=adb-shell-perfetto. The 5.3 MB raw trace stays in the artifact.
226
+
227
+ Memory diagnostics:
228
+ Use perf memory when the symptom is leak/growth/OOM suspicion and you need agent-readable evidence.
229
+ agent-device perf memory sample --json
230
+ agent-device perf memory snapshot --kind android-hprof --out ./artifacts/app.hprof
231
+ agent-device perf memory snapshot --kind memgraph --out ./artifacts/app.memgraph
232
+ Example sample shape:
233
+ {"metrics":{"memory":{"available":true,"totalPssKb":562958,"totalRssKb":570304,"topConsumers":[{"name":"Dalvik Heap","pssKb":213456}]}}}
234
+ Example default snapshot output:
235
+ Memory artifact (android-hprof): /tmp/app.hprof (42MB)
236
+ Prefer perf memory sample over raw dumpsys/leaks output for first-pass agent diagnosis: it keeps arrays bounded, preserves the same memory source as perf metrics, and returns only memory data instead of startup/CPU/frame noise.
237
+ Prefer perf memory snapshot over printing heap/memgraph data: snapshots return path, size, kind, method, and support metadata while the large artifact stays on disk for external inspection.
238
+ Unsupported platforms return artifact.available=false with reason/hint; do not pretend a heap or memgraph was captured.
200
239
 
201
240
  Stabilizers:
202
241
  Android animation-sensitive flows:
@@ -449,37 +488,37 @@ Rules:
449
488
  Prefer refs for exploration and selectors for deterministic replay.
450
489
  Use logs, network, screenshot --overlay-refs, trace, perf metrics, perf frames, or react-devtools only when they add evidence to a specific issue.
451
490
  Never delete screenshots, videos, traces, or report artifacts during a session.
452
- Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function v(e){let t=e.endsWith("?"),o=t?e.slice(0,-1):e;return t?`[${o}]`:`<${o}>`}function w(e){return r().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function b(e,t){return y(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function y(e,t){if(0===t.length)return`${e}
491
+ Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function v(e){let t=e.endsWith("?"),o=t?e.slice(0,-1):e;return t?`[${o}]`:`<${o}>`}function b(e){return c().filter(t=>e.has(t.key)&&void 0!==t.usageLabel&&void 0!==t.usageDescription)}function w(e,t){return y(e,t.map(e=>({label:e.usageLabel??"",description:e.usageDescription??""})))}function y(e,t){if(0===t.length)return`${e}
453
492
  (none)`;let o=Math.max(...t.map(e=>e.label.length))+2,a=[e];for(let e of t)a.push(` ${e.label.padEnd(o)}${e.description}`);return a.join("\n")}function k(e,t){return 0===t.length?`${e}
454
- (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),I=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),A=function(){let o=new Map;for(let e of r()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of s)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:I.has(e)?[]:[l(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(A.map(e=>[e.key,e]));function S(e){return R.get(e)}function N(e){return A.filter(t=>t.config.enabled&&t.supportsCommand(e))}function U(e,t){return S(e)?.supportsCommand(t)??!1}function E(e,t,o,a){return i(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function D(e){let t={json:!1,help:!1,version:!1},a=null,s=[],r=[],i=!0;for(let p=0;p<e.length;p+=1){var l,d;let u=e[p];if(i&&"--"===u){i=!1;continue}if(!i){a?s.push(u):a=M(u);continue}let f=u.startsWith("--"),h=u.startsWith("-")&&u.length>1;if(!f&&!h){a?s.push(u):a=M(u);continue}let[g,m]=f?C(u):[u,void 0],v=n(g);if(l=a,d=v,"react-devtools"===l&&(!d||!U(d.key,l))){s.push(u);continue}if(!v){if(function(e,t,a){var s;if(s=a,!/^-\d+(\.\d+)?$/.test(s)||!e)return!1;let n=o(e);if(!n||n.allowsExtraPositionals)return!0;let r=n.positionalArgs??[];return 0!==r.length&&(t.length<r.length||r.some(e=>e.includes("?")))}(a,s,u)){a?s.push(u):a=u;continue}throw new c("INVALID_ARGS",`Unknown flag: ${g}`)}let w=function(e,t,o,a){if(void 0!==e.setValue){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==o)throw new c("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==o){if(0===o.trim().length)throw new c("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:o,consumeNext:!1}}return void 0===a||L(a)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let s=o??a;if(void 0===s||void 0===o&&L(s))throw new c("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:s,consumeNext:void 0===o};if("enum"===e.type){if(!e.enumValues?.includes(s))throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:s,consumeNext:void 0===o}}let n=Number(s);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new c("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:Math.floor(n),consumeNext:void 0===o}}(v,g,m,e[p+1]);w.consumeNext&&(p+=1);let b=t[v.key];if(v.multiple){let e=Array.isArray(b)?[...b,w.value]:void 0===b?[w.value]:[b,w.value];t[v.key]=e}else t[v.key]=w.value;r.push({key:v.key,token:g})}return{command:a,positionals:s,flags:t,warnings:[],providedFlags:r}}function O(e,t){let o=t?.strictFlags??!0,s=[...e.warnings],n=d({json:!1,help:!1,version:!1},t?.defaultFlags??{});d(n,e.flags);let r=e.providedFlags.filter(t=>!U(t.key,e.command));if(r.length>0){var i,l;let t=r.map(e=>e.token),a=(i=e.command,l=t,i?1===l.length?`Flag ${l[0]} is not supported for command ${i}.`:`Flags ${l.join(", ")} are not supported for command ${i}.`:1===l.length?`Flag ${l[0]} requires a command that supports it.`:`Flags ${l.join(", ")} require a command that supports them.`);if(o)throw new c("INVALID_ARGS",a);for(let e of(s.push(a),r))delete n[e.key]}for(let t of Object.keys(n))void 0!==n[t]&&(U(t,e.command)||delete n[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new c("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),a(e.command,n),"batch"===e.command&&1!=+!!n.steps+ +!!n.stepsFile)throw new c("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...o}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:o,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:n,warnings:s})}function C(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function _(e){return e.replace(/^-+/,"")}function L(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?C(e):[e,void 0];return void 0!==n(t)}function T(){let o,a,n,r,i,l,c,d;return o=`agent-device <command> [args] [--json]
493
+ (none)`:[e,...t.map(e=>` ${e}`)].join("\n")}let x=new Set(["config","remoteConfig","help","version","batchSteps","githubActionsArtifact"]),A=new Set(["appsFilter","iosSimulatorDeviceSet","sessionLocked","sessionLockConflicts"]),I=function(){let o=new Map;for(let e of c()){let t=o.get(e.key);t?t.push(e):o.set(e.key,[e])}let a=new Map;for(let e of i)a.set(e,new Set(["*"]));for(let o of e())for(let e of t(o).allowedFlags??[]){let t=a.get(e);t&&t.has("*")||(t?t.add(o):a.set(e,new Set([o])))}return[...o.entries()].map(([e,t])=>({key:e,flagDefinitions:t,config:{enabled:!x.has(e),key:e},env:{names:A.has(e)?[]:[n(e)]},supportsCommand(t){let o=a.get(e);return!!o&&(!!o.has("*")||!!t&&o.has(t))}})).sort((e,t)=>e.key.localeCompare(t.key))}(),R=new Map(I.map(e=>[e.key,e]));function S(e){return R.get(e)}function U(e){return I.filter(t=>t.config.enabled&&t.supportsCommand(e))}function N(e,t){return S(e)?.supportsCommand(t)??!1}function D(e,t,o,a){return s(function(e){let t=e.flagDefinitions.find(e=>void 0===e.setValue);if(t)return t;let o=function(e){let t=e.flagDefinitions[0];if(!t)throw Error(`Missing flag definition for option ${e.key}`);return t}(e);if("enum"===o.type){let t=o.enumValues??e.flagDefinitions.map(e=>e.setValue).filter(e=>void 0!==e);return{...o,setValue:void 0,enumValues:t}}return o}(e),t,o,a)}function E(e){let t={json:!1,help:!1,version:!1},a=null,s=[],n=[],i=!0;for(let u=0;u<e.length;u+=1){var c,d,p;let f=e[u];if(i&&"--"===f){i=!1;continue}if(!i){a?s.push(f):a=P(f);continue}let h=f.startsWith("--"),m=f.startsWith("-")&&f.length>1;if(!h&&!m){a?s.push(f):a=P(f);continue}let[g,v]=h?O(f):[f,void 0];if(c=a,"-c"===g&&("snapshot"===c||"diff"===c))continue;let b=l(g);if(d=a,p=b,"react-devtools"===d&&(!p||!N(p.key,d))){s.push(f);continue}if(!b){if(function(e,t,a){var s;if(s=a,!/^-\d+(\.\d+)?$/.test(s)||!e)return!1;let n=o(e);if(!n||n.allowsExtraPositionals)return!0;let r=n.positionalArgs??[];return 0!==r.length&&(t.length<r.length||r.some(e=>e.includes("?")))}(a,s,f)){a?s.push(f):a=f;continue}throw new r("INVALID_ARGS",`Unknown flag: ${g}`)}let w=function(e,t,o,a){if(void 0!==e.setValue){if(void 0!==o)throw new r("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:e.setValue,consumeNext:!1}}if("boolean"===e.type){if(void 0!==o)throw new r("INVALID_ARGS",`Flag ${t} does not take a value.`);return{value:!0,consumeNext:!1}}if("booleanOrString"===e.type){if(void 0!==o){if(0===o.trim().length)throw new r("INVALID_ARGS",`Flag ${t} requires a non-empty value when provided.`);return{value:o,consumeNext:!1}}return void 0===a||L(a)||!function(e){let t=e.trim();return!(!t||/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t))&&!!(t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t.startsWith("/")||t.includes("/")||t.includes("\\"))}(a)?{value:!0,consumeNext:!1}:{value:a,consumeNext:!0}}let s=o??a;if(void 0===s||void 0===o&&L(s))throw new r("INVALID_ARGS",`Flag ${t} requires a value.`);if("string"===e.type)return{value:s,consumeNext:void 0===o};if("enum"===e.type){if(!e.enumValues?.includes(s))throw new r("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:s,consumeNext:void 0===o}}let n=Number(s);if(!Number.isFinite(n)||"number"==typeof e.min&&n<e.min||"number"==typeof e.max&&n>e.max)throw new r("INVALID_ARGS",`Invalid ${_(t)}: ${s}`);return{value:Math.floor(n),consumeNext:void 0===o}}(b,g,v,e[u+1]);w.consumeNext&&(u+=1);let y=t[b.key];if(b.multiple){let e=Array.isArray(y)?[...y,w.value]:void 0===y?[w.value]:[y,w.value];t[b.key]=e}else t[b.key]=w.value;n.push({key:b.key,token:g})}return{command:a,positionals:s,flags:t,warnings:[],providedFlags:n}}function C(e,t){let o=t?.strictFlags??!0,s=[...e.warnings],n=d({json:!1,help:!1,version:!1},t?.defaultFlags??{});d(n,e.flags);let i=e.providedFlags.filter(t=>!N(t.key,e.command));if(i.length>0){var l,c;let t=i.map(e=>e.token),a=(l=e.command,c=t,l?1===c.length?`Flag ${c[0]} is not supported for command ${l}.`:`Flags ${c.join(", ")} are not supported for command ${l}.`:1===c.length?`Flag ${c[0]} requires a command that supports it.`:`Flags ${c.join(", ")} require a command that supports them.`);if(o)throw new r("INVALID_ARGS",a);for(let e of(s.push(a),i))delete n[e.key]}for(let t of Object.keys(n))void 0!==n[t]&&(N(t,e.command)||delete n[t]);if(function(e){if("back"===e.command&&!(new Set(e.providedFlags.filter(e=>"backMode"===e.key).map(e=>e.token)).size<=1))throw new r("INVALID_ARGS","back accepts only one explicit mode flag: use either --in-app or --system.")}(e),a(e.command,n),"batch"===e.command&&1!=+!!n.steps+ +!!n.stepsFile)throw new r("INVALID_ARGS","batch requires exactly one step source: --steps or --steps-file.");return function(e){if(e.flags.help)return e;if("snapshot"===e.command&&e.flags.snapshotDiff){let{snapshotDiff:t,...o}=e.flags;return{command:"diff",positionals:["snapshot",...e.positionals],flags:o,warnings:e.warnings}}return e}({command:e.command,positionals:e.positionals,flags:n,warnings:s})}function O(e){let t=e.indexOf("=");return -1===t?[e,void 0]:[e.slice(0,t),e.slice(t+1)]}function _(e){return e.replace(/^-+/,"")}function L(e){if(!e.startsWith("-")||"-"===e)return!1;let[t]=e.startsWith("--")?O(e):[e,void 0];return void 0!==l(t)}function T(){let o,a,s,n,r,l,c,d;return o=`agent-device <command> [args] [--json]
455
494
 
456
495
  CLI to control iOS and Android devices for AI agents.
457
- `,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,c;return a=e,s=t,i=(r=(n=o).endsWith("?"))?n.slice(0,-1):n,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${a} ${i}`),r?l?`[${i}]`:c?i:`[${i}]`:c?i:`<${i}>`});return[e,...o].join(" ")}(e,o)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),n=b("Flags:",w(s)),r=k("Agent Quickstart:",u),i=y("Agent Workflows:",p),l=k("Configuration:",f),c=y("Environment:",h),d=k("Examples:",g),`${o}
496
+ `,a=y("Commands:",e().map(e=>{let o=t(e);return{name:e,schema:o,usage:function(e,t){if(t.listUsageOverride)return t.listUsageOverride;let o=(t.positionalArgs??[]).map(o=>{var a,s,n;let r,i,l,c;return a=e,s=t,i=(r=(n=o).endsWith("?"))?n.slice(0,-1):n,c=(l=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i))||void 0!==s.usageOverride&&s.usageOverride.startsWith(`${a} ${i}`),r?l?`[${i}]`:c?i:`[${i}]`:c?i:`<${i}>`});return[e,...o].join(" ")}(e,o)}}).map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription}))),s=w("Flags:",b(i)),n=k("Agent Quickstart:",u),r=y("Agent Workflows:",p),l=k("Configuration:",f),c=y("Environment:",h),d=k("Examples:",m),`${o}
458
497
  ${a}
459
498
 
499
+ ${s}
500
+
460
501
  ${n}
461
502
 
462
503
  ${r}
463
504
 
464
- ${i}
465
-
466
505
  ${l}
467
506
 
468
507
  ${c}
469
508
 
470
509
  ${d}
471
- `}function F(e){return function(e){var t,a;let n,i=(n=m[e])?`${n.body}
510
+ `}function M(e){return function(e){var t,a;let s,n=(s=g[e])?`${s.body}
472
511
 
473
512
  Related:
474
513
  agent-device help command list and global flags
475
514
  agent-device help <command> command-specific flags
476
515
  agent-device help workflow normal app automation loop
477
- `:null;if(i)return i;let l=o(e);if(!l)return null;let c=(t=e,(a=l).usageOverride?a.usageOverride:[t,...(a.positionalArgs??[]).map(v),...(a.allowedFlags??[]).flatMap(e=>{var t;return(t=e,r().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=w(new Set(l.allowedFlags??[])),p=w(s),u=[];return d.length>0&&u.push(b("Command flags:",d)),u.push(b("Global flags:",p)),`agent-device ${c}
516
+ `:null;if(n)return n;let r=o(e);if(!r)return null;let l=(t=e,(a=r).usageOverride?a.usageOverride:[t,...(a.positionalArgs??[]).map(v),...(a.allowedFlags??[]).flatMap(e=>{var t;return(t=e,c().filter(e=>e.key===t)).map(e=>e.usageLabel??e.names[0])}).map(e=>`[${e}]`)].join(" ")),d=b(new Set(r.allowedFlags??[])),p=b(i),u=[];return d.length>0&&u.push(w("Command flags:",d)),u.push(w("Global flags:",p)),`agent-device ${l}
478
517
 
479
- ${l.helpDescription}
518
+ ${r.helpDescription}
480
519
 
481
520
  Usage:
482
- agent-device ${c}
521
+ agent-device ${l}
483
522
 
484
523
  ${u.join("\n\n")}
485
- `}(M(e))}function M(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,O as finalizeParsedArgs,N as getConfigurableOptionSpecs,S as getOptionSpec,d as mergeDefinedFlags,E as parseOptionValueFromSource,D as parseRawArgs,F as usageForCommand};
524
+ `}(P(e))}function P(e){return"long-press"===e?"longpress":"metrics"===e?"perf":e}export{T as usage,C as finalizeParsedArgs,U as getConfigurableOptionSpecs,S as getOptionSpec,d as mergeDefinedFlags,D as parseOptionValueFromSource,E as parseRawArgs,M as usageForCommand};
package/dist/src/batch.js CHANGED
@@ -1 +1 @@
1
- var _=100;export{BATCH_BLOCKED_COMMANDS,INHERITED_PARENT_FLAG_KEYS,buildBatchStepFlags,runBatch,validateAndNormalizeBatchSteps}from"./1231.js";export{_ as DEFAULT_BATCH_MAX_STEPS};
1
+ var _=100;export{BATCH_BLOCKED_COMMANDS,INHERITED_PARENT_FLAG_KEYS}from"./6088.js";export{buildBatchStepFlags,runBatch,validateAndNormalizeBatchSteps}from"./1231.js";export{_ as DEFAULT_BATCH_MAX_STEPS};
@@ -0,0 +1,29 @@
1
+ import e from"node:path";import{styleText as t}from"node:util";import{buildMobileSnapshotPresentation as n,serializeOpenResult as r,serializeSnapshotResult as i,serializeSessionListEntry as o,readCommandMessage as a,serializeDeployResult as s,serializeCloseResult as u,displayNodeLabel as l,serializeInstallFromSourceResult as d,serializeDevice as f}from"./6133.js";import{normalizeError as p,AppError as c}from"./9152.js";import{buildSnapshotDisplayLines as h,formatSnapshotLine as $}from"./5827.js";function g(e){return({result:t})=>e(t)}let m=g(y);function y(e){return{data:e,text:a(e)}}function x(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function v(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}let b={batch:g(function(e){let t="number"==typeof e.total?e.total:0,n="number"==typeof e.executed?e.executed:0,r="number"==typeof e.totalDurationMs?e.totalDurationMs:void 0,i=[`Batch completed: ${n}/${t} steps${void 0!==r?` in ${r}ms`:""}`];for(let t of Array.isArray(e.results)?e.results:[]){let e=function(e){let t=x(e);if(!t)return;let n="number"==typeof t.step?t.step:void 0,r="string"==typeof t.command?t.command:"step",i=!1!==t.ok,o=function(e,t,n){var r;return t?a(x(e.data))??n:(r=x(e.error),("string"==typeof r?.message&&r.message.length>0?r.message:null)??n)}(t,i,r),s=void 0!==n?`${n}. `:"- ",u="number"==typeof t.durationMs?t.durationMs:void 0,l=void 0!==u?` (${u}ms)`:"";return`${s}${i?"OK":"FAILED"} ${o}${l}`}(t);e&&i.push(e)}return{data:e,text:i.join("\n")}})};function w(e){return e.width>0&&e.height>0}function C(e,t){return!!e&&!!t&&e.x>=t.x-2&&e.y>=t.y-2&&e.x+e.width<=t.x+t.width+2&&e.y+e.height<=t.y+t.height+2}function M(e){return"number"!=typeof e.parentIndex}function S(e){let t=(e.type??"").toLowerCase(),n=(e.identifier??"").trim().toLowerCase();return t.includes("edittext")||t.includes("textfield")||"composer"===n}function k(e){let t=(e.type??"").toLowerCase();return t.includes("scroll")||t.includes("list")||t.includes("recyclerview")}function P(e){var t;let n=l(e);if(!n||n!==e.identifier?.trim()||(t=n,!/^[\w.]+:id\/[\w.-]+$/i.test(t)))return n;let r=(e.type??"").toLowerCase();return r.includes("view")||r.includes("layout")||r.includes("image")||r.includes("list")||r.includes("recyclerview")||r.includes("collection")?"":n}function I(e){let t=e.trim().replace(/\s+/g," ").toLowerCase();return!t||/^(true|false|\d+)$/.test(t)?null:t}function N(e,t){let n=[],r=[t];for(;r.length>0;){let t=r.pop();for(let i of e)i.parentIndex===t&&(n.push(i),r.push(i.index))}return n}function j(e,t,n){let r=[t];for(;r.length>0;){let t=r.pop();if(!n.has(t))for(let i of(n.add(t),e))i.parentIndex!==t||n.has(i.index)||r.push(i.index)}}let A=["button","switch","checkbox","radio"],O=["button","image","textview","view"];function F(e){if(!0===e.hittable||S(e))return!1;let t=(e.type??"").toLowerCase();return t.includes("text")||t.includes("image")||t.includes("icon")}function B(e){if(!e.rect||!w(e.rect)||M(e)||S(e))return!1;let t=(e.type??"").toLowerCase();return"text"===t||L(t,O)}function T(e,t){let n=D(e);return D(t)>n?t:e}function D(e){let t=(e.type??"").toLowerCase(),n=0;return L(t,A)?n+=100:t.includes("image")?n+=30:t.includes("textview")||"text"===t?n+=20:t.includes("view")&&(n+=10),!0===e.hittable&&(n+=20),!1!==e.enabled&&(n+=5),n}function L(e,t){return t.some(t=>e.includes(t))}function R(e){process.stdout.write(`${JSON.stringify(e,null,2)}
2
+ `)}function H(e,t={}){let n=e instanceof c?p(e):e;process.stderr.write(`Error (${n.code}): ${n.message}
3
+ `),n.hint&&process.stderr.write(`Hint: ${n.hint}
4
+ `),n.diagnosticId&&process.stderr.write(`Diagnostic ID: ${n.diagnosticId}
5
+ `),n.logPath&&process.stderr.write(`Diagnostics Log: ${n.logPath}
6
+ `),t.showDetails&&n.details&&process.stderr.write(`${JSON.stringify(n.details,null,2)}
7
+ `)}function K(e){return e&&e.summaryLines.length>0?`
8
+ ${e.summaryLines.join("\n")}`:""}function _(e){var n;let r=!0===e.baselineInitialized,i=e.summary??{},o=Q(i.additions),a=Q(i.removals),s=Q(i.unchanged),u=Y(),l=V(e),d=l.length>0?`${l.join("\n")}
9
+ `:"";if(r)return`${d}Baseline initialized (${s} lines).
10
+ `;let f=(function(e){if(0===e.length)return e;let t=e.map((e,t)=>({index:t,kind:e.kind})).filter(e=>"added"===e.kind||"removed"===e.kind).map(e=>e.index);if(0===t.length)return e;let n=Array(e.length).fill(!1);for(let r of t){let t=Math.max(0,r-1),i=Math.min(e.length-1,r+1);for(let e=t;e<=i;e+=1)n[e]=!0}return e.filter((e,t)=>n[t])})(Array.isArray(e.lines)?e.lines:[]).map(e=>{let n="string"==typeof e.text?e.text:"";if("added"===e.kind){let e=n.startsWith(" ")?`+${n}`:`+ ${n}`;return u?t("green",e):e}if("removed"===e.kind){let e=n.startsWith(" ")?`-${n}`:`- ${n}`;return u?t("red",e):e}return u?t("dim",n):n}),p=f.length>0?`${f.join("\n")}
11
+ `:"";if(!u)return`${d}${p}${o} additions, ${a} removals, ${s} unchanged
12
+ `;let c=`${(n=String(o),t("green",n))} additions, ${t("red",String(a))} removals, ${t("dim",String(s))} unchanged`;return`${d}${p}${c}
13
+ `}function z(e){var n,r,i,o;let a,s,u,l,d=Y(),f=!0===e.match,p=e.dimensionMismatch,c=[];return c.push(...function(e,n){if(!0===e.match){let e=n?function(e,n){return t(n,e)}("✓","green"):"✓";return[`${e} Screenshots match.`]}let r=e.dimensionMismatch,i=n?function(e,n){return t(n,e)}("✗","red"):"✗";if(r){let e=r.expected,t=r.actual;return[`${i} Screenshots have different dimensions: expected ${e?.width}x${e?.height}, got ${t?.width}x${t?.height}`]}let o=Q(e.differentPixels),a=Q(e.mismatchPercentage),s=0===a&&o>0?"<0.01":String(a),u=`${s}% pixels differ`;return[`${i} ${n?function(e,n){return t(n,e)}(u,"red"):u}`]}(e,d)),c.push(...function(e,n,r){if(n)return[];let i=[];if(e.diffPath){let n=q(e.diffPath),o=r?function(e,n){return t(n,e)}("Diff image:","dim"):"Diff image:",a=r?function(e,n){return t(n,e)}(n,"green"):n;i.push(` ${o} ${a}`)}if(e.currentOverlayPath){let n=q(e.currentOverlayPath),o=r?function(e,n){return t(n,e)}("Current overlay:","dim"):"Current overlay:",a=r?function(e,n){return t(n,e)}(n,"green"):n,s=Q(e.currentOverlayRefCount),u=s>0?` (${s} refs)`:"";i.push(` ${o} ${a}${u}`)}return i}(e,f,d)),f||p||(c.push(...(n=e,r=d,a=Q(n.differentPixels),s=Q(n.totalPixels),u=r?function(e,n){return t(n,e)}(String(a),"red"):String(a),[` ${u} different / ${s} total pixels`])),c.push(...(i=e,o=d,0===(l=function(e){let t=[];for(let n of(e.ocr?.movementClusters??[]).slice(0,2))t.push(`text movement cluster: ${function(e){let t=e.slice(0,4).map(e=>JSON.stringify(e)),n=e.length>t.length?` +${e.length-t.length} more`:"";return`${t.join(", ")}${n}`}(n.texts)} dx=${U(n.xRange)}px dy=${U(n.yRange)}px`);let n=(e.nonTextDeltas??[]).filter(e=>["icon","toggle","chevron"].includes(e.likelyKind)).slice(0,3);n.length>0&&t.push(`non-text controls: ${n.map(E).join("; ")}`);let r=(e.nonTextDeltas??[]).filter(e=>"separator"===e.likelyKind).slice(0,2);return r.length>0&&t.push(`non-text boundaries: ${r.map(E).join("; ")}`),t.slice(0,6)}(i)).length?[]:[` ${G("Hints:",o)}`,...l.map(e=>` - ${e}`)])),c.push(...function(e,t){let n=Array.isArray(e.regions)?e.regions:[];if(0===n.length)return[];let r=[` ${G("Changed regions:",t)}`];for(let e of n.slice(0,5))r.push(...function(e){let t=0===e.shareOfDiffPercentage&&e.differentPixels>0?"<0.01":String(e.shareOfDiffPercentage),n=e.rect,r=[` ${e.index}. ${e.location} x=${n.x} y=${n.y} ${n.width}x${n.height}, ${t}% of diff, change=${e.dominantChange}`],i=function(e){let t=[e.size?`size=${e.size}`:null,e.shape?`shape=${e.shape}`:null,"number"==typeof e.densityPercentage?`density=${e.densityPercentage}%`:null,e.averageBaselineColorHex&&e.averageCurrentColorHex?`avgColor=${e.averageBaselineColorHex}->${e.averageCurrentColorHex}`:null,"number"==typeof e.baselineLuminance&&"number"==typeof e.currentLuminance?`luminance=${e.baselineLuminance}->${e.currentLuminance}`:null].filter(e=>null!==e);return t.length>0?t.join(" "):null}(e);i&&r.push(` ${i}`);let o=e.currentOverlayMatches?.[0];if(o){let e=o.label?` "${o.label}"`:"";r.push(` overlaps @${o.ref}${e}, ${o.regionCoveragePercentage}% of region`)}return r}(e));return r}(e,d)),c.push(...function(e,t){let n=e.ocr?.matches??[];if(0===n.length)return[];let r=n.slice(0,8),i=[` ${G(`OCR text deltas (${e.ocr?.provider}; baselineBlocks=${e.ocr?.baselineBlocks} currentBlocks=${e.ocr?.currentBlocks}; showing ${r.length}/${n.length}; px):`,t)}`,` ${G("item | text | movePx | sizeDeltaPx | bboxBaseline | bboxCurrent | confidence | issueHint",t)}`];for(let[e,t]of r.entries()){let n=t.delta;i.push(` ${e+1} | ${JSON.stringify(t.text)} | ${J(n.x)},${J(n.y)} | ${J(n.width)},${J(n.height)} | ${W(t.baselineRect)} | ${W(t.currentRect)} | ${t.confidence} | ${t.possibleTextMetricMismatch?"ocr-bbox-size-change":"-"}`)}return i}(e,d)),c.push(...function(e,t){let n=e.nonTextDeltas??[];if(0===n.length)return[];let r=n.slice(0,8),i=[` ${G(`Non-text visual deltas (showing ${r.length}/${n.length}; px):`,t)}`,` ${G("item | region | slot | kind | bboxCurrent | nearestText",t)}`];for(let e of r)i.push(` ${e.index} | ${e.regionIndex?`r${e.regionIndex}`:"-"} | ${e.slot} | ${e.likelyKind} | ${W(e.rect)} | ${e.nearestText?JSON.stringify(e.nearestText):"-"}`);return i}(e,d))),`${c.join("\n")}
14
+ `}function W(e){return`x=${e.x},y=${e.y},w=${e.width},h=${e.height}`}function J(e){return e>0?`+${e}`:String(e)}function E(e){let t=e.nearestText?` near ${JSON.stringify(e.nearestText)}`:"",n=e.regionIndex?` r${e.regionIndex}`:"";return`${e.likelyKind}${t}${n}`}function U(e){return e.min===e.max?J(e.min):`${J(e.min)}..${J(e.max)}`}function q(t){let n=process.cwd(),r=e.relative(n,t);return""!==r&&(r.startsWith("..")||e.isAbsolute(r))?t:""===r?".":`.${e.sep}${r}`}function Q(e){return"number"==typeof e&&Number.isFinite(e)?e:0}function Y(){let e=process.env.FORCE_COLOR;return"string"==typeof e?"0"!==e:"string"!=typeof process.env.NO_COLOR&&!!process.stdout.isTTY}function G(e,n){return n?t("dim",e):e}function V(e){let t=e.warnings;return Array.isArray(t)?t.filter(e=>"string"==typeof e&&e.length>0):[]}function X(e,t){var n;let r="scroll-area"===(n=e.type)||"list"===n||"collection"===n||"table"===n?n:null;if(!r)return[];let i=[];if(e.node.hiddenContentAbove&&"below"!==t&&i.push(`[content above ${r} hidden]`),e.node.hiddenContentBelow&&"above"!==t&&i.push(`[content below ${r} hidden]`),0===i.length)return[];let o=" ".repeat(e.depth+1);return i.map(e=>`${o}${e}`)}let Z={debug:g(function(e){let t=[e.outPath,e.message];for(let n of(t.push(...function(e){let t=e.crash,n=[`Crash: ${t.appName??"unknown app"}${void 0===t.crashedThread?"":` thread ${t.crashedThread}`}`];for(let e of(t.bundleId&&n.push(`Bundle: ${t.bundleId}`),t.exceptionType&&n.push(`Exception: ${t.exceptionType}`),t.terminationReason&&n.push(`Termination: ${t.terminationReason}`),t.topFrames))n.push(`Frame ${e.index}: ${e.image} ${e.symbol??e.address}`);for(let e of t.findings)n.push(`Finding: ${e}`);return n}(e)),e.matchedImages))t.push(`Matched: ${n.name} ${n.uuid}${n.arch?` ${n.arch}`:""}`);for(let n of e.warnings??[])t.push(`Warning: ${n}`);return{data:e,text:t.join("\n")}})};function ee(e){let t=e.ref??"",n=e.x,r=e.y;return t&&"number"==typeof n&&"number"==typeof r?{data:e,text:`Tapped @${t} (${n}, ${r})`}:y(e)}let et={click:g(ee),press:g(ee),get:({input:e,result:t})=>{var n;let r;return r=(n={result:t,format:e.format}).result,"text"===n.format?{data:r,text:"string"==typeof r.text?r.text:""}:"attrs"===n.format?{data:r,text:JSON.stringify(r.node??{},null,2)}:y(r)},is:g(function(e){return{data:e,text:`Passed: is ${e.predicate??"assertion"}`}}),find:g(function(e){return"string"==typeof e.text?{data:e,text:e.text}:"boolean"==typeof e.found?{data:e,text:`Found: ${e.found}`}:e.node?{data:e,text:JSON.stringify(e.node,null,2)}:y(e)})};function en(e){return y(s(e))}let er={boot:g(function(e){let t=e.platform??"unknown",n=e.device??e.id??"unknown";return{data:e,text:`Boot ready: ${n} (${t})`}}),shutdown:g(function(e){let t=e.platform??"unknown",n=e.device??e.id??"unknown",r=e.shutdown,i=!!r&&"object"==typeof r&&"success"in r&&!0===r.success;return{data:e,text:`${i?"Shutdown":"Shutdown failed"}: ${n} (${t})`}}),devices:g(function(e){return{data:{devices:e.map(f)},text:e.map(ei).join("\n")}}),apps:({input:e,result:t})=>{var n;return{data:{apps:(n={result:t,appsFilter:e.appsFilter}).result},stderr:"all"===n.appsFilter?"Showing all apps, including system apps.\n":"Showing user-installed apps. Use --all to include system apps.\n",text:n.result.length>0?n.result.join("\n"):"all"===n.appsFilter?"No apps found.":"No user-installed apps found."}},session:g(function(e){if("stateDir"in e)return{data:e,text:e.stateDir};let t={sessions:e.sessions.map(o)};return{data:t,text:JSON.stringify(t,null,2)}}),open:g(function(e){let t=r(e),n=[a(t)].filter(e=>!!e);return"string"==typeof t.sessionStateDir&&n.push(`Session state: ${t.sessionStateDir}`),{data:t,text:n.join("\n")||null}}),close:g(function(e){return y(u(e))}),install:g(en),reinstall:g(en),"install-from-source":g(function(e){return y(d(e))}),prepare:m};function ei(e){let t=e.kind?` ${e.kind}`:"",n=e.target?` target=${e.target}`:"",r="boolean"==typeof e.booted?` booted=${e.booted}`:"";return`${e.name} (${e.platform}${t}${n})${r}`}let eo={logs:g(function(e){var t;return{data:e,text:"string"==typeof e.path?e.path:"",stderr:el([es(e,["active","state","backend","sizeBytes"]),(t=e,["started","stopped","marked","cleared","restarted","removedRotatedFiles"].map(e=>{var n,r;return n=e,!0===(r=t[e])?`${n}=true`:"number"==typeof r?`${n}=${r}`:""}).filter(Boolean).join(" ")||void 0),"string"==typeof e.hint?e.hint:void 0,eu(e.notes)])}}),network:g(function(e){let t=[],n="string"==typeof e.path?e.path:"";n&&t.push(n);let r=Array.isArray(e.entries)?e.entries:[];if(0===r.length)t.push("No recent HTTP(s) entries found.");else for(let e of r)t.push(...function(e){let t=x(e)??{},n="string"==typeof t.method?t.method:"HTTP",r="string"==typeof t.url?t.url:"<unknown-url>",i="number"==typeof t.status?` status=${t.status}`:"",o="string"==typeof t.timestamp?`${t.timestamp} `:"",a="number"==typeof t.durationMs?` durationMs=${t.durationMs}`:"",s=[`${o}${n} ${r}${i}${a}`];return ea(s,"headers",t.headers),ea(s,"request",t.requestBody),ea(s,"response",t.responseBody),s}(e));return{data:e,text:t.join("\n"),stderr:el([es(e,["active","state","backend","include","scannedLines","matchedLines"]),eu(e.notes)])}})};function ea(e,t,n){"string"==typeof n&&e.push(` ${t}: ${n}`)}function es(e,t){return t.map(t=>void 0!==e[t]&&null!==e[t]?`${t}=${e[t]}`:"").filter(Boolean).join(" ")||void 0}function eu(e){if(!Array.isArray(e))return;let t=e.filter(e=>"string"==typeof e&&e.length>0);return t.length>0?t.join("\n"):void 0}function el(e){return e.filter(e=>!!e).join("\n")||void 0}let ed={perf:g(function(e){return{data:e,text:function(e){var t,n,r,i;let o,a="xctrace"===(t=e).kind?function(e){var t,n,r,i,o;let a="string"==typeof e.perf?e.perf:void 0,s="string"==typeof(t=e).outPath?t.outPath:"string"==typeof t.reportPath?t.reportPath:void 0;if(a&&s&&"xctrace"===e.kind){let t;return n=s,r="string"==typeof e.mode?e.mode:"capture",i=a,o=e.template,t=[n,`Perf ${r}: ${i}`],"string"==typeof o&&t.push(`Template: ${o}`),t.join("\n")}}(t):function(e){var t;let n,r,i,o=(n=ef((t=e).action),r=ef(t.kind),i=ef(t.type),n&&r&&i?{action:n,kind:r,type:i}:void 0);if(o){let t;return`Perf ${o.action}: ${o.kind} ${o.type}${(t=ef(e.state))?` state=${t}`:""}${function(e){let t=ef(e.outPath);if(!t)return"";let n=ec(e.sizeBytes);return`
15
+ ${t}${void 0!==n?` (${eg(n)})`:""}`}(e)}${function(e){let t=x(e.summary),n=x(t?.frameHealth);if(!n||!0!==n.available)return"";let r=ec(n.droppedFramePercent),i=ec(n.droppedFrameCount),o=ec(n.totalFrameCount);return void 0===r||void 0===i||void 0===o?"":`
16
+ Trace frame health: dropped ${eh(r)} (${Math.round(i)}/${Math.round(o)} frames)`}(e)}`}}(t);if(a)return a;let s=x(e.artifact);if(s)return function(e){let t="string"==typeof e.kind?e.kind:"memory";if(!1===e.available){let n="string"==typeof e.reason&&e.reason.length>0?e.reason:"not available";return`Memory artifact (${t}): unavailable - ${n}`}let n="string"==typeof e.path?e.path:void 0,r=ec(e.sizeBytes),i=void 0===r?"":` (${eg(r)})`;return n?`Memory artifact (${t}): ${n}${i}`:`Memory artifact (${t}): captured${i}`}(s);let u=x(e.metrics),l=x(u?.fps),d=(n=u,(o=[function(e){if(e?.available!==!0)return;let t=ec(e.usagePercent);return void 0!==t?`CPU ${eh(t)}`:void 0}(x(n?.cpu)),function(e){let t;if(e?.available!==!0)return;let n=ec(e.residentMemoryKb)??ec(e.totalPssKb)??ec(e.totalRssKb);return void 0!==n?`memory ${t=n/1024,`${t>=10?Math.round(t):t.toFixed(1)}MB`}`:void 0}(x(n?.memory))].filter(e=>!!e)).length>0?o.join(", "):void 0);if(!l)return ep(d,"missing frame metric");if(!1===l.available){return ep(d,"string"==typeof(r=l).reason&&r.reason.length>0?r.reason:"not available")}let f=function(e){let t=ec(e.droppedFramePercent),n=ec(e.droppedFrameCount);if(void 0!==t&&void 0!==n){var r,i,o;return[`dropped ${eh(t)}`,(r=n,void 0!==(i=ec(e.totalFrameCount))?`(${Math.round(r)}/${Math.round(i)} frames)`:`(${Math.round(r)} dropped frames)`),void 0!==(o=ec(e.sampleWindowMs))?`window ${e$(o)}`:""].filter(Boolean).join(" ")}}(l);if(!f)return ep(d,"missing dropped-frame summary");let p=[`Frame health: ${f}`],c=(Array.isArray(i=l.worstWindows)?i.filter(v):[]).flatMap(e=>{let t=function(e){let t=ec(e.startOffsetMs),n=ec(e.endOffsetMs),r=ec(e.missedDeadlineFrameCount);if(void 0===t||void 0===n||void 0===r)return;let i=ec(e.worstFrameMs),o=void 0===i?"":`, worst ${e$(i)}`;return`- +${e$(t)}-+${e$(n)}: ${Math.round(r)} missed-deadline frames${o}`}(e);return t?[t]:[]});return c.length>0&&p.push("Worst windows:",...c),p.join("\n")}(e)}})};function ef(e){return"string"==typeof e?e:void 0}function ep(e,t){return e?`Performance: ${e}`:`Frame health: unavailable - ${t}`}function ec(e){return"number"==typeof e&&Number.isFinite(e)?e:void 0}function eh(e){return`${Number.isInteger(e)?e:e.toFixed(1)}%`}function e$(e){let t=Math.max(0,Math.round(e));if(t<1e3)return`${t}ms`;let n=Math.round(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;return i>0?`${r}m ${i}s`:`${r}m`}function eg(e){if(e<1024)return`${Math.round(e)}B`;let t=e/1024;if(t<1024)return`${t>=10?Math.round(t):t.toFixed(1)}KB`;let n=t/1024;return`${n>=10?Math.round(n):n.toFixed(1)}MB`}let em={record:g(function(e){let t,n="string"==typeof e.outPath?e.outPath:"",r=Array.isArray(t=e.chunks)?t.flatMap(e=>e&&"object"==typeof e?"number"!=typeof e.index||"string"!=typeof e.path?[]:[{index:e.index,path:e.path}]:[]):[];if(r.length<=1){var i,o;let t;return{data:e,text:(i=e,t=[],(o=n)&&t.push(o),"string"==typeof i.sessionStateDir&&t.push(`Session state: ${i.sessionStateDir}`),"string"==typeof i.warning&&t.push(`Warning: ${i.warning}`),"string"==typeof i.overlayWarning&&t.push(`Overlay warning: ${i.overlayWarning}`),t.join("\n"))}}let a=["Recording chunks:"];for(let e of r)a.push(` ${e.index}: ${e.path}`);return"string"==typeof e.telemetryPath&&a.push(`Telemetry: ${e.telemetryPath}`),"string"==typeof e.warning&&a.push(`Warning: ${e.warning}`),"string"==typeof e.overlayWarning&&a.push(`Overlay warning: ${e.overlayWarning}`),{data:e,text:a.join("\n")}})},ey={appstate:g(function(e){return{data:e,text:function(e){if("ios"===e.platform){let t=[`Foreground app: ${e.appName??e.appBundleId??"unknown"}`];return e.appBundleId&&t.push(`Bundle: ${e.appBundleId}`),e.source&&t.push(`Source: ${e.source}`),t.join("\n")}if("android"===e.platform){let t=[`Foreground app: ${e.package??"unknown"}`];return e.activity&&t.push(`Activity: ${e.activity}`),t.join("\n")}return null}(e)}}),back:m,home:m,rotate:m,"app-switcher":m,keyboard:g(function(e){if("android"===e.platform&&"status"===e.action){var t;let n=[`Keyboard visible: ${!0===e.visible?"yes":"no"}`,`Input type: ${e.type??e.inputType??"unknown"}`,`Input owner: ${e.inputOwner??"unknown"}`];return e.inputMethodPackage&&n.push(`Input method: ${e.inputMethodPackage}`),e.focusedPackage&&n.push(`Focused package: ${e.focusedPackage}`),e.focusedResourceId&&n.push(`Focused resource: ${e.focusedResourceId}`),n.push(`Next action: ${(t=e.visible,"ime"===e.inputOwner?"Focused input appears to be owned by the keyboard/IME; dismiss or change the IME before retrying text entry.":!0===t?"Keyboard is visible and focused input appears app-owned; fill/type can proceed.":"Keyboard is hidden; focus an app field before type, or use fill with a concrete target.")}`),{data:e,text:n.join("\n")}}return y(e)}),clipboard:g(function(e){return"read"===e.action?{data:e,text:e.text}:y(e)})},ex={...er,snapshot:({input:e,result:t})=>{var r;let o;return{data:o=i((r={result:t,raw:e.raw,interactiveOnly:e.interactiveOnly,scope:e.scope,depth:e.depth}).result),jsonData:function(e){let{unchanged:t,...n}=e;return n}(o),text:function(e,t={}){var r,i,o,a;let s,u,d,f,p,c=e.nodes,g=Array.isArray(c)?c:[],m="string"==typeof e.backend?e.backend:void 0,y=function(e,t,n){let r;if(n.raw||!((r=e.androidSnapshot)&&"object"==typeof r&&"android-helper"===r.backend))return{nodes:t,filteredCount:0};let i=function(e){var t,n;if(0===e.length)return e;let r=new Set,i=new Map,o=new Map(e.map(e=>[e.index,e]));(function(e,t){for(let n of e)!n.rect||w(n.rect)||M(n)||j(e,n.index,t)})(e,r),function(e,t,n,r){for(let i of e){if(n.has(i.index)||i.rect||M(i))continue;let o=function(e,t,n){let r=e;for(;"number"==typeof r.parentIndex;){let e=t.get(r.parentIndex);if(!e)break;if(n(e))return e;r=e}return null}(i,t,k);o&&function(e,t,n){if(!n)return;let r=e.get(t.index)??t;e.set(t.index,{...r,hiddenContentAbove:!0===r.hiddenContentAbove||"above"===n||void 0,hiddenContentBelow:!0===r.hiddenContentBelow||"below"===n||void 0})}(r,o,function(e,t){let n=t.filter(t=>t.parentIndex===e.parentIndex&&t.rect&&w(t.rect)).map(e=>e.index);return 0===n.length?null:e.index<Math.min(...n)?"above":e.index>Math.max(...n)?"below":null}(i,e)),j(e,i.index,n)}}(e,o,r,i);for(let n of e){if(r.has(n.index)||!(!0===(t=n).hittable&&!S(t)&&t.rect&&w(t.rect)&&0===P(t).trim().length))continue;let o=function(e,t,n){let r=[],i=[],o=new Set;for(let a of e){if(n.has(a.index)||!F(a)||!C(a.rect,t.rect))continue;let e=P(a).trim().replace(/\s+/g," "),s=I(e);i.push(a.index),!e||!s||o.has(s)||(o.add(s),r.push(e))}return{label:r.join(", "),removableIndexes:i}}(N(e,n.index),n,r);if(o.label)for(let t of(i.set(n.index,{...n,...i.get(n.index),label:o.label}),o.removableIndexes))j(e,t,r)}for(let t of e){if(r.has(t.index)||!(!0===(n=t).hittable&&!S(n)&&n.rect&&w(n.rect)&&I(P(n))))continue;let i=I(P(t));if(!i)continue;let o=N(e,t.index).filter(e=>!r.has(e.index)&&function(e,t,n){if(!B(t)||!C(t.rect,e.rect))return!1;let r=I(P(t));return!!(r&&n!==r&&n.includes(r))}(t,e,i));for(let t of o.filter(F))j(e,t.index,r);let a=o.filter(e=>!F(e)),s=new Set(a.map(e=>I(P(e))).filter(e=>!!e));if(!(a.length<2)&&!(s.size<2))for(let t of a)j(e,t.index,r)}let a=new Map;for(let t of e){if(r.has(t.index)||!B(t))continue;let n=I(P(t));if(!n)continue;let o=a.get(n);if(o&&function(e,t,n){var r,i,o,a;return!n.has(e.index)&&(r=e.rect,i=t.rect,!r||!i||Math.abs(r.y+r.height/2-(i.y+i.height/2))<=Math.max(r.height,i.height,1))&&(o=e,a=t,(o.parentIndex===a.parentIndex?3>=Math.abs(o.index-a.index):o.parentIndex!==a.index&&a.parentIndex!==o.index&&1>=Math.abs((o.depth??0)-(a.depth??0))&&2>=Math.abs(o.index-a.index))||function(e,t){let n=e.parentIndex===t.index?t:t.parentIndex===e.index?e:null,r=n?.index===e.index?t:n?.index===t.index?e:null;return!!n&&!!r&&T(n,r).index===n.index}(e,t))}(o,t,r)){let s=function(e,t,n,r,i){var o,a,s;let u=T(t,n),l=u.index===t.index?n:t,d=(l.type??"").toLowerCase().includes("image")?"has image":null,f=i.get(u.index)??u,p=i.get(l.index)?.presentationHints??l.presentationHints;return i.set(u.index,{...f,presentationHints:(o=f.presentationHints,a=p,s=d,[...new Set([...Array.isArray(o)?o:[],...Array.isArray(a)?a:[],...s?[s]:[]])])}),j(e,l.index,r),i.get(u.index)??u}(e,o,t,r,i);a.set(n,s);continue}a.set(n,t)}return e.filter(e=>!r.has(e.index)).map(e=>i.get(e.index)??e)}(t);return{nodes:i,filteredCount:t.length-i.length}}(e,g,t),x=(s="string"==typeof(r=e).appName?r.appName:void 0,u="string"==typeof r.appBundleId?r.appBundleId:void 0,d=[],s&&d.push(`Page: ${s}`),u&&d.push(`App: ${u}`),d.length>0?`${d.join("\n")}
17
+ `:""),v=function(e,t,n,r={nodes:t,filteredCount:0}){let i=V(e);if(!e.snapshotQuality){let e=function(e,t){if(!0===t.scoped||!0===t.depthLimited||e.length>3)return null;let n=1===e.length?"node":"nodes";return`Hint: sparse accessibility snapshot returned ${e.length} ${n}; snapshot state is invalid or unavailable for this screen. Use plain screenshot, not screenshot --overlay-refs, as visual truth. If screenshot shows the Home Screen or another app, run open for this app again first. Then navigate away with coordinates if needed and retry snapshot -i on the next screen.`}(t,n);e&&i.push(e)}!n.raw&&r.filteredCount>0&&i.push(`Collapsed ${r.filteredCount} Android helper node${1===r.filteredCount?"":"s"} from the agent-facing text snapshot; use --raw or --json for the full hierarchy.`);let o=r.filteredCount>0?r.nodes:t;return!n.raw&&function(e){if(e.length<20)return!1;let t=new Map;for(let n of e){let e=(n.type??"").toLowerCase(),r=function(e){var t;let n=e.trim().replace(/\s+/g," ").toLowerCase();return!n||(t=n,/\S+@\S+\.\S+/.test(t))?null:n}(l(n));if(!r)continue;let i=`${e}|${r}`,o=t.get(i)??[];o.push(n),t.set(i,o)}let n=0;for(let e of t.values())!(e.length<=1)&&function(e){for(let r=0;r<e.length;r+=1)for(let i=r+1;i<e.length;i+=1){var t,n;if(t=e[r]?.rect,n=e[i]?.rect,!t||!n||!(t.x+t.width<=n.x+.5||n.x+n.width<=t.x+.5||t.y+t.height<=n.y+.5||n.y+n.height<=t.y+.5))return!0}return!1}(e)&&(n+=e.length);return n>=8}(o)&&i.push("Warning: possible repeated nav subtree detected."),i}(e,g,t,y),b=v.length>0?`${v.join("\n")}
18
+ `:"",A=t.raw?null:(f=e.unchanged)&&"object"==typeof f?"number"!=typeof f.ageMs||"number"!=typeof f.nodeCount?null:{ageMs:f.ageMs,nodeCount:f.nodeCount,interactiveOnly:!0===f.interactiveOnly||void 0,scope:"string"==typeof f.scope?f.scope:void 0}:null;if(A){let e;return`${x}${b}${e=function(e){if(e<1e3)return`${Math.round(e)}ms`;if(e<6e4)return`${(Math.round(e/100)/10).toFixed(1)}s`;let t=e/6e4;return t<60?`${(Math.round(10*t)/10).toFixed(1)}m`:`${(Math.round(t/60*10)/10).toFixed(1)}h`}((i=A).ageMs),i.scope?`Scoped snapshot unchanged for scope "${i.scope}" since previous read ${e} ago.
19
+ Previous refs in this scope remain valid. Use find/get/is for a targeted query, or --force-full to re-emit.`:i.interactiveOnly?`Interactive snapshot unchanged since previous read ${e} ago.
20
+ ${i.nodeCount} visible nodes are unchanged. Previous @e refs are still valid. Use find/get/is for a targeted query, or --force-full to re-emit.`:`Snapshot unchanged since previous read ${e} ago.
21
+ Refs from the previous snapshot are still valid. Use --force-full to re-emit the tree, or use find/get/is for a targeted query.`}
22
+ `}let O=t.raw||"macos-helper"===m?null:n(y.nodes),D=!!e.truncated,L=O?.nodes??g,R=t.raw||"macos-helper"===m?null:function(e,t,n,r,i=0){let o,a=(o=e.visibility)&&"object"==typeof o&&"boolean"==typeof o.partial&&"number"==typeof o.visibleNodeCount&&"number"==typeof o.totalNodeCount&&Array.isArray(o.reasons)?{partial:o.partial,visibleNodeCount:o.visibleNodeCount,totalNodeCount:o.totalNodeCount,reasons:o.reasons.filter(e=>"string"==typeof e)}:null;if(0===i&&a)return a;let s=(t?.hiddenCount??0)+i,u=!!t&&t.nodes.some(e=>e.hiddenContentAbove||e.hiddenContentBelow);return s>0?{partial:!0,visibleNodeCount:n,totalNodeCount:Math.max(r,a?.totalNodeCount??r),reasons:[...new Set([...a?.reasons??[],"offscreen-nodes"])]}:a||(u?{partial:!0,visibleNodeCount:n,totalNodeCount:n,reasons:[]}:null)}(e,O,L.length,g.length,y.filteredCount),H=(o=g.length,a=R,p=D?" (truncated)":"",a?.partial?a.totalNodeCount>a.visibleNodeCount?`Snapshot: ${a.visibleNodeCount} visible nodes (${a.totalNodeCount} total)${p}`:`Snapshot: ${a.visibleNodeCount} visible nodes${p}`:`Snapshot: ${o} nodes${p}`);return 0===g.length?`${x}${H}
23
+ ${b}`:t.raw?`${x}${H}
24
+ ${b}${g.map(e=>JSON.stringify(e)).join("\n")}
25
+ `:t.flatten?`${x}${H}
26
+ ${b}${h(L,{summarizeTextSurfaces:!0}).flatMap(e=>[$(e.node,0,!1,e.type,{summarizeTextSurfaces:!0}),...X({...e,depth:0})]).join("\n")}${K(O)}
27
+ `:`${x}${H}
28
+ ${b}${(function(e){let t=[],n=[],r=new Map(e.map(e=>[e.node.index,e.node])),i=e=>{for(var i,o,a;n.length>0&&(!e||(i=e,o=n[n.length-1],a=r,!function(e,t,n){let r=e;for(;"number"==typeof r.parentIndex;){if(r.parentIndex===t.index)return!0;let e=n.get(r.parentIndex);if(!e)break;r=e}return!1}(i.node,o.node,a)&&i.depth<=o.depth));)t.push(...X(n.pop(),"below"))};for(let r of e)i(r),t.push(r.text),t.push(...X(r,"above")),r.node.hiddenContentBelow&&n.push(r);return i(),t})(h(L,{summarizeTextSurfaces:!0})).join("\n")}${K(O)}
29
+ `}(o,{raw:r.raw,flatten:r.interactiveOnly,scoped:"string"==typeof r.scope&&r.scope.trim().length>0,depthLimited:"number"==typeof r.depth})}},wait:m,alert:m,...ey,...et,...eo,...ed,...Z,...b,...em,metro:({input:e,result:t})=>{var n;return{data:(n={result:t,action:e.action}).result,text:"reload"===n.action?`Reloaded React Native apps via ${n.result.reloadUrl}`:JSON.stringify(n.result,null,2)}}};function ev(e){return ex[e.name]?.({input:e.input??{},result:e.result})}export{ev as formatCliOutput,z as formatScreenshotDiffText,_ as formatSnapshotDiffText,H as printHumanError,R as printJson};