agent-device 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.0.apk → agent-device-android-multitouch-helper-0.17.2.apk} +0 -0
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.2.apk.sha256 +1 -0
- package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.17.0.manifest.json → agent-device-android-multitouch-helper-0.17.2.manifest.json} +4 -4
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.0.apk → agent-device-android-snapshot-helper-0.17.2.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.2.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.17.0.manifest.json → agent-device-android-snapshot-helper-0.17.2.manifest.json} +6 -6
- package/dist/src/123.js +1 -0
- package/dist/src/1352.js +1 -1
- package/dist/src/1534.js +1 -0
- package/dist/src/1620.js +1 -0
- package/dist/src/1644.js +2 -0
- package/dist/src/2284.js +1 -0
- package/dist/src/2403.js +3 -0
- package/dist/src/2415.js +28 -29
- package/dist/src/2474.js +1 -0
- package/dist/src/2672.js +1 -0
- package/dist/src/3393.js +1 -0
- package/dist/src/4778.js +1 -1
- package/dist/src/5898.js +1 -0
- package/dist/src/7556.js +1 -1
- package/dist/src/7847.js +1 -1
- package/dist/src/8173.js +27 -0
- package/dist/src/8407.js +1 -0
- package/dist/src/8699.js +1 -1
- package/dist/src/8806.js +3 -3
- package/dist/src/9010.js +1 -0
- package/dist/src/9238.js +3 -3
- package/dist/src/9471.js +1 -1
- package/dist/src/9542.js +3 -3
- package/dist/src/9616.js +1 -0
- package/dist/src/9673.js +1 -0
- package/dist/src/9974.js +1 -0
- package/dist/src/android-adb.d.ts +12 -6
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +15 -7
- package/dist/src/android.js +1 -1
- package/dist/src/apple.js +1 -1
- package/dist/src/apps.js +2 -2
- package/dist/src/args.js +2 -2
- package/dist/src/batch.d.ts +16 -4
- package/dist/src/cli.js +18 -42
- package/dist/src/command-surface.js +1 -1
- package/dist/src/contracts.d.ts +28 -4
- package/dist/src/contracts.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/finders.d.ts +3 -1
- package/dist/src/generic.js +13 -11
- package/dist/src/index.d.ts +142 -73
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/internal/png-worker.d.ts +26 -0
- package/dist/src/internal/png-worker.js +1 -0
- package/dist/src/metro.d.ts +3 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-trace-recording.js +26 -0
- package/dist/src/record-trace.js +1 -26
- package/dist/src/remote-config.d.ts +33 -7
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +3 -3
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +2 -2
- package/dist/src/session.js +10 -11
- package/dist/src/snapshot.js +1 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +6 -2
- package/package.json +7 -4
- package/server.json +2 -2
- package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.17.0.apk.sha256 +0 -1
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.17.0.apk.sha256 +0 -1
- package/dist/src/1998.js +0 -1
- package/dist/src/2805.js +0 -1
- package/dist/src/4057.js +0 -1
- package/dist/src/5792.js +0 -1
- package/dist/src/6085.js +0 -1
- package/dist/src/6232.js +0 -1
- package/dist/src/8020.js +0 -1
- package/dist/src/8502.js +0 -1
- package/dist/src/940.js +0 -1
- package/dist/src/9404.js +0 -1
- package/dist/src/9533.js +0 -1
- package/dist/src/command-metadata.js +0 -1
- /package/dist/src/{1393.js → 3675.js} +0 -0
- /package/dist/src/{5310.js → 695.js} +0 -0
package/dist/src/apps.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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"./1998.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,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}
|
|
2
2
|
${i}
|
|
3
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}
|
|
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)
|
|
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
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
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
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}
|
package/dist/src/args.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{listCliCommandNames as e}from"./
|
|
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
|
|
2
2
|
|
|
3
3
|
Version-matched operating guide for normal agent-device work.
|
|
4
4
|
|
|
@@ -27,7 +27,7 @@ Bootstrap:
|
|
|
27
27
|
agent-device prepare ios-runner --platform ios --timeout 240000
|
|
28
28
|
If app id is unknown, plan devices, apps, then open <discovered-app-id>. Discovery is not enough when the task asks to open/start the app.
|
|
29
29
|
Install arguments are app/package id then artifact path. If the task says install, use install; use reinstall only when explicitly requested. Fresh runtime state is open --relaunch after install.
|
|
30
|
-
In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner, health-checks it with a lightweight command, and retries one stuck/non-connecting runner launch before the first snapshot pays that setup cost.
|
|
30
|
+
In Apple CI, run prepare ios-runner after boot/install and before replay/test. prepare ios-runner builds/reuses the XCTest runner, health-checks it with a lightweight command, and retries one stuck/non-connecting runner launch before the first snapshot pays that setup cost. If the replay/test step starts a separate daemon, run clean:daemon after prepare so the prepared runner does not keep a live lease owned by the prepare daemon.
|
|
31
31
|
CI may cache ~/.agent-device/ios-runner/derived with an exact key that includes the agent-device package and Xcode version. Avoid broad restore-key fallbacks; prepare ios-runner already recovers bad restored runner artifacts and one retryable non-connecting runner launch. Runner build/start output is written to the session's runner.log; daemon.log is for daemon lifecycle/startup issues.
|
|
32
32
|
Do not open artifact paths or invent package ids. If apps lookup misses the target and no URL/artifact is provided, ask or stop.
|
|
33
33
|
|
package/dist/src/batch.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export declare type BatchStepResult = {
|
|
|
22
22
|
|
|
23
23
|
export declare function buildBatchStepFlags(parentFlags: BatchFlags | Record<string, unknown> | undefined, stepFlags: DaemonBatchStep['flags'] | Record<string, unknown> | undefined): BatchFlags;
|
|
24
24
|
|
|
25
|
+
declare const DAEMON_LOCK_POLICIES: readonly ["reject", "strip"];
|
|
26
|
+
|
|
25
27
|
declare type DaemonArtifact = {
|
|
26
28
|
field: string;
|
|
27
29
|
artifactId?: string;
|
|
@@ -66,7 +68,7 @@ declare type DaemonInstallSource = {
|
|
|
66
68
|
artifactName: string;
|
|
67
69
|
}));
|
|
68
70
|
|
|
69
|
-
declare type DaemonLockPolicy =
|
|
71
|
+
declare type DaemonLockPolicy = (typeof DAEMON_LOCK_POLICIES)[number];
|
|
70
72
|
|
|
71
73
|
declare type DaemonRequest = {
|
|
72
74
|
token?: string;
|
|
@@ -88,7 +90,7 @@ declare type DaemonRequestMeta = {
|
|
|
88
90
|
leaseId?: string;
|
|
89
91
|
leaseTtlMs?: number;
|
|
90
92
|
leaseBackend?: LeaseBackend;
|
|
91
|
-
sessionIsolation?:
|
|
93
|
+
sessionIsolation?: SessionIsolationMode;
|
|
92
94
|
uploadedArtifactId?: string;
|
|
93
95
|
clientArtifactPaths?: Record<string, string>;
|
|
94
96
|
installSource?: DaemonInstallSource;
|
|
@@ -96,7 +98,7 @@ declare type DaemonRequestMeta = {
|
|
|
96
98
|
materializedPathRetentionMs?: number;
|
|
97
99
|
materializationId?: string;
|
|
98
100
|
lockPolicy?: DaemonLockPolicy;
|
|
99
|
-
lockPlatform?:
|
|
101
|
+
lockPlatform?: PlatformSelector;
|
|
100
102
|
requestProgress?: 'replay-test';
|
|
101
103
|
};
|
|
102
104
|
|
|
@@ -116,7 +118,9 @@ export declare const DEFAULT_BATCH_MAX_STEPS = 100;
|
|
|
116
118
|
|
|
117
119
|
export declare const INHERITED_PARENT_FLAG_KEYS: readonly ["platform", "target", "device", "udid", "serial", "verbose", "out"];
|
|
118
120
|
|
|
119
|
-
declare
|
|
121
|
+
declare const LEASE_BACKENDS: readonly ["ios-simulator", "ios-instance", "android-instance"];
|
|
122
|
+
|
|
123
|
+
declare type LeaseBackend = (typeof LEASE_BACKENDS)[number];
|
|
120
124
|
|
|
121
125
|
export declare type NormalizedBatchStep = {
|
|
122
126
|
command: string;
|
|
@@ -125,8 +129,16 @@ export declare type NormalizedBatchStep = {
|
|
|
125
129
|
runtime?: unknown;
|
|
126
130
|
};
|
|
127
131
|
|
|
132
|
+
declare const PLATFORM_SELECTORS: readonly ["ios", "macos", "android", "linux", "apple"];
|
|
133
|
+
|
|
134
|
+
declare type PlatformSelector = (typeof PLATFORM_SELECTORS)[number];
|
|
135
|
+
|
|
128
136
|
export declare function runBatch(req: BatchRequest, sessionName: string, invoke: BatchInvoke): Promise<DaemonResponse>;
|
|
129
137
|
|
|
138
|
+
declare const SESSION_ISOLATION_MODES: readonly ["none", "tenant"];
|
|
139
|
+
|
|
140
|
+
declare type SessionIsolationMode = (typeof SESSION_ISOLATION_MODES)[number];
|
|
141
|
+
|
|
130
142
|
declare type SessionRuntimeHints = {
|
|
131
143
|
platform?: 'ios' | 'android';
|
|
132
144
|
metroHost?: string;
|