agent-device 0.21.19 → 0.21.21

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 (369) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.19.apk → agent-device-android-ime-helper-0.21.21.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.21.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.19.manifest.json → agent-device-android-ime-helper-0.21.21.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.19.manifest.json → agent-device-android-snapshot-helper-0.21.21.manifest.json} +6 -6
  7. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AppWindowScreenshot.swift +73 -0
  8. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/BackgroundInteraction.swift +557 -0
  9. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/GhostCursor.swift +141 -0
  10. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/SnapshotTraversal.swift +107 -3
  11. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +136 -22
  12. package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/BackgroundInteractionTests.swift +88 -0
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +133 -4
  14. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +10 -2
  15. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +36 -9
  16. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +28 -0
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -14
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +14 -16
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +67 -14
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +6 -1
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +7 -2
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +21 -7
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +121 -17
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +179 -6
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryConfirmation.swift +119 -0
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +8 -1
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +23 -11
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +59 -6
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +112 -23
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +25 -12
  31. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +6 -1
  32. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +43 -13
  33. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +20 -5
  34. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +2 -15
  35. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +10 -25
  36. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -18
  37. package/dist/src/adapter.js +1 -1
  38. package/dist/src/adb-executor.js +2 -2
  39. package/dist/src/adb-failure.js +1 -1
  40. package/dist/src/adb-transport.js +1 -1
  41. package/dist/src/agent-browser-lifecycle.js +1 -1
  42. package/dist/src/agent-browser-process-record.js +1 -1
  43. package/dist/src/agent-browser-provider.js +1 -1
  44. package/dist/src/agent-browser-tool.js +1 -1
  45. package/dist/src/agent-device-client.js +2 -2
  46. package/dist/src/ai-sdk.js +1 -1
  47. package/dist/src/alert-runtime.js +1 -1
  48. package/dist/src/alert.js +1 -0
  49. package/dist/src/android-adb.d.ts +12 -0
  50. package/dist/src/android-input-ownership.js +1 -1
  51. package/dist/src/app-backend.js +1 -0
  52. package/dist/src/app-catalog.js +1 -1
  53. package/dist/src/app-deployment-resolution.js +1 -1
  54. package/dist/src/app-inventory.js +1 -1
  55. package/dist/src/app-launch.js +2 -2
  56. package/dist/src/app-lifecycle.js +2 -2
  57. package/dist/src/app-lifecycle2.js +1 -1
  58. package/dist/src/app-log-files.js +1 -1
  59. package/dist/src/app-log-reconnect.js +1 -1
  60. package/dist/src/app-log-runtime2.js +3 -3
  61. package/dist/src/app-log-session-resource.js +1 -0
  62. package/dist/src/app-resolution.js +2 -2
  63. package/dist/src/apple-runner-platform.js +1 -1
  64. package/dist/src/application-lifecycle-interaction.js +1 -1
  65. package/dist/src/archive.js +2 -2
  66. package/dist/src/artifact-download.js +1 -1
  67. package/dist/src/auth-session.js +1 -1
  68. package/dist/src/auth.js +1 -1
  69. package/dist/src/back-mode.js +1 -1
  70. package/dist/src/backend-snapshot-options.js +1 -1
  71. package/dist/src/boot-diagnostics.js +1 -1
  72. package/dist/src/browser-launch.js +1 -1
  73. package/dist/src/cache.js +1 -1
  74. package/dist/src/capabilities.js +1 -1
  75. package/dist/src/capture.js +1 -1
  76. package/dist/src/cli-config.js +1 -1
  77. package/dist/src/cli-help.js +317 -323
  78. package/dist/src/cli-runner.js +1 -1
  79. package/dist/src/cli.js +4 -4
  80. package/dist/src/click-button.js +1 -1
  81. package/dist/src/client-metro-companion.js +1 -1
  82. package/dist/src/client-metro.js +1 -1
  83. package/dist/src/client-options.js +3 -0
  84. package/dist/src/client-types.d.ts +101 -6
  85. package/dist/src/clipboard-shell-response.js +1 -1
  86. package/dist/src/{scroll-command.d.ts → cloud-artifacts.d.ts} +249 -240
  87. package/dist/src/code-signature-cache.js +1 -1
  88. package/dist/src/code-signature.js +1 -1
  89. package/dist/src/command-schema.js +3 -3
  90. package/dist/src/command-tools.js +2 -2
  91. package/dist/src/command.js +1 -1
  92. package/dist/src/config.js +1 -1
  93. package/dist/src/connection-runtime.js +1 -1
  94. package/dist/src/connection.js +5 -5
  95. package/dist/src/contracts.d.ts +1 -1
  96. package/dist/src/contracts.js +1 -1
  97. package/dist/src/daemon-artifacts.js +1 -0
  98. package/dist/src/daemon-client-lease-beat.js +1 -1
  99. package/dist/src/daemon-client-lifecycle.js +1 -1
  100. package/dist/src/daemon-client-liveness-probe.js +1 -0
  101. package/dist/src/daemon-client-transport.js +1 -1
  102. package/dist/src/daemon-http.js +1 -0
  103. package/dist/src/daemon-policy-file.js +1 -1
  104. package/dist/src/daemon-registration-owner.js +1 -0
  105. package/dist/src/daemon-registration.js +1 -1
  106. package/dist/src/daemon-resolution.js +1 -1
  107. package/dist/src/daemon-shutdown-report.js +1 -1
  108. package/dist/src/daemon.js +2 -2
  109. package/dist/src/debug-symbols-facade.js +3 -3
  110. package/dist/src/device-claim-inspection.js +1 -1
  111. package/dist/src/device-claim-rule.js +1 -1
  112. package/dist/src/device-inventory-context.js +1 -1
  113. package/dist/src/device-readiness-runtime.js +1 -1
  114. package/dist/src/device-release.js +1 -1
  115. package/dist/src/device-rotation.js +1 -1
  116. package/dist/src/device-selection-resolver.js +1 -1
  117. package/dist/src/device-session.js +1 -1
  118. package/dist/src/device-shell.js +1 -1
  119. package/dist/src/device.js +1 -1
  120. package/dist/src/device2.js +1 -3
  121. package/dist/src/device3.js +3 -0
  122. package/dist/src/devicectl.js +1 -1
  123. package/dist/src/diagnostics.js +3 -3
  124. package/dist/src/dispatch-resolve.js +4 -1
  125. package/dist/src/display-inventory.js +1 -1
  126. package/dist/src/doctor-facade.js +1 -1
  127. package/dist/src/doctor2.js +1 -1
  128. package/dist/src/durable-capture-resource.js +1 -0
  129. package/dist/src/engine-eval-script.js +1 -1
  130. package/dist/src/error.js +1 -1
  131. package/dist/src/exec.js +1 -1
  132. package/dist/src/file.js +1 -1
  133. package/dist/src/find.js +1 -1
  134. package/dist/src/generic-settle.js +1 -1
  135. package/dist/src/generic.js +1 -1
  136. package/dist/src/gesture-admission.js +1 -1
  137. package/dist/src/gesture-plan.js +1 -1
  138. package/dist/src/gesture-runtime.js +1 -1
  139. package/dist/src/harmonyos.js +1 -1
  140. package/dist/src/hdc.js +1 -1
  141. package/dist/src/helper.js +2 -2
  142. package/dist/src/host-file.js +1 -1
  143. package/dist/src/host.js +1 -1
  144. package/dist/src/human-control-contract.js +1 -1
  145. package/dist/src/human-control.js +1 -1
  146. package/dist/src/index.d.ts +2 -2
  147. package/dist/src/index.js +1 -1
  148. package/dist/src/input-actions.js +1 -1
  149. package/dist/src/input-actions2.js +2 -2
  150. package/dist/src/install-artifact-facade.js +1 -1
  151. package/dist/src/install-source-network-transport.js +1 -1
  152. package/dist/src/install-source.d.ts +5 -0
  153. package/dist/src/install-source2.js +1 -1
  154. package/dist/src/instance-client.js +1 -0
  155. package/dist/src/interaction-positionals.js +1 -1
  156. package/dist/src/interaction-ref-policy.js +1 -1
  157. package/dist/src/interaction.js +1 -1
  158. package/dist/src/interaction2.js +1 -1
  159. package/dist/src/interactor-operation-binding.js +1 -1
  160. package/dist/src/interactor.js +5 -5
  161. package/dist/src/interactor2.js +1 -1
  162. package/dist/src/interactors.js +1 -1
  163. package/dist/src/internal/bin.js +1 -1
  164. package/dist/src/internal/daemon.js +1 -2
  165. package/dist/src/internal/png-worker.js +1 -1
  166. package/dist/src/internal/run-script-http-child.js +1 -1
  167. package/dist/src/inventory.js +4 -4
  168. package/dist/src/inventory2.js +1 -1
  169. package/dist/src/inventory3.js +1 -1
  170. package/dist/src/inventory5.js +1 -1
  171. package/dist/src/ios-client.js +4 -30
  172. package/dist/src/ios-settings.js +1 -0
  173. package/dist/src/ios-snapshot-engine.js +1 -1
  174. package/dist/src/ios-snapshot-runtime.js +1 -1
  175. package/dist/src/launch-confirmation.js +1 -0
  176. package/dist/src/lease-context.js +1 -1
  177. package/dist/src/lease-registry-scope.js +1 -0
  178. package/dist/src/lease-scope.js +1 -1
  179. package/dist/src/lease.js +1 -1
  180. package/dist/src/legacy-xctest-device-set.js +1 -1
  181. package/dist/src/limrun-download-file.js +1 -1
  182. package/dist/src/limrun-runtime-dependencies.js +1 -1
  183. package/dist/src/limrun.d.ts +78 -44
  184. package/dist/src/limrun.js +1 -1
  185. package/dist/src/linux.js +1 -1
  186. package/dist/src/load.js +1 -0
  187. package/dist/src/location-coordinates.js +1 -1
  188. package/dist/src/macos-facade.js +1 -1
  189. package/dist/src/managed-device-scope.js +1 -1
  190. package/dist/src/mechanics.js +16 -16
  191. package/dist/src/observation.js +1 -1
  192. package/dist/src/observe-until.js +1 -1
  193. package/dist/src/overlay.js +2 -2
  194. package/dist/src/owner-identity.js +3 -3
  195. package/dist/src/path-resolution.js +1 -1
  196. package/dist/src/perf-facade.js +1 -1
  197. package/dist/src/perf-runtime-operation-builder.js +1 -1
  198. package/dist/src/perf-runtime-plan.js +1 -1
  199. package/dist/src/perf-target.js +1 -1
  200. package/dist/src/perf.js +1 -1
  201. package/dist/src/physical-device-control.js +1 -1
  202. package/dist/src/platform-request-scope.js +1 -1
  203. package/dist/src/platform-runtime-android-adb-host.js +1 -1
  204. package/dist/src/platform-runtime-app-log-process.js +1 -1
  205. package/dist/src/platform-runtime-host.js +1 -1
  206. package/dist/src/platform-runtime-managed-owner.js +1 -1
  207. package/dist/src/platform-runtime-open-target.js +1 -1
  208. package/dist/src/platform-runtime-operation-host.js +2 -2
  209. package/dist/src/platform-runtime-runtime-hints.js +2 -2
  210. package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
  211. package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
  212. package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
  213. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  214. package/dist/src/platform-runtime-screen-recording-output-host.js +1 -1
  215. package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
  216. package/dist/src/platform-runtime-unavailable.js +1 -1
  217. package/dist/src/platform-runtime.js +1 -1
  218. package/dist/src/platform-runtime2.js +1 -1
  219. package/dist/src/plugins.d.ts +9 -0
  220. package/dist/src/plugins.js +1 -0
  221. package/dist/src/plugins2.js +2 -0
  222. package/dist/src/png-crop-bytes.js +1 -1
  223. package/dist/src/png-size.js +1 -1
  224. package/dist/src/png-worker-client.js +1 -1
  225. package/dist/src/png.js +1 -1
  226. package/dist/src/prepare-kind.js +1 -1
  227. package/dist/src/process.js +1 -1
  228. package/dist/src/project-runtime.js +1 -1
  229. package/dist/src/provider-credential-fingerprint.js +1 -0
  230. package/dist/src/provider-device-admission.js +1 -1
  231. package/dist/src/provider-device-runtimes.js +1 -0
  232. package/dist/src/provider-limrun-credentials.js +1 -0
  233. package/dist/src/provider-profile-fields.js +1 -0
  234. package/dist/src/provider-session-ownership.js +2 -2
  235. package/dist/src/provider-webdriver.js +2 -1
  236. package/dist/src/providers.js +1 -1
  237. package/dist/src/proxy.js +1 -1
  238. package/dist/src/quality-warnings.js +1 -1
  239. package/dist/src/react-native.js +1 -1
  240. package/dist/src/record-runtime.js +1 -1
  241. package/dist/src/record-trace.js +1 -1
  242. package/dist/src/recording.js +1 -1
  243. package/dist/src/rect-center.js +1 -1
  244. package/dist/src/register-builtins.js +1 -1
  245. package/dist/src/registry.js +52 -36
  246. package/dist/src/remote-config2.js +1 -1
  247. package/dist/src/replay-divergence.js +1 -1
  248. package/dist/src/replay.js +2 -2
  249. package/dist/src/reporting.js +5 -5
  250. package/dist/src/request-admission.js +1 -1
  251. package/dist/src/request-cancel.js +1 -1
  252. package/dist/src/request-cancellation.js +1 -1
  253. package/dist/src/request-runtime-binding.js +1 -1
  254. package/dist/src/result-serialization.js +1 -1
  255. package/dist/src/retry.js +1 -1
  256. package/dist/src/runner-artifact-manifest.js +1 -1
  257. package/dist/src/runner-cache-metadata.js +3 -3
  258. package/dist/src/runner-client.js +1 -1
  259. package/dist/src/runner-dev-tools-security.js +1 -1
  260. package/dist/src/runner-device-readiness.js +1 -1
  261. package/dist/src/runner-disposal.js +1 -1
  262. package/dist/src/runner-error-classification.js +2 -2
  263. package/dist/src/runner-exchange.js +1 -1
  264. package/dist/src/runner-operations-facade.js +1 -1
  265. package/dist/src/runner-session-types.js +1 -1
  266. package/dist/src/runner-start-budget.js +1 -1
  267. package/dist/src/runner.js +1 -1
  268. package/dist/src/runtime-admission.js +1 -1
  269. package/dist/src/runtime-transport-hints.js +1 -1
  270. package/dist/src/runtime.js +1 -1
  271. package/dist/src/runtime10.js +2 -2
  272. package/dist/src/runtime2.js +3 -3
  273. package/dist/src/runtime3.js +1 -1
  274. package/dist/src/runtime4.js +5 -5
  275. package/dist/src/runtime5.js +1 -1
  276. package/dist/src/runtime6.js +1 -1
  277. package/dist/src/runtime7.js +1 -1
  278. package/dist/src/runtime8.js +1 -1
  279. package/dist/src/runtime9.js +1 -1
  280. package/dist/src/screen-recording-admission-ledger.js +1 -1
  281. package/dist/src/screen-recording-completion.js +1 -1
  282. package/dist/src/screen-recording-options.js +1 -1
  283. package/dist/src/screen-recording-resource-recovery.js +1 -1
  284. package/dist/src/screen-recording-transport.js +1 -1
  285. package/dist/src/screenshot-density.js +1 -1
  286. package/dist/src/screenshot-image.js +1 -1
  287. package/dist/src/screenshot-result.js +1 -1
  288. package/dist/src/screenshot-runtime.js +1 -1
  289. package/dist/src/screenshot.js +1 -1
  290. package/dist/src/screenshot3.js +1 -1
  291. package/dist/src/script.js +1 -1
  292. package/dist/src/scroll-command.js +1 -1
  293. package/dist/src/scroll-gesture.js +1 -1
  294. package/dist/src/sdk-batch-runner.js +2 -2
  295. package/dist/src/sdk-batch.js +2 -2
  296. package/dist/src/sdk-contracts.d.ts +47 -2
  297. package/dist/src/sdk-contracts.js +2 -2
  298. package/dist/src/sdk-device.js +1 -1
  299. package/dist/src/sdk-io.js +1 -1
  300. package/dist/src/sdk-remote-config.js +1 -1
  301. package/dist/src/sdk-selectors.d.ts +37 -8
  302. package/dist/src/selection.js +0 -0
  303. package/dist/src/selector-runtime.js +1 -1
  304. package/dist/src/selectors.d.ts +2 -2
  305. package/dist/src/selectors.js +1 -1
  306. package/dist/src/server.js +1 -1
  307. package/dist/src/session-allocation.js +1 -1
  308. package/dist/src/session-artifact-paths.js +1 -1
  309. package/dist/src/session-repair-tombstone.js +1 -1
  310. package/dist/src/session-routing.js +1 -1
  311. package/dist/src/session-runtime-admission.js +1 -1
  312. package/dist/src/session-snapshot.js +1 -1
  313. package/dist/src/session-stream.js +27 -0
  314. package/dist/src/session.js +1 -1
  315. package/dist/src/session2.js +5 -5
  316. package/dist/src/settings.js +1 -1
  317. package/dist/src/settings2.js +1 -1
  318. package/dist/src/simctl-settings-facade.js +1 -0
  319. package/dist/src/simctl-settings.js +1 -0
  320. package/dist/src/simctl.js +1 -1
  321. package/dist/src/simulator-boot.js +1 -1
  322. package/dist/src/simulator.js +1 -1
  323. package/dist/src/snapshot-diagnostics.js +1 -1
  324. package/dist/src/snapshot-runtime-binding.js +1 -1
  325. package/dist/src/snapshot-runtime.js +1 -1
  326. package/dist/src/snapshot-state.js +1 -1
  327. package/dist/src/snapshot2.js +1 -1
  328. package/dist/src/snapshot3.js +1 -1
  329. package/dist/src/snapshot4.js +1 -1
  330. package/dist/src/src.js +1 -1
  331. package/dist/src/src7.js +1 -1
  332. package/dist/src/src8.js +2 -2
  333. package/dist/src/store.js +1 -0
  334. package/dist/src/string-enum.js +1 -1
  335. package/dist/src/surface-snapshot.js +1 -1
  336. package/dist/src/takeover.js +1 -1
  337. package/dist/src/target-evidence.js +1 -1
  338. package/dist/src/telemetry.js +1 -1
  339. package/dist/src/text-entry-focus.js +1 -1
  340. package/dist/src/tool-provider.js +3 -3
  341. package/dist/src/tool-provider2.js +1 -1
  342. package/dist/src/tool-provider3.js +1 -1
  343. package/dist/src/toolchain-probe.js +2 -2
  344. package/dist/src/touch-runtime.js +1 -1
  345. package/dist/src/touch-runtime2.js +1 -1
  346. package/dist/src/transport.js +2 -2
  347. package/dist/src/tv-remote.js +1 -1
  348. package/dist/src/type-text-runtime.js +1 -1
  349. package/dist/src/update-check.js +1 -1
  350. package/dist/src/vars.js +1 -1
  351. package/dist/src/verified-file.js +1 -1
  352. package/dist/src/version.js +1 -1
  353. package/dist/src/video.js +1 -1
  354. package/dist/src/viewport.js +1 -1
  355. package/dist/src/web.js +1 -1
  356. package/dist/src/web2.js +1 -1
  357. package/dist/src/webdriver-source.js +1 -1
  358. package/package.json +5 -1
  359. package/server.json +2 -2
  360. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.19.apk.sha256 +0 -1
  361. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk +0 -0
  362. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk.sha256 +0 -1
  363. package/dist/src/api.js +0 -3
  364. package/dist/src/daemon-process.js +0 -1
  365. package/dist/src/multitouch-support.js +0 -1
  366. package/dist/src/parameterized-recorded-fill.js +0 -1
  367. package/dist/src/runner-startup-transport.js +0 -1
  368. package/dist/src/runner-xctestrun.js +0 -1
  369. package/dist/src/session-store.js +0 -4
