execbro 2.3.0 → 2.6.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 (596) hide show
  1. package/README.md +2 -0
  2. package/build/__tests__/helpers/fake-cdp-server.d.ts +0 -12
  3. package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -1
  4. package/build/__tests__/helpers/fake-cdp-server.js +0 -22
  5. package/build/__tests__/helpers/fake-cdp-server.js.map +1 -1
  6. package/build/__tests__/helpers/tap-test-helpers.d.ts +0 -23
  7. package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -1
  8. package/build/__tests__/helpers/tap-test-helpers.js +2 -29
  9. package/build/__tests__/helpers/tap-test-helpers.js.map +1 -1
  10. package/build/__tests__/integration/auto-reconnect.test.js +4 -14
  11. package/build/__tests__/integration/auto-reconnect.test.js.map +1 -1
  12. package/build/__tests__/integration/connection-health.test.js +1 -10
  13. package/build/__tests__/integration/connection-health.test.js.map +1 -1
  14. package/build/__tests__/integration/execute-in-app.test.js +1 -11
  15. package/build/__tests__/integration/execute-in-app.test.js.map +1 -1
  16. package/build/__tests__/integration/native-logs.test.js +0 -5
  17. package/build/__tests__/integration/native-logs.test.js.map +1 -1
  18. package/build/__tests__/integration/per-call-timeout.test.js +1 -5
  19. package/build/__tests__/integration/per-call-timeout.test.js.map +1 -1
  20. package/build/__tests__/integration/socket-close-midflight.test.js +2 -12
  21. package/build/__tests__/integration/socket-close-midflight.test.js.map +1 -1
  22. package/build/__tests__/integration/stale-target-probe.test.js +2 -17
  23. package/build/__tests__/integration/stale-target-probe.test.js.map +1 -1
  24. package/build/__tests__/integration/tap-strategies.test.js +2 -36
  25. package/build/__tests__/integration/tap-strategies.test.js.map +1 -1
  26. package/build/__tests__/integration/text-input.test.js +0 -39
  27. package/build/__tests__/integration/text-input.test.js.map +1 -1
  28. package/build/__tests__/integration/tools.test.js +1 -7
  29. package/build/__tests__/integration/tools.test.js.map +1 -1
  30. package/build/__tests__/setup.js +0 -2
  31. package/build/__tests__/setup.js.map +1 -1
  32. package/build/__tests__/unit/androidEmulatorAvds.test.js +0 -10
  33. package/build/__tests__/unit/androidEmulatorAvds.test.js.map +1 -1
  34. package/build/__tests__/unit/androidPinch.test.d.ts +2 -0
  35. package/build/__tests__/unit/androidPinch.test.d.ts.map +1 -0
  36. package/build/__tests__/unit/androidPinch.test.js +119 -0
  37. package/build/__tests__/unit/androidPinch.test.js.map +1 -0
  38. package/build/__tests__/unit/appContext.test.js +0 -2
  39. package/build/__tests__/unit/appContext.test.js.map +1 -1
  40. package/build/__tests__/unit/appRequest.test.js +0 -3
  41. package/build/__tests__/unit/appRequest.test.js.map +1 -1
  42. package/build/__tests__/unit/buildToken.test.js +0 -6
  43. package/build/__tests__/unit/buildToken.test.js.map +1 -1
  44. package/build/__tests__/unit/burst.test.js +0 -1
  45. package/build/__tests__/unit/burst.test.js.map +1 -1
  46. package/build/__tests__/unit/clearLogsNative.test.js +0 -8
  47. package/build/__tests__/unit/clearLogsNative.test.js.map +1 -1
  48. package/build/__tests__/unit/componentFormatNaming.test.js +0 -13
  49. package/build/__tests__/unit/componentFormatNaming.test.js.map +1 -1
  50. package/build/__tests__/unit/componentSource.test.js +0 -4
  51. package/build/__tests__/unit/componentSource.test.js.map +1 -1
  52. package/build/__tests__/unit/componentSourceResolve.test.js +0 -1
  53. package/build/__tests__/unit/componentSourceResolve.test.js.map +1 -1
  54. package/build/__tests__/unit/contextWiring.test.js +0 -3
  55. package/build/__tests__/unit/contextWiring.test.js.map +1 -1
  56. package/build/__tests__/unit/coordinateMiss.test.js +0 -16
  57. package/build/__tests__/unit/coordinateMiss.test.js.map +1 -1
  58. package/build/__tests__/unit/deviceDiscovery.test.js +0 -4
  59. package/build/__tests__/unit/deviceDiscovery.test.js.map +1 -1
  60. package/build/__tests__/unit/deviceResolution.test.js +0 -2
  61. package/build/__tests__/unit/deviceResolution.test.js.map +1 -1
  62. package/build/__tests__/unit/deviceResolver.test.js +0 -1
  63. package/build/__tests__/unit/deviceResolver.test.js.map +1 -1
  64. package/build/__tests__/unit/deviceResolverStaleRetry.test.js +0 -8
  65. package/build/__tests__/unit/deviceResolverStaleRetry.test.js.map +1 -1
  66. package/build/__tests__/unit/emulatorBridge.test.d.ts +2 -0
  67. package/build/__tests__/unit/emulatorBridge.test.d.ts.map +1 -0
  68. package/build/__tests__/unit/emulatorBridge.test.js +76 -0
  69. package/build/__tests__/unit/emulatorBridge.test.js.map +1 -0
  70. package/build/__tests__/unit/emulatorGrpc.test.d.ts +2 -0
  71. package/build/__tests__/unit/emulatorGrpc.test.d.ts.map +1 -0
  72. package/build/__tests__/unit/emulatorGrpc.test.js +33 -0
  73. package/build/__tests__/unit/emulatorGrpc.test.js.map +1 -0
  74. package/build/__tests__/unit/epochRender.test.js +0 -3
  75. package/build/__tests__/unit/epochRender.test.js.map +1 -1
  76. package/build/__tests__/unit/errorCategorization.test.js +0 -18
  77. package/build/__tests__/unit/errorCategorization.test.js.map +1 -1
  78. package/build/__tests__/unit/exec.test.js +0 -1
  79. package/build/__tests__/unit/exec.test.js.map +1 -1
  80. package/build/__tests__/unit/executor.test.js +0 -15
  81. package/build/__tests__/unit/executor.test.js.map +1 -1
  82. package/build/__tests__/unit/findElementTreeReuse.test.js +0 -12
  83. package/build/__tests__/unit/findElementTreeReuse.test.js.map +1 -1
  84. package/build/__tests__/unit/fingerprint.test.js +0 -4
  85. package/build/__tests__/unit/fingerprint.test.js.map +1 -1
  86. package/build/__tests__/unit/focusedInputTools.test.js +0 -4
  87. package/build/__tests__/unit/focusedInputTools.test.js.map +1 -1
  88. package/build/__tests__/unit/getLogsEmptyContract.test.js +0 -30
  89. package/build/__tests__/unit/getLogsEmptyContract.test.js.map +1 -1
  90. package/build/__tests__/unit/getLogsNativeSource.test.js +0 -22
  91. package/build/__tests__/unit/getLogsNativeSource.test.js.map +1 -1
  92. package/build/__tests__/unit/graphqlOperation.test.d.ts +2 -0
  93. package/build/__tests__/unit/graphqlOperation.test.d.ts.map +1 -0
  94. package/build/__tests__/unit/graphqlOperation.test.js +107 -0
  95. package/build/__tests__/unit/graphqlOperation.test.js.map +1 -0
  96. package/build/__tests__/unit/inputTarget.test.js +0 -16
  97. package/build/__tests__/unit/inputTarget.test.js.map +1 -1
  98. package/build/__tests__/unit/inputTextTool.test.js +0 -3
  99. package/build/__tests__/unit/inputTextTool.test.js.map +1 -1
  100. package/build/__tests__/unit/jsLogEvents.test.js +0 -3
  101. package/build/__tests__/unit/jsLogEvents.test.js.map +1 -1
  102. package/build/__tests__/unit/keyboardMetrics.test.js +0 -2
  103. package/build/__tests__/unit/keyboardMetrics.test.js.map +1 -1
  104. package/build/__tests__/unit/keyboardRaise.test.js +0 -2
  105. package/build/__tests__/unit/keyboardRaise.test.js.map +1 -1
  106. package/build/__tests__/unit/licenseGrace.test.js +1 -4
  107. package/build/__tests__/unit/licenseGrace.test.js.map +1 -1
  108. package/build/__tests__/unit/logEventFormat.test.js +0 -27
  109. package/build/__tests__/unit/logEventFormat.test.js.map +1 -1
  110. package/build/__tests__/unit/logEvents.test.js +1 -5
  111. package/build/__tests__/unit/logEvents.test.js.map +1 -1
  112. package/build/__tests__/unit/logGrouping.test.js +0 -2
  113. package/build/__tests__/unit/logGrouping.test.js.map +1 -1
  114. package/build/__tests__/unit/logOwnership.test.js +0 -11
  115. package/build/__tests__/unit/logOwnership.test.js.map +1 -1
  116. package/build/__tests__/unit/logRelevance.test.js +0 -6
  117. package/build/__tests__/unit/logRelevance.test.js.map +1 -1
  118. package/build/__tests__/unit/logSourceAndroid.test.js +0 -4
  119. package/build/__tests__/unit/logSourceAndroid.test.js.map +1 -1
  120. package/build/__tests__/unit/logSourceIos.test.js +0 -5
  121. package/build/__tests__/unit/logSourceIos.test.js.map +1 -1
  122. package/build/__tests__/unit/logs.test.js +0 -1
  123. package/build/__tests__/unit/logs.test.js.map +1 -1
  124. package/build/__tests__/unit/measureComponentTools.test.js +0 -1
  125. package/build/__tests__/unit/measureComponentTools.test.js.map +1 -1
  126. package/build/__tests__/unit/metro.test.js +0 -2
  127. package/build/__tests__/unit/metro.test.js.map +1 -1
  128. package/build/__tests__/unit/nativeInputValue.test.js +0 -4
  129. package/build/__tests__/unit/nativeInputValue.test.js.map +1 -1
  130. package/build/__tests__/unit/nativeLogs.test.js +1 -23
  131. package/build/__tests__/unit/nativeLogs.test.js.map +1 -1
  132. package/build/__tests__/unit/navigateVerify.test.js +0 -6
  133. package/build/__tests__/unit/navigateVerify.test.js.map +1 -1
  134. package/build/__tests__/unit/navigation.test.js +0 -5
  135. package/build/__tests__/unit/navigation.test.js.map +1 -1
  136. package/build/__tests__/unit/networkInterceptor.test.js +0 -2
  137. package/build/__tests__/unit/networkInterceptor.test.js.map +1 -1
  138. package/build/__tests__/unit/overlayGuard.test.d.ts +2 -0
  139. package/build/__tests__/unit/overlayGuard.test.d.ts.map +1 -0
  140. package/build/__tests__/unit/overlayGuard.test.js +123 -0
  141. package/build/__tests__/unit/overlayGuard.test.js.map +1 -0
  142. package/build/__tests__/unit/pendingExecutions.test.js +0 -6
  143. package/build/__tests__/unit/pendingExecutions.test.js.map +1 -1
  144. package/build/__tests__/unit/pinchGeometry.test.d.ts +2 -0
  145. package/build/__tests__/unit/pinchGeometry.test.d.ts.map +1 -0
  146. package/build/__tests__/unit/pinchGeometry.test.js +139 -0
  147. package/build/__tests__/unit/pinchGeometry.test.js.map +1 -0
  148. package/build/__tests__/unit/pinchTool.test.d.ts +2 -0
  149. package/build/__tests__/unit/pinchTool.test.d.ts.map +1 -0
  150. package/build/__tests__/unit/pinchTool.test.js +39 -0
  151. package/build/__tests__/unit/pinchTool.test.js.map +1 -0
  152. package/build/__tests__/unit/probe.test.js +0 -1
  153. package/build/__tests__/unit/probe.test.js.map +1 -1
  154. package/build/__tests__/unit/projectMemory.test.js +6 -7
  155. package/build/__tests__/unit/projectMemory.test.js.map +1 -1
  156. package/build/__tests__/unit/projectStore.test.js +2 -2
  157. package/build/__tests__/unit/projectStore.test.js.map +1 -1
  158. package/build/__tests__/unit/reloadAppAutoConnect.test.js +0 -9
  159. package/build/__tests__/unit/reloadAppAutoConnect.test.js.map +1 -1
  160. package/build/__tests__/unit/rnGlobalsBootstrap.test.js +3 -3
  161. package/build/__tests__/unit/rnGlobalsBootstrap.test.js.map +1 -1
  162. package/build/__tests__/unit/routeHistory.test.d.ts +2 -0
  163. package/build/__tests__/unit/routeHistory.test.d.ts.map +1 -0
  164. package/build/__tests__/unit/routeHistory.test.js +136 -0
  165. package/build/__tests__/unit/routeHistory.test.js.map +1 -0
  166. package/build/__tests__/unit/screenSpace.test.js +30 -13
  167. package/build/__tests__/unit/screenSpace.test.js.map +1 -1
  168. package/build/__tests__/unit/screenState.test.js +3 -6
  169. package/build/__tests__/unit/screenState.test.js.map +1 -1
  170. package/build/__tests__/unit/screenStateInputValue.test.js +0 -7
  171. package/build/__tests__/unit/screenStateInputValue.test.js.map +1 -1
  172. package/build/__tests__/unit/screenStateKeyboard.test.js +0 -1
  173. package/build/__tests__/unit/screenStateKeyboard.test.js.map +1 -1
  174. package/build/__tests__/unit/screenshot-diff.test.js +0 -6
  175. package/build/__tests__/unit/screenshot-diff.test.js.map +1 -1
  176. package/build/__tests__/unit/sdkMirrorPoller.test.js +0 -8
  177. package/build/__tests__/unit/sdkMirrorPoller.test.js.map +1 -1
  178. package/build/__tests__/unit/settleAndDiff.test.js +0 -11
  179. package/build/__tests__/unit/settleAndDiff.test.js.map +1 -1
  180. package/build/__tests__/unit/signedVerdict.test.js +0 -5
  181. package/build/__tests__/unit/signedVerdict.test.js.map +1 -1
  182. package/build/__tests__/unit/swipeDirection.test.js +6 -9
  183. package/build/__tests__/unit/swipeDirection.test.js.map +1 -1
  184. package/build/__tests__/unit/symbolicate.test.js +0 -1
  185. package/build/__tests__/unit/symbolicate.test.js.map +1 -1
  186. package/build/__tests__/unit/tap.test.js +2 -40
  187. package/build/__tests__/unit/tap.test.js.map +1 -1
  188. package/build/__tests__/unit/textEntry.test.js +0 -27
  189. package/build/__tests__/unit/textEntry.test.js.map +1 -1
  190. package/build/__tests__/unit/toolDescriptions.test.js +0 -40
  191. package/build/__tests__/unit/toolDescriptions.test.js.map +1 -1
  192. package/build/__tests__/unit/toolsJson.test.js +0 -10
  193. package/build/__tests__/unit/toolsJson.test.js.map +1 -1
  194. package/build/__tests__/unit/transportClassify.test.js +0 -20
  195. package/build/__tests__/unit/transportClassify.test.js.map +1 -1
  196. package/build/__tests__/unit/truncate.test.js +0 -5
  197. package/build/__tests__/unit/truncate.test.js.map +1 -1
  198. package/build/__tests__/unit/usageCache.test.js +0 -3
  199. package/build/__tests__/unit/usageCache.test.js.map +1 -1
  200. package/build/__tests__/unit/usageGate.test.js +1 -1
  201. package/build/__tests__/unit/usageGate.test.js.map +1 -1
  202. package/build/__tests__/unit/visibility.test.js +0 -8
  203. package/build/__tests__/unit/visibility.test.js.map +1 -1
  204. package/build/__tests__/unit/waitForMeasurements.test.js +2 -7
  205. package/build/__tests__/unit/waitForMeasurements.test.js.map +1 -1
  206. package/build/bin.js +0 -18
  207. package/build/bin.js.map +1 -1
  208. package/build/core/android.d.ts +0 -120
  209. package/build/core/android.d.ts.map +1 -1
  210. package/build/core/android.js +4 -259
  211. package/build/core/android.js.map +1 -1
  212. package/build/core/androidPinch.d.ts +21 -0
  213. package/build/core/androidPinch.d.ts.map +1 -0
  214. package/build/core/androidPinch.js +72 -0
  215. package/build/core/androidPinch.js.map +1 -0
  216. package/build/core/androidSystemBars.d.ts +7 -0
  217. package/build/core/androidSystemBars.d.ts.map +1 -0
  218. package/build/core/androidSystemBars.js +21 -0
  219. package/build/core/androidSystemBars.js.map +1 -0
  220. package/build/core/appContext.d.ts +0 -50
  221. package/build/core/appContext.d.ts.map +1 -1
  222. package/build/core/appContext.js +0 -50
  223. package/build/core/appContext.js.map +1 -1
  224. package/build/core/appDetection.d.ts +0 -16
  225. package/build/core/appDetection.d.ts.map +1 -1
  226. package/build/core/appDetection.js +0 -36
  227. package/build/core/appDetection.js.map +1 -1
  228. package/build/core/appRequest.d.ts +0 -12
  229. package/build/core/appRequest.d.ts.map +1 -1
  230. package/build/core/appRequest.js +0 -15
  231. package/build/core/appRequest.js.map +1 -1
  232. package/build/core/bufferConfig.d.ts +0 -2
  233. package/build/core/bufferConfig.d.ts.map +1 -1
  234. package/build/core/bufferConfig.js +0 -2
  235. package/build/core/bufferConfig.js.map +1 -1
  236. package/build/core/bundle.js +0 -40
  237. package/build/core/bundle.js.map +1 -1
  238. package/build/core/componentSearch.d.ts +0 -19
  239. package/build/core/componentSearch.d.ts.map +1 -1
  240. package/build/core/componentSearch.js +1 -22
  241. package/build/core/componentSearch.js.map +1 -1
  242. package/build/core/componentSource.d.ts +0 -21
  243. package/build/core/componentSource.d.ts.map +1 -1
  244. package/build/core/componentSource.js +0 -27
  245. package/build/core/componentSource.js.map +1 -1
  246. package/build/core/componentTree.js +0 -12
  247. package/build/core/componentTree.js.map +1 -1
  248. package/build/core/config.d.ts +0 -8
  249. package/build/core/config.d.ts.map +1 -1
  250. package/build/core/config.js +0 -10
  251. package/build/core/config.js.map +1 -1
  252. package/build/core/connection.d.ts +0 -76
  253. package/build/core/connection.d.ts.map +1 -1
  254. package/build/core/connection.js +15 -340
  255. package/build/core/connection.js.map +1 -1
  256. package/build/core/connectionState.d.ts +0 -78
  257. package/build/core/connectionState.d.ts.map +1 -1
  258. package/build/core/connectionState.js +4 -92
  259. package/build/core/connectionState.js.map +1 -1
  260. package/build/core/debugGlobals.js +0 -68
  261. package/build/core/debugGlobals.js.map +1 -1
  262. package/build/core/deviceDiscovery.d.ts +0 -5
  263. package/build/core/deviceDiscovery.d.ts.map +1 -1
  264. package/build/core/deviceDiscovery.js +0 -12
  265. package/build/core/deviceDiscovery.js.map +1 -1
  266. package/build/core/deviceResolver.d.ts +0 -10
  267. package/build/core/deviceResolver.d.ts.map +1 -1
  268. package/build/core/deviceResolver.js +0 -54
  269. package/build/core/deviceResolver.js.map +1 -1
  270. package/build/core/emulatorBridge.d.ts +17 -0
  271. package/build/core/emulatorBridge.d.ts.map +1 -0
  272. package/build/core/emulatorBridge.js +78 -0
  273. package/build/core/emulatorBridge.js.map +1 -0
  274. package/build/core/emulatorGrpc.d.ts +14 -0
  275. package/build/core/emulatorGrpc.d.ts.map +1 -0
  276. package/build/core/emulatorGrpc.js +93 -0
  277. package/build/core/emulatorGrpc.js.map +1 -0
  278. package/build/core/epochRender.d.ts +0 -12
  279. package/build/core/epochRender.d.ts.map +1 -1
  280. package/build/core/epochRender.js +0 -12
  281. package/build/core/epochRender.js.map +1 -1
  282. package/build/core/errorScreenParser.d.ts +0 -21
  283. package/build/core/errorScreenParser.d.ts.map +1 -1
  284. package/build/core/errorScreenParser.js +0 -50
  285. package/build/core/errorScreenParser.js.map +1 -1
  286. package/build/core/errors.d.ts +0 -15
  287. package/build/core/errors.d.ts.map +1 -1
  288. package/build/core/errors.js +0 -15
  289. package/build/core/errors.js.map +1 -1
  290. package/build/core/escapeNonAscii.d.ts +0 -9
  291. package/build/core/escapeNonAscii.d.ts.map +1 -1
  292. package/build/core/escapeNonAscii.js +1 -43
  293. package/build/core/escapeNonAscii.js.map +1 -1
  294. package/build/core/exec.d.ts +0 -12
  295. package/build/core/exec.d.ts.map +1 -1
  296. package/build/core/exec.js +2 -14
  297. package/build/core/exec.js.map +1 -1
  298. package/build/core/executor.js +0 -3
  299. package/build/core/executor.js.map +1 -1
  300. package/build/core/fastRefreshRecorder.js +0 -4
  301. package/build/core/fastRefreshRecorder.js.map +1 -1
  302. package/build/core/fastRefreshTools.js +0 -3
  303. package/build/core/fastRefreshTools.js.map +1 -1
  304. package/build/core/feedback.js +0 -4
  305. package/build/core/feedback.js.map +1 -1
  306. package/build/core/graphqlOperation.d.ts +13 -0
  307. package/build/core/graphqlOperation.d.ts.map +1 -0
  308. package/build/core/graphqlOperation.js +80 -0
  309. package/build/core/graphqlOperation.js.map +1 -0
  310. package/build/core/guides.d.ts +0 -10
  311. package/build/core/guides.d.ts.map +1 -1
  312. package/build/core/guides.js +18 -12
  313. package/build/core/guides.js.map +1 -1
  314. package/build/core/iconSemantics.d.ts +0 -15
  315. package/build/core/iconSemantics.d.ts.map +1 -1
  316. package/build/core/iconSemantics.js +0 -31
  317. package/build/core/iconSemantics.js.map +1 -1
  318. package/build/core/index.d.ts +2 -0
  319. package/build/core/index.d.ts.map +1 -1
  320. package/build/core/index.js +5 -47
  321. package/build/core/index.js.map +1 -1
  322. package/build/core/injected/visibility.d.ts +0 -30
  323. package/build/core/injected/visibility.d.ts.map +1 -1
  324. package/build/core/injected/visibility.js +0 -33
  325. package/build/core/injected/visibility.js.map +1 -1
  326. package/build/core/injectedFilters.d.ts +0 -28
  327. package/build/core/injectedFilters.d.ts.map +1 -1
  328. package/build/core/injectedFilters.js +0 -28
  329. package/build/core/injectedFilters.js.map +1 -1
  330. package/build/core/inputTarget.d.ts +1 -34
  331. package/build/core/inputTarget.d.ts.map +1 -1
  332. package/build/core/inputTarget.js +0 -26
  333. package/build/core/inputTarget.js.map +1 -1
  334. package/build/core/inputTargetTools.d.ts +0 -7
  335. package/build/core/inputTargetTools.d.ts.map +1 -1
  336. package/build/core/inputTargetTools.js +0 -7
  337. package/build/core/inputTargetTools.js.map +1 -1
  338. package/build/core/inspector.d.ts +0 -33
  339. package/build/core/inspector.d.ts.map +1 -1
  340. package/build/core/inspector.js +27 -40
  341. package/build/core/inspector.js.map +1 -1
  342. package/build/core/ios.d.ts +11 -122
  343. package/build/core/ios.d.ts.map +1 -1
  344. package/build/core/ios.js +32 -299
  345. package/build/core/ios.js.map +1 -1
  346. package/build/core/jsExecute.d.ts +0 -100
  347. package/build/core/jsExecute.d.ts.map +1 -1
  348. package/build/core/jsExecute.js +0 -261
  349. package/build/core/jsExecute.js.map +1 -1
  350. package/build/core/jsLogEvents.d.ts +0 -8
  351. package/build/core/jsLogEvents.d.ts.map +1 -1
  352. package/build/core/jsLogEvents.js +0 -8
  353. package/build/core/jsLogEvents.js.map +1 -1
  354. package/build/core/keyboardMetrics.js +0 -8
  355. package/build/core/keyboardMetrics.js.map +1 -1
  356. package/build/core/keyboardRaise.d.ts +0 -8
  357. package/build/core/keyboardRaise.d.ts.map +1 -1
  358. package/build/core/keyboardRaise.js +0 -23
  359. package/build/core/keyboardRaise.js.map +1 -1
  360. package/build/core/license.d.ts +0 -4
  361. package/build/core/license.d.ts.map +1 -1
  362. package/build/core/license.js +2 -55
  363. package/build/core/license.js.map +1 -1
  364. package/build/core/logDiagnosis.d.ts +0 -34
  365. package/build/core/logDiagnosis.d.ts.map +1 -1
  366. package/build/core/logDiagnosis.js +0 -15
  367. package/build/core/logDiagnosis.js.map +1 -1
  368. package/build/core/logEventFormat.d.ts +0 -1
  369. package/build/core/logEventFormat.d.ts.map +1 -1
  370. package/build/core/logEventFormat.js +0 -30
  371. package/build/core/logEventFormat.js.map +1 -1
  372. package/build/core/logEvents.d.ts +0 -54
  373. package/build/core/logEvents.d.ts.map +1 -1
  374. package/build/core/logEvents.js +0 -37
  375. package/build/core/logEvents.js.map +1 -1
  376. package/build/core/logGrouping.d.ts +0 -9
  377. package/build/core/logGrouping.d.ts.map +1 -1
  378. package/build/core/logGrouping.js +0 -17
  379. package/build/core/logGrouping.js.map +1 -1
  380. package/build/core/logOwnership.d.ts +0 -17
  381. package/build/core/logOwnership.d.ts.map +1 -1
  382. package/build/core/logOwnership.js +0 -34
  383. package/build/core/logOwnership.js.map +1 -1
  384. package/build/core/logRelevance.d.ts +0 -8
  385. package/build/core/logRelevance.d.ts.map +1 -1
  386. package/build/core/logRelevance.js +0 -15
  387. package/build/core/logRelevance.js.map +1 -1
  388. package/build/core/logSourceAndroid.d.ts +0 -8
  389. package/build/core/logSourceAndroid.d.ts.map +1 -1
  390. package/build/core/logSourceAndroid.js +0 -11
  391. package/build/core/logSourceAndroid.js.map +1 -1
  392. package/build/core/logSourceIos.d.ts +0 -8
  393. package/build/core/logSourceIos.d.ts.map +1 -1
  394. package/build/core/logSourceIos.js +1 -24
  395. package/build/core/logSourceIos.js.map +1 -1
  396. package/build/core/logbox.d.ts +0 -30
  397. package/build/core/logbox.d.ts.map +1 -1
  398. package/build/core/logbox.js +0 -43
  399. package/build/core/logbox.js.map +1 -1
  400. package/build/core/logs.d.ts +0 -6
  401. package/build/core/logs.d.ts.map +1 -1
  402. package/build/core/logs.js +0 -19
  403. package/build/core/logs.js.map +1 -1
  404. package/build/core/metro.d.ts +0 -14
  405. package/build/core/metro.d.ts.map +1 -1
  406. package/build/core/metro.js +1 -32
  407. package/build/core/metro.js.map +1 -1
  408. package/build/core/moduleRegistry.d.ts +0 -17
  409. package/build/core/moduleRegistry.d.ts.map +1 -1
  410. package/build/core/moduleRegistry.js +0 -17
  411. package/build/core/moduleRegistry.js.map +1 -1
  412. package/build/core/nativeInputValue.d.ts +0 -29
  413. package/build/core/nativeInputValue.d.ts.map +1 -1
  414. package/build/core/nativeInputValue.js +0 -18
  415. package/build/core/nativeInputValue.js.map +1 -1
  416. package/build/core/nativeLogs.d.ts +0 -47
  417. package/build/core/nativeLogs.d.ts.map +1 -1
  418. package/build/core/nativeLogs.js +0 -82
  419. package/build/core/nativeLogs.js.map +1 -1
  420. package/build/core/nativeOnlyHints.js +0 -4
  421. package/build/core/nativeOnlyHints.js.map +1 -1
  422. package/build/core/navigate.d.ts +0 -15
  423. package/build/core/navigate.d.ts.map +1 -1
  424. package/build/core/navigate.js +0 -22
  425. package/build/core/navigate.js.map +1 -1
  426. package/build/core/navigation.d.ts +0 -60
  427. package/build/core/navigation.d.ts.map +1 -1
  428. package/build/core/navigation.js +0 -60
  429. package/build/core/navigation.js.map +1 -1
  430. package/build/core/network.d.ts +0 -5
  431. package/build/core/network.d.ts.map +1 -1
  432. package/build/core/network.js +10 -31
  433. package/build/core/network.js.map +1 -1
  434. package/build/core/networkInterceptor.d.ts +0 -19
  435. package/build/core/networkInterceptor.d.ts.map +1 -1
  436. package/build/core/networkInterceptor.js +3 -27
  437. package/build/core/networkInterceptor.js.map +1 -1
  438. package/build/core/ocr.d.ts +0 -31
  439. package/build/core/ocr.d.ts.map +1 -1
  440. package/build/core/ocr.js +1 -71
  441. package/build/core/ocr.js.map +1 -1
  442. package/build/core/paths.js +0 -1
  443. package/build/core/paths.js.map +1 -1
  444. package/build/core/pinchGeometry.d.ts +28 -0
  445. package/build/core/pinchGeometry.d.ts.map +1 -0
  446. package/build/core/pinchGeometry.js +97 -0
  447. package/build/core/pinchGeometry.js.map +1 -0
  448. package/build/core/pinchThresholds.d.ts +14 -0
  449. package/build/core/pinchThresholds.d.ts.map +1 -0
  450. package/build/core/pinchThresholds.js +9 -0
  451. package/build/core/pinchThresholds.js.map +1 -0
  452. package/build/core/posthog.js +0 -7
  453. package/build/core/posthog.js.map +1 -1
  454. package/build/core/pressables.d.ts +0 -25
  455. package/build/core/pressables.d.ts.map +1 -1
  456. package/build/core/pressables.js +0 -37
  457. package/build/core/pressables.js.map +1 -1
  458. package/build/core/probe.d.ts +0 -9
  459. package/build/core/probe.d.ts.map +1 -1
  460. package/build/core/probe.js +0 -9
  461. package/build/core/probe.js.map +1 -1
  462. package/build/core/projectMemory.d.ts +0 -2
  463. package/build/core/projectMemory.d.ts.map +1 -1
  464. package/build/core/projectMemory.js +2 -7
  465. package/build/core/projectMemory.js.map +1 -1
  466. package/build/core/projectStore.d.ts +0 -18
  467. package/build/core/projectStore.d.ts.map +1 -1
  468. package/build/core/projectStore.js +0 -19
  469. package/build/core/projectStore.js.map +1 -1
  470. package/build/core/promiseHandles.d.ts +0 -13
  471. package/build/core/promiseHandles.d.ts.map +1 -1
  472. package/build/core/promiseHandles.js +0 -25
  473. package/build/core/promiseHandles.js.map +1 -1
  474. package/build/core/register.js +0 -44
  475. package/build/core/register.js.map +1 -1
  476. package/build/core/rnGlobalsBootstrap.d.ts +0 -13
  477. package/build/core/rnGlobalsBootstrap.d.ts.map +1 -1
  478. package/build/core/rnGlobalsBootstrap.js +0 -22
  479. package/build/core/rnGlobalsBootstrap.js.map +1 -1
  480. package/build/core/routeHistory.d.ts +24 -0
  481. package/build/core/routeHistory.d.ts.map +1 -0
  482. package/build/core/routeHistory.js +186 -0
  483. package/build/core/routeHistory.js.map +1 -0
  484. package/build/core/screenLayout.d.ts +0 -11
  485. package/build/core/screenLayout.d.ts.map +1 -1
  486. package/build/core/screenLayout.js +24 -61
  487. package/build/core/screenLayout.js.map +1 -1
  488. package/build/core/screenSpace.d.ts +32 -44
  489. package/build/core/screenSpace.d.ts.map +1 -1
  490. package/build/core/screenSpace.js +80 -46
  491. package/build/core/screenSpace.js.map +1 -1
  492. package/build/core/screenSpaceDevice.d.ts +0 -8
  493. package/build/core/screenSpaceDevice.d.ts.map +1 -1
  494. package/build/core/screenSpaceDevice.js +31 -14
  495. package/build/core/screenSpaceDevice.js.map +1 -1
  496. package/build/core/screenState.d.ts +2 -74
  497. package/build/core/screenState.d.ts.map +1 -1
  498. package/build/core/screenState.js +204 -145
  499. package/build/core/screenState.js.map +1 -1
  500. package/build/core/sdkBridge.js +0 -8
  501. package/build/core/sdkBridge.js.map +1 -1
  502. package/build/core/sdkMirrorPoller.d.ts +0 -18
  503. package/build/core/sdkMirrorPoller.d.ts.map +1 -1
  504. package/build/core/sdkMirrorPoller.js +0 -47
  505. package/build/core/sdkMirrorPoller.js.map +1 -1
  506. package/build/core/selectionBuffer.d.ts +0 -6
  507. package/build/core/selectionBuffer.d.ts.map +1 -1
  508. package/build/core/selectionBuffer.js +0 -5
  509. package/build/core/selectionBuffer.js.map +1 -1
  510. package/build/core/signedVerdict.js +0 -6
  511. package/build/core/signedVerdict.js.map +1 -1
  512. package/build/core/state.d.ts +0 -31
  513. package/build/core/state.d.ts.map +1 -1
  514. package/build/core/state.js +0 -57
  515. package/build/core/state.js.map +1 -1
  516. package/build/core/symbolicate.js +0 -11
  517. package/build/core/symbolicate.js.map +1 -1
  518. package/build/core/telemetry.d.ts +0 -47
  519. package/build/core/telemetry.d.ts.map +1 -1
  520. package/build/core/telemetry.js +1 -173
  521. package/build/core/telemetry.js.map +1 -1
  522. package/build/core/textEntry.d.ts +0 -34
  523. package/build/core/textEntry.d.ts.map +1 -1
  524. package/build/core/textEntry.js +0 -73
  525. package/build/core/textEntry.js.map +1 -1
  526. package/build/core/toolHelpers.d.ts +0 -12
  527. package/build/core/toolHelpers.d.ts.map +1 -1
  528. package/build/core/toolHelpers.js +2 -47
  529. package/build/core/toolHelpers.js.map +1 -1
  530. package/build/core/truncate.d.ts +0 -17
  531. package/build/core/truncate.d.ts.map +1 -1
  532. package/build/core/truncate.js +0 -32
  533. package/build/core/truncate.js.map +1 -1
  534. package/build/core/types.d.ts +0 -6
  535. package/build/core/types.d.ts.map +1 -1
  536. package/build/core/usageCache.js +0 -12
  537. package/build/core/usageCache.js.map +1 -1
  538. package/build/index.js +0 -18
  539. package/build/index.js.map +1 -1
  540. package/build/pro/coordinateMiss.d.ts +0 -30
  541. package/build/pro/coordinateMiss.d.ts.map +1 -1
  542. package/build/pro/coordinateMiss.js +0 -17
  543. package/build/pro/coordinateMiss.js.map +1 -1
  544. package/build/pro/overlayGuard.d.ts +27 -0
  545. package/build/pro/overlayGuard.d.ts.map +1 -0
  546. package/build/pro/overlayGuard.js +103 -0
  547. package/build/pro/overlayGuard.js.map +1 -0
  548. package/build/pro/screenshot-diff.js +4 -6
  549. package/build/pro/screenshot-diff.js.map +1 -1
  550. package/build/pro/tap.d.ts +0 -55
  551. package/build/pro/tap.d.ts.map +1 -1
  552. package/build/pro/tap.js +72 -316
  553. package/build/pro/tap.js.map +1 -1
  554. package/build/pro/usageGate.js +0 -9
  555. package/build/pro/usageGate.js.map +1 -1
  556. package/build/pro/usageNotifications.js +1 -13
  557. package/build/pro/usageNotifications.js.map +1 -1
  558. package/build/pro/verifyAction.d.ts +0 -13
  559. package/build/pro/verifyAction.d.ts.map +1 -1
  560. package/build/pro/verifyAction.js +0 -45
  561. package/build/pro/verifyAction.js.map +1 -1
  562. package/build/tools/_deviceArg.d.ts +0 -35
  563. package/build/tools/_deviceArg.d.ts.map +1 -1
  564. package/build/tools/_deviceArg.js +0 -35
  565. package/build/tools/_deviceArg.js.map +1 -1
  566. package/build/tools/accountTools.js +2 -2
  567. package/build/tools/accountTools.js.map +1 -1
  568. package/build/tools/bundleTools.js +0 -16
  569. package/build/tools/bundleTools.js.map +1 -1
  570. package/build/tools/componentTools.d.ts.map +1 -1
  571. package/build/tools/componentTools.js +47 -53
  572. package/build/tools/componentTools.js.map +1 -1
  573. package/build/tools/connectionTools.js +1 -59
  574. package/build/tools/connectionTools.js.map +1 -1
  575. package/build/tools/deviceTools.js +0 -11
  576. package/build/tools/deviceTools.js.map +1 -1
  577. package/build/tools/executionTools.js +1 -18
  578. package/build/tools/executionTools.js.map +1 -1
  579. package/build/tools/interactionTools.d.ts +0 -10
  580. package/build/tools/interactionTools.d.ts.map +1 -1
  581. package/build/tools/interactionTools.js +190 -59
  582. package/build/tools/interactionTools.js.map +1 -1
  583. package/build/tools/logTools.d.ts +0 -13
  584. package/build/tools/logTools.d.ts.map +1 -1
  585. package/build/tools/logTools.js +2 -126
  586. package/build/tools/logTools.js.map +1 -1
  587. package/build/tools/metaTools.js +0 -10
  588. package/build/tools/metaTools.js.map +1 -1
  589. package/build/tools/networkTools.js +4 -43
  590. package/build/tools/networkTools.js.map +1 -1
  591. package/build/tools/requestTools.js +0 -5
  592. package/build/tools/requestTools.js.map +1 -1
  593. package/build/tools/screenshotTools.js +5 -111
  594. package/build/tools/screenshotTools.js.map +1 -1
  595. package/package.json +2 -2
  596. package/tools.json +16 -1
