agent-device 0.20.10 → 0.21.0

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 (490) 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.0.apk} +0 -0
  3. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.0.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.0.manifest.json} +4 -4
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.apk +0 -0
  6. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.0.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.0.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 +49 -0
  12. package/apple/snapshot-bridge/SnapshotBridge.m +280 -0
  13. package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +33 -0
  14. package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +382 -0
  15. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +58 -0
  16. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +19 -0
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAlertVerification.swift +36 -0
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerStringNormalization.swift +8 -0
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +12 -1
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +100 -6
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +2 -2
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +16 -8
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -88
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +124 -0
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +106 -103
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +6 -14
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +63 -91
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +13 -6
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +72 -155
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXElementTypes.swift +12 -0
  31. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +74 -78
  32. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +17 -9
  33. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +42 -11
  34. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +185 -461
  35. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +98 -0
  36. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +224 -164
  37. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationInvariant.swift +19 -0
  38. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +110 -0
  39. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +206 -0
  40. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +147 -25
  41. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +1 -0
  42. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +24 -307
  43. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +206 -0
  44. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +158 -0
  45. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +49 -16
  46. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +2 -11
  47. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +4 -19
  48. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -20
  49. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +111 -0
  50. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +42 -81
  51. package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +35 -82
  52. package/dist/apple/snapshot-presentation/Package.swift +21 -0
  53. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +56 -0
  54. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +259 -0
  55. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentation.swift +153 -0
  56. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationFailure.swift +27 -0
  57. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +91 -0
  58. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +161 -0
  59. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotScopePolicy.swift +53 -0
  60. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +242 -0
  61. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +97 -0
  62. package/dist/src/adapter.js +1 -0
  63. package/dist/src/adb-executor.js +2 -0
  64. package/dist/src/adb-failure.js +1 -0
  65. package/dist/src/adb-host.js +1 -0
  66. package/dist/src/adb.js +1 -0
  67. package/dist/src/agent-browser-lifecycle.js +1 -0
  68. package/dist/src/agent-browser-process-record.js +1 -0
  69. package/dist/src/agent-browser-provider.js +1 -0
  70. package/dist/src/agent-browser-tool.js +1 -1
  71. package/dist/src/agent-device-client.js +2 -2
  72. package/dist/src/ai-sdk.d.ts +2 -2
  73. package/dist/src/ai-sdk.js +1 -1
  74. package/dist/src/alert-contract.js +1 -0
  75. package/dist/src/alert-runtime.js +1 -0
  76. package/dist/src/android-adb.d.ts +27 -19
  77. package/dist/src/android-adb.js +1 -1
  78. package/dist/src/android-input-ownership.js +1 -0
  79. package/dist/src/android-system-chrome.js +1 -0
  80. package/dist/src/android.js +1 -1
  81. package/dist/src/api.js +11 -0
  82. package/dist/src/app-catalog.js +1 -0
  83. package/dist/src/app-deployment-resolution.js +2 -0
  84. package/dist/src/app-helpers.js +1 -1
  85. package/dist/src/app-inventory-contract.js +1 -0
  86. package/dist/src/app-inventory.js +1 -0
  87. package/dist/src/app-launch.js +2 -0
  88. package/dist/src/app-lifecycle-facade.js +1 -0
  89. package/dist/src/app-lifecycle.js +3 -6
  90. package/dist/src/app-lifecycle2.js +2 -2
  91. package/dist/src/app-lifecycle3.js +1 -0
  92. package/dist/src/app-log-files.js +1 -1
  93. package/dist/src/app-log-reconnect.js +1 -1
  94. package/dist/src/app-log-runtime.js +1 -4
  95. package/dist/src/app-log-runtime2.js +4 -0
  96. package/dist/src/app-parsers.js +4 -0
  97. package/dist/src/app-resolution-cache.js +1 -0
  98. package/dist/src/app-resolution-facade.js +1 -0
  99. package/dist/src/app-resolution.js +2 -2
  100. package/dist/src/app-state.js +1 -2
  101. package/dist/src/application-lifecycle-interaction.js +1 -0
  102. package/dist/src/application-lifecycle-runtime.js +1 -0
  103. package/dist/src/apps-simctl.js +1 -0
  104. package/dist/src/archive.js +4 -0
  105. package/dist/src/artifact-download.js +1 -0
  106. package/dist/src/artifacts.d.ts +6 -2
  107. package/dist/src/artifacts.js +1 -1
  108. package/dist/src/async-lifecycle.js +1 -0
  109. package/dist/src/audio-probe-result.js +1 -0
  110. package/dist/src/audio-probe-runtime.js +1 -0
  111. package/dist/src/audio-probe-support.js +1 -0
  112. package/dist/src/auth-session.js +1 -1
  113. package/dist/src/auth.js +1 -1
  114. package/dist/src/back-mode.js +1 -0
  115. package/dist/src/{url.js → base-url.js} +1 -1
  116. package/dist/src/boot-diagnostics.js +2 -2
  117. package/dist/src/byte-limit-stream.js +1 -1
  118. package/dist/src/capabilities.js +1 -0
  119. package/dist/src/capture.js +1 -0
  120. package/dist/src/catalog.js +1 -0
  121. package/dist/src/cli-command-aliases.js +1 -0
  122. package/dist/src/cli-config.js +1 -1
  123. package/dist/src/cli-help.js +69 -50
  124. package/dist/src/cli-output.js +1 -1
  125. package/dist/src/cli-runner.js +1 -1
  126. package/dist/src/cli.js +4 -6
  127. package/dist/src/click-button.js +1 -0
  128. package/dist/src/client-metro-companion.js +1 -0
  129. package/dist/src/client-metro.js +1 -1
  130. package/dist/src/client-types.d.ts +255 -231
  131. package/dist/src/clipboard.js +1 -0
  132. package/dist/src/code-signature-cache.js +1 -0
  133. package/dist/src/code-signature.js +1 -0
  134. package/dist/src/color.js +1 -0
  135. package/dist/src/command-metadata.js +1 -1
  136. package/dist/src/command-schema.js +3 -3
  137. package/dist/src/command-surface.js +1 -1
  138. package/dist/src/command-tools.js +2 -2
  139. package/dist/src/command.js +1 -0
  140. package/dist/src/compatibility-policy.js +1 -0
  141. package/dist/src/config.js +1 -1
  142. package/dist/src/config2.js +1 -0
  143. package/dist/src/connection-runtime.js +1 -1
  144. package/dist/src/connection.js +5 -5
  145. package/dist/src/contracts.d.ts +1 -1
  146. package/dist/src/contracts.js +1 -1
  147. package/dist/src/daemon-client-lifecycle.js +1 -0
  148. package/dist/src/daemon-process.js +1 -0
  149. package/dist/src/daemon-registration.js +1 -0
  150. package/dist/src/daemon-shutdown-report.js +1 -1
  151. package/dist/src/daemon.js +2 -2
  152. package/dist/src/debug-symbols-facade.js +5 -0
  153. package/dist/src/deploy-result-target.js +1 -0
  154. package/dist/src/device-claim-inspection.js +1 -1
  155. package/dist/src/device-claim-rule.js +1 -0
  156. package/dist/src/device-input-state.d.ts +190 -3
  157. package/dist/src/device-inventory-context.js +1 -0
  158. package/dist/src/device-isolation.js +1 -0
  159. package/dist/src/device-release.js +1 -0
  160. package/dist/src/device-rotation.js +1 -0
  161. package/dist/src/device-selection-resolver.js +1 -0
  162. package/dist/src/device-session.js +1 -0
  163. package/dist/src/device.js +1 -1
  164. package/dist/src/device2.js +3 -2
  165. package/dist/src/diagnostics.js +3 -0
  166. package/dist/src/diagnostics2.js +1 -0
  167. package/dist/src/dispatch-resolve.js +1 -0
  168. package/dist/src/doctor-facade.js +1 -0
  169. package/dist/src/doctor-output.js +1 -0
  170. package/dist/src/doctor.js +1 -0
  171. package/dist/src/doctor2.js +1 -0
  172. package/dist/src/doctor3.js +1 -0
  173. package/dist/src/durable-resource.js +1 -0
  174. package/dist/src/entities.js +1 -1
  175. package/dist/src/error.js +2 -0
  176. package/dist/src/exec.js +1 -0
  177. package/dist/src/file.js +1 -0
  178. package/dist/src/find.js +1 -1
  179. package/dist/src/finders.js +1 -1
  180. package/dist/src/format.js +2 -0
  181. package/dist/src/generic-settle.js +1 -1
  182. package/dist/src/generic.js +1 -1
  183. package/dist/src/gesture-admission.js +1 -0
  184. package/dist/src/gesture-plan-types.js +1 -0
  185. package/dist/src/gesture-plan.js +1 -0
  186. package/dist/src/gesture-runtime.js +1 -0
  187. package/dist/src/harmonyos.js +1 -1
  188. package/dist/src/hdc.js +1 -1
  189. package/dist/src/helper.js +2 -2
  190. package/dist/src/host-file.js +1 -0
  191. package/dist/src/human-control-contract.js +1 -0
  192. package/dist/src/human-control.js +1 -0
  193. package/dist/src/index.d.ts +1 -1
  194. package/dist/src/index.js +1 -1
  195. package/dist/src/input-actions.js +1 -4
  196. package/dist/src/input-actions2.js +2 -1
  197. package/dist/src/install-artifact-facade.js +1 -0
  198. package/dist/src/install-source-network-transport.js +1 -0
  199. package/dist/src/install-source.d.ts +3 -10
  200. package/dist/src/install-source2.js +1 -1
  201. package/dist/src/interaction-positionals.js +1 -0
  202. package/dist/src/interaction-ref-policy.js +1 -0
  203. package/dist/src/interaction.js +1 -1
  204. package/dist/src/interaction2.js +1 -1
  205. package/dist/src/interactor-operation-catalog.js +1 -0
  206. package/dist/src/interactor-types.js +1 -0
  207. package/dist/src/interactor.js +6 -2
  208. package/dist/src/interactor2.js +1 -1
  209. package/dist/src/interactors.js +1 -1
  210. package/dist/src/internal/bin.d.ts +1 -1
  211. package/dist/src/internal/bin.js +1 -2
  212. package/dist/src/internal/companion-tunnel.d.ts +1 -1
  213. package/dist/src/internal/companion-tunnel.js +1 -1
  214. package/dist/src/internal/daemon.d.ts +1 -1
  215. package/dist/src/internal/daemon.js +2 -4
  216. package/dist/src/internal/png-worker.d.ts +4 -4
  217. package/dist/src/internal/png-worker.js +1 -1
  218. package/dist/src/internal/run-script-http-child.d.ts +4 -0
  219. package/dist/src/internal/run-script-http-child.js +1 -0
  220. package/dist/src/internal/update-check-entry.d.ts +1 -1
  221. package/dist/src/inventory.js +4 -4
  222. package/dist/src/inventory2.js +1 -1
  223. package/dist/src/inventory3.js +1 -1
  224. package/dist/src/inventory5.js +1 -1
  225. package/dist/src/inventory6.js +1 -1
  226. package/dist/src/ios-client.js +16 -0
  227. package/dist/src/ios-snapshot-acquisition.js +1 -0
  228. package/dist/src/ios-snapshot-adapter.js +1 -0
  229. package/dist/src/ios-snapshot-planning.js +1 -0
  230. package/dist/src/ios-snapshot-runtime.js +1 -0
  231. package/dist/src/json.js +1 -0
  232. package/dist/src/keyboard-actions.js +1 -0
  233. package/dist/src/launch-console.js +1 -0
  234. package/dist/src/lease-context.js +1 -1
  235. package/dist/src/lease-scope.js +1 -0
  236. package/dist/src/lease.js +1 -1
  237. package/dist/src/limrun-runtime-dependencies.js +1 -1
  238. package/dist/src/limrun.d.ts +1610 -7
  239. package/dist/src/limrun.js +1 -1
  240. package/dist/src/linux.js +1 -1
  241. package/dist/src/local-interactor-operation-set.js +1 -0
  242. package/dist/src/location-coordinates.js +1 -1
  243. package/dist/src/logcat.js +1 -1
  244. package/dist/src/macos-facade.js +1 -0
  245. package/dist/src/managed-device-scope.js +1 -0
  246. package/dist/src/mechanics.js +19 -0
  247. package/dist/src/metro.d.ts +4 -2
  248. package/dist/src/metro.js +1 -1
  249. package/dist/src/metro2.js +1 -1
  250. package/dist/src/mobile-snapshot-semantics.js +1 -1
  251. package/dist/src/multitouch-support.js +1 -0
  252. package/dist/src/numeric.js +1 -0
  253. package/dist/src/observability.js +1 -1
  254. package/dist/src/observation.js +2 -0
  255. package/dist/src/output-path.js +1 -1
  256. package/dist/src/owner-identity.js +3 -1
  257. package/dist/src/parameterized-recorded-fill.js +1 -0
  258. package/dist/src/parser.js +1 -1
  259. package/dist/src/perf-facade.js +2 -0
  260. package/dist/src/perf-runtime-operation-builder.js +1 -0
  261. package/dist/src/perf-runtime-plan.js +1 -0
  262. package/dist/src/perf-runtime.js +1 -0
  263. package/dist/src/perf.js +1 -4
  264. package/dist/src/physical-device-control.js +1 -1
  265. package/dist/src/physical-device-facade.js +1 -0
  266. package/dist/src/platform-request-scope.js +1 -0
  267. package/dist/src/platform-runtime-android-adb-host.js +1 -0
  268. package/dist/src/platform-runtime-android-mechanics.js +1 -0
  269. package/dist/src/platform-runtime-app-log-android-transport.js +1 -1
  270. package/dist/src/platform-runtime-app-log-process.js +1 -1
  271. package/dist/src/platform-runtime-apple-resources.js +1 -0
  272. package/dist/src/platform-runtime-host.js +1 -1
  273. package/dist/src/platform-runtime-managed-owner.js +1 -0
  274. package/dist/src/platform-runtime-network-web-transport.js +1 -1
  275. package/dist/src/platform-runtime-open-target.js +1 -1
  276. package/dist/src/platform-runtime-operation-host.js +4 -4
  277. package/dist/src/platform-runtime-runtime-hints.js +2 -2
  278. package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
  279. package/dist/src/platform-runtime-screen-recording-apple-runner-host.js +1 -1
  280. package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
  281. package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
  282. package/dist/src/platform-runtime-screen-recording-apple-transport.js +1 -1
  283. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  284. package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
  285. package/dist/src/platform-runtime-screen-recording-process-host.js +1 -0
  286. package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
  287. package/dist/src/platform-runtime-unavailable.js +1 -0
  288. package/dist/src/platform-runtime.js +1 -1
  289. package/dist/src/platform-runtime2.js +1 -1
  290. package/dist/src/plist.js +1 -1
  291. package/dist/src/png-worker-contract.js +1 -1
  292. package/dist/src/prepare-kind.js +1 -0
  293. package/dist/src/process-exit.js +1 -1
  294. package/dist/src/process.js +1 -0
  295. package/dist/src/provider-device-runtime.js +1 -0
  296. package/dist/src/provider-session-ownership.js +2 -0
  297. package/dist/src/provider-webdriver.js +1 -1
  298. package/dist/src/provider.js +1 -1
  299. package/dist/src/providers.js +1 -0
  300. package/dist/src/proxy.js +2 -2
  301. package/dist/src/react-native-overlay.js +1 -0
  302. package/dist/src/react-native.js +1 -1
  303. package/dist/src/record-runtime.js +1 -1
  304. package/dist/src/record-trace.js +1 -1
  305. package/dist/src/rect-center.js +1 -0
  306. package/dist/src/register-builtins.js +1 -0
  307. package/dist/src/registry.js +39 -28
  308. package/dist/src/remote-config2.js +1 -1
  309. package/dist/src/replay-divergence.js +2 -0
  310. package/dist/src/replay.js +2 -2
  311. package/dist/src/reporting.js +8 -8
  312. package/dist/src/request-admission.js +1 -0
  313. package/dist/src/request-cancel.js +1 -0
  314. package/dist/src/request-cancellation.js +1 -0
  315. package/dist/src/request-progress-protocol.js +1 -0
  316. package/dist/src/request-providers.js +1 -0
  317. package/dist/src/request-runtime-binding.js +1 -0
  318. package/dist/src/request.js +1 -0
  319. package/dist/src/result-serialization.js +1 -0
  320. package/dist/src/retry.js +1 -0
  321. package/dist/src/rolldown-runtime.js +1 -1
  322. package/dist/src/runner-cache-metadata.js +2 -0
  323. package/dist/src/runner-client.js +1 -1
  324. package/dist/src/runner-disposal.js +1 -1
  325. package/dist/src/runner-operations-facade.js +1 -0
  326. package/dist/src/runner-owner-facade.js +1 -0
  327. package/dist/src/runner-owner-state.js +1 -0
  328. package/dist/src/runner-presentation.js +1 -0
  329. package/dist/src/runner-selector-query.js +1 -0
  330. package/dist/src/runner.js +1 -0
  331. package/dist/src/{runtime-transport.js → runtime-transport-hints.js} +1 -1
  332. package/dist/src/runtime.js +3 -3
  333. package/dist/src/runtime2.js +4 -4
  334. package/dist/src/runtime3.js +1 -1
  335. package/dist/src/runtime4.js +4 -3
  336. package/dist/src/runtime5.js +1 -1
  337. package/dist/src/runtime6.js +1 -1
  338. package/dist/src/runtime7.js +1 -1
  339. package/dist/src/runtime8.js +1 -1
  340. package/dist/src/runtime9.js +1 -1
  341. package/dist/src/scoped-provider.js +1 -1
  342. package/dist/src/screen-recording-completion.js +1 -0
  343. package/dist/src/screen-recording-live-handle.js +1 -0
  344. package/dist/src/screen-recording-options.js +1 -0
  345. package/dist/src/screen-recording-resource-recovery.js +1 -0
  346. package/dist/src/screen-recording-runtime.js +1 -0
  347. package/dist/src/screenshot-density.js +1 -1
  348. package/dist/src/screenshot-result.js +1 -6
  349. package/dist/src/screenshot-runtime.js +1 -0
  350. package/dist/src/screenshot.js +1 -1
  351. package/dist/src/screenshot2.js +1 -0
  352. package/dist/src/screenshot3.js +5 -0
  353. package/dist/src/script.js +1 -0
  354. package/dist/src/scroll-command.js +1 -0
  355. package/dist/src/scroll-gesture.js +1 -0
  356. package/dist/src/scroll-indicator.js +1 -0
  357. package/dist/src/sdk-batch-runner.d.ts +23 -6
  358. package/dist/src/sdk-batch-runner.js +2 -3
  359. package/dist/src/sdk-batch.js +2 -0
  360. package/dist/src/sdk-contracts.d.ts +127 -41
  361. package/dist/src/sdk-contracts.js +2 -2
  362. package/dist/src/sdk-device.js +1 -1
  363. package/dist/src/sdk-finders.js +1 -1
  364. package/dist/src/sdk-io.js +1 -1
  365. package/dist/src/sdk-remote-config.d.ts +1 -1
  366. package/dist/src/sdk-remote-config.js +1 -1
  367. package/dist/src/sdk-selectors.d.ts +472 -144
  368. package/dist/src/sdk-selectors.js +1 -1
  369. package/dist/src/selection.js +1 -0
  370. package/dist/src/selector-runtime.js +1 -1
  371. package/dist/src/selectors.js +1 -1
  372. package/dist/src/semantic-index.js +1 -0
  373. package/dist/src/server.js +4 -4
  374. package/dist/src/session-allocation.js +1 -0
  375. package/dist/src/session-artifact-paths.js +1 -0
  376. package/dist/src/session-paths.js +1 -0
  377. package/dist/src/session-repair-tombstone.js +1 -0
  378. package/dist/src/session-routing.js +1 -0
  379. package/dist/src/session-runtime-admission.js +1 -0
  380. package/dist/src/session-snapshot.js +1 -0
  381. package/dist/src/session-store.js +4 -0
  382. package/dist/src/session-target-evidence.js +1 -1
  383. package/dist/src/session2.js +5 -27
  384. package/dist/src/settings.js +1 -0
  385. package/dist/src/shared.js +2 -2
  386. package/dist/src/simctl-facade.js +1 -0
  387. package/dist/src/simctl.js +1 -1
  388. package/dist/src/simulator-facade.js +1 -0
  389. package/dist/src/simulator.js +1 -1
  390. package/dist/src/snapshot-capture-annotations.js +1 -0
  391. package/dist/src/snapshot-desktop-projection.js +1 -0
  392. package/dist/src/snapshot-diagnostics.js +1 -0
  393. package/dist/src/snapshot-process.js +1 -0
  394. package/dist/src/snapshot-quality-backend-capabilities.js +1 -0
  395. package/dist/src/snapshot-quality-verdict.js +1 -0
  396. package/dist/src/snapshot-runtime-binding.js +1 -0
  397. package/dist/src/snapshot-runtime.js +1 -1
  398. package/dist/src/snapshot-scope.js +1 -1
  399. package/dist/src/snapshot-state.js +1 -0
  400. package/dist/src/snapshot.js +1 -8
  401. package/dist/src/snapshot2.js +1 -1
  402. package/dist/src/snapshot3.js +1 -1
  403. package/dist/src/snapshot4.js +1 -0
  404. package/dist/src/src.js +1 -1
  405. package/dist/src/src2.js +1 -1
  406. package/dist/src/src3.js +1 -2
  407. package/dist/src/src4.js +1 -1
  408. package/dist/src/src5.js +1 -0
  409. package/dist/src/src6.js +1 -0
  410. package/dist/src/src7.js +2 -0
  411. package/dist/src/src8.js +115 -0
  412. package/dist/src/startup-recovery-fence.js +1 -0
  413. package/dist/src/status-markers.js +1 -0
  414. package/dist/src/string-enum.js +1 -1
  415. package/dist/src/success-text.js +1 -0
  416. package/dist/src/surface-snapshot.js +1 -0
  417. package/dist/src/surface-snapshot2.js +1 -0
  418. package/dist/src/takeover.js +5 -0
  419. package/dist/src/tool-provider-facade.js +1 -0
  420. package/dist/src/tool-provider.js +4 -3
  421. package/dist/src/tool-provider2.js +1 -1
  422. package/dist/src/tool-provider3.js +1 -1
  423. package/dist/src/toolchain-probe.js +2 -0
  424. package/dist/src/touch-runtime.js +1 -0
  425. package/dist/src/transport.js +3 -0
  426. package/dist/src/tree.js +1 -0
  427. package/dist/src/ttl-memo.js +1 -0
  428. package/dist/src/tv-remote.js +1 -0
  429. package/dist/src/type-text-runtime.js +1 -0
  430. package/dist/src/undici.js +99 -0
  431. package/dist/src/update-check.js +1 -1
  432. package/dist/src/verified-file.js +1 -1
  433. package/dist/src/version.js +1 -1
  434. package/dist/src/video.js +2 -2
  435. package/dist/src/web.js +2 -1
  436. package/dist/src/web2.js +1 -0
  437. package/dist/src/webdriver-ios-snapshot.js +1 -0
  438. package/dist/src/webdriver-source.js +1 -0
  439. package/linux/atspi-dump.py +54 -9
  440. package/package.json +56 -34
  441. package/server.json +9 -3
  442. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.10.apk.sha256 +0 -1
  443. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk +0 -0
  444. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk.sha256 +0 -1
  445. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CoordinateTextEntryTests.swift +0 -4
  446. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -168
  447. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +0 -6
  448. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+RecordingTests.swift +0 -4
  449. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SelectorMatchPolicyTests.swift +0 -4
  450. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentation.swift +0 -183
  451. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationTests.swift +0 -0
  452. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +0 -4
  453. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryPolicyTests.swift +0 -4
  454. package/dist/src/appearance.js +0 -1
  455. package/dist/src/apps.js +0 -5
  456. package/dist/src/audio-probe.js +0 -1
  457. package/dist/src/cli-grammar.js +0 -1
  458. package/dist/src/command-catalog.js +0 -1
  459. package/dist/src/debug-symbols.js +0 -5
  460. package/dist/src/device-input-state.js +0 -2
  461. package/dist/src/device-ready.js +0 -1
  462. package/dist/src/dispatch.js +0 -1
  463. package/dist/src/handler-utils.js +0 -1
  464. package/dist/src/helper-package-install.js +0 -1
  465. package/dist/src/host-process.js +0 -3
  466. package/dist/src/ime-lifecycle.js +0 -2
  467. package/dist/src/ime-recovery-marker.js +0 -1
  468. package/dist/src/input-actions3.js +0 -1
  469. package/dist/src/install-artifact.js +0 -1
  470. package/dist/src/install-artifact2.js +0 -1
  471. package/dist/src/interaction-common.js +0 -1
  472. package/dist/src/interaction-runtime.js +0 -1
  473. package/dist/src/interaction-snapshot.js +0 -1
  474. package/dist/src/manifest.js +0 -1
  475. package/dist/src/method-scope.js +0 -1
  476. package/dist/src/png-resize.js +0 -1
  477. package/dist/src/process-lock.js +0 -1
  478. package/dist/src/runner-lease.js +0 -1
  479. package/dist/src/runner-sequence.js +0 -1
  480. package/dist/src/script-source-bundle.js +0 -16
  481. package/dist/src/sdk-android-adb.d.ts +0 -245
  482. package/dist/src/sdk-android-adb.js +0 -4
  483. package/dist/src/sdk.js +0 -1
  484. package/dist/src/setting-state.js +0 -1
  485. package/dist/src/shell-quote.js +0 -1
  486. package/dist/src/snapshot-session.js +0 -1
  487. package/dist/src/timing-safe-equal.js +0 -1
  488. package/dist/src/unsupported-interactor.js +0 -1
  489. package/dist/src/verdict.js +0 -1
  490. /package/dist/src/{recording-telemetry.js → telemetry.js} +0 -0
