react-native-ai-debugger 2.4.0 → 2.5.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 (547) hide show
  1. package/build/__tests__/helpers/fake-cdp-server.d.ts +0 -12
  2. package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -1
  3. package/build/__tests__/helpers/fake-cdp-server.js +0 -22
  4. package/build/__tests__/helpers/fake-cdp-server.js.map +1 -1
  5. package/build/__tests__/helpers/tap-test-helpers.d.ts +0 -23
  6. package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -1
  7. package/build/__tests__/helpers/tap-test-helpers.js +2 -29
  8. package/build/__tests__/helpers/tap-test-helpers.js.map +1 -1
  9. package/build/__tests__/integration/auto-reconnect.test.js +4 -14
  10. package/build/__tests__/integration/auto-reconnect.test.js.map +1 -1
  11. package/build/__tests__/integration/connection-health.test.js +1 -10
  12. package/build/__tests__/integration/connection-health.test.js.map +1 -1
  13. package/build/__tests__/integration/execute-in-app.test.js +1 -11
  14. package/build/__tests__/integration/execute-in-app.test.js.map +1 -1
  15. package/build/__tests__/integration/native-logs.test.js +0 -5
  16. package/build/__tests__/integration/native-logs.test.js.map +1 -1
  17. package/build/__tests__/integration/per-call-timeout.test.js +1 -5
  18. package/build/__tests__/integration/per-call-timeout.test.js.map +1 -1
  19. package/build/__tests__/integration/socket-close-midflight.test.js +2 -12
  20. package/build/__tests__/integration/socket-close-midflight.test.js.map +1 -1
  21. package/build/__tests__/integration/stale-target-probe.test.js +2 -17
  22. package/build/__tests__/integration/stale-target-probe.test.js.map +1 -1
  23. package/build/__tests__/integration/tap-strategies.test.js +2 -36
  24. package/build/__tests__/integration/tap-strategies.test.js.map +1 -1
  25. package/build/__tests__/integration/text-input.test.js +0 -39
  26. package/build/__tests__/integration/text-input.test.js.map +1 -1
  27. package/build/__tests__/integration/tools.test.js +1 -7
  28. package/build/__tests__/integration/tools.test.js.map +1 -1
  29. package/build/__tests__/setup.js +0 -2
  30. package/build/__tests__/setup.js.map +1 -1
  31. package/build/__tests__/unit/androidEmulatorAvds.test.js +0 -10
  32. package/build/__tests__/unit/androidEmulatorAvds.test.js.map +1 -1
  33. package/build/__tests__/unit/appContext.test.js +0 -2
  34. package/build/__tests__/unit/appContext.test.js.map +1 -1
  35. package/build/__tests__/unit/appRequest.test.js +0 -3
  36. package/build/__tests__/unit/appRequest.test.js.map +1 -1
  37. package/build/__tests__/unit/buildToken.test.js +0 -6
  38. package/build/__tests__/unit/buildToken.test.js.map +1 -1
  39. package/build/__tests__/unit/burst.test.js +0 -1
  40. package/build/__tests__/unit/burst.test.js.map +1 -1
  41. package/build/__tests__/unit/clearLogsNative.test.js +0 -8
  42. package/build/__tests__/unit/clearLogsNative.test.js.map +1 -1
  43. package/build/__tests__/unit/componentFormatNaming.test.js +0 -13
  44. package/build/__tests__/unit/componentFormatNaming.test.js.map +1 -1
  45. package/build/__tests__/unit/componentSource.test.js +0 -4
  46. package/build/__tests__/unit/componentSource.test.js.map +1 -1
  47. package/build/__tests__/unit/componentSourceResolve.test.js +0 -1
  48. package/build/__tests__/unit/componentSourceResolve.test.js.map +1 -1
  49. package/build/__tests__/unit/contextWiring.test.js +0 -3
  50. package/build/__tests__/unit/contextWiring.test.js.map +1 -1
  51. package/build/__tests__/unit/coordinateMiss.test.js +0 -16
  52. package/build/__tests__/unit/coordinateMiss.test.js.map +1 -1
  53. package/build/__tests__/unit/deviceDiscovery.test.js +0 -4
  54. package/build/__tests__/unit/deviceDiscovery.test.js.map +1 -1
  55. package/build/__tests__/unit/deviceResolution.test.js +0 -2
  56. package/build/__tests__/unit/deviceResolution.test.js.map +1 -1
  57. package/build/__tests__/unit/deviceResolver.test.js +0 -1
  58. package/build/__tests__/unit/deviceResolver.test.js.map +1 -1
  59. package/build/__tests__/unit/deviceResolverStaleRetry.test.js +0 -8
  60. package/build/__tests__/unit/deviceResolverStaleRetry.test.js.map +1 -1
  61. package/build/__tests__/unit/epochRender.test.js +0 -3
  62. package/build/__tests__/unit/epochRender.test.js.map +1 -1
  63. package/build/__tests__/unit/errorCategorization.test.js +0 -18
  64. package/build/__tests__/unit/errorCategorization.test.js.map +1 -1
  65. package/build/__tests__/unit/exec.test.js +0 -1
  66. package/build/__tests__/unit/exec.test.js.map +1 -1
  67. package/build/__tests__/unit/executor.test.js +0 -15
  68. package/build/__tests__/unit/executor.test.js.map +1 -1
  69. package/build/__tests__/unit/findElementTreeReuse.test.js +0 -12
  70. package/build/__tests__/unit/findElementTreeReuse.test.js.map +1 -1
  71. package/build/__tests__/unit/fingerprint.test.js +0 -4
  72. package/build/__tests__/unit/fingerprint.test.js.map +1 -1
  73. package/build/__tests__/unit/focusedInputTools.test.js +0 -4
  74. package/build/__tests__/unit/focusedInputTools.test.js.map +1 -1
  75. package/build/__tests__/unit/getLogsEmptyContract.test.js +0 -30
  76. package/build/__tests__/unit/getLogsEmptyContract.test.js.map +1 -1
  77. package/build/__tests__/unit/getLogsNativeSource.test.js +0 -22
  78. package/build/__tests__/unit/getLogsNativeSource.test.js.map +1 -1
  79. package/build/__tests__/unit/graphqlOperation.test.d.ts +2 -0
  80. package/build/__tests__/unit/graphqlOperation.test.d.ts.map +1 -0
  81. package/build/__tests__/unit/graphqlOperation.test.js +107 -0
  82. package/build/__tests__/unit/graphqlOperation.test.js.map +1 -0
  83. package/build/__tests__/unit/inputTarget.test.js +0 -16
  84. package/build/__tests__/unit/inputTarget.test.js.map +1 -1
  85. package/build/__tests__/unit/inputTextTool.test.js +0 -3
  86. package/build/__tests__/unit/inputTextTool.test.js.map +1 -1
  87. package/build/__tests__/unit/jsLogEvents.test.js +0 -3
  88. package/build/__tests__/unit/jsLogEvents.test.js.map +1 -1
  89. package/build/__tests__/unit/keyboardMetrics.test.js +0 -2
  90. package/build/__tests__/unit/keyboardMetrics.test.js.map +1 -1
  91. package/build/__tests__/unit/keyboardRaise.test.js +0 -2
  92. package/build/__tests__/unit/keyboardRaise.test.js.map +1 -1
  93. package/build/__tests__/unit/licenseGrace.test.js +1 -4
  94. package/build/__tests__/unit/licenseGrace.test.js.map +1 -1
  95. package/build/__tests__/unit/logEventFormat.test.js +0 -27
  96. package/build/__tests__/unit/logEventFormat.test.js.map +1 -1
  97. package/build/__tests__/unit/logEvents.test.js +1 -5
  98. package/build/__tests__/unit/logEvents.test.js.map +1 -1
  99. package/build/__tests__/unit/logGrouping.test.js +0 -2
  100. package/build/__tests__/unit/logGrouping.test.js.map +1 -1
  101. package/build/__tests__/unit/logOwnership.test.js +0 -11
  102. package/build/__tests__/unit/logOwnership.test.js.map +1 -1
  103. package/build/__tests__/unit/logRelevance.test.js +0 -6
  104. package/build/__tests__/unit/logRelevance.test.js.map +1 -1
  105. package/build/__tests__/unit/logSourceAndroid.test.js +0 -4
  106. package/build/__tests__/unit/logSourceAndroid.test.js.map +1 -1
  107. package/build/__tests__/unit/logSourceIos.test.js +0 -5
  108. package/build/__tests__/unit/logSourceIos.test.js.map +1 -1
  109. package/build/__tests__/unit/logs.test.js +0 -1
  110. package/build/__tests__/unit/logs.test.js.map +1 -1
  111. package/build/__tests__/unit/measureComponentTools.test.js +0 -1
  112. package/build/__tests__/unit/measureComponentTools.test.js.map +1 -1
  113. package/build/__tests__/unit/metro.test.js +0 -2
  114. package/build/__tests__/unit/metro.test.js.map +1 -1
  115. package/build/__tests__/unit/nativeInputValue.test.js +0 -4
  116. package/build/__tests__/unit/nativeInputValue.test.js.map +1 -1
  117. package/build/__tests__/unit/nativeLogs.test.js +1 -23
  118. package/build/__tests__/unit/nativeLogs.test.js.map +1 -1
  119. package/build/__tests__/unit/navigateVerify.test.js +0 -6
  120. package/build/__tests__/unit/navigateVerify.test.js.map +1 -1
  121. package/build/__tests__/unit/navigation.test.js +0 -5
  122. package/build/__tests__/unit/navigation.test.js.map +1 -1
  123. package/build/__tests__/unit/networkInterceptor.test.js +0 -2
  124. package/build/__tests__/unit/networkInterceptor.test.js.map +1 -1
  125. package/build/__tests__/unit/overlayGuard.test.js +0 -17
  126. package/build/__tests__/unit/overlayGuard.test.js.map +1 -1
  127. package/build/__tests__/unit/pendingExecutions.test.js +0 -6
  128. package/build/__tests__/unit/pendingExecutions.test.js.map +1 -1
  129. package/build/__tests__/unit/probe.test.js +0 -1
  130. package/build/__tests__/unit/probe.test.js.map +1 -1
  131. package/build/__tests__/unit/projectMemory.test.js +6 -7
  132. package/build/__tests__/unit/projectMemory.test.js.map +1 -1
  133. package/build/__tests__/unit/projectStore.test.js +2 -2
  134. package/build/__tests__/unit/projectStore.test.js.map +1 -1
  135. package/build/__tests__/unit/reloadAppAutoConnect.test.js +0 -9
  136. package/build/__tests__/unit/reloadAppAutoConnect.test.js.map +1 -1
  137. package/build/__tests__/unit/rnGlobalsBootstrap.test.js +3 -3
  138. package/build/__tests__/unit/rnGlobalsBootstrap.test.js.map +1 -1
  139. package/build/__tests__/unit/routeHistory.test.d.ts +2 -0
  140. package/build/__tests__/unit/routeHistory.test.d.ts.map +1 -0
  141. package/build/__tests__/unit/routeHistory.test.js +136 -0
  142. package/build/__tests__/unit/routeHistory.test.js.map +1 -0
  143. package/build/__tests__/unit/screenSpace.test.js +0 -16
  144. package/build/__tests__/unit/screenSpace.test.js.map +1 -1
  145. package/build/__tests__/unit/screenState.test.js +3 -6
  146. package/build/__tests__/unit/screenState.test.js.map +1 -1
  147. package/build/__tests__/unit/screenStateInputValue.test.js +0 -7
  148. package/build/__tests__/unit/screenStateInputValue.test.js.map +1 -1
  149. package/build/__tests__/unit/screenStateKeyboard.test.js +0 -1
  150. package/build/__tests__/unit/screenStateKeyboard.test.js.map +1 -1
  151. package/build/__tests__/unit/screenshot-diff.test.js +0 -6
  152. package/build/__tests__/unit/screenshot-diff.test.js.map +1 -1
  153. package/build/__tests__/unit/sdkMirrorPoller.test.js +0 -8
  154. package/build/__tests__/unit/sdkMirrorPoller.test.js.map +1 -1
  155. package/build/__tests__/unit/settleAndDiff.test.js +0 -11
  156. package/build/__tests__/unit/settleAndDiff.test.js.map +1 -1
  157. package/build/__tests__/unit/signedVerdict.test.js +0 -5
  158. package/build/__tests__/unit/signedVerdict.test.js.map +1 -1
  159. package/build/__tests__/unit/swipeDirection.test.js +6 -9
  160. package/build/__tests__/unit/swipeDirection.test.js.map +1 -1
  161. package/build/__tests__/unit/symbolicate.test.js +0 -1
  162. package/build/__tests__/unit/symbolicate.test.js.map +1 -1
  163. package/build/__tests__/unit/tap.test.js +0 -38
  164. package/build/__tests__/unit/tap.test.js.map +1 -1
  165. package/build/__tests__/unit/textEntry.test.js +0 -27
  166. package/build/__tests__/unit/textEntry.test.js.map +1 -1
  167. package/build/__tests__/unit/toolDescriptions.test.js +0 -40
  168. package/build/__tests__/unit/toolDescriptions.test.js.map +1 -1
  169. package/build/__tests__/unit/toolsJson.test.js +0 -10
  170. package/build/__tests__/unit/toolsJson.test.js.map +1 -1
  171. package/build/__tests__/unit/transportClassify.test.js +0 -20
  172. package/build/__tests__/unit/transportClassify.test.js.map +1 -1
  173. package/build/__tests__/unit/truncate.test.js +0 -5
  174. package/build/__tests__/unit/truncate.test.js.map +1 -1
  175. package/build/__tests__/unit/usageCache.test.js +0 -3
  176. package/build/__tests__/unit/usageCache.test.js.map +1 -1
  177. package/build/__tests__/unit/usageGate.test.js +1 -1
  178. package/build/__tests__/unit/usageGate.test.js.map +1 -1
  179. package/build/__tests__/unit/visibility.test.js +0 -8
  180. package/build/__tests__/unit/visibility.test.js.map +1 -1
  181. package/build/__tests__/unit/waitForMeasurements.test.js +2 -7
  182. package/build/__tests__/unit/waitForMeasurements.test.js.map +1 -1
  183. package/build/bin.js +0 -18
  184. package/build/bin.js.map +1 -1
  185. package/build/core/android.d.ts +0 -120
  186. package/build/core/android.d.ts.map +1 -1
  187. package/build/core/android.js +4 -259
  188. package/build/core/android.js.map +1 -1
  189. package/build/core/appContext.d.ts +0 -50
  190. package/build/core/appContext.d.ts.map +1 -1
  191. package/build/core/appContext.js +0 -50
  192. package/build/core/appContext.js.map +1 -1
  193. package/build/core/appDetection.d.ts +0 -16
  194. package/build/core/appDetection.d.ts.map +1 -1
  195. package/build/core/appDetection.js +0 -36
  196. package/build/core/appDetection.js.map +1 -1
  197. package/build/core/appRequest.d.ts +0 -12
  198. package/build/core/appRequest.d.ts.map +1 -1
  199. package/build/core/appRequest.js +0 -15
  200. package/build/core/appRequest.js.map +1 -1
  201. package/build/core/bufferConfig.d.ts +0 -2
  202. package/build/core/bufferConfig.d.ts.map +1 -1
  203. package/build/core/bufferConfig.js +0 -2
  204. package/build/core/bufferConfig.js.map +1 -1
  205. package/build/core/bundle.js +0 -40
  206. package/build/core/bundle.js.map +1 -1
  207. package/build/core/componentSearch.d.ts +0 -19
  208. package/build/core/componentSearch.d.ts.map +1 -1
  209. package/build/core/componentSearch.js +1 -22
  210. package/build/core/componentSearch.js.map +1 -1
  211. package/build/core/componentSource.d.ts +0 -21
  212. package/build/core/componentSource.d.ts.map +1 -1
  213. package/build/core/componentSource.js +0 -27
  214. package/build/core/componentSource.js.map +1 -1
  215. package/build/core/componentTree.js +0 -12
  216. package/build/core/componentTree.js.map +1 -1
  217. package/build/core/config.d.ts +0 -8
  218. package/build/core/config.d.ts.map +1 -1
  219. package/build/core/config.js +0 -10
  220. package/build/core/config.js.map +1 -1
  221. package/build/core/connection.d.ts +0 -76
  222. package/build/core/connection.d.ts.map +1 -1
  223. package/build/core/connection.js +15 -340
  224. package/build/core/connection.js.map +1 -1
  225. package/build/core/connectionState.d.ts +0 -78
  226. package/build/core/connectionState.d.ts.map +1 -1
  227. package/build/core/connectionState.js +4 -92
  228. package/build/core/connectionState.js.map +1 -1
  229. package/build/core/debugGlobals.js +0 -68
  230. package/build/core/debugGlobals.js.map +1 -1
  231. package/build/core/deviceDiscovery.d.ts +0 -5
  232. package/build/core/deviceDiscovery.d.ts.map +1 -1
  233. package/build/core/deviceDiscovery.js +0 -12
  234. package/build/core/deviceDiscovery.js.map +1 -1
  235. package/build/core/deviceResolver.d.ts +0 -10
  236. package/build/core/deviceResolver.d.ts.map +1 -1
  237. package/build/core/deviceResolver.js +0 -54
  238. package/build/core/deviceResolver.js.map +1 -1
  239. package/build/core/epochRender.d.ts +0 -12
  240. package/build/core/epochRender.d.ts.map +1 -1
  241. package/build/core/epochRender.js +0 -12
  242. package/build/core/epochRender.js.map +1 -1
  243. package/build/core/errorScreenParser.d.ts +0 -21
  244. package/build/core/errorScreenParser.d.ts.map +1 -1
  245. package/build/core/errorScreenParser.js +0 -50
  246. package/build/core/errorScreenParser.js.map +1 -1
  247. package/build/core/errors.d.ts +0 -15
  248. package/build/core/errors.d.ts.map +1 -1
  249. package/build/core/errors.js +0 -15
  250. package/build/core/errors.js.map +1 -1
  251. package/build/core/escapeNonAscii.d.ts +0 -9
  252. package/build/core/escapeNonAscii.d.ts.map +1 -1
  253. package/build/core/escapeNonAscii.js +1 -43
  254. package/build/core/escapeNonAscii.js.map +1 -1
  255. package/build/core/exec.d.ts +0 -12
  256. package/build/core/exec.d.ts.map +1 -1
  257. package/build/core/exec.js +2 -14
  258. package/build/core/exec.js.map +1 -1
  259. package/build/core/executor.js +0 -3
  260. package/build/core/executor.js.map +1 -1
  261. package/build/core/fastRefreshRecorder.js +0 -4
  262. package/build/core/fastRefreshRecorder.js.map +1 -1
  263. package/build/core/fastRefreshTools.js +0 -3
  264. package/build/core/fastRefreshTools.js.map +1 -1
  265. package/build/core/feedback.js +0 -4
  266. package/build/core/feedback.js.map +1 -1
  267. package/build/core/graphqlOperation.d.ts +13 -0
  268. package/build/core/graphqlOperation.d.ts.map +1 -0
  269. package/build/core/graphqlOperation.js +80 -0
  270. package/build/core/graphqlOperation.js.map +1 -0
  271. package/build/core/guides.d.ts +0 -10
  272. package/build/core/guides.d.ts.map +1 -1
  273. package/build/core/guides.js +0 -10
  274. package/build/core/guides.js.map +1 -1
  275. package/build/core/iconSemantics.d.ts +0 -15
  276. package/build/core/iconSemantics.d.ts.map +1 -1
  277. package/build/core/iconSemantics.js +0 -31
  278. package/build/core/iconSemantics.js.map +1 -1
  279. package/build/core/index.js +4 -47
  280. package/build/core/index.js.map +1 -1
  281. package/build/core/injected/visibility.d.ts +0 -30
  282. package/build/core/injected/visibility.d.ts.map +1 -1
  283. package/build/core/injected/visibility.js +0 -33
  284. package/build/core/injected/visibility.js.map +1 -1
  285. package/build/core/injectedFilters.d.ts +0 -28
  286. package/build/core/injectedFilters.d.ts.map +1 -1
  287. package/build/core/injectedFilters.js +0 -28
  288. package/build/core/injectedFilters.js.map +1 -1
  289. package/build/core/inputTarget.d.ts +1 -34
  290. package/build/core/inputTarget.d.ts.map +1 -1
  291. package/build/core/inputTarget.js +0 -26
  292. package/build/core/inputTarget.js.map +1 -1
  293. package/build/core/inputTargetTools.d.ts +0 -7
  294. package/build/core/inputTargetTools.d.ts.map +1 -1
  295. package/build/core/inputTargetTools.js +0 -7
  296. package/build/core/inputTargetTools.js.map +1 -1
  297. package/build/core/inspector.d.ts +0 -33
  298. package/build/core/inspector.d.ts.map +1 -1
  299. package/build/core/inspector.js +0 -36
  300. package/build/core/inspector.js.map +1 -1
  301. package/build/core/ios.d.ts +0 -127
  302. package/build/core/ios.d.ts.map +1 -1
  303. package/build/core/ios.js +2 -313
  304. package/build/core/ios.js.map +1 -1
  305. package/build/core/jsExecute.d.ts +0 -100
  306. package/build/core/jsExecute.d.ts.map +1 -1
  307. package/build/core/jsExecute.js +0 -261
  308. package/build/core/jsExecute.js.map +1 -1
  309. package/build/core/jsLogEvents.d.ts +0 -8
  310. package/build/core/jsLogEvents.d.ts.map +1 -1
  311. package/build/core/jsLogEvents.js +0 -8
  312. package/build/core/jsLogEvents.js.map +1 -1
  313. package/build/core/keyboardMetrics.js +0 -8
  314. package/build/core/keyboardMetrics.js.map +1 -1
  315. package/build/core/keyboardRaise.d.ts +0 -8
  316. package/build/core/keyboardRaise.d.ts.map +1 -1
  317. package/build/core/keyboardRaise.js +0 -23
  318. package/build/core/keyboardRaise.js.map +1 -1
  319. package/build/core/license.d.ts +0 -4
  320. package/build/core/license.d.ts.map +1 -1
  321. package/build/core/license.js +2 -55
  322. package/build/core/license.js.map +1 -1
  323. package/build/core/logDiagnosis.d.ts +0 -34
  324. package/build/core/logDiagnosis.d.ts.map +1 -1
  325. package/build/core/logDiagnosis.js +0 -15
  326. package/build/core/logDiagnosis.js.map +1 -1
  327. package/build/core/logEventFormat.d.ts +0 -1
  328. package/build/core/logEventFormat.d.ts.map +1 -1
  329. package/build/core/logEventFormat.js +0 -30
  330. package/build/core/logEventFormat.js.map +1 -1
  331. package/build/core/logEvents.d.ts +0 -54
  332. package/build/core/logEvents.d.ts.map +1 -1
  333. package/build/core/logEvents.js +0 -37
  334. package/build/core/logEvents.js.map +1 -1
  335. package/build/core/logGrouping.d.ts +0 -9
  336. package/build/core/logGrouping.d.ts.map +1 -1
  337. package/build/core/logGrouping.js +0 -17
  338. package/build/core/logGrouping.js.map +1 -1
  339. package/build/core/logOwnership.d.ts +0 -17
  340. package/build/core/logOwnership.d.ts.map +1 -1
  341. package/build/core/logOwnership.js +0 -34
  342. package/build/core/logOwnership.js.map +1 -1
  343. package/build/core/logRelevance.d.ts +0 -8
  344. package/build/core/logRelevance.d.ts.map +1 -1
  345. package/build/core/logRelevance.js +0 -15
  346. package/build/core/logRelevance.js.map +1 -1
  347. package/build/core/logSourceAndroid.d.ts +0 -8
  348. package/build/core/logSourceAndroid.d.ts.map +1 -1
  349. package/build/core/logSourceAndroid.js +0 -11
  350. package/build/core/logSourceAndroid.js.map +1 -1
  351. package/build/core/logSourceIos.d.ts +0 -8
  352. package/build/core/logSourceIos.d.ts.map +1 -1
  353. package/build/core/logSourceIos.js +1 -24
  354. package/build/core/logSourceIos.js.map +1 -1
  355. package/build/core/logbox.d.ts +0 -30
  356. package/build/core/logbox.d.ts.map +1 -1
  357. package/build/core/logbox.js +0 -43
  358. package/build/core/logbox.js.map +1 -1
  359. package/build/core/logs.d.ts +0 -6
  360. package/build/core/logs.d.ts.map +1 -1
  361. package/build/core/logs.js +0 -19
  362. package/build/core/logs.js.map +1 -1
  363. package/build/core/metro.d.ts +0 -14
  364. package/build/core/metro.d.ts.map +1 -1
  365. package/build/core/metro.js +1 -32
  366. package/build/core/metro.js.map +1 -1
  367. package/build/core/moduleRegistry.d.ts +0 -17
  368. package/build/core/moduleRegistry.d.ts.map +1 -1
  369. package/build/core/moduleRegistry.js +0 -17
  370. package/build/core/moduleRegistry.js.map +1 -1
  371. package/build/core/nativeInputValue.d.ts +0 -29
  372. package/build/core/nativeInputValue.d.ts.map +1 -1
  373. package/build/core/nativeInputValue.js +0 -18
  374. package/build/core/nativeInputValue.js.map +1 -1
  375. package/build/core/nativeLogs.d.ts +0 -47
  376. package/build/core/nativeLogs.d.ts.map +1 -1
  377. package/build/core/nativeLogs.js +0 -82
  378. package/build/core/nativeLogs.js.map +1 -1
  379. package/build/core/nativeOnlyHints.js +0 -4
  380. package/build/core/nativeOnlyHints.js.map +1 -1
  381. package/build/core/navigate.d.ts +0 -15
  382. package/build/core/navigate.d.ts.map +1 -1
  383. package/build/core/navigate.js +0 -22
  384. package/build/core/navigate.js.map +1 -1
  385. package/build/core/navigation.d.ts +0 -60
  386. package/build/core/navigation.d.ts.map +1 -1
  387. package/build/core/navigation.js +0 -60
  388. package/build/core/navigation.js.map +1 -1
  389. package/build/core/network.d.ts +0 -5
  390. package/build/core/network.d.ts.map +1 -1
  391. package/build/core/network.js +10 -31
  392. package/build/core/network.js.map +1 -1
  393. package/build/core/networkInterceptor.d.ts +0 -19
  394. package/build/core/networkInterceptor.d.ts.map +1 -1
  395. package/build/core/networkInterceptor.js +3 -27
  396. package/build/core/networkInterceptor.js.map +1 -1
  397. package/build/core/ocr.d.ts +0 -31
  398. package/build/core/ocr.d.ts.map +1 -1
  399. package/build/core/ocr.js +1 -71
  400. package/build/core/ocr.js.map +1 -1
  401. package/build/core/paths.js +0 -1
  402. package/build/core/paths.js.map +1 -1
  403. package/build/core/posthog.js +0 -7
  404. package/build/core/posthog.js.map +1 -1
  405. package/build/core/pressables.d.ts +0 -25
  406. package/build/core/pressables.d.ts.map +1 -1
  407. package/build/core/pressables.js +0 -37
  408. package/build/core/pressables.js.map +1 -1
  409. package/build/core/probe.d.ts +0 -9
  410. package/build/core/probe.d.ts.map +1 -1
  411. package/build/core/probe.js +0 -9
  412. package/build/core/probe.js.map +1 -1
  413. package/build/core/projectMemory.d.ts +0 -2
  414. package/build/core/projectMemory.d.ts.map +1 -1
  415. package/build/core/projectMemory.js +2 -7
  416. package/build/core/projectMemory.js.map +1 -1
  417. package/build/core/projectStore.d.ts +0 -18
  418. package/build/core/projectStore.d.ts.map +1 -1
  419. package/build/core/projectStore.js +0 -19
  420. package/build/core/projectStore.js.map +1 -1
  421. package/build/core/promiseHandles.d.ts +0 -13
  422. package/build/core/promiseHandles.d.ts.map +1 -1
  423. package/build/core/promiseHandles.js +0 -25
  424. package/build/core/promiseHandles.js.map +1 -1
  425. package/build/core/register.js +0 -44
  426. package/build/core/register.js.map +1 -1
  427. package/build/core/rnGlobalsBootstrap.d.ts +0 -13
  428. package/build/core/rnGlobalsBootstrap.d.ts.map +1 -1
  429. package/build/core/rnGlobalsBootstrap.js +0 -22
  430. package/build/core/rnGlobalsBootstrap.js.map +1 -1
  431. package/build/core/routeHistory.d.ts +24 -0
  432. package/build/core/routeHistory.d.ts.map +1 -0
  433. package/build/core/routeHistory.js +186 -0
  434. package/build/core/routeHistory.js.map +1 -0
  435. package/build/core/screenLayout.d.ts +0 -11
  436. package/build/core/screenLayout.d.ts.map +1 -1
  437. package/build/core/screenLayout.js +1 -60
  438. package/build/core/screenLayout.js.map +1 -1
  439. package/build/core/screenSpace.d.ts +0 -107
  440. package/build/core/screenSpace.d.ts.map +1 -1
  441. package/build/core/screenSpace.js +0 -103
  442. package/build/core/screenSpace.js.map +1 -1
  443. package/build/core/screenSpaceDevice.d.ts +0 -8
  444. package/build/core/screenSpaceDevice.d.ts.map +1 -1
  445. package/build/core/screenSpaceDevice.js +0 -23
  446. package/build/core/screenSpaceDevice.js.map +1 -1
  447. package/build/core/screenState.d.ts +0 -73
  448. package/build/core/screenState.d.ts.map +1 -1
  449. package/build/core/screenState.js +6 -115
  450. package/build/core/screenState.js.map +1 -1
  451. package/build/core/sdkBridge.js +0 -8
  452. package/build/core/sdkBridge.js.map +1 -1
  453. package/build/core/sdkMirrorPoller.d.ts +0 -18
  454. package/build/core/sdkMirrorPoller.d.ts.map +1 -1
  455. package/build/core/sdkMirrorPoller.js +0 -47
  456. package/build/core/sdkMirrorPoller.js.map +1 -1
  457. package/build/core/selectionBuffer.d.ts +0 -6
  458. package/build/core/selectionBuffer.d.ts.map +1 -1
  459. package/build/core/selectionBuffer.js +0 -5
  460. package/build/core/selectionBuffer.js.map +1 -1
  461. package/build/core/signedVerdict.js +0 -6
  462. package/build/core/signedVerdict.js.map +1 -1
  463. package/build/core/state.d.ts +0 -31
  464. package/build/core/state.d.ts.map +1 -1
  465. package/build/core/state.js +0 -57
  466. package/build/core/state.js.map +1 -1
  467. package/build/core/symbolicate.js +0 -11
  468. package/build/core/symbolicate.js.map +1 -1
  469. package/build/core/telemetry.d.ts +0 -47
  470. package/build/core/telemetry.d.ts.map +1 -1
  471. package/build/core/telemetry.js +1 -173
  472. package/build/core/telemetry.js.map +1 -1
  473. package/build/core/textEntry.d.ts +0 -34
  474. package/build/core/textEntry.d.ts.map +1 -1
  475. package/build/core/textEntry.js +0 -73
  476. package/build/core/textEntry.js.map +1 -1
  477. package/build/core/toolHelpers.d.ts +0 -12
  478. package/build/core/toolHelpers.d.ts.map +1 -1
  479. package/build/core/toolHelpers.js +2 -47
  480. package/build/core/toolHelpers.js.map +1 -1
  481. package/build/core/truncate.d.ts +0 -17
  482. package/build/core/truncate.d.ts.map +1 -1
  483. package/build/core/truncate.js +0 -32
  484. package/build/core/truncate.js.map +1 -1
  485. package/build/core/types.d.ts +0 -6
  486. package/build/core/types.d.ts.map +1 -1
  487. package/build/core/usageCache.js +0 -12
  488. package/build/core/usageCache.js.map +1 -1
  489. package/build/index.js +0 -18
  490. package/build/index.js.map +1 -1
  491. package/build/pro/coordinateMiss.d.ts +0 -30
  492. package/build/pro/coordinateMiss.d.ts.map +1 -1
  493. package/build/pro/coordinateMiss.js +0 -17
  494. package/build/pro/coordinateMiss.js.map +1 -1
  495. package/build/pro/overlayGuard.d.ts +2 -40
  496. package/build/pro/overlayGuard.d.ts.map +1 -1
  497. package/build/pro/overlayGuard.js +0 -63
  498. package/build/pro/overlayGuard.js.map +1 -1
  499. package/build/pro/screenshot-diff.js +4 -6
  500. package/build/pro/screenshot-diff.js.map +1 -1
  501. package/build/pro/tap.d.ts +0 -55
  502. package/build/pro/tap.d.ts.map +1 -1
  503. package/build/pro/tap.js +7 -330
  504. package/build/pro/tap.js.map +1 -1
  505. package/build/pro/usageGate.js +0 -9
  506. package/build/pro/usageGate.js.map +1 -1
  507. package/build/pro/usageNotifications.js +1 -13
  508. package/build/pro/usageNotifications.js.map +1 -1
  509. package/build/pro/verifyAction.d.ts +0 -13
  510. package/build/pro/verifyAction.d.ts.map +1 -1
  511. package/build/pro/verifyAction.js +0 -45
  512. package/build/pro/verifyAction.js.map +1 -1
  513. package/build/tools/_deviceArg.d.ts +0 -35
  514. package/build/tools/_deviceArg.d.ts.map +1 -1
  515. package/build/tools/_deviceArg.js +0 -35
  516. package/build/tools/_deviceArg.js.map +1 -1
  517. package/build/tools/accountTools.js +2 -2
  518. package/build/tools/accountTools.js.map +1 -1
  519. package/build/tools/bundleTools.js +0 -16
  520. package/build/tools/bundleTools.js.map +1 -1
  521. package/build/tools/componentTools.d.ts.map +1 -1
  522. package/build/tools/componentTools.js +17 -45
  523. package/build/tools/componentTools.js.map +1 -1
  524. package/build/tools/connectionTools.js +1 -59
  525. package/build/tools/connectionTools.js.map +1 -1
  526. package/build/tools/deviceTools.js +0 -11
  527. package/build/tools/deviceTools.js.map +1 -1
  528. package/build/tools/executionTools.js +1 -18
  529. package/build/tools/executionTools.js.map +1 -1
  530. package/build/tools/interactionTools.d.ts +0 -10
  531. package/build/tools/interactionTools.d.ts.map +1 -1
  532. package/build/tools/interactionTools.js +0 -57
  533. package/build/tools/interactionTools.js.map +1 -1
  534. package/build/tools/logTools.d.ts +0 -13
  535. package/build/tools/logTools.d.ts.map +1 -1
  536. package/build/tools/logTools.js +2 -126
  537. package/build/tools/logTools.js.map +1 -1
  538. package/build/tools/metaTools.js +0 -10
  539. package/build/tools/metaTools.js.map +1 -1
  540. package/build/tools/networkTools.js +4 -43
  541. package/build/tools/networkTools.js.map +1 -1
  542. package/build/tools/requestTools.js +0 -5
  543. package/build/tools/requestTools.js.map +1 -1
  544. package/build/tools/screenshotTools.js +5 -111
  545. package/build/tools/screenshotTools.js.map +1 -1
  546. package/package.json +2 -2
  547. package/tools.json +1 -0
