agent-device 0.21.0 → 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 (282) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.0.apk → agent-device-android-ime-helper-0.21.1.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.1.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.0.manifest.json → agent-device-android-ime-helper-0.21.1.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.0.apk → agent-device-android-snapshot-helper-0.21.1.apk} +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.1.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.0.manifest.json → agent-device-android-snapshot-helper-0.21.1.manifest.json} +6 -6
  7. package/apple/snapshot-bridge/README.md +58 -1
  8. package/apple/snapshot-bridge/SnapshotBridge.m +6 -0
  9. package/apple/snapshot-bridge/SnapshotBridgeCapture.h +25 -0
  10. package/apple/snapshot-bridge/SnapshotBridgeCapture.m +138 -0
  11. package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +1 -0
  12. package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +32 -3
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +12 -0
  14. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +20 -0
  15. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSelectorMatchPolicy.swift +15 -15
  16. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +72 -0
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +63 -14
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +668 -82
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +14 -4
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +39 -4
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1065 -223
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +290 -0
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +1 -1
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +10 -10
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +249 -61
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +101 -42
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +13 -13
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +51 -43
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +71 -4
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +144 -7
  31. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +13 -1
  32. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +216 -17
  33. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +206 -22
  34. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +289 -42
  35. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +92 -22
  36. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +617 -122
  37. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +79 -4
  38. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +71 -71
  39. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +83 -5
  40. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +67 -67
  41. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +4 -4
  42. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +17 -17
  43. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +30 -30
  44. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +31 -31
  45. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +28 -0
  46. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +101 -0
  47. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +19 -19
  48. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +55 -17
  49. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +26 -5
  50. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +125 -75
  51. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +9 -9
  52. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +9 -9
  53. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +4 -4
  54. package/dist/src/adapter.js +1 -1
  55. package/dist/src/adb-executor.js +1 -1
  56. package/dist/src/adb-failure.js +1 -1
  57. package/dist/src/agent-browser-process-record.js +1 -1
  58. package/dist/src/agent-browser-provider.js +1 -1
  59. package/dist/src/agent-browser-tool.js +1 -1
  60. package/dist/src/agent-device-client.js +2 -2
  61. package/dist/src/ai-sdk.d.ts +1 -1
  62. package/dist/src/ai-sdk.js +1 -1
  63. package/dist/src/alert-runtime.js +1 -1
  64. package/dist/src/android-input-ownership.js +1 -1
  65. package/dist/src/app-catalog.js +1 -1
  66. package/dist/src/app-deployment-resolution.js +1 -1
  67. package/dist/src/app-inventory-contract.js +1 -1
  68. package/dist/src/app-inventory.js +1 -1
  69. package/dist/src/app-launch.js +2 -2
  70. package/dist/src/app-lifecycle.js +3 -3
  71. package/dist/src/app-lifecycle2.js +1 -1
  72. package/dist/src/app-log-files.js +1 -1
  73. package/dist/src/app-log-runtime2.js +3 -3
  74. package/dist/src/app-resolution.js +1 -1
  75. package/dist/src/apple-runner-platform.js +1 -0
  76. package/dist/src/application-lifecycle-interaction.js +1 -1
  77. package/dist/src/archive.js +1 -1
  78. package/dist/src/artifact-download.js +1 -1
  79. package/dist/src/auth-session.js +1 -1
  80. package/dist/src/auth.js +1 -1
  81. package/dist/src/backend-snapshot-options.js +1 -1
  82. package/dist/src/boot-diagnostics.js +1 -1
  83. package/dist/src/capture.js +1 -1
  84. package/dist/src/cli-config.js +1 -1
  85. package/dist/src/cli-help.js +25 -21
  86. package/dist/src/cli-runner.js +1 -1
  87. package/dist/src/cli.js +4 -4
  88. package/dist/src/click-button.js +1 -1
  89. package/dist/src/client-metro-companion.js +1 -1
  90. package/dist/src/client-metro.js +1 -1
  91. package/dist/src/client-types.d.ts +27 -13
  92. package/dist/src/code-signature-cache.js +1 -1
  93. package/dist/src/code-signature.js +1 -1
  94. package/dist/src/command-schema.js +3 -3
  95. package/dist/src/command-tools.js +2 -2
  96. package/dist/src/command.js +1 -1
  97. package/dist/src/connection-runtime.js +1 -1
  98. package/dist/src/connection.js +3 -3
  99. package/dist/src/contracts.d.ts +1 -1
  100. package/dist/src/contracts.js +1 -1
  101. package/dist/src/daemon-client-lifecycle.js +1 -1
  102. package/dist/src/daemon.js +1 -1
  103. package/dist/src/debug-symbols-facade.js +1 -1
  104. package/dist/src/device-claim-rule.js +1 -1
  105. package/dist/src/device-inventory-context.js +1 -1
  106. package/dist/src/device-rotation.js +1 -1
  107. package/dist/src/device-selection-resolver.js +1 -1
  108. package/dist/src/device-session.js +1 -1
  109. package/dist/src/device2.js +1 -1
  110. package/dist/src/diagnostics.js +1 -1
  111. package/dist/src/dispatch-resolve.js +1 -1
  112. package/dist/src/doctor2.js +1 -1
  113. package/dist/src/error.js +1 -1
  114. package/dist/src/exec.js +1 -1
  115. package/dist/src/file.js +1 -1
  116. package/dist/src/find.js +1 -1
  117. package/dist/src/generic-settle.js +1 -1
  118. package/dist/src/gesture-plan.js +1 -1
  119. package/dist/src/gesture-runtime.js +1 -1
  120. package/dist/src/harmonyos.js +1 -1
  121. package/dist/src/hdc.js +1 -1
  122. package/dist/src/helper.js +2 -2
  123. package/dist/src/human-control-contract.js +1 -1
  124. package/dist/src/human-control.js +1 -1
  125. package/dist/src/index.d.ts +1 -1
  126. package/dist/src/index.js +1 -1
  127. package/dist/src/input-actions.js +1 -1
  128. package/dist/src/input-actions2.js +2 -2
  129. package/dist/src/install-artifact-facade.js +1 -1
  130. package/dist/src/install-source-network-transport.js +1 -1
  131. package/dist/src/install-source2.js +1 -1
  132. package/dist/src/interaction-positionals.js +1 -1
  133. package/dist/src/interaction-ref-policy.js +1 -1
  134. package/dist/src/interaction2.js +1 -1
  135. package/dist/src/interactor.js +5 -5
  136. package/dist/src/interactor2.js +1 -1
  137. package/dist/src/interactors.js +1 -1
  138. package/dist/src/internal/bin.js +1 -1
  139. package/dist/src/internal/daemon.js +2 -2
  140. package/dist/src/internal/png-worker.js +1 -1
  141. package/dist/src/internal/run-script-http-child.js +1 -1
  142. package/dist/src/inventory.js +2 -2
  143. package/dist/src/inventory2.js +1 -1
  144. package/dist/src/inventory3.js +1 -1
  145. package/dist/src/inventory5.js +1 -1
  146. package/dist/src/ios-snapshot-runtime.js +1 -1
  147. package/dist/src/ios-system-surface.js +1 -0
  148. package/dist/src/lease-scope.js +1 -1
  149. package/dist/src/lease.js +1 -1
  150. package/dist/src/limrun-runtime-dependencies.js +1 -1
  151. package/dist/src/limrun.d.ts +1 -1
  152. package/dist/src/linux.js +1 -1
  153. package/dist/src/location-coordinates.js +1 -1
  154. package/dist/src/managed-device-scope.js +1 -1
  155. package/dist/src/mechanics.js +16 -16
  156. package/dist/src/multitouch-support.js +1 -1
  157. package/dist/src/observation.js +1 -1
  158. package/dist/src/open-target-resolution.js +1 -0
  159. package/dist/src/owner-identity.js +3 -3
  160. package/dist/src/parameterized-recorded-fill.js +1 -1
  161. package/dist/src/perf-facade.js +2 -2
  162. package/dist/src/perf-process-identity.js +1 -0
  163. package/dist/src/perf-runtime-operation-builder.js +1 -1
  164. package/dist/src/perf-runtime-plan.js +1 -1
  165. package/dist/src/perf.js +1 -1
  166. package/dist/src/physical-device-control.js +1 -1
  167. package/dist/src/platform-runtime-android-adb-host.js +1 -1
  168. package/dist/src/platform-runtime-app-log-process.js +1 -1
  169. package/dist/src/platform-runtime-host.js +1 -1
  170. package/dist/src/platform-runtime-managed-owner.js +1 -1
  171. package/dist/src/platform-runtime-open-target.js +1 -1
  172. package/dist/src/platform-runtime-operation-host.js +2 -2
  173. package/dist/src/platform-runtime-runtime-hints.js +2 -2
  174. package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
  175. package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
  176. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  177. package/dist/src/platform-runtime-unavailable.js +1 -1
  178. package/dist/src/platform-runtime.js +1 -1
  179. package/dist/src/platform-runtime2.js +1 -1
  180. package/dist/src/png-worker-contract.js +1 -1
  181. package/dist/src/prepare-kind.js +1 -1
  182. package/dist/src/provider-device-runtime.js +1 -1
  183. package/dist/src/provider-session-ownership.js +1 -1
  184. package/dist/src/provider-webdriver.js +1 -1
  185. package/dist/src/proxy.js +1 -1
  186. package/dist/src/react-native.js +1 -1
  187. package/dist/src/record-runtime.js +1 -1
  188. package/dist/src/rect-center.js +1 -1
  189. package/dist/src/register-builtins.js +1 -1
  190. package/dist/src/registry.js +37 -36
  191. package/dist/src/remote-config2.js +1 -1
  192. package/dist/src/replay-divergence.js +1 -1
  193. package/dist/src/replay.js +2 -2
  194. package/dist/src/reporting.js +9 -8
  195. package/dist/src/request-admission.js +1 -1
  196. package/dist/src/request-cancel.js +1 -1
  197. package/dist/src/request-runtime-binding.js +1 -1
  198. package/dist/src/retry.js +1 -1
  199. package/dist/src/runner-cache-metadata.js +2 -2
  200. package/dist/src/runner-client.js +1 -1
  201. package/dist/src/runner-disposal.js +1 -1
  202. package/dist/src/runner-operations-facade.js +1 -1
  203. package/dist/src/runner.js +1 -1
  204. package/dist/src/runtime-transport-hints.js +1 -1
  205. package/dist/src/runtime.js +3 -3
  206. package/dist/src/runtime2.js +4 -4
  207. package/dist/src/runtime3.js +1 -1
  208. package/dist/src/runtime4.js +5 -4
  209. package/dist/src/runtime5.js +1 -1
  210. package/dist/src/runtime6.js +1 -1
  211. package/dist/src/runtime7.js +1 -1
  212. package/dist/src/runtime8.js +1 -1
  213. package/dist/src/runtime9.js +1 -1
  214. package/dist/src/screen-recording-live-handle.js +1 -1
  215. package/dist/src/screen-recording-options.js +1 -1
  216. package/dist/src/screen-recording-resource-recovery.js +1 -1
  217. package/dist/src/screenshot-density.js +1 -1
  218. package/dist/src/screenshot-runtime.js +1 -1
  219. package/dist/src/screenshot.js +1 -1
  220. package/dist/src/screenshot3.js +3 -3
  221. package/dist/src/script.js +1 -1
  222. package/dist/src/scroll-command.js +1 -1
  223. package/dist/src/scroll-gesture.js +1 -1
  224. package/dist/src/sdk-batch-runner.js +2 -2
  225. package/dist/src/sdk-batch.js +2 -2
  226. package/dist/src/sdk-contracts.d.ts +44 -1
  227. package/dist/src/sdk-contracts.js +2 -2
  228. package/dist/src/sdk-device.js +1 -1
  229. package/dist/src/sdk-finders.d.ts +1 -1
  230. package/dist/src/sdk-io.js +1 -1
  231. package/dist/src/sdk-remote-config.d.ts +1 -1
  232. package/dist/src/sdk-remote-config.js +1 -1
  233. package/dist/src/sdk-selectors.d.ts +69 -13
  234. package/dist/src/selector-runtime.js +1 -1
  235. package/dist/src/server.js +3 -3
  236. package/dist/src/session-allocation.js +1 -1
  237. package/dist/src/session-observation.js +1 -0
  238. package/dist/src/session-routing.js +1 -1
  239. package/dist/src/session-runtime-admission.js +1 -1
  240. package/dist/src/session-snapshot.js +1 -1
  241. package/dist/src/session-store.js +3 -3
  242. package/dist/src/session-target-evidence.js +1 -1
  243. package/dist/src/session2.js +5 -5
  244. package/dist/src/settings.js +1 -1
  245. package/dist/src/simulator.js +1 -1
  246. package/dist/src/snapshot-quality-backend-capabilities.js +1 -1
  247. package/dist/src/snapshot-quality-verdict.js +1 -1
  248. package/dist/src/snapshot-runtime-binding.js +1 -1
  249. package/dist/src/snapshot-runtime.js +1 -1
  250. package/dist/src/snapshot-state.js +1 -1
  251. package/dist/src/snapshot2.js +1 -1
  252. package/dist/src/snapshot3.js +1 -1
  253. package/dist/src/snapshot4.js +1 -1
  254. package/dist/src/src.js +1 -1
  255. package/dist/src/src7.js +2 -2
  256. package/dist/src/src8.js +2 -2
  257. package/dist/src/string-enum.js +1 -1
  258. package/dist/src/takeover.js +1 -1
  259. package/dist/src/tool-provider.js +2 -2
  260. package/dist/src/tool-provider2.js +1 -1
  261. package/dist/src/tool-provider3.js +1 -1
  262. package/dist/src/toolchain-probe.js +1 -1
  263. package/dist/src/touch-reference-frame.js +1 -0
  264. package/dist/src/touch-runtime.js +1 -1
  265. package/dist/src/transport.js +1 -1
  266. package/dist/src/tv-remote.js +1 -1
  267. package/dist/src/type-text-runtime.js +1 -1
  268. package/dist/src/update-check.js +1 -1
  269. package/dist/src/verified-file.js +1 -1
  270. package/dist/src/video.js +1 -1
  271. package/dist/src/web.js +1 -1
  272. package/dist/src/web2.js +1 -1
  273. package/dist/src/webdriver-source.js +1 -1
  274. package/dist/src/window-state.js +1 -0
  275. package/package.json +3 -2
  276. package/server.json +2 -2
  277. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.0.apk.sha256 +0 -1
  278. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk.sha256 +0 -1
  279. package/dist/src/back-mode.js +0 -1
  280. package/dist/src/format.js +0 -2
  281. package/dist/src/platform-runtime-apple-resources.js +0 -1
  282. package/dist/src/runner-selector-query.js +0 -1