@@ -0,0 +1,110 @@
1
+ import Foundation
2
+ import XCTest
3
+
4
+ struct SnapshotCaptureTiming: Codable, Equatable {
5
+ let acquisitionMs: Double
6
+ let presentationMs: Double
7
+
8
+ init(acquisitionMs: Double, presentationMs: Double) {
9
+ self.acquisitionMs = max(0, acquisitionMs)
10
+ self.presentationMs = max(0, presentationMs)
11
+ }
12
+
13
+ init(acquisition: TimeInterval, presentation: TimeInterval) {
14
+ self.init(
15
+ acquisitionMs: max(0, acquisition) * 1_000,
16
+ presentationMs: max(0, presentation) * 1_000
17
+ )
18
+ }
19
+ }
20
+
21
+ enum SnapshotCapturePhase: Equatable {
22
+ case acquisition
23
+ case presentation
24
+ }
25
+
26
+ struct SnapshotPhaseTimer {
27
+ private let now: () -> Date
28
+ private var acquisitionSeconds: TimeInterval = 0
29
+ private var presentationSeconds: TimeInterval = 0
30
+
31
+ init(now: @escaping () -> Date = { Date() }) {
32
+ self.now = now
33
+ }
34
+
35
+ mutating func measure<T>(
36
+ _ phase: SnapshotCapturePhase,
37
+ _ operation: () throws -> T
38
+ ) rethrows -> T {
39
+ let startedAt = now()
40
+ defer {
41
+ let elapsed = max(0, now().timeIntervalSince(startedAt))
42
+ switch phase {
43
+ case .acquisition:
44
+ acquisitionSeconds += elapsed
45
+ case .presentation:
46
+ presentationSeconds += elapsed
47
+ }
48
+ }
49
+ return try operation()
50
+ }
51
+
52
+ var timing: SnapshotCaptureTiming {
53
+ SnapshotCaptureTiming(
54
+ acquisition: acquisitionSeconds,
55
+ presentation: presentationSeconds
56
+ )
57
+ }
58
+ }
59
+
60
+ extension RunnerTests {
61
+ struct SnapshotBackendAttempt {
62
+ enum Outcome {
63
+ case noCapture
64
+ case captured(SnapshotBackendCapture)
65
+ case failed(SnapshotCaptureFailure, phase: SnapshotCapturePhase)
66
+ }
67
+
68
+ /// The failure phase is part of the result, so penalty policy cannot infer it from duration
69
+ /// or error text.
70
+ let outcome: Outcome
71
+ let timing: SnapshotCaptureTiming
72
+ }
73
+
74
+ /// The penalty breaker observes only acquisition facts. Presentation is a separate phase and
75
+ /// cannot arm the breaker, even when it is slower than the acquisition that produced the tree.
76
+ private static func snapshotXCTestPenaltyReason(
77
+ kind: SnapshotBackendKind,
78
+ attempt: SnapshotBackendAttempt,
79
+ slowThresholdMs: Double
80
+ ) -> String? {
81
+ guard kind.usesXCTestAccessibilityChannel else { return nil }
82
+ if case let .failed(failure, phase: .acquisition) = attempt.outcome,
83
+ failure.code == Self.xCTestSnapshotTimeoutCode
84
+ {
85
+ return "\(kind.rawValue)_backend_timeout"
86
+ }
87
+ guard attempt.timing.acquisitionMs > slowThresholdMs else { return nil }
88
+ return "slow_\(kind.rawValue)_capture_\(Int(attempt.timing.acquisitionMs))ms"
89
+ }
90
+
91
+ func recordXCTestSnapshotBackendAttemptIfNeeded(
92
+ _ kind: SnapshotBackendKind,
93
+ attempt: SnapshotBackendAttempt,
94
+ penaltySuppressed: Bool
95
+ ) {
96
+ guard !penaltySuppressed else { return }
97
+ guard
98
+ let reason = Self.snapshotXCTestPenaltyReason(
99
+ kind: kind,
100
+ attempt: attempt,
101
+ slowThresholdMs: snapshotXCTestSlowCaptureThreshold * 1_000
102
+ )
103
+ else { return }
104
+ penalizeSnapshotXCTestChannel(
105
+ bundleId: currentBundleId,
106
+ reason: reason
107
+ )
108
+ }
109
+ }
110
+
@@ -0,0 +1,206 @@
1
+ import XCTest
2
+
3
+ // The synthesized text-entry commit wait, end to end: the deadline that bounds it, the two waits
4
+ // that run it, the observation/pacing they poll through, and the value-free cadence line that path
5
+ // is allowed to log. Split from RunnerTests+SynthesizedTextEntry.swift, which keeps the
6
+ // private-XCTest synthesis boundary and the route policies; the pure outcome functions these wrap
7
+ // stay there next to the rules they encode. Everything that touches the polled field value now
8
+ // lives in this one file, which is the surface apple-runner-log-redaction.test.ts guards.
9
+ extension RunnerTests {
10
+ /// One commit wait's running deadline.
11
+ ///
12
+ /// A synthesized burst can be *throttled* rather than dropped: on a loaded simulator the
13
+ /// characters keep landing, just slowly, and everything touching the input system slows with
14
+ /// them (#1874). A flat wall-clock budget cannot tell that apart from a wedged pipeline, so it
15
+ /// condemned both at the same instant — and the throttled case is a working command reported as
16
+ /// `TEXT_INPUT_COMMIT_NOT_OBSERVED`, which is what turned an environment episode into a red
17
+ /// lane on branches touching no iOS code.
18
+ ///
19
+ /// So time is granted against *progress* — the observed value's expected-prefix growing, the
20
+ /// same length-only evidence `logCommitCadence` already emits — with an absolute `ceiling`, so a
21
+ /// pipeline delivering one character per stall window cannot hold a command open forever. A
22
+ /// pipeline making no progress at all still expires at exactly the `stallBudget` the flat
23
+ /// deadline used, so nothing that fails today starts passing merely by waiting longer.
24
+ ///
25
+ /// Started by the poll loop from its own first `now()`, and held as a local `var` there. The
26
+ /// wait's setup reads the field's placeholder first, an AX round-trip that takes seconds on
27
+ /// exactly the loaded host this exists for; charging that to the deadline made the wait give up
28
+ /// sooner than the flat budget it replaced.
29
+ struct SynthesizedCommitDeadline {
30
+ private let startedAt: Date
31
+ private let stallBudget: TimeInterval
32
+ private let ceiling: TimeInterval
33
+ // Nothing has landed yet, and an observation of "still nothing" must not read as progress.
34
+ private var bestPrefixLength = 0
35
+ private var lastProgressAt: Date
36
+
37
+ init(startedAt: Date, stallBudget: TimeInterval, ceiling: TimeInterval) {
38
+ self.startedAt = startedAt
39
+ self.stallBudget = stallBudget
40
+ self.ceiling = ceiling
41
+ self.lastProgressAt = startedAt
42
+ }
43
+
44
+ /// Records one observation's expected-prefix length. Only forward movement counts: a shorter
45
+ /// read — the app clearing the field mid-flight, or a value that could not be read at all,
46
+ /// which measures as 0 — is not evidence the burst is still landing, so it neither buys time
47
+ /// nor takes any back.
48
+ mutating func record(expectedPrefixLength: Int, at now: Date) {
49
+ guard expectedPrefixLength > bestPrefixLength else { return }
50
+ bestPrefixLength = expectedPrefixLength
51
+ lastProgressAt = now
52
+ }
53
+
54
+ func isExpired(at now: Date) -> Bool {
55
+ now.timeIntervalSince(startedAt) >= ceiling
56
+ || now.timeIntervalSince(lastProgressAt) >= stallBudget
57
+ }
58
+ }
59
+
60
+ /// Blocks until the synthesized bare-type text is observable in the target field, so `type`
61
+ /// cannot report ok while trailing characters are still uncommitted on a slow simulator.
62
+ ///
63
+ /// Observation only. A stalled prefix cannot be told apart from a suffix still queued in the
64
+ /// event stream, so re-synthesizing the difference risks committing it twice after the command
65
+ /// already reported success (#1676 rejected exactly that repair). Reporting `.notObserved` is
66
+ /// what the caller does instead: the partial value is the agent's to resolve, and a named
67
+ /// failure beats a success that misdescribes the field. Text carrying a submit key is skipped
68
+ /// outright: the app may clear or rewrite the field on submit, so `textBefore + typedText` is
69
+ /// not the value to wait for.
70
+ func awaitSynthesizedFirstResponderCommit(
71
+ app: XCUIApplication,
72
+ target: TextEntryTarget,
73
+ textBefore: String?,
74
+ typedText: String
75
+ ) -> SynthesizedTextCommitOutcome {
76
+ guard let textBefore, !typedText.contains("\n"), !typedText.contains("\r") else {
77
+ return .unobservable
78
+ }
79
+ let expectedText = textBefore + typedText
80
+ let waitStartedAt = Date()
81
+ NSLog("[DEBUG-1874] wait start expectedLen=%ld route=append", expectedText.count)
82
+ let ingredients = synthesizedCommitPollingIngredients(app: app, target: target, expectedText: expectedText)
83
+ let outcome = Self.awaitSynthesizedCommitOutcome(
84
+ expectedText: expectedText,
85
+ placeholder: ingredients.placeholder,
86
+ now: { Date() },
87
+ observe: ingredients.observe,
88
+ waitForNextObservation: ingredients.waitForNextObservation
89
+ )
90
+ NSLog(
91
+ "[DEBUG-1874] wait outcome=%@ elapsedMs=%.0f route=append",
92
+ String(describing: outcome),
93
+ waitStartedAt.timeIntervalSinceNow * -1000
94
+ )
95
+ return outcome
96
+ }
97
+
98
+ /// Blocks until the synthesized replacement text (`fill`) is observable in the target field, so
99
+ /// `fill` cannot report ok while the select-all-and-retype it posted is still uncommitted — or
100
+ /// silently wrong — on a slow or channel-penalized simulator (this route runs only when the
101
+ /// XCTest channel is already penalized, and never resolves an `XCUIElement`, so it previously had
102
+ /// no verification at all).
103
+ ///
104
+ /// Unlike the append route, the expected value is the final text itself — replacement mode
105
+ /// clears the field first, so there is no `textBefore` prefix to account for — and unlike the
106
+ /// append route, a settled mismatch is always reported rather than trusted: see
107
+ /// `awaitSynthesizedReplacementCommitOutcome`'s doc comment.
108
+ func awaitSynthesizedReplacementCommit(
109
+ app: XCUIApplication,
110
+ target: TextEntryTarget,
111
+ expectedText: String
112
+ ) -> SynthesizedTextCommitOutcome {
113
+ guard !expectedText.contains("\n"), !expectedText.contains("\r") else {
114
+ return .unobservable
115
+ }
116
+ let waitStartedAt = Date()
117
+ NSLog("[DEBUG-1874] wait start expectedLen=%ld route=replacement", expectedText.count)
118
+ let ingredients = synthesizedCommitPollingIngredients(app: app, target: target, expectedText: expectedText)
119
+ let outcome = Self.awaitSynthesizedReplacementCommitOutcome(
120
+ expectedText: expectedText,
121
+ placeholder: ingredients.placeholder,
122
+ now: { Date() },
123
+ observe: ingredients.observe,
124
+ waitForNextObservation: ingredients.waitForNextObservation
125
+ )
126
+ NSLog(
127
+ "[DEBUG-1874] wait outcome=%@ elapsedMs=%.0f route=replacement",
128
+ String(describing: outcome),
129
+ waitStartedAt.timeIntervalSinceNow * -1000
130
+ )
131
+ return outcome
132
+ }
133
+
134
+ /// The emitted cadence line, as a pure function so its output is assertable. Only lengths and
135
+ /// a timestamp are representable here; there is no String parameter, so observed field
136
+ /// contents cannot reach runner.log through this boundary whatever they contain.
137
+ static func commitCadenceLogLine(
138
+ elapsedMs: Int,
139
+ observedLen: Int,
140
+ expectedPrefixLen: Int
141
+ ) -> String {
142
+ "[DEBUG-1874] poll t=\(elapsedMs)ms observedLen=\(observedLen) expectedPrefixLen=\(expectedPrefixLen)"
143
+ }
144
+
145
+ /// The typed boundary for commit-wait cadence evidence. The poll path must log through this
146
+ /// function and never through a raw NSLog: every parameter is an Int, so the polled value's
147
+ /// contents are unrepresentable at the call site.
148
+ static func logCommitCadence(
149
+ elapsedMs: Int,
150
+ observedLen: Int,
151
+ expectedPrefixLen: Int
152
+ ) {
153
+ NSLog(
154
+ "%@",
155
+ commitCadenceLogLine(
156
+ elapsedMs: elapsedMs,
157
+ observedLen: observedLen,
158
+ expectedPrefixLen: expectedPrefixLen
159
+ )
160
+ )
161
+ }
162
+
163
+ /// The placeholder/observe/pacing ingredients shared by the append route
164
+ /// (`awaitSynthesizedFirstResponderCommit`) and the replacement route
165
+ /// (`awaitSynthesizedReplacementCommit`). What must NOT be shared is which outcome function
166
+ /// consumes them: see `awaitSynthesizedReplacementCommitOutcome`'s doc comment for why append
167
+ /// mode's "trust a diverged value" rule is wrong for replacement mode. Each caller therefore
168
+ /// calls its own named outcome function directly, with real argument labels — deliberately not
169
+ /// a stored closure/function-value parameter here, which would erase those labels at the call
170
+ /// site and make the observe closure unrecognizable to the static content-redaction check in
171
+ /// `apple-runner-log-redaction.test.ts` (`extractObserveClosure` locates the labeled closure
172
+ /// literal by its text; a closure passed as a plain function value carries no such label).
173
+ private func synthesizedCommitPollingIngredients(
174
+ app: XCUIApplication,
175
+ target: TextEntryTarget,
176
+ expectedText: String
177
+ ) -> (
178
+ placeholder: String?,
179
+ observe: () -> String?,
180
+ waitForNextObservation: () -> Void
181
+ ) {
182
+ let placeholder = resolveTextEntryElement(app: app, target: target)?.placeholderValue
183
+ let waitStartedAt = Date()
184
+ return (
185
+ placeholder: placeholder,
186
+ observe: {
187
+ let observedText = self.editableTextValue(
188
+ for: self.resolveTextEntryElement(app: app, target: target),
189
+ treatingPlaceholderAsEmpty: true
190
+ )
191
+ // Cadence evidence stays value-free: the polled value is user content typed through
192
+ // `type`/`fill` and must never reach runner.log. Lengths and the expected-prefix walk
193
+ // are enough to distinguish throttling (prefix grows slowly) from a wedge (it freezes).
194
+ Self.logCommitCadence(
195
+ elapsedMs: Int(waitStartedAt.timeIntervalSinceNow * -1000),
196
+ observedLen: observedText?.count ?? -1,
197
+ expectedPrefixLen: observedText.map { Self.commonPrefixLength($0, expectedText) } ?? -1
198
+ )
199
+ return observedText
200
+ },
201
+ // XCUI resolution shares the automation channel with the in-flight synthesized event.
202
+ // Sparse reads let the target consume that event instead of continuously interrupting it.
203
+ waitForNextObservation: { self.sleepFor(TextEntryTiming.synthesizedCommitPollInterval) }
204
+ )
205
+ }
206
+ }
@@ -40,9 +40,14 @@ extension RunnerTests {
40
40
  replacingExistingText: Bool
41
41
  ) -> SynthesizedTextEntryAction {
42
42
  #if os(iOS)
43
+ let postStartedAt = Date()
43
44
  let result = replacingExistingText
44
45
  ? RunnerSynthesizedTextEntry.replaceText(withApplication: app, text: text)
45
46
  : RunnerSynthesizedTextEntry.synthesizeText(withApplication: app, text: text)
47
+ NSLog(
48
+ "[DEBUG-1874] synthesize posted %d chars status=%d tookMs=%.0f",
49
+ text.count, result.status.rawValue, postStartedAt.timeIntervalSinceNow * -1000
50
+ )
46
51
  return Self.action(status: result.status, message: result.message)
47
52
  #else
48
53
  return .fallback
@@ -122,6 +127,17 @@ extension RunnerTests {
122
127
  sleepFor(request.delaySeconds)
123
128
  }
124
129
  }