@@ -2,9 +2,6 @@ import { executeInApp, delay } from "./jsExecute.js";
2
2
  import { iconSemanticHint } from "./iconSemantics.js";
3
3
  import { VISIBILITY_HELPERS_JS, detectNativeSheet, NATIVE_SHEET_MARKER_RE_SRC } from "./injected/visibility.js";
4
4
  import { RN_PRIMITIVES_SRC, GENERIC_COMPONENT_SRC } from "./injectedFilters.js";
5
- // ============================================================================
6
- // Pure helpers (exported for unit tests)
7
- // ============================================================================
8
5
  export function markPressablesCoveredByOverlay(pressables, overlayBounds) {
9
6
  for (const p of pressables) {
10
7
  const b = p.bounds;
@@ -17,18 +14,7 @@ export function markPressablesCoveredByOverlay(pressables, overlayBounds) {
17
14
  }
18
15
  return pressables;
19
16
  }
20
- /** A count badge such as "1" or "99+" — the only "label" an icon button like a cart carries. */
21
17
  const COUNT_BADGE_LABEL = /^\d{1,3}\+?$/;
22
- /**
23
- * Replace component-name fallback labels with semantic icon labels when the
24
- * pressable's icon child name carries recognizable semantics:
25
- * { label: "[FloatingHeader]", icon: "SvgChevronBackward" }
26
- * → label "[SvgChevronBackward — possibly back button]"
27
- * An icon button whose only text is a count badge (cart with "1") keeps that
28
- * count as nearby context while the label is upgraded to the icon's meaning:
29
- * { label: "1", icon: "SvgCartNew" } → label "[SvgCartNew — possibly cart button]", nearbyText "1"
30
- * Labels from text/a11y are never touched (icon is null for those).
31
- */
32
18
  export function applyIconHintToLabel(p) {
33
19
  if (!p.icon)
34
20
  return p;
@@ -45,20 +31,17 @@ export function applyIconHintToLabel(p) {
45
31
  return p;
46
32
  }
47
33
  const identityCoords = (item) => ({ center: item.center, frame: item.bounds });
48
- /** Stand-in when no keyboard state was read: nothing is blocked. */
49
34
  const NO_KEYBOARD = { visible: false, height: null, screenY: null, width: null };
50
35
  const TEXT_DISPLAY_MAX = 80;
51
36
  const IMAGE_SRC_DISPLAY_MAX = 60;
52
37
  function truncate(s, max) {
53
38
  return s.length > max ? s.slice(0, max) + "…" : s;
54
39
  }
55
- /** One merged-list line for a static text node — coordinates match pressable lines. */
56
40
  export function formatTextEntry(t, convert = identityCoords, opts = {}) {
57
41
  const { center, frame } = convert(t);
58
42
  const body = opts.fullText ? t.text : truncate(t.text, TEXT_DISPLAY_MAX);
59
43
  return ` (${center.x}, ${center.y}) 📝 "${body}" frame:(${frame.x},${frame.y} ${frame.width}x${frame.height})`;
60
44
  }
61
- /** One merged-list line for an image node — coordinates match pressable lines. */
62
45
  export function formatImageEntry(img, convert = identityCoords) {
63
46
  const { center, frame } = convert(img);
64
47
  const src = img.src ? ` src="${truncate(img.src, IMAGE_SRC_DISPLAY_MAX)}"` : "";
@@ -67,44 +50,17 @@ export function formatImageEntry(img, convert = identityCoords) {
67
50
  }
68
51
  const TEXT_CAP = 60;
69
52
  const IMAGE_CAP = 40;
70
- /**
71
- * Render a ScreenState as the orientation summary used by get_screen_state and the
72
- * screenshot tools. By default it merges pressables, static text (📝), and images
73
- * (🖼) into one spatially-ordered list per reachability group — enough to read and
74
- * navigate the screen without a screenshot:
75
- * 📍 Detail [Detail]
76
- * 🎯 Pressables:
77
- * (210, 175) 🖼 Image 420x350 src="…"
78
- * (146, 394) 📝 "Valya product" frame:(20,382 251x24)
79
- * (210, 838) <Button /> "In cart" frame:(20,810 380x56)
80
- * pressablesOnly restores the lean pressable-only snapshot; fullText disables the
81
- * 80-char text truncation.
82
- */
83
- /**
84
- * One line describing the keyboard, or "" when it is down and known to be.
85
- *
86
- * The point is layout validation: a raised keyboard shrinks the usable area,
87
- * and that is exactly when bottom-anchored UI misbehaves. Reporting the height
88
- * and the remaining content area makes that inspectable without a screenshot.
89
- */
90
- export function formatKeyboardLine(k) {
53
+ export function formatKeyboardLine(k, pixelScale = 1) {
91
54
  if (k.error)
92
55
  return `⌨️ Keyboard: unknown (${k.error})`;
93
56
  if (!k.visible || k.height == null || k.screenY == null)
94
57
  return "";
95
- // Android reports fractional dp (288.3809509277344); whole points are what
96
- // a reader can act on, and the sub-pixel tail only obscures the number.
97
- const r = (n) => Math.round(n);
58
+ const s = pixelScale > 0 ? pixelScale : 1;
59
+ const r = (n) => Math.round(n * s);
60
+ const unit = s === 1 ? "pt" : "px";
98
61
  const width = k.width != null ? `${r(k.width)}x` : "";
99
- return `⌨️ Keyboard: visible, ${r(k.height)}pt — content area above it ${width}${r(k.screenY)}pt`;
62
+ return `⌨️ Keyboard: visible, ${r(k.height)}${unit} — content area above it ${width}${r(k.screenY)}${unit}`;
100
63
  }
101
- /**
102
- * Splits elements the keyboard covers from those still reachable.
103
- *
104
- * Mirrors the existing overlay handling rather than inventing a second notion
105
- * of "blocked": an element under the keyboard cannot be tapped, for the same
106
- * reason and with the same consequence as one under a sheet.
107
- */
108
64
  export function partitionByKeyboard(items, k) {
109
65
  if (!k.visible || k.screenY == null)
110
66
  return { reachable: items, blocked: [] };
@@ -115,18 +71,11 @@ export function partitionByKeyboard(items, k) {
115
71
  }
116
72
  return { reachable, blocked };
117
73
  }
118
- /**
119
- * Renders an input's state so the value is unmistakably the value and the
120
- * placeholder is unmistakably a placeholder. Returns "" for non-inputs.
121
- */
122
74
  export function formatInputState(p) {
123
75
  if (!p.isInput)
124
76
  return "";
125
77
  if (p.inputValue)
126
78
  return ` [input] value:${JSON.stringify(p.inputValue)}`;
127
- // inputValue/inputPlaceholder are absent on entries captured before this
128
- // field existed (or by other producers); fall back to the bare marker
129
- // rather than asserting the field is empty.
130
79
  if (p.inputValue === undefined && p.inputPlaceholder === undefined)
131
80
  return " [input]";
132
81
  return p.inputPlaceholder
@@ -146,7 +95,7 @@ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}
146
95
  lines.push("📍 Currently focused screen: unknown (no React Navigation / Expo Router detected)");
147
96
  }
148
97
  if (opts.keyboard) {
149
- const kbLine = formatKeyboardLine(opts.keyboard);
98
+ const kbLine = formatKeyboardLine(opts.keyboard, opts.pixelScale);
150
99
  if (kbLine)
151
100
  lines.push(kbLine);
152
101
  }
@@ -161,17 +110,12 @@ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}
161
110
  }
162
111
  const formatPressable = (p) => {
163
112
  const { center, frame } = convert(p);
164
- // 🔘 marks tap targets in the enriched view (where 📝 text / 🖼 images also
165
- // appear); omitted under pressablesOnly to keep the lean legacy lines.
166
113
  const marker = opts.pressablesOnly ? "" : " 🔘";
167
114
  return ` (${center.x}, ${center.y})${marker}${p.component ? ` <${p.component} />` : ""} ${p.label ? `"${p.label}"` : "(unlabeled)"}` +
168
115
  `${p.nearbyText ? ` near "${p.nearbyText}"` : ""}${p.onPressHint ? ` ${p.onPressHint}` : ""}` +
169
116
  `${p.testID ? ` testID="${p.testID}"` : ""}${formatInputState(p)}` +
170
117
  ` frame:(${frame.x},${frame.y} ${frame.width}x${frame.height})`;
171
118
  };
172
- // Merge pressables + (unless pressablesOnly) texts + images for one reachability
173
- // group, sorted spatially (top→bottom, then left→right). A text duplicating a
174
- // pressable's nearbyText is dropped; texts/images cap with an explicit marker.
175
119
  const renderGroup = (pressables, texts, images) => {
176
120
  const out = [];
177
121
  const nearby = new Set(pressables.map((p) => (p.nearbyText || "").trim()).filter(Boolean));
@@ -195,9 +139,6 @@ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}
195
139
  }