@@ -2,30 +2,30 @@ import XCTest
2
2
 
3
3
  private enum KeyboardDismissObservationTiming {
4
4
  static let timeout: TimeInterval = 2
5
- // #1542: dismissing the keyboard can trigger the host app's own content-offset
6
- // adjustment (e.g. a ScrollView correcting the inset it grew to keep a focused
7
- // field above the keyboard). That adjustment is a separate, unsynchronized
8
- // animation the keyboard's own `waitForNonExistence` above knows nothing about:
9
- // the keyboard AX element can vanish well before the app settles. The very next
10
- // command is frequently a synthesized, AX-free drag (scroll/gesture — kept
11
- // AX-free so it still works under #1105-family AX degradation), which has no
12
- // XCTest quiescence wait of its own, so it can land mid-animation and net to
13
- // zero. These bounds cap the settle wait this trades in.
14
- // A spring-driven content-offset correction can pass through a near-zero-
15
- // velocity inflection (the top of an overshoot) that two adjacent samples
16
- // alone cannot distinguish from true rest. Requiring 3 consecutive matching
17
- // samples demands ~2 full sample intervals of actual stillness before
18
- // stopping early, so a momentary pause mid-animation cannot look settled.
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
19
  static let settleTimeout: TimeInterval = 2.0
20
20
  static let settleSampleInterval: TimeInterval = 0.15
21
21
  static let settleRequiredConsecutiveMatches: Int = 3
22
22
  }
