agent-device 0.20.10 → 0.21.1

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 (510) hide show
  1. package/README.md +2 -2
  2. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.10.apk → agent-device-android-ime-helper-0.21.1.apk} +0 -0
  3. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.1.apk.sha256 +1 -0
  4. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.10.manifest.json → agent-device-android-ime-helper-0.21.1.manifest.json} +4 -4
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.1.apk +0 -0
  6. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.1.apk.sha256 +1 -0
  7. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.10.manifest.json → agent-device-android-snapshot-helper-0.21.1.manifest.json} +6 -6
  8. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AudioProbe.swift +35 -33
  9. package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +6 -1
  10. package/apple/snapshot-bridge/LICENSE.idb +23 -0
  11. package/apple/snapshot-bridge/README.md +106 -0
  12. package/apple/snapshot-bridge/SnapshotBridge.m +286 -0
  13. package/apple/snapshot-bridge/SnapshotBridgeCapture.h +25 -0
  14. package/apple/snapshot-bridge/SnapshotBridgeCapture.m +138 -0
  15. package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +34 -0
  16. package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +411 -0
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +58 -0
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +19 -0
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +12 -0
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +20 -0
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAlertVerification.swift +36 -0
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSelectorMatchPolicy.swift +15 -15
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerStringNormalization.swift +8 -0
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +12 -1
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +100 -6
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +72 -0
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +63 -14
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +677 -83
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +35 -92
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +124 -0
  31. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +39 -4
  32. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1058 -213
  33. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +296 -14
  34. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +1 -1
  35. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +10 -10
  36. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +309 -149
  37. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +101 -42
  38. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +24 -17
  39. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +124 -199
  40. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +71 -4
  41. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXElementTypes.swift +12 -0
  42. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +211 -78
  43. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +30 -10
  44. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +254 -24
  45. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +206 -22
  46. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +465 -494
  47. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +168 -0
  48. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +802 -247
  49. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationInvariant.swift +19 -0
  50. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +185 -0
  51. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +206 -0
  52. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +83 -5
  53. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +156 -34
  54. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +5 -4
  55. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +35 -318
  56. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +206 -0
  57. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +158 -0
  58. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +28 -0
  59. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +101 -0
  60. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +56 -23
  61. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +56 -27
  62. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +30 -24
  63. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +126 -80
  64. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +111 -0
  65. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +47 -86
  66. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +32 -79
  67. package/dist/apple/snapshot-presentation/Package.swift +21 -0
  68. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +56 -0
  69. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +259 -0
  70. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentation.swift +153 -0
  71. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationFailure.swift +27 -0
  72. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +91 -0
  73. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +161 -0
  74. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotScopePolicy.swift +53 -0
  75. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +242 -0
  76. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +97 -0
  77. package/dist/src/adapter.js +1 -0
  78. package/dist/src/adb-executor.js +2 -0
  79. package/dist/src/adb-failure.js +1 -0
  80. package/dist/src/adb-host.js +1 -0
  81. package/dist/src/adb.js +1 -0
  82. package/dist/src/agent-browser-lifecycle.js +1 -0
  83. package/dist/src/agent-browser-process-record.js +1 -0
  84. package/dist/src/agent-browser-provider.js +1 -0
  85. package/dist/src/agent-browser-tool.js +1 -1
  86. package/dist/src/agent-device-client.js +2 -2
  87. package/dist/src/ai-sdk.d.ts +2 -2
  88. package/dist/src/ai-sdk.js +1 -1
  89. package/dist/src/alert-contract.js +1 -0
  90. package/dist/src/alert-runtime.js +1 -0
  91. package/dist/src/android-adb.d.ts +27 -19
  92. package/dist/src/android-adb.js +1 -1
  93. package/dist/src/android-input-ownership.js +1 -0
  94. package/dist/src/android-system-chrome.js +1 -0
  95. package/dist/src/android.js +1 -1
  96. package/dist/src/api.js +11 -0
  97. package/dist/src/app-catalog.js +1 -0
  98. package/dist/src/app-deployment-resolution.js +2 -0
  99. package/dist/src/app-helpers.js +1 -1
  100. package/dist/src/app-inventory-contract.js +1 -0
  101. package/dist/src/app-inventory.js +1 -0
  102. package/dist/src/app-launch.js +2 -0
  103. package/dist/src/app-lifecycle-facade.js +1 -0
  104. package/dist/src/app-lifecycle.js +3 -6
  105. package/dist/src/app-lifecycle2.js +2 -2
  106. package/dist/src/app-lifecycle3.js +1 -0
  107. package/dist/src/app-log-files.js +1 -1
  108. package/dist/src/app-log-reconnect.js +1 -1
  109. package/dist/src/app-log-runtime.js +1 -4
  110. package/dist/src/app-log-runtime2.js +4 -0
  111. package/dist/src/app-parsers.js +4 -0
  112. package/dist/src/app-resolution-cache.js +1 -0
  113. package/dist/src/app-resolution-facade.js +1 -0
  114. package/dist/src/app-resolution.js +2 -2
  115. package/dist/src/app-state.js +1 -2
  116. package/dist/src/apple-runner-platform.js +1 -0
  117. package/dist/src/application-lifecycle-interaction.js +1 -0
  118. package/dist/src/application-lifecycle-runtime.js +1 -0
  119. package/dist/src/apps-simctl.js +1 -0
  120. package/dist/src/archive.js +4 -0
  121. package/dist/src/artifact-download.js +1 -0
  122. package/dist/src/artifacts.d.ts +6 -2
  123. package/dist/src/artifacts.js +1 -1
  124. package/dist/src/async-lifecycle.js +1 -0
  125. package/dist/src/audio-probe-result.js +1 -0
  126. package/dist/src/audio-probe-runtime.js +1 -0
  127. package/dist/src/audio-probe-support.js +1 -0
  128. package/dist/src/auth-session.js +1 -1
  129. package/dist/src/auth.js +1 -1
  130. package/dist/src/backend-snapshot-options.js +1 -1
  131. package/dist/src/{url.js → base-url.js} +1 -1
  132. package/dist/src/boot-diagnostics.js +2 -2
  133. package/dist/src/byte-limit-stream.js +1 -1
  134. package/dist/src/capabilities.js +1 -0
  135. package/dist/src/capture.js +1 -0
  136. package/dist/src/catalog.js +1 -0
  137. package/dist/src/cli-command-aliases.js +1 -0
  138. package/dist/src/cli-config.js +1 -1
  139. package/dist/src/cli-help.js +74 -51
  140. package/dist/src/cli-output.js +1 -1
  141. package/dist/src/cli-runner.js +1 -1
  142. package/dist/src/cli.js +4 -6
  143. package/dist/src/click-button.js +1 -0
  144. package/dist/src/client-metro-companion.js +1 -0
  145. package/dist/src/client-metro.js +1 -1
  146. package/dist/src/client-types.d.ts +280 -242
  147. package/dist/src/clipboard.js +1 -0
  148. package/dist/src/code-signature-cache.js +1 -0
  149. package/dist/src/code-signature.js +1 -0
  150. package/dist/src/color.js +1 -0
  151. package/dist/src/command-metadata.js +1 -1
  152. package/dist/src/command-schema.js +3 -3
  153. package/dist/src/command-surface.js +1 -1
  154. package/dist/src/command-tools.js +2 -2
  155. package/dist/src/command.js +1 -0
  156. package/dist/src/compatibility-policy.js +1 -0
  157. package/dist/src/config.js +1 -1
  158. package/dist/src/config2.js +1 -0
  159. package/dist/src/connection-runtime.js +1 -1
  160. package/dist/src/connection.js +5 -5
  161. package/dist/src/contracts.d.ts +1 -1
  162. package/dist/src/contracts.js +1 -1
  163. package/dist/src/daemon-client-lifecycle.js +1 -0
  164. package/dist/src/daemon-process.js +1 -0
  165. package/dist/src/daemon-registration.js +1 -0
  166. package/dist/src/daemon-shutdown-report.js +1 -1
  167. package/dist/src/daemon.js +2 -2
  168. package/dist/src/debug-symbols-facade.js +5 -0
  169. package/dist/src/deploy-result-target.js +1 -0
  170. package/dist/src/device-claim-inspection.js +1 -1
  171. package/dist/src/device-claim-rule.js +1 -0
  172. package/dist/src/device-input-state.d.ts +190 -3
  173. package/dist/src/device-inventory-context.js +1 -0
  174. package/dist/src/device-isolation.js +1 -0
  175. package/dist/src/device-release.js +1 -0
  176. package/dist/src/device-rotation.js +1 -0
  177. package/dist/src/device-selection-resolver.js +1 -0
  178. package/dist/src/device-session.js +1 -0
  179. package/dist/src/device.js +1 -1
  180. package/dist/src/device2.js +3 -2
  181. package/dist/src/diagnostics.js +3 -0
  182. package/dist/src/diagnostics2.js +1 -0
  183. package/dist/src/dispatch-resolve.js +1 -0
  184. package/dist/src/doctor-facade.js +1 -0
  185. package/dist/src/doctor-output.js +1 -0
  186. package/dist/src/doctor.js +1 -0
  187. package/dist/src/doctor2.js +1 -0
  188. package/dist/src/doctor3.js +1 -0
  189. package/dist/src/durable-resource.js +1 -0
  190. package/dist/src/entities.js +1 -1
  191. package/dist/src/error.js +2 -0
  192. package/dist/src/exec.js +1 -0
  193. package/dist/src/file.js +1 -0
  194. package/dist/src/find.js +1 -1
  195. package/dist/src/finders.js +1 -1
  196. package/dist/src/generic-settle.js +1 -1
  197. package/dist/src/generic.js +1 -1
  198. package/dist/src/gesture-admission.js +1 -0
  199. package/dist/src/gesture-plan-types.js +1 -0
  200. package/dist/src/gesture-plan.js +1 -0
  201. package/dist/src/gesture-runtime.js +1 -0
  202. package/dist/src/harmonyos.js +1 -1
  203. package/dist/src/hdc.js +1 -1
  204. package/dist/src/helper.js +2 -2
  205. package/dist/src/host-file.js +1 -0
  206. package/dist/src/human-control-contract.js +1 -0
  207. package/dist/src/human-control.js +1 -0
  208. package/dist/src/index.d.ts +1 -1
  209. package/dist/src/index.js +1 -1
  210. package/dist/src/input-actions.js +1 -4
  211. package/dist/src/input-actions2.js +2 -1
  212. package/dist/src/install-artifact-facade.js +1 -0
  213. package/dist/src/install-source-network-transport.js +1 -0
  214. package/dist/src/install-source.d.ts +3 -10
  215. package/dist/src/install-source2.js +1 -1
  216. package/dist/src/interaction-positionals.js +1 -0
  217. package/dist/src/interaction-ref-policy.js +1 -0
  218. package/dist/src/interaction.js +1 -1
  219. package/dist/src/interaction2.js +1 -1
  220. package/dist/src/interactor-operation-catalog.js +1 -0
  221. package/dist/src/interactor-types.js +1 -0
  222. package/dist/src/interactor.js +6 -2
  223. package/dist/src/interactor2.js +1 -1
  224. package/dist/src/interactors.js +1 -1
  225. package/dist/src/internal/bin.d.ts +1 -1
  226. package/dist/src/internal/bin.js +1 -2
  227. package/dist/src/internal/companion-tunnel.d.ts +1 -1
  228. package/dist/src/internal/companion-tunnel.js +1 -1
  229. package/dist/src/internal/daemon.d.ts +1 -1
  230. package/dist/src/internal/daemon.js +2 -4
  231. package/dist/src/internal/png-worker.d.ts +4 -4
  232. package/dist/src/internal/png-worker.js +1 -1
  233. package/dist/src/internal/run-script-http-child.d.ts +4 -0
  234. package/dist/src/internal/run-script-http-child.js +1 -0
  235. package/dist/src/internal/update-check-entry.d.ts +1 -1
  236. package/dist/src/inventory.js +4 -4
  237. package/dist/src/inventory2.js +1 -1
  238. package/dist/src/inventory3.js +1 -1
  239. package/dist/src/inventory5.js +1 -1
  240. package/dist/src/inventory6.js +1 -1
  241. package/dist/src/ios-client.js +16 -0
  242. package/dist/src/ios-snapshot-acquisition.js +1 -0
  243. package/dist/src/ios-snapshot-adapter.js +1 -0
  244. package/dist/src/ios-snapshot-planning.js +1 -0
  245. package/dist/src/ios-snapshot-runtime.js +1 -0
  246. package/dist/src/ios-system-surface.js +1 -0
  247. package/dist/src/json.js +1 -0
  248. package/dist/src/keyboard-actions.js +1 -0
  249. package/dist/src/launch-console.js +1 -0
  250. package/dist/src/lease-context.js +1 -1
  251. package/dist/src/lease-scope.js +1 -0
  252. package/dist/src/lease.js +1 -1
  253. package/dist/src/limrun-runtime-dependencies.js +1 -1
  254. package/dist/src/limrun.d.ts +1610 -7
  255. package/dist/src/limrun.js +1 -1
  256. package/dist/src/linux.js +1 -1
  257. package/dist/src/local-interactor-operation-set.js +1 -0
  258. package/dist/src/location-coordinates.js +1 -1
  259. package/dist/src/logcat.js +1 -1
  260. package/dist/src/macos-facade.js +1 -0
  261. package/dist/src/managed-device-scope.js +1 -0
  262. package/dist/src/mechanics.js +19 -0
  263. package/dist/src/metro.d.ts +4 -2
  264. package/dist/src/metro.js +1 -1
  265. package/dist/src/metro2.js +1 -1
  266. package/dist/src/mobile-snapshot-semantics.js +1 -1
  267. package/dist/src/multitouch-support.js +1 -0
  268. package/dist/src/numeric.js +1 -0
  269. package/dist/src/observability.js +1 -1
  270. package/dist/src/observation.js +2 -0
  271. package/dist/src/open-target-resolution.js +1 -0
  272. package/dist/src/output-path.js +1 -1
  273. package/dist/src/owner-identity.js +3 -1
  274. package/dist/src/parameterized-recorded-fill.js +1 -0
  275. package/dist/src/parser.js +1 -1
  276. package/dist/src/perf-facade.js +2 -0
  277. package/dist/src/perf-process-identity.js +1 -0
  278. package/dist/src/perf-runtime-operation-builder.js +1 -0
  279. package/dist/src/perf-runtime-plan.js +1 -0
  280. package/dist/src/perf-runtime.js +1 -0
  281. package/dist/src/perf.js +1 -4
  282. package/dist/src/physical-device-control.js +1 -1
  283. package/dist/src/physical-device-facade.js +1 -0
  284. package/dist/src/platform-request-scope.js +1 -0
  285. package/dist/src/platform-runtime-android-adb-host.js +1 -0
  286. package/dist/src/platform-runtime-android-mechanics.js +1 -0
  287. package/dist/src/platform-runtime-app-log-android-transport.js +1 -1
  288. package/dist/src/platform-runtime-app-log-process.js +1 -1
  289. package/dist/src/platform-runtime-host.js +1 -1
  290. package/dist/src/platform-runtime-managed-owner.js +1 -0
  291. package/dist/src/platform-runtime-network-web-transport.js +1 -1
  292. package/dist/src/platform-runtime-open-target.js +1 -1
  293. package/dist/src/platform-runtime-operation-host.js +4 -4
  294. package/dist/src/platform-runtime-runtime-hints.js +2 -2
  295. package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
  296. package/dist/src/platform-runtime-screen-recording-apple-runner-host.js +1 -1
  297. package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
  298. package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
  299. package/dist/src/platform-runtime-screen-recording-apple-transport.js +1 -1
  300. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  301. package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
  302. package/dist/src/platform-runtime-screen-recording-process-host.js +1 -0
  303. package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
  304. package/dist/src/platform-runtime-unavailable.js +1 -0
  305. package/dist/src/platform-runtime.js +1 -1
  306. package/dist/src/platform-runtime2.js +1 -1
  307. package/dist/src/plist.js +1 -1
  308. package/dist/src/png-worker-contract.js +1 -1
  309. package/dist/src/prepare-kind.js +1 -0
  310. package/dist/src/process-exit.js +1 -1
  311. package/dist/src/process.js +1 -0
  312. package/dist/src/provider-device-runtime.js +1 -0
  313. package/dist/src/provider-session-ownership.js +2 -0
  314. package/dist/src/provider-webdriver.js +1 -1
  315. package/dist/src/provider.js +1 -1
  316. package/dist/src/providers.js +1 -0
  317. package/dist/src/proxy.js +2 -2
  318. package/dist/src/react-native-overlay.js +1 -0
  319. package/dist/src/react-native.js +1 -1
  320. package/dist/src/record-runtime.js +1 -1
  321. package/dist/src/record-trace.js +1 -1
  322. package/dist/src/rect-center.js +1 -0
  323. package/dist/src/register-builtins.js +1 -0
  324. package/dist/src/registry.js +40 -28
  325. package/dist/src/remote-config2.js +1 -1
  326. package/dist/src/replay-divergence.js +2 -0
  327. package/dist/src/replay.js +2 -2
  328. package/dist/src/reporting.js +8 -7
  329. package/dist/src/request-admission.js +1 -0
  330. package/dist/src/request-cancel.js +1 -0
  331. package/dist/src/request-cancellation.js +1 -0
  332. package/dist/src/request-progress-protocol.js +1 -0
  333. package/dist/src/request-providers.js +1 -0
  334. package/dist/src/request-runtime-binding.js +1 -0
  335. package/dist/src/request.js +1 -0
  336. package/dist/src/result-serialization.js +1 -0
  337. package/dist/src/retry.js +1 -0
  338. package/dist/src/rolldown-runtime.js +1 -1
  339. package/dist/src/runner-cache-metadata.js +2 -0
  340. package/dist/src/runner-client.js +1 -1
  341. package/dist/src/runner-disposal.js +1 -1
  342. package/dist/src/runner-operations-facade.js +1 -0
  343. package/dist/src/runner-owner-facade.js +1 -0
  344. package/dist/src/runner-owner-state.js +1 -0
  345. package/dist/src/runner-presentation.js +1 -0
  346. package/dist/src/runner.js +1 -0
  347. package/dist/src/{runtime-transport.js → runtime-transport-hints.js} +1 -1
  348. package/dist/src/runtime.js +3 -3
  349. package/dist/src/runtime2.js +4 -4
  350. package/dist/src/runtime3.js +1 -1
  351. package/dist/src/runtime4.js +5 -3
  352. package/dist/src/runtime5.js +1 -1
  353. package/dist/src/runtime6.js +1 -1
  354. package/dist/src/runtime7.js +1 -1
  355. package/dist/src/runtime8.js +1 -1
  356. package/dist/src/runtime9.js +1 -1
  357. package/dist/src/scoped-provider.js +1 -1
  358. package/dist/src/screen-recording-completion.js +1 -0
  359. package/dist/src/screen-recording-live-handle.js +1 -0
  360. package/dist/src/screen-recording-options.js +1 -0
  361. package/dist/src/screen-recording-resource-recovery.js +1 -0
  362. package/dist/src/screen-recording-runtime.js +1 -0
  363. package/dist/src/screenshot-density.js +1 -1
  364. package/dist/src/screenshot-result.js +1 -6
  365. package/dist/src/screenshot-runtime.js +1 -0
  366. package/dist/src/screenshot.js +1 -1
  367. package/dist/src/screenshot2.js +1 -0
  368. package/dist/src/screenshot3.js +5 -0
  369. package/dist/src/script.js +1 -0
  370. package/dist/src/scroll-command.js +1 -0
  371. package/dist/src/scroll-gesture.js +1 -0
  372. package/dist/src/scroll-indicator.js +1 -0
  373. package/dist/src/sdk-batch-runner.d.ts +23 -6
  374. package/dist/src/sdk-batch-runner.js +2 -3
  375. package/dist/src/sdk-batch.js +2 -0
  376. package/dist/src/sdk-contracts.d.ts +170 -41
  377. package/dist/src/sdk-contracts.js +2 -2
  378. package/dist/src/sdk-device.js +1 -1
  379. package/dist/src/sdk-finders.d.ts +1 -1
  380. package/dist/src/sdk-finders.js +1 -1
  381. package/dist/src/sdk-io.js +1 -1
  382. package/dist/src/sdk-remote-config.d.ts +1 -1
  383. package/dist/src/sdk-remote-config.js +1 -1
  384. package/dist/src/sdk-selectors.d.ts +524 -140
  385. package/dist/src/sdk-selectors.js +1 -1
  386. package/dist/src/selection.js +1 -0
  387. package/dist/src/selector-runtime.js +1 -1
  388. package/dist/src/selectors.js +1 -1
  389. package/dist/src/semantic-index.js +1 -0
  390. package/dist/src/server.js +4 -4
  391. package/dist/src/session-allocation.js +1 -0
  392. package/dist/src/session-artifact-paths.js +1 -0
  393. package/dist/src/session-observation.js +1 -0
  394. package/dist/src/session-paths.js +1 -0
  395. package/dist/src/session-repair-tombstone.js +1 -0
  396. package/dist/src/session-routing.js +1 -0
  397. package/dist/src/session-runtime-admission.js +1 -0
  398. package/dist/src/session-snapshot.js +1 -0
  399. package/dist/src/session-store.js +4 -0
  400. package/dist/src/session-target-evidence.js +1 -1
  401. package/dist/src/session2.js +5 -27
  402. package/dist/src/settings.js +1 -0
  403. package/dist/src/shared.js +2 -2
  404. package/dist/src/simctl-facade.js +1 -0
  405. package/dist/src/simctl.js +1 -1
  406. package/dist/src/simulator-facade.js +1 -0
  407. package/dist/src/simulator.js +1 -1
  408. package/dist/src/snapshot-capture-annotations.js +1 -0
  409. package/dist/src/snapshot-desktop-projection.js +1 -0
  410. package/dist/src/snapshot-diagnostics.js +1 -0
  411. package/dist/src/snapshot-process.js +1 -0
  412. package/dist/src/snapshot-quality-backend-capabilities.js +1 -0
  413. package/dist/src/snapshot-quality-verdict.js +1 -0
  414. package/dist/src/snapshot-runtime-binding.js +1 -0
  415. package/dist/src/snapshot-runtime.js +1 -1
  416. package/dist/src/snapshot-scope.js +1 -1
  417. package/dist/src/snapshot-state.js +1 -0
  418. package/dist/src/snapshot.js +1 -8
  419. package/dist/src/snapshot2.js +1 -1
  420. package/dist/src/snapshot3.js +1 -1
  421. package/dist/src/snapshot4.js +1 -0
  422. package/dist/src/src.js +1 -1
  423. package/dist/src/src2.js +1 -1
  424. package/dist/src/src3.js +1 -2
  425. package/dist/src/src4.js +1 -1
  426. package/dist/src/src5.js +1 -0
  427. package/dist/src/src6.js +1 -0
  428. package/dist/src/src7.js +2 -0
  429. package/dist/src/src8.js +115 -0
  430. package/dist/src/startup-recovery-fence.js +1 -0
  431. package/dist/src/status-markers.js +1 -0
  432. package/dist/src/string-enum.js +1 -1
  433. package/dist/src/success-text.js +1 -0
  434. package/dist/src/surface-snapshot.js +1 -0
  435. package/dist/src/surface-snapshot2.js +1 -0
  436. package/dist/src/takeover.js +5 -0
  437. package/dist/src/tool-provider-facade.js +1 -0
  438. package/dist/src/tool-provider.js +4 -3
  439. package/dist/src/tool-provider2.js +1 -1
  440. package/dist/src/tool-provider3.js +1 -1
  441. package/dist/src/toolchain-probe.js +2 -0
  442. package/dist/src/touch-reference-frame.js +1 -0
  443. package/dist/src/touch-runtime.js +1 -0
  444. package/dist/src/transport.js +3 -0
  445. package/dist/src/tree.js +1 -0
  446. package/dist/src/ttl-memo.js +1 -0
  447. package/dist/src/tv-remote.js +1 -0
  448. package/dist/src/type-text-runtime.js +1 -0
  449. package/dist/src/undici.js +99 -0
  450. package/dist/src/update-check.js +1 -1
  451. package/dist/src/verified-file.js +1 -1
  452. package/dist/src/version.js +1 -1
  453. package/dist/src/video.js +2 -2
  454. package/dist/src/web.js +2 -1
  455. package/dist/src/web2.js +1 -0
  456. package/dist/src/webdriver-ios-snapshot.js +1 -0
  457. package/dist/src/webdriver-source.js +1 -0
  458. package/dist/src/window-state.js +1 -0
  459. package/linux/atspi-dump.py +54 -9
  460. package/package.json +58 -35
  461. package/server.json +9 -3
  462. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.10.apk.sha256 +0 -1
  463. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk +0 -0
  464. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk.sha256 +0 -1
  465. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CoordinateTextEntryTests.swift +0 -4
  466. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -168
  467. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +0 -6
  468. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+RecordingTests.swift +0 -4
  469. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SelectorMatchPolicyTests.swift +0 -4
  470. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentation.swift +0 -183
  471. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationTests.swift +0 -0
  472. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +0 -4
  473. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryPolicyTests.swift +0 -4
  474. package/dist/src/appearance.js +0 -1
  475. package/dist/src/apps.js +0 -5
  476. package/dist/src/audio-probe.js +0 -1
  477. package/dist/src/cli-grammar.js +0 -1
  478. package/dist/src/command-catalog.js +0 -1
  479. package/dist/src/debug-symbols.js +0 -5
  480. package/dist/src/device-input-state.js +0 -2
  481. package/dist/src/device-ready.js +0 -1
  482. package/dist/src/dispatch.js +0 -1
  483. package/dist/src/handler-utils.js +0 -1
  484. package/dist/src/helper-package-install.js +0 -1
  485. package/dist/src/host-process.js +0 -3
  486. package/dist/src/ime-lifecycle.js +0 -2
  487. package/dist/src/ime-recovery-marker.js +0 -1
  488. package/dist/src/input-actions3.js +0 -1
  489. package/dist/src/install-artifact.js +0 -1
  490. package/dist/src/install-artifact2.js +0 -1
  491. package/dist/src/interaction-common.js +0 -1
  492. package/dist/src/interaction-runtime.js +0 -1
  493. package/dist/src/interaction-snapshot.js +0 -1
  494. package/dist/src/manifest.js +0 -1
  495. package/dist/src/method-scope.js +0 -1
  496. package/dist/src/png-resize.js +0 -1
  497. package/dist/src/process-lock.js +0 -1
  498. package/dist/src/runner-lease.js +0 -1
  499. package/dist/src/runner-sequence.js +0 -1
  500. package/dist/src/script-source-bundle.js +0 -16
  501. package/dist/src/sdk-android-adb.d.ts +0 -245
  502. package/dist/src/sdk-android-adb.js +0 -4
  503. package/dist/src/sdk.js +0 -1
  504. package/dist/src/setting-state.js +0 -1
  505. package/dist/src/shell-quote.js +0 -1
  506. package/dist/src/snapshot-session.js +0 -1
  507. package/dist/src/timing-safe-equal.js +0 -1
  508. package/dist/src/unsupported-interactor.js +0 -1
  509. package/dist/src/verdict.js +0 -1
  510. /package/dist/src/{recording-telemetry.js → telemetry.js} +0 -0