196
140
  return out;
197
141
  };
198
- // A native sheet has no entry in ss.overlays (it's not in the fiber-measured tree), but
199
- // it flags the underlying pressables blockedByOverlay — so take the split reachable/blocked
200
- // path even when overlays is empty, so those flags surface in the summary.
201
142
  if (ss.overlays.length > 0 || ss.nativeOverlay) {
202
143
  for (const overlay of ss.overlays) {
203
144
  lines.push(`\n🔲 ${overlay.type}${overlay.title ? ` — "${overlay.title}"` : ""}:`);
@@ -227,8 +168,6 @@ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}
227
168
  }
228
169
  }
229
170
  else {
230
- // A raised keyboard blocks taps exactly as an overlay does, so it gets
231
- // the same treatment rather than a second notion of "blocked".
232
171
  const kb = opts.keyboard;
233
172
  const splitP = partitionByKeyboard(ss.pressables, kb ?? NO_KEYBOARD);
234
173
  const splitT = partitionByKeyboard(ss.texts, kb ?? NO_KEYBOARD);
@@ -246,14 +185,6 @@ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}
246
185
  }
247
186
  return lines.join("\n");
248
187
  }
249
- /**
250
- * Turn raw onPress handler info ({ n: fn.name, s: source head }) into a
251
- * displayable hint, or null when nothing meaningful survives:
252
- * - real names ("handleSubmit", "bound goBack") → "handleSubmit()" / "goBack()"
253
- * - generic/minified names ("onPress", "anonymous", "t12") are rejected
254
- * - anonymous with retained source → "{() => setAccepted(prev => !prev)…}"
255
- * - Hermes bytecode bundles (source = "[bytecode]", stripped in-app) → null
256
- */
257
188
  const GENERIC_HANDLER_NAMES = new Set(["", "anonymous", "onpress", "onclick", "handler", "callback", "fn", "press", "value"]);