package/build/pro/tap.js CHANGED
@@ -14,7 +14,6 @@ export function buildVerificationExplanation(v) {
14
14
  const action = v.action ?? "tap";
15
15
  const Action = action[0].toUpperCase() + action.slice(1);
16
16
  const target = action === "swipe" ? "scroll surface" : "element";
17
- // Burst path with typed verdict
18
17
  if (v.kind === "settled_elsewhere") {
19
18
  return `${Action} caused a visible UI change (${pct(v.changeRate)} pixel diff). Something on screen responded; a pixel diff cannot identify which element, so this is not confirmation that the intended target handled it.`;
20
19
  }
@@ -31,7 +30,6 @@ export function buildVerificationExplanation(v) {
31
30
  return (`No visual change detected — neither persistent nor transient across burst frames. ` +
32
31
  `The ${target} may not respond visually or the ${action} may have missed its target.`);
33
32
  }
34
- // Legacy non-burst path
35
33
  if (v.meaningful) {
36
34
  return `${Action} caused a visible UI change (${pct(v.changeRate)} pixel diff). Something on screen responded; a pixel diff cannot identify which element, so this is not confirmation that the intended target handled it.`;
37
35
  }
@@ -67,9 +65,6 @@ export async function analyzeBurstFrames(frames, options) {
67
65
  const persistentDiff = await compareScreenshots(frames[0], frames[frames.length - 1], options);
68
66
  const persistentChangeRate = persistentDiff.changeRate;
69
67
  const transientChangeDetected = !persistentDiff.changed && framesWithChange.length > 0;
70
- // Snap-back (transient motion that reverts) is NOT a successful gesture —
71
- // the content moved during the drag but returned to its starting position.
72
- // Callers diagnosing scroll failures need this to read as "didn't work".
73
68
  const meaningful = persistentDiff.changed;
74
69
  let kind;
75
70
  if (persistentDiff.changed) {
@@ -91,7 +86,6 @@ export async function analyzeBurstFrames(frames, options) {
91
86
  kind
92
87
  };
93
88
  }
94
- // --- Helpers ---
95
89
  export function buildQuery(options) {
96
90
  const query = {};
97
91
  if (options.text !== undefined)
@@ -106,11 +100,6 @@ export function buildQuery(options) {
106
100
  query.y = options.y;
107
101
  return query;
108
102
  }
109
- /**
110
- * Check if text contains characters that break Hermes Runtime.evaluate.
111
- * Standard accented Latin characters (Polish, Vietnamese, French, German, etc.)
112
- * and Cyrillic work fine in Hermes. Only emoji and special Unicode ranges cause issues.
113
- */
114
103
  export function hasProblematicUnicode(text) {
115
104
  const emojiPattern = /[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{FE00}-\u{FE0F}]|[\u{1F900}-\u{1F9FF}]|[\u{200D}]|[\u{20E3}]|[\u{E0020}-\u{E007F}]/u;
116
105
  return emojiPattern.test(text);
@@ -157,13 +146,6 @@ export function reconstructLinesFromWords(words) {
157
146
  return { text, bbox: { x0, y0, x1, y1 }, tapCenter: { x: tapX, y: tapY }, words: sortedWords };
158
147
  });
159
148
  }
160
- /**
161
- * Narrow the tap point to just the words that produced the substring match.
162
- * Without this, a query for "Remotely" against a reconstructed line "Yes Remotely No"
163
- * would tap at the line's centroid (middle of "Remotely" in this case, but easily wrong
164
- * for asymmetric layouts). Tracks character offsets through the joined text so we know
165
- * which constituent words contributed to the matched range.
166
- */
167
149
  function refineTapCenterToMatchingWords(line, normalizedNeedle) {
168
150
  const normalizedFull = normalizeForMatch(line.text);
169
151
  const startChar = normalizedFull.indexOf(normalizedNeedle);
@@ -176,11 +158,10 @@ function refineTapCenterToMatchingWords(line, normalizedNeedle) {
176
158
  const wNorm = normalizeForMatch(w.text);
177
159
  const wordStart = offset;
178
160
  const wordEnd = offset + wNorm.length;
179
- // Word overlaps the matched range
180
161
  if (wordEnd > startChar && wordStart < endChar) {
181
162
  covered.push(w);
182
163
  }
183
- offset = wordEnd + 1; // +1 for the joining space
164
+ offset = wordEnd + 1;
184
165
  }
185
166
  if (covered.length === 0)
186
167
  return line.tapCenter;
@@ -206,10 +187,6 @@ export function findOcrMatch(ocrResult, query) {
206
187
  const substringWord = words.find((w) => normalizeForMatch(w.text).includes(needle));
207
188
  if (substringWord)
208
189
  return { text: substringWord.text, tapCenter: substringWord.tapCenter };
209
- // Fall through to phrases reconstructed from word detections. Tap point is
210
- // refined to only the words covering the matched substring, so a query for
211
- // "Continue with Google" inside "[icon] Continue with Google" lands on the
212
- // text run instead of the line centroid (and won't drift onto the icon).
213
190
  const reconstructed = reconstructLinesFromWords(words);
214
191
  const exactRecon = reconstructed.find((l) => normalizeForMatch(l.text) === needle);
215
192
  if (exactRecon) {
@@ -226,7 +203,6 @@ export function getAvailableStrategies(query, strategy) {
226
203
  return ["coordinate"];
227
204
  }
228
205
  if (strategy !== "auto") {
229
- // Always fallback to OCR for text queries — explicit strategy may miss visible text
230
206
  if (query.text && strategy !== "ocr" && strategy !== "coordinate") {
231
207
  return [strategy, "ocr"];
232
208
  }
@@ -249,16 +225,6 @@ export function getAvailableStrategies(query, strategy) {
249
225
  }
250
226
  return ["fiber", "accessibility", "ocr"];
251
227
  }
252
- /**
253
- * Convert screenshot image coordinates to platform-native tap coordinates.
254
- *
255
- * For iOS: screenshot pixels → device pixels (undo downscale) → points (÷ DPR)
256
- * For Android: screenshot pixels → device pixels (undo downscale)
257
- *
258
- * IMPORTANT: Only use this for EXTERNAL coordinates from screenshots.
259
- * Internal strategies (OCR, accessibility, fiber) produce tap-ready coordinates
260
- * and call iosTap/androidTap directly — they must NOT go through this function.
261
- */
262
228
  export function convertScreenshotToTapCoords(pixelX, pixelY, platform, devicePixelRatio, scaleFactor = 1) {
263
229
  const deviceX = pixelX * scaleFactor;
264
230
  const deviceY = pixelY * scaleFactor;
@@ -270,16 +236,7 @@ export function convertScreenshotToTapCoords(pixelX, pixelY, platform, devicePix
270
236
  y: Math.round(deviceY / devicePixelRatio)
271
237
  };
272
238
  }
273
- /** @deprecated Use convertScreenshotToTapCoords instead */
274
239
  export const convertPixelsToPoints = convertScreenshotToTapCoords;
275
- /**
276
- * Turn a swipe direction (+ optional pixel distance) into screenshot-pixel
277
- * start/end coordinates, centered on the screen. Content-scroll semantics:
278
- * "up" = finger travels bottom→top, revealing content below.
279
- * Distance defaults to 33% of the relevant axis and endpoints clamp to the
280
- * 10%–90% margin so the gesture never runs off-screen. Exact travel length is
281
- * preserved; for odd distances the band may sit ≤1px off the axis midpoint.
282
- */
283
240
  export function computeSwipeFromDirection(direction, distance, width, height) {
284
241
  const vertical = direction === "up" || direction === "down";
285
242
  const axis = vertical ? height : width;
@@ -288,11 +245,10 @@ export function computeSwipeFromDirection(direction, distance, width, height) {
288
245
  const cy = Math.round(height / 2);
289
246
  const lo = Math.round(0.1 * axis);
290
247
  const hi = Math.round(0.9 * axis);
291
- // Center a band of length d on the axis midpoint, then clamp to [lo, hi].
292
248
  const mid = Math.round(axis / 2);
293
249
  const half = Math.floor(d / 2);
294
- let far = mid - half; // smaller-coordinate end
295
- let near = far + d; // exact length d
250
+ let far = mid - half;
251
+ let near = far + d;
296
252
  if (near > hi) {
297
253
  near = hi;
298
254
  far = near - d;
@@ -301,29 +257,23 @@ export function computeSwipeFromDirection(direction, distance, width, height) {
301
257
  far = lo;
302
258
  near = far + d;
303
259
  }
304
- // distance exceeds the available span — collapse to the full margin
305
260
  if (near > hi)
306
261
  near = hi;
307
262
  if (far < lo)
308
263
  far = lo;
309
264
  switch (direction) {
310
- case "up": // finger bottom→top: start at larger Y, end at smaller Y
265
+ case "up":
311
266
  return { startX: cx, startY: near, endX: cx, endY: far };
312
- case "down": // finger top→bottom
267
+ case "down":
313
268
  return { startX: cx, startY: far, endX: cx, endY: near };
314
- case "left": // finger right→left
269
+ case "left":
315
270
  return { startX: near, startY: cy, endX: far, endY: cy };
316
- case "right": // finger left→right
271
+ case "right":
317
272
  return { startX: far, startY: cy, endX: near, endY: cy };
318
273
  }
319
274
  }
320
275
  export function formatTapSuccess(data) {
321
276
  const { screenshot, verification, ...rest } = data;
322
- // I3 (2026-05-16): when the tap landed on a TextInput-like element and the diff
323
- // reports no visual change, that does NOT mean the focus failed. iOS simulators with
324
- // the hardware keyboard connected (Cmd+K) suppress the on-screen keyboard, so the
325
- // input is focused but the screen looks identical. Surface this so the agent doesn't
326
- // assume the tap missed and retry the wrong thing.
327
277
  const isTextInputComponent = (() => {
328
278
  const name = data.component ?? data.pressed ?? "";
329
279
  return /textfield|textinput|edittext|searchfield/i.test(name);
@@ -370,16 +320,6 @@ function buildErrorMessage(query) {
370
320
  parts.push(`component="${query.component}"`);
371
321
  return `No element found matching ${parts.join(", ")}`;
372
322
  }
373
- // I2 (2026-05-16): RN component composition routinely produces N matches at the same
374
- // coordinates for the same testID/text (e.g. ThemedButton → TouchableOpacity → TouchableOpacity).
375
- // The C1 ambiguity guard refuses all such taps and demands `index=`. That's correct in the
376
- // spatial-ambiguity case (two distinct buttons share a label) but wrong in the
377
- // wrapper-ambiguity case — there's only one logical button, just stacked components.
378
- //
379
- // Collapse matches that share the same (testID, text) and overlap geometrically
380
- // (centers within TOLERANCE_PX). Keeps the first occurrence — fiber/a11y walks parent-first,
381
- // so the outermost wrapper survives (its onPress almost always proxies to inner handlers).
382
- // Spatial ambiguity (different x/y) is preserved and continues to surface the C1 refusal.
383
323
  function collapseGeometricallyEquivalentMatches(matches, getCenter, getKey) {
384
324
  if (matches.length <= 1)
385
325
  return matches;
@@ -412,7 +352,6 @@ function ocrSimilarity(a, b) {
412
352
  return 0;
413
353
  if (a === b)
414
354
  return 1;
415
- // Dice coefficient over character bigrams (case/space-insensitive)
416
355
  const bigrams = (s) => {
417
356
  const m = new Map();
418
357
  if (s.length < 2) {
@@ -451,9 +390,6 @@ export function findClosestOcrText(ocrResult, query) {
451
390
  candidates.push(...ocrResult.words.map(w => ({ text: w.text })));
452
391
  if (ocrResult?.lines?.length)
453
392
  candidates.push(...ocrResult.lines.map(l => ({ text: l.text })));
454
- // Include reconstructed phrases so the diagnostic surfaces "Continue with Google@1.00"
455
- // instead of "Continue@0.54" when the engine fragmented a multi-word phrase into
456
- // separate word detections.
457
393
  if (ocrResult?.words?.length) {
458
394
  candidates.push(...reconstructLinesFromWords(ocrResult.words).map(l => ({ text: l.text })));
459
395
  }
@@ -470,7 +406,6 @@ export function findClosestOcrText(ocrResult, query) {
470
406
  }
471
407
  return best;
472
408
  }
473
- // --- Strategy Functions ---
474
409
  async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device) {
475
410
  if (sink) {
476
411
  sink.fiber.ran = true;
@@ -478,10 +413,8 @@ async function tryFiberStrategy(query, index, maxTraversalDepth, sink, device) {
478
413
  }
479
414
  const startedAt = Date.now();
480
415
  try {
481
- // Retry with increasing depth if the initial traversal finds nothing
482
416
  const baseDepth = maxTraversalDepth ?? 15;
483
417
  const depthAttempts = [baseDepth];
484
- // Only add deeper retries if user didn't explicitly set a high depth
485
418
  if (baseDepth <= 15) {
486
419
  depthAttempts.push(30, 45);
487
420
  }
@@ -540,16 +473,8 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
540
473
  }
541
474
  return strategyResult;
542
475
  }
543
- // Fiber finds the element by text/testID/component, then measures its
544
- // host component's screen position for a native tap. This ensures the tap
545
- // goes through React's event pipeline, executing any onPress wrappers
546
- // (analytics, debouncing, state tracking) inside the component.
547
476
  if (parsed.needsNativeTap) {
548
- // Ambiguity guard: if multiple elements match and the caller didn't
549
- // specify an explicit index, refuse to tap and surface the full list
550
- // so the agent can pick the right one.
551
477
  if ((parsed.totalMatches ?? 1) > 1 && index === undefined) {
552
- // I2: collapse geometrically-identical wrapper matches before refusing.
553
478
  const collapsed = collapseGeometricallyEquivalentMatches(parsed.allMatches ?? [], (m) => ({ x: m.x, y: m.y }), (m) => `${m.testID ?? ""}::${m.text ?? ""}`);
554
479
  if (collapsed.length > 1) {
555
480
  return {
@@ -559,9 +484,6 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
559
484
  ambiguous: true
560
485
  };
561
486
  }
562
- // Collapsed to one logical element — fall through and tap. The JS-side
563
- // search already picked allMatches[0] (the outermost wrapper) for
564
- // parsed.pressed/parsed.nativeTapTarget.
565
487
  }
566
488
  const elementType = parsed.isInput ? "input element" : "pressable element";
567
489
  if (parsed.nativeTapTarget && parsed.nativeTapTarget.x && parsed.nativeTapTarget.y) {
@@ -584,7 +506,6 @@ async function tryFiberAtDepth(query, index, maxTraversalDepth, device) {
584
506
  reason: `Found ${parsed.pressed} (${elementType}) but could not measure coordinates — falling through to next strategy`
585
507
  };
586
508
  }
587
- // All elements now use needsNativeTap — this shouldn't be reached
588
509
  return {
589
510
  success: false,
590
511
  reason: "Unexpected: element did not request native tap"
@@ -611,28 +532,20 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
611
532
  };
612
533
  }
613
534
  if (platform === "ios") {
614
- // One accessibility dump serves every pass below: `axe describe-ui`
615
- // costs ~210ms and the screen cannot change between predicates, so
616
- // re-fetching per pass was pure overhead (2-3 dumps per tap).
617
535
  const { iosGetUITree } = await import("../core/ios.js");
618
536
  const tree = await iosGetUITree(udid);
619
- // iOS: testID maps to accessibilityIdentifier — search by identifier first,
620
- // then fall back to labelContains for text-based searches
621
537
  let result;
622
538
  if (hasTestID && !hasText) {
623
- // Try exact identifier match first (testID → accessibilityIdentifier)
624
539
  result = await iosFindElement({
625
540
  identifier: query.testID,
626
541
  index
627
542
  }, udid, tree);
628
- // Fall back to identifierContains if exact match fails
629
543
  if (!result.success || !result.allMatches || result.allMatches.length === 0) {
630
544
  result = await iosFindElement({
631
545
  identifierContains: query.testID,
632
546
  index
633
547
  }, udid, tree);
634
548
  }
635
- // Last resort: try labelContains in case testID is reflected in label
636
549
  if (!result.success || !result.allMatches || result.allMatches.length === 0) {
637
550
  result = await iosFindElement({
638
551
  labelContains: query.testID,
@@ -642,8 +555,6 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
642
555
  }
643
556
  else {
644
557
  const searchText = query.text;
645
- // Exact label match first to avoid matching dialog titles like "Clear All"
646
- // when the query is a single word that happens to be a substring ("Clear").
647
558
  result = await iosFindElement({
648
559
  label: searchText,
649
560
  index
@@ -670,12 +581,6 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
670
581
  reason: result.error ?? "No iOS accessibility match"
671
582
  };
672
583
  }
673
- // Ambiguity guard: when the predicate matches multiple a11y elements
674
- // (e.g. text="My Events" hits both the header title AND the bottom tab),
675
- // refuse to tap without an explicit index — picking allMatches[0] silently
676
- // landed on non-interactive header elements in production telemetry.
677
- // Mirrors the fiber-strategy guard further up the file.
678
- // I2: collapse geometrically-identical wrapper matches before refusing.
679
584
  const iosEffectiveMatches = result.allMatches.length > 1
680
585
  ? collapseGeometricallyEquivalentMatches(result.allMatches, (m) => ({ x: m.center?.x, y: m.center?.y }), (m) => `${m.identifier ?? ""}::${m.label ?? ""}`)
681
586
  : result.allMatches;
@@ -712,7 +617,6 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
712
617
  };
713
618
  }
714
619
  else {
715
- // Android: testID maps to resource-id, text maps to text content
716
620
  const searchOptions = { index };
717
621
  if (hasTestID && !hasText) {
718
622
  searchOptions.resourceId = query.testID;
@@ -720,13 +624,9 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
720
624
  else if (hasText) {
721
625
  searchOptions.textContains = query.text;
722
626
  }
723
- // Same single-dump reuse as iOS above — a uiautomator hierarchy dump
724
- // is the most expensive step of an Android accessibility tap.
725
627
  const { androidGetUITree } = await import("../core/android.js");
726
628
  const androidTree = await androidGetUITree(undefined, signal);
727
629
  let result = await androidFindElement(searchOptions, undefined, signal, androidTree);
728
- // If testID search via resourceId failed, try contentDescContains
729
- // (older RN versions map testID to content-description)
730
630
  if (hasTestID && !hasText && (!result.success || !result.allMatches || result.allMatches.length === 0)) {
731
631
  result = await androidFindElement({
732
632
  contentDescContains: query.testID,
@@ -748,8 +648,6 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
748
648
  reason: result.error ?? "No Android accessibility match"
749
649
  };
750
650
  }
751
- // Ambiguity guard — see iOS branch above for rationale.
752
- // I2: collapse geometrically-identical wrapper matches before refusing.
753
651
  const androidEffectiveMatches = result.allMatches.length > 1
754
652
  ? collapseGeometricallyEquivalentMatches(result.allMatches, (m) => ({ x: m.center?.x, y: m.center?.y }), (m) => `${m.resourceId ?? ""}::${m.text ?? m.contentDesc ?? ""}`)
755
653
  : result.allMatches;
@@ -797,11 +695,6 @@ async function tryAccessibilityStrategy(query, index, platform, udid, sink, sign
797
695
  sink.accessibility.durationMs = Date.now() - startedAt;
798
696
  }
799
697
  }
800
- /**
801
- * Run OCR sense (capture + recognize + match) and tap the match. Also records
802
- * `sink.ocr.bestCandidate` (matched text + tap coords) into the evidence sink,
803
- * which is serialized into the R2 failure bundle for diagnostics.
804
- */
805
698
  async function tryOcrStrategy(query, platform, udid, sink, signal) {
806
699
  if (sink)
807
700
  sink.ocr.ran = true;
@@ -855,10 +748,6 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
855
748
  sink.ocr.closestMatch = findClosestOcrText(ocrResult, searchText);
856
749
  }
857
750
  const match = findOcrMatch(ocrResult, searchText);
858
- // Record the best candidate (matched text + tap coords) into the
859
- // evidence sink. This is serialized into the R2 failure bundle and is
860
- // useful when diagnosing OCR taps (e.g. OCR found the match at these
861
- // coords but the tap didn't register a visual change).
862
751
  if (sink && match) {
863
752
  const closest = sink.ocr.closestMatch;
864
753
  sink.ocr.bestCandidate = {
@@ -875,7 +764,6 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
875
764
  };
876
765
  }
877
766
  if (platform === "ios") {
878
- // tapCenter is in image-pixel space (downscaled) — convert to points
879
767
  const { getDevicePixelRatio } = await import("../core/ios.js");
880
768
  const dpr = await getDevicePixelRatio(udid);
881
769
  const tapResult = await iosTap(Math.round((match.tapCenter.x * scaleFactor) / dpr), Math.round((match.tapCenter.y * scaleFactor) / dpr), { udid });
@@ -887,7 +775,6 @@ async function tryOcrStrategy(query, platform, udid, sink, signal) {
887
775
  }
888
776
  }
889
777
  else {
890
- // Android: image-pixel → device-pixel (undo downscale), ADB accepts pixels
891
778
  await androidTap(Math.round(match.tapCenter.x * scaleFactor), Math.round(match.tapCenter.y * scaleFactor));
892
779
  }
893
780
  return {
@@ -917,8 +804,6 @@ async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, u
917
804
  if (platform === "ios") {
918
805
  const scaleFactor = lastScreenshot?.scaleFactor ?? 1;
919
806
  const { getDevicePixelRatio } = await import("../core/ios.js");
920
- // Reuse the caller's frame dimensions when it has them, so the first
921
- // coordinate tap of a session doesn't pay for an extra screenshot.
922
807
  const dprHint = lastScreenshot && lastScreenshot.originalWidth > 0 && lastScreenshot.originalHeight > 0
923
808
  ? { width: lastScreenshot.originalWidth, height: lastScreenshot.originalHeight }
924
809
  : undefined;
@@ -957,24 +842,7 @@ async function tryCoordinateStrategy(pixelX, pixelY, platform, lastScreenshot, u
957
842
  }
958
843
  const TAP_TIMEOUT_MS = 25000;
959
844
  const MIN_STRATEGY_BUDGET_MS = 500;
960
- /**
961
- * Ceiling for the pre-dispatch overlay check. It shares the tap's deadline with the
962
- * strategies that follow, so it must not be able to spend the whole budget on a fiber
963
- * read — a screen big enough to make this slow is exactly when the tap still needs time.
964
- */
965
845
  const OVERLAY_GUARD_BUDGET_MS = 3000;
966
- // Per-strategy budget. OCR cap on Android is bumped via maxStrategyMs() because
967
- // the ADB screencap+pull leg has ~2s variance on real devices; iOS stays at 5s
968
- // where xcrun simctl screenshot is consistent.
969
- // Heavy strategies (fiber on deep trees with multi-depth retries, axe accessibility
970
- // dumps on dense iOS screens) need more headroom — previous caps produced spurious
971
- // timeouts that the agent read as "element missing" when the strategy simply didn't
972
- // get to finish. The overall TAP_TIMEOUT_MS budget still bounds the worst case.
973
- // Coordinate looks "light" (one tap subprocess) but on iOS it pairs an axe/idb
974
- // invocation with a CDP getDevicePixelRatio + best-effort fiber inspection;
975
- // the 3000ms cap surfaced as spurious "coordinate timed out" failures while
976
- // 20+ seconds of the overall budget were still unused. Align with the other
977
- // strategies — the global TAP_TIMEOUT_MS still bounds the worst case.
978
846
  const MAX_STRATEGY_MS = {
979
847
  fiber: 8000,
980
848
  accessibility: 6000,
@@ -986,9 +854,6 @@ function maxStrategyMs(strategy, platform) {
986
854
  return 9000;
987
855
  return MAX_STRATEGY_MS[strategy] ?? 5000;
988
856
  }
989
- // Matches only the outer withTimeout wrapper message for a tap strategy.
990
- // Nested sub-operation errors inside a strategy (e.g. "CDP getProperties timed out after 150ms")
991
- // must NOT be classified as a tap-level timeout.
992
857
  const STRATEGY_TIMEOUT_RE = /^(fiber|accessibility|ocr|coordinate) timed out after \d+ms$/;
993
858
  export function isTapTimeout(attempted) {
994
859
  return attempted.some((a) => a.outcome === "timeout" || a.outcome === "skipped" || STRATEGY_TIMEOUT_RE.test(a.reason) || a.reason.startsWith("Skipped —"));
@@ -1005,12 +870,6 @@ function withTimeout(promise, ms, label) {
1005
870
  });
1006
871
  });
1007
872
  }
1008
- /**
1009
- * Like withTimeout, but creates an AbortController whose signal is handed to
1010
- * the inner factory. On timeout the signal aborts so subprocess work
1011
- * (uiautomator dump, OCR fetch, screencap) can be killed instead of running
1012
- * past the strategy cap and bleeding into total tap duration.
1013
- */
1014
873
  function withCancelableTimeout(make, ms, label) {
1015
874
  const ctrl = new AbortController();
1016
875
  const timer = setTimeout(() => ctrl.abort(), ms);
@@ -1021,15 +880,6 @@ function withCancelableTimeout(make, ms, label) {
1021
880
  throw err;
1022
881
  });
1023
882
  }
1024
- /**
1025
- * Compute marker coordinates in screenshot-pixel space (what the returned PNG uses).
1026
- * Unit rules by strategy, assuming screenshotScale = downscale factor:
1027
- * coordinate : input is already screenshot pixels → pass through
1028
- * ocr : match.tapCenter is image-pixel (= screenshot-pixel) → pass through
1029
- * iOS points : point * DPR / screenshotScale
1030
- * android dp : dp * densityScale / screenshotScale
1031
- * android devicePx : devicePx / screenshotScale
1032
- */
1033
883
  function computeMarkerPx(args) {
1034
884
  const { strategy, input, convertedTo, platform, screenshotScale, devicePixelRatio, androidDensityScale } = args;
1035
885
  const scale = screenshotScale || 1;
@@ -1042,36 +892,27 @@ function computeMarkerPx(args) {
1042
892
  return { x: Math.round(convertedTo.x), y: Math.round(convertedTo.y) };
1043
893
  }
1044
894
  if (platform === "ios") {
1045
- // fiber/accessibility on iOS return points
1046
895
  const dpr = devicePixelRatio || 3;
1047
896
  return {
1048
897
  x: Math.round((convertedTo.x * dpr) / scale),
1049
898
  y: Math.round((convertedTo.y * dpr) / scale)
1050
899
  };
1051
900
  }
1052
- // Android
1053
901
  if (strategy === "fiber+native" && androidDensityScale) {
1054
- // Fabric fiber returns dp; fiber+native path scales to device pixels before tap
1055
902
  return {
1056
903
  x: Math.round((convertedTo.x * androidDensityScale) / scale),
1057
904
  y: Math.round((convertedTo.y * androidDensityScale) / scale)
1058
905
  };
1059
906
  }
1060
- // accessibility android: convertedTo is device pixels
1061
907
  return {
1062
908
  x: Math.round(convertedTo.x / scale),
1063
909
  y: Math.round(convertedTo.y / scale)
1064
910
  };
1065
911
  }
1066
- // D2 (Step 6): in-memory ring buffer of recent coord-strategy artifact keys
1067
- // `${round(x/20)}:${round(y/20)}`. Entries expire after 60s. The first
1068
- // failed coord tap at a grid cell uploads its artifact; retries within the
1069
- // window get suppressed.
1070
912
  const recentCoordArtifacts = new Map();
1071
913
  const COORD_DEDUP_WINDOW_MS = 60_000;
1072
914
  const COORD_DEDUP_BUCKET = 20;
1073
915
  function shouldDedupArtifact(ctx) {
1074
- // Only applies to coordinate-strategy artifacts where we have x,y coords.
1075
916
  const winningStrat = ctx.attempted.find(a => a.reason === "success")?.strategy
1076
917
  ?? ctx.attempted[ctx.attempted.length - 1]?.strategy;
1077
918
  if (winningStrat !== "coordinate")
@@ -1082,7 +923,6 @@ function shouldDedupArtifact(ctx) {
1082
923
  return false;
1083
924
  const key = `${Math.round(x / COORD_DEDUP_BUCKET)}:${Math.round(y / COORD_DEDUP_BUCKET)}`;
1084
925
  const now = Date.now();
1085
- // Sweep stale entries opportunistically — keeps the map from growing.
1086
926
  for (const [k, ts] of recentCoordArtifacts) {
1087
927
  if (now - ts > COORD_DEDUP_WINDOW_MS)
1088
928
  recentCoordArtifacts.delete(k);
@@ -1093,26 +933,9 @@ function shouldDedupArtifact(ctx) {
1093
933
  recentCoordArtifacts.set(key, now);
1094
934
  return false;
1095
935
  }
1096
- /** Test-only: drop the dedup state so a fresh tap always uploads. */
1097
936
  export function resetCoordArtifactDedup() {
1098
937
  recentCoordArtifacts.clear();
1099
938
  }
1100
- /**
1101
- * Turn an unmeaningful coordinate tap into an explanation.
1102
- *
1103
- * Coordinate spaces used to be the hard part here, and the old approach — recovering a
1104
- * scale by dividing the caller's input by the executed tap point, then multiplying the
1105
- * raw screen state by it — was wrong in a way that mattered. That ratio carries no inset
1106
- * term, but the caller's coordinate comes from a space where `topInset` has been applied,
1107
- * so on Android and inside iOS modal presentations the probe landed roughly
1108
- * `topInset x factor` off. An offset probe can hit-test a neighbouring element, and
1109
- * because `explainCoordinateMiss` checks reachable pressables before blocked ones, the
1110
- * usual result was a confident "the coordinates were correct, check your onPress handler"
1111
- * about an element that was in fact covered.
1112
- *
1113
- * Now that every tool shares one space, there is nothing to recover: normalise the state
1114
- * the same way the layout tools do and hit-test the caller's own coordinate against it.
1115
- */
1116
939
  async function diagnoseCoordinateMiss(args) {
1117
940
  try {
1118
941
  const { getScreenState } = await import("../core/screenState.js");
@@ -1130,12 +953,9 @@ async function diagnoseCoordinateMiss(args) {
1130
953
  deviceId: app?.adbSerial
1131
954
  });
1132
955
  const normalised = screenStateToDeliveredPx(screenStateToScreenSpace(ss.screenState, metrics), metrics);
1133
- // State and probe are both in delivered pixels now, so the reported coordinates
1134
- // are already the caller's space — no mapping back.
1135
956
  return explainCoordinateMiss(args.inputPoint, normalised) ?? undefined;
1136
957
  }
1137
958
  catch {
1138
- // Diagnosis is best-effort — never let it turn a successful tap into an error.
1139
959
  return undefined;
1140
960
  }
1141
961
  }
@@ -1143,26 +963,15 @@ async function captureTapArtifact(ctx) {
1143
963
  try {
1144
964
  const { getServerVersion, categorizeError } = await import("../core/telemetry.js");
1145
965
  const strategyChain = ctx.attempted.map(a => `${a.strategy}:${a.reason.slice(0, 40)}`).join("|");
1146
- // Resolve error category up-front so we can short-circuit driver-missing failures.
1147
- // These aren't tap-tool bugs — they're host setup problems (no idb/axe/adb on PATH).
1148
- // Skipping the artifact upload saves R2 storage and stops these from polluting the
1149
- // failure dashboard, which is the signal we use to triage genuine tap regressions.
1150
966
  const errorCategory = ctx.errorCategory
1151
967
  ?? categorizeError(ctx.errorMessage ?? "", strategyChain);
1152
968
  if (errorCategory === "driver_missing") {
1153
969
  return undefined;
1154
970
  }
1155
- // D1 (Step 6): no-metro unmeaningful taps have no diagnostic signal
1156
- // beyond a screenshot diff that's already below threshold by definition.
1157
- // ~50% of recent failure-artifact rows were these — they crowd out real
1158
- // failures in the dashboard. Telemetry row still flows; just no R2 bundle.
1159
971
  const noMetro = ctx.evidence ? !ctx.evidence.fiber.metroConnected : connectedApps.size === 0;
1160
972
  if (ctx.outcome === "unmeaningful" && noMetro) {
1161
973
  return undefined;
1162
974
  }
1163
- // D2 (Step 6): retry deduplication — coord-strategy taps at the same
1164
- // grid cell within 60s upload the same near-identical artifact. The
1165
- // first capture is enough; subsequent ones are noise.
1166
975
  if (shouldDedupArtifact(ctx)) {
1167
976
  return undefined;
1168
977
  }
@@ -1258,7 +1067,6 @@ function attachArtifactSignals(result, signals) {
1258
1067
  result.accessibilityMatchCount = signals.accessibilityMatchCount;
1259
1068
  if (signals.appRoute)
1260
1069
  result.appRoute = signals.appRoute;
1261
- // Append agent-facing hints to error message
1262
1070
  if (result.error) {
1263
1071
  if (signals.ocrClosestMatch) {
1264
1072
  result.error = `${result.error}\nClosest OCR match: ${signals.ocrClosestMatch}`;
@@ -1275,7 +1083,6 @@ function attachArtifactSignals(result, signals) {
1275
1083
  }
1276
1084
  return result;
1277
1085
  }
1278
- // --- Orchestrator ---
1279
1086
  export async function tap(options) {
1280
1087
  const query = buildQuery(options);
1281
1088
  const strategy = options.strategy || "auto";
@@ -1283,7 +1090,6 @@ export async function tap(options) {
1283
1090
  const maxTraversalDepth = options.maxTraversalDepth;
1284
1091
  const deadline = Date.now() + TAP_TIMEOUT_MS;
1285
1092
  const remainingMs = () => Math.max(0, deadline - Date.now());
1286
- // Validate inputs
1287
1093
  const hasSearchParam = query.text || query.testID || query.component;
1288
1094
  const hasCoordinates = query.x !== undefined || query.y !== undefined;
1289
1095
  if (!hasSearchParam && !hasCoordinates) {
@@ -1300,7 +1106,6 @@ export async function tap(options) {
1300
1106
  error: "Both x and y coordinates must be provided"
1301
1107
  };
1302
1108
  }
1303
- // Native mode: bypass React Native connection, tap directly via ADB/simctl
1304
1109
  if (options.native && hasCoordinates) {
1305
1110
  const nativeResolved = await resolveDeviceTarget(options.device);
1306
1111
  if (!nativeResolved.ok) {
@@ -1313,7 +1118,6 @@ export async function tap(options) {
1313
1118
  const platform = nativeResolved.target.platform;
1314
1119
  const nativeUdid = nativeResolved.target.iosUdid;
1315
1120
  const nativeShouldScreenshot = options.screenshot !== false;
1316
- // Decoupled (I5, 2026-05-16): verify runs even when image bytes aren't returned.
1317
1121
  const nativeShouldVerify = options.verify !== false;
1318
1122
  let nativeBeforeBuffer = null;
1319
1123
  let nativeScreenshotMeta;
@@ -1328,7 +1132,6 @@ export async function tap(options) {
1328
1132
  };
1329
1133
  }
1330
1134
  }
1331
- // If no screenshot was taken for verification, take one just for scaleFactor
1332
1135
  if (!nativeScreenshotMeta) {
1333
1136
  const ref = await captureScreenshot(platform, nativeUdid);
1334
1137
  if (ref) {
@@ -1337,7 +1140,6 @@ export async function tap(options) {
1337
1140
  originalHeight: ref.height,
1338
1141
  scaleFactor: ref.scaleFactor
1339
1142
  };
1340
- // Also use it for verification if buffer is needed
1341
1143
  if (!nativeBeforeBuffer) {
1342
1144
  nativeBeforeBuffer = ref.buffer;
1343
1145
  }
@@ -1406,10 +1208,6 @@ export async function tap(options) {
1406
1208
  suggestion: `Take a screenshot (${platform === "ios" ? "ios_screenshot" : "android_screenshot"}) to verify coordinates.`
1407
1209
  });
1408
1210
  }
1409
- // Resolve device target via the unified resolver. Replaces the prior chain
1410
- // of (udid → connectedApp → findSimulatorByName) lookups and the standalone
1411
- // "no platform → probe OS for devices" branch. Returns a structured error
1412
- // when ambiguous; surface that to the caller so they can disambiguate.
1413
1211
  const resolved = await resolveDeviceTarget(options.device);
1414
1212
  if (!resolved.ok) {
1415
1213
  return {
@@ -1421,10 +1219,6 @@ export async function tap(options) {
1421
1219
  const deviceNote = resolved.note;
1422
1220
  const platform = resolved.target.platform;
1423
1221
  let targetUdid = resolved.target.iosUdid;
1424
- // Pick the connected app to bias strategy selection. Prefer the registry
1425
- // entry whose identifier matches the resolved target; fall back to a
1426
- // device-name match (handy when registry entries lack identifiers yet);
1427
- // last resort is the first connected app on the matching platform.
1428
1222
  const allApps = Array.from(connectedApps.values());
1429
1223
  let hasMetro = allApps.length > 0;
1430
1224
  let app;
@@ -1439,16 +1233,11 @@ export async function tap(options) {
1439
1233
  app = getConnectedAppByDevice(options.device) ?? undefined;
1440
1234
  }
1441
1235
  catch {
1442
- // getConnectedAppByDevice throws on ambiguous matches; the resolver
1443
- // would have already returned that error, so reaching here means
1444
- // the resolved target's identifier just doesn't appear in the
1445
- // registry yet — fall through to the platform-first pick below.
1446
1236
  }
1447
1237
  }
1448
1238
  if (!app) {
1449
1239
  app = allApps.find((a) => a.platform === platform) ?? allApps[0];
1450
1240
  }
1451
- // Try to auto-connect to Metro (for fiber strategy), but don't fail if it doesn't work.
1452
1241
  if (!hasMetro) {
1453
1242
  try {
1454
1243
  await withTimeout((async () => {
@@ -1471,26 +1260,17 @@ export async function tap(options) {
1471
1260
  }
1472
1261
  }
1473
1262
  catch {
1474
- // Auto-connect failed — Metro-dependent strategies will be skipped
1475
1263
  }
1476
1264
  }
1477
- // The response's `device` label must reflect the RESOLVED target, not the
1478
- // registry-app fallback. When the registry lookup couldn't find a matching
1479
- // app (e.g. simulatorUdid hadn't been backfilled yet), `app` lands on the
1480
- // first iOS entry — which on a multi-sim setup is the WRONG device. The
1481
- // resolver already knows the right deviceName; trust it. Bug #5 (2026-05-20).
1482
1265
  const deviceName = resolved.target.deviceName || app?.deviceInfo?.deviceName;
1483
- // Determine strategies
1484
1266
  const strategies = getAvailableStrategies(query, strategy);
1485
1267
  const attempted = [];
1486
1268
  const evidence = makeEmptyEvidenceSink();
1487
- // Early UI driver check for iOS — fail fast instead of falling through every strategy
1488
1269
  const UI_DRIVER_REQUIRED_STRATEGIES = ["accessibility", "ocr", "coordinate"];
1489
1270
  let uiDriverMissing = false;
1490
1271
  if (platform === "ios") {
1491
1272
  uiDriverMissing = !(await isUiDriverAvailable());
1492
1273
  }
1493
- // Filter strategies by available capabilities
1494
1274
  const filteredStrategies = strategies.filter((strat) => {
1495
1275
  if (strat === "fiber" && !hasMetro) {
1496
1276
  attempted.push({
@@ -1524,18 +1304,6 @@ export async function tap(options) {
1524
1304
  error: errorMessage
1525
1305
  };
1526
1306
  }
1527
- // Refuse before dispatch when the target is under an overlay. Every strategy resolves
1528
- // to a coordinate tap, so the OS would deliver the touch to the overlay — firing it
1529
- // would press the wrong element and mutate state the caller never asked to change.
1530
- //
1531
- // Bounded, and failure-open by construction: the guard costs one fiber read, and if
1532
- // that read is slow, errors, or cannot reach a verdict, the tap proceeds exactly as it
1533
- // did before. Blocking a legitimate tap because a diagnostic timed out would be a far
1534
- // worse regression than the mis-delivery this prevents — tap is the tool everything
1535
- // else is built on.
1536
- // Set when the tap is dispatched onto an overlay control that shadows a covered
1537
- // element; attached to the successful result so the caller learns what actually
1538
- // received the touch.
1539
1307
  let shadowWarning;
1540
1308
  if (hasMetro) {
1541
1309
  const guardBudget = Math.min(remainingMs(), OVERLAY_GUARD_BUDGET_MS);
@@ -1555,9 +1323,6 @@ export async function tap(options) {
1555
1323
  blockedBy = null;
1556
1324
  }
1557
1325
  if (blockedBy?.kind === "blocked") {
1558
- // Recorded as an attempt so the refusal is distinguishable in telemetry
1559
- // (_errorContext) from a tap that tried and failed. Without it every
1560
- // declined tap looks like a tap-tool regression on the failure dashboard.
1561
1326
  attempted.push({
1562
1327
  strategy: "overlay-guard",
1563
1328
  reason: `refused — target covered by ${blockedBy.overlay}`,
@@ -1578,8 +1343,6 @@ export async function tap(options) {
1578
1343
  };
1579
1344
  }
1580
1345
  if (blockedBy?.kind === "shadowed") {
1581
- // Dispatch, but name the element that will actually receive the touch.
1582
- // Staying silent here is the reported bug in miniature.
1583
1346
  shadowWarning =
1584
1347
  `This coordinate is occupied by ${blockedBy.hit}, part of ${blockedBy.overlay} — ` +
1585
1348
  `that is what received the tap. ${blockedBy.covered} sits underneath it and ` +
@@ -1587,18 +1350,10 @@ export async function tap(options) {
1587
1350
  }
1588
1351
  }
1589
1352
  }
1590
- // Determine screenshot and verification behavior.
1591
- // Decoupled (I5, 2026-05-16): verify can run without returning image bytes —
1592
- // capture cost is paid either way; bandwidth cost is what `screenshot` toggles.
1593
1353
  const shouldScreenshot = options.screenshot !== false;
1594
1354
  const canVerify = options.verify !== false;
1595
- // Capture "before" screenshot. Always attempted (independent of canVerify)
1596
- // so failure artifacts always carry a before.png — the diagnostic value of
1597
- // the before frame doesn't depend on whether we run the post-tap diff.
1598
1355
  let beforeBuffer = null;
1599
1356
  let beforeScaleFactor;
1600
- // Pixel dimensions of the frame we just captured. getDevicePixelRatio would
1601
- // otherwise shell out for a screenshot of its own to learn exactly this.
1602
1357
  let beforeDims;
1603
1358
  {
1604
1359
  const before = await captureScreenshot(platform, targetUdid);
@@ -1608,16 +1363,6 @@ export async function tap(options) {
1608
1363
  beforeDims = { width: before.width, height: before.height };
1609
1364
  }
1610
1365
  }
1611
- // OCR runs lazily when the loop reaches it (see the `case "ocr"` branch).
1612
- // A concurrent pre-warm probe used to fire here to shave ~5s off OCR-win
1613
- // rows, but it dispatched a paid Google Vision request at t=0 on every
1614
- // text-predicate tap — and since cloud OCR (~200ms) finishes well before
1615
- // the higher-priority strategy that usually wins, the post-win abort came
1616
- // too late to cancel the billed request. OCR wins only ~1.9% of taps, so
1617
- // the pre-warm paid for cloud Vision on ~42% of eligible taps to help a
1618
- // tiny minority. Removed 2026-06-02; the timeout-recovery path below still
1619
- // salvages the perfect-match-past-cap case.
1620
- // Execute strategies in order with per-strategy caps and overall budget
1621
1366
  for (const strat of filteredStrategies) {
1622
1367
  const remaining = remainingMs();
1623
1368
  if (remaining < MIN_STRATEGY_BUDGET_MS) {
@@ -1634,8 +1379,6 @@ export async function tap(options) {
1634
1379
  try {
1635
1380
  switch (strat) {
1636
1381
  case "fiber":
1637
- // Fiber is JS-only against a CDP target — no subprocess to cancel,
1638
- // so the cheaper non-cancellable wrapper is fine.
1639
1382
  result = await withTimeout(tryFiberStrategy(query, index, maxTraversalDepth, evidence, deviceName), budget, `fiber`);
1640
1383
  break;
1641
1384
  case "accessibility":
@@ -1645,9 +1388,6 @@ export async function tap(options) {
1645
1388
  result = await withCancelableTimeout((signal) => tryOcrStrategy(query, platform, targetUdid, evidence, signal), budget, `ocr`);
1646
1389
  break;
1647
1390
  case "coordinate":
1648
- // Prefer `beforeScaleFactor` (captured against `targetUdid` this turn)
1649
- // over `app.lastScreenshot.scaleFactor` (stale and may belong to a
1650
- // different device on a multi-sim setup). Bug #5 (2026-05-20).
1651
1391
  result = await withTimeout(tryCoordinateStrategy(query.x, query.y, platform, beforeScaleFactor != null
1652
1392
  ? {
1653
1393
  originalWidth: beforeDims?.width ?? 0,
@@ -1662,11 +1402,6 @@ export async function tap(options) {
1662
1402
  }
1663
1403
  catch (err) {
1664
1404
  const reason = err instanceof Error ? err.message : String(err);
1665
- // Classify the throw: a strategy-level timeout means "result UNKNOWN"
1666
- // (the strategy didn't finish), distinct from "ran clean and found
1667
- // nothing". Agents must not infer absence from timeouts. The
1668
- // `outcome` field carries that distinction; `reason` stays the raw
1669
- // message so existing log-matchers / classifiers keep working.
1670
1405
  const outcome = STRATEGY_TIMEOUT_RE.test(reason) ? "timeout" : "error";
1671
1406
  attempted.push({ strategy: strat, reason, outcome });
1672
1407
  continue;
@@ -1701,11 +1436,6 @@ export async function tap(options) {
1701
1436
  beforeScaleFactor,
1702
1437
  markerPx: strategyMarker
1703
1438
  }));
1704
- // Burst always produces a screenshot for diff visualization. Drop the
1705
- // bytes when the caller didn't ask for them AND the tap was meaningful
1706
- // — keeping the screenshot on unmeaningful taps saves the agent a
1707
- // round-trip when it needs to diagnose. Frames remain in imageBuffer
1708
- // either way (accessible via get_images(groupId=verification.burstGroupId)).
1709
1439
  if (!shouldScreenshot && verification?.meaningful !== false)
1710
1440
  screenshot = undefined;
1711
1441
  }
@@ -1719,8 +1449,6 @@ export async function tap(options) {
1719
1449
  beforeScaleFactor,
1720
1450
  markerPx: strategyMarker
1721
1451
  }));
1722
- // Mirror the burst-path gate: drop the screenshot only when the
1723
- // caller didn't ask for it AND the tap was meaningful.
1724
1452
  if (!shouldScreenshot && verification?.meaningful !== false)
1725
1453
  screenshot = undefined;
1726
1454
  }
@@ -1745,26 +1473,12 @@ export async function tap(options) {
1745
1473
  screenshot,
1746
1474
  verification
1747
1475
  });
1748
- // The guard already resolved what occupies this coordinate. Reporting it turns
1749
- // "something responded" into "this element responded" for the one case where
1750
- // the caller most likely meant something else.
1751
1476
  if (shadowWarning) {
1752
1477
  successResult.warning = successResult.warning
1753
1478
  ? `${successResult.warning}\n${shadowWarning}`
1754
1479
  : shadowWarning;
1755
1480
  }
1756
- // Capture an artifact for "successful but unmeaningful" taps so we can
1757
- // diagnose taps that landed wrong or hit non-responsive elements.
1758
- // Uses the same `meaningful` flag the agent sees so dashboard outcomes
1759
- // stay consistent with what the caller observed.
1760
1481
  if (verification && !verification.skipped && verification.meaningful === false) {
1761
- // A coordinate tap that changed nothing is the one case where the
1762
- // agent has no idea what went wrong — it estimated x/y from a
1763
- // screenshot and got back "nothing happened". Screen state knows
1764
- // what sits at that point and what an overlay blocks; spend the
1765
- // ~200ms here (already the slow path) to turn a dead end into a
1766
- // next step. Text/testID/component predicates don't need this:
1767
- // their failure modes are already named in `attempted`.
1768
1482
  if (strat === "coordinate" && result.convertedTo) {
1769
1483
  const diagnosis = await diagnoseCoordinateMiss({
1770
1484
  point: { x: result.convertedTo.x, y: result.convertedTo.y },
@@ -1800,10 +1514,6 @@ export async function tap(options) {
1800
1514
  }
1801
1515
  return successResult;
1802
1516
  }
1803
- // Classify the strategy's non-success result. The reason string carries
1804
- // the diagnostic from the strategy; outcome lets agents branch on category
1805
- // without parsing prose. "invisible" / "ambiguous" are pinned by substring
1806
- // matches the fiber strategy emits via pressables.ts.
1807
1517
  const reasonStr = result.reason || "";
1808
1518
  let attemptOutcome = "not-found";
1809
1519
  if (result.ambiguous)
@@ -1813,36 +1523,26 @@ export async function tap(options) {
1813
1523
  else if (STRATEGY_TIMEOUT_RE.test(reasonStr))
1814
1524
  attemptOutcome = "timeout";
1815
1525
  attempted.push({ strategy: strat, reason: reasonStr, outcome: attemptOutcome });
1816
- // If fiber found an element with measured coordinates, do a native tap directly
1817
1526
  if (strat === "fiber" && result.convertedTo && result.pressed) {
1818
1527
  try {
1819
1528
  const coords = result.convertedTo;
1820
1529
  if (platform === "ios") {
1821
- // react-native-screens modal/sheet presentations cause measureInWindow to
1822
- // return y relative to the screen's content origin, not the window. If the
1823
- // measured y falls inside the safe-area band, shift it down by the inset.
1824
1530
  const safeAreaTop = await getIOSSafeAreaTop(targetUdid);
1825
1531
  const tapY = (safeAreaTop > 0 && coords.y < safeAreaTop) ? coords.y + safeAreaTop : coords.y;
1826
1532
  await iosTap(coords.x, tapY, { udid: targetUdid });
1827
1533
  coords.y = tapY;
1828
1534
  }
1829
1535
  else {
1830
- // Fabric returns dp — androidTap expects pixels
1831
- // Convert dp to pixels using device density
1832
1536
  const { androidGetDensity } = await import("../core/android.js");
1833
1537
  const densityResult = await androidGetDensity();
1834
1538
  const densityScale = (densityResult.density || 420) / 160;
1835
1539
  const pxX = Math.round(coords.x * densityScale);
1836
1540
  const pxY = Math.round(coords.y * densityScale);
1837
1541
  await androidTap(pxX, pxY);
1838
- // Report the actual tap coords (pixels) the caller can pass straight
1839
- // to coordinate tools / verification — not the raw dp from fiber.
1840
- // Matches every other Android coord report in the tool (OB1, 2026-05-20).
1841
1542
  coords.x = pxX;
1842
1543
  coords.y = pxY;
1843
1544
  coords.unit = "pixels";
1844
1545
  }
1845
- // fiber+native uses native tap — always verify
1846
1546
  let screenshot;
1847
1547
  let verification;
1848
1548
  let fnDpr;
@@ -1919,12 +1619,8 @@ export async function tap(options) {
1919
1619
  });
1920
1620
  }
1921
1621
  catch {
1922
- // Native tap at fiber coordinates failed — continue to next strategy
1923
1622
  }
1924
1623
  }
1925
- // Ambiguous fiber result — multiple elements matched, no index given.
1926
- // Return immediately with the full list so the agent can decide.
1927
- // Do NOT fall through to other strategies (they can't resolve ambiguity).
1928
1624
  if (result.matches && result.ambiguous) {
1929
1625
  const { screenshot: matchScreenshot } = shouldScreenshot
1930
1626
  ? await verifyAndCapture({ platform, shouldVerify: false, shouldScreenshot: true, beforeBuffer: null, udid: targetUdid })
@@ -1948,15 +1644,8 @@ export async function tap(options) {
1948
1644
  });
1949
1645
  }
1950
1646
  }
1951
- // All strategies failed — check if the tap budget was the cause.
1952
- // Only outer withTimeout wrapper messages or Skipped entries count; nested
1953
- // sub-op errors that happen to contain "timed out" do not imply the tap
1954
- // itself ran out of time.
1955
1647
  const hitTimeout = isTapTimeout(attempted);
1956
1648
  const elapsed = TAP_TIMEOUT_MS - remainingMs();
1957
- // If fiber located the element but visibility filtered it out, prepend a
1958
- // scroll-or-dismiss hint so the agent doesn't waste a turn assuming the
1959
- // testID/component is missing.
1960
1649
  const fiberSawInvisible = attempted.some(a => a.strategy === "fiber" && a.outcome === "invisible");
1961
1650
  const allTimedOut = attempted.length > 0 && attempted.every(a => a.outcome === "timeout" || a.outcome === "skipped");
1962
1651
  let suggestion = buildSuggestion(query, strategies, platform);
@@ -1964,8 +1653,6 @@ export async function tap(options) {
1964
1653
  suggestion = `Element exists in the React tree but is not on screen. Try scrolling it into view with swipe(), dismiss any overlay covering it, or wait for layout to settle. ` + suggestion;
1965
1654
  }
1966
1655
  else if (allTimedOut) {
1967
- // No strategy got to a definitive answer — don't let the agent conclude
1968
- // the element is missing. Steer toward retry or a different strategy.
1969
1656
  suggestion = `All strategies timed out — the element's presence is UNKNOWN. Retry the tap (transient slowness is common on dense screens), or try a different strategy explicitly (e.g. strategy='fiber' if accessibility timed out). ` + suggestion;
1970
1657
  }
1971
1658
  const { screenshot: failScreenshot } = shouldScreenshot
@@ -1978,8 +1665,6 @@ export async function tap(options) {
1978
1665
  scaleFactor: failScreenshot.scaleFactor
1979
1666
  };
1980
1667
  }
1981
- // Pick the right error framing: a definitive "not found" is different from
1982
- // "all strategies timed out — we don't know whether it exists".
1983
1668
  let errorOverride;
1984
1669
  if (hitTimeout) {
1985
1670
  errorOverride = `Tap timed out after ${elapsed}ms (budget ${TAP_TIMEOUT_MS}ms)`;
@@ -2014,10 +1699,6 @@ export async function tap(options) {
2014
1699
  });
2015
1700
  return attachArtifactSignals(failureResult, failSignals);
2016
1701
  }
2017
- // Matches testIDs typical of virtualized list items: trailing `-<digits>` (e.g. `store-item-0`,
2018
- // `route-item-6`) or containing a UUID v4 fragment (e.g. `group-card-e4566bc6-9164-4fd0-...`).
2019
- // Used by buildSuggestion() to tell the agent to scroll first when a list-item testID
2020
- // can't be found in the visible fiber tree.
2021
1702
  const VIRTUALIZED_TESTID_RE = /(-\d+$)|([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
2022
1703
  function looksLikeVirtualizedListItem(testID) {
2023
1704
  return VIRTUALIZED_TESTID_RE.test(testID);
@@ -2039,10 +1720,6 @@ function buildSuggestion(query, triedStrategies, platform) {
2039
1720
  if (query.testID && !triedStrategies.includes("ocr")) {
2040
1721
  suggestions.push("testID not found in fiber/accessibility tree — verify the element is on the current screen with a screenshot");
2041
1722
  }
2042
- // List-item testIDs (suffix `-N` or containing a UUID) are typically rendered inside a
2043
- // virtualized list — items beyond the viewport are unmounted, so the fiber tree genuinely
2044
- // doesn't contain them. Adding the hint as a separate suggestion (rather than rewriting
2045
- // the error) keeps the existing message stable for tooling that parses it.
2046
1723
  if (query.testID && looksLikeVirtualizedListItem(query.testID)) {
2047
1724
  suggestions.push("testID looks like a virtualized list item — scroll it on-screen first " +
2048
1725
  `(swipe()${platform === "ios" ? " or ios_button arrow keys" : ""}) before tapping`);