@@ -1,72 +1,34 @@
1
1
  import XCTest
2
+ import AgentDeviceSnapshotPresentation
3
+
4
+
5
+
6
+
7
+
8
+
9
+
2
10
 
3
- // MARK: - Snapshot capture plans (ADR 0004)
4
- //
5
- // Each snapshot strategy declares an ordered chain of capture backends. One runner walks the
6
- // chain: capture, classify, accept the first payload the quality classifier calls usable, and
7
- // stamp the outcome with a structured quality verdict so the daemon renders state instead of
8
- // re-deriving it from node shapes. Recovery ordering is data here, never a per-call-site branch.
9
11
 
10
- /// Structured quality verdict shipped with every iOS snapshot payload.
11
12
  struct SnapshotQuality: Codable {
12
- /// healthy: first backend produced a usable tree. recovered: a later backend did.
13
- /// sparse: no backend produced a usable tree; the best attempt is returned as-is.
13
+
14
+
14
15
  let state: String
15
- /// Backend that produced the returned payload: tree | queries | private-ax.
16
+
16
17
  let backend: String
17
- /// Why recovery ran (first failure) or why the payload is degraded.
18
+
19
+
18
20
  let reason: String?
19
- /// Machine-readable reason: ax-rejected | sparse-tree | budget | no-nodes.
21
+
22
+
20
23
  let reasonCode: String?
21
- /// Private AX ladder cap when the accepted tree is shallower than requested.
24
+
22
25
  let effectiveDepth: Int?
23
- /// Leaves that merge many labels — a container marked accessible hides its descendants.
24
- let collapsedLeafIndexes: [Int]?
25
- /// Coverage of the bounded custom-action pass, when the capture asked for one.
26
- let customActions: SnapshotCustomActionCoverage?
27
- }
28
26
 