130
+ // The private synthesize call returns at post time, not commit time (same as bare `type`,
131
+ // see awaitSynthesizedFirstResponderCommit) — but this route never resolves an XCUIElement,
132
+ // so without this wait it had no way to notice a dropped or still-in-flight character at all
133
+ // and reported ok purely because the event posted. Wait here, on the same request.target
134
+ // (element nil, refreshPoint set) that gated this route, so each poll re-resolves via the
135
+ // refresh point rather than trusting a stale element handle.
136
+ let commit = awaitSynthesizedReplacementCommit(
137
+ app: request.app,
138
+ target: request.target,
139
+ expectedText: request.text
140
+ )
125
141
  logTextEntryPhase(
126
142
  commandId: request.commandId,
127
143
  phase: "total",
@@ -135,7 +151,8 @@ extension RunnerTests {
135
151
  repaired: false,
136
152
  expectedText: request.text,
137
153
  observedText: nil,
138
- textEntryRoute: "synthesized-first-responder-replacement"
154
+ textEntryRoute: "synthesized-first-responder-replacement",
155
+ failure: Self.textEntryFailure(forCommitOutcome: commit)
139
156
  )
140
157
  )
141
158
  #else
@@ -184,38 +201,143 @@ extension RunnerTests {
184
201
  return expectedText.hasPrefix(observedText) ? .pending : .diverged
185
202
  }
