agent-device 0.19.2 → 0.19.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 (85) hide show
  1. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.2.apk → agent-device-android-multitouch-helper-0.19.3.apk} +0 -0
  2. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.3.apk.sha256 +1 -0
  3. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.2.manifest.json → agent-device-android-multitouch-helper-0.19.3.manifest.json} +4 -4
  4. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.2.apk → agent-device-android-snapshot-helper-0.19.3.apk} +0 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.3.apk.sha256 +1 -0
  6. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.2.manifest.json → agent-device-android-snapshot-helper-0.19.3.manifest.json} +6 -6
  7. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +7 -0
  8. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +99 -30
  9. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +9 -1
  10. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +21 -8
  11. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +10 -0
  12. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +1 -0
  13. package/dist/src/agent-browser-tool.js +1 -1
  14. package/dist/src/android-adb.js +1 -1
  15. package/dist/src/android-input-ownership.js +1 -1
  16. package/dist/src/android.js +1 -1
  17. package/dist/src/app-lifecycle.js +1 -1
  18. package/dist/src/apple-runner-options.js +1 -1
  19. package/dist/src/apps.js +5 -5
  20. package/dist/src/audio-probe.js +1 -1
  21. package/dist/src/cli-help.js +14 -14
  22. package/dist/src/cli-runner.js +1 -1
  23. package/dist/src/cli.js +11 -11
  24. package/dist/src/client.js +2 -2
  25. package/dist/src/contracts.js +1 -1
  26. package/dist/src/debug-symbols.js +1 -1
  27. package/dist/src/device-input-state.js +1 -1
  28. package/dist/src/devices2.js +1 -1
  29. package/dist/src/find.js +1 -1
  30. package/dist/src/generic.js +1 -1
  31. package/dist/src/helper.js +1 -1
  32. package/dist/src/index.d.ts +11 -7
  33. package/dist/src/index.js +1 -1
  34. package/dist/src/input-actions.js +1 -1
  35. package/dist/src/input-actions2.js +1 -1
  36. package/dist/src/install-source2.js +1 -1
  37. package/dist/src/interaction-snapshot.js +1 -1
  38. package/dist/src/interaction.js +1 -1
  39. package/dist/src/interactor.js +2 -2
  40. package/dist/src/internal/bin.js +1 -1
  41. package/dist/src/internal/daemon.js +20 -16
  42. package/dist/src/internal/png-worker.js +1 -1
  43. package/dist/src/lease.js +1 -1
  44. package/dist/src/linux.js +1 -1
  45. package/dist/src/notifications.js +1 -1
  46. package/dist/src/png-worker-contract.js +1 -1
  47. package/dist/src/points.js +3 -3
  48. package/dist/src/providers.js +1 -1
  49. package/dist/src/react-native.js +1 -1
  50. package/dist/src/record-trace-recording.js +2 -2
  51. package/dist/src/record-trace.js +1 -1
  52. package/dist/src/registry.js +14 -14
  53. package/dist/src/reporting.js +3 -3
  54. package/dist/src/runner-client.js +1 -1
  55. package/dist/src/runner-sequence.js +1 -1
  56. package/dist/src/runtime-transport.js +1 -1
  57. package/dist/src/runtime.js +2 -2
  58. package/dist/src/sdk-android-adb.js +3 -3
  59. package/dist/src/sdk-app-inventory.js +1 -1
  60. package/dist/src/sdk-batch-runner.js +2 -2
  61. package/dist/src/sdk-batch.js +2 -2
  62. package/dist/src/sdk-contracts.js +2 -2
  63. package/dist/src/sdk-device.js +1 -0
  64. package/dist/src/sdk-finders.js +1 -1
  65. package/dist/src/sdk-io.js +1 -1
  66. package/dist/src/sdk-remote-config.js +1 -1
  67. package/dist/src/sdk-selectors.js +1 -1
  68. package/dist/src/selector-runtime.js +1 -1
  69. package/dist/src/server.js +2 -2
  70. package/dist/src/session.js +10 -10
  71. package/dist/src/setting-state.js +1 -1
  72. package/dist/src/simctl.js +1 -1
  73. package/dist/src/simulator.js +1 -1
  74. package/dist/src/snapshot-diagnostics.js +1 -1
  75. package/dist/src/snapshot.js +1 -1
  76. package/dist/src/snapshot2.js +2 -2
  77. package/dist/src/tool-provider.js +2 -2
  78. package/dist/src/tool-provider2.js +1 -1
  79. package/dist/src/tv-remote.js +12 -12
  80. package/dist/src/web.js +1 -1
  81. package/package.json +11 -3
  82. package/server.json +2 -2
  83. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.2.apk.sha256 +0 -1
  84. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.2.apk.sha256 +0 -1
  85. package/dist/src/snapshot-helper.js +0 -5