29
- /// How much of the merged-element set the custom-action pass actually read. An
30
- /// unread element renders exactly like one with no actions, so a partial pass
31
- /// has to say so — otherwise absence reads as proof of absence.
32
- struct SnapshotCustomActionCoverage: Codable {
33
- let read: Int
34
- let candidates: Int
35
- /// Elements whose action list was clipped by the per-element output caps. A
36
- /// clipped list looks complete, so it is disclosed on the same principle as
37
- /// an unread element.
38
- let truncated: Int
39
- /// The pass stopped early because an earlier read is still hung. Distinct from
40
- /// a budget stop: the remedy is waiting, not scrolling.
41
- let blocked: Bool
42
- }
27
+ let collapsedLeafIndexes: [Int]?
43
28
 
44
- enum SnapshotBackendKind: String, CaseIterable {
45
- case recursiveTree = "tree"
46
- case querySweep = "queries"
47
- case privateAX = "private-ax"
48
-
49
- var usesXCTestAccessibilityChannel: Bool {
50
- switch self {
51
- case .recursiveTree, .querySweep:
52
- return true
53
- case .privateAX:
54
- return false
55
- }
56
- }
29
+ let customActions: SnapshotCustomActionCoverage?
57
30
 
58
- var isAvailableOnCurrentPlatform: Bool {
59
- switch self {
60
- case .recursiveTree, .querySweep:
61
- return true
62
- case .privateAX:
63
- #if os(iOS) && targetEnvironment(simulator)
64
- return true
65
- #else
66
- return false
67
- #endif
68
- }
69
- }
31
+ var timing: SnapshotCaptureTiming? = nil
70
32
  }