23
23
 
24
- // The mechanism that actually resigned the keyboard, disclosed to the caller
25
- // (#1598) so a response never claims "dismissed" without saying how — a
26
- // safe-area tap has a very different reliability/side-effect profile than
27
- // tapping the keyboard's own Done key, and callers need to know which one
28
- // fired.
24
+
25
+
26
+
27
+
28
+
29
29
  enum RunnerKeyboardDismissMechanism: String {
30
30
  case dismissKey
31
31
  }
@@ -61,25 +61,25 @@ extension RunnerTests {
61
61
  return (wasVisible: true, dismissed: !visible, visible: visible, mechanism: visible ? nil : .dismissKey)
62
62
  }
63
63
 
64
- // #1606 review P1 (twice): generic background-tap dismissal is
65
- // deliberately UNSUPPORTED. No geometry or role query can prove a
66
- // coordinate is side-effect-free — a full-screen unlabeled Pressable is
67
- // indistinguishable from an inert backdrop, so a "safe-area" tap can
68
- // navigate or submit while reporting a successful dismiss. The dismiss
69
- // key is the only mechanism the runner can vouch for.
64
+
65
+
66
+
67
+
68
+
69
+
70
70
  return (wasVisible: true, dismissed: false, visible: isKeyboardVisible(app: app), mechanism: nil)
