agent-device 0.20.8 → 0.20.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/README.md +94 -31
  2. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.8.apk → agent-device-android-ime-helper-0.20.9.apk} +0 -0
  3. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.9.apk.sha256 +1 -0
  4. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.8.manifest.json → agent-device-android-ime-helper-0.20.9.manifest.json} +4 -4
  5. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.8.apk → agent-device-android-snapshot-helper-0.20.9.apk} +0 -0
  6. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.9.apk.sha256 +1 -0
  7. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.8.manifest.json → agent-device-android-snapshot-helper-0.20.9.manifest.json} +6 -6
  8. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +3 -0
  9. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +13 -7
  10. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +4 -112
  11. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +9 -1
  12. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +90 -0
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +46 -10
  14. package/dist/src/agent-browser-tool.js +1 -1
  15. package/dist/src/agent-device-client.js +2 -2
  16. package/dist/src/android-adb.d.ts +5 -5
  17. package/dist/src/android-adb.js +1 -1
  18. package/dist/src/android.js +1 -1
  19. package/dist/src/app-helpers.js +1 -1
  20. package/dist/src/app-lifecycle.js +6 -7
  21. package/dist/src/app-lifecycle2.js +2 -2
  22. package/dist/src/app-log-reconnect.js +1 -1
  23. package/dist/src/app-log-runtime.js +3 -3
  24. package/dist/src/app-resolution.js +2 -2
  25. package/dist/src/app-state.js +2 -0
  26. package/dist/src/appearance.js +1 -0
  27. package/dist/src/apps.js +5 -5
  28. package/dist/src/artifacts.d.ts +1 -1
  29. package/dist/src/audio-probe.js +1 -1
  30. package/dist/src/auth-session.js +1 -1
  31. package/dist/src/backend-snapshot-options.js +1 -0
  32. package/dist/src/boot-diagnostics.js +2 -2
  33. package/dist/src/bounds.js +1 -0
  34. package/dist/src/byte-limit-stream.js +1 -0
  35. package/dist/src/cancel.js +1 -0
  36. package/dist/src/cli-config.js +1 -1
  37. package/dist/src/cli-help.js +25 -20
  38. package/dist/src/cli.js +6 -6
  39. package/dist/src/client-metro.js +1 -1
  40. package/dist/src/command-catalog.js +1 -0
  41. package/dist/src/command-metadata.js +1 -1
  42. package/dist/src/command-schema.js +1 -1
  43. package/dist/src/command-surface.js +1 -1
  44. package/dist/src/config.js +1 -0
  45. package/dist/src/connection-runtime.js +1 -1
  46. package/dist/src/connection.js +3 -3
  47. package/dist/src/contracts.js +1 -1
  48. package/dist/src/debug-symbols.js +3 -3
  49. package/dist/src/device-claim-inspection.js +1 -1
  50. package/dist/src/device-input-state.js +1 -1
  51. package/dist/src/device-ready.js +1 -1
  52. package/dist/src/device2.js +2 -2
  53. package/dist/src/dispatch.js +1 -1
  54. package/dist/src/entities.js +1 -1
  55. package/dist/src/find.js +1 -1
  56. package/dist/src/finders.js +1 -1
  57. package/dist/src/generic-settle.js +1 -1
  58. package/dist/src/generic.js +1 -1
  59. package/dist/src/harmonyos.js +1 -1
  60. package/dist/src/hdc.js +1 -1
  61. package/dist/src/helper-package-install.js +1 -0
  62. package/dist/src/helper.js +2 -2
  63. package/dist/src/host-process.js +1 -1
  64. package/dist/src/ime-lifecycle.js +2 -9
  65. package/dist/src/ime-recovery-marker.js +1 -0
  66. package/dist/src/index.d.ts +24 -15
  67. package/dist/src/index.js +1 -1
  68. package/dist/src/input-actions.js +4 -4
  69. package/dist/src/input-actions2.js +1 -1
  70. package/dist/src/input-actions3.js +1 -1
  71. package/dist/src/install-artifact.js +1 -1
  72. package/dist/src/install-artifact2.js +1 -1
  73. package/dist/src/install-source2.js +1 -1
  74. package/dist/src/interaction-common.js +1 -0
  75. package/dist/src/interaction-runtime.js +1 -1
  76. package/dist/src/interaction-snapshot.js +1 -1
  77. package/dist/src/interaction.js +1 -1
  78. package/dist/src/interaction2.js +1 -0
  79. package/dist/src/interactor.js +2 -2
  80. package/dist/src/interactor2.js +1 -1
  81. package/dist/src/interactors.js +1 -0
  82. package/dist/src/internal/bin.js +1 -1
  83. package/dist/src/internal/daemon.js +4 -7
  84. package/dist/src/internal/png-worker.js +1 -1
  85. package/dist/src/inventory.js +1 -1
  86. package/dist/src/keyed-lock.js +1 -0
  87. package/dist/src/lease-context.js +1 -1
  88. package/dist/src/lease.js +1 -1
  89. package/dist/src/limrun-runtime-dependencies.js +1 -1
  90. package/dist/src/limrun.d.ts +3 -1
  91. package/dist/src/limrun.js +1 -1
  92. package/dist/src/linux.js +1 -1
  93. package/dist/src/location-coordinates.js +1 -0
  94. package/dist/src/logcat.js +1 -1
  95. package/dist/src/manifest.js +1 -1
  96. package/dist/src/observability.js +1 -0
  97. package/dist/src/owner-identity.js +1 -1
  98. package/dist/src/perf.js +4 -0
  99. package/dist/src/physical-device-control.js +1 -1
  100. package/dist/src/platform-runtime-app-log-process.js +1 -1
  101. package/dist/src/platform-runtime-host.js +1 -1
  102. package/dist/src/platform-runtime-network-web-transport.js +1 -1
  103. package/dist/src/platform-runtime-open-target.js +1 -0
  104. package/dist/src/platform-runtime-operation-host.js +4 -4
  105. package/dist/src/platform-runtime-runtime-hints.js +2 -0
  106. package/dist/src/platform-runtime-screen-recording-apple-runner-host.js +1 -1
  107. package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
  108. package/dist/src/platform-runtime-screen-recording-apple-transport.js +1 -1
  109. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  110. package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
  111. package/dist/src/platform-runtime.js +1 -1
  112. package/dist/src/platform-runtime2.js +1 -0
  113. package/dist/src/plist.js +1 -1
  114. package/dist/src/png-resize.js +1 -0
  115. package/dist/src/png-worker-contract.js +1 -1
  116. package/dist/src/prepare-kind.js +13 -13
  117. package/dist/src/process-lock.js +1 -1
  118. package/dist/src/project-runtime.js +1 -0
  119. package/dist/src/provider-webdriver.js +1 -1
  120. package/dist/src/provider.js +1 -0
  121. package/dist/src/proxy.js +1 -1
  122. package/dist/src/react-native.js +1 -1
  123. package/dist/src/record-runtime.js +1 -1
  124. package/dist/src/record-trace.js +1 -1
  125. package/dist/src/recording-export-quality.js +1 -0
  126. package/dist/src/registry.js +29 -26
  127. package/dist/src/remote-config2.js +1 -1
  128. package/dist/src/replay.js +1 -1
  129. package/dist/src/reporting.js +3 -3
  130. package/dist/src/rolldown-runtime.js +1 -0
  131. package/dist/src/runner-client.js +1 -0
  132. package/dist/src/runner-disposal.js +1 -1
  133. package/dist/src/runner-lease.js +1 -1
  134. package/dist/src/runner-sequence.js +1 -1
  135. package/dist/src/runtime-transport.js +1 -1
  136. package/dist/src/runtime.js +3 -3
  137. package/dist/src/runtime2.js +4 -3
  138. package/dist/src/runtime3.js +1 -3
  139. package/dist/src/runtime4.js +3 -1
  140. package/dist/src/runtime5.js +1 -1
  141. package/dist/src/runtime6.js +1 -1
  142. package/dist/src/runtime7.js +1 -1
  143. package/dist/src/runtime8.js +1 -0
  144. package/dist/src/runtime9.js +1 -0
  145. package/dist/src/scoped-provider.js +1 -0
  146. package/dist/src/screenshot-density.js +1 -0
  147. package/dist/src/screenshot-geometry.js +1 -0
  148. package/dist/src/screenshot-result.js +4 -4
  149. package/dist/src/screenshot.js +1 -1
  150. package/dist/src/sdk-android-adb.d.ts +20 -2
  151. package/dist/src/sdk-android-adb.js +3 -3
  152. package/dist/src/sdk-batch-runner.js +3 -3
  153. package/dist/src/sdk-contracts.d.ts +3 -3
  154. package/dist/src/sdk-contracts.js +2 -2
  155. package/dist/src/sdk-device.js +1 -1
  156. package/dist/src/sdk-finders.js +1 -1
  157. package/dist/src/sdk-io.js +1 -1
  158. package/dist/src/sdk-remote-config.js +1 -1
  159. package/dist/src/sdk-selectors.d.ts +19 -19
  160. package/dist/src/sdk-selectors.js +1 -1
  161. package/dist/src/sdk.js +1 -0
  162. package/dist/src/selector-runtime.js +1 -1
  163. package/dist/src/selectors.d.ts +1 -1
  164. package/dist/src/selectors.js +1 -1
  165. package/dist/src/server.js +2 -2
  166. package/dist/src/session-target-evidence.js +1 -1
  167. package/dist/src/session.js +1 -30
  168. package/dist/src/session2.js +28 -0
  169. package/dist/src/setting-state.js +1 -1
  170. package/dist/src/shared.js +1 -1
  171. package/dist/src/simctl.js +1 -0
  172. package/dist/src/simulator-state.js +1 -0
  173. package/dist/src/simulator.js +1 -1
  174. package/dist/src/snapshot-runtime.js +1 -1
  175. package/dist/src/snapshot-session.js +1 -1
  176. package/dist/src/snapshot.js +8 -1
  177. package/dist/src/snapshot2.js +1 -1
  178. package/dist/src/snapshot3.js +1 -0
  179. package/dist/src/src.js +1 -1
  180. package/dist/src/src2.js +1 -2
  181. package/dist/src/src3.js +2 -1
  182. package/dist/src/string-enum.js +1 -0
  183. package/dist/src/tool-provider.js +3 -3
  184. package/dist/src/tool-provider2.js +1 -1
  185. package/dist/src/update-check.js +1 -1
  186. package/dist/src/verdict.js +1 -0
  187. package/dist/src/verified-file.js +1 -0
  188. package/dist/src/version.js +1 -1
  189. package/dist/src/video.js +1 -1
  190. package/dist/src/web.js +1 -1
  191. package/package.json +8 -4
  192. package/server.json +3 -3
  193. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.8.apk.sha256 +0 -1
  194. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.8.apk.sha256 +0 -1
  195. package/dist/src/interaction-touch-reference-frame.js +0 -1
  196. package/dist/src/notifications.js +0 -1
  197. package/dist/src/platform-runtime-toolchain-host.js +0 -1
  198. package/dist/src/text-surface.js +0 -1
  199. package/dist/src/tool-provider3.js +0 -1