71
33
 
72
34
  enum SnapshotXCTestChannelPlanState: Equatable {
@@ -79,31 +41,47 @@ struct EffectiveSnapshotCapturePlan {
79
41
  let plan: [SnapshotBackendKind]
80
42
  let xCTestChannelState: SnapshotXCTestChannelPlanState
81
43
  let treeCaptureSliceBudgetOverride: TimeInterval?
44
+
45
+
46
+ let preferredBackend: SnapshotBackendKind?
82
47
  }
83
48
 
84
- /// What the plan runner does when every backend failed or stayed sparse.
49
+
85
50
  enum SnapshotCaptureTerminalPolicy {
86
- /// Return the best sparse payload; if the tree backend hit a real AX serialization failure
87
- /// on an interactive request, fail closed: invalidate the cached target and mark runnerFatal
88
- /// (AX-unavailable target invalidation, CONTEXT.md).
51
+
52
+
53
+
89
54
  case sparseWithFatalOnAXFailure
90
- /// Re-throw the tree backend's AX failure (raw diagnostics preserve errors, ADR 0004).
55
+
91
56
  case throwOnAXFailure
92
57
  }
93
58
 
94
59
  struct SnapshotBackendCapture {
95
60
  let payload: DataPayload
96
- /// Set by the private AX backend when the ladder accepted a shallower depth than requested.
97
61
  let effectiveDepth: Int?
98
- /// Set by the private AX backend when the capture asked for custom actions.
99
62
  var customActions: SnapshotCustomActionCoverage? = nil
63
+ var qualityPayload: DataPayload? = nil
64
+ var timing: SnapshotCaptureTiming? = nil
100
65
  }
101
66
 
102
67
  extension RunnerTests {
68
+ static func makeSnapshotBackendCapture(
69
+ from result: AgentDeviceSnapshotPresentation.SnapshotPresentationResult
70
+ ) -> SnapshotBackendCapture {
71
+ SnapshotBackendCapture(
72
+ payload: DataPayload(nodes: result.nodes, truncated: result.truncated),
73
+ effectiveDepth: result.effectiveDepth,
74
+ customActions: result.customActions,
75
+ qualityPayload: result.qualityNodes.map {
76
+ DataPayload(nodes: $0, truncated: result.truncated)
77
+ }
78
+ )
79
+ }
80
+
103
81
  static let sparseRecoveryTruncatedNodeThreshold = 8
104
- /// Umbrella wall-clock budget for one capture plan. Individual backends bound themselves,
105
- /// but chained recovery tiers must never stack past the 30s main-thread watchdog: when the
106
- /// budget is spent, remaining tiers are skipped and the best payload so far is returned.
82
+
83
+
84
+
107
85
  static let snapshotPlanBudget: TimeInterval = 20
108
86
  static let penalizedXCTestProbeTreeSliceBudget: TimeInterval = 1
109
87
  static let collapsedLeafMinimumSegments = 10
@@ -112,18 +90,21 @@ extension RunnerTests {
112
90
  payload?.nodes?.count ?? 0
113
91
  }
114
92
 
115
- // MARK: Plan definitions
93
+
116
94
 
117
95
  static let regularVisiblePlan: [SnapshotBackendKind] = [.recursiveTree, .querySweep, .privateAX]
118
- static let rawDiagnosticPlan: [SnapshotBackendKind] = [.recursiveTree, .privateAX]
119
96
 
120
- // MARK: XCTest accessibility channel penalty (cross-attempt memory, #1105/#1156)
121
- //
122
- // On some deep/dynamic screens the XCTest bulk snapshot no longer fails fast with
123
- // kAXErrorIllegalArgument (the #758 signature) — it grinds for many seconds first. One slow
124
- // grind is tolerable; re-grinding on every subsequent capture of the same screen buries the
125
- // main thread past the execution watchdog. After a slow, timed-out, or abandoned XCTest-backed
126
- // capture, later plans for the same bundle use non-XCTest recovery tiers until the penalty expires.
97
+
98
+
99
+ static let rawDiagnosticPlan: [SnapshotBackendKind] = regularVisiblePlan.filter(\.supportsRawProjection)
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
127
108
 
128
109
  func penalizeSnapshotXCTestChannel(bundleId: String?, reason: String) {
129
110
  snapshotXCTestChannelPenaltyLock.lock()
@@ -152,7 +133,7 @@ extension RunnerTests {
152
133
  snapshotXCTestChannelPenaltyLock.lock()
153
134
  defer { snapshotXCTestChannelPenaltyLock.unlock() }
154
135
  guard Date() < snapshotXCTestChannelPenaltyUntil else { return false }
155
- // A penalty recorded without a bundle id applies to whatever target is current.
136
+
156
137
  guard let penalized = snapshotXCTestChannelPenaltyBundleId else { return true }
157
138
  return penalized == bundleId
158
139
  }
@@ -163,20 +144,27 @@ extension RunnerTests {
163
144
  return pending
164
145
  }
165
146
 
166
- /// The pre-seeded first-failure a penalized plan stamps into its verdict. The deferred case
167
- /// uses the dedicated 'deferred' code: the breaker pre-selected the backend, nothing new
168
- /// degraded on this capture, and the daemon keys warning suppression and the settle budget
169
- /// reset off exactly that distinction. The bounded probe keeps 'budget': its short XCTest
170
- /// slice genuinely constrains what this capture could read.
171
- ///
172
- /// `requestPinnedBackend` separates the two ways the plan can arrive at the same
173
- /// deferred shape. A capture that ASKED for a private-AX-only reading (custom
174
- /// actions) degraded nothing, so reporting slow accessibility work would name a
175
- /// cause that does not exist.
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
176
157
  static func xcTestChannelStateFirstFailure(
177
158
  _ state: SnapshotXCTestChannelPlanState,
178
- requestPinnedBackend: Bool = false
159
+ requestPinnedBackend: Bool = false,
160
+ preferredBackend: String? = nil
179
161
  ) -> (reason: String, code: String)? {
162
+ if state == .normal && preferredBackend == SnapshotBackendKind.recursiveTree.rawValue {
163
+ return (
164
+ "the recursive XCTest tree backend was explicitly selected for this capture",
165
+ "requested-backend"
166
+ )
167
+ }
180
168
  switch state {
181
169
  case .normal:
182
170
  return nil
@@ -199,10 +187,10 @@ extension RunnerTests {
199
187
  }
200
188
  }
201
189
 
202
- /// Pure gate: a capture is planned as penalized when the channel penalty is
203
- /// active OR the daemon pinned the private-AX backend (same-backend evidence
204
- /// probe) — both mean "do not enter XCTest tree work first, and stamp the
205
- /// pre-selection as 'deferred' rather than a degradation".
190
+
191
+
192
+
193
+
206
194
  static func snapshotXCTestChannelTreatedAsPenalized(
207
195
  penalized: Bool,
208
196
  preferredBackend: String?
@@ -210,19 +198,36 @@ extension RunnerTests {
210
198
  penalized || preferredBackend == SnapshotBackendKind.privateAX.rawValue
211
199
  }
212
200
 
213
- /// Pure plan-reorder rule: a penalized XCTest accessibility channel uses independent backends
214
- /// when the platform has one, otherwise it keeps XCTest work on a short probe. The raw
215
- /// diagnostic plan keeps tree-first errors, and unknown plans are left untouched.
201
+
202
+
203
+
204
+
205
+
216
206
  static func effectiveSnapshotCapturePlan(
217
207
  _ plan: [SnapshotBackendKind],
218
208
  xCTestChannelPenalized: Bool,
219
- availableBackends: Set<SnapshotBackendKind> = Set(SnapshotBackendKind.allCases)
209
+ availableBackends: Set<SnapshotBackendKind> = Set(SnapshotBackendKind.allCases),
210
+ preferredBackend: String? = nil
220
211
  ) -> EffectiveSnapshotCapturePlan {
212
+ if
213
+ plan == Self.regularVisiblePlan,
214
+ let preferred = preferredBackend.flatMap(SnapshotBackendKind.init(rawValue:)),
215
+ preferred.isForceable,
216
+ availableBackends.contains(preferred)
217
+ {
218
+ return EffectiveSnapshotCapturePlan(
219
+ plan: [preferred],
220
+ xCTestChannelState: preferred == .privateAX ? .deferredToIndependentBackend : .normal,
221
+ treeCaptureSliceBudgetOverride: nil,
222
+ preferredBackend: preferred
223
+ )
224
+ }
221
225
  guard xCTestChannelPenalized, plan == Self.regularVisiblePlan else {
222
226
  return EffectiveSnapshotCapturePlan(
223
227
  plan: plan,
224
228
  xCTestChannelState: .normal,
225
- treeCaptureSliceBudgetOverride: nil
229
+ treeCaptureSliceBudgetOverride: nil,
230
+ preferredBackend: nil
226
231
  )
227
232
  }
228
233
  let availablePlan = plan.filter { availableBackends.contains($0) }
@@ -231,13 +236,15 @@ extension RunnerTests {
231
236
  return EffectiveSnapshotCapturePlan(
232
237
  plan: recoveryPlan,
233
238
  xCTestChannelState: .deferredToIndependentBackend,
234
- treeCaptureSliceBudgetOverride: nil
239
+ treeCaptureSliceBudgetOverride: nil,
240
+ preferredBackend: nil
235
241
  )
236
242
  }
237
243
  return EffectiveSnapshotCapturePlan(
238
244
  plan: availablePlan.filter(\.usesXCTestAccessibilityChannel),
239
245
  xCTestChannelState: .boundedXCTestProbe,
240
- treeCaptureSliceBudgetOverride: Self.penalizedXCTestProbeTreeSliceBudget
246
+ treeCaptureSliceBudgetOverride: Self.penalizedXCTestProbeTreeSliceBudget,
247
+ preferredBackend: nil
241
248
  )
242
249
  }
243
250
 
@@ -245,7 +252,7 @@ extension RunnerTests {
245
252
  kind.usesXCTestAccessibilityChannel && hasAbandonedTreeCapture()
246
253
  }
247
254
 
248
- // MARK: Plan runner
255
+
249
256
 
250
257
  func runSnapshotCapturePlan(
251
258
  _ plan: [SnapshotBackendKind],
@@ -257,16 +264,16 @@ extension RunnerTests {
257
264
  var best: (kind: SnapshotBackendKind, capture: SnapshotBackendCapture)?
258
265
  var firstFailure: (reason: String, code: String)?
259
266
  var axFailure: SnapshotCaptureFailure?
260
- // A caller may share the pre-plan system-modal probe's deadline; otherwise own the full budget (#1244).
267
+
261
268
  let deadline = deadline ?? Date().addingTimeInterval(Self.snapshotPlanBudget)
262
269
  let suppressXCTestPenalty = consumeSnapshotXCTestPenaltyWarmupExemption()
263
270
 
264
- // Reorder is iOS-only because hostile screens can make XCTest tree/query work grind while
265
- // the app remains visually responsive. Simulators can avoid that channel through private AX;
266
- // physical devices have no independent semantic backend yet, so they use a bounded probe.
267
- // A daemon-preferred private-AX capture (same-backend evidence probe) takes the exact
268
- // penalized route: privateAX-first plan, 'deferred' verdict — the backend was pre-selected
269
- // deliberately, so no degradation warning should render for it.
271
+
272
+
273
+
274
+
275
+
276
+
270
277
  var xCTestChannelPenalized = false
271
278
  var xCTestChannelPenalizedByBreaker = false
272
279
  #if os(iOS)
@@ -279,14 +286,16 @@ extension RunnerTests {
279
286
  let effective = Self.effectiveSnapshotCapturePlan(
280
287
  plan,
281
288
  xCTestChannelPenalized: xCTestChannelPenalized,
282
- availableBackends: Set(SnapshotBackendKind.allCases.filter(\.isAvailableOnCurrentPlatform))
289
+ availableBackends: Set(SnapshotBackendKind.allCases.filter(\.isAvailableOnCurrentPlatform)),
290
+ preferredBackend: options.preferredBackend
283
291
  )
284
292
  let effectivePlan = effective.plan
285
- // Only a customActions-implied pin is request-pinned; the daemon's
286
- // same-backend evidence probe pins for its own reasons and keeps 'deferred'.
293
+
294
+
287
295
  firstFailure = Self.xcTestChannelStateFirstFailure(
288
296
  effective.xCTestChannelState,
289
- requestPinnedBackend: options.customActions && !xCTestChannelPenalizedByBreaker
297
+ requestPinnedBackend: options.customActions && !xCTestChannelPenalizedByBreaker,
298
+ preferredBackend: effective.preferredBackend?.rawValue
290
299
  )
291
300
  switch effective.xCTestChannelState {
292
301
  case .normal:
@@ -305,8 +314,8 @@ extension RunnerTests {
305
314
  }
306
315
  break
307
316
  }
308
- // While an abandoned tree capture is still grinding inside testmanagerd, XCTest-backed
309
- // tiers would block behind it; only independent backends stay responsive (#1105).
317
+
318
+
310
319
  if shouldSkipSnapshotBackendForAbandonedTreeCapture(kind) {
311
320
  NSLog("AGENT_DEVICE_RUNNER_SNAPSHOT_TIER_SKIPPED_XCTEST_OCCUPIED tier=%@", kind.rawValue)
312
321
  if firstFailure == nil {
@@ -317,45 +326,22 @@ extension RunnerTests {
317
326
  }
318
327
  continue
319
328
  }
320
- let capture: SnapshotBackendCapture
321
- let backendStartedAt = Date()
322
- do {
323
- guard
324
- let result = try captureWithBackend(
325
- kind,
326
- app: app,
327
- options: options,
328
- deadline: deadline,
329
- treeCaptureSliceBudgetOverride: effective.treeCaptureSliceBudgetOverride
330
- )
331
- else {
332
- recordSlowXCTestSnapshotBackendIfNeeded(
333
- kind,
334
- startedAt: backendStartedAt,
335
- penaltySuppressed: suppressXCTestPenalty
336
- )
337
- continue
338
- }
339
- capture = result
340
- recordSlowXCTestSnapshotBackendIfNeeded(
341
- kind,
342
- startedAt: backendStartedAt,
343
- penaltySuppressed: suppressXCTestPenalty
344
- )
345
- } catch let failure as SnapshotCaptureFailure {
346
- recordXCTestSnapshotBackendFailureIfNeeded(
347
- kind,
348
- failure: failure,
349
- penaltySuppressed: suppressXCTestPenalty
350
- )
351
- recordSlowXCTestSnapshotBackendIfNeeded(
352
- kind,
353
- startedAt: backendStartedAt,
354
- penaltySuppressed: suppressXCTestPenalty
355
- )
329
+ let attempt = try captureWithBackend(
330
+ kind,
331
+ app: app,
332
+ options: options,
333
+ deadline: deadline,
334
+ treeCaptureSliceBudgetOverride: effective.treeCaptureSliceBudgetOverride
335
+ )
336
+ recordXCTestSnapshotBackendAttemptIfNeeded(
337
+ kind,
338
+ attempt: attempt,
339
+ penaltySuppressed: suppressXCTestPenalty
340
+ )
341
+ if case let .failed(failure, phase: _) = attempt.outcome {
356
342
  if Self.isAxSnapshotFailure(failure) { axFailure = failure }
357
343
  if firstFailure == nil {
358
- firstFailure = (failure.message, Self.isAxSnapshotFailure(failure) ? "ax-rejected" : "capture-failed")
344
+ firstFailure = (failure.message, Self.snapshotQualityReasonCode(for: failure))
359
345
  }
360
346
  NSLog(
361
347
  "AGENT_DEVICE_RUNNER_SNAPSHOT_BACKEND_FAILED backend=%@ error=%@",
@@ -364,8 +350,9 @@ extension RunnerTests {
364
350
  )
365
351
  continue
366
352
  }
353
+ guard case let .captured(capture) = attempt.outcome else { continue }
367
354
 
368
- if let sparseReason = Self.sparsePayloadReason(capture.payload) {
355
+ if let sparseReason = Self.sparsePayloadReason(capture.qualityPayload ?? capture.payload) {
369
356
  if firstFailure == nil { firstFailure = sparseReason }
370
357
  if Self.payloadNodeCount(capture.payload) > Self.payloadNodeCount(best?.capture.payload) {
371
358
  best = (kind, capture)
@@ -385,7 +372,7 @@ extension RunnerTests {
385
372
  capture,
386
373
  backend: kind,
387
374
  state: recovered ? "recovered" : "healthy",
388
- reason: recovered ? firstFailure : nil
375
+ reason: recovered || firstFailure?.code == "requested-backend" ? firstFailure : nil
389
376
  )
390
377
  }
391
378
 
@@ -397,11 +384,11 @@ extension RunnerTests {
397
384
  case .throwAxFailure:
398
385
  throw axFailure
399
386
  case .failClosed:
400
- // Fail closed on any interactive AX serialization failure that no backend recovered:
401
- // invalidate the cached target so the next command reacquires it (AX-unavailable target
402
- // invalidation, CONTEXT.md). A sparse `best` from a later tier (e.g. the query sweep's
403
- // synthetic root) must NOT suppress this — reaching the terminal already means no backend
404
- // produced a usable tree.
387
+
388
+
389
+
390
+
391
+
405
392
  return snapshotAccessibilityUnavailable(failure: axFailure)
406
393
  case .sparseBest:
407
394
  break
@@ -419,83 +406,125 @@ extension RunnerTests {
419
406
  return fallbackPayload
420
407
  }
421
408
 
422
- /// Marks XCTest-backed snapshot tiers as penalized when one attempt ground past the slow-capture
423
- /// threshold — even a successful one: the next capture of this screen must not re-grind.
424
- private func recordSlowXCTestSnapshotBackendIfNeeded(
425
- _ kind: SnapshotBackendKind,
426
- startedAt: Date,
427
- penaltySuppressed: Bool
428
- ) {
429
- guard !penaltySuppressed else { return }
430
- guard kind.usesXCTestAccessibilityChannel else { return }
431
- let elapsed = Date().timeIntervalSince(startedAt)
432
- guard elapsed > snapshotXCTestSlowCaptureThreshold else { return }
433
- penalizeSnapshotXCTestChannel(
434
- bundleId: currentBundleId,
435
- reason: "slow_\(kind.rawValue)_capture_\(Int(elapsed * 1000))ms"
436
- )
437
- }
438
-
439
- private func recordXCTestSnapshotBackendFailureIfNeeded(
440
- _ kind: SnapshotBackendKind,
441
- failure: SnapshotCaptureFailure,
442
- penaltySuppressed: Bool
443
- ) {
444
- guard !penaltySuppressed else { return }
445
- guard kind.usesXCTestAccessibilityChannel, failure.code == Self.xCTestSnapshotTimeoutCode else { return }
446
- penalizeSnapshotXCTestChannel(
447
- bundleId: currentBundleId,
448
- reason: "\(kind.rawValue)_backend_timeout"
449
- )
450
- }
451
-
452
409
  private func captureWithBackend(
453
410
  _ kind: SnapshotBackendKind,
454
411
  app: XCUIApplication,
455
412
  options: PresentationOptions,
456
413
  deadline: Date,
457
414
  treeCaptureSliceBudgetOverride: TimeInterval?
458
- ) throws -> SnapshotBackendCapture? {
415
+ ) throws -> SnapshotBackendAttempt {
416
+ let hint = SnapshotPresentation.captureHint(for: options)
417
+ var timer = SnapshotPhaseTimer()
459
418
  let acquisition: SnapshotAcquisition?
460
- switch kind {
461
- case .recursiveTree:
462
- guard
463
- let context = try makeSnapshotTraversalContext(
464
- app: app,
465
- options: options,
466
- captureDeadline: deadline,
467
- treeCaptureSliceBudgetOverride: treeCaptureSliceBudgetOverride
468
- )
469
- else {
470
- return nil
471
- }
472
- acquisition = try runMainThreadWork(
473
- command: nil,
474
- timeout: min(treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
475
- timeoutError: snapshotMainThreadTimeoutError("processing tree snapshot")
476
- ) {
477
- options.raw
478
- ? try self.rawTreeSnapshotAcquisition(context: context, options: options)
479
- : self.recursiveTreeSnapshotAcquisition(context: context, options: options)
419
+ do {
420
+ acquisition = try timer.measure(.acquisition) {
421
+ switch kind {
422
+ case .recursiveTree:
423
+ guard
424
+ let context = try self.makeSnapshotTraversalContext(
425
+ app: app,
426
+ hint: hint,
427
+ captureDeadline: deadline,
428
+ treeCaptureSliceBudgetOverride: treeCaptureSliceBudgetOverride
429
+ )
430
+ else {
431
+ return nil
432
+ }
433
+ return try self.runMainThreadWork(
434
+ timeout: min(self.treeCaptureSliceBudget, max(0.5, deadline.timeIntervalSinceNow)),
435
+ timeoutError: self.snapshotMainThreadTimeoutError("processing tree snapshot")
436
+ ) {
437
+ hint.isRaw
438
+ ? try self.rawTreeSnapshotAcquisition(context: context, hint: hint)
439
+ : self.recursiveTreeSnapshotAcquisition(context: context, hint: hint)
440
+ }
441
+ case .querySweep:
442
+ return try self.runMainThreadWork(
443
+ timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
444
+ timeoutError: self.snapshotMainThreadTimeoutError("running query-sweep snapshot")
445
+ ) {
446
+ self.querySweepSnapshotAcquisition(
447
+ app: app,
448
+ hint: hint,
449
+ planDeadline: deadline
450
+ )
451
+ }
452
+ case .privateAX:
453
+ return self.privateAXSnapshotAcquisition(
454
+ app: app,
455
+ hint: hint,
456
+ deadline: deadline
457
+ )
458
+ }
480
459
  }
481
- case .querySweep:
482
- acquisition = try runMainThreadWork(
483
- command: nil,
484
- timeout: min(Self.flatInteractiveFallbackBudget, max(0.1, deadline.timeIntervalSinceNow)),
485
- timeoutError: snapshotMainThreadTimeoutError("running query-sweep snapshot")
486
- ) {
487
- self.querySweepSnapshotAcquisition(app: app, options: options, planDeadline: deadline)
460
+ } catch let failure as SnapshotCaptureFailure {
461
+ return SnapshotBackendAttempt(
462
+ outcome: .failed(failure, phase: .acquisition),
463
+ timing: timer.timing
464
+ )
465
+ }
466
+ guard let acquisition else {
467
+ return SnapshotBackendAttempt(
468
+ outcome: .noCapture,
469
+ timing: timer.timing
470
+ )
471
+ }
472
+
473
+ let presented: SnapshotBackendCapture
474
+ do {
475
+ presented = try timer.measure(.presentation) {
476
+ guard let result = try SnapshotPresentation.present(acquisition, options: options) else {
477
+ NSLog(
478
+ "AGENT_DEVICE_RUNNER_SNAPSHOT_PROJECTION_MISMATCH requested=%@ acquired=%@",
479
+ hint.projection.rawValue,
480
+ acquisition.hint.projection.rawValue
481
+ )
482
+ throw Self.snapshotProjectionMismatchFailure(
483
+ kind,
484
+ requested: hint.projection,
485
+ acquired: acquisition.hint.projection
486
+ )
487
+ }
488
+ return Self.makeSnapshotBackendCapture(from: result)
488
489
  }
489
- case .privateAX:
490
- acquisition = privateAXSnapshotAcquisition(app: app, options: options, deadline: deadline)
490
+ } catch let failure as SnapshotPresentationFailure {
491
+ return SnapshotBackendAttempt(
492
+ outcome: .failed(Self.snapshotCaptureFailure(for: failure), phase: .presentation),
493
+ timing: timer.timing
494
+ )
495
+ } catch let failure as SnapshotCaptureFailure {
496
+ return SnapshotBackendAttempt(
497
+ outcome: .failed(failure, phase: .presentation),
498
+ timing: timer.timing
499
+ )
491
500
  }
492
- guard let acquisition else { return nil }
493
- return SnapshotPresentation.present(acquisition, options: options)
501
+
502
+ var capture = presented
503
+ capture.timing = timer.timing
504
+ return SnapshotBackendAttempt(
505
+ outcome: .captured(capture),
506
+ timing: timer.timing
507
+ )
508
+ }
509
+
510
+
511
+
512
+ static func snapshotProjectionMismatchFailure(
513
+ _ kind: SnapshotBackendKind,
514
+ requested: CaptureHint.Projection,
515
+ acquired: CaptureHint.Projection
516
+ ) -> SnapshotCaptureFailure {
517
+ SnapshotCaptureFailure(
518
+ code: "IOS_SNAPSHOT_PROJECTION_MISMATCH",
519
+ message:
520
+ "the \(kind.rawValue) backend returned a \(acquired.rawValue) capture for a \(requested.rawValue) snapshot request",
521
+ hint: "This is a runner bug: report it with the failing command and the app under test."
522
+ )
494
523
  }
495
524
 
496
- // MARK: Quality classifier (the single source of "is this snapshot degraded")
497
525
 
498
- /// Returns a degradation reason + machine code when the payload is too degraded to accept.
526
+
527
+
499
528
  static func sparsePayloadReason(_ payload: DataPayload) -> (reason: String, code: String)? {
500
529
  guard let nodes = payload.nodes, !nodes.isEmpty else {
501
530
  return ("snapshot returned no nodes", "no-nodes")
@@ -509,9 +538,9 @@ extension RunnerTests {
509
538
  return nil
510
539
  }
511
540
 
512
- /// Terminal action when a capture plan exhausted every backend with an AX serialization
513
- /// failure still pending. Pure so the fail-closed-vs-sparse policy is unit-testable without
514
- /// a live app (the ordering gap the architecture review flagged).
541
+
542
+
543
+
515
544
  enum SnapshotPlanTerminalAction: Equatable {
516
545
  case throwAxFailure
517
546
  case failClosed
@@ -536,8 +565,8 @@ extension RunnerTests {
536
565
  node.type == "Application" || node.type == "Window" ? node.rect : nil
537
566
  }
538
567
  return nodes.allSatisfy { node in
539
- // Application/Window labels are just the app/window name, and full-screen roots
540
- // compute as hittable; neither says anything about tree health.
568
+
569
+
541
570
  let isRootContainer = node.type == "Application" || node.type == "Window"
542
571
  guard Self.structuralOnlyNodeTypes.contains(node.type) else { return false }
543
572
  guard !isRootContainer else { return true }
@@ -553,18 +582,18 @@ extension RunnerTests {
553
582
  }
554
583
  }
555
584
 
556
- /// Private AX can stringify an unserializable accessibility label as the JavaScript object
557
- /// placeholder. It is transport residue, not UI content, and must not make a shell-only tree
558
- /// look healthy.
585
+
586
+
587
+
559
588
  static func isSemanticSnapshotText(_ text: String?) -> Bool {
560
589
  guard let text else { return false }
561
590
  let normalized = text.trimmingCharacters(in: .whitespacesAndNewlines)
562
591
  return !normalized.isEmpty && normalized.lowercased() != "[object object]"
563
592
  }
564
593
 
565
- /// A leaf whose label joins many short segments is a container marked as an accessibility
566
- /// element: the platform folds every descendant into one merged node. Nothing below it can
567
- /// be addressed — by automation or by assistive tech. This is app-side; no backend recovers it.
594
+
595
+
596
+
568
597
  static func collapsedLeafIndexes(_ nodes: [PresentedNode]) -> [Int]? {
569
598
  let parents = Set(nodes.compactMap { $0.parentIndex })
570
599
  let collapsed = nodes.filter { node in
@@ -576,7 +605,7 @@ extension RunnerTests {
576
605
  return collapsed.isEmpty ? nil : collapsed.map(\.index)
577
606
  }
578
607
 
579
- // MARK: Outcome stamping
608
+
580
609
 
581
610
  private func stampedSnapshotPayload(
582
611
  _ capture: SnapshotBackendCapture,
@@ -593,27 +622,36 @@ extension RunnerTests {
593
622
  reasonCode: reason?.code,
594
623
  effectiveDepth: capture.effectiveDepth,
595
624
  collapsedLeafIndexes: Self.collapsedLeafIndexes(payload.nodes ?? []),
596
- customActions: capture.customActions
625
+ customActions: capture.customActions,
626
+ timing: capture.timing
597
627
  )
598
628
  return DataPayload(
599
- // Legacy human text for older daemons that read message instead of snapshotQuality.
629
+
600
630
  message: Self.legacyQualityMessage(quality) ?? payload.message,
601
631
  nodes: payload.nodes,
602
- truncated: payload.truncated == true || state != "healthy" || capture.effectiveDepth != nil,
632
+
633
+
634
+
635
+
636
+ truncated: payload.truncated == true || state == "sparse" || capture.effectiveDepth != nil,
637
+ qualityPayload: capture.qualityPayload.flatMap { quality in
638
+ guard let nodes = quality.nodes else { return nil }
639
+ return SnapshotQualityPayload(nodes: nodes, truncated: quality.truncated == true)
640
+ },
603
641
  snapshotQuality: quality,
604
642
  runnerFatal: payload.runnerFatal,
605
643
  runnerFatalReason: payload.runnerFatalReason
606
644
  )
607
645
  }
608
646
 
609
- /// Response level, one line per incompleteness. An unread merged element is
610
- /// byte-identical to one with no actions, and a clipped list looks complete,
611
- /// so both have to name themselves.
647
+
648
+
649
+
612
650
  static func customActionCoverageWarnings(_ coverage: SnapshotCustomActionCoverage) -> [String] {
613
651
  var lines: [String] = []
614
652
  if coverage.blocked {
615
- // Scrolling is the remedy for a budget stop, not for this one — saying it
616
- // here would send the reader off doing something that cannot help.
653
+
654
+
617
655
  lines.append(
618
656
  "Custom actions were not read: an earlier accessibility read is still hung, so this "
619
657
  + "capture skipped the read pass instead of queueing behind it. No element's actions "
@@ -641,9 +679,15 @@ extension RunnerTests {
641
679
  else { return nil }
642
680
  var parts: [String] = []
643
681
  if quality.state == "recovered" {
644
- let meaning = quality.reasonCode == "budget" || quality.reasonCode == "deferred"
645
- ? " The primary capture ran out of its time budget (busy app or simulator); the recovered tree is authoritative for this screen."
646
- : " This usually means the app publishes an unhealthy accessibility tree — fixing the app's accessibility is the real cure. Treat screenshot as visual truth when this warning appears."
682
+ let meaning: String
683
+ switch quality.reasonCode {
684
+ case "budget", "deferred":
685
+ meaning = " The primary capture ran out of its time budget (busy app or simulator); the recovered tree is authoritative for this screen."
686
+ case "presentation-failed":
687
+ meaning = " The runner rejected a regular presentation because its cumulative clip invariant failed; report this as a runner bug and treat screenshot as visual truth."
688
+ default:
689
+ meaning = " This usually means the app publishes an unhealthy accessibility tree — fixing the app's accessibility is the real cure. Treat screenshot as visual truth when this warning appears."
690
+ }
647
691
  parts.append(
648
692
  "Detected an overly complex or slow accessibility tree. Fell back to the \(quality.backend) snapshot backend"
649
693
  + (quality.reason.map { " after: \($0)." } ?? ".")
@@ -659,9 +703,9 @@ extension RunnerTests {
659
703
  }
660
704
  parts.append(contentsOf: customActionWarnings)
661
705
  if let depth = quality.effectiveDepth {
662
- // No --depth remedy here: an explicit --depth capture disables the
663
- // frontier extension, so following it would return strictly less than
664
- // this capture did. A plain re-run retries with a fresh extension budget.
706
+
707
+
708
+
665
709
  parts.append(
666
710
  "The accessibility server rejected deeper requests; content below depth \(depth) may be missing — re-run snapshot to retry deeper content."
667
711
  )
@@ -670,3 +714,514 @@ extension RunnerTests {
670
714
  }
671
715
  }
672
716
 
717
+
718
+
719
+
720
+
721
+
722
+
723
+
724
+
725
+
726
+
727
+
728
+
729
+
730
+
731
+
732
+
733
+
734
+
735
+
736
+
737
+
738
+
739
+
740
+
741
+
742
+
743
+
744
+
745
+
746
+
747
+
748
+
749
+
750
+
751
+
752
+
753
+
754
+
755
+
756
+
757
+
758
+
759
+
760
+
761
+
762
+
763
+
764
+
765
+
766
+
767
+
768
+
769
+
770
+
771
+
772
+
773
+
774
+
775
+
776
+
777
+
778
+
779
+
780
+
781
+
782
+
783
+
784
+
785
+
786
+
787
+
788
+
789
+
790
+
791
+
792
+
793
+
794
+
795
+
796
+
797
+
798
+
799
+
800
+
801
+
802
+
803
+
804
+
805
+
806
+
807
+
808
+
809
+
810
+
811
+
812
+
813
+
814
+
815
+
816
+
817
+
818
+
819
+
820
+
821
+
822
+
823
+
824
+
825
+
826
+
827
+
828
+
829
+
830
+
831
+
832
+
833
+
834
+
835
+
836
+
837
+
838
+
839
+
840
+
841
+
842
+
843
+
844
+
845
+
846
+
847
+
848
+
849
+
850
+
851
+
852
+
853
+
854
+
855
+
856
+
857
+
858
+
859
+
860
+
861
+
862
+
863
+
864
+
865
+
866
+
867
+
868
+
869
+
870
+
871
+
872
+
873
+
874
+
875
+
876
+
877
+
878
+
879
+
880
+
881
+
882
+
883
+
884
+
885
+
886
+
887
+
888
+
889
+
890
+
891
+
892
+
893
+
894
+
895
+
896
+
897
+
898
+
899
+
900
+
901
+
902
+
903
+
904
+
905
+
906
+
907
+
908
+
909
+
910
+
911
+
912
+
913
+
914
+
915
+
916
+
917
+
918
+
919
+
920
+
921
+
922
+
923
+
924
+
925
+
926
+
927
+
928
+
929
+
930
+
931
+
932
+
933
+
934
+
935
+
936
+
937
+
938
+
939
+
940
+
941
+
942
+
943
+
944
+
945
+
946
+
947
+
948
+
949
+
950
+
951
+
952
+
953
+
954
+
955
+
956
+
957
+
958
+
959
+
960
+
961
+
962
+
963
+
964
+
965
+
966
+
967
+
968
+
969
+
970
+
971
+
972
+
973
+
974
+
975
+
976
+
977
+
978
+
979
+
980
+
981
+
982
+
983
+
984
+
985
+
986
+
987
+
988
+
989
+
990
+
991
+
992
+
993
+
994
+
995
+
996
+
997
+
998
+
999
+
1000
+
1001
+
1002
+
1003
+
1004
+
1005
+
1006
+
1007
+
1008
+
1009
+
1010
+
1011
+
1012
+
1013
+
1014
+
1015
+
1016
+
1017
+
1018
+
1019
+
1020
+
1021
+
1022
+
1023
+
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+
1030
+
1031
+
1032
+
1033
+
1034
+
1035
+
1036
+
1037
+
1038
+
1039
+
1040
+
1041
+
1042
+
1043
+
1044
+
1045
+
1046
+
1047
+
1048
+
1049
+
1050
+
1051
+
1052
+
1053
+
1054
+
1055
+
1056
+
1057
+
1058
+
1059
+
1060
+
1061
+
1062
+
1063
+
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+
1073
+
1074
+
1075
+
1076
+
1077
+
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+
1087
+
1088
+
1089
+
1090
+
1091
+
1092
+
1093
+
1094
+
1095
+
1096
+
1097
+
1098
+
1099
+
1100
+
1101
+
1102
+
1103
+
1104
+
1105
+
1106
+
1107
+
1108
+
1109
+
1110
+
1111
+
1112
+
1113
+
1114
+
1115
+
1116
+
1117
+
1118
+
1119
+
1120
+
1121
+
1122
+
1123
+
1124
+
1125
+
1126
+
1127
+
1128
+
1129
+
1130
+
1131
+
1132
+
1133
+
1134
+
1135
+
1136
+
1137
+
1138
+
1139
+
1140
+
1141
+
1142
+
1143
+
1144
+
1145
+
1146
+
1147
+
1148
+
1149
+
1150
+
1151
+
1152
+
1153
+
1154
+
1155
+
1156
+
1157
+
1158
+
1159
+
1160
+
1161
+
1162
+
1163
+
1164
+
1165
+
1166
+
1167
+
1168
+
1169
+
1170
+
1171
+
1172
+
1173
+
1174
+
1175
+
1176
+
1177
+
1178
+
1179
+
1180
+
1181
+
1182
+
1183
+
1184
+
1185
+
1186
+
1187
+
1188
+
1189
+
1190
+
1191
+
1192
+
1193
+
1194
+
1195
+
1196
+
1197
+
1198
+
1199
+
1200
+
1201
+
1202
+
1203
+
1204
+
1205
+
1206
+
1207
+
1208
+
1209
+
1210
+
1211
+
1212
+
1213
+
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+
1220
+
1221
+
1222
+
1223
+
1224
+
1225
+
1226
+
1227
+