258
189
  function meaningfulHandlerName(n) {
259
190
  let name = (n || "").trim();
@@ -262,7 +193,7 @@ function meaningfulHandlerName(n) {
262
193
  if (!name || GENERIC_HANDLER_NAMES.has(name.toLowerCase()))
263
194
  return null;
264
195
  if (/^[a-zA-Z_$]\d{1,4}$/.test(name) || name.length === 1)
265
- return null; // minified (t12, e)
196
+ return null;
266
197
  return name;
267
198
  }
268
199
  export function describePressHandler(raw) {
@@ -277,17 +208,6 @@ export function describePressHandler(raw) {
277
208
  return `{${src.length > 70 ? src.slice(0, 70) + "…" : src}}`;
278
209
  return null;
279
210
  }
280
- /**
281
- * Fallback handler context from the custom component's on* props, for when the
282
- * direct onPress is anonymous (Hermes discards source even in dev bundles, and
283
- * names like navigation.goBack are lost to computed assignment):
284
- * - only trust the prop whose value IS the touchable's onPress (pass-through);
285
- * a non-matched candidate is an unverifiable guess that mislabels every button
286
- * in a multi-button container (FloatingHeader exposes only onBack, but its menu
287
- * and cart buttons run internal handlers) — so it yields null
288
- * - named fn → "onBack=goBack()"; nameless → "onPress→onBack" (the prop name
289
- * alone is greppable context); a bare nameless "onPress" prop adds nothing → null
290
- */
291
211
  export function describePropHandlers(raw) {
292
212
  if (!Array.isArray(raw) || raw.length === 0)
293
213
  return null;
@@ -318,9 +238,6 @@ export function parseScreenStateResponse(raw) {
318
238
  notes: r.notes ?? [],
319
239
  };
320
240
  }
321
- // ============================================================================
322
- // Main function (dispatch phase — Task 3; resolve phase added in Task 4)
323
- // ============================================================================
324
241
  export async function getScreenState(options = {}) {
325
242
  const { device } = options;
326
243
  const dispatchExpression = `
@@ -618,6 +535,83 @@ export async function getScreenState(options = {}) {
618
535
  return 'Unknown';
619
536
  }
620
537
 
538
+ // style can be an object, a nested array, or null. Only the flattened result can be
539
+ // asked about position/backgroundColor, and the previous heuristic read the raw prop —
540
+ // so any component passing style={[base, override]} was silently skipped.
541
+ function flattenStyle(s) {
542
+ if (!s) return null;
543
+ if (Array.isArray(s)) {
544
+ var out = null;
545
+ for (var fi = 0; fi < s.length; fi++) {
546
+ var f = flattenStyle(s[fi]);
547
+ if (!f) continue;
548
+ if (!out) out = {};
549
+ for (var k in f) out[k] = f[k];
550
+ }
551
+ return out;
552
+ }
553
+ return typeof s === 'object' ? s : null;
554
+ }
555
+
556
+ // "Opaque enough to hide what is behind it." Colours reach the fiber either as CSS
557
+ // strings or, on Fabric, as processed ARGB integers; both carry the alpha that decides
558
+ // whether this is a cover or just a tint. A translucent scrim is deliberately NOT a
559
+ // cover — the screen shows through it and its elements stay readable.
560
+ function isOpaqueBackground(st) {
561
+ if (st.opacity != null && st.opacity < 0.95) return false;
562
+ var bg = st.backgroundColor;
563
+ if (bg == null) return false;
564
+ if (typeof bg === 'number') return ((bg >>> 24) & 255) >= 242;
565
+ if (typeof bg !== 'string') return false;
566
+ var v = bg.replace(/\\s/g, '').toLowerCase();
567
+ if (v === 'transparent') return false;
568
+ var m = v.match(/^rgba\\(([^)]*)\\)$/);
569
+ if (m) {
570
+ var parts = m[1].split(',');
571
+ if (parts.length === 4 && parseFloat(parts[3]) < 0.95) return false;
572
+ }
573
+ if (v.charAt(0) === '#' && (v.length === 9 || v.length === 5)) {
574
+ var hex = v.length === 9 ? v.slice(7, 9) : (v.charAt(4) + v.charAt(4));
575
+ var alpha = parseInt(hex, 16);
576
+ if (!isNaN(alpha) && alpha < 242) return false;
577
+ }
578
+ return true;
579
+ }
580
+
581
+ // The opaque surface is usually NOT on the positioned node. The common shape is a
582
+ // transparent absolutely-positioned wrapper whose child paints the panel — a bottom
583
+ // sheet is typically an absolute View wrapping an inner (often animated) View that
584
+ // carries the opaque backgroundColor. Inspecting only the wrapper's own style (the
585
+ // first version of this rule) therefore recognises almost no real sheet.
586
+ function hasOpaqueSurface(fiber, ownStyle) {
587
+ // A wrapper that is itself faded out is not covering anything, whatever its
588
+ // children declare.
589
+ if (ownStyle && ownStyle.opacity != null && ownStyle.opacity < 0.95) return false;
590
+ if (ownStyle && isOpaqueBackground(ownStyle)) return true;
591
+ var found = false;
592
+ (function scan(n, d) {
593
+ if (!n || d > 4 || found) return;
594
+ if (typeof n.type === 'string') {
595
+ var st = flattenStyle(n.memoizedProps && n.memoizedProps.style);
596
+ if (st && isOpaqueBackground(st)) { found = true; return; }
597
+ }
598
+ scan(n.child, d + 1);
599
+ if (!found) scan(n.sibling, d);
600
+ })(fiber.child, 0);
601
+ return found;
602
+ }
603
+
604
+ function hasPressableDescendant(f) {
605
+ var found = false;
606
+ (function scan(n, d) {
607
+ if (!n || d > 12 || found) return;
608
+ if (n.memoizedProps && typeof n.memoizedProps.onPress === 'function') { found = true; return; }
609
+ scan(n.child, d + 1);
610
+ if (!found) scan(n.sibling, d);
611
+ })(f.child, 0);
612
+ return found;
613
+ }
614
+
621
615
  // Walk to find viewport dimensions (reused for heuristic overlay detection)
622
616
  var viewportW = 9999, viewportH = 9999;
623
617
  var rootHostFiber = findFirstHost(roots[0].current, 0);
@@ -660,35 +654,35 @@ export async function getScreenState(options = {}) {
660
654
  }
661
655
  }
662
656
 
663
- // Heuristic: absolute-positioned node with high zIndex covering > 40% screen
664
- // Only fires if it has at least one pressable child
665
- if (typeof fiber.type === 'string') {
666
- var style = props.style;
667
- if (style && typeof style === 'object' && !Array.isArray(style)) {
668
- if ((style.zIndex > 999 || style.position === 'absolute') &&
669
- typeof style.width === 'number' && typeof style.height === 'number') {
670
- if (viewportW < 9999) {
671
- var area = style.width * style.height;
672
- var vArea = viewportW * viewportH;
673
- if (area > vArea * 0.4) {
674
- // Check if it has a pressable child
675
- var hasPressable = false;
676
- (function checkPress(f, d) {
677
- if (!f || d > 10 || hasPressable) return;
678
- if (f.memoizedProps && typeof f.memoizedProps.onPress === 'function') { hasPressable = true; return; }
679
- checkPress(f.child, d + 1);
680
- if (!hasPressable) checkPress(f.sibling, d);
681
- })(fiber.child, 0);
682
- if (hasPressable) {
683
- var hosts2 = [];
684
- findHostsInSubtree(fiber, 0, hosts2, 64);
685
- if (hosts2.length > 0) {
686
- overlayFiberMeta.push({ type: 'Unknown', fiber: fiber, hostFibers: hosts2 });
687
- }
688
- return;
689
- }
690
- }
691
- }
657
+ // Geometric occluder: an opaque, absolutely-positioned host view holding at least
658
+ // one pressable. This is the branch that catches a sheet mounted as an ordinary
659
+ // view rather than as a Modal, a BottomSheet or a native presentation — a
660
+ // third-party in-app devtool panel, a hand-rolled dialog — which none of the
661
+ // name/prop classifiers above can recognise. Without it every element underneath
662
+ // such a sheet is reported as reachable and taps on them silently hit the sheet.
663
+ //
664
+ // Two deliberate changes from the rule this replaces:
665
+ // - the size test moves to the resolve pass, which works on MEASURED frames.
666
+ // Requiring literal numeric style.width/height here missed every sheet sized
667
+ // by flex, percentages or an animated value, which is nearly all of them.
668
+ // - opacity is required. A translucent scrim leaves the screen visible and its
669
+ // elements legitimately reachable, so it must not count as a cover.
670
+ // react-native-screens wraps every route in an absolutely-positioned, opaque
671
+ // container full of pressables — structurally identical to a sheet and, measured,
672
+ // 78% of the viewport. It is a route container, never an overlay: a screen
673
+ // presented ON TOP of another is caught by the stackPresentation branch above,
674
+ // which runs first. Excluding the family here is what keeps the whole visible
675
+ // screen from being filed under an overlay group.
676
+ var NAV_CONTAINER_HOST = /^RNS/;
677
+ if (typeof fiber.type === 'string' && !NAV_CONTAINER_HOST.test(fiber.type)) {
678
+ var style = flattenStyle(props.style);
679
+ if (style && (style.zIndex > 999 || style.position === 'absolute') &&
680
+ hasOpaqueSurface(fiber, style) && hasPressableDescendant(fiber)) {
681
+ var hosts2 = [];
682
+ findHostsInSubtree(fiber, 0, hosts2, 64);
683
+ if (hosts2.length > 0) {
684
+ overlayFiberMeta.push({ type: 'Unknown', fiber: fiber, hostFibers: hosts2, geometric: true });
685
+ return;
692
686
  }
693
687
  }
694
688
  }
@@ -708,6 +702,8 @@ export async function getScreenState(options = {}) {
708
702
 
709
703
  var hostFibers = [];
710
704
  var fiberMeta = [];
705
+ // overlayFiberMeta index -> fiberMeta index at which that overlay's subtree was entered.
706
+ var overlayEnterIdx = [];
711
707
  // A count badge ("1", "99+") is the only text on icon buttons like a cart — treat it
712
708
  // as no-own-label so the icon child still surfaces (the count is kept as nearby text).
713
709
  var COUNT_BADGE = /^\\d{1,3}\\+?$/;
@@ -886,7 +882,17 @@ export async function getScreenState(options = {}) {
886
882
  // geometric containment wrongly swallows the underlying screen's pressables.
887
883
  if (ovIdx == null) {
888
884
  for (var ofi = 0; ofi < overlayFiberMeta.length; ofi++) {
889
- if (overlayFiberMeta[ofi].fiber === fiber) { ovIdx = ofi; break; }
885
+ if (overlayFiberMeta[ofi].fiber === fiber) {
886
+ ovIdx = ofi;
887
+ // Paint position of the overlay, expressed on the same counter as the
888
+ // pressables. This walk is DFS pre-order over siblings in order, which
889
+ // is RN's paint order, so "collected earlier" == "painted underneath".
890
+ // Anything collected AFTER the overlay is drawn on top of it and must
891
+ // not be reported as blocked by it — a LogBox banner over a sheet, a
892
+ // toast over a dialog.
893
+ if (overlayEnterIdx[ofi] == null) overlayEnterIdx[ofi] = fiberMeta.length;
894
+ break;
895
+ }
890
896
  }
891
897
  }
892
898
 
@@ -1155,7 +1161,7 @@ export async function getScreenState(options = {}) {
1155
1161
 
1156
1162
  // Store overlay host fibers separately
1157
1163
  var overlayHostFibers = [];
1158
- var overlayMetaList = overlayFiberMeta.map(function(om) {
1164
+ var overlayMetaList = overlayFiberMeta.map(function(om, omIdx) {
1159
1165
  var startIdx = overlayHostFibers.length;
1160
1166
  for (var hi = 0; hi < om.hostFibers.length; hi++) {
1161
1167
  overlayHostFibers.push(om.hostFibers[hi]);
@@ -1166,7 +1172,11 @@ export async function getScreenState(options = {}) {
1166
1172
  title: (title && title.length > 2) ? title.slice(0, 60) : null,
1167
1173
  hostStart: startIdx,
1168
1174
  hostEnd: overlayHostFibers.length,
1169
- fullCover: !!om.fullCover
1175
+ fullCover: !!om.fullCover,
1176
+ geometric: !!om.geometric,
1177
+ // null means "never entered during the pressable walk" — treat as painted last
1178
+ // (Infinity) so a subtree with no pressables of its own cannot block anything.
1179
+ enterIdx: overlayEnterIdx[omIdx] == null ? -1 : overlayEnterIdx[omIdx]
1170
1180
  };
1171
1181
  });
1172
1182
 
@@ -1240,7 +1250,7 @@ export async function getScreenState(options = {}) {
1240
1250
  if (dp.error)
1241
1251
  return { success: false, error: dp.error };
1242
1252
  }
1243
- catch { /* ignore */ }
1253
+ catch { }
1244
1254
  await delay(300);
1245
1255
  const resolveExpression = `
1246
1256
  (function() {
@@ -1311,6 +1321,26 @@ export async function getScreenState(options = {}) {
1311
1321
  if (mm.y + mm.height > cMaxY) cMaxY = mm.y + mm.height;
1312
1322
  }
1313
1323
  if (!bValid) continue;
1324
+ // Size gate for geometric candidates, applied here because this is the first
1325
+ // point where a measured frame exists.
1326
+ //
1327
+ // The upper bound is the important half. A candidate covering essentially the
1328
+ // whole viewport is far more likely to be a screen container (react-native-screens
1329
+ // wraps routes in absoluteFill views, which are opaque and full of pressables)
1330
+ // than a sheet, and promoting one to "overlay" would file the entire visible
1331
+ // screen under an overlay group. Genuine full-screen covers arrive as Modal or as
1332
+ // a covering stackPresentation and are classified above, before this branch runs.
1333
+ if (om.geometric) {
1334
+ var gArea = (bMaxX - bMinX) * (bMaxY - bMinY);
1335
+ if (!(vArea > 0) || gArea < vArea * 0.15 || gArea > vArea * 0.92) continue;
1336
+ // A closed drawer is an opaque, absolutely-positioned, pressable-filled panel
1337
+ // that happens to be parked off-screen (measured at x = -width). It covers
1338
+ // nothing until it slides in, so candidacy has to be judged on the visible
1339
+ // intersection rather than the panel's own size.
1340
+ var visW = Math.min(bMaxX, viewportW) - Math.max(bMinX, 0);
1341
+ var visH = Math.min(bMaxY, viewportH) - Math.max(bMinY, 0);
1342
+ if (visW <= 0 || visH <= 0 || (visW * visH) < gArea * 0.6) continue;
1343
+ }
1314
1344
  // Native covering modals occlude the whole screen — expand their block region to
1315
1345
  // the full viewport so elements that extend past the modal's measured content
1316
1346
  // frame (e.g. the bottom tab bar) are still flagged as blocked, not reachable.
@@ -1323,7 +1353,14 @@ export async function getScreenState(options = {}) {
1323
1353
  var contentBounds = cValid
1324
1354
  ? { x: Math.round(cMinX), y: Math.round(cMinY), width: Math.round(cMaxX - cMinX), height: Math.round(cMaxY - cMinY) }
1325
1355
  : blockBounds;
1326
- overlays.push({ origIdx: oi, type: om.type, title: om.title, blockBounds: blockBounds, contentBounds: contentBounds, hasContent: cValid, pressables: [] });
1356
+ // Geometric overlays never adopt by geometry. A classified overlay may portal its
1357
+ // content elsewhere in the tree, so containment is a needed fallback for it; a
1358
+ // geometric candidate is a plain in-tree view whose content is exactly its fiber
1359
+ // descendants. Letting it claim everything inside its rect would file the bottom
1360
+ // tab bar as part of the sheet drawn over it, when the truth is the opposite —
1361
+ // the tab bar is behind it and blocked.
1362
+ var geometric = !!om.geometric;
1363
+ overlays.push({ origIdx: oi, type: om.type, title: om.title, blockBounds: blockBounds, contentBounds: contentBounds, hasContent: cValid && !geometric, geometric: geometric, enterIdx: om.enterIdx, pressables: [] });
1327
1364
  }
1328
1365
 
1329
1366
  // Build pressable list
@@ -1335,6 +1372,9 @@ export async function getScreenState(options = {}) {
1335
1372
  if (m.x + m.width < 0 || m.y + m.height < 0) continue;
1336
1373
  if (m.x > viewportW || m.y > viewportH) continue;
1337
1374
  allPressables.push({
1375
+ // Position in the DFS collection order == paint order. Kept so occlusion can
1376
+ // ask "was this drawn before the overlay?" rather than only "is it inside it?".
1377
+ paintIdx: i,
1338
1378
  label: meta[i].label,
1339
1379
  component: meta[i].component || null,
1340
1380
  center: { x: Math.round(m.x + m.width / 2), y: Math.round(m.y + m.height / 2) },
@@ -1402,6 +1442,37 @@ export async function getScreenState(options = {}) {
1402
1442
  b.x + b.width <= ob.x + ob.width &&
1403
1443
  b.y + b.height <= ob.y + ob.height;
1404
1444
  }
1445
+
1446
+ // A geometric candidate has to earn its place: it must either own pressable content or
1447
+ // actually cover something. The name-based classifiers describe a real widget whether
1448
+ // or not it currently holds a button, but "opaque absolute view" is a guess, and a
1449
+ // guess that occludes nothing buys no information — it only adds an empty overlay
1450
+ // group to the output and invites the reader to treat a plain view as a sheet.
1451
+ // True when this overlay is painted over that pressable: the pressable is inside its
1452
+ // rect, is not part of its own subtree, and was collected before it.
1453
+ function occludes(o, p) {
1454
+ return p.overlayIdx !== o.origIdx &&
1455
+ o.enterIdx >= 0 && p.paintIdx < o.enterIdx &&
1456
+ inside(p.bounds, o.blockBounds);
1457
+ }
1458
+
1459
+ var keptOverlays = [];
1460
+ for (var fo = 0; fo < overlays.length; fo++) {
1461
+ var cand = overlays[fo];
1462
+ if (!cand.geometric) { keptOverlays.push(cand); continue; }
1463
+ // A geometric candidate must actually cover something that is not its own content.
1464
+ // Owning pressables is NOT enough: react-native-screens wraps every route in an
1465
+ // absolutely-positioned container that paints an opaque background and is full of
1466
+ // pressables, and promoting one to "overlay" files the whole visible screen under
1467
+ // an overlay group and empties the reachable list. Occluding a foreign element is
1468
+ // what distinguishes a sheet from a screen container.
1469
+ var earns = false;
1470
+ for (var cp = 0; cp < allPressables.length && !earns; cp++) {
1471
+ if (occludes(cand, allPressables[cp])) earns = true;
1472
+ }
1473
+ if (earns) keptOverlays.push(cand);
1474
+ }
1475
+ overlays = keptOverlays;
1405
1476
  for (var pi = 0; pi < allPressables.length; pi++) {
1406
1477
  var p = allPressables[pi];
1407
1478
  var assignedToOverlay = false;
@@ -1417,7 +1488,14 @@ export async function getScreenState(options = {}) {
1417
1488
  // Covered pressables stay in the list but are flagged — agents see what's
1418
1489
  // behind the sheet while knowing taps won't reach it until it closes.
1419
1490
  for (var ov2 = 0; ov2 < overlays.length; ov2++) {
1420
- if (inside(p.bounds, overlays[ov2].blockBounds)) { p.blockedByOverlay = true; break; }
1491
+ // Geometric overlays respect paint order, so a banner drawn on top of a
1492
+ // sheet is not reported as hidden by it. The name-classified overlays keep
1493
+ // the original containment-only rule: a Modal or a native sheet occludes
1494
+ // what is behind it regardless of where its subtree sits in the walk.
1495
+ var blocks = overlays[ov2].geometric
1496
+ ? occludes(overlays[ov2], p)
1497
+ : inside(p.bounds, overlays[ov2].blockBounds);
1498
+ if (blocks) { p.blockedByOverlay = true; break; }
1421
1499
  }
1422
1500
  rootPressables.push(p);
1423
1501
  }
@@ -1425,6 +1503,7 @@ export async function getScreenState(options = {}) {
1425
1503
  for (var si = 0; si < allPressables.length; si++) {
1426
1504
  delete allPressables[si].overlayIdx;
1427
1505
  delete allPressables[si].hasOwnLabel;
1506
+ delete allPressables[si].paintIdx;
1428
1507
  }
1429
1508
 
1430
1509
  // Build typed text/image lists (pair each measurement with its meta by index,
@@ -1505,7 +1584,6 @@ export async function getScreenState(options = {}) {
1505
1584
  }
1506
1585
  if (!screenState)
1507
1586
  return { success: false, error: "Empty screen state response" };
1508
- // Deduplicate pressables by center coordinates (PDV + onPress fallback can both fire)
1509
1587
  const dedupPressables = (list) => {
1510
1588
  const seen = new Set();
1511
1589
  return list.filter((p) => {
@@ -1520,8 +1598,6 @@ export async function getScreenState(options = {}) {
1520
1598
  for (const overlay of screenState.overlays) {
1521
1599
  overlay.pressables = dedupPressables(overlay.pressables);
1522
1600
  }
1523
- // Dedup texts/images: a single visual element often maps to nested host nodes
1524
- // (Image > ExpoImage) or repeated text spans that all measure to the same box.
1525
1601
  const dedupBy = (list, keyExtra) => {
1526
1602
  const seen = new Set();
1527
1603
  return list.filter((item) => {
@@ -1533,16 +1609,6 @@ export async function getScreenState(options = {}) {
1533
1609
  });
1534
1610
  };
1535
1611
  screenState.texts = dedupBy(screenState.texts, (t) => t.text);
1536
- // Images need geometry-only dedup, not center+src.
1537
- //
1538
- // RN's <Image> and the <ExpoImage> it renders both match IMG_NAME and climb to the
1539
- // same measurable host, but their sources stringify differently — "asset#77" for the
1540
- // required asset, the resolved "http://127.0.0.1:8083/assets/…?unstable_path=…" URL
1541
- // for the inner one. Keying on src therefore treated one picture as two, and every
1542
- // local asset on screen was listed twice at identical coordinates.
1543
- //
1544
- // Keep the more informative source: "asset#N" is an opaque registry index, while the
1545
- // resolved URL carries the actual filename.
1546
1612
  const OPAQUE_ASSET_REF = /^asset#\d+$/;
1547
1613
  const dedupImages = (list) => {
1548
1614
  const byBox = new Map();
@@ -1566,7 +1632,6 @@ export async function getScreenState(options = {}) {
1566
1632
  if (overlay.images)
1567
1633
  overlay.images = dedupImages(overlay.images);
1568
1634
  }
1569
- // Semantic icon hints + onPress handler hints
1570
1635
  const decorate = (p) => {
1571
1636
  applyIconHintToLabel(p);
1572
1637
  const direct = describePressHandler(p.handler);
@@ -1580,7 +1645,6 @@ export async function getScreenState(options = {}) {
1580
1645
  for (const overlay of screenState.overlays) {
1581
1646
  overlay.pressables.forEach(decorate);
1582
1647
  }
1583
- // Apply TS-side overlay marking as a safety pass
1584
1648
  for (const overlay of screenState.overlays) {
1585
1649
  if (overlay.pressables.length === 0)
1586
1650
  continue;
@@ -1591,9 +1655,6 @@ export async function getScreenState(options = {}) {
1591
1655
  const overlayBounds = { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
1592
1656
  markPressablesCoveredByOverlay(screenState.pressables, overlayBounds);
1593
1657
  }
1594
- // Native-presented sheet detection: when an open native sheet covers the screen, its
1595
- // (and the underlying screen's) coordinates are unreliable — flag it and mark the
1596
- // underlying pressables blocked so agents fall back to screenshot/OCR.
1597
1658
  try {
1598
1659
  const parsedRaw = JSON.parse(resolveResult.result || "{}");
1599
1660
  const markers = Array.isArray(parsedRaw.nativeMarkers) ? parsedRaw.nativeMarkers : [];
@@ -1604,13 +1665,11 @@ export async function getScreenState(options = {}) {
1604
1665
  `unreliable. Use ios_screenshot / ocr_screenshot to read and tap it.`;
1605
1666
  screenState.nativeOverlay = { kind: sheet.kind, component: sheet.component, note };
1606
1667
  screenState.notes = [...(screenState.notes ?? []), note];
1607
- // The native sheet dims/blocks the underlying screen — flag root pressables.
1608
1668
  for (const p of screenState.pressables)
1609
1669
  p.blockedByOverlay = true;
1610
1670
  }
1611
1671
  }
1612
1672
  catch {
1613
- /* detection is best-effort; never fail the call over it */
1614
1673
  }
1615
1674
  const json = JSON.stringify(screenState, null, 2);
1616
1675
  return { success: true, result: json, screenState };