186
203
 
187
- /// Blocks until the synthesized bare-type text is observable in the target field, so `type`
188
- /// cannot report ok while trailing characters are still uncommitted on a slow simulator.
204
+ /// Length of the shared prefix of two strings. Feeds value-free commit-wait logging: the
205
+ /// expected-prefix walk over time distinguishes throttled delivery (grows slowly) from a
206
+ /// wedged pipeline (freezes) without ever logging the field's contents.
207
+ static func commonPrefixLength(_ lhs: String, _ rhs: String) -> Int {
208
+ var length = 0
209
+ for (l, r) in zip(lhs, rhs) {
210
+ if l != r { break }
211
+ length += 1
212
+ }
213
+ return length
214
+ }
215
+
216
+ /// How the commit wait ended. Distinct from `SynthesizedTextCommitProgress`, which classifies a
217
+ /// single observation: this is the whole wait's verdict, and it exists so the deadline can be
218
+ /// told apart from success. The wait used to return `Void`, which made an expired deadline
219
+ /// indistinguishable from a committed one — `type` then reported ok with a partial value in the
220
+ /// field (#1874, #1844).
221
+ enum SynthesizedTextCommitOutcome: Equatable {
222
+ /// The wait's success case, but its meaning is route-specific: for append mode (bare `type`),
223
+ /// the expected text committed OR the app transformed the input in a way the runner must not
224
+ /// second-guess; for replacement mode (`fill`), it means only an exact match — see
225
+ /// `awaitSynthesizedReplacementCommitOutcome`'s doc comment for why replacement mode has no
226
+ /// "trust it" case.
227
+ case settled
228
+ /// There was nothing to wait for — no readable baseline, or the text carries a submit key.
229
+ case unobservable
230
+ /// The deadline expired with the expected text still not observed.
231
+ case notObserved
232
+ }
233
+
234
+ /// The commit wait's decision, with observation, pacing and the clock injected so both deadline
235
+ /// branches are exercisable without a simulator (the macOS host lane runs this; the member
236
+ /// wrapper below binds the real XCUI reads).
189
237
  ///