@@ -1 +1 @@
1
- import{o as e}from"./png-worker-contract.js";import{_ as t}from"./sdk-contracts.js";import{f as n,h as r}from"./sdk-android-adb.js";import{i,n as a,o,t as s}from"./boot-diagnostics.js";import{L as c,N as l,R as u,d,p as f}from"./physical-device-control.js";import{a as p,i as m}from"./tool-provider.js";var h=e({SIMULATOR_BOOTED_MEMO_TTL_MS:()=>v,ensureBootedSimulator:()=>E,getSimulatorState:()=>O,markSimulatorBooted:()=>S,openIosSimulatorApp:()=>T,requireSimulatorDevice:()=>w,shutdownSimulator:()=>D});const g=[`Simulator`],_=[`Device Hub`,`Simulator`],v=5e3,y=l({ttlMs:v});function b(e){return`${e.id}|${e.simulatorSetPath??``}`}function x(e){return y.get(b(e))===!0}function S(e){y.set(b(e),!0)}function C(e){y.delete(b(e))}function w(e,n){if(e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`${n} is only supported on iOS simulators`)}async function T(e={}){let t=e.deviceHub?_:g,n=e.background?[`-g`,`-a`]:[`-a`];for(let e of t)if((await m(`open`,[...n,e],{allowFailure:!0,timeoutMs:1e4})).exitCode===0)return}async function E(e,c={}){if(e.kind!==`simulator`)return;if((x(e)?`Booted`:await O(e))===`Booted`){S(e),c.focusExisting&&await T({background:c.deviceHub,deviceHub:c.deviceHub});return}c.onColdBootStart?.(e);let l=i.fromTimeoutMs(d),f,m;try{await o(async({deadline:i})=>{if(i?.isExpired())throw new t(`COMMAND_FAILED`,`iOS simulator boot deadline exceeded`,{timeoutMs:d});let a=Math.max(1e3,i?.remainingMs()??18e4);f=await p(u(e,[`boot`,e.id]),{allowFailure:!0,timeoutMs:a});let o=`${f.stdout}\n${f.stderr}`.toLowerCase(),s=o.includes(`already booted`)||o.includes(`current state: booted`);if(f.exitCode!==0&&!s)throw new t(`COMMAND_FAILED`,`simctl boot failed`,n(f));m=await p(u(e,[`bootstatus`,e.id,`-b`]),{allowFailure:!0,timeoutMs:a}),r(m,`simctl bootstatus failed`);let c=await O(e);if(c!==`Booted`)throw new t(`COMMAND_FAILED`,`Simulator is still booting`,{state:c})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let t=a({error:e,stdout:m?.stdout??f?.stdout,stderr:m?.stderr??f?.stderr,context:{platform:`ios`,phase:`boot`}});return t!==`IOS_BOOT_TIMEOUT`&&t!==`CI_RESOURCE_STARVATION_SUSPECTED`}},{deadline:l,phase:`boot`,classifyReason:e=>a({error:e,stdout:m?.stdout??f?.stdout,stderr:m?.stderr??f?.stderr,context:{platform:`ios`,phase:`boot`}})})}catch(n){let r=a({error:n,stdout:m?.stdout??f?.stdout,stderr:m?.stderr??f?.stderr,context:{platform:`ios`,phase:`boot`}});throw new t(`COMMAND_FAILED`,`iOS simulator failed to boot`,{platform:`ios`,deviceId:e.id,timeoutMs:d,elapsedMs:l.elapsedMs(),reason:r,hint:s(r),boot:f,bootstatus:m})}S(e),await T({deviceHub:c.deviceHub})}async function D(e){C(e);let t=await p(u(e,[`shutdown`,e.id]),{allowFailure:!0,timeoutMs:15e3});return{success:t.exitCode===0,exitCode:t.exitCode,stdout:t.stdout,stderr:t.stderr}}async function O(e){let t=typeof e==`string`?e:e.id,n=await p(typeof e==`string`?c([`list`,`devices`,`-j`]):u(e,[`list`,`devices`,`-j`]),{allowFailure:!0,timeoutMs:f});if(n.exitCode!==0)return null;try{let e=JSON.parse(n.stdout);for(let n of Object.values(e.devices??{})){let e=n.find(e=>e.udid===t);if(e)return e.state}return null}catch{return null}}export{h as a,D as i,O as n,w as r,E as t};
1
+ import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{f as n,h as r}from"./sdk-android-adb.js";import{i,n as a,o,t as s}from"./boot-diagnostics.js";import{n as c,t as l}from"./simctl.js";import{a as u,i as d}from"./tool-provider.js";import{n as f,o as p,p as m}from"./config.js";var h=e({SIMULATOR_BOOTED_MEMO_TTL_MS:()=>v,ensureBootedSimulator:()=>T,getSimulatorState:()=>E,markSimulatorBooted:()=>S,openIosSimulatorApp:()=>w,requireSimulatorDevice:()=>C});const g=[`Simulator`],_=[`Device Hub`,`Simulator`],v=5e3,y=m({ttlMs:v});function b(e){return`${e.id}|${e.simulatorSetPath??``}`}function x(e){return y.get(b(e))===!0}function S(e){y.set(b(e),!0)}function C(e,n){if(e.kind!==`simulator`)throw new t(`UNSUPPORTED_OPERATION`,`${n} is only supported on iOS simulators`)}async function w(e={}){let t=e.deviceHub?_:g,n=e.background?[`-g`,`-a`]:[`-a`];for(let r of t)if((await d(`open`,[...n,r],{allowFailure:!0,signal:e.signal,timeoutMs:1e4})).exitCode===0)return}async function T(e,l={}){if(e.kind!==`simulator`)return;if(l.signal?.throwIfAborted(),(x(e)?`Booted`:await E(e,l.signal))===`Booted`){S(e),l.focusExisting&&await w({background:l.deviceHub,deviceHub:l.deviceHub,signal:l.signal});return}l.onColdBootStart?.(e);let d=i.fromTimeoutMs(f),p,m;try{await o(async({deadline:i})=>{if(i?.isExpired())throw new t(`COMMAND_FAILED`,`iOS simulator boot deadline exceeded`,{timeoutMs:f});let a=Math.max(1e3,i?.remainingMs()??18e4);p=await u(c(e,[`boot`,e.id]),{allowFailure:!0,signal:l.signal,timeoutMs:a});let o=`${p.stdout}\n${p.stderr}`.toLowerCase(),s=o.includes(`already booted`)||o.includes(`current state: booted`);if(p.exitCode!==0&&!s)throw new t(`COMMAND_FAILED`,`simctl boot failed`,n(p));m=await u(c(e,[`bootstatus`,e.id,`-b`]),{allowFailure:!0,signal:l.signal,timeoutMs:a}),r(m,`simctl bootstatus failed`);let d=await E(e,l.signal);if(d!==`Booted`)throw new t(`COMMAND_FAILED`,`Simulator is still booting`,{state:d})},{maxAttempts:3,baseDelayMs:500,maxDelayMs:2e3,jitter:.2,shouldRetry:e=>{let t=a({error:e,stdout:m?.stdout??p?.stdout,stderr:m?.stderr??p?.stderr,context:{platform:`ios`,phase:`boot`}});return t!==`IOS_BOOT_TIMEOUT`&&t!==`CI_RESOURCE_STARVATION_SUSPECTED`}},{deadline:d,phase:`boot`,signal:l.signal,classifyReason:e=>a({error:e,stdout:m?.stdout??p?.stdout,stderr:m?.stderr??p?.stderr,context:{platform:`ios`,phase:`boot`}})})}catch(n){let r=a({error:n,stdout:m?.stdout??p?.stdout,stderr:m?.stderr??p?.stderr,context:{platform:`ios`,phase:`boot`}});throw new t(`COMMAND_FAILED`,`iOS simulator failed to boot`,{platform:`ios`,deviceId:e.id,timeoutMs:f,elapsedMs:d.elapsedMs(),reason:r,hint:s(r),boot:p,bootstatus:m})}S(e),await w({deviceHub:l.deviceHub,signal:l.signal})}async function E(e,t){let n=typeof e==`string`?e:e.id,r=await u(typeof e==`string`?l([`list`,`devices`,`-j`]):c(e,[`list`,`devices`,`-j`]),{allowFailure:!0,signal:t,timeoutMs:p});if(r.exitCode!==0)return null;try{let e=JSON.parse(r.stdout);for(let t of Object.values(e.devices??{})){let e=t.find(e=>e.udid===n);if(e)return e.state}return null}catch{return null}}export{h as i,E as n,C as r,T as t};
@@ -1 +1 @@
1
- import{S as e,_ as t}from"./sdk-contracts.js";import{bt as n,wt as r}from"./version.js";import{$ as i}from"./sdk-batch-runner.js";import{_ as a,c as o}from"./sdk-device.js";import{H as s}from"./prepare-kind.js";import{j as c}from"./screenshot-result.js";import{t as l}from"./runtime.js";import{j as u}from"./sdk-android-adb.js";import{n as d}from"./shell-quote.js";import{N as f}from"./runner-disposal.js";import{E as p,b as m,c as h,o as g,t as _,y as v}from"./dispatch.js";import{$t as y,Qt as b,Wt as x,an as S,fn as C,on as w,qt as T}from"./internal/daemon.js";import{i as E,l as D,r as O,t as k}from"./snapshot-session.js";import{n as A}from"./app-resolution.js";import j from"node:path";import{promises as M}from"node:fs";import N from"node:os";function P(e){return o(e)&&e.kind===`simulator`}function F(e){return e.platform===`android`&&e.kind===`emulator`}async function I(e={}){try{let t=await v({platform:`ios`,iosSimulatorSetPath:e.simulatorSetPath,kind:`simulator`,booted:!0});if(t.length!==1)return;let[n]=t;if(!n)return;let r=await A(n);return r?{device:n,app:r}:void 0}catch(e){if(m(e))throw e;return}}async function L(e){if(!o(e)||e.kind!==`simulator`)return;let t=await I({simulatorSetPath:e.simulatorSetPath});if(!t)return;let n=R(t.device,t.app.bundleId),r=`One booted device found ("${t.device.name}", udid ${t.device.id}) with ${t.app.bundleId} running. Run: ${n}`;return r.length<=350?r:void 0}function R(e,t){let n=e.simulatorSetPath?` --ios-simulator-device-set ${d(e.simulatorSetPath)}`:``;return`agent-device open ${t} --platform ios --udid ${e.id}${n}`}async function z(t){if(t.command!==`snapshot`||t.device.platform!==`android`)return;let n=e(t.error);if(U(n))return{ok:!1,error:{...n,details:{...n.details??{},androidSnapshotTimeoutScreenshot:await ee(t)}}}}async function ee(t){try{let e=await M.mkdtemp(j.join(N.tmpdir(),`agent-device-android-snapshot-timeout-`)),n=j.join(e,`snapshot-timeout-overlay-refs.png`),r=V(await _(t.device,`screenshot`,[n],void 0,{...C(t.logPath,{screenshotNoStabilize:!0},t.session?.appBundleId,t.session?.trace?.outPath),surface:t.session?.surface}),n);await M.access(r);let i=await B(r,t.session);return u({level:`warn`,phase:`android_snapshot_timeout_screenshot_captured`,data:{path:r,overlayRefCount:`overlayRefCount`in i?i.overlayRefCount:void 0,overlayRefsAnnotated:`overlayRefsAnnotated`in i?i.overlayRefsAnnotated:void 0}}),i}catch(t){let n=e(t);return u({level:`warn`,phase:`android_snapshot_timeout_screenshot_failed`,data:{error:n.message}}),{captureFailed:!0,error:n.message}}}async function B(t,n){if(!n?.snapshot)return{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:`unavailable`,overlayRefCount:0};try{let e=await x({screenshotPath:t,snapshot:n.snapshot});return{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:e.length>0,overlayRefCount:e.length,overlayRefSource:`session-snapshot`,overlayRefs:e}}catch(n){let r=e(n);return u({level:`warn`,phase:`android_snapshot_timeout_screenshot_overlay_failed`,data:{path:t,error:r.message}}),{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:`session-snapshot`,overlayRefCount:0,overlayAnnotationError:r.message}}}function V(e,t){return H(e)?e.path:t}function H(e){return typeof e==`object`&&!!e&&`path`in e&&typeof e.path==`string`}function U(e){return e.code===`COMMAND_FAILED`?W(e)||G(e.details?.helper):!1}function W(e){let t=`${e.message}\n${e.hint??``}`;return/Android accessibility snapshots can be blocked/i.test(t)}function G(e){if(!e||typeof e!=`object`)return!1;let t=e,n=String(t.errorType??``),r=String(t.message??``);return/TimeoutException/i.test(n)||/timed out/i.test(r)}function K(e){let{verdict:t,appBundleId:n,latch:r}=e;return t?t.state===`healthy`?{latch:void 0}:t.state!==`recovered`||t.reasonCode===`requested-backend`?{latch:r}:t.reasonCode===`deferred`?r!==void 0&&r.appBundleId===n?{latch:r}:{warning:s(t.backend),latch:{appBundleId:n}}:{latch:{appBundleId:n}}:{latch:r}}function q(e){let{session:t,data:n,verdict:r,internalObservation:i}=e;if(i||!t)return n;let a=K({verdict:r,appBundleId:t.appBundleId,latch:t.recoveredSnapshotWarningLatch});if(t.recoveredSnapshotWarningLatch=a.latch,!a.warning)return n;let o=Array.isArray(n.warnings)?n.warnings:[];return{...n,warnings:[a.warning,...o]}}async function J(e){return await Z({...e,command:`snapshot`,unsupportedMessage:`snapshot is not supported on this device`,execute:async({runtime:t,sessionName:n,req:r,snapshotScope:a})=>{let o=await t.capture.snapshot({session:n,interactiveOnly:r.flags?.snapshotInteractiveOnly,depth:r.flags?.snapshotDepth,scope:a,raw:r.flags?.snapshotRaw,customActions:r.flags?.snapshotCustomActions,forceFull:r.flags?.snapshotForceFull}),s=Y(r,e.sessionStore.get(n)),c=i(o.nodes),l=c===o.nodes?o:{...o,nodes:c};return{data:s===void 0?l:{...l,refsGeneration:s},record:{kind:`snapshot`,nodes:o.nodes.length,truncated:o.truncated}}}})}function Y(e,t){return e.internal?.observationOnly===!0?void 0:t?.snapshotGeneration}async function X(e){return await Z({...e,command:`diff`,unsupportedMessage:`diff is not supported on this device`,execute:async({runtime:e,sessionName:t,req:n,snapshotScope:r})=>{let i=await e.capture.diffSnapshot({session:t,interactiveOnly:n.flags?.snapshotInteractiveOnly,depth:n.flags?.snapshotDepth,scope:r,raw:n.flags?.snapshotRaw});return{data:i,record:{kind:`diff`,mode:`snapshot`,baselineInitialized:i.baselineInitialized,summary:i.summary}}}})}async function Z(e){let{req:t,sessionName:n,logPath:r,sessionStore:i}=e,{session:a,device:o}=await O(i,n,t.flags),s=h(e.command,o,{message:e.unsupportedMessage});if(s)return s;let c=w(t.flags?.snapshotScope,a);return c.ok?Q(t,o)||await $(e.command,a,o)||await E(a,o,async()=>{let s={},l=te({req:t,sessionName:n,logPath:r,sessionStore:i,session:a,device:o,snapshotScope:c.scope,capturedQuality:s}),u;try{u=await e.execute({runtime:l,sessionName:n,req:t,snapshotScope:c.scope})}catch(t){let n=await z({error:t,command:e.command,logPath:r,session:a,device:o});if(!n)throw t;return n}return ce({req:t,sessionName:n,sessionStore:i,result:u.record}),{ok:!0,data:q({session:i.get(n),data:u.data,verdict:s.value,internalObservation:t.internal?.observationOnly===!0})}}):c}function Q(e,t){return e.flags?.snapshotCustomActions!==!0||P(t)?null:g(`UNSUPPORTED_OPERATION`,`--actions requires an iOS simulator: custom actions are read through the private accessibility snapshot backend, which ${t.platform}/${t.kind} targets do not have.`,{hint:`Re-run without --actions, or target an iOS simulator.`})}async function $(e,t,n){if(!o(n)||t?.appBundleId||p(n))return null;let r=await L(n);return g(`SESSION_NOT_FOUND`,`iOS ${e} requires an active app session on the target device. Run open first (for example: open --session ${t?.name??`sim`} --platform ios --device "<name>" <app>).`,{reason:`ios_app_session_required`,...r?{hint:r}:{}})}function te(e){let{req:t,sessionName:n,logPath:r,sessionStore:i,session:a,device:o,snapshotScope:s}=e;return l({backend:se({req:t,logPath:r,session:a,device:o,snapshotScope:s,capturedQuality:e.capturedQuality}),...D(`snapshot`),signal:f(t.meta?.requestId),sessions:T({sessionName:n,getSession:()=>i.get(n),recordOptions:{includeSnapshot:!0},setRecord:e=>{let r=le(e),a=i.get(n);i.set(n,ne({current:a,sessionName:n,device:o,record:r,refScopedSnapshot:re(t),issuesRefsToClient:t.command===`snapshot`&&t.internal?.observationOnly!==!0}))}})})}function ne(e){let{current:t,sessionName:n,device:r,record:i,refScopedSnapshot:a}=e,o=ie(t,i,a),s=k({session:t,sessionName:n,device:r,snapshot:o?t.snapshot:i.snapshot,appBundleId:i.appBundleId});return b(s,{scopeSource:oe({current:t,keepCurrentSnapshot:o,refScopedSnapshot:a}),keptCurrentSnapshot:o,previousGeneration:t?.snapshotGeneration}),ae(s,o,e.issuesRefsToClient),i.appName&&(s.appName=i.appName),s}function re(e){return e.flags?.snapshotScope?.trim().startsWith(`@`)===!0}function ie(e,t,n){return n&&t.snapshot?.nodes.length===0&&e?.snapshot!==void 0}function ae(e,t,n){!t&&n&&y(e)}function oe(e){let{current:t,keepCurrentSnapshot:n,refScopedSnapshot:r}=e;if(r)return n?t?.snapshotScopeSource:t?.snapshotScopeSource??t?.snapshot}function se(e){let{req:t,logPath:i,session:o,device:s,snapshotScope:c}=e;return{platform:a(s),captureSnapshot:async(a,l)=>{let u=await S({device:s,session:o,flags:t.flags,outPath:l?.outPath??t.flags?.out,logPath:i,snapshotScope:c,signal:a.signal}),d=r(u);e.capturedQuality.value=d.quality;let f=n(o);return{snapshot:u.snapshot,...d,...f?{snapshotDiagnostics:f}:{},appName:o?.appBundleId?o.appName??o.appBundleId:void 0,appBundleId:o?.appBundleId}}}}function ce(e){let t=e.sessionStore.get(e.sessionName);t&&e.sessionStore.recordAction(t,{command:e.req.command,positionals:e.req.positionals??[],flags:e.req.flags??{},result:ue(e.result),interactiveObservation:c(e.req)})}function le(e){if(!e.snapshot)throw new t(`UNKNOWN`,`snapshot runtime did not produce session state`);return e}function ue(e){return e.kind===`snapshot`?{nodes:e.nodes,truncated:e.truncated}:{mode:e.mode,baselineInitialized:e.baselineInitialized,summary:e.summary}}export{P as a,F as i,J as n,I as r,X as t};
1
+ import{C as e,_ as t}from"./sdk-contracts.js";import{f as n,g as r}from"./location-coordinates.js";import{Nt as i}from"./sdk-batch-runner.js";import{_ as a,c as o}from"./sdk-device.js";import{j as s}from"./screenshot-result.js";import{t as c}from"./verdict.js";import{o as l,t as u}from"./runtime.js";import{A as d}from"./sdk-android-adb.js";import{n as f}from"./shell-quote.js";import{i as p}from"./cancel.js";import{o as m}from"./interactors.js";import{a as h,s as g,t as _}from"./dispatch.js";import{Et as ee,Gt as v,Mt as y,Rt as b,St as x,Tt as S,jt as C,p as w,zt as T}from"./internal/daemon.js";import{a as E,i as D,r as O,t as k}from"./snapshot-session.js";import{a as A}from"./platform-runtime-open-target.js";import j from"node:path";import{promises as M}from"node:fs";import N from"node:os";async function P(t){if(t.command!==`snapshot`||t.device.platform!==`android`)return;let n=e(t.error);if(R(n))return{ok:!1,error:{...n,details:{...n.details??{},androidSnapshotTimeoutScreenshot:await F(t)}}}}async function F(t){try{let e=await M.mkdtemp(j.join(N.tmpdir(),`agent-device-android-snapshot-timeout-`)),n=j.join(e,`snapshot-timeout-overlay-refs.png`),r=L(await _(t.device,`screenshot`,[n],void 0,{...v(t.logPath,{screenshotNoStabilize:!0},t.session?.appBundleId,t.session?.trace?.outPath),surface:t.session?.surface}),n);await M.access(r);let i=await I(r,t.session);return d({level:`warn`,phase:`android_snapshot_timeout_screenshot_captured`,data:{path:r,overlayRefCount:`overlayRefCount`in i?i.overlayRefCount:void 0,overlayRefsAnnotated:`overlayRefsAnnotated`in i?i.overlayRefsAnnotated:void 0}}),i}catch(t){let n=e(t);return d({level:`warn`,phase:`android_snapshot_timeout_screenshot_failed`,data:{error:n.message}}),{captureFailed:!0,error:n.message}}}async function I(t,n){if(!n?.snapshot)return{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:`unavailable`,overlayRefCount:0};try{let e=await x({screenshotPath:t,snapshot:n.snapshot});return{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:e.length>0,overlayRefCount:e.length,overlayRefSource:`session-snapshot`,overlayRefs:e}}catch(n){let r=e(n);return d({level:`warn`,phase:`android_snapshot_timeout_screenshot_overlay_failed`,data:{path:t,error:r.message}}),{path:t,overlayRefsRequested:!0,overlayRefsAnnotated:!1,overlayRefSource:`session-snapshot`,overlayRefCount:0,overlayAnnotationError:r.message}}}function L(e,t){return te(e)?e.path:t}function te(e){return typeof e==`object`&&!!e&&`path`in e&&typeof e.path==`string`}function R(e){return e.code===`COMMAND_FAILED`?z(e)||B(e.details?.helper):!1}function z(e){let t=`${e.message}\n${e.hint??``}`;return/Android accessibility snapshots can be blocked/i.test(t)}function B(e){if(!e||typeof e!=`object`)return!1;let t=e,n=String(t.errorType??``),r=String(t.message??``);return/TimeoutException/i.test(n)||/timed out/i.test(r)}async function V(e){if(!o(e)||e.kind!==`simulator`)return;let t=await A({simulatorSetPath:e.simulatorSetPath});if(!t)return;let n=H(t.device,t.app.bundleId),r=`One booted device found ("${t.device.name}", udid ${t.device.id}) with ${t.app.bundleId} running. Run: ${n}`;return r.length<=350?r:void 0}function H(e,t){let n=e.simulatorSetPath?` --ios-simulator-device-set ${f(e.simulatorSetPath)}`:``;return`agent-device open ${t} --platform ios --udid ${e.id}${n}`}function U(e){let{verdict:t,appBundleId:n,latch:r}=e;return t?t.state===`healthy`?{latch:void 0}:t.state!==`recovered`||t.reasonCode===`requested-backend`?{latch:r}:t.reasonCode===`deferred`?r!==void 0&&r.appBundleId===n?{latch:r}:{warning:l(t.backend),latch:{appBundleId:n}}:{latch:{appBundleId:n}}:{latch:r}}function W(e){let{session:t,data:n,verdict:r,internalObservation:i}=e;if(i||!t)return n;let a=U({verdict:r,appBundleId:t.appBundleId,latch:t.recoveredSnapshotWarningLatch});if(t.recoveredSnapshotWarningLatch=a.latch,!a.warning)return n;let o=Array.isArray(n.warnings)?n.warnings:[];return{...n,warnings:[a.warning,...o]}}async function G(e){let t=e.session;if(!t||!c(e.verdict)||e.req.internal?.observationOnly===!0)return;let n=await K({...e,session:t});if(n!==void 0)return{path:n,artifact:{field:`fallbackScreenshotPath`,artifactType:`screenshot`,path:n,fileName:`snapshot-fallback.png`}}}async function K(e){let{req:t,session:n}=e;try{let r=await S({session:n,sessionName:e.sessionName,outputPlacement:`default`,dispatchContext:v(e.logPath,t.flags,n.appBundleId,n.trace?.outPath,t.meta?.requestId,t.meta)});return typeof r.path==`string`?r.path:void 0}catch{return}}async function q(e){return await X({...e,command:`snapshot`,unsupportedMessage:`snapshot is not supported on this device`,execute:async({runtime:t,sessionName:n,req:r,snapshotScope:a})=>{let o=await t.capture.snapshot({session:n,interactiveOnly:r.flags?.snapshotInteractiveOnly,depth:r.flags?.snapshotDepth,scope:a,raw:r.flags?.snapshotRaw,customActions:r.flags?.snapshotCustomActions,forceFull:r.flags?.snapshotForceFull}),s=e.sessionStore.get(n),c=J(r,s),l=i(o.nodes),u=l===o.nodes?o:{...o,nodes:l},d=await G({req:r,session:s,sessionName:n,logPath:e.logPath,verdict:o.snapshotQuality}),f=d?{...u,fallbackScreenshotPath:d.path,artifacts:[d.artifact]}:u;return{data:c===void 0?f:{...f,refsGeneration:c},record:{kind:`snapshot`,nodes:o.nodes.length,truncated:o.truncated}}}})}function J(e,t){return e.internal?.observationOnly===!0?void 0:t?.snapshotGeneration}async function Y(e){return await X({...e,command:`diff`,unsupportedMessage:`diff is not supported on this device`,execute:async({runtime:e,sessionName:t,req:n,snapshotScope:r})=>{let i=await e.capture.diffSnapshot({session:t,interactiveOnly:n.flags?.snapshotInteractiveOnly,depth:n.flags?.snapshotDepth,scope:r,raw:n.flags?.snapshotRaw});return{data:i,record:{kind:`diff`,mode:`snapshot`,baselineInitialized:i.baselineInitialized,summary:i.summary}}}})}async function X(e){let{req:t,sessionName:n,logPath:r,sessionStore:i}=e,{session:a,device:o}=await O(i,n,t.flags),s=g(e.command,o,{message:e.unsupportedMessage});if(s)return s;let c=T(t.flags?.snapshotScope,a);return c.ok?Z(t,o)||await Q(e.command,a,o)||await D(a,o,async()=>{let s={},l=ne({req:t,sessionName:n,logPath:r,sessionStore:i,session:a,device:o,snapshotScope:c.scope,capturedQuality:s}),u;try{u=await e.execute({runtime:l,sessionName:n,req:t,snapshotScope:c.scope})}catch(t){let n=await P({error:t,command:e.command,logPath:r,session:a,device:o});if(!n)throw t;return n}return ce({req:t,sessionName:n,sessionStore:i,result:u.record}),{ok:!0,data:W({session:i.get(n),data:u.data,verdict:s.value,internalObservation:t.internal?.observationOnly===!0})}}):c}function Z(e,t){return e.flags?.snapshotCustomActions!==!0||w(t)?null:h(`UNSUPPORTED_OPERATION`,`--actions requires an iOS simulator: custom actions are read through the private accessibility snapshot backend, which ${t.platform}/${t.kind} targets do not have.`,{hint:`Re-run without --actions, or target an iOS simulator.`})}async function Q(e,t,n){if(!o(n)||t?.appBundleId||m(n))return null;let r=await V(n);return h(`SESSION_NOT_FOUND`,`iOS ${e} requires an active app session on the target device. Run open first (for example: open --session ${t?.name??`sim`} --platform ios --device "<name>" <app>).`,{reason:`ios_app_session_required`,...r?{hint:r}:{}})}function ne(e){let{req:t,sessionName:n,logPath:r,sessionStore:i,session:a,device:o,snapshotScope:s}=e;return u({backend:se({req:t,logPath:r,session:a,device:o,snapshotScope:s,capturedQuality:e.capturedQuality}),...E(`snapshot`),signal:p(t.meta?.requestId),sessions:ee({sessionName:n,getSession:()=>i.get(n),recordOptions:{includeSnapshot:!0},setRecord:e=>{let r=le(e),a=i.get(n);i.set(n,re({current:a,sessionName:n,device:o,record:r,refScopedSnapshot:ie(t),issuesRefsToClient:t.command===`snapshot`&&t.internal?.observationOnly!==!0}))}})})}function re(e){let{current:t,sessionName:n,device:r,record:i,refScopedSnapshot:a}=e,o=ae(t,i,a),s=k({session:t,sessionName:n,device:r,snapshot:o?t.snapshot:i.snapshot,appBundleId:i.appBundleId});return C(s,{scopeSource:$({current:t,keepCurrentSnapshot:o,refScopedSnapshot:a}),keptCurrentSnapshot:o,previousGeneration:t?.snapshotGeneration}),oe(s,o,e.issuesRefsToClient),i.appName&&(s.appName=i.appName),s}function ie(e){return e.flags?.snapshotScope?.trim().startsWith(`@`)===!0}function ae(e,t,n){return n&&t.snapshot?.nodes.length===0&&e?.snapshot!==void 0}function oe(e,t,n){!t&&n&&y(e)}function $(e){let{current:t,keepCurrentSnapshot:n,refScopedSnapshot:r}=e;if(r)return n?t?.snapshotScopeSource:t?.snapshotScopeSource??t?.snapshot}function se(e){let{req:t,logPath:i,session:o,device:s,snapshotScope:c}=e;return{platform:a(s),captureSnapshot:async(a,l)=>{let u=await b({device:s,session:o,flags:t.flags,outPath:l?.outPath??t.flags?.out,logPath:i,snapshotScope:c,signal:a.signal}),d=r(u);e.capturedQuality.value=d.quality;let f=n(o);return{snapshot:u.snapshot,...d,...f?{snapshotDiagnostics:f}:{},appName:o?.appBundleId?o.appName??o.appBundleId:void 0,appBundleId:o?.appBundleId}}}}function ce(e){let t=e.sessionStore.get(e.sessionName);t&&e.sessionStore.recordAction(t,{command:e.req.command,positionals:e.req.positionals??[],flags:e.req.flags??{},result:ue(e.result),interactiveObservation:s(e.req)})}function le(e){if(!e.snapshot)throw new t(`UNKNOWN`,`snapshot runtime did not produce session state`);return e}function ue(e){return e.kind===`snapshot`?{nodes:e.nodes,truncated:e.truncated}:{mode:e.mode,baselineInitialized:e.baselineInitialized,summary:e.summary}}export{q as n,Y as t};
@@ -1 +1 @@
1
- import{_ as e}from"./sdk-contracts.js";import{s as t}from"./sdk-batch-runner.js";import{c as n}from"./sdk-device.js";import"./screenshot-result.js";import{n as r}from"./runtime.js";import{j as i}from"./sdk-android-adb.js";import{E as a,g as o}from"./dispatch.js";import{w as s}from"./physical-device-control.js";import{fn as c,ot as l,pt as u}from"./internal/daemon.js";import{a as d}from"./apps.js";import{t as f}from"./device-ready.js";function p(t,n={}){let r=n.plural===!0?`do`:`does`;return{resolveInput:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not resolve input artifacts`)},reserveOutput:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not reserve output artifacts`)},createTempFile:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not create temporary files`)}}}function m(e,t={}){return{artifacts:p(e,t),policy:r()}}function h(e){let{req:t,logPath:n,traceLogPath:r}=e;return{verbose:t.flags?.verbose,logPath:n,traceLogPath:r,requestId:t.meta?.requestId,iosXctestrunFile:t.flags?.iosXctestrunFile,iosXctestDerivedDataPath:t.flags?.iosXctestDerivedDataPath,iosXctestEnvDir:t.flags?.iosXctestEnvDir}}function g(e){let{req:t,logPath:n,appBundleId:r,traceLogPath:i}=e;return{...h({req:t,logPath:n,traceLogPath:i}),runnerLeaseContext:c(n,t.flags,r,i,t.meta?.requestId,t.meta).runnerLeaseContext}}function _(e){let{req:t,logPath:r,device:i,traceLogPath:o,enabled:s}=e;if(!(!s||!n(i)||a(i)||i.kind!==`simulator`))return e=>l(e,h({req:t,logPath:r,traceLogPath:o}))}function v(e){let{req:n,logPath:r,device:i,surface:a,openTarget:o,traceLogPath:s}=e;return _({req:n,logPath:r,device:i,traceLogPath:s,enabled:a===`app`&&!!o&&!t(o??``)})}async function y(e,t,n){let r=e.get(t),i=r?.device??await o(n??{});return r||await f(i),{session:r,device:i}}async function b(e,t,r){let i=!e&&n(t);try{return await r()}finally{i&&(await u(t.id),await x(t))}}async function x(e){let t=s();await d(e,t).catch(n=>{i({level:`debug`,phase:`ios_sessionless_runner_host_close_failed`,data:{deviceId:e.id,bundleId:t,error:n instanceof Error?n.message:String(n)}})})}function S(e,t,n,r){t&&e.recordAction(t,{command:n.command,positionals:n.positionals??[],flags:n.flags??{},result:r})}function C(e){let{session:t,sessionName:n,device:r,snapshot:i,appBundleId:a}=e;return t?{...t,snapshot:i,lastComparisonSafeSnapshot:i?.comparisonSafe===!0?i:t.lastComparisonSafeSnapshot}:{name:n,device:r,createdAt:Date.now(),appBundleId:a,snapshot:i,...i?.comparisonSafe===!0?{lastComparisonSafeSnapshot:i}:{},actions:[]}}export{h as a,_ as c,b as i,m as l,S as n,g as o,y as r,v as s,C as t};
1
+ import{_ as e}from"./sdk-contracts.js";import{c as t}from"./sdk-device.js";import"./screenshot-result.js";import{n}from"./runtime.js";import{A as r}from"./sdk-android-adb.js";import{p as i}from"./dispatch.js";import{p as a}from"./physical-device-control.js";import{s as o}from"./runner-client.js";import{a as s}from"./apps.js";import{t as c}from"./device-ready.js";function l(t,n={}){let r=n.plural===!0?`do`:`does`;return{resolveInput:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not resolve input artifacts`)},reserveOutput:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not reserve output artifacts`)},createTempFile:async()=>{throw new e(`UNSUPPORTED_OPERATION`,`${t} ${r} not create temporary files`)}}}function u(e,t={}){return{artifacts:l(e,t),policy:n()}}async function d(e,t,n){let r=e.get(t),a=r?.device??await i(n??{});return r||await c(a),{session:r,device:a}}async function f(e,n,r){let i=!e&&t(n);try{return await r()}finally{i&&(await o(n.id),await p(n))}}async function p(e){let t=a();await s(e,t).catch(n=>{r({level:`debug`,phase:`ios_sessionless_runner_host_close_failed`,data:{deviceId:e.id,bundleId:t,error:n instanceof Error?n.message:String(n)}})})}function m(e,t,n,r){t&&e.recordAction(t,{command:n.command,positionals:n.positionals??[],flags:n.flags??{},result:r})}function h(e){let{session:t,sessionName:n,device:r,snapshot:i,appBundleId:a}=e;return t?{...t,snapshot:i,lastComparisonSafeSnapshot:i?.comparisonSafe===!0?i:t.lastComparisonSafeSnapshot}:{name:n,device:r,createdAt:Date.now(),appBundleId:a,snapshot:i,...i?.comparisonSafe===!0?{lastComparisonSafeSnapshot:i}:{},actions:[]}}export{u as a,f as i,m as n,d as r,h as t};
@@ -1 +1,8 @@
1
- import{o as e}from"./png-worker-contract.js";import{_ as t}from"./sdk-contracts.js";import{j as n}from"./sdk-android-adb.js";import{n as r,t as i}from"./tool-provider2.js";import a from"node:path";import o from"node:fs";import{fileURLToPath as s}from"node:url";const c={"push button":`Button`,"toggle button":`Button`,"push button menu":`Button`,label:`StaticText`,static:`StaticText`,caption:`StaticText`,text:`TextField`,entry:`TextField`,"password text":`TextField`,"spin button":`TextField`,terminal:`TextArea`,"document text":`TextArea`,paragraph:`TextArea`,frame:`Window`,window:`Window`,dialog:`Dialog`,alert:`Alert`,"file chooser":`Dialog`,"color chooser":`Dialog`,"font chooser":`Dialog`,panel:`Group`,filler:`Group`,section:`Group`,form:`Group`,grouping:`Group`,"layered pane":`Group`,"glass pane":`Group`,"root pane":`Group`,"option pane":`Group`,"internal frame":`Group`,"desktop frame":`Group`,"block quote":`Group`,article:`Group`,comment:`Group`,landmark:`Group`,log:`Group`,marquee:`Group`,math:`Group`,notification:`Group`,"content deletion":`Group`,"content insertion":`Group`,mark:`Group`,suggestion:`Group`,"scroll pane":`ScrollArea`,"scroll bar":`ScrollBar`,"menu bar":`MenuBar`,menu:`Menu`,"popup menu":`Menu`,"menu item":`MenuItem`,"check menu item":`MenuItem`,"radio menu item":`MenuItem`,"tearoff menu item":`MenuItem`,"check box":`CheckBox`,"radio button":`RadioButton`,switch:`Switch`,"combo box":`ComboBox`,"page tab":`Tab`,"page tab list":`TabList`,table:`Table`,"tree table":`Table`,"table cell":`Cell`,"table row":`Row`,"table column header":`Cell`,"table row header":`Cell`,"column header":`Cell`,"row header":`Cell`,list:`List`,"list item":`ListItem`,"list box":`List`,tree:`Tree`,"tree item":`TreeItem`,"description list":`List`,"description term":`ListItem`,"description value":`ListItem`,"tool bar":`Toolbar`,"status bar":`StatusBar`,"info bar":`StatusBar`,slider:`Slider`,"progress bar":`ProgressBar`,"level bar":`ProgressBar`,image:`Image`,icon:`Image`,animation:`Image`,canvas:`Image`,"drawing area":`Image`,video:`Video`,audio:`Audio`,link:`Link`,hyperlink:`Link`,separator:`Separator`,application:`Application`,"tool tip":`Tooltip`,timer:`Timer`,heading:`Heading`,footnote:`Footnote`,"title bar":`TitleBar`,"date editor":`DateEditor`,rating:`Slider`};function l(e){let t=e.toLowerCase().trim();return c[t]||t.split(/[\s_-]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``)}const u=`atspi-dump.py`;let d=null;function f(){if(d)return d;let e=a.dirname(s(import.meta.url));for(let t=0;t<6;t++){let t=a.join(e,`linux`,u);if(o.existsSync(t))return d=t,t;e=a.dirname(e)}throw new t(`TOOL_MISSING`,`Cannot find ${u}. Ensure the agent-device package is installed correctly.`)}async function p(e,n={}){let a=i().accessibility;if(a)return await a.captureTree(e,n);if(process.platform!==`linux`)throw new t(`UNSUPPORTED_PLATFORM`,`AT-SPI2 bridge is only available on Linux`);if(!await i().whichCommand(`python3`))throw new t(`TOOL_MISSING`,`python3 is required for AT-SPI2 accessibility snapshots on Linux.`);let o=n.maxNodes??1500,s=n.maxDepth??12,c=n.maxApps??24,u=await r(`python3`,[f(),`--surface`,e,`--max-nodes`,String(o),`--max-depth`,String(s),`--max-apps`,String(c)],{allowFailure:!0,timeoutMs:3e4,signal:n.signal});if(u.exitCode!==0){let e=u.stderr.trim();throw e.includes(`No module named`)||e.includes(`gi.require_version`)?new t(`TOOL_MISSING`,`AT-SPI2 Python bindings not found. Install python3-gi and gir1.2-atspi-2.0.`,{cause:e}):new t(`COMMAND_FAILED`,`AT-SPI2 snapshot failed (exit ${u.exitCode}): ${e||u.stdout}`)}let d;try{d=JSON.parse(u.stdout)}catch{throw new t(`COMMAND_FAILED`,`AT-SPI2 snapshot returned invalid JSON: ${u.stdout.slice(0,200)}`)}if(d.error)throw new t(`COMMAND_FAILED`,`AT-SPI2: ${d.error}`);return{nodes:(d.nodes??[]).map(e=>({index:e.index,type:l(e.role),role:e.role,label:e.label??void 0,value:e.value??void 0,rect:e.rect??void 0,enabled:e.enabled??void 0,selected:e.selected??void 0,hittable:e.hittable??void 0,depth:e.depth,parentIndex:e.parentIndex??void 0,pid:e.pid??void 0,appName:e.appName??void 0,windowTitle:e.windowTitle??void 0})),truncated:d.truncated,surface:e}}var m=e({readLinuxTextAtPoint:()=>_,snapshotLinux:()=>g});function h(e){return e===`desktop`?`desktop`:e===`frontmost-app`||e===`app`?`frontmost-app`:(e===`menubar`&&n({level:`warn`,phase:`linux_snapshot`,data:{message:`menubar surface is not supported on Linux, falling back to desktop`}}),`desktop`)}async function g(e,t){let n=await p(h(e),{signal:t});return{nodes:n.nodes,truncated:n.truncated}}async function _(e,t,n){let{nodes:r}=await g(n),i=r.filter(n=>{let r=n.rect;return r?e>=r.x&&t>=r.y&&e<=r.x+r.width&&t<=r.y+r.height:!1}).sort((e,t)=>{let n=e.depth??0,r=t.depth??0;return n===r?v(e.rect)-v(t.rect):r-n});for(let e of i){let t=y(e);if(t.trim())return t}return``}function v(e){return(e?.width??0)*(e?.height??0)}function y(e){for(let t of[e.value,e.label,e.identifier])if(typeof t==`string`&&t.length>0)return t;return``}export{m as n,g as t};
1
+ import{C as e,E as t,_ as n,c as r,u as i,v as a}from"./sdk-contracts.js";import{Mt as o,Rt as s,br as c,jt as l}from"./sdk-batch-runner.js";import{a as u,t as d}from"./screenshot-geometry.js";import{A as f,F as p,f as ee,i as te,n as ne,s as m}from"./sdk-android-adb.js";import{n as re,t as ie}from"./version.js";import{t as ae}from"./timeouts.js";import"./app-lifecycle.js";import{t as oe}from"./bounds.js";import{t as se}from"./entities.js";import{a as ce,d as h,i as le,o as ue,s as de,t as fe,u as g}from"./helper-package-install.js";import _ from"node:path";import v from"node:fs/promises";import pe from"node:net";function me(){let e=[],t=()=>e[e.length-1]===!0;return{open(n,r){let i=t()||o(n);return r||e.push(i),i},close(){e.pop()}}}function*he(e){let t=/<node\b[^>]*>|<\/node>/g,n=me(),r=t.exec(e);for(;r;){let i=r[0];if(i.startsWith(`</node`))n.close();else{let e=ge(i);yield n.open(e.resourceId,i.endsWith(`/>`))?{...e,systemChrome:!0}:e}r=t.exec(e)}}function ge(e){let t=Se(e),n=oe(t.bounds);return{...t,...n?{rect:n}:{}}}function _e(e,t,n){let{sourceNodes:r,...i}=y(S(e),t,n);return i}function y(e,t,n){let r={nodes:[],sourceNodes:[],...t===void 0?{}:{maxNodes:t},maxDepth:n.depth??1/0,options:n,analysis:ut(e),interactiveDescendantMemo:new Map,truncated:!1},i=n.scope?lt(e,n.scope):null,a=i?[i]:e.children;for(let e of a)if(ve(r,e,0),r.truncated)break;let o={nodes:r.nodes,sourceNodes:r.sourceNodes,analysis:r.analysis};return r.truncated?{...o,truncated:!0}:o}function ve(e,t,n,r,i=!1,a=!1,s=!1){if(e.maxNodes!==void 0&&e.nodes.length>=e.maxNodes){e.truncated=!0;return}if(n>e.maxDepth)return;let c=e.options.raw?!0:et(t,e.options,i,xe(e,t),a),l=s||o(t.identifier),u=c?ye(e,t,r,l):r,d=i||C(t),f=a||ot(t.type);for(let r of t.children)if(ve(e,r,n+1,u,d,f,l),e.truncated)return}function ye(e,t,n,r){let i=e.nodes.length;return e.sourceNodes.push(t),e.nodes.push({index:i,type:t.type??void 0,label:t.label??void 0,value:t.value??void 0,identifier:t.identifier??void 0,bundleId:t.packageName??void 0,rect:t.rect,enabled:t.enabled,focused:t.focused,visibleToUser:t.visibleToUser,hittable:C(t)||void 0,depth:be(e.nodes,n),parentIndex:n,...t.hiddenContentAbove?{hiddenContentAbove:!0}:{},...t.hiddenContentBelow?{hiddenContentBelow:!0}:{},...r?{systemChrome:!0}:{}}),i}function be(e,t){return t===void 0?0:(e[t]?.depth??-1)+1}function xe(e,t){let n=e.interactiveDescendantMemo.get(t);if(n!==void 0)return n;for(let n of t.children)if(n.visibleToUser!==!1&&(C(n)||xe(e,n)))return e.interactiveDescendantMemo.set(t,!0),!0;return e.interactiveDescendantMemo.set(t,!1),!1}function Se(e){let t=Ce(e),n=e=>ke(t,e),r=e=>{let t=n(e);if(t!==null)return t===`true`},i=e=>{let t=n(e);if(t===null||t.trim()===``)return;let r=Number(t);return Number.isFinite(r)?r:void 0},a=(e,t)=>{let n=i(t);return n===void 0?{}:{[e]:n}},o=(e,t)=>{let r=oe(n(t));return r===void 0?{}:{[e]:r}},s=(e,t)=>{let n=r(t);return n===void 0?{}:{[e]:n}};return{text:n(`text`),desc:n(`content-desc`),resourceId:n(`resource-id`),packageName:n(`package`),className:n(`class`),bounds:n(`bounds`),clickable:r(`clickable`),enabled:r(`enabled`),focusable:r(`focusable`),focused:r(`focused`),password:r(`password`),...s(`visibleToUser`,`visible-to-user`),...a(`drawingOrder`,`drawing-order`),...s(`scrollable`,`scrollable`),...s(`canScrollForward`,`can-scroll-forward`),...s(`canScrollBackward`,`can-scroll-backward`),...a(`windowIndex`,`window-index`),...a(`windowType`,`window-type`),...a(`windowLayer`,`window-layer`),...s(`windowActive`,`window-active`),...s(`windowFocused`,`window-focused`),...o(`windowRect`,`window-bounds`)}}function Ce(e){let t=new Map,n=e.indexOf(` `),r=e.lastIndexOf(`>`);if(n<0||r<=n)return t;let i=n;for(;i<r;){let n=we(e,i,r);if(!n)break;t.set(n.name,n.value),i=n.nextCursor}return t}function we(e,t,n){if(t=b(e,t,n),t>=n||Ee(e[t]))return;let r=t;t=Te(e,t,n);let i=e.slice(r,t);if(t=b(e,t,n),!i||e[t]!==`=`)return;t=b(e,t+1,n);let a=e[t];if(!De(a))return;let o=t+1,s=e.indexOf(a,o);if(!(s<0||s>=n))return{name:i,value:se(e.slice(o,s)),nextCursor:s+1}}function Te(e,t,n){for(;t<n&&!Oe(e[t]??``);)t+=1;return t}function b(e,t,n){for(;t<n&&x(e[t]??``);)t+=1;return t}function Ee(e){return e===`/`||e===`>`}function De(e){return e===`"`||e===`'`}function x(e){return e===` `||e===`
2
+ `||e===`\r`||e===` `}function Oe(e){return e===`=`||e===`/`||e===`>`||x(e)}function ke(e,t){return e.get(t)??null}function S(e){let t={type:null,label:null,value:null,identifier:null,packageName:null,clickable:!1,focusable:!1,depth:-1,children:[]},n=[t],r=/<node\b[^>]*>|<\/node>/g,i=r.exec(e);for(;i;){let t=i[0];if(t.startsWith(`</node`)){n.length>1&&n.pop(),i=r.exec(e);continue}let a=ge(t),o=n[n.length-1],s={type:a.className,label:a.text||a.desc,value:a.text,identifier:a.resourceId,packageName:a.packageName,rect:a.rect,enabled:a.enabled,focused:a.focused,visibleToUser:a.visibleToUser,drawingOrder:a.drawingOrder,clickable:a.clickable===!0,focusable:a.focusable===!0,scrollable:a.scrollable,canScrollForward:a.canScrollForward,canScrollBackward:a.canScrollBackward,windowIndex:a.windowIndex,windowType:a.windowType,windowLayer:a.windowLayer,windowActive:a.windowActive,windowFocused:a.windowFocused,windowRect:a.windowRect,depth:o.depth+1,parentIndex:void 0,children:[]};o.children.push(s),t.endsWith(`/>`)||n.push(s),i=r.exec(e)}return Ie(t),qe(t),Le(t,{actionableContentMemo:new WeakMap}),Ke(t),t}function Ae(e){return e.clickable}function je(e){return e.focusable||e.focused===!0}function C(e){return Ae(e)||je(e)}function Me(e){return Ue(e)||Be(e)}function Ne(e){return e.visibleToUser!==!1&&(Ae(e)||Me(e))}function Pe(e,t){let n=t.actionableContentMemo.get(e);if(n!==void 0)return n;let r=e.children.some(e=>e.visibleToUser!==!1&&(C(e)||Pe(e,t)));return t.actionableContentMemo.set(e,r),r}function Fe(e){return e.children.length===0&&!C(e)&&Me(e)}function Ie(e){let t=0;for(let n of e.children)n.visibleToUser!==!1&&(Ie(n),e.children[t]=n,t+=1);t<e.children.length&&(e.children.length=t)}function Le(e,t){for(let n of e.children)Le(n,t);if(e.children.length<2)return;let n=e.children,r=n.filter(e=>Ve(e,t));r.length!==0&&(e.children=n.filter(e=>Re(e,r)))}function Re(e,t){return Fe(e)||!ze(e,t)}function ze(e,t){if(e.visibleToUser===!1||e.drawingOrder===void 0||!We(e))return!1;for(let n of t)if(!(n===e||n.drawingOrder<=e.drawingOrder)&&Ge(n.rect,e.rect)>=.9)return!0;return!1}function Be(e){let t=e.identifier?.trim()??``;return!!(t&&!w(t))}function Ve(e,t){return e.visibleToUser!==!1&&e.drawingOrder!==void 0&&We(e)&&He(e,t)}function He(e,t){return Ne(e)||Pe(e,t)}function Ue(e){let t=e.label?.trim()??``;return!!(t&&!w(t))}function We(e){return!!(e.rect&&e.rect.width>0&&e.rect.height>0)}function Ge(e,t){let n=t.width*t.height;return n<=0?0:d(e,t)/n}function Ke(e){let t=[...e.children];for(;t.length>0;){let e=t.pop();t.push(...e.children),Qe(e)&&(e.canScrollBackward&&(e.hiddenContentAbove=!0),e.canScrollForward&&(e.hiddenContentBelow=!0))}}function qe(e){let t=e.children.filter(Ye);if(t.length<2)return;let n=t.filter(e=>Xe(e)&&Ze(e));if(n.length===0)return;let r=Je(n);e.children=e.children.filter(e=>Xe(e)?Ze(e)?r===void 0||e.windowLayer===r:!1:!0)}function Je(e){let t=e.map(e=>e.windowLayer).filter(e=>e!==void 0);return t.length>0?Math.max(...t):void 0}function Ye(e){return e.windowIndex!==void 0||e.windowType!==void 0}function Xe(e){return e.windowType===1}function Ze(e){return e.windowActive===!0||e.windowFocused===!0}function Qe(e){if(!e.scrollable||!c(e.type)||`${e.type??``}`.toLowerCase().includes(`horizontalscrollview`))return!1;let t=$e(e);return!(t&&t.horizontal>t.vertical&&t.horizontal>16)}function $e(e){if(!e.rect||e.children.length===0)return null;let t=e.children.map(e=>e.rect).filter(e=>e!==void 0);if(t.length===0)return null;let n=Math.min(...t.map(e=>e.x)),r=Math.max(...t.map(e=>e.x+e.width)),i=Math.min(...t.map(e=>e.y)),a=Math.max(...t.map(e=>e.y+e.height));return{horizontal:Math.max(0,r-n-e.rect.width),vertical:Math.max(0,a-i-e.rect.height)}}function et(e,t,n,r,i){if(e.visibleToUser===!1)return!1;let a=tt(e);return t.interactiveOnly?nt(e,a,n,r,i):a.isStructural||a.isVisual?at(e,a,r):!0}function tt(e){let t=st(e.type),n=!!(e.label&&e.label.trim().length>0),r=!!(e.identifier&&e.identifier.trim().length>0);return{type:t,hasMeaningfulText:n&&!w(e.label??``),hasMeaningfulId:r&&!w(e.identifier??``),isStructural:ct(t),isVisual:t===`imageview`||t===`imagebutton`}}function nt(e,t,n,r,i){return it(e)?!1:C(e)||c(t.type)&&r?!0:rt(t,n,r,i)}function rt(e,t,n,r){return!e.hasMeaningfulText&&!e.hasMeaningfulId||e.isVisual||e.isStructural&&!r&&!t?!1:t||n||r}function it(e){return!!(e.rect&&(e.rect.width<=0||e.rect.height<=0))}function at(e,t,n){return C(e)||t.hasMeaningfulText||t.hasMeaningfulId?!0:n}function ot(e){if(!e)return!1;let t=st(e);return t.includes(`recyclerview`)||t.includes(`listview`)||t.includes(`gridview`)}function st(e){return e?e.toLowerCase():``}function ct(e){let t=e.split(`.`).pop()??e;return t.includes(`layout`)||t===`viewgroup`||t===`view`}function w(e){let t=e.trim();return t?/^[\w.]+:id\/[\w.-]+$/i.test(t):!1}function lt(e,t){let n=t.toLowerCase(),r=[...e.children],i=0;for(;i<r.length;){let e=r[i++],t=e.label?.toLowerCase()??``,a=e.value?.toLowerCase()??``,o=e.identifier?.toLowerCase()??``;if(t.includes(n)||a.includes(n)||o.includes(n))return e;r.push(...e.children)}return null}function ut(e){let t=0,n=0,r=[...e.children];for(;r.length>0;){let e=r.pop();t+=1,n=Math.max(n,e.depth),r.push(...e.children)}return{rawNodeCount:t,maxDepth:n}}const T=`android-snapshot-helper-v1`,E=`uiautomator-xml`,dt={"-r":`replace`,"-t":`allowTestPackages`,"-d":`allowDowngrade`,"-g":`grantPermissions`};function ft(e){if(!e||typeof e!=`object`||Array.isArray(e))throw new n(`INVALID_ARGS`,`Android snapshot helper manifest must be an object.`);let t=e;return{name:O(t.name,`name`,`android-snapshot-helper`),version:k(t.version,`version`),releaseTag:A(t.releaseTag),assetName:A(t.assetName),apkUrl:_t(t.apkUrl,`apkUrl`),sha256:gt(t.sha256),checksumName:A(t.checksumName),packageName:k(t.packageName,`packageName`),versionCode:D(t.versionCode,`versionCode`),instrumentationRunner:k(t.instrumentationRunner,`instrumentationRunner`),minSdk:D(t.minSdk,`minSdk`),targetSdk:t.targetSdk===void 0?void 0:D(t.targetSdk,`targetSdk`),outputFormat:O(t.outputFormat,`outputFormat`,E),statusProtocol:O(t.statusProtocol,`statusProtocol`,T),installArgs:mt(t.installArgs)}}function D(e,t){return ue(e,t,`snapshot helper`)}function O(e,t,n){return de(e,t,n,`snapshot helper`)}function pt(e){return ht(mt(e.installArgs))}function mt(e){let t=vt(e,`installArgs`);if(t[0]!==`install`)throw new n(`INVALID_ARGS`,`Android snapshot helper manifest installArgs must start with "install".`);if(t.some(e=>e.includes(`\0`)))throw new n(`INVALID_ARGS`,`Android snapshot helper manifest installArgs must not contain null bytes.`);let r=t.slice(1).find(e=>!yt(e));if(r)throw new n(`INVALID_ARGS`,`Android snapshot helper manifest installArgs contains unsupported install flag "${r}".`);return t}function ht(e){let t={};for(let r of e.slice(1)){let e=bt(r);if(!e)throw new n(`INVALID_ARGS`,`Android snapshot helper manifest installArgs contains unsupported install flag "${r}".`);t[e]=!0}return t}function gt(e){let t=k(e,`sha256`).trim().toLowerCase();if(t.length!==64||!xt(t))throw new n(`INVALID_ARGS`,`Android snapshot helper manifest sha256 must be a 64-character hex string.`);return t}function k(e,t){if(typeof e!=`string`||e.trim().length===0)throw new n(`INVALID_ARGS`,`Android snapshot helper manifest ${t} is required.`);return e}function A(e){return typeof e==`string`&&e.trim().length>0?e:void 0}function _t(e,t){return e===null?null:k(e,t)}function vt(e,t){if(!Array.isArray(e)||!e.every(e=>typeof e==`string`))throw new n(`INVALID_ARGS`,`Android snapshot helper manifest ${t} must be a string array.`);return e}function yt(e){return bt(e)!==void 0}function bt(e){if(Object.hasOwn(dt,e))return dt[e]}function xt(e){for(let t of e){let e=t.charCodeAt(0);if(!(e>=48&&e<=57)&&!(e>=97&&e<=102))return!1}return!0}const j=2e3,M=`android_snapshot_helper_retirement_unconfirmed`,N=new Map;function P(e){return`${e.platform}:${e.id}`}async function St(e){await Ot({adb:e.adb,packageName:e.packageName,timeoutMs:2e3})||I(e)}async function F(e){let t=N.get(e.deviceKey);if(t){try{let n=await e.adb([`shell`,`am`,`force-stop`,t.packageName],{allowFailure:!0,timeoutMs:5e3,signal:e.signal});if(e.signal?.throwIfAborted(),n.exitCode===0){N.delete(e.deviceKey);return}}catch{e.signal?.throwIfAborted()}I({deviceKey:e.deviceKey,packageName:t.packageName,cause:t.cause})}}function I(e){let t=e.cause instanceof Error?e.cause.message:String(e.cause);throw N.set(e.deviceKey,{packageName:e.packageName,cause:t}),new n(`COMMAND_FAILED`,`Android snapshot helper could not confirm release of device automation ownership`,{reason:M,deviceKey:e.deviceKey,cause:t,hint:`Retry after the helper process exits, or restart the device if Android still reports automation as busy.`})}function Ct(e){return e instanceof n&&e.details?.reason===M}async function wt(e){let t=AbortSignal.timeout(e.timeoutMs),[n]=await Promise.allSettled([Ot({adb:e.adb,packageName:e.packageName,timeoutMs:e.timeoutMs,signal:t}),kt({...e,signal:t})]);return{timedOut:t.aborted,runtimeForceStopped:n?.status===`fulfilled`?n.value:!1}}function Tt(e){return e.exitCode!=null||e.signalCode!=null?Promise.resolve():new Promise(t=>{e.once(`close`,()=>t()),e.once(`exit`,()=>t())})}async function L(e,t,n){let r,i,a=await Promise.race([e.then(()=>!0),new Promise(e=>{r=setTimeout(()=>e(!1),t)}),...n?[new Promise(e=>{i=()=>e(!1),n.addEventListener(`abort`,i,{once:!0}),n.aborted&&i()})]:[]]);return r&&clearTimeout(r),i&&n?.removeEventListener(`abort`,i),a}async function Et(e){if(e.alreadyExited)return!0;try{e.process.kill(`SIGTERM`)}catch{}return await L(e.processExit,e.timeoutMs)}function Dt(){N.clear()}async function Ot(e){let t=e.signal??AbortSignal.timeout(e.timeoutMs);try{return(await e.adb([`shell`,`am`,`force-stop`,e.packageName],{allowFailure:!0,timeoutMs:e.timeoutMs,signal:t})).exitCode===0}catch{return!1}}async function kt(e){e.process.stdin?.end(),e.process.stdout?.destroy(),e.process.stderr?.destroy(),await e.adb([`forward`,`--remove`,`tcp:${e.port}`],{allowFailure:!0,timeoutMs:e.timeoutMs,signal:e.signal})}async function At(e){let t=jt(e),r=e.deviceKey??`android:default`;await F({deviceKey:r,adb:e.adb,signal:e.signal});let i;try{i=await e.adb(Mt(t),{allowFailure:!0,timeoutMs:t.commandTimeoutMs,signal:e.signal})}catch(n){throw e.signal?.aborted?(await St({deviceKey:r,packageName:t.packageName,adb:e.adb,cause:n}),e.signal.throwIfAborted(),n):n}e.signal?.aborted&&(await St({deviceKey:r,packageName:t.packageName,adb:e.adb,cause:e.signal.reason}),e.signal.throwIfAborted());let{output:a,cleanupDone:o}=await Nt(e,t,i);if(t.outputPath&&!o&&await Bt(e.adb,t.outputPath),i.exitCode!==0)throw new n(`COMMAND_FAILED`,`Android snapshot helper failed`,ee(i,{helper:a.metadata}));return a}function jt(e){let t=R(e.timeoutMs,8e3),n=R(e.packageName,`com.callstack.agentdevice.snapshothelper`);return{waitForIdleTimeoutMs:R(e.waitForIdleTimeoutMs,500),waitForIdleQuietMs:R(e.waitForIdleQuietMs,100),timeoutMs:t,commandTimeoutMs:R(e.commandTimeoutMs,t+5e3),maxDepth:R(e.maxDepth,128),maxNodes:R(e.maxNodes,5e3),packageName:n,runner:R(e.instrumentationRunner,`${n}/.SnapshotInstrumentation`),...e.outputPath?{outputPath:e.outputPath}:{},...e.emitChunks===void 0?{}:{emitChunks:e.emitChunks}}}function R(e,t){return e===void 0?t:e}function Mt(e){return[`shell`,`am`,`instrument`,`-w`,`-e`,`waitForIdleTimeoutMs`,String(e.waitForIdleTimeoutMs),`-e`,`waitForIdleQuietMs`,String(e.waitForIdleQuietMs),`-e`,`timeoutMs`,String(e.timeoutMs),`-e`,`maxDepth`,String(e.maxDepth),`-e`,`maxNodes`,String(e.maxNodes),...e.outputPath?[`-e`,`outputPath`,e.outputPath]:[],...e.emitChunks===void 0?[]:[`-e`,`emitChunks`,String(e.emitChunks)],e.runner]}async function Nt(e,t,n){try{return{output:Vt(`${n.stdout}\n${n.stderr}`),cleanupDone:!1}}catch(r){return await Pt(e,t,n,r)}}async function Pt(e,t,r,i){if(i instanceof n&&r.exitCode!==0&&i.details?.helper)throw i;let a=await Ft(e,t,r);if(a)return{output:a,cleanupDone:!0};throw new n(`COMMAND_FAILED`,r.exitCode===0?`Android snapshot helper output could not be parsed`:`Android snapshot helper failed before returning parseable output`,{stdout:r.stdout,stderr:r.stderr,exitCode:r.exitCode},i)}async function Ft(e,t,n){if(!(n.exitCode!==0||!t.outputPath))return await Lt(e.adb,t.outputPath,zt(`${n.stdout}\n${n.stderr}`)??It(t))}function It(e){return{outputFormat:E,waitForIdleTimeoutMs:e.waitForIdleTimeoutMs,waitForIdleQuietMs:e.waitForIdleQuietMs,timeoutMs:e.timeoutMs,maxDepth:e.maxDepth,maxNodes:e.maxNodes,transport:`instrumentation`}}async function Lt(e,t,n){let r;try{r=await e(Rt(t),{allowFailure:!0,timeoutMs:5e3})}catch{return}if(r.exitCode!==0)return;let i=r.stdout.trim();if(!(!i.includes(`<hierarchy`)||!i.includes(`</hierarchy>`)))return{xml:i,metadata:n}}function Rt(e){return[`shell`,`sh`,`-c`,`cat "$1"; status=$?; rm -f "$1"; exit "$status"`,`agent-device-snapshot-helper-output`,e]}function zt(e){try{return Yt(Ut(ce(e).results))}catch{return null}}async function Bt(e,t){try{await e([`shell`,`rm`,`-f`,t],{allowFailure:!0,timeoutMs:5e3})}catch{}}function Vt(e){let t=ce(e),n=Ut(t.results);return{xml:Gt(Ht(t.status),n),metadata:{...Yt(n),transport:`instrumentation`}}}function Ht(e){let t=[];for(let n of e){if(n.agentDeviceProtocol!==`android-snapshot-helper-v1`||n.outputFormat!==`uiautomator-xml`)continue;let{payloadBase64:e}=n;e!==void 0&&t.push({index:z(n.chunkIndex),count:z(n.chunkCount),payloadBase64:e})}return t}function Ut(e){let t=e.find(e=>e.agentDeviceProtocol===T);if(!t)throw new n(`COMMAND_FAILED`,`Android snapshot helper did not return a final result`);if(t.ok!==`true`)throw new n(`COMMAND_FAILED`,Wt(t),{errorType:t.errorType,helper:t});return t}function Wt(e){return e.message&&e.message!==`null`?e.message:e.errorType||`Android snapshot helper returned an error`}function Gt(e,t){if(e.length===0)throw new n(`COMMAND_FAILED`,`Android snapshot helper did not return XML chunks`,{helper:t});let r=Kt(e),i=Buffer.concat(Jt(qt(e,r),r)).toString(`utf8`);if(!i.includes(`<hierarchy`)||!i.includes(`</hierarchy>`))throw new n(`COMMAND_FAILED`,`Android snapshot helper output did not contain XML`,{xml:i});return i}function Kt(e){let t=e[0]?.count??e.length;if(t<1||e.length!==t||e.some(e=>e.count!==t))throw new n(`COMMAND_FAILED`,`Android snapshot helper returned incomplete XML chunks`,{expectedChunks:t,actualChunks:e.length});return t}function qt(e,t){let r=new Map;for(let i of e){if(i.index===void 0||i.index<0||i.index>=t)throw new n(`COMMAND_FAILED`,`Android snapshot helper returned invalid chunk index`,{chunkIndex:i.index,expectedChunks:t});if(r.has(i.index))throw new n(`COMMAND_FAILED`,`Android snapshot helper returned duplicate XML chunks`,{chunkIndex:i.index});r.set(i.index,i.payloadBase64)}return r}function Jt(e,t){let r=[];for(let i=0;i<t;i+=1){let a=e.get(i);if(a===void 0)throw new n(`COMMAND_FAILED`,`Android snapshot helper returned incomplete XML chunks`,{missingChunkIndex:i,expectedChunks:t});r.push(Buffer.from(a,`base64`))}return r}function Yt(e){return{helperApiVersion:e.helperApiVersion,outputFormat:E,waitForIdleTimeoutMs:z(e.waitForIdleTimeoutMs),waitForIdleQuietMs:z(e.waitForIdleQuietMs),timeoutMs:z(e.timeoutMs),maxDepth:z(e.maxDepth),maxNodes:z(e.maxNodes),rootPresent:Zt(e.rootPresent),captureMode:Xt(e.captureMode),windowCount:z(e.windowCount),nodeCount:z(e.nodeCount),truncated:Zt(e.truncated),elapsedMs:z(e.elapsedMs)}}function Xt(e){return e===`interactive-windows`||e===`active-window`?e:void 0}const z=h,Zt=g;function Qt(){return new Promise((e,t)=>{let n=pe.createServer();n.unref(),n.on(`error`,t),n.listen(0,`127.0.0.1`,()=>{let r=n.address();if(!r||typeof r==`string`){n.close(()=>t(Error(`Failed to allocate a local TCP port`)));return}let i=r.port;n.close(()=>e(i))})})}function B(e,t,r,i){return new Promise((a,o)=>{let s=pe.connect({host:`127.0.0.1`,port:e}),c=[],l=setTimeout(()=>{u(),s.destroy(),o(new n(`COMMAND_FAILED`,`Android snapshot helper session request timed out`,{command:t,timeoutMs:r,port:e}))},r),u=()=>{clearTimeout(l),i?.removeEventListener(`abort`,d)},d=()=>{u(),s.destroy(),o(i?.reason??new DOMException(`The operation was aborted`,`AbortError`))};if(i?.addEventListener(`abort`,d,{once:!0}),i?.aborted){d();return}s.on(`connect`,()=>s.write(`${t}\n`)),s.on(`data`,e=>c.push(Buffer.from(e))),s.on(`error`,e=>{u(),o(e)}),s.on(`close`,()=>{u(),a(Buffer.concat(c).toString(`utf8`))})})}async function $t(e){let t=`snapshot-${Date.now()}-${Math.random().toString(16).slice(2)}`;return on(await B(e.port,`snapshot ${t}`,en(e),e.signal),t)}function en(e){return Math.min(e.commandTimeoutMs,Math.max(e.timeoutMs+3e3,3e3))}function tn(e,t,r){return new Promise((i,a)=>{let o=``,s=setTimeout(()=>{r?.removeEventListener(`abort`,l),a(new n(`COMMAND_FAILED`,`Android snapshot helper session did not become ready`,{output:o,timeoutMs:t}))},t),c=e=>{o+=e.toString(),o.includes(`agentDeviceProtocol=android-snapshot-helper-v1`)&&o.includes(`sessionReady=true`)&&(clearTimeout(s),r?.removeEventListener(`abort`,l),i())},l=()=>{clearTimeout(s),a(r?.reason??new DOMException(`The operation was aborted`,`AbortError`))};if(r?.addEventListener(`abort`,l,{once:!0}),r?.aborted){l();return}e.stdout?.on(`data`,c),e.stderr?.on(`data`,c),e.once(`exit`,(e,t)=>{clearTimeout(s),r?.removeEventListener(`abort`,l),a(new n(`COMMAND_FAILED`,`Android snapshot helper session exited before ready`,{output:o,exitCode:e,signal:t}))}),e.on(`error`,e=>{clearTimeout(s),r?.removeEventListener(`abort`,l),a(e)})})}function nn(e){let t=e.indexOf(`
3
+
4
+ `);return ln(e.slice(0,t<0?e.length:t))}function rn(e,t){if(e.agentDeviceProtocol!==`android-snapshot-helper-v1`)throw new n(`COMMAND_FAILED`,`Android automation helper session returned wrong protocol`,{headers:e});if(e.requestId!==t)throw new n(`COMMAND_FAILED`,`Android automation helper session returned stale output`,{headers:e,requestId:t})}function an(e,t){let n=nn(e);return n.agentDeviceProtocol===`android-snapshot-helper-v1`&&n.requestId===t&&n.ok===`true`}function on(e,t){let r=e.indexOf(`
5
+
6
+ `);if(r<0)throw new n(`COMMAND_FAILED`,`Android snapshot helper session returned malformed output`,{response:e});let i=ln(e.slice(0,r)),a=e.slice(r+2);return sn(i,t),cn(i,a),{xml:a,metadata:un(i)}}function sn(e,t){if(e.agentDeviceProtocol!==`android-snapshot-helper-v1`)throw new n(`COMMAND_FAILED`,`Android snapshot helper session returned wrong protocol`,{headers:e});if(e.outputFormat!==`uiautomator-xml`)throw new n(`COMMAND_FAILED`,`Android snapshot helper session returned wrong output format`,{headers:e});if(e.requestId!==t)throw new n(`COMMAND_FAILED`,`Android snapshot helper session returned stale output`,{headers:e,requestId:t});if(e.ok!==`true`)throw new n(`COMMAND_FAILED`,e.message||e.errorType||`Android snapshot helper session returned an error`,{helper:e})}function cn(e,t){let r=h(e.byteLength);if(r!==void 0&&Buffer.byteLength(t,`utf8`)!==r)throw new n(`COMMAND_FAILED`,`Android snapshot helper session returned truncated XML`,{headers:e,actualByteLength:Buffer.byteLength(t,`utf8`)});if(!t.includes(`<hierarchy`)||!t.includes(`</hierarchy>`))throw new n(`COMMAND_FAILED`,`Android snapshot helper session did not return XML`,{headers:e,xml:t})}function ln(e){let t={};for(let n of e.split(/\r?\n/)){let e=n.indexOf(`=`);e<0||(t[n.slice(0,e)]=n.slice(e+1))}return t}function un(e){return{helperApiVersion:e.helperApiVersion,outputFormat:E,waitForIdleTimeoutMs:h(e.waitForIdleTimeoutMs),waitForIdleQuietMs:h(e.waitForIdleQuietMs),timeoutMs:h(e.timeoutMs),maxDepth:h(e.maxDepth),maxNodes:h(e.maxNodes),rootPresent:g(e.rootPresent),captureMode:e.captureMode===`interactive-windows`||e.captureMode===`active-window`?e.captureMode:void 0,windowCount:h(e.windowCount),nodeCount:h(e.nodeCount),truncated:g(e.truncated),elapsedMs:h(e.elapsedMs)}}const dn=5e3,V=new Map,H=new Map;async function fn(e){let t=e.deviceKey??`android:default`;if(await F({deviceKey:t,adb:e.adb,signal:e.signal}),!wn()||!e.adbProvider?.spawn)return;let n=hn(jt(e)),r=await pn({deviceKey:t,identity:Cn(t,n,e),options:e,resolved:n});if(r)return await mn({session:r,deviceKey:t,options:e,resolved:n})}async function pn(e){let{deviceKey:t,identity:n,options:r,resolved:i}=e;if(H.get(t)===n)return;let a=V.get(t);if(a&&a.identity!==n&&(await W(t),a=void 0),!a)try{a=await Sn({deviceKey:t,identity:n,options:r,resolved:i})}catch(e){if(r.signal?.throwIfAborted(),H.set(t,n),f({level:`warn`,phase:`android_snapshot_helper_session_disabled`,data:{deviceKey:t,reason:e instanceof Error?e.message:String(e)}}),Ct(e))throw e;return}return a}async function mn(e){let{session:t,deviceKey:n,options:r,resolved:i}=e;try{let e=t.capturedCount>0,n=await $t({port:t.port,timeoutMs:i.timeoutMs,commandTimeoutMs:i.commandTimeoutMs,signal:r.signal});return t.capturedCount+=1,{xml:n.xml,metadata:{...n.metadata,transport:`persistent-session`,sessionReused:e}}}catch(e){await W(n,{force:!0,signal:r.signal,cause:e}),r.signal?.throwIfAborted(),f({level:`warn`,phase:`android_snapshot_helper_session_fallback`,data:{deviceKey:n,reason:e instanceof Error?e.message:String(e),uiAutomationConnectionTimeout:gn(e)}});return}}function hn(e){let t=Math.min(e.timeoutMs,2e3);return{...e,timeoutMs:t,commandTimeoutMs:Math.min(e.commandTimeoutMs,t+3e3)}}function gn(e){if(!(e instanceof n))return!1;let t=e.details?.helper;return!t||typeof t!=`object`?!1:t.errorType===`java.util.concurrent.TimeoutException`}async function _n(e){let t=V.get(e.deviceKey);if(!t)return;if(!vn(t.helper,e.helper)){f({level:`warn`,phase:`android_snapshot_helper_session_touch_identity_mismatch`,data:{deviceKey:e.deviceKey,sessionHelper:t.helper,requestedHelper:e.helper}}),await W(e.deviceKey);return}let r=`${e.action}-${Date.now()}-${Math.random().toString(16).slice(2)}`,i=e.payloadBase64?`${e.action} ${r} ${e.payloadBase64}`:`${e.action} ${r}`,a;try{a=nn(await B(t.port,i,e.timeoutMs)),rn(a,r)}catch(t){throw await W(e.deviceKey),t}if(a.ok!==`true`)throw new n(`COMMAND_FAILED`,a.message||a.errorType||`Android automation helper ${e.action} failed`,{errorType:a.errorType,helper:a});return a}function vn(e,t){return e.packageName===t.packageName&&e.runner===t.runner&&U(e.helperVersion,t.helperVersion)&&U(e.helperVersionCode,t.helperVersionCode)&&U(e.sha256,t.sha256)}function U(e,t){return e===void 0||t===void 0||e===t}async function W(e,t={}){let n=V.get(e);if(!n)return!1;V.delete(e);let r=Tt(n.process),i=t.force===!0||t.signal?.aborted===!0,a=await yn(n,r,i,t.signal),o=i?t.signal?.aborted===!0?250:j:dn,s=i?250:2e3,[c,l]=await Promise.all([Et({process:n.process,processExit:r,alreadyExited:a.exited,timeoutMs:s}),wt({adb:n.adb,process:n.process,port:n.port,packageName:n.helper.packageName,timeoutMs:o})]);return f({phase:`android_snapshot_helper_session_stop`,data:{deviceKey:e,port:n.port,capturedCount:n.capturedCount,lifetimeMs:Date.now()-n.startedAtMs,quitAcknowledged:a.acknowledged,forceKilled:!a.exited&&c,forced:i||t.signal?.aborted===!0,runtimeForceStopped:l.runtimeForceStopped,externalCleanupTimedOut:l.timedOut}}),!a.exited&&!l.runtimeForceStopped&&I({deviceKey:e,packageName:n.helper.packageName,cause:t.cause}),!0}async function yn(e,t,n,r){if(n)return{acknowledged:!1,exited:!1};let i=`quit-${Date.now()}`;try{let n=an(await B(e.port,`quit ${i}`,1e3,r),i);return{acknowledged:n,exited:n&&await L(t,11e3,r)}}catch{return{acknowledged:!1,exited:!1}}}async function bn(e){await W(P(e))}async function xn(){let e=await Promise.allSettled([...V.keys()].map(e=>W(e)));H.clear();let t=e.filter(e=>e.status===`rejected`).map(e=>e.reason);if(t.length>0)throw AggregateError(t,`Failed to retire every Android snapshot helper session`);Dt()}async function Sn(e){let t=await Qt();await e.options.adb([`forward`,`tcp:${t}`,`tcp:${t}`],{allowFailure:!1,timeoutMs:dn,signal:e.options.signal});let r=Mt({...e.resolved,outputPath:void 0,emitChunks:!1}),i=r[r.length-1];if(!i)throw new n(`INVALID_ARGS`,`Android snapshot helper runner was not resolved`);let a=[...r.slice(0,-1),`-e`,`sessionPort`,String(t),i],o=e.options.adbProvider.spawn(a,{allowFailure:!0,captureOutput:!1}),s={identity:e.identity,deviceKey:e.deviceKey,helper:{packageName:e.resolved.packageName,runner:e.resolved.runner,helperVersion:e.options.helperVersion,helperVersionCode:e.options.helperVersionCode,sha256:e.options.helperSha256},port:t,adb:e.options.adb,process:o,startedAtMs:Date.now(),capturedCount:0};try{return await tn(o,1e4,e.options.signal),V.set(e.deviceKey,s),f({phase:`android_snapshot_helper_session_ready`,data:{deviceKey:e.deviceKey,port:t,packageName:e.resolved.packageName,runner:e.resolved.runner}}),s}catch(t){let n=Tt(o);try{o.kill(`SIGTERM`)}catch{}let[,r]=await Promise.all([L(n,250),wt({adb:s.adb,process:s.process,port:s.port,packageName:s.helper.packageName,timeoutMs:j})]);throw r.runtimeForceStopped||I({deviceKey:e.deviceKey,packageName:s.helper.packageName,cause:t}),t}}function Cn(e,t,n){return JSON.stringify({deviceKey:e,packageName:t.packageName,runner:t.runner,helperVersion:n.helperVersion,helperVersionCode:n.helperVersionCode,helperSha256:n.helperSha256,waitForIdleTimeoutMs:t.waitForIdleTimeoutMs,waitForIdleQuietMs:t.waitForIdleQuietMs,timeoutMs:t.timeoutMs,maxDepth:t.maxDepth,maxNodes:t.maxNodes})}function wn(){let e=process.env.AGENT_DEVICE_ANDROID_SNAPSHOT_HELPER_SESSION;return e===void 0||!/^(0|false|no|off)$/i.test(e)}const G=new Map;function Tn(e){let t=`${e.deviceKey}\0${e.packageName}\0${e.versionCode}\0`;for(let e of G.keys())e.startsWith(t)&&K(e)}function En(e,t,n,r){return e?`${e}\0${t}\0${n}\0${r}`:void 0}function Dn(e,t){if(!e)return;let[n,r]=e.split(`\0`),i=`${n}\0${r}\0`;for(let t of G.keys())t!==e&&t.startsWith(i)&&G.delete(t);G.set(e,t)}function K(e){e&&G.delete(e)}async function On(e){let{adb:t,artifact:n}=e,r=e.installPolicy??`missing-or-outdated`,i=n.manifest.packageName,a=n.manifest.versionCode,o=n.manifest.sha256;if(r===`never`)return{packageName:i,versionCode:a,installed:!1,reason:`skipped`};let s=En(e.deviceKey,i,a,o),c=s?G.get(s):void 0;if(s&&r!==`always`&&c!==void 0)return{packageName:i,versionCode:a,installedVersionCode:c,installedSha256:o,installed:!1,reason:`current`};await le(n.apkPath,o,`Android snapshot helper`);let l=r===`always`?{installedVersionCode:await jn(t,i,e.timeoutMs,e.signal),reason:`forced`}:await fe({adb:t,adbProvider:An(e.adbProvider,t),packageName:i,versionCode:a,sha256:o,signal:e.signal}),{installedVersionCode:u}=l,d=`installedSha256`in l?l.installedSha256:void 0,f=l.reason;if(f===`current`){if(u===void 0)throw Error(`Expected installed versionCode for current Android snapshot helper`);return Dn(s,u),{packageName:i,versionCode:a,installedVersionCode:u,installedSha256:d,installed:!1,reason:f}}let p;try{p=await Mn(t,e.adbProvider??t,n.apkPath,pt(n.manifest),{packageName:i,timeoutMs:e.timeoutMs,signal:e.signal})}catch(e){throw K(s),kn(e,{packageName:i,versionCode:a})}if(p.exitCode!==0)throw K(s),kn(ne(`Failed to install Android snapshot helper`,p,{packageName:i,versionCode:a}));return Dn(s,a),{packageName:i,versionCode:a,installedVersionCode:u,installedSha256:d,installed:!0,reason:f}}function kn(e,t){let n=a(e,`COMMAND_FAILED`);return n.details={...t,...n.details,androidSnapshotHelperInstallFailure:!0},n}function An(e,t){return e?typeof e==`function`?{exec:e}:e:{exec:t}}async function jn(e,t,n,r){let i=await e([`shell`,`cmd`,`package`,`list`,`packages`,`--show-versioncode`,t],{allowFailure:!0,timeoutMs:n,signal:r});if(i.exitCode===0)return Nn(`${i.stdout}\n${i.stderr}`,t)}async function Mn(e,t,n,r,i){let a=async()=>await te(n,{allowFailure:!0,provider:t,...r,timeoutMs:i.timeoutMs,signal:i.signal}),o=await a();if(o.exitCode===0||!Pn(o))return o;let s=await e([`uninstall`,i.packageName],{allowFailure:!0,timeoutMs:i.timeoutMs,signal:i.signal}),c=await a();return c.exitCode===0?c:{...c,stderr:[c.stderr,s.stderr?`Previous uninstall stderr after INSTALL_FAILED_UPDATE_INCOMPATIBLE: ${s.stderr}`:``].filter(Boolean).join(`
7
+ `)}}function Nn(e,t){let n=`package:${t}`;for(let t of e.split(/\r?\n/)){if(!t.startsWith(n)||t.length>n.length&&!/\s/.test(t[n.length]??``))continue;let e=/(?:^|\s)versionCode:(\d+)(?:\s|$)/.exec(t);if(e)return Number(e[1])}}function Pn(e){return`${e.stdout}\n${e.stderr}`.includes(`INSTALL_FAILED_UPDATE_INCOMPATIBLE`)}const Fn=new Set([`com.android.permissioncontroller`,`com.google.android.permissioncontroller`,`com.google.android.packageinstaller`,`com.android.packageinstaller`]);function In(e){return Fn.has(e)}const Ln=new Set([`android`,`com.android.systemui`]),Rn=/^android:id\/(?:alertTitle|message|button[123]|parentPanel|buttonPanel|contentPanel)$/i,q=/^android:id\/button[123]$/i,zn=/(?:^|:)id\/permission_/i,Bn=/\b(?:is(?:n't| not) responding|keeps stopping|has stopped|close app|app info)\b/i,Vn=/^(?:ok|allow|allow all|while using the app|only this time|yes|continue|save|confirm|turn on|open settings)$/i,Hn=/^(?:cancel|deny|don.t allow|don’t allow|not now|no|dismiss|close|close app|later|skip)$/i;function Un(e){if(e!==null){if(q.test(e))return`button`;if(Rn.test(e))return`content`}}function Wn(e){let t=Kn(e),n=t.nodes;if(n.length===0)return null;let r=Zn(n),i=n.filter(e=>J(e)&&!sr(e)),a=er(i),o=tr(i,a),s=cr(n);return{alert:{...a?{title:a}:{},...o?{message:o}:{},buttons:r.map(e=>e.label),platform:`android`,source:t.source,...s?{packageName:s}:{}},buttons:r}}function Gn(e,t){let n=t===`accept`?`accept`:`dismiss`;return e.find(e=>e.role===n)||(t===`dismiss`?e.find(e=>e.role===`neutral`)??null:e.length===1?e[0]??null:null)}function Kn(e){let t=e.filter(e=>ar(e));if(t.length)return{nodes:t,source:`permission`};let n=Xn(e);return n.length?{nodes:n,source:`system-dialog`}:{nodes:qn(e),source:`native-dialog`}}function qn(e){let t=e.filter(e=>Jn(e.type??``)),n=e.filter(e=>Rn.test(e.identifier??``)),r=t.length?[...t,...n]:Yn(n);if(r.length===0)return[];let i=nr(e,r);return i===void 0?r:ir(e,i)}function Jn(e){return/(?:^|[.$])[^.]*Dialog$/i.test(e)}function Yn(e){let t=e.some(e=>q.test(e.identifier??``)),n=e.some(e=>!q.test(e.identifier??``));return t&&n?e:[]}function Xn(e){let t=e.filter(e=>or(e));if(t.length===0)return[];let n=nr(e,t);return n===void 0?t:ir(e,n).filter(e=>e.bundleId&&Ln.has(e.bundleId))}function Zn(e){let t=new Set,n=[];for(let r of e){let e=J(r);if(!e||!r.rect||!sr(r))continue;let a=e.trim().toLowerCase();if(!a||t.has(a))continue;t.add(a);let o=i(r.rect);n.push({label:e,x:o.x,y:o.y,role:Qn(r,e)})}return n}function Qn(e,t){return $n(e.identifier??``)||(Vn.test(t.trim())?`accept`:Hn.test(t.trim())?`dismiss`:`neutral`)}function $n(e){return/(?:^|:)id\/button1$/i.test(e)?`accept`:/(?:^|:)id\/button2$/i.test(e)?`dismiss`:/(?:^|:)id\/button3$/i.test(e)?`neutral`:/(?:^|:)id\/permission_allow/i.test(e)?`accept`:/(?:^|:)id\/permission_deny/i.test(e)?`dismiss`:null}function er(e){return J(e.find(e=>/(?:^|:)id\/(?:alertTitle|permission_message)$/i.test(e.identifier??``)))||J(e[0])}function tr(e,t){let n=e.map(e=>J(e)).filter(e=>e&&e!==t);return n.length?[...new Set(n)].join(`
8
+ `):void 0}function nr(e,t){let n=t[0];if(!n)return;let r=rr(e,n.index);for(let n of t.slice(1)){let t=new Set(rr(e,n.index));for(let e=r.length-1;e>=0;--e)t.has(r[e])||r.splice(e,1)}return r[r.length-1]}function rr(e,t){let n=new Map(e.map(e=>[e.index,e])),r=[],i=n.get(t);for(;i;)r.push(i.index),i=i.parentIndex===void 0?void 0:n.get(i.parentIndex);return r.reverse()}function ir(e,t){let n=new Map;for(let t of e){if(t.parentIndex===void 0)continue;let e=n.get(t.parentIndex)??[];e.push(t),n.set(t.parentIndex,e)}let r=new Set([t]),i=[t];for(let e of i)for(let t of n.get(e)??[])r.has(t.index)||(r.add(t.index),i.push(t.index));return e.filter(e=>r.has(e.index))}function ar(e){let t=e.bundleId??``;return Fn.has(t)||zn.test(e.identifier??``)}function or(e){let t=e.bundleId??``;return Ln.has(t)&&Bn.test(J(e))}function sr(e){let t=e.type??``,n=e.identifier??``;return!!(e.hittable||/\bbutton\b/i.test(t)||q.test(n)||/(?:^|:)id\/permission_(?:allow|deny)/i.test(n))}function J(e){return e?[e.label,e.value].filter(e=>typeof e==`string`&&e.trim().length>0)[0]?.trim()??``:``}function cr(e){return e.find(e=>e.bundleId)?.bundleId}const lr=new Set([`android`,`com.android.systemui`]);function ur(e,t,n={}){if(t.backend!==`android-helper`)return{outcome:`ok`};let r=yr(e,n.foregroundAppPackage);return fr(r,t)?Y(r,t,`empty-helper-output`,`Android snapshot helper returned no accessibility nodes`):_r(r)?{outcome:`ok`}:dr(r)?{outcome:`system-surface-only`}:pr(r)?{outcome:`ok`}:X(r)?Y(r,t,`content-poor-app-window`,`Android snapshot helper returned insufficient foreground app content`):mr(r)||hr(r,t)?Y(r,t,`content-poor-app-window`,`Android snapshot helper returned insufficient application window content`):gr(r)?Y(r,t,`system-window-only`,`Android snapshot helper returned only non-application windows`):{outcome:`ok`}}function Y(e,t,n,r){return{outcome:`unusable`,decision:vr(e,t,n,r)}}function dr(e){return e.windowRootCount>0&&e.applicationWindowRootCount===0&&e.activeSystemSurfaceMeaningfulNodeCount>=3}function fr(e,t){return e.nodeCount===0||t.nodeCount===0||t.rootPresent===!1}function pr(e){return X(e)&&e.inputMethodMeaningfulNodeCount>=2}function X(e){let t=e.foregroundAppMeaningfulNodeCount;return t===void 0?!1:t===0?e.applicationMeaningfulNodeCount<2:t<2&&e.meaningfulNodeCount>t}function mr(e){return e.foregroundAppMeaningfulNodeCount===void 0&&e.applicationWindowRootCount>0&&e.applicationMeaningfulNodeCount<2}function hr(e,t){return e.foregroundAppMeaningfulNodeCount===void 0&&e.windowRootCount===0&&(t.windowCount??0)>1&&e.nonSystemMeaningfulNodeCount<2}function gr(e){return e.windowRootCount>0&&e.applicationWindowRootCount===0||e.windowRootCount===0&&e.nodeCount>0&&e.systemUiNodeCount===e.nodeCount}function _r(e){return e.hasAlertButtonIdentifier&&e.hasAlertContentIdentifier}function vr(e,t,n,r){return{reason:n,failureReason:r,diagnostics:Mr(e,t)}}function yr(e,t){let n=br(t);for(let t of he(e))xr(n,t);return Or(n)}function br(e){return{nodeCount:0,systemUiNodeCount:0,windowRootCount:0,applicationWindowRootCount:0,activeSystemSurfaceMeaningfulNodeCount:0,meaningfulNodeCount:0,applicationMeaningfulNodeCount:0,nonSystemMeaningfulNodeCount:0,inputMethodMeaningfulNodeCount:0,hasAlertButtonIdentifier:!1,hasAlertContentIdentifier:!1,...e===void 0?{}:{foregroundAppPackage:e,foregroundAppMeaningfulNodeCount:0},windowTypes:new Set}}function xr(e,t){e.nodeCount+=1,jr(t.packageName)&&(e.systemUiNodeCount+=1),t.visibleToUser!==!1&&Sr(e,t.resourceId),Cr(e,t),wr(e,t)}function Sr(e,t){let n=Un(t);n===`button`&&(e.hasAlertButtonIdentifier=!0),n===`content`&&(e.hasAlertContentIdentifier=!0)}function Cr(e,t){t.windowType!==void 0&&(e.currentWindowType=t.windowType,e.currentWindowActiveOrFocused=t.windowActive===!0||t.windowFocused===!0,e.windowRootCount+=1,e.windowTypes.add(t.windowType),t.windowType===1&&(e.applicationWindowRootCount+=1))}function wr(e,t){kr(t)&&(e.meaningfulNodeCount+=1,Tr(e,t),Dr(e,t))}function Tr(e,t){e.currentWindowType===1&&!Ar(t.packageName)&&(e.applicationMeaningfulNodeCount+=1),Er(e)&&!l(t)&&(e.activeSystemSurfaceMeaningfulNodeCount+=1)}function Er(e){return e.currentWindowType!==void 0&&e.currentWindowType!==1&&e.currentWindowActiveOrFocused===!0}function Dr(e,t){Ar(t.packageName)||(e.nonSystemMeaningfulNodeCount+=1),s({packageName:t.packageName,resourceId:t.resourceId})&&(e.inputMethodMeaningfulNodeCount+=1),e.foregroundAppPackage!==void 0&&t.packageName===e.foregroundAppPackage&&(e.foregroundAppMeaningfulNodeCount=(e.foregroundAppMeaningfulNodeCount??0)+1)}function Or(e){return{nodeCount:e.nodeCount,systemUiNodeCount:e.systemUiNodeCount,windowRootCount:e.windowRootCount,applicationWindowRootCount:e.applicationWindowRootCount,activeSystemSurfaceMeaningfulNodeCount:e.activeSystemSurfaceMeaningfulNodeCount,meaningfulNodeCount:e.meaningfulNodeCount,applicationMeaningfulNodeCount:e.applicationMeaningfulNodeCount,nonSystemMeaningfulNodeCount:e.nonSystemMeaningfulNodeCount,inputMethodMeaningfulNodeCount:e.inputMethodMeaningfulNodeCount,hasAlertButtonIdentifier:e.hasAlertButtonIdentifier,hasAlertContentIdentifier:e.hasAlertContentIdentifier,...e.foregroundAppPackage===void 0?{}:{foregroundAppPackage:e.foregroundAppPackage,foregroundAppMeaningfulNodeCount:e.foregroundAppMeaningfulNodeCount??0},windowTypes:[...e.windowTypes].sort((e,t)=>e-t).slice(0,8)}}function kr(e){return e.visibleToUser===!1?!1:Z(e.text)||Z(e.desc)||Z(e.resourceId)}function Z(e){return e!==null&&e.trim()!==``}function Ar(e){return e===null||lr.has(e)}function jr(e){return e!==null&&lr.has(e)}function Mr(e,t){return{helperNodeCount:e.nodeCount,helperSystemUiNodeCount:e.systemUiNodeCount,helperWindowRootCount:e.windowRootCount,helperApplicationWindowRootCount:e.applicationWindowRootCount,helperMeaningfulNodeCount:e.meaningfulNodeCount,helperApplicationMeaningfulNodeCount:e.applicationMeaningfulNodeCount,helperNonSystemMeaningfulNodeCount:e.nonSystemMeaningfulNodeCount,helperInputMethodMeaningfulNodeCount:e.inputMethodMeaningfulNodeCount,...e.foregroundAppPackage===void 0?{}:{helperForegroundAppPackage:e.foregroundAppPackage,helperForegroundAppMeaningfulNodeCount:e.foregroundAppMeaningfulNodeCount,helperForegroundAppMeaningfulNodeThreshold:2},helperWindowTypes:e.windowTypes,...t.captureMode?{helperCaptureMode:t.captureMode}:{}}}async function Nr(e){let t=await W(e.deviceKey,{signal:e.signal,cause:e.cause});e.signal?.throwIfAborted(),t||await Q(e.adb,e.packageName)}async function Q(t,n){try{await t([`shell`,`am`,`force-stop`,n],{allowFailure:!0,timeoutMs:2e3}),await ae(150),f({level:`debug`,phase:`android_snapshot_helper_runtime_reset`,data:{packageName:n}})}catch(t){f({level:`warn`,phase:`android_snapshot_helper_runtime_reset_failed`,data:{packageName:n,error:e(t).message}})}}const $=5e3,Pr=3e4;async function Fr(e,t={}){let n=m(e,t.helperAdb).exec;return(await Br(e,t,n)).xml}async function Ir(e,t={}){let n=m(e,t.helperAdb).exec,r=await Br(e,t,n),i=r.xml;if(!t.interactiveOnly){let e=_e(i,void 0,t),n=Lr(e.truncated,r.metadata);return{...e,...Rr(n),androidSnapshot:r.metadata}}let a=S(i),o=y(a,void 0,t),s=Lr(o.truncated,r.metadata);t.includeHiddenContentHints!==!1&&zr({options:t,tree:a,xml:i,interactiveSnapshot:o});let{sourceNodes:c,...l}=o;return{...l,...Rr(s),androidSnapshot:r.metadata}}function Lr(e,t){return e===!0||t.helperTruncated===!0?!0:e}function Rr(e){return e===!0?{truncated:!0}:{}}function zr(e){if(ai(e.interactiveSnapshot.nodes).size>0||ii(e.xml))return;let t=y(e.tree,void 0,{...e.options,interactiveOnly:!1});oi(u(r(t.nodes)),t,e.interactiveSnapshot)}async function Br(e,t,n){let r=m(e,t.helperAdb),i=await p(`android_snapshot_helper_artifact_resolution`,async()=>await ni(t.helperArtifact??r.snapshotHelperArtifact));if(i.artifact)return await Vr(e,t,n,i.artifact);throw f({level:`error`,phase:`android_snapshot_helper_unavailable`,data:{reason:i.errorReason??`artifact_not_found`}}),ri(i.errorReason)}async function Vr(e,t,n,r){let i=P(e),a=m(e,t.helperAdb),o=t.helperSessionScope!==`daemon-session`;try{let e;for(let o=0;;o+=1){o>0&&await Kr(t.signal);let s=await Gr({options:t,adb:n,adbProvider:a,artifact:r,helperDeviceKey:i,attempt:o,previousContentReason:e});if(s.outcome===`captured`)return s.capture;if(o+1>=3)return await qr({contentRecovery:s.decision,attempts:o+1,helperDeviceKey:i,artifact:r,adb:n,signal:t.signal});e=s.decision.reason}}finally{o&&await W(i)}}async function Hr(e,t,n,r,i){let a=await p(`android_snapshot_helper_install`,async()=>await On({adb:t,adbProvider:n,artifact:r,deviceKey:i,installPolicy:e.helperInstallPolicy,timeoutMs:3e4,signal:e.signal}),{packageName:r.manifest.packageName,versionCode:r.manifest.versionCode,installPolicy:e.helperInstallPolicy??`missing-or-outdated`});return f({phase:`android_snapshot_helper_install_decision`,data:{packageName:a.packageName,versionCode:a.versionCode,installedVersionCode:a.installedVersionCode,artifactSha256:r.manifest.sha256,installedSha256:a.installedSha256,installed:a.installed,reason:a.reason}}),a}async function Ur(t){let{signal:n,adb:r,adbProvider:i,artifact:a,helperDeviceKey:o}=t,s={adb:r,adbProvider:i,deviceKey:o,helperVersion:a.manifest.version,helperVersionCode:a.manifest.versionCode,helperSha256:a.manifest.sha256,packageName:a.manifest.packageName,instrumentationRunner:a.manifest.instrumentationRunner,waitForIdleTimeoutMs:500,timeoutMs:$,commandTimeoutMs:Pr,signal:n};try{let e=await p(`android_snapshot_helper_session_capture`,async()=>await fn(s),{packageName:a.manifest.packageName,version:a.manifest.version,timeoutMs:$});if(e)return e}catch(t){if(n?.throwIfAborted(),Ct(t))throw t;f({level:`warn`,phase:`android_snapshot_helper_session_fallback`,data:{reason:e(t).message}}),await Q(r,a.manifest.packageName)}return await p(`android_snapshot_helper_capture`,async()=>await At(s),{packageName:a.manifest.packageName,version:a.manifest.version,timeoutMs:$,commandTimeoutMs:Pr})}function Wr(e,t,n){return{xml:e.xml,metadata:{backend:`android-helper`,helperVersion:t.manifest.version,helperApiVersion:e.metadata.helperApiVersion,helperTransport:e.metadata.transport,helperSessionReused:e.metadata.sessionReused,installReason:n,waitForIdleTimeoutMs:e.metadata.waitForIdleTimeoutMs,waitForIdleQuietMs:e.metadata.waitForIdleQuietMs,timeoutMs:e.metadata.timeoutMs,maxDepth:e.metadata.maxDepth,maxNodes:e.metadata.maxNodes,rootPresent:e.metadata.rootPresent,captureMode:e.metadata.captureMode,windowCount:e.metadata.windowCount,nodeCount:e.metadata.nodeCount,helperTruncated:e.metadata.truncated,elapsedMs:e.metadata.elapsedMs}}}async function Gr(e){let{options:t,adb:n,adbProvider:r,artifact:i,helperDeviceKey:a,attempt:o}=e,s;try{let e=await Hr(t,n,r,i,a);e.installed&&await W(a),s=Wr(await Ur({signal:t.signal,adb:n,adbProvider:r,artifact:i,helperDeviceKey:a}),i,e.reason)}catch(e){return t.signal?.throwIfAborted(),{outcome:`captured`,capture:await Jr({error:e,helperDeviceKey:a,artifact:i,adb:n})}}let c=ur(s.xml,s.metadata,{foregroundAppPackage:t.appBundleId});return c.outcome===`system-surface-only`?(f({phase:`android_snapshot_helper_system_surface`,data:{foregroundAppPackage:t.appBundleId}}),{outcome:`captured`,capture:{xml:s.xml,metadata:{...s.metadata,systemSurfaceOnly:!0}}}):c.outcome===`ok`?(o>0&&f({phase:`android_snapshot_helper_content_recaptured`,data:{attempts:o+1,recoveredFromReason:e.previousContentReason}}),{outcome:`captured`,capture:s}):{outcome:`unusable`,decision:c.decision}}async function Kr(e){e?.throwIfAborted(),await ae(250),e?.throwIfAborted()}async function qr(e){throw f({level:`error`,phase:`android_snapshot_helper_content_invalid`,data:{reason:e.contentRecovery.reason,failureReason:e.contentRecovery.failureReason,attempts:e.attempts,...e.contentRecovery.diagnostics}}),await Nr({adb:e.adb,deviceKey:e.helperDeviceKey,packageName:e.artifact.manifest.packageName,signal:e.signal,cause:e.contentRecovery.failureReason}),new n(`COMMAND_FAILED`,e.contentRecovery.failureReason,{...e.contentRecovery.diagnostics,androidSnapshotHelperFailureReason:e.contentRecovery.reason,attempts:e.attempts,retriable:!0,hint:`Retry after the app UI stabilizes. If this persists, capture a screenshot and report the helper diagnostics; agent-device does not substitute a second snapshot engine.`})}async function Jr(e){let t=Yr(e.error);throw f({level:`error`,phase:`android_snapshot_helper_failed`,data:{reason:t}}),await W(e.helperDeviceKey),await Q(e.adb,e.artifact.manifest.packageName),Tn({deviceKey:e.helperDeviceKey,packageName:e.artifact.manifest.packageName,versionCode:e.artifact.manifest.versionCode}),Xr(e.error,t)}function Yr(t){let n=e(t),r=ei(n.details?.helper);if(r&&r!==n.message)return`${n.message}: ${r}`;if(r)return r;let i=(typeof n.details?.stderr==`string`?n.details.stderr.trim():``).split(/\r?\n/).find(e=>e.trim());return i?`${n.message}: ${i}`:n.message}function Xr(r,i){let a=e(r);return new n(t(a.code),`Android snapshot helper failed: ${i}`,{...a.details,...Qr(a),androidSnapshotHelperFailureReason:i,hint:Zr(a)},r)}function Zr(e){return ti(e.details?.helper,e.message)||$r(e)?`Android accessibility snapshots can be blocked by busy or continuously changing app UI. Use screenshot as visual truth after this timeout and report the busy UI if it persists.`:e.details?.androidSnapshotHelperInstallFailure===!0?[e.hint,`This is a device-side install failure (adb rejection or OEM policy) — the helper artifact itself is present, this is not a missing/unbuilt build.`].filter(Boolean).join(` `):e.hint??`Retry once. If the helper still fails, run agent-device doctor and report the diagnostic log; agent-device does not substitute a second snapshot engine.`}function Qr(e){let t={};return e.diagnosticId!==void 0&&(t.diagnosticId=e.diagnosticId),e.logPath!==void 0&&(t.logPath=e.logPath),e.retriable!==void 0&&(t.retriable=e.retriable),e.supportedOn!==void 0&&(t.supportedOn=e.supportedOn),t}function $r(e){return e.details?.exitCode===137?/Android snapshot helper (failed before returning parseable output|output could not be parsed)/.test(e.message):!1}function ei(e){if(!e||typeof e!=`object`||!(`message`in e))return;let t=String(e.message).trim();return t&&t!==`null`?t:void 0}function ti(e,t){if(!e||typeof e!=`object`)return!1;let n=`errorType`in e?String(e.errorType):``,r=ei(e)??t;return/TimeoutException/.test(n)||/timed out/i.test(r)}async function ni(t){if(t)return{artifact:t};let n=re(),r=_.join(ie(),`android`,`snapshot-helper`,`dist`),i=_.join(r,`agent-device-android-snapshot-helper-${n}.manifest.json`);try{await v.access(i)}catch{return{}}try{let e=ft(JSON.parse(await v.readFile(i,`utf8`))),t=_.join(r,e.assetName??`agent-device-android-snapshot-helper-${e.version}.apk`);return await v.access(t),{artifact:{apkPath:t,manifest:e}}}catch(t){return{errorReason:e(t).message}}}function ri(e){let t=e??`the bundled helper artifact was not found`;return new n(`COMMAND_FAILED`,`Android snapshot helper is unavailable: ${t}`,{androidSnapshotHelperFailureReason:t,hint:"Run `pnpm build:android` to build the helper dist for a source checkout — the runtime needs android/snapshot-helper/dist/agent-device-android-snapshot-helper-<version>.manifest.json and the .apk it references. Packaged installs ship these via the prepack script; if they are missing from a packaged install, reinstall agent-device."})}function ii(e){return e.includes(` can-scroll-forward=`)||e.includes(` can-scroll-backward=`)}function ai(e){let t=new Map;for(let n of e){let e={};n.hiddenContentAbove&&(e.hiddenContentAbove=!0),n.hiddenContentBelow&&(e.hiddenContentBelow=!0),(e.hiddenContentAbove||e.hiddenContentBelow)&&t.set(n.index,e)}return t}function oi(e,t,n){if(e.size===0)return;let r=new Map;for(let[e,t]of n.sourceNodes.entries()){let i=n.nodes[e];i&&r.set(t,i)}for(let[n,i]of e){let e=t.sourceNodes[n];if(!e)continue;let a=r.get(e);a&&(i.hiddenContentAbove&&(a.hiddenContentAbove=!0),i.hiddenContentBelow&&(a.hiddenContentBelow=!0))}}export{In as a,_n as c,P as d,F as f,he as h,Wn as i,W as l,T as m,Ir as n,On as o,ft as p,Gn as r,xn as s,Fr as t,bn as u};
@@ -1 +1 @@
1
- import{_ as e}from"./sdk-contracts.js";import{_ as t,gt as n,h as r,ht as i,v as a}from"./version.js";import{lt as o}from"./sdk-batch-runner.js";import{c as s,l as c}from"./sdk-device.js";import{gn as l}from"./prepare-kind.js";import"./screenshot-result.js";import{I as u}from"./sdk-android-adb.js";import{t as d}from"./timeouts.js";import{l as f,n as p}from"./input-actions.js";import{f as m,m as h,p as g}from"./ime-lifecycle.js";import{c as _,o as v,t as y}from"./dispatch.js";import{i as b}from"./helper.js";import{ct as x,fn as S,tn as C,yn as w}from"./internal/daemon.js";import{i as T}from"./selector-runtime.js";import{a as E,i as D,n as O,r as k}from"./snapshot-session.js";import{n as A,t as j}from"./snapshot-runtime.js";async function M(e,t,n={}){return t===`wait`?await N(e,n.timeoutMs??1e4):t===`get`?L((await I(e))?.alert??null):await P(e,t)}async function N(t,n){let r=Date.now(),i=await F(t,n);if(!i)throw new e(`COMMAND_FAILED`,`alert wait timed out`);return{kind:`alertWait`,platform:`android`,action:`wait`,alert:i.alert,waitedMs:Date.now()-r,...l(`Alert visible`)}}async function P(t,n){let r=await F(t,i);if(!r)throw new e(`COMMAND_FAILED`,`alert not found`,{hint:`If a sheet is visible in snapshot but alert reports no alert, it is likely app-owned UI. Use snapshot -i and press the visible label/ref.`});let a=g(r.buttons,n);if(a)return await f(t,a.x,a.y),R(n,r.alert,a.label);if(n===`dismiss`)return await p(t),R(n,r.alert,`Back`);throw new e(`COMMAND_FAILED`,`alert accept found an alert but no accept button`,{alert:r.alert,hint:`Inspect alert get --json for visible buttons, then use press by visible label/ref if needed.`})}async function F(e,t){let n=Date.now();for(;Date.now()-n<t;){let t=await I(e);if(t)return t;await d(300)}return null}async function I(e){return h((await u(`snapshot_capture`,async()=>await m(e,{includeHiddenContentHints:!1}),{backend:`android`,purpose:`alert`})).nodes)}function L(e){return{kind:`alertStatus`,platform:`android`,action:`get`,alert:e,...l(e?`Alert visible`:`No alert visible`)}}function R(e,t,n){return{kind:`alertHandled`,platform:`android`,action:e,handled:!0,alert:t,button:n,...l(`Alert ${e}ed`)}}async function z(e){let{req:t,logPath:n,session:r,device:i}=e,a=V(t.positionals?.[0]),s=r?r.surface===`frontmost-app`?{surface:`frontmost-app`}:{bundleId:r.appBundleId,surface:r.surface}:{},l=_(`alert`,i);if(l)return l;if(r&&w(t)===`may-invalidate`&&C(r),i.platform===`android`)return G(e,await M(i,a,{timeoutMs:o(t.positionals?.[1])??1e4}));if(c(i))return await B(e,a,async e=>await b(e,s));let u=E({req:t,logPath:n,traceLogPath:r?.trace?.outPath});return await B(e,a,async(e,t)=>await x(i,{command:`alert`,action:e,appBundleId:r?.appBundleId,timeoutMs:t},u))}async function B(e,t,r){if(t===`wait`)return await H(e,r);let i=t===`accept`||t===`dismiss`?t:`get`;return i===`accept`||i===`dismiss`?await U(e,i,r):G(e,await r(`get`,n))}function V(e){return e===`accept`||e===`dismiss`||e===`wait`?e:`get`}async function H(e,t){let n=o(e.req.positionals?.[1])??1e4,r=Date.now(),i=!0;for(;Date.now()-r<n;){try{let a=i?n:W(r,n);return i=!1,G(e,await t(`get`,a))}catch{}await d(300)}return v(`COMMAND_FAILED`,`alert wait timed out`)}async function U(e,t,r){let a=s(e.device)?n:i,o=Date.now(),c,l=!0;for(;Date.now()-o<i;){try{let n=l?a:W(o,i);return l=!1,G(e,await r(t,n))}catch(e){c=e;let t=String(e?.message??``).toLowerCase();if(!t.includes(`alert not found`)&&!t.includes(`no alert`))break}await d(300)}throw K(c)}function W(e,t){return Math.max(1,t-(Date.now()-e))}function G(e,t){let n=t;return O(e.sessionStore,e.session,e.req,n),{ok:!0,data:n}}function K(t){return!(t instanceof e)||!q(t)?t:new e(t.code,t.message,{...t.details??{},hint:`If the permission sheet is visible in snapshot or screenshot but alert reports no alert, take a scoped snapshot around the visible button label and use press @ref.`})}function q(e){let t=String(e?.message??``).toLowerCase();return t.includes(`alert not found`)||t.includes(`no alert`)}function J(e){let t=e.positionals?.[0]?.toLowerCase(),n=e.positionals?.[1]?.toLowerCase(),i=e.positionals?.[2]?.toLowerCase();return t===`clear-app-state`?{ok:!0,parsed:{setting:t,state:`clear`,appBundleId:n===`clear`?e.positionals?.[2]:e.positionals?.[1]}}:!t||!n||t===`permission`&&!i||t===`location`&&n===`set`&&(!e.positionals?.[2]||!e.positionals?.[3])?v(`INVALID_ARGS`,r):{ok:!0,parsed:{setting:t,state:n,permissionTarget:i,latitude:e.positionals?.[2],longitude:e.positionals?.[3]}}}async function Y(e){let{req:n,logPath:r,sessionStore:i,session:o,device:s,parsed:l}=e,{setting:u,state:d,appBundleId:f,permissionTarget:p,latitude:m,longitude:h}=l,g=_(`settings`,s);if(g)return g;if(c(s)&&!a(u))return v(`INVALID_ARGS`,t(u));let b=f??o?.appBundleId;if(u===`clear-app-state`&&!b)return v(`INVALID_ARGS`,`settings clear-app-state requires an app id when no app is bound to the session`);let x=u===`clear-app-state`?[u,d,b??``]:u===`permission`?[u,d,p??``,n.positionals?.[3]??``,b??``]:u===`location`&&d===`set`?[u,d,m??``,h??``,b??``]:[u,d,b??``];o&&C(o);let w=await y(s,`settings`,x,n.flags?.out,{...S(r,n.flags,b,o?.trace?.outPath)});return O(i,o,n,w??{setting:u,state:d}),{ok:!0,data:w??{setting:u,state:d}}}const X={snapshot:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>await A({req:e,sessionName:t,logPath:n,sessionStore:r}),diff:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>e.positionals?.[0]===`snapshot`?await j({req:e,sessionName:t,logPath:n,sessionStore:r}):v(`INVALID_ARGS`,`diff currently supports only: diff snapshot`),wait:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>await T({req:e,sessionName:t,logPath:n,sessionStore:r}),alert:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>{let{session:i,device:a}=await k(r,t,e.flags);return await D(i,a,async()=>await z({req:e,logPath:n,sessionStore:r,session:i,device:a}))},settings:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>{let i=J(e);if(!i.ok)return i;let{session:a,device:o}=await k(r,t,e.flags);return await D(a,o,async()=>await Y({req:e,logPath:n,sessionStore:r,session:a,device:o,parsed:i.parsed}))}};async function Z(e){let t=e.req.command,n=X[t];return n?await n(e):null}export{Z as handleSnapshotCommands};
1
+ import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{A as n,C as r,_ as i}from"./sdk-android-adb.js";import{t as a}from"./timeouts.js";import{t as o}from"./scoped-provider.js";import s from"node:path";import c from"node:fs";import{fileURLToPath as l}from"node:url";const u={"push button":`Button`,"toggle button":`Button`,"push button menu":`Button`,label:`StaticText`,static:`StaticText`,caption:`StaticText`,text:`TextField`,entry:`TextField`,"password text":`TextField`,"spin button":`TextField`,terminal:`TextArea`,"document text":`TextArea`,paragraph:`TextArea`,frame:`Window`,window:`Window`,dialog:`Dialog`,alert:`Alert`,"file chooser":`Dialog`,"color chooser":`Dialog`,"font chooser":`Dialog`,panel:`Group`,filler:`Group`,section:`Group`,form:`Group`,grouping:`Group`,"layered pane":`Group`,"glass pane":`Group`,"root pane":`Group`,"option pane":`Group`,"internal frame":`Group`,"desktop frame":`Group`,"block quote":`Group`,article:`Group`,comment:`Group`,landmark:`Group`,log:`Group`,marquee:`Group`,math:`Group`,notification:`Group`,"content deletion":`Group`,"content insertion":`Group`,mark:`Group`,suggestion:`Group`,"scroll pane":`ScrollArea`,"scroll bar":`ScrollBar`,"menu bar":`MenuBar`,menu:`Menu`,"popup menu":`Menu`,"menu item":`MenuItem`,"check menu item":`MenuItem`,"radio menu item":`MenuItem`,"tearoff menu item":`MenuItem`,"check box":`CheckBox`,"radio button":`RadioButton`,switch:`Switch`,"combo box":`ComboBox`,"page tab":`Tab`,"page tab list":`TabList`,table:`Table`,"tree table":`Table`,"table cell":`Cell`,"table row":`Row`,"table column header":`Cell`,"table row header":`Cell`,"column header":`Cell`,"row header":`Cell`,list:`List`,"list item":`ListItem`,"list box":`List`,tree:`Tree`,"tree item":`TreeItem`,"description list":`List`,"description term":`ListItem`,"description value":`ListItem`,"tool bar":`Toolbar`,"status bar":`StatusBar`,"info bar":`StatusBar`,slider:`Slider`,"progress bar":`ProgressBar`,"level bar":`ProgressBar`,image:`Image`,icon:`Image`,animation:`Image`,canvas:`Image`,"drawing area":`Image`,video:`Video`,audio:`Audio`,link:`Link`,hyperlink:`Link`,separator:`Separator`,application:`Application`,"tool tip":`Tooltip`,timer:`Timer`,heading:`Heading`,footnote:`Footnote`,"title bar":`TitleBar`,"date editor":`DateEditor`,rating:`Slider`};function d(e){let t=e.toLowerCase().trim();return u[t]||t.split(/[\s_-]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``)}var f=e({createLocalLinuxToolProvider:()=>h,resolveLinuxToolProvider:()=>g,runLinuxToolCommand:()=>v,withLinuxToolProvider:()=>_});const p={runCommand:i,whichCommand:r,desktop:y(i,r),clipboard:b(i,r),screenshot:x(i,r)},m=o(p,h);function h(e={}){let t={...p,...e};return{...t,desktop:e.desktop??y(t.runCommand,t.whichCommand),clipboard:e.clipboard??b(t.runCommand,t.whichCommand),screenshot:e.screenshot??x(t.runCommand,t.whichCommand)}}function g(e){return m.resolve(e)}async function _(e,t){return await m.run(e,t)}async function v(e,t,n){return await g().runCommand(e,t,n)}function y(e,t){return{async openTarget(r){if(r.includes(`://`)||r.startsWith(`/`)){await e(`xdg-open`,[r]);return}if(await t(r)){e(r,[],{allowFailure:!0}).catch(e=>{n({level:`warn`,phase:`linux_app_launch`,data:{app:r,error:String(e)}})}),await a(500);return}await e(`xdg-open`,[r],{allowFailure:!0})},async closeApp(n){if(await t(`wmctrl`)){await e(`wmctrl`,[`-c`,n],{allowFailure:!0});return}await e(`pkill`,[`-x`,n],{allowFailure:!0})}}}function b(e,t){return{async readText(){let n=await O(t,C),r=T[n];return(await e(r.cmd,r.args,r.options)).stdout},async writeText(n){let r=await O(t,C),i=E[r](n);await e(i.cmd,i.args,i.options)}}}function x(e,t){return{async capture(n){let r=await O(t,w),i=D[r](n);await e(i.cmd,i.args,i.options)}}}const S=5e3,C={wayland:[{tool:`wl-clipboard`,command:`wl-paste`}],x11:[{tool:`xclip`,command:`xclip`},{tool:`xsel`,command:`xsel`}],waylandError:`wl-paste (wl-clipboard) is required for clipboard access on Wayland. Install via your package manager.`,x11Error:`xclip or xsel is required for clipboard access on X11. Install via your package manager.`},w={wayland:[{tool:`grim`,command:`grim`},{tool:`gnome-screenshot`,command:`gnome-screenshot`}],x11:[{tool:`scrot`,command:`scrot`},{tool:`import`,command:`import`},{tool:`gnome-screenshot`,command:`gnome-screenshot`}],waylandError:`grim or gnome-screenshot is required for screenshots on Wayland. Install via your package manager.`,x11Error:`scrot, import (ImageMagick), or gnome-screenshot is required for screenshots on X11. Install via your package manager.`},T={"wl-clipboard":{cmd:`wl-paste`,args:[`--no-newline`],options:{allowFailure:!0,timeoutMs:S}},xclip:{cmd:`xclip`,args:[`-selection`,`clipboard`,`-o`],options:{allowFailure:!0,timeoutMs:S}},xsel:{cmd:`xsel`,args:[`--clipboard`,`--output`],options:{allowFailure:!0,timeoutMs:S}}},E={"wl-clipboard":e=>({cmd:`wl-copy`,args:[`--`,e],options:{allowFailure:!1,timeoutMs:S}}),xclip:e=>({cmd:`xclip`,args:[`-selection`,`clipboard`],options:{allowFailure:!1,timeoutMs:S,stdin:e}}),xsel:e=>({cmd:`xsel`,args:[`--clipboard`,`--input`],options:{allowFailure:!1,timeoutMs:S,stdin:e}})},D={grim:e=>({cmd:`grim`,args:[e]}),scrot:e=>({cmd:`scrot`,args:[e]}),import:e=>({cmd:`import`,args:[`-window`,`root`,e]}),"gnome-screenshot":e=>({cmd:`gnome-screenshot`,args:[`-f`,e]})};async function O(e,n){let r=k()?`wayland`:`x11`;for(let t of n[r])if(await e(t.command))return t.tool;throw new t(`TOOL_MISSING`,r===`wayland`?n.waylandError:n.x11Error)}function k(){return!!process.env.WAYLAND_DISPLAY||process.env.XDG_SESSION_TYPE===`wayland`}const A=`atspi-dump.py`;let j=null;function M(){if(j)return j;let e=s.dirname(l(import.meta.url));for(let t=0;t<6;t++){let t=s.join(e,`linux`,A);if(c.existsSync(t))return j=t,t;e=s.dirname(e)}throw new t(`TOOL_MISSING`,`Cannot find ${A}. Ensure the agent-device package is installed correctly.`)}async function N(e,n={}){let r=g().accessibility;if(r)return await r.captureTree(e,n);if(process.platform!==`linux`)throw new t(`UNSUPPORTED_PLATFORM`,`AT-SPI2 bridge is only available on Linux`);if(!await g().whichCommand(`python3`))throw new t(`TOOL_MISSING`,`python3 is required for AT-SPI2 accessibility snapshots on Linux.`);let i=n.maxNodes??1500,a=n.maxDepth??12,o=n.maxApps??24,s=await v(`python3`,[M(),`--surface`,e,`--max-nodes`,String(i),`--max-depth`,String(a),`--max-apps`,String(o)],{allowFailure:!0,timeoutMs:3e4,signal:n.signal});if(s.exitCode!==0){let e=s.stderr.trim();throw e.includes(`No module named`)||e.includes(`gi.require_version`)?new t(`TOOL_MISSING`,`AT-SPI2 Python bindings not found. Install python3-gi and gir1.2-atspi-2.0.`,{cause:e}):new t(`COMMAND_FAILED`,`AT-SPI2 snapshot failed (exit ${s.exitCode}): ${e||s.stdout}`)}let c;try{c=JSON.parse(s.stdout)}catch{throw new t(`COMMAND_FAILED`,`AT-SPI2 snapshot returned invalid JSON: ${s.stdout.slice(0,200)}`)}if(c.error)throw new t(`COMMAND_FAILED`,`AT-SPI2: ${c.error}`);return{nodes:(c.nodes??[]).map(e=>({index:e.index,type:d(e.role),role:e.role,label:e.label??void 0,value:e.value??void 0,rect:e.rect??void 0,enabled:e.enabled??void 0,selected:e.selected??void 0,hittable:e.hittable??void 0,depth:e.depth,parentIndex:e.parentIndex??void 0,pid:e.pid??void 0,appName:e.appName??void 0,windowTitle:e.windowTitle??void 0})),truncated:c.truncated,surface:e}}var P=e({readLinuxTextAtPoint:()=>L,snapshotLinux:()=>I});function F(e){return e===`desktop`?`desktop`:e===`frontmost-app`||e===`app`?`frontmost-app`:(e===`menubar`&&n({level:`warn`,phase:`linux_snapshot`,data:{message:`menubar surface is not supported on Linux, falling back to desktop`}}),`desktop`)}async function I(e,t){let n=await N(F(e),{signal:t});return{nodes:n.nodes,truncated:n.truncated}}async function L(e,t,n){let{nodes:r}=await I(n),i=r.filter(n=>{let r=n.rect;return r?e>=r.x&&t>=r.y&&e<=r.x+r.width&&t<=r.y+r.height:!1}).sort((e,t)=>{let n=e.depth??0,r=t.depth??0;return n===r?R(e.rect)-R(t.rect):r-n});for(let e of i){let t=z(e);if(t.trim())return t}return``}function R(e){return(e?.width??0)*(e?.height??0)}function z(e){for(let t of[e.value,e.label,e.identifier])if(typeof t==`string`&&t.length>0)return t;return``}export{f as i,P as n,g as r,I as t};
@@ -0,0 +1 @@
1
+ import{_ as e}from"./sdk-contracts.js";import{a as t,o as n,r}from"./location-coordinates.js";import{Wt as i}from"./sdk-batch-runner.js";import{c as a,l as o}from"./sdk-device.js";import{Vt as s}from"./prepare-kind.js";import{J as c,Y as l}from"./interaction.js";import"./screenshot-result.js";import{F as u}from"./sdk-android-adb.js";import{t as d}from"./timeouts.js";import{l as f,n as p}from"./input-actions.js";import{i as m,n as h,r as g}from"./snapshot.js";import{a as _,s as v,t as y}from"./dispatch.js";import{r as b}from"./helper.js";import{n as x}from"./runner-client.js";import{Gt as S,Pt as C,Xt as w}from"./internal/daemon.js";import{i as T,m as E}from"./selector-runtime.js";import{i as D,n as O,r as k}from"./snapshot-session.js";import{n as A,t as j}from"./snapshot-runtime.js";async function M(e,t,n={}){return t===`wait`?await N(e,n.timeoutMs??1e4):t===`get`?L((await I(e))?.alert??null):await P(e,t)}async function N(t,n){let r=Date.now(),i=await F(t,n);if(!i)throw new e(`COMMAND_FAILED`,`alert wait timed out`);return{kind:`alertWait`,platform:`android`,action:`wait`,alert:i.alert,waitedMs:Date.now()-r,...s(`Alert visible`)}}async function P(t,n){let r=await F(t,c);if(!r)throw new e(`COMMAND_FAILED`,`alert not found`,{hint:`If a sheet is visible in snapshot but alert reports no alert, it is likely app-owned UI. Use snapshot -i and press the visible label/ref.`});let i=g(r.buttons,n);if(i)return await f(t,i.x,i.y),R(n,r.alert,i.label);if(n===`dismiss`)return await p(t),R(n,r.alert,`Back`);throw new e(`COMMAND_FAILED`,`alert accept found an alert but no accept button`,{alert:r.alert,hint:`Inspect alert get --json for visible buttons, then use press by visible label/ref if needed.`})}async function F(e,t){let n=Date.now();for(;Date.now()-n<t;){let t=await I(e);if(t)return t;await d(300)}return null}async function I(e){return m((await u(`snapshot_capture`,async()=>await h(e,{includeHiddenContentHints:!1}),{backend:`android`,purpose:`alert`})).nodes)}function L(e){return{kind:`alertStatus`,platform:`android`,action:`get`,alert:e,...s(e?`Alert visible`:`No alert visible`)}}function R(e,t,n){return{kind:`alertHandled`,platform:`android`,action:e,handled:!0,alert:t,button:n,...s(`Alert ${e}ed`)}}async function z(e){let{req:t,logPath:n,session:r,device:a}=e,s=V(t.positionals?.[0]),c=r?r.surface===`frontmost-app`?{surface:`frontmost-app`}:{bundleId:r.appBundleId,surface:r.surface}:{},l=v(`alert`,a);if(l)return l;if(r&&w(t)===`may-invalidate`&&C(r),a.platform===`android`)return G(e,await M(a,s,{timeoutMs:i(t.positionals?.[1])??1e4}));if(o(a))return await B(e,s,async e=>await b(e,c));let u=E({req:t,logPath:n,traceLogPath:r?.trace?.outPath});return await B(e,s,async(e,t)=>await x(a,{command:`alert`,action:e,appBundleId:r?.appBundleId,timeoutMs:t},u))}async function B(e,t,n){if(t===`wait`)return await H(e,n);let r=t===`accept`||t===`dismiss`?t:`get`;return r===`accept`||r===`dismiss`?await U(e,r,n):G(e,await n(`get`,l))}function V(e){return e===`accept`||e===`dismiss`||e===`wait`?e:`get`}async function H(e,t){let n=i(e.req.positionals?.[1])??1e4,r=Date.now(),a=!0;for(;Date.now()-r<n;){try{let i=a?n:W(r,n);return a=!1,G(e,await t(`get`,i))}catch{}await d(300)}return _(`COMMAND_FAILED`,`alert wait timed out`)}async function U(e,t,n){let r=a(e.device)?l:c,i=Date.now(),o,s=!0;for(;Date.now()-i<c;){try{let a=s?r:W(i,c);return s=!1,G(e,await n(t,a))}catch(e){o=e;let t=String(e?.message??``).toLowerCase();if(!t.includes(`alert not found`)&&!t.includes(`no alert`))break}await d(300)}throw K(o)}function W(e,t){return Math.max(1,t-(Date.now()-e))}function G(e,t){let n=t;return O(e.sessionStore,e.session,e.req,n),{ok:!0,data:n}}function K(t){return!(t instanceof e)||!q(t)?t:new e(t.code,t.message,{...t.details??{},hint:`If the permission sheet is visible in snapshot or screenshot but alert reports no alert, take a scoped snapshot around the visible button label and use press @ref.`})}function q(e){let t=String(e?.message??``).toLowerCase();return t.includes(`alert not found`)||t.includes(`no alert`)}function J(e){let t=e.positionals?.[0]?.toLowerCase(),n=e.positionals?.[1]?.toLowerCase(),i=e.positionals?.[2]?.toLowerCase();return t===`clear-app-state`?{ok:!0,parsed:{setting:t,state:`clear`,appBundleId:n===`clear`?e.positionals?.[2]:e.positionals?.[1]}}:!t||!n||t===`permission`&&!i||t===`location`&&n===`set`&&(!e.positionals?.[2]||!e.positionals?.[3])?_(`INVALID_ARGS`,r):{ok:!0,parsed:{setting:t,state:n,permissionTarget:i,latitude:e.positionals?.[2],longitude:e.positionals?.[3]}}}async function Y(e){let{req:r,logPath:i,sessionStore:a,session:s,device:c,parsed:l}=e,{setting:u,state:d,appBundleId:f,permissionTarget:p,latitude:m,longitude:h}=l,g=v(`settings`,c);if(g)return g;if(o(c)&&!n(u))return _(`INVALID_ARGS`,t(u));let b=f??s?.appBundleId;if(u===`clear-app-state`&&!b)return _(`INVALID_ARGS`,`settings clear-app-state requires an app id when no app is bound to the session`);let x=u===`clear-app-state`?[u,d,b??``]:u===`permission`?[u,d,p??``,r.positionals?.[3]??``,b??``]:u===`location`&&d===`set`?[u,d,m??``,h??``,b??``]:[u,d,b??``];s&&C(s);let w=await y(c,`settings`,x,r.flags?.out,{...S(i,r.flags,b,s?.trace?.outPath)});return O(a,s,r,w??{setting:u,state:d}),{ok:!0,data:w??{setting:u,state:d}}}const X={snapshot:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>await A({req:e,sessionName:t,logPath:n,sessionStore:r}),diff:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>e.positionals?.[0]===`snapshot`?await j({req:e,sessionName:t,logPath:n,sessionStore:r}):_(`INVALID_ARGS`,`diff currently supports only: diff snapshot`),wait:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>await T({req:e,sessionName:t,logPath:n,sessionStore:r}),alert:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>{let{session:i,device:a}=await k(r,t,e.flags);return await D(i,a,async()=>await z({req:e,logPath:n,sessionStore:r,session:i,device:a}))},settings:async({req:e,sessionName:t,logPath:n,sessionStore:r})=>{let i=J(e);if(!i.ok)return i;let{session:a,device:o}=await k(r,t,e.flags);return await D(a,o,async()=>await Y({req:e,logPath:n,sessionStore:r,session:a,device:o,parsed:i.parsed}))}};async function Z(e){let t=e.req.command,n=X[t];return n?await n(e):null}export{Z as handleSnapshotCommands};
package/dist/src/src.js CHANGED
@@ -1 +1 @@
1
- import{o as e}from"./png-worker-contract.js";import{_ as t}from"./sdk-contracts.js";import{s as n,z as r}from"./sdk-batch-runner.js";import{p as i}from"./device.js";import a from"node:path";import{scryptSync as o}from"node:crypto";import s from"node:fs";import ee from"node:os";import c from"@limrun/api";import{createInstanceClient as l}from"@limrun/api/instance-client";import{createInstanceClient as te}from"@limrun/api/ios-client";import{setTimeout as u}from"node:timers/promises";const d=`limrun`,f=d;function p(e){if(e===`ios-instance`)return`ios`;if(e===`android-instance`)return`android`}function m(e,t,n){return{platform:e===`ios`?`apple`:`android`,...e===`ios`?{appleOs:`ios`}:{},id:ne(e,t.leaseId),name:`Limrun ${e} ${n.slice(0,8)}`,kind:e===`ios`?`simulator`:`emulator`,target:`mobile`,booted:!0}}function h(e){let[t,n,r]=e.split(`:`);if(t===f&&!(n!==`ios`&&n!==`android`)&&r)return{platform:n,leaseId:r}}function ne(e,t){return`${f}:${e}:${t}`}function g(e){return e?.trim()||void 0}async function _(e,t){let n=await l({apiUrl:e.apiUrl,adbUrl:e.adbUrl,token:e.token,logLevel:`warn`}),r={platform:`android`,lease:e.lease,instanceId:e.instanceId,device:e.device,client:n,dependencies:t},i={exec:async(e,t)=>await C(r,e,t),text:async e=>{await n.setText(e.target,e.text)}};return i.reverse=await t.android.createPortReverse(i.exec),Object.assign(r,{adbProvider:i})}function v(e){return e.dependencies.android.createInteractor(e.device,e.adbProvider)}async function y(e,t,n,r){let i=g(r?.packageNameHint);r?.relaunch&&i&&await C(t,[`shell`,`am`,`force-stop`,i],{allowFailure:!0});let a=await e.assets.getOrUpload({path:n,name:se(i,n)});await t.client.sendAsset(a.signedDownloadUrl);let o=i?await t.dependencies.android.inferAppName(i):void 0;return{...i?{packageName:i,launchTarget:i}:{},...o?{appName:o}:{}}}async function b(e,t){await e.adbProvider.reverse?.ensure({local:w(t.devicePort),remote:w(t.hostPort),ownerId:t.name})}async function x(e){await e.adbTunnelPromise?.catch(()=>{});let t=e.adbSerial;t&&(await S(e),await e.dependencies.host.runAdb([`disconnect`,t],{allowFailure:!0,timeoutMs:1e4}).catch(()=>{})),e.adbTunnel?.close(),e.adbTunnel=void 0,e.adbSerial=void 0,e.adbTunnelPromise=void 0}async function S(e){let t=e.adbProvider.reverse;if(!t?.list)return;let n=await t.list().catch(()=>[]),r=new Set,i=[];for(let e of n)e.ownerId?r.add(e.ownerId):i.push(e.local);await Promise.allSettled([...[...r].map(async e=>await t.removeAllOwned(e)),...i.map(async e=>await t.remove(e))])}async function C(e,t,n){let{adbArgs:r,result:i}=await re(e,t,n);return await ie(r,i,n?.allowFailure,e.dependencies)}async function re(e,t,n){let r=[`-s`,await ae(e),...t];return{adbArgs:r,result:await e.dependencies.host.runAdb(r,{allowFailure:n?.allowFailure,binaryStdout:n?.binaryStdout,stdin:n?.stdin,timeoutMs:n?.timeoutMs??3e4,signal:n?.signal})}}async function ie(e,t,n,r){if(t.exitCode!==0&&n!==!0)throw await r.android.adbError(`Limrun Android ADB command failed`,t,{command:[`adb`,...e].join(` `)});return t}async function ae(e){if(e.adbSerial)return e.adbSerial;let t=e.adbTunnelPromise??oe(e);e.adbTunnelPromise=t;try{return await t}catch(n){throw e.adbTunnelPromise===t&&(e.adbTunnelPromise=void 0),n}}async function oe(e){let t=await e.client.startAdbTunnel(),n=`${t.address.address}:${t.address.port}`;return e.adbTunnel=t,e.adbSerial=n,n}function w(e){if(!Number.isInteger(e)||e<1||e>65535)throw new t(`INVALID_ARGS`,`Invalid Android tcp reverse port: ${e}`);return`tcp:${e}`}function se(e,t){let n=a.extname(t)||`.apk`;return`${e?.replace(/[^a-zA-Z0-9_.-]+/g,`-`)||`android-app`}${n}`}function T(e){let t=Array.isArray(e)?e:[e],n=[],r=(e,t,i)=>{let a=n.length;n.push(E(e,{index:a,depth:t,parentIndex:i}));for(let n of N(e))r(n,t+1,a)};for(let e of t)r(e,0);return n}function E(e,t){return{index:t.index,type:D(e),role:O(e),label:k(e),value:A(e),identifier:j(e),rect:M(e),enabled:e.enabled,selected:e.selected,hittable:e.hittable,depth:t.depth,parentIndex:t.parentIndex}}function D(e){return e.elementType??e.type}function O(e){return e.role??D(e)}function k(e){return e.label??e.AXLabel??void 0}function A(e){return e.value??e.AXValue??void 0}function j(e){return e.identifier??e.AXUniqueId??void 0}function M(e){let t=e.rect??e.frame;if(!(!t||typeof t.x!=`number`||typeof t.y!=`number`||typeof t.width!=`number`||typeof t.height!=`number`))return{x:t.x,y:t.y,width:t.width,height:t.height}}function N(e){return e.children??e.nodes??e.elements??[]}function P(e){return e.key===`id`?{accessibilityId:e.value}:e.key===`value`?{value:e.value}:{label:e.value}}async function F(e,t){s.mkdirSync(a.dirname(e),{recursive:!0}),await s.promises.writeFile(e,Buffer.from(t,`base64`))}async function I(e,t){let n=await te({apiUrl:e.apiUrl,token:e.token,logLevel:`warn`});return{platform:`ios`,lease:e.lease,instanceId:e.instanceId,device:e.device,client:n,dependencies:t}}async function L(e,t,n,r){let i=await ce(n,t.dependencies);try{let n=await e.assets.getOrUpload({path:i.uploadPath,name:i.assetName}),a=(await R(t,n.signedDownloadUrl,{md5:n.md5,relaunch:r?.relaunch,appIdentifierHint:r?.appIdentifierHint})).appId;return{...a?{bundleId:a,launchTarget:a}:{},...i.appName?{appName:i.appName}:{}}}finally{await i.cleanup()}}async function R(e,n,r){let i=await e.client.listApps().catch(()=>void 0),a=g((await e.client.installApp(n,{md5:r?.md5,launchMode:r?.relaunch?`RelaunchIfRunning`:`ForegroundIfRunning`})).bundleId),o=g(r?.appIdentifierHint),s=[];for(let t of H){t>0&&await u(t),s=await e.client.listApps();let n=U({resultBundleId:a,requestedBundleId:o,beforeInstallApps:i,afterInstallApps:s});if(n)return{appId:n}}throw new t(`COMMAND_FAILED`,`Limrun iOS app installation could not be verified.`,{resultBundleId:a,requestedBundleId:o,installedUserApps:s.filter(G).map(e=>e.bundleId).sort()})}function z(e){return new B(e)}var B=class{session;constructor(e){this.session=e}async open(e,t){if(t?.url){await this.session.client.launchApp(await this.session.dependencies.ios.resolveAppAlias(e)),await this.session.client.openUrl(t.url);return}if(n(e)){await this.session.client.openUrl(e);return}await this.session.client.launchApp(await this.session.dependencies.ios.resolveAppAlias(e))}async openDevice(){}async close(e){e&&await this.session.client.terminateApp(await this.session.dependencies.ios.resolveAppAlias(e)).catch(()=>{})}async tap(e,t){await this.session.client.tap(e,t)}async tapElementSelector(e){await this.session.client.tapElement(P(e))}async doubleTap(e,t){await this.tap(e,t),await this.tap(e,t)}async longPress(){throw K(`longpress`,`Limrun iOS direct sessions do not expose long press yet.`)}async focus(e,t){await this.tap(e,t)}async type(e,t){if(t&&t>0){for(let n of Array.from(e))await this.session.client.typeText(n),await u(t);return}await this.session.client.typeText(e)}async fill(e,t,n){await this.tap(e,t),await this.session.client.typeText(n)}async fillElementSelector(e,t){await this.session.client.setElementValue(t,P(e))}async scroll(e,t){await this.session.client.scroll(e,t?.pixels??300)}async screenshot(e){await F(e,(await this.session.client.screenshot()).base64)}async snapshot(e){let t=await this.session.client.elementTree();return{nodes:T(JSON.parse(t)),backend:`xctest`}}async back(){await this.session.client.pressKey(`escape`)}async home(){throw K(`home`,`Limrun iOS direct sessions do not expose home yet.`)}async setOrientation(e){if(e===`portrait-upside-down`)throw K(`orientation`,`Limrun iOS direct sessions support portrait and landscape orientation, not portrait upside-down.`);await this.session.client.setOrientation(e===`portrait`?`Portrait`:`Landscape`)}async performGesture(){throw K(`gesture`,`Limrun iOS direct sessions do not expose portable gesture execution yet.`)}async appSwitcher(){throw K(`app-switcher`,`Limrun iOS direct sessions do not expose app switcher yet.`)}async tvRemote(){throw K(`tv-remote`,`Limrun iOS direct sessions do not expose tv remote control.`)}async readClipboard(){throw K(`clipboard`,`Limrun iOS direct sessions do not expose clipboard read yet.`)}async writeClipboard(){throw K(`clipboard`,`Limrun iOS direct sessions do not expose clipboard write yet.`)}async setSetting(){throw K(`settings`,`Limrun iOS direct sessions do not expose settings changes yet.`)}};async function ce(e,t){if(!(await s.promises.stat(e)).isDirectory())return{uploadPath:e,assetName:a.basename(e),appName:V(e),cleanup:async()=>{}};let n=await s.promises.mkdtemp(a.join(ee.tmpdir(),`agent-device-limrun-ios-app-`)),r=a.join(n,`${a.basename(e)}.zip`);try{await t.host.archiveDirectory({sourceDirectory:a.dirname(e),entryName:a.basename(e),archivePath:r})}catch(e){throw await s.promises.rm(n,{recursive:!0,force:!0}),e}return{uploadPath:r,assetName:a.basename(r),appName:await t.ios.readBundleAppName(e)??V(e),cleanup:async()=>{await s.promises.rm(n,{recursive:!0,force:!0})}}}function V(e){return a.basename(e).replace(/\.(?:app|ipa|apk|aab|zip)$/i,``)||void 0}const H=[0,250];function U(e){let t=new Set(e.afterInstallApps.map(e=>e.bundleId));return(e.resultBundleId&&t.has(e.resultBundleId)?e.resultBundleId:void 0)??(e.requestedBundleId&&t.has(e.requestedBundleId)?e.requestedBundleId:void 0)??W(e.beforeInstallApps,e.afterInstallApps)}function W(e,t){if(!e)return;let n=new Set(e.map(e=>e.bundleId)),r=t.filter(e=>G(e)&&!n.has(e.bundleId));return r.length===1?r[0]?.bundleId:void 0}function G(e){return!e.bundleId.startsWith(`com.apple.`)&&!e.installType.toLowerCase().includes(`system`)}function K(e,n){throw new t(`UNSUPPORTED_OPERATION`,n,{command:e})}function q(e){return e.platform===`android`?le(e):ue(e)}function le(e){let t=e.adbProvider.exec;return{platform:`android`,device:e.device,interactor:v(e),adb:e.adbProvider,listApps:async n=>await e.dependencies.android.listApps(t,i(n)),getForegroundApp:async()=>await e.dependencies.android.getForegroundApp(t),pressKey:async(t,n)=>{await e.client.pressKey(t,n)},getKeyboardState:async()=>await e.dependencies.android.getKeyboardState(t),dismissKeyboard:async()=>await e.dependencies.android.dismissKeyboard(t),readLogs:async n=>await e.dependencies.android.readLogs(t,n),...J(e.client),installRemoteApp:async t=>{await e.client.sendAsset(t)}}}function ue(e){return{platform:`ios`,device:e.device,interactor:z(e),viewport:{width:e.client.deviceInfo.screenWidth,height:e.client.deviceInfo.screenHeight},listApps:async t=>(await e.client.listApps()).filter(e=>i(t)===`all`||G(e)).map(e=>({id:e.bundleId,name:e.name,installType:e.installType})).sort((e,t)=>e.id.localeCompare(t.id)),pressKey:async(t,n)=>{await e.client.pressKey(t,n)},readLogs:async(t,n)=>await e.client.appLogTail(t,n),...J(e.client),installRemoteApp:async(t,n)=>await R(e,t,n),runSimctl:t=>e.client.simctl(t)}}function J(e){return{startRecording:async t=>{await e.startRecording(t)},stopRecording:async({outPath:t})=>await e.stopRecording({localPath:t})}}const Y=`agent-device-cli`;function X(e){return{apiKey:e.apiKey,defaultHeaders:{"x-agent-device-client":Y,"x-agent-device-version":e.clientVersion}}}function de(e){if(e.runtimeInstance!==void 0){let t=e.runtimeInstance.trim();if(!t)throw TypeError(`Limrun runtimeInstance must be a non-empty string`);return t}return`principal-${o(JSON.stringify({provider:`limrun`,region:e.region?.trim().toLowerCase()||`default`,apiKey:e.apiKey}),`agent-device:limrun-runtime-owner:v1`,32,{N:16384,r:8,p:1,maxmem:67108864}).toString(`hex`)}`}function Z(e,t,n){let i=new Q(e,t);if(!n?.includePlatformModule)return i;let a=r(d,de(e));if(a.kind!==`provider-runtime`)throw TypeError(`Invalid Limrun runtime owner`);return Object.freeze({runtime:i,platformModule:Object.freeze({owner:a,loadRuntime:async e=>await fe(i,a.instance,e)})})}var Q=class{limrun;sessions=new Map;options;dependencies;provider=d;leaseLifecycle={allocate:async e=>await this.allocate(e),release:async e=>await this.release(e)};recoverExpiredLease=async e=>{if(e.leaseProvider!==this.provider||!p(e.backend))throw new t(`UNSUPPORTED_OPERATION`,`Limrun cannot recover this expired lease.`,{leaseId:e.leaseId,leaseProvider:e.leaseProvider,leaseBackend:e.backend});await this.release(e)};deviceInventoryProvider=async e=>{if(e.leaseProvider!==this.provider||!e.leaseId)return null;let t=this.sessions.get(e.leaseId);return t?e.platform&&e.platform!==t.platform?[]:[t.device]:null};constructor(e,t){this.options=e,this.dependencies=t,this.limrun=new c(X({apiKey:e.apiKey,clientVersion:t.clientVersion}))}ownsDevice(e){return h(e.id)!==void 0}getInteractor(e){let t=this.getSessionForDevice(e);if(t)return t.platform===`ios`?z(t):v(t)}getDeviceSession(e){let t=this.getSessionForDevice(e);return t?q(t):void 0}async installApp(e,t,n,r){return await this.installInstallablePath(e,n,{...r,appIdentifierHint:r?.appIdentifierHint??t,packageNameHint:r?.packageNameHint??t})}async installInstallablePath(e,t,n){let r=this.getSessionForDevice(e);if(r)return r.platform===`ios`?await L(this.limrun,r,t,n):await y(this.limrun,r,t,n)}async configurePortReverse(e){let t=this.requireAndroidPortReverseSession(e.leaseId);if(t)return await b(t,e),pe(e)}async shutdown(){let e=[...this.sessions.values()];await Promise.allSettled(e.map(async e=>await this.terminateSession(e))),this.sessions.clear()}async allocate(e){if(e.leaseProvider!==this.provider)return;let t=p(e.backend);if(!t)return;let n=this.sessions.get(e.leaseId);if(n)return{limrunInstanceId:n.instanceId,device:n.device};let r=t===`ios`?await this.createIosSession(e):await this.createAndroidSession(e);return this.sessions.set(e.leaseId,r),{limrunInstanceId:r.instanceId,device:r.device}}async createIosSession(e){let n=await this.limrun.iosInstances.create({wait:!0,metadata:this.buildInstanceMetadata(e),spec:this.options.region?{region:this.options.region}:{}});try{if(!n.status.apiUrl)throw new t(`COMMAND_FAILED`,`Limrun iOS instance did not expose apiUrl`);return await I({lease:e,instanceId:n.metadata.id,device:m(`ios`,e,n.metadata.id),apiUrl:n.status.apiUrl,token:n.status.token},this.dependencies)}catch(e){throw await this.limrun.iosInstances.delete(n.metadata.id).catch(()=>{}),e}}async createAndroidSession(e){let n=await this.limrun.androidInstances.create({wait:!0,metadata:this.buildInstanceMetadata(e),spec:this.options.region?{region:this.options.region}:{}});try{if(!n.status.apiUrl||!n.status.adbWebSocketUrl)throw new t(`COMMAND_FAILED`,`Limrun Android instance did not expose API and ADB websocket endpoints`);return await _({lease:e,instanceId:n.metadata.id,device:m(`android`,e,n.metadata.id),apiUrl:n.status.apiUrl,adbUrl:n.status.adbWebSocketUrl,token:n.status.token},this.dependencies)}catch(e){throw await this.limrun.androidInstances.delete(n.metadata.id).catch(()=>{}),e}}buildInstanceMetadata(e){return{displayName:`agent-device-${e.tenantId}-${e.runId}`,labels:{tenantId:e.tenantId,runId:e.runId,leaseId:e.leaseId,provider:e.leaseProvider??`limrun`,source:Y}}}async release(e){let t=this.sessions.get(e.leaseId);return t?(await this.terminateSession(t),this.sessions.delete(e.leaseId),{limrunInstanceId:t.instanceId}):await this.releaseRecoveredSession(e)}async releaseRecoveredSession(e){let t=p(e.backend);if(!t)return;let n=`provider=${d},leaseId=${e.leaseId}`,r=(t===`ios`?await this.limrun.iosInstances.list({labelSelector:n}):await this.limrun.androidInstances.list({labelSelector:n})).getPaginatedItems().map(e=>e.metadata.id);for(let e of r)t===`ios`?await this.limrun.iosInstances.delete(e):await this.limrun.androidInstances.delete(e);if(r.length!==0)return{limrunInstanceId:r[0],limrunInstanceCount:r.length}}async terminateSession(e){if(e.client.disconnect(),e.platform===`ios`){await this.limrun.iosInstances.delete(e.instanceId);return}await x(e),await this.limrun.androidInstances.delete(e.instanceId)}getSessionForDevice(e){let t=h(e.id);if(!t)return;let n=this.sessions.get(t.leaseId);return n?.platform===t.platform?n:void 0}currentAppLogReader(e){let t=this.getSessionForDevice(e);if(!t)return;let n=q(t);return{platform:t.platform,leaseId:t.lease.leaseId,instanceId:t.instanceId,readLogs:async(e,t)=>n.platform===`ios`?await n.readLogs(e,t):await n.readLogs(t),[Symbol.asyncDispose]:async()=>void 0}}async reconnectAppLogReader(e,t){let{reconnectLimrunAppLogReader:n}=await import(`./app-log-reconnect.js`);return await n({limrun:this.limrun,descriptor:e,dependencies:this.dependencies,signal:t})}requireAndroidPortReverseSession(e){let t=this.sessions.get(e);if(!t||t.platform===`android`)return t;throw me(`port reverse`,`Direct Limrun iOS sessions cannot reach local host ports; use a bridge public URL.`)}};async function fe(e,t,n){let{createLimrunPlatformRuntimeOwner:r}=await import(`./app-log-runtime.js`);return r({host:n,runtimeInstance:t,ownsDevice:t=>e.ownsDevice(t),openCurrent:async t=>e.currentAppLogReader(t),reconnect:async(t,n)=>await e.reconnectAppLogReader(t,n)})}function pe(e){return{leaseId:e.leaseId,devicePort:e.devicePort,hostPort:e.hostPort,name:e.name}}function me(e,n){throw new t(`UNSUPPORTED_OPERATION`,n,{command:e})}async function $(e){let n=new c({...X(e),timeout:15e3,maxRetries:0}),r={limit:1,...e.region?{region:e.region}:{}};try{e.platform===`android`?await n.androidInstances.list(r):await n.iosInstances.list(r)}catch(e){let n=he(e);throw n===401||n===403?new t(`UNAUTHORIZED`,`Limrun rejected connection verification.`,{status:n,hint:`Check LIMRUN_API_KEY and its organization access.`}):new t(`COMMAND_FAILED`,`Limrun connection verification failed.`,{hint:`Check Limrun service access, LIMRUN_REGION, and network connectivity, then retry.`},e)}let i=e.platform===`android`?`Android`:`iOS`,a=e.platform===`android`?`emulator`:`simulator`;return{provider:`limrun`,service:`Limrun`,verificationMessage:`Credentials and ${i} instance access verified.`,device:{status:`deferred`,name:`Provider-selected ${i} ${a}`,platform:e.platform},app:{status:`missing`,message:`A new Limrun instance does not have your app yet.`}}}function he(e){if(!e||typeof e!=`object`)return;let t=e.status;return typeof t==`number`?t:void 0}var ge=e({LIMRUN_PROVIDER:()=>d,createLimrunRuntime:()=>Z,verifyLimrunConnection:()=>$});export{h as a,d as i,$ as n,Z as r,ge as t};
1
+ import{n as e}from"./rolldown-runtime.js";import{_ as t}from"./sdk-contracts.js";import{K as n,St as r}from"./sdk-batch-runner.js";import{p as i}from"./device.js";import a from"node:path";import{scryptSync as o}from"node:crypto";import s from"node:fs";import c from"node:os";import l from"@limrun/api";import{createInstanceClient as u}from"@limrun/api/instance-client";import{createInstanceClient as ee}from"@limrun/api/ios-client";import{setTimeout as d}from"node:timers/promises";const f=`limrun`,p=f;function m(e){if(e===`ios-instance`)return`ios`;if(e===`android-instance`)return`android`}function h(e,t,n){return{platform:e===`ios`?`apple`:`android`,...e===`ios`?{appleOs:`ios`}:{},id:_(e,t.leaseId),name:`Limrun ${e} ${n.slice(0,8)}`,kind:e===`ios`?`simulator`:`emulator`,target:`mobile`,booted:!0}}function g(e){let[t,n,r]=e.split(`:`);if(t===p&&!(n!==`ios`&&n!==`android`)&&r)return{platform:n,leaseId:r}}function _(e,t){return`${p}:${e}:${t}`}function v(e){return e?.trim()||void 0}async function y(e,t,n=`Limrun provider operation aborted`,r){if(!t)try{return await e}finally{r?.()}return await new Promise((i,a)=>{let o=()=>a(t.reason??Error(n));if(t.aborted){e.then(e=>{r?.(),i(e)},e=>{r?.(),a(e)}),o();return}t.addEventListener(`abort`,o,{once:!0}),e.then(e=>{t.removeEventListener(`abort`,o),r?.(),i(e)},e=>{t.removeEventListener(`abort`,o),r?.(),a(e)})})}function te(){let e=new Set;return{wait:async(t,n,r)=>{let i,a=new Promise(e=>{i=e});return e.add(a),a.then(()=>e.delete(a)),await y(t,n,r,i)},[Symbol.asyncDispose]:async()=>{for(;e.size>0;)await Promise.all(e)}}}async function b(e,t,n,r){return await(e?e.wait(t,n,r):y(t,n,r))}async function x(e,t){let n=await u({apiUrl:e.apiUrl,adbUrl:e.adbUrl,token:e.token,logLevel:`warn`}),r={platform:`android`,lease:e.lease,instanceId:e.instanceId,device:e.device,client:n,dependencies:t},i={exec:async(e,t)=>await T(r,e,t),text:async e=>{await n.setText(e.target,e.text)}};return i.reverse=await t.android.createPortReverse(i.exec),Object.assign(r,{adbProvider:i})}function S(e){return e.dependencies.android.createInteractor(e.device,e.adbProvider)}async function C(e,t,n,r,i,a){i?.throwIfAborted();let o=v(r?.packageNameHint);r?.relaunch&&o&&await T(t,[`shell`,`am`,`force-stop`,o],{allowFailure:!0,signal:i});let s=await b(a,e.assets.getOrUpload({path:n,name:ce(o,n)},{signal:i}),i);await b(a,t.client.sendAsset(s.signedDownloadUrl),i),i?.throwIfAborted();let c=o?await t.dependencies.android.inferAppName(o):void 0;return{...o?{packageName:o,launchTarget:o}:{},...c?{appName:c}:{}}}async function w(e,t){await e.adbProvider.reverse?.ensure({local:E(t.devicePort),remote:E(t.hostPort),ownerId:t.name})}async function ne(e){await e.adbTunnelPromise?.catch(()=>{});let t=e.adbSerial;t&&(await re(e),await e.dependencies.host.runAdb([`disconnect`,t],{allowFailure:!0,timeoutMs:1e4}).catch(()=>{})),e.adbTunnel?.close(),e.adbTunnel=void 0,e.adbSerial=void 0,e.adbTunnelPromise=void 0}async function re(e){let t=e.adbProvider.reverse;if(!t?.list)return;let n=await t.list().catch(()=>[]),r=new Set,i=[];for(let e of n)e.ownerId?r.add(e.ownerId):i.push(e.local);await Promise.allSettled([...[...r].map(async e=>await t.removeAllOwned(e)),...i.map(async e=>await t.remove(e))])}async function T(e,t,n){let{adbArgs:r,result:i}=await ie(e,t,n);return await ae(r,i,n?.allowFailure,e.dependencies)}async function ie(e,t,n){let r=[`-s`,await oe(e),...t];return{adbArgs:r,result:await e.dependencies.host.runAdb(r,{allowFailure:n?.allowFailure,binaryStdout:n?.binaryStdout,stdin:n?.stdin,timeoutMs:n?.timeoutMs??3e4,signal:n?.signal})}}async function ae(e,t,n,r){if(t.exitCode!==0&&n!==!0)throw await r.android.adbError(`Limrun Android ADB command failed`,t,{command:[`adb`,...e].join(` `)});return t}async function oe(e){if(e.adbSerial)return e.adbSerial;let t=e.adbTunnelPromise??se(e);e.adbTunnelPromise=t;try{return await t}catch(n){throw e.adbTunnelPromise===t&&(e.adbTunnelPromise=void 0),n}}async function se(e){let t=await e.client.startAdbTunnel(),n=`${t.address.address}:${t.address.port}`;return e.adbTunnel=t,e.adbSerial=n,n}function E(e){if(!Number.isInteger(e)||e<1||e>65535)throw new t(`INVALID_ARGS`,`Invalid Android tcp reverse port: ${e}`);return`tcp:${e}`}function ce(e,t){let n=a.extname(t)||`.apk`;return`${e?.replace(/[^a-zA-Z0-9_.-]+/g,`-`)||`android-app`}${n}`}function D(e){let t=Array.isArray(e)?e:[e],n=[],r=(e,t,i)=>{let a=n.length;n.push(O(e,{index:a,depth:t,parentIndex:i}));for(let n of F(e))r(n,t+1,a)};for(let e of t)r(e,0);return n}function O(e,t){return{index:t.index,type:k(e),role:A(e),label:j(e),value:M(e),identifier:N(e),rect:P(e),enabled:e.enabled,selected:e.selected,hittable:e.hittable,depth:t.depth,parentIndex:t.parentIndex}}function k(e){return e.elementType??e.type}function A(e){return e.role??k(e)}function j(e){return e.label??e.AXLabel??void 0}function M(e){return e.value??e.AXValue??void 0}function N(e){return e.identifier??e.AXUniqueId??void 0}function P(e){let t=e.rect??e.frame;if(!(!t||typeof t.x!=`number`||typeof t.y!=`number`||typeof t.width!=`number`||typeof t.height!=`number`))return{x:t.x,y:t.y,width:t.width,height:t.height}}function F(e){return e.children??e.nodes??e.elements??[]}function I(e){return e.key===`id`?{accessibilityId:e.value}:e.key===`value`?{value:e.value}:{label:e.value}}async function L(e,t){s.mkdirSync(a.dirname(e),{recursive:!0}),await s.promises.writeFile(e,Buffer.from(t,`base64`))}async function R(e,t){let n=await ee({apiUrl:e.apiUrl,token:e.token,logLevel:`warn`});return{platform:`ios`,lease:e.lease,instanceId:e.instanceId,device:e.device,client:n,dependencies:t}}async function z(e,t,n,r,i,a){i?.throwIfAborted();let o=await le(n,t.dependencies);try{i?.throwIfAborted();let n=await b(a,e.assets.getOrUpload({path:o.uploadPath,name:o.assetName},{signal:i}),i),s=(await B(t,n.signedDownloadUrl,{md5:n.md5,relaunch:r?.relaunch,appIdentifierHint:r?.appIdentifierHint},i,a)).appId;return{...s?{bundleId:s,launchTarget:s}:{},...o.appName?{appName:o.appName}:{}}}finally{await o.cleanup()}}async function B(e,n,r,i,a){i?.throwIfAborted();let o=await b(a,e.client.listApps(),i).catch(e=>{if(i?.aborted)throw e}),s=v((await b(a,e.client.installApp(n,{md5:r?.md5,launchMode:r?.relaunch?`RelaunchIfRunning`:`ForegroundIfRunning`}),i)).bundleId),c=v(r?.appIdentifierHint),l=[];for(let t of W){t>0&&await d(t,void 0,{signal:i}),l=await b(a,e.client.listApps(),i);let n=ue({resultBundleId:s,requestedBundleId:c,beforeInstallApps:o,afterInstallApps:l});if(n)return{appId:n}}throw new t(`COMMAND_FAILED`,`Limrun iOS app installation could not be verified.`,{resultBundleId:s,requestedBundleId:c,installedUserApps:l.filter(G).map(e=>e.bundleId).sort()})}function V(e){return new H(e)}var H=class{session;constructor(e){this.session=e}async open(e,t){if(t?.url){await this.session.client.launchApp(await this.session.dependencies.ios.resolveAppAlias(e)),await this.session.client.openUrl(t.url);return}if(n(e)){await this.session.client.openUrl(e);return}await this.session.client.launchApp(await this.session.dependencies.ios.resolveAppAlias(e))}async openDevice(){}async close(e){e&&await this.session.client.terminateApp(await this.session.dependencies.ios.resolveAppAlias(e)).catch(()=>{})}async tap(e,t){await this.session.client.tap(e,t)}async tapElementSelector(e){await this.session.client.tapElement(I(e))}async doubleTap(e,t){await this.tap(e,t),await this.tap(e,t)}async longPress(){throw K(`longpress`,`Limrun iOS direct sessions do not expose long press yet.`)}async focus(e,t){await this.tap(e,t)}async type(e,t){if(t&&t>0){for(let n of Array.from(e))await this.session.client.typeText(n),await d(t);return}await this.session.client.typeText(e)}async fill(e,t,n){await this.tap(e,t),await this.session.client.typeText(n)}async fillElementSelector(e,t){await this.session.client.setElementValue(t,I(e))}async scroll(e,t){await this.session.client.scroll(e,t?.pixels??300)}async screenshot(e){await L(e,(await this.session.client.screenshot()).base64)}async snapshot(e){let t=await this.session.client.elementTree();return{nodes:D(JSON.parse(t)),backend:`xctest`}}async back(){await this.session.client.pressKey(`escape`)}async home(){throw K(`home`,`Limrun iOS direct sessions do not expose home yet.`)}async setOrientation(e){if(e===`portrait-upside-down`)throw K(`orientation`,`Limrun iOS direct sessions support portrait and landscape orientation, not portrait upside-down.`);await this.session.client.setOrientation(e===`portrait`?`Portrait`:`Landscape`)}async performGesture(){throw K(`gesture`,`Limrun iOS direct sessions do not expose portable gesture execution yet.`)}async appSwitcher(){throw K(`app-switcher`,`Limrun iOS direct sessions do not expose app switcher yet.`)}async tvRemote(){throw K(`tv-remote`,`Limrun iOS direct sessions do not expose tv remote control.`)}async readClipboard(){throw K(`clipboard`,`Limrun iOS direct sessions do not expose clipboard read yet.`)}async writeClipboard(){throw K(`clipboard`,`Limrun iOS direct sessions do not expose clipboard write yet.`)}async setSetting(){throw K(`settings`,`Limrun iOS direct sessions do not expose settings changes yet.`)}};async function le(e,t){if(!(await s.promises.stat(e)).isDirectory())return{uploadPath:e,assetName:a.basename(e),appName:U(e),cleanup:async()=>{}};let n=await s.promises.mkdtemp(a.join(c.tmpdir(),`agent-device-limrun-ios-app-`)),r=a.join(n,`${a.basename(e)}.zip`);try{await t.host.archiveDirectory({sourceDirectory:a.dirname(e),entryName:a.basename(e),archivePath:r})}catch(e){throw await s.promises.rm(n,{recursive:!0,force:!0}),e}return{uploadPath:r,assetName:a.basename(r),appName:await t.ios.readBundleAppName(e)??U(e),cleanup:async()=>{await s.promises.rm(n,{recursive:!0,force:!0})}}}function U(e){return a.basename(e).replace(/\.(?:app|ipa|apk|aab|zip)$/i,``)||void 0}const W=[0,250];function ue(e){let t=new Set(e.afterInstallApps.map(e=>e.bundleId));return(e.resultBundleId&&t.has(e.resultBundleId)?e.resultBundleId:void 0)??(e.requestedBundleId&&t.has(e.requestedBundleId)?e.requestedBundleId:void 0)??de(e.beforeInstallApps,e.afterInstallApps)}function de(e,t){if(!e)return;let n=new Set(e.map(e=>e.bundleId)),r=t.filter(e=>G(e)&&!n.has(e.bundleId));return r.length===1?r[0]?.bundleId:void 0}function G(e){return!e.bundleId.startsWith(`com.apple.`)&&!e.installType.toLowerCase().includes(`system`)}function K(e,n){throw new t(`UNSUPPORTED_OPERATION`,n,{command:e})}function q(e){return e.platform===`android`?fe(e):pe(e)}function fe(e){let t=e.adbProvider.exec;return{platform:`android`,device:e.device,interactor:S(e),adb:e.adbProvider,listApps:async n=>await e.dependencies.android.listApps(t,i(n)),getForegroundApp:async n=>await e.dependencies.android.getForegroundApp(e.device,t,n),pressKey:async(t,n)=>{await e.client.pressKey(t,n)},getKeyboardState:async()=>await e.dependencies.android.getKeyboardState(t),dismissKeyboard:async()=>await e.dependencies.android.dismissKeyboard(t),readLogs:async n=>await e.dependencies.android.readLogs(t,n),...J(e.client),installRemoteApp:async t=>{await e.client.sendAsset(t)}}}function pe(e){return{platform:`ios`,device:e.device,interactor:V(e),viewport:{width:e.client.deviceInfo.screenWidth,height:e.client.deviceInfo.screenHeight},listApps:async t=>(await e.client.listApps()).filter(e=>i(t)===`all`||G(e)).map(e=>({id:e.bundleId,name:e.name,installType:e.installType})).sort((e,t)=>e.id.localeCompare(t.id)),pressKey:async(t,n)=>{await e.client.pressKey(t,n)},readLogs:async(t,n)=>await e.client.appLogTail(t,n),...J(e.client),installRemoteApp:async(t,n)=>await B(e,t,n),runSimctl:t=>e.client.simctl(t)}}function J(e){return{startRecording:async t=>{await e.startRecording(t)},stopRecording:async({outPath:t})=>await e.stopRecording({localPath:t})}}const Y=`agent-device-cli`;function X(e){return{apiKey:e.apiKey,defaultHeaders:{"x-agent-device-client":Y,"x-agent-device-version":e.clientVersion}}}function me(e){if(e.runtimeInstance!==void 0){let t=e.runtimeInstance.trim();if(!t)throw TypeError(`Limrun runtimeInstance must be a non-empty string`);return t}return`principal-${o(JSON.stringify({provider:`limrun`,region:e.region?.trim().toLowerCase()||`default`,apiKey:e.apiKey}),`agent-device:limrun-runtime-owner:v1`,32,{N:16384,r:8,p:1,maxmem:67108864}).toString(`hex`)}`}function Z(e,t,n){let i=new he(e,t);if(!n?.includePlatformModule)return i;let a=r(f,me(e));if(a.kind!==`provider-runtime`)throw TypeError(`Invalid Limrun runtime owner`);return Object.freeze({runtime:i,platformModule:Object.freeze({owner:a,loadRuntime:async e=>await ge(i,a.instance,e)})})}var he=class{limrun;sessions=new Map;options;dependencies;provider=f;leaseLifecycle={allocate:async e=>await this.allocate(e),release:async e=>await this.release(e)};recoverExpiredLease=async e=>{if(e.leaseProvider!==this.provider||!m(e.backend))throw new t(`UNSUPPORTED_OPERATION`,`Limrun cannot recover this expired lease.`,{leaseId:e.leaseId,leaseProvider:e.leaseProvider,leaseBackend:e.backend});await this.release(e)};deviceInventoryProvider=async e=>{if(e.leaseProvider!==this.provider||!e.leaseId)return null;let t=this.sessions.get(e.leaseId);return t?e.platform&&e.platform!==t.platform?[]:[t.device]:null};constructor(e,t){this.options=e,this.dependencies=t,this.limrun=new l(X({apiKey:e.apiKey,clientVersion:t.clientVersion}))}ownsDevice(e){return g(e.id)!==void 0}hasLiveSession(e){return this.getSessionForDevice(e)!==void 0}getInteractor(e,t){let n=this.getSessionForDevice(e);if(n)return n.platform===`ios`?V(n):S(n)}getDeviceSession(e){let t=this.getSessionForDevice(e);return t?q(t):void 0}async installApp(e,t,n,r,i,a){return await this.installInstallablePath(e,n,{...r,appIdentifierHint:r?.appIdentifierHint??t,packageNameHint:r?.packageNameHint??t},i,a)}async installInstallablePath(e,t,n,r,i){let a=this.getSessionForDevice(e);if(a)return a.platform===`ios`?await z(this.limrun,a,t,n,r,i):await C(this.limrun,a,t,n,r,i)}async configurePortReverse(e){let t=this.requireAndroidPortReverseSession(e.leaseId);if(t)return await w(t,e),_e(e)}async shutdown(){let e=[...this.sessions.values()];await Promise.allSettled(e.map(async e=>await this.terminateSession(e))),this.sessions.clear()}async allocate(e){if(e.leaseProvider!==this.provider)return;let t=m(e.backend);if(!t)return;let n=this.sessions.get(e.leaseId);if(n)return{limrunInstanceId:n.instanceId,device:n.device};let r=t===`ios`?await this.createIosSession(e):await this.createAndroidSession(e);return this.sessions.set(e.leaseId,r),{limrunInstanceId:r.instanceId,device:r.device}}async createIosSession(e){let n=await this.limrun.iosInstances.create({wait:!0,metadata:this.buildInstanceMetadata(e),spec:this.options.region?{region:this.options.region}:{}});try{if(!n.status.apiUrl)throw new t(`COMMAND_FAILED`,`Limrun iOS instance did not expose apiUrl`);return await R({lease:e,instanceId:n.metadata.id,device:h(`ios`,e,n.metadata.id),apiUrl:n.status.apiUrl,token:n.status.token},this.dependencies)}catch(e){throw await this.limrun.iosInstances.delete(n.metadata.id).catch(()=>{}),e}}async createAndroidSession(e){let n=await this.limrun.androidInstances.create({wait:!0,metadata:this.buildInstanceMetadata(e),spec:this.options.region?{region:this.options.region}:{}});try{if(!n.status.apiUrl||!n.status.adbWebSocketUrl)throw new t(`COMMAND_FAILED`,`Limrun Android instance did not expose API and ADB websocket endpoints`);return await x({lease:e,instanceId:n.metadata.id,device:h(`android`,e,n.metadata.id),apiUrl:n.status.apiUrl,adbUrl:n.status.adbWebSocketUrl,token:n.status.token},this.dependencies)}catch(e){throw await this.limrun.androidInstances.delete(n.metadata.id).catch(()=>{}),e}}buildInstanceMetadata(e){return{displayName:`agent-device-${e.tenantId}-${e.runId}`,labels:{tenantId:e.tenantId,runId:e.runId,leaseId:e.leaseId,provider:e.leaseProvider??`limrun`,source:Y}}}async release(e){let t=this.sessions.get(e.leaseId);return t?(await this.terminateSession(t),this.sessions.delete(e.leaseId),{limrunInstanceId:t.instanceId}):await this.releaseRecoveredSession(e)}async releaseRecoveredSession(e){let t=m(e.backend);if(!t)return;let n=`provider=${f},leaseId=${e.leaseId}`,r=(t===`ios`?await this.limrun.iosInstances.list({labelSelector:n}):await this.limrun.androidInstances.list({labelSelector:n})).getPaginatedItems().map(e=>e.metadata.id);for(let e of r)t===`ios`?await this.limrun.iosInstances.delete(e):await this.limrun.androidInstances.delete(e);if(r.length!==0)return{limrunInstanceId:r[0],limrunInstanceCount:r.length}}async terminateSession(e){if(e.client.disconnect(),e.platform===`ios`){await this.limrun.iosInstances.delete(e.instanceId);return}await ne(e),await this.limrun.androidInstances.delete(e.instanceId)}getSessionForDevice(e){let t=g(e.id);if(!t)return;let n=this.sessions.get(t.leaseId);return n?.platform===t.platform?n:void 0}currentAppLogReader(e){let t=this.getSessionForDevice(e);if(!t)return;let n=q(t);return{platform:t.platform,leaseId:t.lease.leaseId,instanceId:t.instanceId,readLogs:async(e,t)=>n.platform===`ios`?await n.readLogs(e,t):await n.readLogs(t),[Symbol.asyncDispose]:async()=>void 0}}async reconnectAppLogReader(e,t){let{reconnectLimrunAppLogReader:n}=await import(`./app-log-reconnect.js`);return await n({limrun:this.limrun,descriptor:e,dependencies:this.dependencies,signal:t})}requireAndroidPortReverseSession(e){let t=this.sessions.get(e);if(!t||t.platform===`android`)return t;throw Q(`port reverse`,`Direct Limrun iOS sessions cannot reach local host ports; use a bridge public URL.`)}};async function ge(e,n,r){let{createLimrunPlatformRuntimeOwner:i}=await import(`./app-log-runtime.js`);return i({host:r,runtimeInstance:n,ownsDevice:t=>e.ownsDevice(t),hasLiveSession:t=>e.hasLiveSession(t),getInteractor:(t,n)=>e.getInteractor(t,n),openCurrent:async t=>e.currentAppLogReader(t),reconnect:async(t,n)=>await e.reconnectAppLogReader(t,n),listApps:async(n,r,i)=>{i.throwIfAborted();let a=e.getDeviceSession(n);if(!a)throw new t(`DEVICE_NOT_FOUND`,`Limrun app inventory session is unavailable`,{deviceId:n.id});return(await a.listApps(r)).map(e=>({id:e.id,name:e.name??e.id}))},getAppState:async(n,r)=>{r.throwIfAborted();let i=e.getDeviceSession(n);if(i?.platform!==`android`)throw new t(`UNSUPPORTED_OPERATION`,`Limrun Android appstate requires an active provider session`);let a=await i.getForegroundApp(r);return r.throwIfAborted(),{package:a?.appId,activity:a?.activity}},deployApp:async(t,n,r,i)=>await e.installApp(t,n.app,n.appPath,{relaunch:n.replaceExisting,appIdentifierHint:n.app,packageNameHint:n.app},r,i),deployMaterializedApp:async(t,n,r,i)=>await e.installInstallablePath(t,n.artifact.installablePath,{appIdentifierHint:n.artifact.bundleId,packageNameHint:n.artifact.packageName},r,i),configurePortReverse:async t=>await e.configurePortReverse(t)})}function _e(e){return{leaseId:e.leaseId,devicePort:e.devicePort,hostPort:e.hostPort,name:e.name}}function Q(e,n){throw new t(`UNSUPPORTED_OPERATION`,n,{command:e})}async function $(e){let n=new l({...X(e),timeout:15e3,maxRetries:0}),r={limit:1,...e.region?{region:e.region}:{}};try{e.platform===`android`?await n.androidInstances.list(r):await n.iosInstances.list(r)}catch(e){let n=ve(e);throw n===401||n===403?new t(`UNAUTHORIZED`,`Limrun rejected connection verification.`,{status:n,hint:`Check LIMRUN_API_KEY and its organization access.`}):new t(`COMMAND_FAILED`,`Limrun connection verification failed.`,{hint:`Check Limrun service access, LIMRUN_REGION, and network connectivity, then retry.`},e)}let i=e.platform===`android`?`Android`:`iOS`,a=e.platform===`android`?`emulator`:`simulator`;return{provider:`limrun`,service:`Limrun`,verificationMessage:`Credentials and ${i} instance access verified.`,device:{status:`deferred`,name:`Provider-selected ${i} ${a}`,platform:e.platform},app:{status:`missing`,message:`A new Limrun instance does not have your app yet.`}}}function ve(e){if(!e||typeof e!=`object`)return;let t=e.status;return typeof t==`number`?t:void 0}var ye=e({LIMRUN_PROVIDER:()=>f,createLimrunRuntime:()=>Z,verifyLimrunConnection:()=>$});export{te as a,y as i,$ as n,f as o,Z as r,g as s,ye as t};