@@ -5,7 +5,7 @@ final class TextInputProbeIssues {
5
5
  var count = 0
6
6
  }
7
7
 
8
- enum TextInputProbeFailure: String {
8
+ enum TextInputProbeFailure: String, Error {
9
9
  case recordedIssue = "text_input_probe_recorded_issue"
10
10
  case exception = "text_input_probe_exception"
11
11
  }
@@ -38,7 +38,60 @@ extension RunnerTests {
38
38
  }
39
39
  }
40
40
 
41
+
42
+
43
+ func coordinateTapTextInputIdentityAt(app: XCUIApplication, x: Double, y: Double) -> TextInputAtPoint? {
44
+ let probed = containingTextInputProbeIssues(fallback: nil) { shouldStop -> TextInputAtPoint? in
45
+ guard let element = queryTextInputs(app: app, point: CGPoint(x: x, y: y), shouldStop: shouldStop).first,
46
+ case .input(let identity) = probeTextEntryInput(element)
47
+ else {
48
+ return nil
49
+ }
50
+ return TextInputAtPoint(element: element, identity: identity)
51
+ }
52
+ guard case .success(let input) = probed else { return nil }
53
+ return input
54
+ }
55
+
56
+
57
+
58
+ func textInputStillResolves(_ input: TextInputAtPoint) -> Bool {
59
+ let probed = containingTextInputProbeIssues(fallback: false) { _ in
60
+ input.element.exists && probeTextEntryInput(input.element) == .input(input.identity)
61
+ }
62
+ guard case .success(let resolves) = probed else { return false }
63
+ return resolves
64
+ }
65
+
66
+
67
+
68
+ func clearedFieldRead(app: XCUIApplication, target: TextEntryTarget) -> ClearedFieldRead {
69
+ let probed = containingTextInputProbeIssues(fallback: ClearedFieldRead.unavailable) { _ in
70
+ guard let input = resolveTextEntryElement(app: app, target: target) else { return .unavailable }
71
+ if input.elementType == .secureTextField { return .unreadable }
72
+ return editableTextValue(for: input, treatingPlaceholderAsEmpty: true).map { .text($0) } ?? .unavailable
73
+ }
74
+ guard case .success(let read) = probed else { return .unavailable }
75
+ return read
76
+ }
77
+
41
78
  func probeTextInputs(app: XCUIApplication, point: CGPoint) -> TextInputProbeOutcome {
79
+ switch containingTextInputProbeIssues(fallback: [], { shouldStop in
80
+ queryTextInputs(app: app, point: point, shouldStop: shouldStop)
81
+ }) {
82
+ case .success(let elements):
83
+ return elements.isEmpty ? .absent : .matches(elements)
84
+ case .failure(let failure):
85
+ return .unavailable(failure)
86
+ }
87
+ }
88
+
89
+
90
+
91
+ private func containingTextInputProbeIssues<T>(
92
+ fallback: T,
93
+ _ probe: (_ shouldStop: () -> Bool) -> T
94
+ ) -> Result<T, TextInputProbeFailure> {
42
95
  precondition(Thread.isMainThread)
43
96
  let issues = TextInputProbeIssues()
44
97
  suppressedIssueLock.lock()
@@ -50,12 +103,12 @@ extension RunnerTests {
50
103
  textInputProbeIssues = previous
51
104
  suppressedIssueLock.unlock()
52
105
  }
53
- let (elements, exception) = catchingObjCException(fallback: []) {
54
- queryTextInputs(app: app, point: point, shouldStop: { self.hasTextInputProbeIssues(issues) })
106
+ let (value, exception) = catchingObjCException(fallback: fallback) {
107
+ probe({ self.hasTextInputProbeIssues(issues) })
55
108
  }
56
- if hasTextInputProbeIssues(issues) { return .unavailable(.recordedIssue) }
57
- if exception != nil { return .unavailable(.exception) }
58
- return elements.isEmpty ? .absent : .matches(elements)
109
+ if hasTextInputProbeIssues(issues) { return .failure(.recordedIssue) }
110
+ if exception != nil { return .failure(.exception) }
111
+ return .success(value)
59
112
  }
60
113
 
61
114
  private func hasTextInputProbeIssues(_ scope: TextInputProbeIssues) -> Bool {
@@ -117,6 +117,7 @@ extension RunnerTests {
117
117
  )
118
118
  }
119
119
 
120
+ var entryBaseline: TextEntryObservation?
120
121
  if repairMode == .replacement {
121
122
  guard let replacementTarget = initialTarget else {
122
123
  logTextEntryPhase(commandId: commandId, phase: "total", startedAt: totalStartedAt, chars: text.count, mode: repairMode)
@@ -134,6 +135,7 @@ extension RunnerTests {
134
135
  mode: repairMode
135
136
  )
136
137
  }
138
+ entryBaseline = textEntryObservation(for: replacementTarget)
137
139
  }
138
140
 
139
141
 
@@ -194,7 +196,7 @@ extension RunnerTests {
194
196
  textEntryRoute = "xctest-element"
195
197
  currentTarget.typeText(value)
196
198
  return (currentTarget, nil)
197
- } else if activeTarget.prefersFocusedElement && isKeyboardVisible(app: app) {
199
+ } else if activeTarget.boundIdentity == nil && activeTarget.prefersFocusedElement && isKeyboardVisible(app: app) {
198
200
  #if os(iOS)
199
201
 
200
202
 
@@ -344,7 +346,8 @@ extension RunnerTests {
344
346
  app: app,
345
347
  target: activeTarget,
346
348
  expectedText: expectedText,
347
- repairMode: repairMode
349
+ repairMode: repairMode,
350
+ baseline: entryBaseline
348
351
  )
349
352
  logTextEntryPhase(
350
353
  commandId: commandId,
@@ -390,14 +393,40 @@ extension RunnerTests {
390
393
  app: XCUIApplication,
391
394
  target: TextEntryTarget,
392
395
  expectedText: String?,
393
- repairMode: TextTypingRepairMode
396
+ repairMode: TextTypingRepairMode,
397
+ baseline: TextEntryObservation?
394
398
  ) -> TextEntryResult {
399
+ if target.boundIdentity != nil, resolveTextEntryElement(app: app, target: target) == nil {
400
+ guard boundTextEntryInputIsGone(app: app, target: target) else {
401
+ return TextEntryResult(
402
+ verified: nil,
403
+ repaired: false,
404
+ expectedText: expectedText,
405
+ observedText: nil,
406
+ failure: .commitNotObserved
407
+ )
408
+ }
409
+
410
+
411
+ NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_INPUT_REMOVED_AFTER_DELIVERY")
412
+ return TextEntryResult(verified: nil, repaired: false, expectedText: expectedText, observedText: nil)
413
+ }
395
414
  let initialResult = verifyTextEntry(
396
415
  app: app,
397
416
  target: target,
398
417
  expectedText: expectedText,
399
418
  repaired: false
400
419
  )
420
+
421
+
422
+ if let unconfirmed = settledUnconfirmedTextEntry(
423
+ app: app,
424
+ target: target,
425
+ result: initialResult,
426
+ baseline: baseline
427
+ ) {
428
+ return unconfirmed
429
+ }
401
430
  #if os(iOS)
402
431
  guard initialResult.verified == false,
403
432
  let expectedText = initialResult.expectedText
@@ -417,6 +446,15 @@ extension RunnerTests {
417
446
  repaired: false
418
447
  )
419
448
  }
449
+ guard Self.textEntryRepairCanTarget(boundIdentity: target.boundIdentity) else {
450
+ NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_REPAIR_REFUSED reason=unidentified-input")
451
+ return verifyTextEntry(
452
+ app: app,
453
+ target: target,
454
+ expectedText: expectedText,
455
+ repaired: false
456
+ )
457
+ }
420
458
 
421
459
  guard let repairTarget = resolveTextEntryElement(app: app, target: target) else {
422
460
  return initialResult
@@ -429,17 +467,83 @@ extension RunnerTests {
429
467
  )
430
468
  clearTextInput(repairTarget)
431
469
  repairTarget.typeText(expectedText)
432
- return verifyTextEntry(
470
+ let repairedTarget = target.withElement(repairTarget)
471
+ let repairedResult = verifyTextEntry(
433
472
  app: app,
434
- target: target.withElement(repairTarget),
473
+ target: repairedTarget,
435
474
  expectedText: expectedText,
436
475
  repaired: true
437
476
  )
477
+ return settledUnconfirmedTextEntry(
478
+ app: app,
479
+ target: repairedTarget,
480
+ result: repairedResult,
481
+ baseline: baseline
482
+ ) ?? repairedResult
438
483
  #else
439
484
  return initialResult
440
485
  #endif
441
486
  }
442
487
 
488
+
489
+
490
+ private func settledUnconfirmedTextEntry(
491
+ app: XCUIApplication,
492
+ target: TextEntryTarget,
493
+ result: TextEntryResult,
494
+ baseline: TextEntryObservation?
495
+ ) -> TextEntryResult? {
496
+ guard result.verified == false, let requested = result.expectedText, let baseline else {
497
+ return nil
498
+ }
499
+ func observe() -> TextEntryObservation? {
500
+ textEntryObservation(for: resolveTextEntryElement(app: app, target: target))
501
+ }
502
+ func evidence(_ observed: TextEntryObservation?) -> TextEntryUnconfirmedEvidence? {
503
+ Self.unconfirmedTextEntryEvidence(requested: requested, baseline: baseline, observed: observed)
504
+ }
505
+ let moveDeadline = Date().addingTimeInterval(TextEntryTiming.unconfirmedSettleCeiling)
506
+ var latest = observe()
507
+ while let unmoved = latest, unmoved.isSettled(with: baseline), Date() < moveDeadline {
508
+ sleepFor(TextEntryTiming.pollInterval)
509
+ latest = observe()
510
+ }
511
+ guard evidence(latest) != nil else {
512
+ return nil
513
+ }
514
+ let ceiling = Date().addingTimeInterval(TextEntryTiming.unconfirmedSettleCeiling)
515
+ var stableSince = Date()
516
+ while Date().timeIntervalSince(stableSince) < TextEntryTiming.verificationStabilityWindow {
517
+ guard Date() < ceiling else {
518
+ return nil
519
+ }
520
+ sleepFor(TextEntryTiming.pollInterval)
521
+ let next = observe()
522
+ if let next, let settled = latest, next.isSettled(with: settled) {
523
+ latest = next
524
+ continue
525
+ }
526
+ latest = next
527
+ stableSince = Date()
528
+ }
529
+ guard let unconfirmed = evidence(latest) else {
530
+ return nil
531
+ }
532
+ NSLog(
533
+ "AGENT_DEVICE_RUNNER_TEXT_ENTRY_UNCONFIRMED expectedLength=%d observedLength=%d repaired=%d",
534
+ requested.count,
535
+ unconfirmed.after.count,
536
+ result.repaired ? 1 : 0
537
+ )
538
+ return TextEntryResult(
539
+ verified: nil,
540
+ repaired: result.repaired,
541
+ expectedText: requested,
542
+ observedText: unconfirmed.after,
543
+ unconfirmed: unconfirmed
544
+ )
545
+ }
546
+
443
547
  private func verifyTextEntry(
444
548
  app: XCUIApplication,
445
549
  target: TextEntryTarget,
@@ -503,18 +607,10 @@ extension RunnerTests {
503
607
  if observedText == expectedText {
504
608
  return true
505
609
  }
506
- guard hasTextEntrySubmitSuffix(expectedText), element?.elementType != .textView else {
610
+ guard element?.elementType != .textView else {
507
611
  return false
508
612
  }
509
- var submittedText = expectedText
510
- while hasTextEntrySubmitSuffix(submittedText) {
511
- submittedText.removeLast()
512
- }
513
- return observedText == submittedText
514
- }
515
-
516
- private func hasTextEntrySubmitSuffix(_ text: String) -> Bool {
517
- text.hasSuffix("\n") || text.hasSuffix("\r")
613
+ return observedText == Self.textEntryRequestWithoutSubmitKeys(expectedText)
518
614
  }
519
615
 
520
616
  private func expectedTextEntryValue(
@@ -611,13 +707,6 @@ extension RunnerTests {
611
707
  guard missingCharacterCount <= max(2, expectedText.count / 4) else {
612
708
  return false
613
709
  }
614
- var expectedIndex = expectedText.startIndex
615
- for character in observedText {
616
- guard let matchIndex = expectedText[expectedIndex...].firstIndex(of: character) else {
617
- return false
618
- }
619
- expectedIndex = expectedText.index(after: matchIndex)
620
- }
621
- return true
710
+ return Self.isOrderedSubsequence(observedText, of: expectedText)
622
711
  }
623
712
  }
@@ -27,6 +27,8 @@ extension RunnerTests {
27
27
  hasY: command.y != nil,
28
28
  xCTestChannelPenalized: xCTestChannelPenalized
29
29
  ), let x = command.x, let y = command.y {
30
+
31
+ let inputAtPoint = coordinateTapTextInputIdentityAt(app: activeApp, x: x, y: y)
30
32
  let policyKind = SynthesizedGesturePolicyKind.coordinateTap
31
33
  let context = synthesizedCoordinateContext(
32
34
  app: activeApp,
@@ -40,7 +42,8 @@ extension RunnerTests {
40
42
  resolvedCoordinateTarget = TextEntryTarget(
41
43
  element: nil,
42
44
  refreshPoint: CGPoint(x: x, y: y),
43
- prefersFocusedElement: false
45
+ prefersFocusedElement: false,
46
+ inputAtRefreshPoint: inputAtPoint
44
47
  )
45
48
  case .xctestFallback:
46
49
  break
@@ -120,17 +123,27 @@ extension RunnerTests {
120
123
 
121
124
  frame = .zero
122
125
  }
123
- return Response(
124
- ok: true,
125
- data: DataPayload(
126
- message: textResult.repaired ? "typed after repair" : "typed",
127
- x: point.map { Double($0.x) },
128
- y: point.map { Double($0.y) },
129
- referenceWidth: frame.isEmpty ? nil : Double(frame.width),
130
- referenceHeight: frame.isEmpty ? nil : Double(frame.height),
131
- maestroNonHittableCoordinateFallbackUsed: maestroNonHittableCoordinateFallbackUsed,
132
- textEntryRoute: textResult.textEntryRoute
133
- )
126
+ var data = DataPayload(
127
+ message: textResult.repaired ? "typed after repair" : "typed",
128
+ x: point.map { Double($0.x) },
129
+ y: point.map { Double($0.y) },
130
+ referenceWidth: frame.isEmpty ? nil : Double(frame.width),
131
+ referenceHeight: frame.isEmpty ? nil : Double(frame.height),
132
+ maestroNonHittableCoordinateFallbackUsed: maestroNonHittableCoordinateFallbackUsed,
133
+ textEntryRoute: textResult.textEntryRoute
134
134
  )
135
+ if let unconfirmed = textResult.unconfirmed {
136
+ data.verification = "unconfirmed"
137
+ data.requested = unconfirmed.requested
138
+ data.before = unconfirmed.before
139
+ data.after = unconfirmed.after
140
+ data.target = TextEntryVerificationTargetPayload(
141
+ resourceId: unconfirmed.target.identifier,
142
+ className: unconfirmed.target.elementType,
143
+ packageName: command.appBundleId,
144
+ rect: SnapshotRect(unconfirmed.target.frame)
145
+ )
146
+ }
147
+ return Response(ok: true, data: data)
135
148
  }
136
149
  }
@@ -89,9 +89,14 @@ func makeRecordingExporter(
89
89
  }
90
90
 
91
91
 
92
+ let defaultRecordingExportTimeoutSeconds: Double = 120
93
+
94
+
95
+
92
96
 
93
97
  func runRecordingExport(
94
98
  _ exporter: AVAssetExportSession,
99
+ timeoutSeconds: Double = defaultRecordingExportTimeoutSeconds,
95
100
  timeoutMessage: String,
96
101
  failureMessage: String
97
102
  ) throws {
@@ -99,7 +104,7 @@ func runRecordingExport(
99
104
  exporter.exportAsynchronously {
100
105
  semaphore.signal()
101
106
  }
102
- if semaphore.wait(timeout: .now() + 120) == .timedOut {
107
+ if semaphore.wait(timeout: .now() + timeoutSeconds) == .timedOut {
103
108
  exporter.cancelExport()
104
109
  throw RecordingScriptError.exportFailed(timeoutMessage)
105
110
  }
@@ -88,7 +88,10 @@ func run() throws {
88
88
  let renderSize = resolvedRenderSize(for: sourceVideoTrack)
89
89
  let videoComposition = AVMutableVideoComposition()
90
90
  videoComposition.renderSize = renderSize
91
- videoComposition.frameDuration = resolvedFrameDuration(for: sourceVideoTrack)
91
+ videoComposition.frameDuration = resolvedFrameDuration(
92
+ for: sourceVideoTrack,
93
+ maximumFrameRate: parsedArgs.maximumFrameRate
94
+ )
92
95
 
93
96
  let instruction = AVMutableVideoCompositionInstruction()
94
97
  instruction.timeRange = fullRange
@@ -145,6 +148,7 @@ func run() throws {
145
148
  )
146
149
  try runRecordingExport(
147
150
  exporter,
151
+ timeoutSeconds: parsedArgs.timeoutSeconds,
148
152
  timeoutMessage: "Touch overlay export timed out.",
149
153
  failureMessage: "Touch overlay export failed."
150
154
  )
@@ -157,10 +161,15 @@ func run() throws {
157
161
 
158
162
  func parseArguments(
159
163
  _ arguments: [String]
160
- ) throws -> (inputPath: String, outputPath: String, eventsPath: String) {
164
+ ) throws -> (
165
+ inputPath: String, outputPath: String, eventsPath: String, timeoutSeconds: Double,
166
+ maximumFrameRate: Int32
167
+ ) {
161
168
  var inputPath: String?
162
169
  var outputPath: String?
163
170
  var eventsPath: String?
171
+ var timeoutSeconds = defaultRecordingExportTimeoutSeconds
172
+ var maximumFrameRate = maximumCompositedFrameRate
164
173
  var index = 0
165
174
 
166
175
  while index < arguments.count {
@@ -185,6 +194,20 @@ func parseArguments(
185
194
  throw RecordingScriptError.invalidArgs("--quality must be one of: medium, high")
186
195
  }
187
196
  index += 2
197
+ case "--timeout-ms":
198
+ let rawValue = try recordingOptionValue(arguments, nextIndex, "--timeout-ms")
199
+ guard let milliseconds = Double(rawValue), milliseconds > 0 else {
200
+ throw RecordingScriptError.invalidArgs("--timeout-ms must be a positive number")
201
+ }
202
+ timeoutSeconds = milliseconds / 1000
203
+ index += 2
204
+ case "--max-fps":
205
+ let rawValue = try recordingOptionValue(arguments, nextIndex, "--max-fps")
206
+ guard let framesPerSecond = Int32(rawValue), framesPerSecond > 0 else {
207
+ throw RecordingScriptError.invalidArgs("--max-fps must be a positive integer")
208
+ }
209
+ maximumFrameRate = min(framesPerSecond, maximumCompositedFrameRate)
210
+ index += 2
188
211
  default:
189
212
  throw RecordingScriptError.invalidArgs("Unknown argument: \(argument)")
190
213
  }
@@ -192,10 +215,10 @@ func parseArguments(
192
215
 
193
216
  guard let inputPath, let outputPath, let eventsPath else {
194
217
  throw RecordingScriptError.invalidArgs(
195
- "Usage: recording-overlay.swift --input <video> --output <video> --events <json> [--quality <medium|high>]"
218
+ "Usage: recording-overlay.swift --input <video> --output <video> --events <json> [--quality <medium|high>] [--timeout-ms <ms>] [--max-fps <n>]"
196
219
  )
197
220
  }
198
- return (inputPath, outputPath, eventsPath)
221
+ return (inputPath, outputPath, eventsPath, timeoutSeconds, maximumFrameRate)
199
222
  }
200
223
 
201
224
 
@@ -329,19 +352,26 @@ func frameMeanLuma(_ image: CGImage) -> Double? {
329
352
  return total / Double(count)
330
353
  }
331
354
 
332
- func resolvedFrameDuration(for track: AVAssetTrack) -> CMTime {
355
+
356
+
357
+ let maximumCompositedFrameRate: Int32 = 30
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+ func resolvedFrameDuration(for track: AVAssetTrack, maximumFrameRate: Int32) -> CMTime {
368
+ let shortest = CMTime(value: 1, timescale: maximumFrameRate)
333
369
  let minFrameDuration = track.minFrameDuration
334
370
  if minFrameDuration.isValid && !minFrameDuration.isIndefinite && minFrameDuration.seconds > 0 {
335
- return minFrameDuration
336
- }
337
-
338
- let nominalFrameRate = track.nominalFrameRate
339
- if nominalFrameRate > 0 {
340
- let timescale = Int32(max(1, round(nominalFrameRate)))
341
- return CMTime(value: 1, timescale: timescale)
371
+ return CMTimeMaximum(minFrameDuration, shortest)
342
372
  }
343
373
 
344
- return CMTime(value: 1, timescale: 60)
374
+ return shortest
345
375
  }
346
376
 
347
377
  func overlayPoint(event: GestureEvent, x: Double, y: Double, renderSize: CGSize) -> CGPoint {
@@ -29,7 +29,7 @@ public struct SnapshotRect: Codable, Equatable {
29
29
  }
30
30
 
31
31
  public struct RawAXNode: Equatable {
32
- public let index: Int
32
+ public private(set) var index: Int
33
33
  public let type: String
34
34
  public let label: String?
35
35
  public let identifier: String?
@@ -42,10 +42,10 @@ public struct RawAXNode: Equatable {
42
42
  public let selected: Bool?
43
43
  /// Geometric actionability; `nil` when the capture has no viewport box to decide it against.
44
44
  public var hittable: Bool?
45
- public let depth: Int
46
- public let parentIndex: Int?
47
- public let hiddenContentAbove: Bool?
48
- public let hiddenContentBelow: Bool?
45
+ public private(set) var depth: Int
46
+ public private(set) var parentIndex: Int?
47
+ public private(set) var hiddenContentAbove: Bool?
48
+ public private(set) var hiddenContentBelow: Bool?
49
49
  public var actions: [String]?
50
50
 
51
51
  public init(
@@ -91,6 +91,21 @@ public struct RawAXNode: Equatable {
91
91
  return updated
92
92
  }
93
93
 
94
+ func reindexed(index: Int, depth: Int, parentIndex: Int?) -> RawAXNode {
95
+ var updated = self
96
+ updated.index = index
97
+ updated.depth = depth
98
+ updated.parentIndex = parentIndex
99
+ return updated
100
+ }
101
+
102
+ func addingHiddenContentHints(above: Bool, below: Bool) -> RawAXNode {
103
+ var updated = self
104
+ updated.hiddenContentAbove = hiddenContentAbove == true || above ? true : nil
105
+ updated.hiddenContentBelow = hiddenContentBelow == true || below ? true : nil
106
+ return updated
107
+ }
108
+
94
109
  public var hasSemanticContent: Bool {
95
110
  [label, identifier, value].contains {
96
111
  !($0?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)
@@ -134,23 +134,10 @@ extension SnapshotPresentation {
134
134
  return nodes.enumerated().map { offset, node in
135
135
  let raw = node.raw
136
136
  return SnapshotPresentationNode(
137
- raw: RawAXNode(
137
+ raw: raw.reindexed(
138
138
  index: offset,
139
- type: raw.type,
140
- label: raw.label,
141
- identifier: raw.identifier,
142
- value: raw.value,
143
- placeholder: raw.placeholder,
144
- rect: raw.rect,
145
- enabled: raw.enabled,
146
- focused: raw.focused,
147
- selected: raw.selected,
148
- hittable: raw.hittable,
149
139
  depth: max(0, raw.depth - depthOffset),
150
- parentIndex: raw.parentIndex.flatMap { indexMap[$0] },
151
- hiddenContentAbove: raw.hiddenContentAbove,
152
- hiddenContentBelow: raw.hiddenContentBelow,
153
- actions: raw.actions
140
+ parentIndex: raw.parentIndex.flatMap { indexMap[$0] }
154
141
  ),
155
142
  effectiveRect: node.effectiveRect
156
143
  )
@@ -191,33 +191,18 @@ public enum SnapshotVisibilityFold {
191
191
  if decision.isIncluded {
192
192
  let outIndex = kept.count
193
193
  let outDepth = keptDepth + 1
194
+ var projected = node.reindexed(index: outIndex, depth: outDepth, parentIndex: keptIndex)
195
+ projected.hittable = node.parentIndex == nil
196
+ ? false
197
+ : clippedHittability(
198
+ source: node.hittable,
199
+ enabled: node.enabled,
200
+ clippedFrame: decision.effectiveFrame,
201
+ viewport: viewport
202
+ )
194
203
  kept.append(
195
204
  SnapshotPresentationNode(
196
- raw: RawAXNode(
197
- index: outIndex,
198
- type: node.type,
199
- label: node.label,
200
- identifier: node.identifier,
201
- value: node.value,
202
- placeholder: node.placeholder,
203
- rect: node.rect,
204
- enabled: node.enabled,
205
- focused: node.focused,
206
- selected: node.selected,
207
- hittable: node.parentIndex == nil
208
- ? false
209
- : clippedHittability(
210
- source: node.hittable,
211
- enabled: node.enabled,
212
- clippedFrame: decision.effectiveFrame,
213
- viewport: viewport
214
- ),
215
- depth: outDepth,
216
- parentIndex: keptIndex,
217
- hiddenContentAbove: node.hiddenContentAbove,
218
- hiddenContentBelow: node.hiddenContentBelow,
219
- actions: node.actions
220
- ),
205
+ raw: projected,
221
206
  effectiveRect: SnapshotGeometry.snapshotRect(
222
207
  from: decision.effectiveFrame,
223
208
  reportedFrame: rect
@@ -73,24 +73,7 @@ extension SnapshotVisibilityFold {
73
73
  let node = presentationNode.raw
74
74
  guard let hint = hints[node.index] else { return presentationNode }
75
75
  return SnapshotPresentationNode(
76
- raw: RawAXNode(
77
- index: node.index,
78
- type: node.type,
79
- label: node.label,
80
- identifier: node.identifier,
81
- value: node.value,
82
- placeholder: node.placeholder,
83
- rect: node.rect,
84
- enabled: node.enabled,
85
- focused: node.focused,
86
- selected: node.selected,
87
- hittable: node.hittable,
88
- depth: node.depth,
89
- parentIndex: node.parentIndex,
90
- hiddenContentAbove: node.hiddenContentAbove == true || hint.above ? true : nil,
91
- hiddenContentBelow: node.hiddenContentBelow == true || hint.below ? true : nil,
92
- actions: node.actions
93
- ),
76
+ raw: node.addingHiddenContentHints(above: hint.above, below: hint.below),
94
77
  effectiveRect: presentationNode.effectiveRect
95
78
  )
96
79
  }