package/dist/src/apps.js CHANGED
@@ -1,5 +1,5 @@
1
- import{t as e}from"./rolldown-runtime.js";import{F as t,m as n,p as r}from"./sdk-contracts.js";import{h as i,j as a,p as o,v as s}from"./sdk-android-adb.js";import{Ot as c,Tt as l}from"./tv-remote.js";import{i as u}from"./runtime.js";import{n as ee,t as te}from"./install-source2.js";import{D as d,E as f,O as ne,S as p,k as re,w as m,x as ie}from"./android-input-ownership.js";import{d as h,i as ae}from"./runner-client.js";import{a as g,i as oe,l as se,o as _}from"./tool-provider.js";import{a as ce,n as le}from"./helper.js";import{n as v,r as ue}from"./simctl.js";import{$ as de,G as y,J as fe,Jt as pe,K as me,Q as he,U as ge,V as b,Y as x,Yt as _e,bt as ve,et as ye,tt as be,yt as xe}from"./internal/daemon.js";import{a as Se,i as Ce,n as S,r as C,t as w}from"./setting-state.js";import{i as T,n as we,t as E}from"./simulator.js";import{promises as D}from"node:fs";import O from"node:os";import k from"node:path";import{fileURLToPath as Te}from"node:url";function A(e){if(!(e instanceof t))return{reason:e instanceof Error?e.message:String(e)};let n=e.details??{},r=Array.isArray(n.args)?n.args.filter(e=>typeof e==`string`).join(` `):void 0;return{errorCode:e.code,reason:e.message,timeoutMs:typeof n.timeoutMs==`number`?n.timeoutMs:void 0,exitCode:typeof n.exitCode==`number`?n.exitCode:void 0,stderr:typeof n.stderr==`string`&&n.stderr.trim()?n.stderr:void 0,stdout:typeof n.stdout==`string`&&n.stdout.trim()?n.stdout:void 0,commandArgs:r}}const Ee=[`--time`,`9:41`,`--dataNetwork`,`wifi`,`--wifiMode`,`active`,`--wifiBars`,`3`,`--batteryState`,`charged`,`--batteryLevel`,`100`],De={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`},Oe={1:`searching`,2:`failed`,3:`active`},ke={0:`notSupported`,1:`searching`,2:`failed`,3:`active`};function j(e,t,n){return ue(e,t,n)}const M=new Set;async function Ae(e){let t=null,n=!1;if(Me(e))n=!0;else try{t=await Ne(e),n=!0}catch(t){R(e,`snapshot_failed`,t)}try{(!n||t)&&await I(e),await L(e,Ee)}catch(t){R(e,`prepare_failed`,t)}return async()=>{await je(e,n?t:null)}}async function je(e,t){if(await I(e),!t){P(e);return}await L(e,Fe(t)),N(e)}function N(e){M.delete(F(e))}function P(e){M.add(F(e))}function Me(e){return M.has(F(e))}function F(e){return`${e.platform}:${e.kind}:${e.id}`}async function Ne(e){return Pe(i(await j(e,[`status_bar`,e.id,`list`],{allowFailure:!0}),`Failed to read simulator status bar overrides`).stdout)}async function I(e){await j(e,[`status_bar`,e.id,`clear`])}async function L(e,t){t.length!==0&&await j(e,[`status_bar`,e.id,`override`,...t])}function Pe(e){let n={},r=e.split(`
2
- `).map(e=>e.trim()).filter(e=>e.length>0&&e!==`Current Status Bar Overrides:`&&!/^=+$/.test(e));for(let e of r){let r=/^DataNetworkType:\s+(\d+)$/.exec(e);if(r){let e=Number(r[1]),i=De[e];if(!i)throw new t(`COMMAND_FAILED`,`Unsupported simulator data network type: ${e}`);n.dataNetwork=i;continue}let i=/^WiFi Mode:\s+(\d+),\s+WiFi Bars:\s+(\d+)$/.exec(e);if(i){let e=Oe[Number(i[1])];e&&(n.wifiMode=e),n.wifiBars=i[2];continue}let a=/^Cell Mode:\s+(\d+),\s+Cell Bars:\s+(\d+)$/.exec(e);if(a){let e=Number(a[1]),r=ke[e];if(!r)throw new t(`COMMAND_FAILED`,`Unsupported simulator cellular mode: ${e}`);n.cellularMode=r,n.cellularBars=a[2];continue}let o=/^Operator Name:\s*(.*)$/.exec(e);if(o){n.operatorName=o[1]??``;continue}}return Object.keys(n).length===0?null:n}function Fe(e){let t=[];return e.dataNetwork&&t.push(`--dataNetwork`,e.dataNetwork),e.wifiMode&&t.push(`--wifiMode`,e.wifiMode),e.wifiBars!==void 0&&(e.dataNetwork===`wifi`||e.wifiMode)&&t.push(`--wifiBars`,e.wifiBars),e.cellularMode&&t.push(`--cellularMode`,e.cellularMode),e.cellularBars!==void 0&&(e.cellularMode||Ie(e.dataNetwork)||e.operatorName!==void 0)&&t.push(`--cellularBars`,e.cellularBars),e.operatorName!==void 0&&t.push(`--operatorName`,e.operatorName),t}function Ie(e){return!!(e&&e!==`hide`&&e!==`wifi`)}function R(e,t,n){a({level:`warn`,phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...A(n)}})}function z(e,t,n){return ue(e,t,n)}const Le={ensureBooted:E,prepareStatusBarForScreenshot:Ae,captureWithRetry:Be,normalizeDensity:Xe,captureWithRunner:V,shouldFallbackToRunner:Je},B=new Map;async function Re(e,t,r={}){if(n(e)){await V(e,t,r.appBundleId,r.fullscreen,r.runnerOptions);return}if(e.kind===`simulator`){await ze(e,t,r);return}try{await y([`device`,`screenshot`,`--device`,e.id,t],{action:`capture iOS screenshot`,deviceId:e.id});return}catch(t){if(!qe(t))throw t;We(e,`devicectl_screenshot`,t)}await V(e,t,r.appBundleId,r.fullscreen,r.runnerOptions)}async function ze(e,n,r={}){if(e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`Simulator screenshot fallback flow supports only iOS simulators`);let i={...Le,...r.deps??{}};r.skipIosSimulatorBootCheck||await i.ensureBooted(e);let a=async()=>{};if(r.normalizeStatusBar===!0)try{a=await i.prepareStatusBarForScreenshot(e)}catch(t){Ge(e,`prepare_failed`,t)}try{try{await i.captureWithRetry(e,n),await i.normalizeDensity(e,n,r.pixelDensity);return}catch(t){let a=t;if(r.skipIosSimulatorBootCheck&&Ye(t)){await i.ensureBooted(e);try{await i.captureWithRetry(e,n),await i.normalizeDensity(e,n,r.pixelDensity);return}catch(e){a=e}}if(!i.shouldFallbackToRunner(a))throw a;We(e,`simctl_screenshot`,a)}await i.captureWithRunner(e,n,r.appBundleId,r.fullscreen,r.runnerOptions),await i.normalizeDensity(e,n,r.pixelDensity)}finally{await a().catch(t=>Ge(e,`restore_failed`,t))}}async function Be(e,t){let n=p.fromTimeoutMs(ye);await m(async({deadline:n})=>{await z(e,[`io`,e.id,`screenshot`,t],{timeoutMs:Math.max(1e3,n?.remainingMs()??2e4)})},{maxAttempts:5,baseDelayMs:he,maxDelayMs:de,jitter:.2,shouldRetry:e=>Je(e)},{deadline:n,phase:`ios_simulator_screenshot`})}async function V(e,r,i,a,o){let s=(await ae(e,{command:`screenshot`,appBundleId:i,fullscreen:a},o)).message;if(!s)throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: runner returned no file path`);if(n(e)){await D.copyFile(s,r);return}if(e.kind===`simulator`){await He(e,s,r);return}await Ve(e,s,r)}async function Ve(e,n,r){let i=p.fromTimeoutMs(x),a={exitCode:1,stdout:``,stderr:``};for(let t of h)if(a=await _([`devicectl`,`device`,`copy`,`from`,`--device`,e.id,`--source`,n,`--destination`,r,`--domain-type`,`appDataContainer`,`--domain-identifier`,t],{allowFailure:!0,timeoutMs:Ue(i,x,`runner screenshot copy`)}),a.exitCode===0)return;throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: ${a.stderr.trim()||a.stdout.trim()||`devicectl exited with code ${a.exitCode}`}`)}async function He(e,n,r){let i=p.fromTimeoutMs(x),a=`Unable to locate runner container for simulator screenshot`;for(let t of h){let o=await z(e,[`get_app_container`,e.id,t,`data`],{allowFailure:!0,timeoutMs:Ue(i,x,`runner screenshot container lookup`)});if(o.exitCode!==0){let e=o.stderr.trim();e&&(a=e);continue}let s=o.stdout.trim();if(!s){a=`simctl get_app_container returned empty output`;continue}let c=Ke(s,n);for(let e of c)try{await D.copyFile(e,r);return}catch(e){a=e instanceof Error?e.message:String(e)}}throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: ${a}`)}function Ue(e,n,r){let i=e.remainingMs();if(i>0)return i;throw new t(`COMMAND_FAILED`,`iOS ${r} timed out after ${n}ms`,{timeoutMs:n,step:r})}function We(e,t,n){let r=A(n);a({level:`warn`,phase:`ios_screenshot_fallback`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:`runner`,...r}})}function Ge(e,t,n){a({level:`warn`,phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...A(n)}})}function Ke(e,t){let n=k.resolve(e),r=t.trim();if(!r)return[];let i=[],a=new Set,o=e=>{let t=k.normalize(e);a.has(t)||(a.add(t),i.push(t))},s=r.replace(/^\/+/,``),c=s.replace(/\\/g,`/`);if(s&&o(k.join(n,s)),k.isAbsolute(r)&&o(k.normalize(r)),c.startsWith(`tmp/`))o(k.join(n,c));else{let e=c.lastIndexOf(`/tmp/`);if(e>=0){let t=c.slice(e+1);o(k.join(n,t))}}let l=k.basename(r);return l&&o(k.join(n,`tmp`,l)),i}function qe(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`unknown option '--device'`)||n.includes(`unknown subcommand`)&&n.includes(`screenshot`)||n.includes(`unrecognized subcommand`)&&n.includes(`screenshot`)}function Je(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`timeout waiting for screen surfaces`)||n.includes(`nsposixerrordomain`)&&n.includes(`code=60`)&&n.includes(`screenshot`)||n.includes(`timed out`)&&n.includes(`screenshot`)}function Ye(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`not booted`)||n.includes(`current state: shutdown`)||n.includes(`current state is shutdown`)||n.includes(`current state=shutdown`)||n.includes(`state: shutdown`)||n.includes(`state=shutdown`)}function H(e){let t=e.details??{},n=typeof t.stdout==`string`?t.stdout:``,r=typeof t.stderr==`string`?t.stderr:``,i=Array.isArray(t.args)?t.args.filter(e=>typeof e==`string`).join(` `):``;return`${e.message}\n${n}\n${r}\n${i}`.toLowerCase()}async function Xe(e,t,n){let r=await Ze(e),i=xe(await ve(t),r,n);i&&await u(t,i.width,i.height)}async function Ze(e){let n=B.get(e.id);if(n!==void 0)return n;let r=await z(e,[`getenv`,e.id,`SIMULATOR_MAINSCREEN_SCALE`],{timeoutMs:5e3}),i=Number(r.stdout.trim());if(!Number.isFinite(i)||i<=0)throw new t(`COMMAND_FAILED`,`Failed to read iOS simulator screenshot scale from SIMULATOR_MAINSCREEN_SCALE`);return B.set(e.id,i),i}const Qe={settings:`com.apple.systempreferences`},$e=/^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/,et={platform:`macos`,deviceId:`host`,variant:`all`},U=f();function tt(e){return $e.test(e)}async function W(e){let n=e.trim(),r=Qe[n.toLowerCase()];if(r)return r;if(tt(n))return n;let i=U.get(et,n);if(i)return i;let a=(await ct(`all`)).filter(e=>e.name.toLowerCase()===n.toLowerCase()),o=a[0];if(o!==void 0&&a.length===1)return U.set(et,n,o.bundleId);throw a.length>1?new t(`INVALID_ARGS`,`Multiple apps matched "${e}"`,{matches:a}):new t(`APP_NOT_INSTALLED`,`No app found matching "${e}"`)}async function nt(e,n,r){let i=r?.url?.trim();if(i){if(!d(i))throw new t(`INVALID_ARGS`,`open <app> <url> requires a valid URL target`);let e=r?.appBundleId??await W(n);await G().openBundle(e,i);return}let a=n.trim();if(d(a)){await G().openTarget(a);return}let o=r?.appBundleId??await W(a);await G().openBundle(o)}async function rt(e,n){let r=await W(n),i=await le(r);if(!(!i.running||i.terminated||i.forceTerminated))throw new t(`COMMAND_FAILED`,`Failed to close macOS app ${n}`,{bundleId:r,running:i.running,terminated:i.terminated,forceTerminated:i.forceTerminated})}async function it(){return await G().readClipboard()}async function at(e){await G().writeClipboard(e)}async function ot(){return await G().readDarkMode()}async function st(e){let t=S(e),n=t===`toggle`?!await ot():t===`dark`;await G().setDarkMode(n)}async function ct(e){return await G().listApps(e)}function G(){let e=oe().macosHost;if(!e)throw new t(`UNSUPPORTED_OPERATION`,`macOS host provider is not available`);return e}function K(e,t){return v(e,t)}function q(e,t,n){return _(K(e,t),n)}function lt(e){return e.includes(`not installed`)||e.includes(`not found`)||e.includes(`no such file`)}const ut={settings:`com.apple.Preferences`},J=f();function dt(e){return{platform:`ios`,deviceId:e.id,variant:e.kind}}async function Y(e,t){return await J.invalidateWhile(dt(e),t)}async function X(e,r){if(n(e))return await W(r);let i=r.trim();if(i.includes(`.`))return i;let a=ut[i.toLowerCase()];if(a)return a;let o=dt(e),s=J.get(o,i);if(s)return s;let c=(e.kind===`simulator`?await ht(e):await ge(e,`all`)).filter(e=>e.name.toLowerCase()===i.toLowerCase()),l=c[0];if(l!==void 0&&c.length===1)return J.set(o,i,l.bundleId);throw c.length>1?new t(`INVALID_ARGS`,`Multiple apps matched "${r}"`,{matches:c}):new t(`APP_NOT_INSTALLED`,`No app found matching "${r}"`)}async function ft(e,t){if(!r(e)||e.kind!==`simulator`)return;let n=pt(t);if(!n)return;let i=await gt(e),a=[];for(let e of i)e.bundleId.startsWith(`com.callstack.agentdevice.runner`)||e.path&&(await vt(k.join(e.path,`Info.plist`))).has(n)&&a.push(e);let o=a.filter(e=>e.applicationType===`User`);if(o.length===1)return o[0]?.bundleId;if(!(o.length>1))return a.length===1?a[0]?.bundleId:void 0}function pt(e){return/^([A-Za-z][A-Za-z0-9+.-]*):/.exec(e.trim())?.[1]?.toLowerCase()}async function mt(e,t){return n(e)?await ct(t):e.kind===`simulator`?se(await ht(e),t):await ge(e,t)}async function ht(e){return(await gt(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function gt(e){let t=(await q(e,[`listapps`,e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let n=null;if(t.startsWith(`{`))try{n=JSON.parse(t)}catch{n=null}if(!n&&t.startsWith(`{`))try{let e=await g(`plutil`,[`-convert`,`json`,`-o`,`-`,`-`],{allowFailure:!0,stdin:t});e.exitCode===0&&e.stdout.trim().startsWith(`{`)&&(n=JSON.parse(e.stdout))}catch{n=null}return n?Object.entries(n).map(([e,t])=>{let n=_t(t);return{bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e,...n?{path:n}:{},...t.ApplicationType?{applicationType:t.ApplicationType}:{}}}):[]}function _t(e){if(e.Path)return e.Path;if(e.Bundle)try{return Te(e.Bundle)}catch{return}}async function vt(e){let t=await g(`plutil`,[`-convert`,`json`,`-o`,`-`,e],{allowFailure:!0});if(t.exitCode!==0)return new Set;try{let e=JSON.parse(t.stdout),n=new Set;for(let t of e.CFBundleURLTypes??[])if(Array.isArray(t.CFBundleURLSchemes))for(let e of t.CFBundleURLSchemes)typeof e==`string`&&e.trim()&&n.add(e.trim().toLowerCase());return n}catch{return new Set}}function yt(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=e.details??{};if(n.exitCode!==4)return!1;let r=String(n.stderr??``).toLowerCase();return r.includes(`fbsopenapplicationserviceerrordomain`)&&r.includes(`the request to open`)}async function bt(e,t){let n=await _(v(e,[`get_app_container`,e.id,t]),{allowFailure:!0});if(n.exitCode!==0)return{installed:!1};let r=n.stdout.trim();if(!r)return{installed:!1};let i=await g(`plutil`,[`-extract`,`CFBundleExecutable`,`raw`,`-o`,`-`,`${r}/Info.plist`],{allowFailure:!0});if(i.exitCode!==0||!i.stdout.trim())return{installed:!0};let a=await g(`otool`,[`-l`,`${r}/${i.stdout.trim()}`],{allowFailure:!0});if(a.exitCode!==0)return{installed:!0};let o=a.stdout.toLowerCase();return{installed:!0,simulatorCompatible:o.includes(`iossimulator`)||o.includes(`platform 7`)}}function xt(e){return e.installed?e.simulatorCompatible===!1?`ARCH_MISMATCH`:`PERSISTENT_LAUNCH_FAIL`:`APP_NOT_INSTALLED`}function St(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.`}}const Z=25e3;async function Ct(e,i,a){let o=a?.launchConsole?.trim(),s=a?.launchArgs;if(o&&(!r(e)||e.kind!==`simulator`))throw new t(`UNSUPPORTED_OPERATION`,_e);if(n(e)){if(s&&s.length>0)throw new t(`UNSUPPORTED_OPERATION`,`--launch-args is not supported on macOS; launch arguments are currently iOS-only.`);await nt(e,i,a);return}let c=a?.url?.trim();if(c){if(o)throw new t(`INVALID_ARGS`,pe);if(!d(c))throw new t(`INVALID_ARGS`,`open <app> <url> requires a valid URL target`);if(e.kind===`simulator`){(s||ne(c))&&await Dt(e,a?.appBundleId??await X(e,i),{...s?{launchArgs:s}:{}}),await wt(e,c,void 0);return}let n=re(a?.appBundleId??await X(e,i),c);if(!n)throw new t(`INVALID_ARGS`,`Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.`);await Q(e,n,{payloadUrl:c,launchArgs:s});return}let l=i.trim();if(d(l)){if(o)throw new t(`INVALID_ARGS`,pe);if(e.kind===`simulator`){await wt(e,l,s);return}let n=re(a?.appBundleId,l);if(!n)throw new t(`INVALID_ARGS`,`Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.`);await Q(e,n,{payloadUrl:l,launchArgs:s});return}let u=a?.appBundleId??await X(e,i);if(e.kind===`simulator`){await Dt(e,u,{...o?{launchConsole:o}:{},...s?{launchArgs:s}:{},...a?.terminateRunningApp?{terminateRunningApp:!0}:{}});return}await Q(e,u,{launchArgs:s})}async function wt(e,n,r){if(r&&r.length>0)throw new t(`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 E(e),await q(e,[`openurl`,e.id,n])}async function Tt(e){n(e)||e.kind===`simulator`&&await we(e)!==`Booted`&&await E(e)}async function Et(e,r){if(n(e)){await rt(e,r);return}let i=await X(e,r);if(e.kind===`simulator`){await E(e);let n=K(e,[`terminate`,e.id,i]),r=await _(n,{allowFailure:!0,timeoutMs:be});if(r.exitCode!==0){if(r.stderr.toLowerCase().includes(`found nothing to terminate`))return;throw new t(`COMMAND_FAILED`,`xcrun exited with code ${r.exitCode}`,o(r,{cmd:`xcrun`,args:n}))}return}await y([`device`,`process`,`terminate`,`--device`,e.id,i],{action:`terminate iOS app`,deviceId:e.id})}async function Dt(e,n,r){await E(e);let i=0,a=p.fromTimeoutMs(me);try{await m(async({deadline:i})=>{if(i?.isExpired())throw new t(`COMMAND_FAILED`,`App launch deadline exceeded`,{timeoutMs:me});let a=K(e,Ot(e.id,n,r)),s=r?.launchConsole?await kt(a,r.launchConsole):await _(a,{allowFailure:!0});if(s.exitCode!==0)throw new t(`COMMAND_FAILED`,`xcrun exited with code ${s.exitCode}`,o(s,{cmd:`xcrun`,args:a}))},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry(e){return yt(e)?(i+=1,i<3):!1}},{deadline:a})}catch(t){if(yt(t)){let r=t,i=xt(await bt(e,n));r.details={...r.details,hint:St(i)}}throw t}}function Ot(e,t,n){let r=[`launch`];return n?.launchConsole&&r.push(`--console-pty`),n?.terminateRunningApp&&r.push(`--terminate-running-process`),r.push(e,t),n?.launchArgs&&n.launchArgs.length>0&&r.push(...n.launchArgs),r}async function kt(e,n){await D.mkdir(k.dirname(n),{recursive:!0});try{let t=await _(e,{allowFailure:!0,timeoutMs:Z});return await At(n,t.stdout,t.stderr),t}catch(e){let r=(e instanceof t?e:void 0)?.details;if(r?.timeoutMs===Z){let e=typeof r.stdout==`string`?r.stdout:``,t=typeof r.stderr==`string`?r.stderr:``;return await At(n,e,t),a({level:`warn`,phase:`ios_simulator_launch_console_capture_timeout`,data:{timeoutMs:Z,logPath:n,stdoutBytes:Buffer.byteLength(e),stderrBytes:Buffer.byteLength(t)}}),{stdout:e,stderr:t,exitCode:0}}throw e}}async function At(e,t,n){await D.writeFile(e,jt(t,n),`utf8`)}function jt(e,t){return!e||!t||e.endsWith(`
3
- `)||e.endsWith(`\r`)?`${e}${t}`:`${e}\n${t}`}async function Q(e,t,n){let r=[`device`,`process`,`launch`,`--device`,e.id,t];n?.payloadUrl&&r.push(`--payload-url`,n.payloadUrl),n?.launchArgs&&n.launchArgs.length>0&&r.push(`--`,...n.launchArgs),await y(r,{action:`launch iOS app`,deviceId:e.id})}var Mt=e({prepareIosInstallArtifact:()=>Nt});async function Nt(e,n){if(e.kind===`url`&&!te(e.url))throw new t(`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 r=await ee({source:e,isInstallablePath:(e,t)=>t.isDirectory()&&e.toLowerCase().endsWith(`.app`)||t.isFile()&&e.toLowerCase().endsWith(`.ipa`),installableLabel:`iOS installable (.app or .ipa)`,allowArchiveExtraction:e.kind!==`url`||te(e.url),signal:n?.signal}),i;try{i=await Ft(r.installablePath,n);let e=i,t=await Pt(e.installPath);return{archivePath:r.archivePath??(r.installablePath.toLowerCase().endsWith(`.ipa`)?r.installablePath:void 0),installablePath:e.installPath,bundleId:t.bundleId,appName:t.appName,cleanup:async()=>{await e.cleanup(),await r.cleanup()}}}catch(e){try{await i?.cleanup()}finally{await r.cleanup()}throw e}}async function Pt(e){let t=k.join(e,`Info.plist`),[n,r,i]=await Promise.all([b(t,`CFBundleIdentifier`),b(t,`CFBundleDisplayName`),b(t,`CFBundleName`)]);return{bundleId:n,appName:r??i}}async function Ft(e,n){if(!e.toLowerCase().endsWith(`.ipa`))return{installPath:e,cleanup:async()=>{}};let r=await D.mkdtemp(k.join(O.tmpdir(),`agent-device-ios-ipa-`)),i=async()=>{await D.rm(r,{recursive:!0,force:!0})};try{await s(`unzip`,[`-q`,e,`-d`,r]);let a=k.join(r,`Payload`),o=(await D.readdir(a,{withFileTypes:!0}).catch(()=>{throw new t(`INVALID_ARGS`,`Invalid IPA: missing Payload directory`)})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(`.app`)).map(e=>({installPath:k.join(a,e.name),bundleName:e.name.replace(/\.app$/i,``)})),c=o[0];if(c!==void 0&&o.length===1)return{installPath:c.installPath,cleanup:i};if(o.length===0)throw new t(`INVALID_ARGS`,`Invalid IPA: expected at least one .app under Payload, found 0`);await It(o);let l=n?.appIdentifierHint?.trim();if(l){let e=Lt(o,l);if(e)return{installPath:e.installPath,cleanup:i};throw new t(`INVALID_ARGS`,`Invalid IPA: found ${o.length} .app bundles under Payload and none matched "${l}". Available bundles: ${o.map(Rt).join(`, `)}`)}throw new t(`INVALID_ARGS`,`Invalid IPA: found ${o.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${o.map(Rt).join(`, `)}`)}catch(e){throw await i(),e}}async function It(e){await Promise.all(e.map(async e=>{if(e.bundleId&&e.appName)return;let t=await Pt(e.installPath);e.bundleId=e.bundleId??t.bundleId,e.appName=e.appName??t.appName}))}function Lt(e,n){let r=n.toLowerCase(),i=e.filter(e=>e.bundleName.toLowerCase()===r);if(i.length===1)return i[0];if(i.length>1)throw new t(`INVALID_ARGS`,`Invalid IPA: multiple app bundles matched "${n}" by name. Use a bundle id hint instead.`);if(n.includes(`.`)){let t=e.filter(e=>e.bundleId?.toLowerCase()===r);if(t.length===1)return t[0]}}function Rt(e){let t=e.bundleId??e.appName;return t?`${e.bundleName}.app (${t})`:`${e.bundleName}.app`}async function zt(e,n){return await Y(e,async()=>{let r=await X(e,n);if(e.kind!==`simulator`)return await y([`device`,`uninstall`,`app`,`--device`,e.id,r],{action:`uninstall iOS app ${r}`,deviceId:e.id},{tolerateOutput:(e,t)=>lt(`${e}\n${t}`.toLowerCase())}),{bundleId:r};await E(e);let i=await q(e,[`uninstall`,e.id,r],{allowFailure:!0});if(i.exitCode!==0&&!lt(`${i.stdout}\n${i.stderr}`.toLowerCase()))throw new t(`COMMAND_FAILED`,`simctl uninstall failed for ${r}`,o(i));return{bundleId:r}})}async function Bt(e,t,n){let r=await Nt({kind:`path`,path:t},n);try{return await Ht(e,r.installablePath),{archivePath:r.archivePath,installablePath:r.installablePath,bundleId:r.bundleId,appName:r.appName,launchTarget:r.bundleId}}finally{await r.cleanup()}}async function Vt(e,t,n){return await Y(e,async()=>{let{bundleId:r}=await zt(e,t);return await Bt(e,n,{appIdentifierHint:t}),{bundleId:r}})}async function Ht(e,t){await Y(e,async()=>{if(e.kind!==`simulator`){await y([`device`,`install`,`app`,`--device`,e.id,t],{action:`install iOS app`,deviceId:e.id},{timeoutMs:fe});return}await E(e),await q(e,[`install`,e.id,t])})}async function Ut(e){return n(e)?await it():(T(e,`clipboard`),await E(e),i(await q(e,[`pbpaste`,e.id],{allowFailure:!0}),`Failed to read iOS simulator clipboard`).stdout.replace(/\r\n/g,`
4
- `).replace(/\n$/,``))}async function Wt(e,t){if(n(e)){await at(t);return}T(e,`clipboard`),await E(e),i(await q(e,[`pbcopy`,e.id],{allowFailure:!0,stdin:t}),`Failed to write iOS simulator clipboard`)}async function Gt(e,t,n){T(e,`push`),await E(e);let r=await D.mkdtemp(k.join(O.tmpdir(),`agent-device-ios-push-`)),i=k.join(r,`payload.apns`);try{await D.writeFile(i,`${JSON.stringify(n)}\n`,`utf8`),await q(e,[`push`,e.id,t,i])}finally{await D.rm(r,{recursive:!0,force:!0})}}let $=null,Kt;async function qt(e,r,i,a,o){if(n(e)){let e=r.toLowerCase();if(e===`appearance`){await st(i);return}if(e===`permission`){let e=C(i);if(e===`deny`)throw new t(`INVALID_ARGS`,c(`permission`));return await ce(e,Yt(o?.permissionTarget))}throw new t(`INVALID_ARGS`,c(r))}T(e,`settings`),await E(e);let s=r.toLowerCase();switch(s){case`clear-app-state`:{if(i.toLowerCase()!==`clear`)throw new t(`INVALID_ARGS`,`settings clear-app-state only supports clear.`);if(!a)throw new t(`INVALID_ARGS`,`settings clear-app-state requires an app id or an active app session.`);let n=await Jt(e,a);return{bundleId:n.bundleId,containerPath:n.containerPath,cleared:!0}}case`wifi`:{let t=w(i)?`active`:`failed`;await q(e,[`status_bar`,e.id,`override`,`--wifiMode`,t]),N(e);return}case`airplane`:w(i)?(await q(e,[`status_bar`,e.id,`override`,`--dataNetwork`,`hide`,`--wifiMode`,`failed`,`--wifiBars`,`0`,`--cellularMode`,`failed`,`--cellularBars`,`0`,`--operatorName`,``]),N(e)):(await q(e,[`status_bar`,e.id,`clear`]),P(e));return;case`location`:{if(i.toLowerCase()===`set`){let{latitude:t,longitude:n}=l(o);return await q(e,[`location`,e.id,`set`,`${t},${n}`]),{latitude:t,longitude:n}}let n=w(i);if(!a)throw new t(`INVALID_ARGS`,`location setting requires an active app in session`);let r=n?`grant`:`revoke`;await q(e,[`privacy`,e.id,r,`location`,a]);return}case`faceid`:case`touchid`:{let t=s,n=Qt[t];await sn(e,on(i,t),{settingName:t,label:n.label,modalityAliases:n.modalityAliases});return}case`appearance`:{let t=await Xt(e,i);await q(e,[`ui`,e.id,`appearance`,t]);return}case`permission`:if(!a)throw new t(`INVALID_ARGS`,`permission setting requires an active app in session`);await en(e,$t(C(i)),an(o?.permissionTarget,o?.permissionMode),a);return;default:throw new t(`INVALID_ARGS`,`Unsupported setting: ${r}`)}}async function Jt(e,n){if(!r(e)||e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`Clearing app state is currently supported only on iOS simulators.`);let a=await X(e,n);await E(e),await Et(e,a);let o=i(await q(e,[`get_app_container`,e.id,a,`data`],{allowFailure:!0}),`simctl get_app_container failed for ${a}`).stdout.trim();if(!o)throw new t(`COMMAND_FAILED`,`simctl get_app_container returned an empty data container path for ${a}`);let s=await D.readdir(o);return await Promise.all(s.map(e=>D.rm(k.join(o,e),{recursive:!0,force:!0}))),{bundleId:a,containerPath:o}}function Yt(e){let n=e?.trim().toLowerCase();if(n===`accessibility`||n===`screen-recording`||n===`input-monitoring`)return n;throw new t(`INVALID_ARGS`,`Unsupported macOS permission target. Use accessibility|screen-recording|input-monitoring.`)}async function Xt(e,n){let r=S(n);if(r!==`toggle`)return r;let a=i(await q(e,[`ui`,e.id,`appearance`],{allowFailure:!0}),`Failed to read current iOS appearance`),o=Zt(a.stdout,a.stderr);if(!o)throw new t(`COMMAND_FAILED`,`Unable to determine current iOS appearance for toggle`,{stdout:a.stdout,stderr:a.stderr});return o===`dark`?`light`:`dark`}function Zt(e,t){let n=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}\n${t}`);if(!n)return null;let r=n[1]?.toLowerCase();return r===`dark`?`dark`:r===`light`?`light`:null}const Qt={faceid:{label:`Face ID`,modalityAliases:[`face`]},touchid:{label:`Touch ID`,modalityAliases:[`finger`,`touch`]}};function $t(e){return e===`deny`?`revoke`:e}async function en(e,n,r,i){let a=await nn(e);if(!a.has(r))throw new t(`UNSUPPORTED_OPERATION`,`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(a).sort().join(`, `)}`});let o=[`privacy`,e.id,n,r,i],s=r===`notifications`;if(!(n===`reset`&&s))try{await q(e,o);return}catch(n){throw s&&tn(n)?new t(`UNSUPPORTED_OPERATION`,`iOS simulator does not support setting notifications permission via simctl privacy on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Use reset notifications for reprompt behavior, or toggle notifications manually in Settings.`}):n}try{await q(e,o);return}catch(e){if(!tn(e))throw e}try{await q(e,[`privacy`,e.id,`reset`,`all`,i])}catch(n){throw new t(`COMMAND_FAILED`,`iOS simulator blocked direct notifications reset. Fallback reset-all also failed.`,{deviceId:e.id,appBundleId:i,hint:`Use reinstall to force a fresh notifications prompt, or reset simulator content and settings.`},n instanceof Error?n:void 0)}}function tn(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=String(e.details?.stderr??``).toLowerCase();return(n.includes(`failed to grant access`)||n.includes(`failed to revoke access`)||n.includes(`failed to reset access`))&&n.includes(`operation not permitted`)}async function nn(e){let n=ie(e.simulatorSetPath),r=`${process.env.PATH??``}::${n??``}`;if($&&Kt===r)return $;let i=await q(e,[`privacy`,`help`],{allowFailure:!0}),a=rn(`${i.stdout}\n${i.stderr}`);if(a.size===0)throw new t(`COMMAND_FAILED`,`Unable to determine supported simctl privacy services`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return $=a,Kt=r,a}function rn(e){let t=new Set,n=!1;for(let r of e.split(`
5
- `)){let e=r.trim();if(!e)continue;if(e===`service`){n=!0;continue}if(!n)continue;if(e.startsWith(`bundle identifier`))break;let i=/^([a-z-]+)\s+-\s+/.exec(e)?.[1];i!==void 0&&t.add(i)}return t}function an(e,n){let r=Ce(e);if(r!==`photos`&&n?.trim())throw new t(`INVALID_ARGS`,`Permission mode is only supported for photos. Received: ${n}.`);if(r===`camera`)return`camera`;if(r===`microphone`)return`microphone`;if(r===`contacts`)return`contacts`;if(r===`contacts-limited`)return`contacts-limited`;if(r===`notifications`)return`notifications`;if(r===`calendar`)return`calendar`;if(r===`location`)return`location`;if(r===`location-always`)return`location-always`;if(r===`media-library`)return`media-library`;if(r===`motion`)return`motion`;if(r===`reminders`)return`reminders`;if(r===`siri`)return`siri`;if(r===`photos`){let e=n?.trim().toLowerCase();if(!e||e===`full`)return`photos`;if(e===`limited`)return`photos-add`;throw new t(`INVALID_ARGS`,`Invalid photos mode: ${n}. Use full|limited.`)}throw new t(`INVALID_ARGS`,`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}function on(e,n){let r=e.trim().toLowerCase();if(r===`match`)return`match`;if(r===`nonmatch`)return`nonmatch`;if(r===`enroll`)return`enroll`;if(r===`unenroll`)return`unenroll`;throw new t(`INVALID_ARGS`,`Invalid ${n} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}async function sn(e,n,r){let i=cn(e.id,n,r.modalityAliases),a=[];for(let t of i){let n=K(e,t),r=await _(n,{allowFailure:!0});if(r.exitCode===0)return;a.push({args:n,stderr:r.stderr,stdout:r.stdout,exitCode:r.exitCode})}let o=Se(a);throw a.length>0&&a.every(e=>ln(e.stdout,e.stderr))?new t(`UNSUPPORTED_OPERATION`,`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:n,setting:r.settingName,attempts:o}):new t(`COMMAND_FAILED`,`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:n,setting:r.settingName,attempts:o})}function cn(e,t,n){let r=n.length>0?n:[`face`];switch(t){case`match`:return r.flatMap(t=>[[`biometric`,e,`match`,t],[`biometric`,`match`,e,t]]);case`nonmatch`:return r.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`]]}}function ln(e,t){let n=`${e}\n${t}`.toLowerCase();return n.includes(`unrecognized subcommand`)||n.includes(`unknown subcommand`)||n.includes(`not supported`)||n.includes(`unavailable`)||n.includes(`biometric`)&&n.includes(`invalid`)}var un=e({installIosApp:()=>Bt,installIosInstallablePath:()=>Ht,listIosApps:()=>mt,pushIosNotification:()=>Gt,reinstallIosApp:()=>Vt,resolveIosApp:()=>X,resolveIosSimulatorDeepLinkBundleId:()=>ft});export{Mt as a,Tt as c,Wt as i,mt as l,qt as n,Et as o,Ut as r,Ct as s,un as t,Re as u};
1
+ import{t as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{h as n,j as r,p as i,v as a}from"./sdk-android-adb.js";import{Ct as o,Et as s}from"./tv-remote.js";import{c,s as l}from"./sdk-device.js";import{i as u}from"./runtime.js";import{n as ee,t as te}from"./install-source2.js";import{D as d,E as f,O as ne,S as p,k as re,w as m,x as ie}from"./android-input-ownership.js";import{d as h,i as ae}from"./runner-client.js";import{a as g,i as _,r as oe,s as se}from"./tool-provider.js";import{a as ce,n as le}from"./helper.js";import{n as v,r as ue}from"./simctl.js";import{$ as de,$t as fe,G as y,J as pe,K as me,Q as he,U as ge,V as b,Y as x,bt as _e,en as ve,et as ye,tt as be,yt as xe}from"./internal/daemon.js";import{a as Se,i as Ce,n as S,r as C,t as w}from"./setting-state.js";import{i as T,n as we,t as E}from"./simulator.js";import{promises as D}from"node:fs";import O from"node:os";import k from"node:path";import{fileURLToPath as Te}from"node:url";function A(e){if(!(e instanceof t))return{reason:e instanceof Error?e.message:String(e)};let n=e.details??{},r=Array.isArray(n.args)?n.args.filter(e=>typeof e==`string`).join(` `):void 0;return{errorCode:e.code,reason:e.message,timeoutMs:typeof n.timeoutMs==`number`?n.timeoutMs:void 0,exitCode:typeof n.exitCode==`number`?n.exitCode:void 0,stderr:typeof n.stderr==`string`&&n.stderr.trim()?n.stderr:void 0,stdout:typeof n.stdout==`string`&&n.stdout.trim()?n.stdout:void 0,commandArgs:r}}const Ee=[`--time`,`9:41`,`--dataNetwork`,`wifi`,`--wifiMode`,`active`,`--wifiBars`,`3`,`--batteryState`,`charged`,`--batteryLevel`,`100`],De={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`},Oe={1:`searching`,2:`failed`,3:`active`},ke={0:`notSupported`,1:`searching`,2:`failed`,3:`active`};function j(e,t,n){return ue(e,t,n)}const M=new Set;async function Ae(e){let t=null,n=!1;if(Me(e))n=!0;else try{t=await Ne(e),n=!0}catch(t){R(e,`snapshot_failed`,t)}try{(!n||t)&&await I(e),await L(e,Ee)}catch(t){R(e,`prepare_failed`,t)}return async()=>{await je(e,n?t:null)}}async function je(e,t){if(await I(e),!t){P(e);return}await L(e,Fe(t)),N(e)}function N(e){M.delete(F(e))}function P(e){M.add(F(e))}function Me(e){return M.has(F(e))}function F(e){return`${e.platform}:${e.kind}:${e.id}`}async function Ne(e){return Pe(n(await j(e,[`status_bar`,e.id,`list`],{allowFailure:!0}),`Failed to read simulator status bar overrides`).stdout)}async function I(e){await j(e,[`status_bar`,e.id,`clear`])}async function L(e,t){t.length!==0&&await j(e,[`status_bar`,e.id,`override`,...t])}function Pe(e){let n={},r=e.split(`
2
+ `).map(e=>e.trim()).filter(e=>e.length>0&&e!==`Current Status Bar Overrides:`&&!/^=+$/.test(e));for(let e of r){let r=/^DataNetworkType:\s+(\d+)$/.exec(e);if(r){let e=Number(r[1]),i=De[e];if(!i)throw new t(`COMMAND_FAILED`,`Unsupported simulator data network type: ${e}`);n.dataNetwork=i;continue}let i=/^WiFi Mode:\s+(\d+),\s+WiFi Bars:\s+(\d+)$/.exec(e);if(i){let e=Oe[Number(i[1])];e&&(n.wifiMode=e),n.wifiBars=i[2];continue}let a=/^Cell Mode:\s+(\d+),\s+Cell Bars:\s+(\d+)$/.exec(e);if(a){let e=Number(a[1]),r=ke[e];if(!r)throw new t(`COMMAND_FAILED`,`Unsupported simulator cellular mode: ${e}`);n.cellularMode=r,n.cellularBars=a[2];continue}let o=/^Operator Name:\s*(.*)$/.exec(e);if(o){n.operatorName=o[1]??``;continue}}return Object.keys(n).length===0?null:n}function Fe(e){let t=[];return e.dataNetwork&&t.push(`--dataNetwork`,e.dataNetwork),e.wifiMode&&t.push(`--wifiMode`,e.wifiMode),e.wifiBars!==void 0&&(e.dataNetwork===`wifi`||e.wifiMode)&&t.push(`--wifiBars`,e.wifiBars),e.cellularMode&&t.push(`--cellularMode`,e.cellularMode),e.cellularBars!==void 0&&(e.cellularMode||Ie(e.dataNetwork)||e.operatorName!==void 0)&&t.push(`--cellularBars`,e.cellularBars),e.operatorName!==void 0&&t.push(`--operatorName`,e.operatorName),t}function Ie(e){return!!(e&&e!==`hide`&&e!==`wifi`)}function R(e,t,n){r({level:`warn`,phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...A(n)}})}function z(e,t,n){return ue(e,t,n)}const Le={ensureBooted:E,prepareStatusBarForScreenshot:Ae,captureWithRetry:Be,normalizeDensity:Xe,captureWithRunner:V,shouldFallbackToRunner:Je},B=new Map;async function Re(e,t,n={}){if(c(e)){await V(e,t,n.appBundleId,n.fullscreen,n.runnerOptions);return}if(e.kind===`simulator`){await ze(e,t,n);return}try{await y([`device`,`screenshot`,`--device`,e.id,t],{action:`capture iOS screenshot`,deviceId:e.id});return}catch(t){if(!qe(t))throw t;We(e,`devicectl_screenshot`,t)}await V(e,t,n.appBundleId,n.fullscreen,n.runnerOptions)}async function ze(e,n,r={}){if(e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`Simulator screenshot fallback flow supports only iOS simulators`);let i={...Le,...r.deps??{}};r.skipIosSimulatorBootCheck||await i.ensureBooted(e);let a=async()=>{};if(r.normalizeStatusBar===!0)try{a=await i.prepareStatusBarForScreenshot(e)}catch(t){Ge(e,`prepare_failed`,t)}try{try{await i.captureWithRetry(e,n),await i.normalizeDensity(e,n,r.pixelDensity);return}catch(t){let a=t;if(r.skipIosSimulatorBootCheck&&Ye(t)){await i.ensureBooted(e);try{await i.captureWithRetry(e,n),await i.normalizeDensity(e,n,r.pixelDensity);return}catch(e){a=e}}if(!i.shouldFallbackToRunner(a))throw a;We(e,`simctl_screenshot`,a)}await i.captureWithRunner(e,n,r.appBundleId,r.fullscreen,r.runnerOptions),await i.normalizeDensity(e,n,r.pixelDensity)}finally{await a().catch(t=>Ge(e,`restore_failed`,t))}}async function Be(e,t){let n=p.fromTimeoutMs(ye);await m(async({deadline:n})=>{await z(e,[`io`,e.id,`screenshot`,t],{timeoutMs:Math.max(1e3,n?.remainingMs()??2e4)})},{maxAttempts:5,baseDelayMs:he,maxDelayMs:de,jitter:.2,shouldRetry:e=>Je(e)},{deadline:n,phase:`ios_simulator_screenshot`})}async function V(e,n,r,i,a){let o=(await ae(e,{command:`screenshot`,appBundleId:r,fullscreen:i},a)).message;if(!o)throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: runner returned no file path`);if(c(e)){await D.copyFile(o,n);return}if(e.kind===`simulator`){await He(e,o,n);return}await Ve(e,o,n)}async function Ve(e,n,r){let i=p.fromTimeoutMs(x),a={exitCode:1,stdout:``,stderr:``};for(let t of h)if(a=await g([`devicectl`,`device`,`copy`,`from`,`--device`,e.id,`--source`,n,`--destination`,r,`--domain-type`,`appDataContainer`,`--domain-identifier`,t],{allowFailure:!0,timeoutMs:Ue(i,x,`runner screenshot copy`)}),a.exitCode===0)return;throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: ${a.stderr.trim()||a.stdout.trim()||`devicectl exited with code ${a.exitCode}`}`)}async function He(e,n,r){let i=p.fromTimeoutMs(x),a=`Unable to locate runner container for simulator screenshot`;for(let t of h){let o=await z(e,[`get_app_container`,e.id,t,`data`],{allowFailure:!0,timeoutMs:Ue(i,x,`runner screenshot container lookup`)});if(o.exitCode!==0){let e=o.stderr.trim();e&&(a=e);continue}let s=o.stdout.trim();if(!s){a=`simctl get_app_container returned empty output`;continue}let c=Ke(s,n);for(let e of c)try{await D.copyFile(e,r);return}catch(e){a=e instanceof Error?e.message:String(e)}}throw new t(`COMMAND_FAILED`,`Failed to capture iOS screenshot: ${a}`)}function Ue(e,n,r){let i=e.remainingMs();if(i>0)return i;throw new t(`COMMAND_FAILED`,`iOS ${r} timed out after ${n}ms`,{timeoutMs:n,step:r})}function We(e,t,n){let i=A(n);r({level:`warn`,phase:`ios_screenshot_fallback`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,from:t,to:`runner`,...i}})}function Ge(e,t,n){r({level:`warn`,phase:`ios_screenshot_status_bar_${t}`,data:{platform:e.platform,deviceKind:e.kind,deviceId:e.id,...A(n)}})}function Ke(e,t){let n=k.resolve(e),r=t.trim();if(!r)return[];let i=[],a=new Set,o=e=>{let t=k.normalize(e);a.has(t)||(a.add(t),i.push(t))},s=r.replace(/^\/+/,``),c=s.replace(/\\/g,`/`);if(s&&o(k.join(n,s)),k.isAbsolute(r)&&o(k.normalize(r)),c.startsWith(`tmp/`))o(k.join(n,c));else{let e=c.lastIndexOf(`/tmp/`);if(e>=0){let t=c.slice(e+1);o(k.join(n,t))}}let l=k.basename(r);return l&&o(k.join(n,`tmp`,l)),i}function qe(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`unknown option '--device'`)||n.includes(`unknown subcommand`)&&n.includes(`screenshot`)||n.includes(`unrecognized subcommand`)&&n.includes(`screenshot`)}function Je(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`timeout waiting for screen surfaces`)||n.includes(`nsposixerrordomain`)&&n.includes(`code=60`)&&n.includes(`screenshot`)||n.includes(`timed out`)&&n.includes(`screenshot`)}function Ye(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=H(e);return n.includes(`not booted`)||n.includes(`current state: shutdown`)||n.includes(`current state is shutdown`)||n.includes(`current state=shutdown`)||n.includes(`state: shutdown`)||n.includes(`state=shutdown`)}function H(e){let t=e.details??{},n=typeof t.stdout==`string`?t.stdout:``,r=typeof t.stderr==`string`?t.stderr:``,i=Array.isArray(t.args)?t.args.filter(e=>typeof e==`string`).join(` `):``;return`${e.message}\n${n}\n${r}\n${i}`.toLowerCase()}async function Xe(e,t,n){let r=await Ze(e),i=xe(await _e(t),r,n);i&&await u(t,i.width,i.height)}async function Ze(e){let n=B.get(e.id);if(n!==void 0)return n;let r=await z(e,[`getenv`,e.id,`SIMULATOR_MAINSCREEN_SCALE`],{timeoutMs:5e3}),i=Number(r.stdout.trim());if(!Number.isFinite(i)||i<=0)throw new t(`COMMAND_FAILED`,`Failed to read iOS simulator screenshot scale from SIMULATOR_MAINSCREEN_SCALE`);return B.set(e.id,i),i}const Qe={settings:`com.apple.systempreferences`},$e=/^[a-z0-9-]+(?:\.[a-z0-9-]+)+$/,et={platform:`macos`,deviceId:`host`,variant:`all`},U=f();function tt(e){return $e.test(e)}async function W(e){let n=e.trim(),r=Qe[n.toLowerCase()];if(r)return r;if(tt(n))return n;let i=U.get(et,n);if(i)return i;let a=(await ct(`all`)).filter(e=>e.name.toLowerCase()===n.toLowerCase()),o=a[0];if(o!==void 0&&a.length===1)return U.set(et,n,o.bundleId);throw a.length>1?new t(`INVALID_ARGS`,`Multiple apps matched "${e}"`,{matches:a}):new t(`APP_NOT_INSTALLED`,`No app found matching "${e}"`)}async function nt(e,n,r){let i=r?.url?.trim();if(i){if(!d(i))throw new t(`INVALID_ARGS`,`open <app> <url> requires a valid URL target`);let e=r?.appBundleId??await W(n);await G().openBundle(e,i);return}let a=n.trim();if(d(a)){await G().openTarget(a);return}let o=r?.appBundleId??await W(a);await G().openBundle(o)}async function rt(e,n){let r=await W(n),i=await le(r);if(!(!i.running||i.terminated||i.forceTerminated))throw new t(`COMMAND_FAILED`,`Failed to close macOS app ${n}`,{bundleId:r,running:i.running,terminated:i.terminated,forceTerminated:i.forceTerminated})}async function it(){return await G().readClipboard()}async function at(e){await G().writeClipboard(e)}async function ot(){return await G().readDarkMode()}async function st(e){let t=S(e),n=t===`toggle`?!await ot():t===`dark`;await G().setDarkMode(n)}async function ct(e){return await G().listApps(e)}function G(){let e=oe().macosHost;if(!e)throw new t(`UNSUPPORTED_OPERATION`,`macOS host provider is not available`);return e}function K(e,t){return v(e,t)}function q(e,t,n){return g(K(e,t),n)}function lt(e){return e.includes(`not installed`)||e.includes(`not found`)||e.includes(`no such file`)}const ut={settings:`com.apple.Preferences`},J=f();function dt(e){return{platform:`ios`,deviceId:e.id,variant:e.kind}}async function Y(e,t){return await J.invalidateWhile(dt(e),t)}async function X(e,n){if(c(e))return await W(n);let r=n.trim();if(r.includes(`.`))return r;let i=ut[r.toLowerCase()];if(i)return i;let a=dt(e),o=J.get(a,r);if(o)return o;let s=(e.kind===`simulator`?await ht(e):await ge(e,`all`)).filter(e=>e.name.toLowerCase()===r.toLowerCase()),l=s[0];if(l!==void 0&&s.length===1)return J.set(a,r,l.bundleId);throw s.length>1?new t(`INVALID_ARGS`,`Multiple apps matched "${n}"`,{matches:s}):new t(`APP_NOT_INSTALLED`,`No app found matching "${n}"`)}async function ft(e,t){if(!l(e)||e.kind!==`simulator`)return;let n=pt(t);if(!n)return;let r=await gt(e),i=[];for(let e of r)e.bundleId.startsWith(`com.callstack.agentdevice.runner`)||e.path&&(await vt(k.join(e.path,`Info.plist`))).has(n)&&i.push(e);let a=i.filter(e=>e.applicationType===`User`);if(a.length===1)return a[0]?.bundleId;if(!(a.length>1))return i.length===1?i[0]?.bundleId:void 0}function pt(e){return/^([A-Za-z][A-Za-z0-9+.-]*):/.exec(e.trim())?.[1]?.toLowerCase()}async function mt(e,t){return c(e)?await ct(t):e.kind===`simulator`?se(await ht(e),t):await ge(e,t)}async function ht(e){return(await gt(e)).map(e=>({bundleId:e.bundleId,name:e.name}))}async function gt(e){let t=(await q(e,[`listapps`,e.id],{allowFailure:!0})).stdout.trim();if(!t)return[];let n=null;if(t.startsWith(`{`))try{n=JSON.parse(t)}catch{n=null}if(!n&&t.startsWith(`{`))try{let e=await _(`plutil`,[`-convert`,`json`,`-o`,`-`,`-`],{allowFailure:!0,stdin:t});e.exitCode===0&&e.stdout.trim().startsWith(`{`)&&(n=JSON.parse(e.stdout))}catch{n=null}return n?Object.entries(n).map(([e,t])=>{let n=_t(t);return{bundleId:e,name:t.CFBundleDisplayName??t.CFBundleName??e,...n?{path:n}:{},...t.ApplicationType?{applicationType:t.ApplicationType}:{}}}):[]}function _t(e){if(e.Path)return e.Path;if(e.Bundle)try{return Te(e.Bundle)}catch{return}}async function vt(e){let t=await _(`plutil`,[`-convert`,`json`,`-o`,`-`,e],{allowFailure:!0});if(t.exitCode!==0)return new Set;try{let e=JSON.parse(t.stdout),n=new Set;for(let t of e.CFBundleURLTypes??[])if(Array.isArray(t.CFBundleURLSchemes))for(let e of t.CFBundleURLSchemes)typeof e==`string`&&e.trim()&&n.add(e.trim().toLowerCase());return n}catch{return new Set}}function yt(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=e.details??{};if(n.exitCode!==4)return!1;let r=String(n.stderr??``).toLowerCase();return r.includes(`fbsopenapplicationserviceerrordomain`)&&r.includes(`the request to open`)}async function bt(e,t){let n=await g(v(e,[`get_app_container`,e.id,t]),{allowFailure:!0});if(n.exitCode!==0)return{installed:!1};let r=n.stdout.trim();if(!r)return{installed:!1};let i=await _(`plutil`,[`-extract`,`CFBundleExecutable`,`raw`,`-o`,`-`,`${r}/Info.plist`],{allowFailure:!0});if(i.exitCode!==0||!i.stdout.trim())return{installed:!0};let a=await _(`otool`,[`-l`,`${r}/${i.stdout.trim()}`],{allowFailure:!0});if(a.exitCode!==0)return{installed:!0};let o=a.stdout.toLowerCase();return{installed:!0,simulatorCompatible:o.includes(`iossimulator`)||o.includes(`platform 7`)}}function xt(e){return e.installed?e.simulatorCompatible===!1?`ARCH_MISMATCH`:`PERSISTENT_LAUNCH_FAIL`:`APP_NOT_INSTALLED`}function St(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.`}}const Z=25e3;async function Ct(e,n,r){let i=r?.launchConsole?.trim(),a=r?.launchArgs;if(i&&(!l(e)||e.kind!==`simulator`))throw new t(`UNSUPPORTED_OPERATION`,ve);if(c(e)){if(a&&a.length>0)throw new t(`UNSUPPORTED_OPERATION`,`--launch-args is not supported on macOS; launch arguments are currently iOS-only.`);await nt(e,n,r);return}let o=r?.url?.trim();if(o){if(i)throw new t(`INVALID_ARGS`,fe);if(!d(o))throw new t(`INVALID_ARGS`,`open <app> <url> requires a valid URL target`);if(e.kind===`simulator`){(a||ne(o))&&await Dt(e,r?.appBundleId??await X(e,n),{...a?{launchArgs:a}:{}}),await wt(e,o,void 0);return}let s=re(r?.appBundleId??await X(e,n),o);if(!s)throw new t(`INVALID_ARGS`,`Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.`);await Q(e,s,{payloadUrl:o,launchArgs:a});return}let s=n.trim();if(d(s)){if(i)throw new t(`INVALID_ARGS`,fe);if(e.kind===`simulator`){await wt(e,s,a);return}let n=re(r?.appBundleId,s);if(!n)throw new t(`INVALID_ARGS`,`Deep link open on iOS devices requires an active app bundle ID. Open the app first, then open the URL.`);await Q(e,n,{payloadUrl:s,launchArgs:a});return}let u=r?.appBundleId??await X(e,n);if(e.kind===`simulator`){await Dt(e,u,{...i?{launchConsole:i}:{},...a?{launchArgs:a}:{},...r?.terminateRunningApp?{terminateRunningApp:!0}:{}});return}await Q(e,u,{launchArgs:a})}async function wt(e,n,r){if(r&&r.length>0)throw new t(`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 E(e),await q(e,[`openurl`,e.id,n])}async function Tt(e){c(e)||e.kind===`simulator`&&await we(e)!==`Booted`&&await E(e)}async function Et(e,n){if(c(e)){await rt(e,n);return}let r=await X(e,n);if(e.kind===`simulator`){await E(e);let n=K(e,[`terminate`,e.id,r]),a=await g(n,{allowFailure:!0,timeoutMs:be});if(a.exitCode!==0){if(a.stderr.toLowerCase().includes(`found nothing to terminate`))return;throw new t(`COMMAND_FAILED`,`xcrun exited with code ${a.exitCode}`,i(a,{cmd:`xcrun`,args:n}))}return}await y([`device`,`process`,`terminate`,`--device`,e.id,r],{action:`terminate iOS app`,deviceId:e.id})}async function Dt(e,n,r){await E(e);let a=0,o=p.fromTimeoutMs(me);try{await m(async({deadline:a})=>{if(a?.isExpired())throw new t(`COMMAND_FAILED`,`App launch deadline exceeded`,{timeoutMs:me});let o=K(e,Ot(e.id,n,r)),s=r?.launchConsole?await kt(o,r.launchConsole):await g(o,{allowFailure:!0});if(s.exitCode!==0)throw new t(`COMMAND_FAILED`,`xcrun exited with code ${s.exitCode}`,i(s,{cmd:`xcrun`,args:o}))},{maxAttempts:10,baseDelayMs:1e3,maxDelayMs:5e3,jitter:.2,shouldRetry(e){return yt(e)?(a+=1,a<3):!1}},{deadline:o})}catch(t){if(yt(t)){let r=t,i=xt(await bt(e,n));r.details={...r.details,hint:St(i)}}throw t}}function Ot(e,t,n){let r=[`launch`];return n?.launchConsole&&r.push(`--console-pty`),n?.terminateRunningApp&&r.push(`--terminate-running-process`),r.push(e,t),n?.launchArgs&&n.launchArgs.length>0&&r.push(...n.launchArgs),r}async function kt(e,n){await D.mkdir(k.dirname(n),{recursive:!0});try{let t=await g(e,{allowFailure:!0,timeoutMs:Z});return await At(n,t.stdout,t.stderr),t}catch(e){let i=(e instanceof t?e:void 0)?.details;if(i?.timeoutMs===Z){let e=typeof i.stdout==`string`?i.stdout:``,t=typeof i.stderr==`string`?i.stderr:``;return await At(n,e,t),r({level:`warn`,phase:`ios_simulator_launch_console_capture_timeout`,data:{timeoutMs:Z,logPath:n,stdoutBytes:Buffer.byteLength(e),stderrBytes:Buffer.byteLength(t)}}),{stdout:e,stderr:t,exitCode:0}}throw e}}async function At(e,t,n){await D.writeFile(e,jt(t,n),`utf8`)}function jt(e,t){return!e||!t||e.endsWith(`
3
+ `)||e.endsWith(`\r`)?`${e}${t}`:`${e}\n${t}`}async function Q(e,t,n){let r=[`device`,`process`,`launch`,`--device`,e.id,t];n?.payloadUrl&&r.push(`--payload-url`,n.payloadUrl),n?.launchArgs&&n.launchArgs.length>0&&r.push(`--`,...n.launchArgs),await y(r,{action:`launch iOS app`,deviceId:e.id})}var Mt=e({prepareIosInstallArtifact:()=>Nt});async function Nt(e,n){if(e.kind===`url`&&!te(e.url))throw new t(`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 r=await ee({source:e,isInstallablePath:(e,t)=>t.isDirectory()&&e.toLowerCase().endsWith(`.app`)||t.isFile()&&e.toLowerCase().endsWith(`.ipa`),installableLabel:`iOS installable (.app or .ipa)`,allowArchiveExtraction:e.kind!==`url`||te(e.url),signal:n?.signal}),i;try{i=await Ft(r.installablePath,n);let e=i,t=await Pt(e.installPath);return{archivePath:r.archivePath??(r.installablePath.toLowerCase().endsWith(`.ipa`)?r.installablePath:void 0),installablePath:e.installPath,bundleId:t.bundleId,appName:t.appName,cleanup:async()=>{await e.cleanup(),await r.cleanup()}}}catch(e){try{await i?.cleanup()}finally{await r.cleanup()}throw e}}async function Pt(e){let t=k.join(e,`Info.plist`),[n,r,i]=await Promise.all([b(t,`CFBundleIdentifier`),b(t,`CFBundleDisplayName`),b(t,`CFBundleName`)]);return{bundleId:n,appName:r??i}}async function Ft(e,n){if(!e.toLowerCase().endsWith(`.ipa`))return{installPath:e,cleanup:async()=>{}};let r=await D.mkdtemp(k.join(O.tmpdir(),`agent-device-ios-ipa-`)),i=async()=>{await D.rm(r,{recursive:!0,force:!0})};try{await a(`unzip`,[`-q`,e,`-d`,r]);let o=k.join(r,`Payload`),s=(await D.readdir(o,{withFileTypes:!0}).catch(()=>{throw new t(`INVALID_ARGS`,`Invalid IPA: missing Payload directory`)})).filter(e=>e.isDirectory()&&e.name.toLowerCase().endsWith(`.app`)).map(e=>({installPath:k.join(o,e.name),bundleName:e.name.replace(/\.app$/i,``)})),c=s[0];if(c!==void 0&&s.length===1)return{installPath:c.installPath,cleanup:i};if(s.length===0)throw new t(`INVALID_ARGS`,`Invalid IPA: expected at least one .app under Payload, found 0`);await It(s);let l=n?.appIdentifierHint?.trim();if(l){let e=Lt(s,l);if(e)return{installPath:e.installPath,cleanup:i};throw new t(`INVALID_ARGS`,`Invalid IPA: found ${s.length} .app bundles under Payload and none matched "${l}". Available bundles: ${s.map(Rt).join(`, `)}`)}throw new t(`INVALID_ARGS`,`Invalid IPA: found ${s.length} .app bundles under Payload. Pass an app identifier or bundle name matching one of: ${s.map(Rt).join(`, `)}`)}catch(e){throw await i(),e}}async function It(e){await Promise.all(e.map(async e=>{if(e.bundleId&&e.appName)return;let t=await Pt(e.installPath);e.bundleId=e.bundleId??t.bundleId,e.appName=e.appName??t.appName}))}function Lt(e,n){let r=n.toLowerCase(),i=e.filter(e=>e.bundleName.toLowerCase()===r);if(i.length===1)return i[0];if(i.length>1)throw new t(`INVALID_ARGS`,`Invalid IPA: multiple app bundles matched "${n}" by name. Use a bundle id hint instead.`);if(n.includes(`.`)){let t=e.filter(e=>e.bundleId?.toLowerCase()===r);if(t.length===1)return t[0]}}function Rt(e){let t=e.bundleId??e.appName;return t?`${e.bundleName}.app (${t})`:`${e.bundleName}.app`}async function zt(e,n){return await Y(e,async()=>{let r=await X(e,n);if(e.kind!==`simulator`)return await y([`device`,`uninstall`,`app`,`--device`,e.id,r],{action:`uninstall iOS app ${r}`,deviceId:e.id},{tolerateOutput:(e,t)=>lt(`${e}\n${t}`.toLowerCase())}),{bundleId:r};await E(e);let a=await q(e,[`uninstall`,e.id,r],{allowFailure:!0});if(a.exitCode!==0&&!lt(`${a.stdout}\n${a.stderr}`.toLowerCase()))throw new t(`COMMAND_FAILED`,`simctl uninstall failed for ${r}`,i(a));return{bundleId:r}})}async function Bt(e,t,n){let r=await Nt({kind:`path`,path:t},n);try{return await Ht(e,r.installablePath),{archivePath:r.archivePath,installablePath:r.installablePath,bundleId:r.bundleId,appName:r.appName,launchTarget:r.bundleId}}finally{await r.cleanup()}}async function Vt(e,t,n){return await Y(e,async()=>{let{bundleId:r}=await zt(e,t);return await Bt(e,n,{appIdentifierHint:t}),{bundleId:r}})}async function Ht(e,t){await Y(e,async()=>{if(e.kind!==`simulator`){await y([`device`,`install`,`app`,`--device`,e.id,t],{action:`install iOS app`,deviceId:e.id},{timeoutMs:pe});return}await E(e),await q(e,[`install`,e.id,t])})}async function Ut(e){return c(e)?await it():(T(e,`clipboard`),await E(e),n(await q(e,[`pbpaste`,e.id],{allowFailure:!0}),`Failed to read iOS simulator clipboard`).stdout.replace(/\r\n/g,`
4
+ `).replace(/\n$/,``))}async function Wt(e,t){if(c(e)){await at(t);return}T(e,`clipboard`),await E(e),n(await q(e,[`pbcopy`,e.id],{allowFailure:!0,stdin:t}),`Failed to write iOS simulator clipboard`)}async function Gt(e,t,n){T(e,`push`),await E(e);let r=await D.mkdtemp(k.join(O.tmpdir(),`agent-device-ios-push-`)),i=k.join(r,`payload.apns`);try{await D.writeFile(i,`${JSON.stringify(n)}\n`,`utf8`),await q(e,[`push`,e.id,t,i])}finally{await D.rm(r,{recursive:!0,force:!0})}}let $=null,Kt;async function qt(e,n,r,i,a){if(c(e)){let e=n.toLowerCase();if(e===`appearance`){await st(r);return}if(e===`permission`){let e=C(r);if(e===`deny`)throw new t(`INVALID_ARGS`,s(`permission`));return await ce(e,Yt(a?.permissionTarget))}throw new t(`INVALID_ARGS`,s(n))}T(e,`settings`),await E(e);let l=n.toLowerCase();switch(l){case`clear-app-state`:{if(r.toLowerCase()!==`clear`)throw new t(`INVALID_ARGS`,`settings clear-app-state only supports clear.`);if(!i)throw new t(`INVALID_ARGS`,`settings clear-app-state requires an app id or an active app session.`);let n=await Jt(e,i);return{bundleId:n.bundleId,containerPath:n.containerPath,cleared:!0}}case`wifi`:{let t=w(r)?`active`:`failed`;await q(e,[`status_bar`,e.id,`override`,`--wifiMode`,t]),N(e);return}case`airplane`:w(r)?(await q(e,[`status_bar`,e.id,`override`,`--dataNetwork`,`hide`,`--wifiMode`,`failed`,`--wifiBars`,`0`,`--cellularMode`,`failed`,`--cellularBars`,`0`,`--operatorName`,``]),N(e)):(await q(e,[`status_bar`,e.id,`clear`]),P(e));return;case`location`:{if(r.toLowerCase()===`set`){let{latitude:t,longitude:n}=o(a);return await q(e,[`location`,e.id,`set`,`${t},${n}`]),{latitude:t,longitude:n}}let n=w(r);if(!i)throw new t(`INVALID_ARGS`,`location setting requires an active app in session`);let s=n?`grant`:`revoke`;await q(e,[`privacy`,e.id,s,`location`,i]);return}case`faceid`:case`touchid`:{let t=l,n=Qt[t];await sn(e,on(r,t),{settingName:t,label:n.label,modalityAliases:n.modalityAliases});return}case`appearance`:{let t=await Xt(e,r);await q(e,[`ui`,e.id,`appearance`,t]);return}case`permission`:if(!i)throw new t(`INVALID_ARGS`,`permission setting requires an active app in session`);await en(e,$t(C(r)),an(a?.permissionTarget,a?.permissionMode),i);return;default:throw new t(`INVALID_ARGS`,`Unsupported setting: ${n}`)}}async function Jt(e,r){if(!l(e)||e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`Clearing app state is currently supported only on iOS simulators.`);let i=await X(e,r);await E(e),await Et(e,i);let a=n(await q(e,[`get_app_container`,e.id,i,`data`],{allowFailure:!0}),`simctl get_app_container failed for ${i}`).stdout.trim();if(!a)throw new t(`COMMAND_FAILED`,`simctl get_app_container returned an empty data container path for ${i}`);let o=await D.readdir(a);return await Promise.all(o.map(e=>D.rm(k.join(a,e),{recursive:!0,force:!0}))),{bundleId:i,containerPath:a}}function Yt(e){let n=e?.trim().toLowerCase();if(n===`accessibility`||n===`screen-recording`||n===`input-monitoring`)return n;throw new t(`INVALID_ARGS`,`Unsupported macOS permission target. Use accessibility|screen-recording|input-monitoring.`)}async function Xt(e,r){let i=S(r);if(i!==`toggle`)return i;let a=n(await q(e,[`ui`,e.id,`appearance`],{allowFailure:!0}),`Failed to read current iOS appearance`),o=Zt(a.stdout,a.stderr);if(!o)throw new t(`COMMAND_FAILED`,`Unable to determine current iOS appearance for toggle`,{stdout:a.stdout,stderr:a.stderr});return o===`dark`?`light`:`dark`}function Zt(e,t){let n=/\b(light|dark|unsupported|unknown)\b/i.exec(`${e}\n${t}`);if(!n)return null;let r=n[1]?.toLowerCase();return r===`dark`?`dark`:r===`light`?`light`:null}const Qt={faceid:{label:`Face ID`,modalityAliases:[`face`]},touchid:{label:`Touch ID`,modalityAliases:[`finger`,`touch`]}};function $t(e){return e===`deny`?`revoke`:e}async function en(e,n,r,i){let a=await nn(e);if(!a.has(r))throw new t(`UNSUPPORTED_OPERATION`,`iOS simctl privacy does not support service "${r}" on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Supported services: ${Array.from(a).sort().join(`, `)}`});let o=[`privacy`,e.id,n,r,i],s=r===`notifications`;if(!(n===`reset`&&s))try{await q(e,o);return}catch(n){throw s&&tn(n)?new t(`UNSUPPORTED_OPERATION`,`iOS simulator does not support setting notifications permission via simctl privacy on this runtime.`,{deviceId:e.id,appBundleId:i,hint:`Use reset notifications for reprompt behavior, or toggle notifications manually in Settings.`}):n}try{await q(e,o);return}catch(e){if(!tn(e))throw e}try{await q(e,[`privacy`,e.id,`reset`,`all`,i])}catch(n){throw new t(`COMMAND_FAILED`,`iOS simulator blocked direct notifications reset. Fallback reset-all also failed.`,{deviceId:e.id,appBundleId:i,hint:`Use reinstall to force a fresh notifications prompt, or reset simulator content and settings.`},n instanceof Error?n:void 0)}}function tn(e){if(!(e instanceof t)||e.code!==`COMMAND_FAILED`)return!1;let n=String(e.details?.stderr??``).toLowerCase();return(n.includes(`failed to grant access`)||n.includes(`failed to revoke access`)||n.includes(`failed to reset access`))&&n.includes(`operation not permitted`)}async function nn(e){let n=ie(e.simulatorSetPath),r=`${process.env.PATH??``}::${n??``}`;if($&&Kt===r)return $;let i=await q(e,[`privacy`,`help`],{allowFailure:!0}),a=rn(`${i.stdout}\n${i.stderr}`);if(a.size===0)throw new t(`COMMAND_FAILED`,`Unable to determine supported simctl privacy services`,{stdout:i.stdout,stderr:i.stderr,exitCode:i.exitCode,hint:"Run `xcrun simctl privacy help` manually to verify available services for this runtime."});return $=a,Kt=r,a}function rn(e){let t=new Set,n=!1;for(let r of e.split(`
5
+ `)){let e=r.trim();if(!e)continue;if(e===`service`){n=!0;continue}if(!n)continue;if(e.startsWith(`bundle identifier`))break;let i=/^([a-z-]+)\s+-\s+/.exec(e)?.[1];i!==void 0&&t.add(i)}return t}function an(e,n){let r=Ce(e);if(r!==`photos`&&n?.trim())throw new t(`INVALID_ARGS`,`Permission mode is only supported for photos. Received: ${n}.`);if(r===`camera`)return`camera`;if(r===`microphone`)return`microphone`;if(r===`contacts`)return`contacts`;if(r===`contacts-limited`)return`contacts-limited`;if(r===`notifications`)return`notifications`;if(r===`calendar`)return`calendar`;if(r===`location`)return`location`;if(r===`location-always`)return`location-always`;if(r===`media-library`)return`media-library`;if(r===`motion`)return`motion`;if(r===`reminders`)return`reminders`;if(r===`siri`)return`siri`;if(r===`photos`){let e=n?.trim().toLowerCase();if(!e||e===`full`)return`photos`;if(e===`limited`)return`photos-add`;throw new t(`INVALID_ARGS`,`Invalid photos mode: ${n}. Use full|limited.`)}throw new t(`INVALID_ARGS`,`Unsupported permission target: ${e}. Use camera|microphone|photos|contacts|contacts-limited|notifications|calendar|location|location-always|media-library|motion|reminders|siri.`)}function on(e,n){let r=e.trim().toLowerCase();if(r===`match`)return`match`;if(r===`nonmatch`)return`nonmatch`;if(r===`enroll`)return`enroll`;if(r===`unenroll`)return`unenroll`;throw new t(`INVALID_ARGS`,`Invalid ${n} state: ${e}. Use match|nonmatch|enroll|unenroll.`)}async function sn(e,n,r){let i=cn(e.id,n,r.modalityAliases),a=[];for(let t of i){let n=K(e,t),r=await g(n,{allowFailure:!0});if(r.exitCode===0)return;a.push({args:n,stderr:r.stderr,stdout:r.stdout,exitCode:r.exitCode})}let o=Se(a);throw a.length>0&&a.every(e=>ln(e.stdout,e.stderr))?new t(`UNSUPPORTED_OPERATION`,`${r.label} simulation is not supported on this simulator runtime.`,{deviceId:e.id,action:n,setting:r.settingName,attempts:o}):new t(`COMMAND_FAILED`,`Failed to simulate ${r.settingName}.`,{deviceId:e.id,action:n,setting:r.settingName,attempts:o})}function cn(e,t,n){let r=n.length>0?n:[`face`];switch(t){case`match`:return r.flatMap(t=>[[`biometric`,e,`match`,t],[`biometric`,`match`,e,t]]);case`nonmatch`:return r.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`]]}}function ln(e,t){let n=`${e}\n${t}`.toLowerCase();return n.includes(`unrecognized subcommand`)||n.includes(`unknown subcommand`)||n.includes(`not supported`)||n.includes(`unavailable`)||n.includes(`biometric`)&&n.includes(`invalid`)}var un=e({installIosApp:()=>Bt,installIosInstallablePath:()=>Ht,listIosApps:()=>mt,pushIosNotification:()=>Gt,reinstallIosApp:()=>Vt,resolveIosApp:()=>X,resolveIosSimulatorDeepLinkBundleId:()=>ft});export{Mt as a,Tt as c,Wt as i,mt as l,qt as n,Et as o,Ut as r,Ct as s,un as t,Re as u};
@@ -1 +1 @@
1
- import{p as e}from"./sdk-contracts.js";import{c as t}from"./helper.js";const n={platform:`host-system-audio`,source:`system-audio`,backend:`macos-screencapturekit`,sourceCount:1,start:t,notes:r};function r(t){return[`Audio probe samples host system audio through ScreenCaptureKit for this ${e(t)?`iOS simulator`:t.platform===`android`?`Android emulator`:`macOS session`}; it is not app-instrumented audio.`,`Screen Recording permission is required for host system audio capture.`,`Other audible host apps can contribute to the measured buckets.`]}export{n as macOsScreenCaptureKitAudioProbeBackend};
1
+ import{s as e}from"./sdk-device.js";import{c as t}from"./helper.js";const n={platform:`host-system-audio`,source:`system-audio`,backend:`macos-screencapturekit`,sourceCount:1,start:t,notes:r};function r(t){return[`Audio probe samples host system audio through ScreenCaptureKit for this ${e(t)?`iOS simulator`:t.platform===`android`?`Android emulator`:`macOS session`}; it is not app-instrumented audio.`,`Screen Recording permission is required for host system audio capture.`,`Other audible host apps can contribute to the measured buckets.`]}export{n as macOsScreenCaptureKitAudioProbeBackend};
@@ -1,4 +1,4 @@
1
- import{er as e}from"./tv-remote.js";import{h as t,v as n}from"./registry.js";import{n as r,r as i}from"./command-schema.js";const a=[{label:`agent-device help manual-qa`,description:`Follow a manual test script with exact interactions and verification`},{label:`agent-device help dogfood`,description:`Explore an app and report issues with evidence`},{label:`agent-device help validate`,description:`Validate code changes, perf, visuals, logs, and cleanup`},{label:`agent-device help workflow`,description:`Full app automation reference for commands, refs, selectors, and waits`},{label:`agent-device help debugging`,description:`Use when logs, network, audio, perf memory, traces, alerts, or diagnostics matter`},{label:`agent-device help tv`,description:`Use when navigating Android TV or tvOS focus-first surfaces`},{label:`agent-device help react-native`,description:`Use when the target app is React Native, Expo, or a dev client`},{label:`agent-device help react-devtools`,description:`Use when inspecting components, props/state/hooks, renders, or profiles`},{label:`agent-device help cdp`,description:`Use when investigating JS heap growth, heap snapshots, or retainers`},{label:`agent-device help physical-device`,description:`Use when using a connected phone/tablet or iOS signing setup`},{label:`agent-device help remote`,description:`Use when working through cloud config, tenants, leases, or local tunnels`},{label:`agent-device help web`,description:`Use when automating a browser through agent-device sessions`},{label:`agent-device help macos`,description:`Use when targeting desktop, frontmost app, or menu bar surfaces`}],o=[`Write full command lines starting with agent-device; do not output pseudo commands, helper prose, pipes, grep, jq, or hidden stderr.`,`Default app loop: agent-device open <app> -> agent-device snapshot -i -> agent-device press/fill/click <target> --settle -> continue from that settled diff -> agent-device close.`,`Use --settle on every mutating app action that supports it: press, click, fill, longpress.`,`The settled diff is the next snapshot. Do not run wait stable or snapshot after settled:true unless the diff lacks the next target/evidence.`,`If --settle prints not settled, follow its hint before the next ref-based action.`,`Use refs or selectors as targets: @e12, label="Search", role=button label="Follow".`,`Pick the help mode below when the task is manual QA, dogfooding, engineering validation, or debugging.`],s=[`Planning output contract: when asked to plan commands, output command lines only: no prose, numbering, Markdown fences, pipes, or shell helpers.`,`If you did not use --settle, verify a mutation with diff snapshot (or diff snapshot -i), not a full snapshot: it prints only the added/removed/changed lines since the last snapshot in this session.`,`Network-backed or debounced results may arrive after the --settle quiet window; follow the settled action with wait text "Expected result" or wait <selector> instead of polling full snapshots.`,`Pin a raw CLI ref to the response that minted it with ~s<n> (n = refsGeneration): press @e12~s4; plain refs stay valid input.`,`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.`,`Truncated text/input preview: expand first with snapshot -s @e12, not get text.`,`React Native apps: read help react-native.`,`Text fields: use fill <target> <text> --settle to replace a field value. Use type <text> only to append after focusing a field with press.`,`Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.`,`Implicit default sessions are scoped to the current worktree; if a prompt names a Session, include --session <name> on every command in that flow.`,`Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.`,`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. Use press/click for taps.`,`macOS context menus use click <ref> --button secondary, then snapshot -i. Longpress is for mobile hold gestures, not macOS secondary-click menus.`,`Remote lifecycle: use connect, then open, commands, close, and disconnect. Read help remote for proxy, cloud, and device-cloud provider flows.`,`TV/D-pad targets: read help tv. Web browser sessions: read help web.`,`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.`,`Routine QA loop with concrete command shapes: agent-device help manual-qa. Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood.`],c=[`Default config files: ~/.agent-device/config.json, ./agent-device.json`,`Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file.`],l=[{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`}],u=[`agent-device open Settings --platform ios`,`agent-device open https://example.com --platform web`,`agent-device snapshot -i`,`agent-device fill @e3 "test@example.com"`,`agent-device replay ./session.ad`,`agent-device test ./suite --platform android`],d={"manual-qa":{summary:`Follow manual test scripts with exact interactions and verification`,body:`agent-device help manual-qa
1
+ import{Qn as e}from"./tv-remote.js";import{h as t,v as n}from"./registry.js";import{n as r,r as i}from"./command-schema.js";function a(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function o(e){return n().filter(t=>t.key===e)}function s(e,t){if(t.usageOverride)return t.usageOverride;let n=(t.positionalArgs??[]).map(a),r=(t.allowedFlags??[]).flatMap(e=>o(e).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`);return[e,...n,...r].join(` `)}const c=[{label:`agent-device help manual-qa`,description:`Follow a manual test script with exact interactions and verification`},{label:`agent-device help dogfood`,description:`Explore an app and report issues with evidence`},{label:`agent-device help validate`,description:`Validate code changes, perf, visuals, logs, and cleanup`},{label:`agent-device help workflow`,description:`Full app automation reference for commands, refs, selectors, and waits`},{label:`agent-device help debugging`,description:`Use when logs, network, audio, perf memory, traces, alerts, or diagnostics matter`},{label:`agent-device help tv`,description:`Use when navigating Android TV or tvOS focus-first surfaces`},{label:`agent-device help react-native`,description:`Use when the target app is React Native, Expo, or a dev client`},{label:`agent-device help react-devtools`,description:`Use when inspecting components, props/state/hooks, renders, or profiles`},{label:`agent-device help cdp`,description:`Use when investigating JS heap growth, heap snapshots, or retainers`},{label:`agent-device help physical-device`,description:`Use when using a connected phone/tablet or iOS signing setup`},{label:`agent-device help remote`,description:`Use when working through cloud config, tenants, leases, or local tunnels`},{label:`agent-device help web`,description:`Use when automating a browser through agent-device sessions`},{label:`agent-device help macos`,description:`Use when targeting desktop, frontmost app, or menu bar surfaces`}],l=[`Write full command lines starting with agent-device; do not output pseudo commands, helper prose, pipes, grep, jq, or hidden stderr.`,`Default app loop: agent-device open <app> -> agent-device snapshot -i -> agent-device press/fill/click <target> --settle -> continue from that settled diff -> agent-device close.`,`Use --settle on every mutating app action that supports it: press, click, fill, longpress.`,`The settled diff is the next snapshot. Do not run wait stable or snapshot after settled:true unless the diff lacks the next target/evidence.`,`If --settle prints not settled, follow its hint before the next ref-based action.`,`Use refs or selectors as targets: @e12, label="Search", role=button label="Follow".`,`Pick the help mode below when the task is manual QA, dogfooding, engineering validation, or debugging.`],u=[`Planning output contract: when asked to plan commands, output command lines only: no prose, numbering, Markdown fences, pipes, or shell helpers.`,`If you did not use --settle, verify a mutation with diff snapshot (or diff snapshot -i), not a full snapshot: it prints only the added/removed/changed lines since the last snapshot in this session.`,`Network-backed or debounced results may arrive after the --settle quiet window; follow the settled action with wait text "Expected result" or wait <selector> instead of polling full snapshots.`,`Pin a raw CLI ref to the response that minted it with ~s<n> (n = refsGeneration): press @e12~s4; plain refs stay valid input.`,`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.`,`Truncated text/input preview: expand first with snapshot -s @e12, not get text.`,`React Native apps: read help react-native.`,`Text fields: use fill <target> <text> --settle to replace a field value. Use type <text> only to append after focusing a field with press.`,`Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.`,`Implicit default sessions are scoped to the current worktree; if a prompt names a Session, include --session <name> on every command in that flow.`,`Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.`,`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. Use press/click for taps.`,`macOS context menus use click <ref> --button secondary, then snapshot -i. Longpress is for mobile hold gestures, not macOS secondary-click menus.`,`Remote lifecycle: use connect, then open, commands, close, and disconnect. Read help remote for proxy, cloud, and device-cloud provider flows.`,`TV/D-pad targets: read help tv. Web browser sessions: read help web.`,`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.`,`Routine QA loop with concrete command shapes: agent-device help manual-qa. Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood.`],d=[`Default config files: ~/.agent-device/config.json, ./agent-device.json`,`Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file.`],f=[{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`}],p=[`agent-device open Settings --platform ios`,`agent-device open https://example.com --platform web`,`agent-device snapshot -i`,`agent-device fill @e3 "test@example.com"`,`agent-device replay ./session.ad`,`agent-device test ./suite --platform android`],m={"manual-qa":{summary:`Follow manual test scripts with exact interactions and verification`,body:`agent-device help manual-qa
2
2
 
3
3
  Use this when asked to follow a manual QA script, test case, checklist, acceptance flow, or user-provided instructions.
4
4
 
@@ -34,7 +34,7 @@ Targets:
34
34
 
35
35
  Recovery:
36
36
  Network/typeahead result missing: wait text "Expected result" or wait <selector>.
37
- Keyboard blocks target: keyboard dismiss when supported, then snapshot -i.
37
+ Keyboard visible over the next target: the on-screen keyboard usually does not block presses, so press the target directly instead of dismissing. If the press fails or reports no visible effect, scroll the target into view or use keyboard enter when submission is wanted.
38
38
  Sparse or recovered accessibility snapshot: use screenshot as visual truth, leave the bad screen if needed, then retry snapshot -i.
39
39
  Non-hittable success hint: verify with the settled diff or snapshot; retarget by a better ref/selector if the UI did not change.`},workflow:{summary:`Normal agent-device bootstrap, exploration, and validation loop`,body:`agent-device help workflow
40
40
 
@@ -112,8 +112,8 @@ Text entry:
112
112
  agent-device press 'id="product-note"'
113
113
  agent-device type "Handle with care" --delay-ms 80
114
114
  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.
115
- Debounced field with no result selector: agent-device wait 1000. Keyboard read-only: keyboard status/get. Blocked control: try keyboard dismiss when supported.
116
- To hide the keyboard, use keyboard dismiss. It taps safe controls like Done when available and verifies the keyboard closed. If it reports UNSUPPORTED_OPERATION, press a visible app control such as Done only when that is the intended fallback.
115
+ Debounced field with no result selector: agent-device wait 1000. Keyboard read-only: keyboard status/get. The on-screen keyboard usually does not block agent-device interactions; press the next target directly instead of dismissing. If that press fails or reports no visible effect, scroll the target into view or use keyboard enter when submission is wanted.
116
+ Only dismiss the keyboard when hiding it is the actual goal. To hide the keyboard, use keyboard dismiss. It taps safe controls like Done when available and verifies the keyboard closed. If it reports UNSUPPORTED_OPERATION, press a visible app control such as Done only when that is the intended fallback, or press the next target directly instead of retrying dismiss.
117
117
  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.
118
118
  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.
119
119
  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.
@@ -868,36 +868,36 @@ Evidence:
868
868
 
869
869
  Report:
870
870
  Summarize what changed, exact validation commands, pass/fail observations, artifact paths, and residual risk.
871
- If live validation is blocked, state the blocker, device/session, and exact next command needed.`}};function f(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function p(e,t,n){let r=n.endsWith(`?`),i=r?n.slice(0,-1):n,a=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i),o=a||t.usageOverride!==void 0&&t.usageOverride.startsWith(`${e} ${i}`);return r?a?`[${i}]`:o?i:`[${i}]`:o?i:`<${i}>`}function m(e,t){if(t.usageOverride)return t.usageOverride;let n=(t.positionalArgs??[]).map(f),r=(t.allowedFlags??[]).flatMap(e=>h(e).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`);return[e,...n,...r].join(` `)}function h(e){return n().filter(t=>t.key===e)}function g(e,t){return t.listUsageOverride?t.listUsageOverride:[e,...(t.positionalArgs??[]).map(n=>p(e,t,n))].join(` `)}function _(){let n=C(e().map(e=>{let t=r(e);return{name:e,schema:t,usage:g(e,t)}})),i=b(`Global Flags:`,y(t)),d=S(`Agent Starting Point:`,o),f=S(`Agent Quickstart:`,s);return`agent-device <command> [args] [--json]
871
+ If live validation is blocked, state the blocker, device/session, and exact next command needed.`}};function h(e,t,n){let r=n.endsWith(`?`),i=r?n.slice(0,-1):n,a=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i),o=a||t.usageOverride!==void 0&&t.usageOverride.startsWith(`${e} ${i}`);return r?a?`[${i}]`:o?i:`[${i}]`:o?i:`<${i}>`}function g(e,t){return t.listUsageOverride?t.listUsageOverride:[e,...(t.positionalArgs??[]).map(n=>h(e,t,n))].join(` `)}function _(){let n=C(e().map(e=>{let t=r(e);return{name:e,schema:t,usage:g(e,t)}})),i=b(`Global Flags:`,y(t)),a=S(`Agent Starting Point:`,l),o=S(`Agent Quickstart:`,u);return`agent-device <command> [args] [--json]
872
872
 
873
873
  CLI to automate supported app, device, desktop, and web targets for AI agents.
874
874
 
875
- ${d}
875
+ ${a}
876
876
 
877
- ${x(`Agent Workflows:`,a)}
877
+ ${x(`Agent Workflows:`,c)}
878
878
 
879
879
  ${n}
880
880
 
881
881
  ${i}
882
882
 
883
- ${f}
883
+ ${o}
884
884
 
885
- ${S(`Configuration:`,c)}
885
+ ${S(`Configuration:`,d)}
886
886
 
887
- ${x(`Environment:`,l)}
887
+ ${x(`Environment:`,f)}
888
888
 
889
- ${S(`Examples:`,u)}
889
+ ${S(`Examples:`,p)}
890
890
  `}function v(){return _()}function y(e){return n().filter(t=>e.has(t.key)&&t.usageLabel!==void 0&&t.usageDescription!==void 0)}function b(e,t){return x(e,t.map(e=>({label:e.usageLabel??``,description:e.usageDescription??``})))}function x(e,t){if(t.length===0)return`${e}\n (none)`;let n=Math.max(...t.map(e=>Math.min(e.label.length,26)))+2,r=[e];for(let e of t){let t=e.label.length<=26?e.label.padEnd(n):`${e.label} `;r.push(` ${t}${e.description}`)}return r.join(`
891
891
  `)}function S(e,t){return t.length===0?`${e}\n (none)`:[e,...t.map(e=>` ${e}`)].join(`
892
- `)}function C(e){return x(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription})))}function w(e){let t=T(e);if(t)return t;let n=i(e);if(!n)return null;let r=m(e,n),a=y(new Set(n.allowedFlags??[])),o=[];a.length>0&&o.push(b(`Command flags:`,a));let s=o.length>0?`\n\n${o.join(`
892
+ `)}function C(e){return x(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription})))}function w(e){let t=T(e);if(t)return t;let n=i(e);if(!n)return null;let r=s(e,n),a=y(new Set(n.allowedFlags??[])),o=[];a.length>0&&o.push(b(`Command flags:`,a));let c=o.length>0?`\n\n${o.join(`
893
893
 
894
894
  `)}`:``;return`agent-device ${r}
895
895
 
896
896
  ${n.helpDescription}
897
897
 
898
898
  Usage:
899
- agent-device ${r}${s}
900
- `}function T(e){let t=d[e];return t?`${t.body}
899
+ agent-device ${r}${c}
900
+ `}function T(e){let t=m[e];return t?`${t.body}
901
901
 
902
902
  Related:
903
903
  agent-device help command list and global flags
@@ -1,2 +1,2 @@
1
- import{Kn as e}from"./tv-remote.js";import{n as t}from"./registry.js";import{t as n}from"./cli-output.js";import{n as r}from"./command-surface.js";function i(t,n,r){if(t.json){e({success:!0,data:n});return}let i=r?.();i&&a(i)}function a(e){process.stdout.write(e.endsWith(`
1
+ import{Wn as e}from"./tv-remote.js";import{n as t}from"./registry.js";import{t as n}from"./cli-output.js";import{n as r}from"./command-surface.js";function i(t,n,r){if(t.json){e({success:!0,data:n});return}let i=r?.();i&&a(i)}function a(e){process.stdout.write(e.endsWith(`
2
2
  `)?e:`${e}\n`)}const o=t();function s(e,t,n){let r=o[e];if(!r)throw Error(`Missing CLI reader for command: ${e}`);return r(t,n)}async function c(e){return(await l(e)).result}async function l(e){let t=s(e.command,e.positionals,e.flags),i=await r(e.client,e.command,t);return{result:i,cliOutput:n({name:e.command,input:t,result:i})}}export{i,l as n,s as r,c as t};