190
- /// Observation only. A stalled prefix cannot be told apart from a suffix still queued in the
191
- /// event stream, so re-synthesizing the difference risks committing it twice after the command
192
- /// already reported success. Text carrying a submit key is skipped outright: the app may clear
193
- /// or rewrite the field on submit, so `textBefore + typedText` is not the value to wait for.
194
- func awaitSynthesizedFirstResponderCommit(
195
- app: XCUIApplication,
196
- target: TextEntryTarget,
197
- textBefore: String?,
198
- typedText: String
199
- ) {
200
- guard let textBefore, !typedText.contains("\n"), !typedText.contains("\r") else {
201
- return
238
+ /// The deadline is a local `var`, started from this loop's own first `now()` and advanced from
239
+ /// the same observation the progress check reads, so "did the burst move" and "is time up" are
240
+ /// two statements in one loop. The budget defaults to the shipped one, so only a test that is
241
+ /// asking about time has to name it.
242
+ static func awaitSynthesizedCommitOutcome(
243
+ expectedText: String,
244
+ placeholder: String?,
245
+ stallBudget: TimeInterval = TextEntryTiming.synthesizedCommitStallTimeout,
246
+ ceiling: TimeInterval = TextEntryTiming.synthesizedCommitCeiling,
247
+ now: () -> Date = { Date() },
248
+ observe: () -> String?,
249
+ waitForNextObservation: () -> Void
250
+ ) -> SynthesizedTextCommitOutcome {
251
+ // A placeholder-equal AX value cannot prove a commit: an input handler may clear even a
252
+ // previously non-empty field after dispatch, making the empty field render the same value.
253
+ // Refuse before polling because no later read can distinguish those states.
254
+ if Self.textMatchesPlaceholder(expectedText, placeholder: placeholder) {
255
+ return .notObserved
202
256
  }
203
- let expectedText = textBefore + typedText
204
- let deadline = Date().addingTimeInterval(TextEntryTiming.synthesizedCommitTimeout)
205
- while Date() < deadline {
206
- let observedText = editableTextValue(
207
- for: resolveTextEntryElement(app: app, target: target),
208
- treatingPlaceholderAsEmpty: true
209
- )
210
- switch Self.synthesizedTextCommitProgress(observedText: observedText, expectedText: expectedText) {
257
+ var deadline = SynthesizedCommitDeadline(startedAt: now(), stallBudget: stallBudget, ceiling: ceiling)
258
+ // The deadline is checked AFTER an observation, never before one, so the last thing that
259
+ // happens before condemning a commit is a read. Checking first would condemn a commit that
260
+ // landed during the final poll sleep — the exact loaded-host timing this wait exists for.
261
+ while true {
262
+ let observedText = observe()
263
+ switch synthesizedTextCommitProgress(observedText: observedText, expectedText: expectedText) {
211
264
  case .committed, .diverged:
212
- return
265
+ return .settled
213
266
  case .pending:
214
- sleepFor(TextEntryTiming.pollInterval)
267
+ // One clock sample, so the instant an observation is recorded at is the instant it is
268
+ // judged against.
269
+ let sampledAt = now()
270
+ deadline.record(
271
+ expectedPrefixLength: Self.commonPrefixLength(observedText ?? "", expectedText),
272
+ at: sampledAt
273
+ )
274
+ if deadline.isExpired(at: sampledAt) { return .notObserved }
275
+ waitForNextObservation()
215
276
  }
216
277
  }
217
278
  }
218
279
 
280
+ /// The command-level consequence of a commit wait. `.unobservable` is not a failure: there was
281
+ /// no baseline to compare against, which is the pre-existing contract for submit-key text and
282
+ /// unreadable fields, not evidence that anything went wrong.
283
+ static func textEntryFailure(
284
+ forCommitOutcome outcome: SynthesizedTextCommitOutcome
285
+ ) -> TextEntryFailure? {
286
+ switch outcome {
287
+ case .settled, .unobservable:
288
+ return nil
289
+ case .notObserved:
290
+ return .commitNotObserved
291
+ }
292
+ }
293
+
294
+ /// The replacement-mode counterpart of `awaitSynthesizedCommitOutcome`. It must NOT reuse that
295
+ /// function's `synthesizedTextCommitProgress`: prefix-walk's `.diverged` case exists to trust an
296
+ /// app that transforms bare-`type` input (formatter, autocomplete) rather than second-guess it —
297
+ /// but that same rule silently accepts a dropped-character corruption too, because a value with a
298
+ /// hole in the middle ("ada@example" -> "aexample") is neither a matching prefix NOR the full
299
+ /// string, yet still gets classified `.diverged` -> `.settled` -> reported `ok: true`. This is not
300
+ /// a hypothetical: it is the exact shape of the corruption this wait exists to catch (`fill`
301
+ /// reporting success over "Avelace"/"aexample"-style drops), verified against both live examples
302
+ /// before writing this comment.
303
+ ///
304
+ /// `.replacement` mode does not need prefix tolerance for legitimate transforms either:
305
+ /// `isRepairableTextEntryMismatch` (RunnerTests+TextTyping.swift) already treats every mismatch in
306
+ /// `.replacement` mode as repairable unconditionally, with no formatter/autocomplete carve-out —
307
+ /// `fill` fully owns the field via select-all, so there is no legitimate reason for the settled
308
+ /// value to be anything other than exactly what was requested. A settled non-match is therefore
309
+ /// always the wait's failure case, never a `.settled` pass-through.
310
+ static func awaitSynthesizedReplacementCommitOutcome(
311
+ expectedText: String,
312
+ placeholder: String?,
313
+ stallBudget: TimeInterval = TextEntryTiming.synthesizedCommitStallTimeout,
314
+ ceiling: TimeInterval = TextEntryTiming.synthesizedCommitCeiling,
315
+ now: () -> Date = { Date() },
316
+ observe: () -> String?,
317
+ waitForNextObservation: () -> Void
318
+ ) -> SynthesizedTextCommitOutcome {
319
+ if Self.textMatchesPlaceholder(expectedText, placeholder: placeholder) {
320
+ return .notObserved
321
+ }
322
+ var deadline = SynthesizedCommitDeadline(startedAt: now(), stallBudget: stallBudget, ceiling: ceiling)
323
+ while true {
324
+ let observedText = observe()
325
+ if observedText == expectedText {
326
+ return .settled
327
+ }
328
+ // Prefix growth cannot settle this wait — a value with a hole in the middle is still a
329
+ // failure, see the doc comment above — but it is the same evidence that the burst is still
330
+ // landing, so it buys the same time here as it does in append mode.
331
+ let sampledAt = now()
332
+ deadline.record(
333
+ expectedPrefixLength: Self.commonPrefixLength(observedText ?? "", expectedText),
334
+ at: sampledAt
335
+ )
336
+ if deadline.isExpired(at: sampledAt) { return .notObserved }
337
+ waitForNextObservation()
338
+ }
339
+ }
340
+
219
341
  static func shouldUseResolvedCoordinateTextEntryRoute(
220
342
  repairMode: TextTypingRepairMode,
221
343
  hasX: Bool,
@@ -1,4 +1,5 @@
1
1
  import XCTest
2
+ import AgentDeviceSnapshotPresentation
2
3
 
3
4
  extension RunnerTests {
4
5
  // MARK: - Blocking System Modal Snapshot