71
71
  #endif
72
72
  }
73
73
 
74
74
 
75
- // AX-free on purpose (screenshot bytes, not the accessibility tree) so it holds
76
- // under the same AX degradation the synthesized gesture lane is built to survive.
77
- // Bounded and self-terminating: returns as soon as `requiredConsecutiveMatches`
78
- // consecutive samples match, so an already-settled screen (the common case)
79
- // pays close to nothing. The stopping decision itself
80
- // (`runnerScreenshotStabilitySettled`) is a pure function of the samples taken
81
- // so far, so it is unit-testable without a real screenshot pipeline; this loop
82
- // is the thin, untestable I/O shell around it.
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
83
  private func waitForScreenshotStability(
84
84
  timeout: TimeInterval,
85
85
  sampleInterval: TimeInterval,
@@ -252,15 +252,15 @@ extension RunnerTests {
252
252
  }
253
253
  }
254
254
 
255
- /// True once the `requiredConsecutiveMatches` most recent samples are all present
256
- /// and byte-identical — i.e. the screen held still across that whole run of
257
- /// polls, not just the last two. A spring-driven content-offset correction can
258
- /// pass through a near-zero-velocity inflection that two adjacent samples alone
259
- /// cannot distinguish from true rest; requiring a longer run of matches demands
260
- /// real elapsed stillness before stopping early. `nil` entries (a screenshot
261
- /// capture that failed) never count toward a match, so a flaky capture cannot
262
- /// look like stability; the caller's bounded loop still terminates on its
263
- /// deadline regardless.
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+
263
+
264
264
  func runnerScreenshotStabilitySettled(
265
265
  _ samples: [Data?],
266
266
  requiredConsecutiveMatches: Int
@@ -273,3 +273,62 @@ func runnerScreenshotStabilitySettled(
273
273
  return window.allSatisfy { $0 == firstData }
274
274
  }
275
275
 
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+
285
+
286
+
287
+
288
+
289
+
290
+
291
+
292
+
293
+
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+
302
+
303
+
304
+
305
+
306
+
307
+
308
+
309
+
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
332
+
333
+
334
+
@@ -22,7 +22,7 @@ func runnerCGImage(from image: RunnerImage) -> CGImage? {
22
22
  }
23
23
 
24
24
  extension RunnerTests {
25
- // MARK: - Recording
25
+
26
26
 
27
27
  func captureRunnerFrame() -> RunnerImage? {
28
28
  var image: RunnerImage?
@@ -70,7 +70,7 @@ extension RunnerTests {
70
70
  return (NSTemporaryDirectory() as NSString).appendingPathComponent(safeFileName)
71
71
  }
72
72
 
73
- // MARK: - Target Activation
73
+
74
74
 
75
75
  func ensureRunnerHostAppActive(reason: String) {
76
76
  NSLog(
@@ -103,9 +103,9 @@ extension RunnerTests {
103
103
 
104
104
  func resetTargetAfterExternalRelaunch() -> Response {
105
105
  invalidateCachedTarget(reason: "external_app_relaunch")
106
- // The app process is replaced, but the retained runner survives. Clear
107
- // process-bound capture state explicitly because invalidation drops the
108
- // old PID before refreshCachedTargetIfProcessChanged can observe it.
106
+
107
+
108
+
109
109
  clearSnapshotXCTestChannelPenalty(reason: "external_app_relaunch")
110
110
  clearPrivateAXAcceptedDepth(reason: "external_app_relaunch")
111
111
  beginFirstInteractionStabilization()
@@ -191,7 +191,7 @@ extension RunnerTests {
191
191
  initialState.rawValue,
192
192
  reason
193
193
  )
194
- // activate avoids terminating and relaunching the target app
194
+
195
195
  if initialState == .runningForeground {
196
196
  NSLog(
197
197
  "AGENT_DEVICE_RUNNER_ACTIVATE_SKIPPED bundle=%@ reason=already_foreground",
@@ -229,7 +229,7 @@ extension RunnerTests {
229
229
  performWithQuiescenceSkippedIfSupported(target, operation: operation)
230
230
  }
231
231
 
232
- // Some apps never report post-gesture quiescence, even after XCTest has synthesized the event.
232
+
233
233
  private func performWithQuiescenceSkippedIfSupported(
234
234
  _ target: XCUIApplication,
235
235
  operation: () -> Void
@@ -285,7 +285,7 @@ extension RunnerTests {
285
285
  return false
286
286
  }
287
287
 
288
- // MARK: - Command Classification
288
+
289
289
 
290
290
  func isReadOnlyCommand(_ command: Command) -> Bool {
291
291
  switch command.command.traits.readOnly {
@@ -294,7 +294,7 @@ extension RunnerTests {
294
294
  case .never:
295
295
  return false
296
296
  case .conditional:
297
- // Today only `alert` is conditional: read-only when getting, mutating otherwise.
297
+
298
298
  return (command.action ?? "get").lowercased() == "get"
299
299
  }
300
300
  }
@@ -313,7 +313,7 @@ extension RunnerTests {
313
313
  return command.traits.isLifecycle
314
314
  }
315
315
 
316
- // MARK: - Interaction Stabilization
316
+
317
317
 
318
318
  func applyInteractionStabilizationIfNeeded() {
319
319
  if needsPostSnapshotInteractionDelay {
@@ -326,8 +326,8 @@ extension RunnerTests {
326
326
  }
327
327
  }
328
328
 
329
- /// Start the post-activation settling window. Measured from now, so the time the caller spends
330
- /// getting back to us counts towards it instead of being charged twice.
329
+
330
+
331
331
  func beginFirstInteractionStabilization() {
332
332
  firstInteractionReadyUptime =
333
333
  ProcessInfo.processInfo.systemUptime + firstInteractionAfterActivateDelay
@@ -335,7 +335,7 @@ extension RunnerTests {
335
335
 
336
336
  func sleepFor(_ delay: TimeInterval) {
337
337
  guard delay > 0 else { return }
338
- // Keep XCTest/UI sources moving during command-local pauses such as delayed typing.
338
+
339
339
  if Thread.isMainThread {
340
340
  let deadline = Date().addingTimeInterval(delay)
341
341
  while Date() < deadline {
@@ -1,6 +1,6 @@
1
1
  import AgentDeviceSnapshotPresentation
2
2
 
3
- // MARK: - Wire Models
3
+
4
4
 
5
5
  enum CommandType: String, Codable {
6
6
  case tap
@@ -39,72 +39,72 @@ enum CommandType: String, Codable {
39
39
  case shutdown
40
40
  }
41
41
 
42
- /// Runner command traits — see CONTEXT.md ("Runner command traits").
43
- ///
44
- /// Single source of truth for how the runner classifies a command across three
45
- /// independent axes, replacing the three hand-maintained switches that used to live
46
- /// in RunnerTests+Lifecycle.swift (isInteractionCommand / isReadOnlyCommand /
47
- /// isRunnerLifecycleCommand). The classification is load-bearing for ADR-0002 session
48
- /// invalidation: `readOnly` gates the retry that nulls currentApp/currentBundleId.
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
49
  struct CommandTraits {
50
- /// Whether the command needs the foreground-guard + stabilization preflight before running.
50
+
51
51
  let isInteraction: Bool
52
- /// Whether the command is eligible for the session-invalidating retry.
53
- /// `.conditional` is resolved against the request (alert is read-only only for its `get` action).
52
+
53
+
54
54
  let readOnly: ReadOnly
55
- /// Whether the command skips the app-activation preflight entirely.
55
+
56
56
  let isLifecycle: Bool
57
57
 
58
58
  enum ReadOnly {
59
59
  case always
60
60
  case never
61
- /// Alert-only today. Resolved in `isReadOnlyCommand` with alert's rule (read-only for the
62
- /// `get` action, mutating otherwise). A new `.conditional` command would inherit that rule
63
- /// until the resolver is generalized — give it explicit handling there if its semantics differ.
61
+
62
+
63
+
64
64
  case conditional
65
65
  }
66
66
  }
67
67
 
68
68
  extension CommandType {
69
- /// The classification for this command. Exhaustive by construction: a new CommandType
70
- /// cannot compile without being classified here, so commands can no longer silently drift
71
- /// out of classification the way the parallel switches allowed.
69
+
70
+
71
+
72
72
  var traits: CommandTraits {
73
73
  switch self {
74
- // Interaction commands: require the foreground-guard + stabilization preflight.
75
- // keyboardReturn is the sibling of keyboardDismiss (missing from the historical switch —
76
- // drift the table now prevents). .scroll is the fused frame-resolve + drag scroll; same
77
- // classification as .drag. .desktopScroll is the macOS frame-resolve + wheel event sibling.
78
- // .sequence is the fused multi-step gesture batch.
74
+
75
+
76
+
77
+
78
+
79
79
  case .tap, .longPress, .drag, .remotePress, .type, .swipe, .scroll, .desktopScroll,
80
80
  .back, .backInApp, .backSystem, .rotate, .appSwitcher,
81
81
  .keyboardDismiss, .keyboardReturn, .sequence, .gesture:
82
82
  return CommandTraits(isInteraction: true, readOnly: .never, isLifecycle: false)
83
83
 
84
- // Read-only reads: eligible for the session-invalidating retry.
84
+
85
85
  case .findText, .readText, .snapshot, .gestureViewport:
86
86
  return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: false)
87
87
 
88
- // Screenshot is both a read and a runner-lifecycle command (skips app-activation preflight).
88
+
89
89
  case .screenshot:
90
90
  return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: true)
91
91
 
92
- // Alert is read-only only for its `get` action (resolved by isReadOnlyCommand).
92
+
93
93
  case .alert:
94
94
  return CommandTraits(isInteraction: false, readOnly: .conditional, isLifecycle: false)
95
95
 
96
- // Runner-lifecycle commands: skip the app-activation preflight.
96
+
97
97
  case .recordStop, .uptime, .terminate, .targetReset, .shutdown:
98
98
  return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: true)
99
99
 
100
100
  case .status:
101
101
  return CommandTraits(isInteraction: false, readOnly: .always, isLifecycle: true)
102
102
 
103
- // Normal preflight, not retried.
104
- // NOTE: mouseClick stays non-interaction for now — it is macOS-only and the foreground
105
- // guard interacts with bespoke macOS activation, so classifying it needs a macOS smoke
106
- // check first (tracked as a follow-up). Also preserved: querySelector is NOT read-only;
107
- // recordStart is NOT a lifecycle command; home/alert remain non-interaction by design.
103
+
104
+
105
+
106
+
107
+
108
108
  case .mouseClick, .querySelector, .home, .recordStart, .activate:
109
109
  return CommandTraits(isInteraction: false, readOnly: .never, isLifecycle: false)
110
110
  }
@@ -156,7 +156,7 @@ enum ScrollReleaseBehavior: String, Codable {
156
156
  case inertial
157
157
  }
158
158
 
159
- /// Canonical one- or two-pointer plan produced by the portable TypeScript planner.
159
+
160
160
  struct RunnerGesturePlan: Codable {
161
161
  let topology: String
162
162
  let intent: String
@@ -188,22 +188,22 @@ struct RunnerGesturePoint: Codable {
188
188
  let y: Double
189
189
  }
190
190
 
191
- /// One allowlisted coordinate gesture step inside a fused `sequence` command.
192
- /// `kind` is decoded as a raw String (not an enum) so the runner can return a clear
193
- /// INVALID_ARGS for an unknown kind instead of a generic decode failure.
191
+
192
+
193
+
194
194
  struct SequenceStep: Codable {
195
195
  let kind: String
196
196
  let x: Double?
197
197
  let y: Double?
198
198
  let durationMs: Double?
199
199
  let pauseMs: Double?
200
- /// For `tap` steps on iOS non-tv: use the synthesized HID fast path instead of the
201
- /// drag-based XCUICoordinate path, matching the individual command behavior.
200
+
201
+
202
202
  let synthesized: Bool?
203
203
  }
204
204
 
205
- /// Per-step result for a `sequence` response. `ok:false` carries the failing step's
206
- /// errorCode/errorMessage; execution stops at the first failed step.
205
+
206
+
207
207
  struct SequenceStepResult: Codable {
208
208
  let ok: Bool
209
209
  let kind: String
@@ -220,9 +220,9 @@ struct Response: Codable {
220
220
  }
221
221
 
222
222
  extension Response {
223
- // The daemon pairs this gesture-clock anchor with its own receipt time to map
224
- // gesture uptimes onto wall-clock for the recording touch overlay. Error responses
225
- // carry no anchor so the daemon falls back instead of pairing a stale value.
223
+
224
+
225
+
226
226
  func stampingCurrentUptimeMs(_ value: Double) -> Response {
227
227
  guard ok else { return self }
228
228
  var payload = data ?? DataPayload()
@@ -241,6 +241,8 @@ struct DataPayload: Codable {
241
241
  var truncated: Bool?
242
242
  var qualityPayload: SnapshotQualityPayload? = nil
243
243
  var snapshotQuality: SnapshotQuality?
244
+
245
+ var systemSurface: SystemSurfaceProvenancePayload?
244
246
  var gestureStartUptimeMs: Double?
245
247
  var gestureEndUptimeMs: Double?
246
248
  var x: Double?
@@ -275,6 +277,12 @@ struct DataPayload: Codable {
275
277
  var sequenceResults: [SequenceStepResult]?
276
278
  }
277
279
 
280
+
281
+ struct SystemSurfaceProvenancePayload: Codable {
282
+ let bundleId: String
283
+ let kind: String
284
+ }
285
+
278
286
  struct SnapshotQualityPayload: Codable {
279
287
  let nodes: [PresentedNode]
280
288
  let truncated: Bool
@@ -81,7 +81,7 @@ extension RunnerTests {
81
81
  return navigationBackKeywords.firstIndex { text.contains($0) }
82
82
  }
83
83
 
84
- // isFinite/>0 alone don't reject CGRect.infinite — its origin (~-9e307) is finite.
84
+
85
85
  static func isUsableNavigationFrame(_ frame: CGRect) -> Bool {
86
86
  guard frame.width.isFinite, frame.height.isFinite, frame.width > 0, frame.height > 0 else {
87
87
  return false
@@ -93,7 +93,7 @@ extension RunnerTests {
93
93
  guard isUsableNavigationFrame(candidate), isUsableNavigationFrame(window) else {
94
94
  return false
95
95
  }
96
- // Accept the compact navigation/search header band without matching deep content controls.
96
+
97
97
  let maxY = window.minY + min(max(window.height * 0.22, 96), 180)
98
98
  return candidate.midY >= window.minY && candidate.midY <= maxY
99
99
  }
@@ -102,9 +102,9 @@ extension RunnerTests {
102
102
  guard isUsableNavigationFrame(frame) else {
103
103
  return nil
104
104
  }
105
- // Aim at the standard leading navigation slot, bounded for compact and tablet widths.
105
+
106
106
  let xOffset = min(max(frame.width * 0.08, 28), 44)
107
- // Sit below the status/dynamic-island region and inside common custom RN search headers.
107
+
108
108
  let yOffset = min(max(frame.height * 0.155, 56), 132)
109
109
  return CGPoint(x: frame.minX + xOffset, y: frame.minY + yOffset)
110
110
  }
@@ -169,4 +169,71 @@ extension RunnerTests {
169
169
  return element.exists ? element : nil
170
170
  }
171
171
 
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
172
239
  }