execbro 0.0.1-reserve → 1.10.13

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 (475) hide show
  1. package/LICENSE +32 -0
  2. package/README.md +496 -0
  3. package/build/__tests__/helpers/fake-cdp-server.d.ts +56 -0
  4. package/build/__tests__/helpers/fake-cdp-server.d.ts.map +1 -0
  5. package/build/__tests__/helpers/fake-cdp-server.js +120 -0
  6. package/build/__tests__/helpers/fake-cdp-server.js.map +1 -0
  7. package/build/__tests__/helpers/tap-test-helpers.d.ts +36 -0
  8. package/build/__tests__/helpers/tap-test-helpers.d.ts.map +1 -0
  9. package/build/__tests__/helpers/tap-test-helpers.js +130 -0
  10. package/build/__tests__/helpers/tap-test-helpers.js.map +1 -0
  11. package/build/__tests__/integration/auto-reconnect.test.d.ts +2 -0
  12. package/build/__tests__/integration/auto-reconnect.test.d.ts.map +1 -0
  13. package/build/__tests__/integration/auto-reconnect.test.js +118 -0
  14. package/build/__tests__/integration/auto-reconnect.test.js.map +1 -0
  15. package/build/__tests__/integration/connection-health.test.d.ts +2 -0
  16. package/build/__tests__/integration/connection-health.test.d.ts.map +1 -0
  17. package/build/__tests__/integration/connection-health.test.js +157 -0
  18. package/build/__tests__/integration/connection-health.test.js.map +1 -0
  19. package/build/__tests__/integration/execute-in-app.test.d.ts +2 -0
  20. package/build/__tests__/integration/execute-in-app.test.d.ts.map +1 -0
  21. package/build/__tests__/integration/execute-in-app.test.js +124 -0
  22. package/build/__tests__/integration/execute-in-app.test.js.map +1 -0
  23. package/build/__tests__/integration/per-call-timeout.test.d.ts +2 -0
  24. package/build/__tests__/integration/per-call-timeout.test.d.ts.map +1 -0
  25. package/build/__tests__/integration/per-call-timeout.test.js +103 -0
  26. package/build/__tests__/integration/per-call-timeout.test.js.map +1 -0
  27. package/build/__tests__/integration/tap-strategies.test.d.ts +2 -0
  28. package/build/__tests__/integration/tap-strategies.test.d.ts.map +1 -0
  29. package/build/__tests__/integration/tap-strategies.test.js +330 -0
  30. package/build/__tests__/integration/tap-strategies.test.js.map +1 -0
  31. package/build/__tests__/integration/tools.test.d.ts +2 -0
  32. package/build/__tests__/integration/tools.test.d.ts.map +1 -0
  33. package/build/__tests__/integration/tools.test.js +227 -0
  34. package/build/__tests__/integration/tools.test.js.map +1 -0
  35. package/build/__tests__/setup.d.ts +2 -0
  36. package/build/__tests__/setup.d.ts.map +1 -0
  37. package/build/__tests__/setup.js +15 -0
  38. package/build/__tests__/setup.js.map +1 -0
  39. package/build/__tests__/unit/androidEmulatorAvds.test.d.ts +2 -0
  40. package/build/__tests__/unit/androidEmulatorAvds.test.d.ts.map +1 -0
  41. package/build/__tests__/unit/androidEmulatorAvds.test.js +98 -0
  42. package/build/__tests__/unit/androidEmulatorAvds.test.js.map +1 -0
  43. package/build/__tests__/unit/buildToken.test.d.ts +2 -0
  44. package/build/__tests__/unit/buildToken.test.d.ts.map +1 -0
  45. package/build/__tests__/unit/buildToken.test.js +22 -0
  46. package/build/__tests__/unit/buildToken.test.js.map +1 -0
  47. package/build/__tests__/unit/bundle.test.d.ts +2 -0
  48. package/build/__tests__/unit/bundle.test.d.ts.map +1 -0
  49. package/build/__tests__/unit/bundle.test.js +53 -0
  50. package/build/__tests__/unit/bundle.test.js.map +1 -0
  51. package/build/__tests__/unit/burst.test.d.ts +2 -0
  52. package/build/__tests__/unit/burst.test.d.ts.map +1 -0
  53. package/build/__tests__/unit/burst.test.js +54 -0
  54. package/build/__tests__/unit/burst.test.js.map +1 -0
  55. package/build/__tests__/unit/connection-health.test.d.ts +2 -0
  56. package/build/__tests__/unit/connection-health.test.d.ts.map +1 -0
  57. package/build/__tests__/unit/connection-health.test.js +38 -0
  58. package/build/__tests__/unit/connection-health.test.js.map +1 -0
  59. package/build/__tests__/unit/debugGlobals.test.d.ts +2 -0
  60. package/build/__tests__/unit/debugGlobals.test.d.ts.map +1 -0
  61. package/build/__tests__/unit/debugGlobals.test.js +14 -0
  62. package/build/__tests__/unit/debugGlobals.test.js.map +1 -0
  63. package/build/__tests__/unit/deviceDiscovery.test.d.ts +2 -0
  64. package/build/__tests__/unit/deviceDiscovery.test.d.ts.map +1 -0
  65. package/build/__tests__/unit/deviceDiscovery.test.js +119 -0
  66. package/build/__tests__/unit/deviceDiscovery.test.js.map +1 -0
  67. package/build/__tests__/unit/deviceResolver.test.d.ts +2 -0
  68. package/build/__tests__/unit/deviceResolver.test.d.ts.map +1 -0
  69. package/build/__tests__/unit/deviceResolver.test.js +261 -0
  70. package/build/__tests__/unit/deviceResolver.test.js.map +1 -0
  71. package/build/__tests__/unit/escapeNonAscii.test.d.ts +2 -0
  72. package/build/__tests__/unit/escapeNonAscii.test.d.ts.map +1 -0
  73. package/build/__tests__/unit/escapeNonAscii.test.js +76 -0
  74. package/build/__tests__/unit/escapeNonAscii.test.js.map +1 -0
  75. package/build/__tests__/unit/exec.test.d.ts +2 -0
  76. package/build/__tests__/unit/exec.test.d.ts.map +1 -0
  77. package/build/__tests__/unit/exec.test.js +54 -0
  78. package/build/__tests__/unit/exec.test.js.map +1 -0
  79. package/build/__tests__/unit/executor.test.d.ts +2 -0
  80. package/build/__tests__/unit/executor.test.d.ts.map +1 -0
  81. package/build/__tests__/unit/executor.test.js +220 -0
  82. package/build/__tests__/unit/executor.test.js.map +1 -0
  83. package/build/__tests__/unit/failureArtifact.test.d.ts +2 -0
  84. package/build/__tests__/unit/failureArtifact.test.d.ts.map +1 -0
  85. package/build/__tests__/unit/failureArtifact.test.js +207 -0
  86. package/build/__tests__/unit/failureArtifact.test.js.map +1 -0
  87. package/build/__tests__/unit/fastRefreshRecorder.test.d.ts +2 -0
  88. package/build/__tests__/unit/fastRefreshRecorder.test.d.ts.map +1 -0
  89. package/build/__tests__/unit/fastRefreshRecorder.test.js +68 -0
  90. package/build/__tests__/unit/fastRefreshRecorder.test.js.map +1 -0
  91. package/build/__tests__/unit/fastRefreshTools.test.d.ts +2 -0
  92. package/build/__tests__/unit/fastRefreshTools.test.d.ts.map +1 -0
  93. package/build/__tests__/unit/fastRefreshTools.test.js +112 -0
  94. package/build/__tests__/unit/fastRefreshTools.test.js.map +1 -0
  95. package/build/__tests__/unit/fiberMatch.test.d.ts +2 -0
  96. package/build/__tests__/unit/fiberMatch.test.d.ts.map +1 -0
  97. package/build/__tests__/unit/fiberMatch.test.js +114 -0
  98. package/build/__tests__/unit/fiberMatch.test.js.map +1 -0
  99. package/build/__tests__/unit/fingerprint.test.d.ts +2 -0
  100. package/build/__tests__/unit/fingerprint.test.d.ts.map +1 -0
  101. package/build/__tests__/unit/fingerprint.test.js +99 -0
  102. package/build/__tests__/unit/fingerprint.test.js.map +1 -0
  103. package/build/__tests__/unit/focusedInput.test.d.ts +2 -0
  104. package/build/__tests__/unit/focusedInput.test.d.ts.map +1 -0
  105. package/build/__tests__/unit/focusedInput.test.js +58 -0
  106. package/build/__tests__/unit/focusedInput.test.js.map +1 -0
  107. package/build/__tests__/unit/focusedInputTools.test.d.ts +2 -0
  108. package/build/__tests__/unit/focusedInputTools.test.d.ts.map +1 -0
  109. package/build/__tests__/unit/focusedInputTools.test.js +79 -0
  110. package/build/__tests__/unit/focusedInputTools.test.js.map +1 -0
  111. package/build/__tests__/unit/iconSemantics.test.d.ts +2 -0
  112. package/build/__tests__/unit/iconSemantics.test.d.ts.map +1 -0
  113. package/build/__tests__/unit/iconSemantics.test.js +80 -0
  114. package/build/__tests__/unit/iconSemantics.test.js.map +1 -0
  115. package/build/__tests__/unit/imageBuffer.test.d.ts +2 -0
  116. package/build/__tests__/unit/imageBuffer.test.d.ts.map +1 -0
  117. package/build/__tests__/unit/imageBuffer.test.js +128 -0
  118. package/build/__tests__/unit/imageBuffer.test.js.map +1 -0
  119. package/build/__tests__/unit/logs.test.d.ts +2 -0
  120. package/build/__tests__/unit/logs.test.d.ts.map +1 -0
  121. package/build/__tests__/unit/logs.test.js +90 -0
  122. package/build/__tests__/unit/logs.test.js.map +1 -0
  123. package/build/__tests__/unit/measureComponent.test.d.ts +2 -0
  124. package/build/__tests__/unit/measureComponent.test.d.ts.map +1 -0
  125. package/build/__tests__/unit/measureComponent.test.js +66 -0
  126. package/build/__tests__/unit/measureComponent.test.js.map +1 -0
  127. package/build/__tests__/unit/measureComponentTools.test.d.ts +2 -0
  128. package/build/__tests__/unit/measureComponentTools.test.d.ts.map +1 -0
  129. package/build/__tests__/unit/measureComponentTools.test.js +94 -0
  130. package/build/__tests__/unit/measureComponentTools.test.js.map +1 -0
  131. package/build/__tests__/unit/metro.test.d.ts +2 -0
  132. package/build/__tests__/unit/metro.test.d.ts.map +1 -0
  133. package/build/__tests__/unit/metro.test.js +61 -0
  134. package/build/__tests__/unit/metro.test.js.map +1 -0
  135. package/build/__tests__/unit/network.test.d.ts +2 -0
  136. package/build/__tests__/unit/network.test.d.ts.map +1 -0
  137. package/build/__tests__/unit/network.test.js +102 -0
  138. package/build/__tests__/unit/network.test.js.map +1 -0
  139. package/build/__tests__/unit/networkInterceptor.test.d.ts +2 -0
  140. package/build/__tests__/unit/networkInterceptor.test.d.ts.map +1 -0
  141. package/build/__tests__/unit/networkInterceptor.test.js +104 -0
  142. package/build/__tests__/unit/networkInterceptor.test.js.map +1 -0
  143. package/build/__tests__/unit/probe.test.d.ts +2 -0
  144. package/build/__tests__/unit/probe.test.d.ts.map +1 -0
  145. package/build/__tests__/unit/probe.test.js +62 -0
  146. package/build/__tests__/unit/probe.test.js.map +1 -0
  147. package/build/__tests__/unit/rnGlobalsBootstrap.test.d.ts +2 -0
  148. package/build/__tests__/unit/rnGlobalsBootstrap.test.d.ts.map +1 -0
  149. package/build/__tests__/unit/rnGlobalsBootstrap.test.js +29 -0
  150. package/build/__tests__/unit/rnGlobalsBootstrap.test.js.map +1 -0
  151. package/build/__tests__/unit/screenState.test.d.ts +2 -0
  152. package/build/__tests__/unit/screenState.test.d.ts.map +1 -0
  153. package/build/__tests__/unit/screenState.test.js +384 -0
  154. package/build/__tests__/unit/screenState.test.js.map +1 -0
  155. package/build/__tests__/unit/screenshot-diff.test.d.ts +2 -0
  156. package/build/__tests__/unit/screenshot-diff.test.d.ts.map +1 -0
  157. package/build/__tests__/unit/screenshot-diff.test.js +97 -0
  158. package/build/__tests__/unit/screenshot-diff.test.js.map +1 -0
  159. package/build/__tests__/unit/tap-evidence.test.d.ts +2 -0
  160. package/build/__tests__/unit/tap-evidence.test.d.ts.map +1 -0
  161. package/build/__tests__/unit/tap-evidence.test.js +89 -0
  162. package/build/__tests__/unit/tap-evidence.test.js.map +1 -0
  163. package/build/__tests__/unit/tap.test.d.ts +2 -0
  164. package/build/__tests__/unit/tap.test.d.ts.map +1 -0
  165. package/build/__tests__/unit/tap.test.js +767 -0
  166. package/build/__tests__/unit/tap.test.js.map +1 -0
  167. package/build/__tests__/unit/timeoutClamp.test.d.ts +2 -0
  168. package/build/__tests__/unit/timeoutClamp.test.d.ts.map +1 -0
  169. package/build/__tests__/unit/timeoutClamp.test.js +17 -0
  170. package/build/__tests__/unit/timeoutClamp.test.js.map +1 -0
  171. package/build/__tests__/unit/toolDescriptions.test.d.ts +2 -0
  172. package/build/__tests__/unit/toolDescriptions.test.d.ts.map +1 -0
  173. package/build/__tests__/unit/toolDescriptions.test.js +145 -0
  174. package/build/__tests__/unit/toolDescriptions.test.js.map +1 -0
  175. package/build/__tests__/unit/transportClassify.test.d.ts +2 -0
  176. package/build/__tests__/unit/transportClassify.test.d.ts.map +1 -0
  177. package/build/__tests__/unit/transportClassify.test.js +60 -0
  178. package/build/__tests__/unit/transportClassify.test.js.map +1 -0
  179. package/build/__tests__/unit/verifyAction.test.d.ts +2 -0
  180. package/build/__tests__/unit/verifyAction.test.d.ts.map +1 -0
  181. package/build/__tests__/unit/verifyAction.test.js +26 -0
  182. package/build/__tests__/unit/verifyAction.test.js.map +1 -0
  183. package/build/core/android.d.ts +299 -0
  184. package/build/core/android.d.ts.map +1 -0
  185. package/build/core/android.js +1582 -0
  186. package/build/core/android.js.map +1 -0
  187. package/build/core/appDetection.d.ts +20 -0
  188. package/build/core/appDetection.d.ts.map +1 -0
  189. package/build/core/appDetection.js +167 -0
  190. package/build/core/appDetection.js.map +1 -0
  191. package/build/core/bundle.d.ts +49 -0
  192. package/build/core/bundle.d.ts.map +1 -0
  193. package/build/core/bundle.js +356 -0
  194. package/build/core/bundle.js.map +1 -0
  195. package/build/core/componentSearch.d.ts +41 -0
  196. package/build/core/componentSearch.d.ts.map +1 -0
  197. package/build/core/componentSearch.js +588 -0
  198. package/build/core/componentSearch.js.map +1 -0
  199. package/build/core/componentTree.d.ts +13 -0
  200. package/build/core/componentTree.d.ts.map +1 -0
  201. package/build/core/componentTree.js +275 -0
  202. package/build/core/componentTree.js.map +1 -0
  203. package/build/core/config.d.ts +9 -0
  204. package/build/core/config.d.ts.map +1 -0
  205. package/build/core/config.js +28 -0
  206. package/build/core/config.js.map +1 -0
  207. package/build/core/connection.d.ts +102 -0
  208. package/build/core/connection.d.ts.map +1 -0
  209. package/build/core/connection.js +1710 -0
  210. package/build/core/connection.js.map +1 -0
  211. package/build/core/connectionState.d.ts +122 -0
  212. package/build/core/connectionState.d.ts.map +1 -0
  213. package/build/core/connectionState.js +313 -0
  214. package/build/core/connectionState.js.map +1 -0
  215. package/build/core/debugGlobals.d.ts +6 -0
  216. package/build/core/debugGlobals.d.ts.map +1 -0
  217. package/build/core/debugGlobals.js +370 -0
  218. package/build/core/debugGlobals.js.map +1 -0
  219. package/build/core/deviceDiscovery.d.ts +52 -0
  220. package/build/core/deviceDiscovery.d.ts.map +1 -0
  221. package/build/core/deviceDiscovery.js +74 -0
  222. package/build/core/deviceDiscovery.js.map +1 -0
  223. package/build/core/deviceResolver.d.ts +44 -0
  224. package/build/core/deviceResolver.d.ts.map +1 -0
  225. package/build/core/deviceResolver.js +225 -0
  226. package/build/core/deviceResolver.js.map +1 -0
  227. package/build/core/errorScreenParser.d.ts +30 -0
  228. package/build/core/errorScreenParser.d.ts.map +1 -0
  229. package/build/core/errorScreenParser.js +198 -0
  230. package/build/core/errorScreenParser.js.map +1 -0
  231. package/build/core/errors.d.ts +14 -0
  232. package/build/core/errors.d.ts.map +1 -0
  233. package/build/core/errors.js +17 -0
  234. package/build/core/errors.js.map +1 -0
  235. package/build/core/escapeNonAscii.d.ts +18 -0
  236. package/build/core/escapeNonAscii.d.ts.map +1 -0
  237. package/build/core/escapeNonAscii.js +352 -0
  238. package/build/core/escapeNonAscii.js.map +1 -0
  239. package/build/core/exec.d.ts +22 -0
  240. package/build/core/exec.d.ts.map +1 -0
  241. package/build/core/exec.js +54 -0
  242. package/build/core/exec.js.map +1 -0
  243. package/build/core/executor.d.ts +9 -0
  244. package/build/core/executor.d.ts.map +1 -0
  245. package/build/core/executor.js +12 -0
  246. package/build/core/executor.js.map +1 -0
  247. package/build/core/failureArtifact.d.ts +120 -0
  248. package/build/core/failureArtifact.d.ts.map +1 -0
  249. package/build/core/failureArtifact.js +113 -0
  250. package/build/core/failureArtifact.js.map +1 -0
  251. package/build/core/fastRefreshRecorder.d.ts +23 -0
  252. package/build/core/fastRefreshRecorder.d.ts.map +1 -0
  253. package/build/core/fastRefreshRecorder.js +83 -0
  254. package/build/core/fastRefreshRecorder.js.map +1 -0
  255. package/build/core/fastRefreshTools.d.ts +19 -0
  256. package/build/core/fastRefreshTools.d.ts.map +1 -0
  257. package/build/core/fastRefreshTools.js +71 -0
  258. package/build/core/fastRefreshTools.js.map +1 -0
  259. package/build/core/feedback.d.ts +18 -0
  260. package/build/core/feedback.d.ts.map +1 -0
  261. package/build/core/feedback.js +73 -0
  262. package/build/core/feedback.js.map +1 -0
  263. package/build/core/fiberMatch.d.ts +25 -0
  264. package/build/core/fiberMatch.d.ts.map +1 -0
  265. package/build/core/fiberMatch.js +35 -0
  266. package/build/core/fiberMatch.js.map +1 -0
  267. package/build/core/fingerprint.d.ts +4 -0
  268. package/build/core/fingerprint.d.ts.map +1 -0
  269. package/build/core/fingerprint.js +47 -0
  270. package/build/core/fingerprint.js.map +1 -0
  271. package/build/core/focusedInput.d.ts +27 -0
  272. package/build/core/focusedInput.d.ts.map +1 -0
  273. package/build/core/focusedInput.js +110 -0
  274. package/build/core/focusedInput.js.map +1 -0
  275. package/build/core/focusedInputTools.d.ts +21 -0
  276. package/build/core/focusedInputTools.d.ts.map +1 -0
  277. package/build/core/focusedInputTools.js +51 -0
  278. package/build/core/focusedInputTools.js.map +1 -0
  279. package/build/core/format.d.ts +8 -0
  280. package/build/core/format.d.ts.map +1 -0
  281. package/build/core/format.js +34 -0
  282. package/build/core/format.js.map +1 -0
  283. package/build/core/guides.d.ts +21 -0
  284. package/build/core/guides.d.ts.map +1 -0
  285. package/build/core/guides.js +397 -0
  286. package/build/core/guides.js.map +1 -0
  287. package/build/core/iconSemantics.d.ts +18 -0
  288. package/build/core/iconSemantics.d.ts.map +1 -0
  289. package/build/core/iconSemantics.js +114 -0
  290. package/build/core/iconSemantics.js.map +1 -0
  291. package/build/core/imageBuffer.d.ts +37 -0
  292. package/build/core/imageBuffer.d.ts.map +1 -0
  293. package/build/core/imageBuffer.js +58 -0
  294. package/build/core/imageBuffer.js.map +1 -0
  295. package/build/core/index.d.ts +37 -0
  296. package/build/core/index.d.ts.map +1 -0
  297. package/build/core/index.js +66 -0
  298. package/build/core/index.js.map +1 -0
  299. package/build/core/inspector.d.ts +55 -0
  300. package/build/core/inspector.d.ts.map +1 -0
  301. package/build/core/inspector.js +603 -0
  302. package/build/core/inspector.js.map +1 -0
  303. package/build/core/ios.d.ts +263 -0
  304. package/build/core/ios.d.ts.map +1 -0
  305. package/build/core/ios.js +1705 -0
  306. package/build/core/ios.js.map +1 -0
  307. package/build/core/jsExecute.d.ts +62 -0
  308. package/build/core/jsExecute.d.ts.map +1 -0
  309. package/build/core/jsExecute.js +696 -0
  310. package/build/core/jsExecute.js.map +1 -0
  311. package/build/core/license.d.ts +48 -0
  312. package/build/core/license.d.ts.map +1 -0
  313. package/build/core/license.js +267 -0
  314. package/build/core/license.js.map +1 -0
  315. package/build/core/logbox.d.ts +58 -0
  316. package/build/core/logbox.d.ts.map +1 -0
  317. package/build/core/logbox.js +330 -0
  318. package/build/core/logbox.js.map +1 -0
  319. package/build/core/logs.d.ts +44 -0
  320. package/build/core/logs.d.ts.map +1 -0
  321. package/build/core/logs.js +149 -0
  322. package/build/core/logs.js.map +1 -0
  323. package/build/core/measureComponent.d.ts +19 -0
  324. package/build/core/measureComponent.d.ts.map +1 -0
  325. package/build/core/measureComponent.js +94 -0
  326. package/build/core/measureComponent.js.map +1 -0
  327. package/build/core/measureComponentTools.d.ts +6 -0
  328. package/build/core/measureComponentTools.d.ts.map +1 -0
  329. package/build/core/measureComponentTools.js +43 -0
  330. package/build/core/measureComponentTools.js.map +1 -0
  331. package/build/core/metro.d.ts +31 -0
  332. package/build/core/metro.d.ts.map +1 -0
  333. package/build/core/metro.js +124 -0
  334. package/build/core/metro.js.map +1 -0
  335. package/build/core/nativeOnlyHints.d.ts +14 -0
  336. package/build/core/nativeOnlyHints.d.ts.map +1 -0
  337. package/build/core/nativeOnlyHints.js +58 -0
  338. package/build/core/nativeOnlyHints.js.map +1 -0
  339. package/build/core/network.d.ts +43 -0
  340. package/build/core/network.d.ts.map +1 -0
  341. package/build/core/network.js +217 -0
  342. package/build/core/network.js.map +1 -0
  343. package/build/core/networkInterceptor.d.ts +30 -0
  344. package/build/core/networkInterceptor.d.ts.map +1 -0
  345. package/build/core/networkInterceptor.js +211 -0
  346. package/build/core/networkInterceptor.js.map +1 -0
  347. package/build/core/ocr.d.ts +87 -0
  348. package/build/core/ocr.d.ts.map +1 -0
  349. package/build/core/ocr.js +335 -0
  350. package/build/core/ocr.js.map +1 -0
  351. package/build/core/paths.d.ts +2 -0
  352. package/build/core/paths.d.ts.map +1 -0
  353. package/build/core/paths.js +28 -0
  354. package/build/core/paths.js.map +1 -0
  355. package/build/core/posthog.d.ts +5 -0
  356. package/build/core/posthog.d.ts.map +1 -0
  357. package/build/core/posthog.js +52 -0
  358. package/build/core/posthog.js.map +1 -0
  359. package/build/core/pressables.d.ts +46 -0
  360. package/build/core/pressables.d.ts.map +1 -0
  361. package/build/core/pressables.js +1719 -0
  362. package/build/core/pressables.js.map +1 -0
  363. package/build/core/probe.d.ts +12 -0
  364. package/build/core/probe.d.ts.map +1 -0
  365. package/build/core/probe.js +56 -0
  366. package/build/core/probe.js.map +1 -0
  367. package/build/core/redux.d.ts +22 -0
  368. package/build/core/redux.d.ts.map +1 -0
  369. package/build/core/redux.js +116 -0
  370. package/build/core/redux.js.map +1 -0
  371. package/build/core/register.d.ts +8 -0
  372. package/build/core/register.d.ts.map +1 -0
  373. package/build/core/register.js +202 -0
  374. package/build/core/register.js.map +1 -0
  375. package/build/core/rnGlobalsBootstrap.d.ts +16 -0
  376. package/build/core/rnGlobalsBootstrap.d.ts.map +1 -0
  377. package/build/core/rnGlobalsBootstrap.js +116 -0
  378. package/build/core/rnGlobalsBootstrap.js.map +1 -0
  379. package/build/core/screenLayout.d.ts +53 -0
  380. package/build/core/screenLayout.d.ts.map +1 -0
  381. package/build/core/screenLayout.js +878 -0
  382. package/build/core/screenLayout.js.map +1 -0
  383. package/build/core/screenState.d.ts +166 -0
  384. package/build/core/screenState.d.ts.map +1 -0
  385. package/build/core/screenState.js +1352 -0
  386. package/build/core/screenState.js.map +1 -0
  387. package/build/core/sdkBridge.d.ts +67 -0
  388. package/build/core/sdkBridge.d.ts.map +1 -0
  389. package/build/core/sdkBridge.js +148 -0
  390. package/build/core/sdkBridge.js.map +1 -0
  391. package/build/core/state.d.ts +37 -0
  392. package/build/core/state.d.ts.map +1 -0
  393. package/build/core/state.js +124 -0
  394. package/build/core/state.js.map +1 -0
  395. package/build/core/telemetry.d.ts +50 -0
  396. package/build/core/telemetry.d.ts.map +1 -0
  397. package/build/core/telemetry.js +653 -0
  398. package/build/core/telemetry.js.map +1 -0
  399. package/build/core/toolHelpers.d.ts +24 -0
  400. package/build/core/toolHelpers.d.ts.map +1 -0
  401. package/build/core/toolHelpers.js +118 -0
  402. package/build/core/toolHelpers.js.map +1 -0
  403. package/build/core/types.d.ts +162 -0
  404. package/build/core/types.d.ts.map +1 -0
  405. package/build/core/types.js +2 -0
  406. package/build/core/types.js.map +1 -0
  407. package/build/index.d.ts +4 -0
  408. package/build/index.d.ts.map +1 -0
  409. package/build/index.js +132 -0
  410. package/build/index.js.map +1 -0
  411. package/build/pro/screenshot-diff.d.ts +10 -0
  412. package/build/pro/screenshot-diff.d.ts.map +1 -0
  413. package/build/pro/screenshot-diff.js +38 -0
  414. package/build/pro/screenshot-diff.js.map +1 -0
  415. package/build/pro/tap.d.ts +291 -0
  416. package/build/pro/tap.d.ts.map +1 -0
  417. package/build/pro/tap.js +1839 -0
  418. package/build/pro/tap.js.map +1 -0
  419. package/build/pro/verifyAction.d.ts +50 -0
  420. package/build/pro/verifyAction.d.ts.map +1 -0
  421. package/build/pro/verifyAction.js +285 -0
  422. package/build/pro/verifyAction.js.map +1 -0
  423. package/build/tools/_deviceArg.d.ts +45 -0
  424. package/build/tools/_deviceArg.d.ts.map +1 -0
  425. package/build/tools/_deviceArg.js +58 -0
  426. package/build/tools/_deviceArg.js.map +1 -0
  427. package/build/tools/accountTools.d.ts +46 -0
  428. package/build/tools/accountTools.d.ts.map +1 -0
  429. package/build/tools/accountTools.js +223 -0
  430. package/build/tools/accountTools.js.map +1 -0
  431. package/build/tools/bundleTools.d.ts +3 -0
  432. package/build/tools/bundleTools.d.ts.map +1 -0
  433. package/build/tools/bundleTools.js +375 -0
  434. package/build/tools/bundleTools.js.map +1 -0
  435. package/build/tools/componentTools.d.ts +3 -0
  436. package/build/tools/componentTools.d.ts.map +1 -0
  437. package/build/tools/componentTools.js +746 -0
  438. package/build/tools/componentTools.js.map +1 -0
  439. package/build/tools/connectionTools.d.ts +3 -0
  440. package/build/tools/connectionTools.d.ts.map +1 -0
  441. package/build/tools/connectionTools.js +625 -0
  442. package/build/tools/connectionTools.js.map +1 -0
  443. package/build/tools/deviceTools.d.ts +3 -0
  444. package/build/tools/deviceTools.d.ts.map +1 -0
  445. package/build/tools/deviceTools.js +423 -0
  446. package/build/tools/deviceTools.js.map +1 -0
  447. package/build/tools/executionTools.d.ts +3 -0
  448. package/build/tools/executionTools.d.ts.map +1 -0
  449. package/build/tools/executionTools.js +243 -0
  450. package/build/tools/executionTools.js.map +1 -0
  451. package/build/tools/interactionTools.d.ts +3 -0
  452. package/build/tools/interactionTools.d.ts.map +1 -0
  453. package/build/tools/interactionTools.js +539 -0
  454. package/build/tools/interactionTools.js.map +1 -0
  455. package/build/tools/logTools.d.ts +3 -0
  456. package/build/tools/logTools.d.ts.map +1 -0
  457. package/build/tools/logTools.js +371 -0
  458. package/build/tools/logTools.js.map +1 -0
  459. package/build/tools/metaTools.d.ts +7 -0
  460. package/build/tools/metaTools.d.ts.map +1 -0
  461. package/build/tools/metaTools.js +186 -0
  462. package/build/tools/metaTools.js.map +1 -0
  463. package/build/tools/networkTools.d.ts +3 -0
  464. package/build/tools/networkTools.d.ts.map +1 -0
  465. package/build/tools/networkTools.js +478 -0
  466. package/build/tools/networkTools.js.map +1 -0
  467. package/build/tools/reduxTools.d.ts +3 -0
  468. package/build/tools/reduxTools.d.ts.map +1 -0
  469. package/build/tools/reduxTools.js +83 -0
  470. package/build/tools/reduxTools.js.map +1 -0
  471. package/build/tools/screenshotTools.d.ts +3 -0
  472. package/build/tools/screenshotTools.d.ts.map +1 -0
  473. package/build/tools/screenshotTools.js +703 -0
  474. package/build/tools/screenshotTools.js.map +1 -0
  475. package/package.json +63 -2
@@ -0,0 +1,1352 @@
1
+ import { executeInApp, delay } from "./jsExecute.js";
2
+ import { iconSemanticHint } from "./iconSemantics.js";
3
+ // ============================================================================
4
+ // Pure helpers (exported for unit tests)
5
+ // ============================================================================
6
+ export function markPressablesCoveredByOverlay(pressables, overlayBounds) {
7
+ for (const p of pressables) {
8
+ const b = p.bounds;
9
+ const fullyCovered = b.x >= overlayBounds.x &&
10
+ b.y >= overlayBounds.y &&
11
+ b.x + b.width <= overlayBounds.x + overlayBounds.width &&
12
+ b.y + b.height <= overlayBounds.y + overlayBounds.height;
13
+ if (fullyCovered)
14
+ p.blockedByOverlay = true;
15
+ }
16
+ return pressables;
17
+ }
18
+ /** A count badge such as "1" or "99+" — the only "label" an icon button like a cart carries. */
19
+ const COUNT_BADGE_LABEL = /^\d{1,3}\+?$/;
20
+ /**
21
+ * Replace component-name fallback labels with semantic icon labels when the
22
+ * pressable's icon child name carries recognizable semantics:
23
+ * { label: "[FloatingHeader]", icon: "SvgChevronBackward" }
24
+ * → label "[SvgChevronBackward — possibly back button]"
25
+ * An icon button whose only text is a count badge (cart with "1") keeps that
26
+ * count as nearby context while the label is upgraded to the icon's meaning:
27
+ * { label: "1", icon: "SvgCartNew" } → label "[SvgCartNew — possibly cart button]", nearbyText "1"
28
+ * Labels from text/a11y are never touched (icon is null for those).
29
+ */
30
+ export function applyIconHintToLabel(p) {
31
+ if (!p.icon)
32
+ return p;
33
+ const hint = iconSemanticHint(p.icon);
34
+ if (hint) {
35
+ if (p.label && COUNT_BADGE_LABEL.test(p.label.trim()) && !p.nearbyText) {
36
+ p.nearbyText = p.label;
37
+ }
38
+ p.label = `[${p.icon} — ${hint}]`;
39
+ }
40
+ else if (!p.label) {
41
+ p.label = `[${p.icon}]`;
42
+ }
43
+ return p;
44
+ }
45
+ const identityCoords = (item) => ({ center: item.center, frame: item.bounds });
46
+ const TEXT_DISPLAY_MAX = 80;
47
+ const IMAGE_SRC_DISPLAY_MAX = 60;
48
+ function truncate(s, max) {
49
+ return s.length > max ? s.slice(0, max) + "…" : s;
50
+ }
51
+ /** One merged-list line for a static text node — coordinates match pressable lines. */
52
+ export function formatTextEntry(t, convert = identityCoords, opts = {}) {
53
+ const { center, frame } = convert(t);
54
+ const body = opts.fullText ? t.text : truncate(t.text, TEXT_DISPLAY_MAX);
55
+ return ` (${center.x}, ${center.y}) 📝 "${body}" frame:(${frame.x},${frame.y} ${frame.width}x${frame.height})`;
56
+ }
57
+ /** One merged-list line for an image node — coordinates match pressable lines. */
58
+ export function formatImageEntry(img, convert = identityCoords) {
59
+ const { center, frame } = convert(img);
60
+ const src = img.src ? ` src="${truncate(img.src, IMAGE_SRC_DISPLAY_MAX)}"` : "";
61
+ const alt = img.alt ? ` alt="${img.alt}"` : "";
62
+ return ` (${center.x}, ${center.y}) 🖼 Image ${frame.width}x${frame.height}${src}${alt} frame:(${frame.x},${frame.y} ${frame.width}x${frame.height})`;
63
+ }
64
+ const TEXT_CAP = 60;
65
+ const IMAGE_CAP = 40;
66
+ /**
67
+ * Render a ScreenState as the orientation summary used by get_screen_state and the
68
+ * screenshot tools. By default it merges pressables, static text (📝), and images
69
+ * (🖼) into one spatially-ordered list per reachability group — enough to read and
70
+ * navigate the screen without a screenshot:
71
+ * 📍 Detail [Detail]
72
+ * 🎯 Pressables:
73
+ * (210, 175) 🖼 Image 420x350 src="…"
74
+ * (146, 394) 📝 "Valya product" frame:(20,382 251x24)
75
+ * (210, 838) <Button /> "In cart" frame:(20,810 380x56)
76
+ * pressablesOnly restores the lean pressable-only snapshot; fullText disables the
77
+ * 80-char text truncation.
78
+ */
79
+ export function formatScreenStateSummary(ss, convert = identityCoords, opts = {}) {
80
+ const lines = [];
81
+ if (ss.route) {
82
+ lines.push(`📍 Currently focused screen: "${ss.route.name}" [navigation stack: ${ss.route.stack.join(" > ")}]`);
83
+ if (ss.route.params && Object.keys(ss.route.params).length > 0) {
84
+ const params = JSON.stringify(ss.route.params);
85
+ lines.push(` route params: ${params.length > 600 ? params.slice(0, 600) + "…" : params}`);
86
+ }
87
+ }
88
+ else {
89
+ lines.push("📍 Currently focused screen: unknown (no React Navigation / Expo Router detected)");
90
+ }
91
+ const formatPressable = (p) => {
92
+ const { center, frame } = convert(p);
93
+ // 🔘 marks tap targets in the enriched view (where 📝 text / 🖼 images also
94
+ // appear); omitted under pressablesOnly to keep the lean legacy lines.
95
+ const marker = opts.pressablesOnly ? "" : " 🔘";
96
+ return ` (${center.x}, ${center.y})${marker}${p.component ? ` <${p.component} />` : ""} ${p.label ? `"${p.label}"` : "(unlabeled)"}` +
97
+ `${p.nearbyText ? ` near "${p.nearbyText}"` : ""}${p.onPressHint ? ` ${p.onPressHint}` : ""}` +
98
+ `${p.testID ? ` testID="${p.testID}"` : ""}${p.isInput ? " [input]" : ""}` +
99
+ ` frame:(${frame.x},${frame.y} ${frame.width}x${frame.height})`;
100
+ };
101
+ // Merge pressables + (unless pressablesOnly) texts + images for one reachability
102
+ // group, sorted spatially (top→bottom, then left→right). A text duplicating a
103
+ // pressable's nearbyText is dropped; texts/images cap with an explicit marker.
104
+ const renderGroup = (pressables, texts, images) => {
105
+ const out = [];
106
+ const nearby = new Set(pressables.map((p) => (p.nearbyText || "").trim()).filter(Boolean));
107
+ const freshTexts = opts.pressablesOnly ? [] : texts.filter((t) => !nearby.has(t.text.trim()));
108
+ const useTexts = freshTexts.slice(0, TEXT_CAP);
109
+ const useImages = opts.pressablesOnly ? [] : images.slice(0, IMAGE_CAP);
110
+ const rows = [
111
+ ...pressables.map((p) => ({ y: p.center.y, x: p.center.x, line: formatPressable(p) })),
112
+ ...useTexts.map((t) => ({ y: t.center.y, x: t.center.x, line: formatTextEntry(t, convert, opts) })),
113
+ ...useImages.map((img) => ({ y: img.center.y, x: img.center.x, line: formatImageEntry(img, convert) })),
114
+ ];
115
+ rows.sort((a, b) => (a.y !== b.y ? a.y - b.y : a.x - b.x));
116
+ rows.forEach((r) => out.push(r.line));
117
+ if (!opts.pressablesOnly) {
118
+ const droppedT = freshTexts.length - useTexts.length;
119
+ const droppedI = images.length - useImages.length;
120
+ if (droppedT > 0)
121
+ out.push(` … +${droppedT} more text`);
122
+ if (droppedI > 0)
123
+ out.push(` … +${droppedI} more images`);
124
+ }
125
+ return out;
126
+ };
127
+ if (ss.overlays.length > 0) {
128
+ for (const overlay of ss.overlays) {
129
+ lines.push(`\n🔲 ${overlay.type}${overlay.title ? ` — "${overlay.title}"` : ""}:`);
130
+ const body = renderGroup(overlay.pressables, overlay.texts ?? [], overlay.images ?? []);
131
+ if (body.length > 0)
132
+ body.forEach((l) => lines.push(l));
133
+ else
134
+ lines.push(" (no pressables)");
135
+ }
136
+ const reachableP = ss.pressables.filter((p) => !p.blockedByOverlay);
137
+ const blockedP = ss.pressables.filter((p) => p.blockedByOverlay);
138
+ const reachableT = ss.texts.filter((t) => !t.blockedByOverlay);
139
+ const blockedT = ss.texts.filter((t) => t.blockedByOverlay);
140
+ const reachableI = ss.images.filter((i) => !i.blockedByOverlay);
141
+ const blockedI = ss.images.filter((i) => i.blockedByOverlay);
142
+ const rootBody = renderGroup(reachableP, reachableT, reachableI);
143
+ if (opts.pressablesOnly) {
144
+ lines.push(`\n🎯 Root pressables: ${reachableP.length > 0 ? "" : "(none reachable)"}`);
145
+ }
146
+ else {
147
+ lines.push(`\n🎯 Reachable (outside any overlay):${rootBody.length > 0 ? "" : " (nothing reachable)"}`);
148
+ }
149
+ rootBody.forEach((l) => lines.push(l));
150
+ if (blockedP.length > 0 || blockedT.length > 0 || blockedI.length > 0) {
151
+ lines.push(`\n🚫 Blocked by overlay (visible on the underlying screen but taps will NOT reach them until the overlay closes):`);
152
+ renderGroup(blockedP, blockedT, blockedI).forEach((l) => lines.push(l));
153
+ }
154
+ }
155
+ else {
156
+ lines.push(opts.pressablesOnly ? "\n🎯 Pressables:" : "\n🎯 On screen:");
157
+ const body = renderGroup(ss.pressables, ss.texts, ss.images);
158
+ if (body.length > 0)
159
+ body.forEach((l) => lines.push(l));
160
+ else
161
+ lines.push(" (none)");
162
+ }
163
+ return lines.join("\n");
164
+ }
165
+ /**
166
+ * Turn raw onPress handler info ({ n: fn.name, s: source head }) into a
167
+ * displayable hint, or null when nothing meaningful survives:
168
+ * - real names ("handleSubmit", "bound goBack") → "handleSubmit()" / "goBack()"
169
+ * - generic/minified names ("onPress", "anonymous", "t12") are rejected
170
+ * - anonymous with retained source → "{() => setAccepted(prev => !prev)…}"
171
+ * - Hermes bytecode bundles (source = "[bytecode]", stripped in-app) → null
172
+ */
173
+ const GENERIC_HANDLER_NAMES = new Set(["", "anonymous", "onpress", "onclick", "handler", "callback", "fn", "press", "value"]);
174
+ function meaningfulHandlerName(n) {
175
+ let name = (n || "").trim();
176
+ if (name.startsWith("bound "))
177
+ name = name.slice(6).trim();
178
+ if (!name || GENERIC_HANDLER_NAMES.has(name.toLowerCase()))
179
+ return null;
180
+ if (/^[a-zA-Z_$]\d{1,4}$/.test(name) || name.length === 1)
181
+ return null; // minified (t12, e)
182
+ return name;
183
+ }
184
+ export function describePressHandler(raw) {
185
+ if (!raw || typeof raw !== "object")
186
+ return null;
187
+ const { n, s } = raw;
188
+ const name = meaningfulHandlerName(n);
189
+ if (name)
190
+ return `${name}()`;
191
+ const src = (s || "").trim();
192
+ if (src)
193
+ return `{${src.length > 70 ? src.slice(0, 70) + "…" : src}}`;
194
+ return null;
195
+ }
196
+ /**
197
+ * Fallback handler context from the custom component's on* props, for when the
198
+ * direct onPress is anonymous (Hermes discards source even in dev bundles, and
199
+ * names like navigation.goBack are lost to computed assignment):
200
+ * - only trust the prop whose value IS the touchable's onPress (pass-through);
201
+ * a non-matched candidate is an unverifiable guess that mislabels every button
202
+ * in a multi-button container (FloatingHeader exposes only onBack, but its menu
203
+ * and cart buttons run internal handlers) — so it yields null
204
+ * - named fn → "onBack=goBack()"; nameless → "onPress→onBack" (the prop name
205
+ * alone is greppable context); a bare nameless "onPress" prop adds nothing → null
206
+ */
207
+ export function describePropHandlers(raw) {
208
+ if (!Array.isArray(raw) || raw.length === 0)
209
+ return null;
210
+ const entries = raw.filter((e) => !!e && typeof e === "object" && typeof e.p === "string");
211
+ const pick = entries.find((e) => e.same) ?? null;
212
+ if (!pick)
213
+ return null;
214
+ const name = meaningfulHandlerName(pick.n);
215
+ if (name)
216
+ return `${pick.p}=${name}()`;
217
+ if (pick.p.toLowerCase() === "onpress")
218
+ return null;
219
+ return `onPress→${pick.p}`;
220
+ }
221
+ export function parseScreenStateResponse(raw) {
222
+ if (!raw || typeof raw !== "object")
223
+ return null;
224
+ const r = raw;
225
+ if (r.error)
226
+ return null;
227
+ return {
228
+ route: r.route ?? null,
229
+ overlays: r.overlays ?? [],
230
+ pressables: r.pressables ?? [],
231
+ texts: r.texts ?? [],
232
+ images: r.images ?? [],
233
+ };
234
+ }
235
+ // ============================================================================
236
+ // Main function (dispatch phase — Task 3; resolve phase added in Task 4)
237
+ // ============================================================================
238
+ export async function getScreenState(options = {}) {
239
+ const { device } = options;
240
+ const dispatchExpression = `
241
+ (function() {
242
+ var hook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
243
+ if (!hook) return { error: 'React DevTools hook not found.' };
244
+
245
+ var roots = [];
246
+ if (hook.getFiberRoots) roots = Array.from(hook.getFiberRoots(1) || []);
247
+ if (roots.length === 0 && hook.renderers) {
248
+ for (var entry of hook.renderers) {
249
+ var r = Array.from(hook.getFiberRoots ? (hook.getFiberRoots(entry[0]) || []) : []);
250
+ if (r.length > 0) { roots = r; break; }
251
+ }
252
+ }
253
+ if (roots.length === 0) return { error: 'No fiber roots found.' };
254
+
255
+ // ------------------------------------------------------------------
256
+ // Shared utilities
257
+ // ------------------------------------------------------------------
258
+
259
+ function getComponentName(fiber) {
260
+ if (!fiber || !fiber.type) return null;
261
+ if (typeof fiber.type === 'string') return fiber.type;
262
+ return fiber.type.displayName || fiber.type.name || null;
263
+ }
264
+
265
+ function getMeasurable(fiber) {
266
+ var sn = fiber.stateNode;
267
+ if (!sn) return null;
268
+ if (typeof sn.measureInWindow === 'function') return sn;
269
+ if (sn.canonical && sn.canonical.publicInstance &&
270
+ typeof sn.canonical.publicInstance.measureInWindow === 'function') {
271
+ return sn.canonical.publicInstance;
272
+ }
273
+ if (sn.node && globalThis.nativeFabricUIManager &&
274
+ typeof globalThis.nativeFabricUIManager.measureInWindow === 'function') {
275
+ var node = sn.node;
276
+ return {
277
+ measureInWindow: function(cb) {
278
+ try { globalThis.nativeFabricUIManager.measureInWindow(node, cb); } catch(e) {}
279
+ }
280
+ };
281
+ }
282
+ return null;
283
+ }
284
+
285
+ function findFirstHost(fiber, depth) {
286
+ if (!fiber || depth > 20) return null;
287
+ if (typeof fiber.type === 'string' && getMeasurable(fiber)) return fiber;
288
+ var child = fiber.child;
289
+ while (child) {
290
+ var found = findFirstHost(child, depth + 1);
291
+ if (found) return found;
292
+ child = child.sibling;
293
+ }
294
+ return null;
295
+ }
296
+
297
+ function findHostsInSubtree(fiber, depth, hosts, limit) {
298
+ if (!fiber || depth > 20 || hosts.length >= limit) return;
299
+ if (typeof fiber.type === 'string' && getMeasurable(fiber)) {
300
+ hosts.push(fiber);
301
+ return;
302
+ }
303
+ var child = fiber.child;
304
+ while (child && hosts.length < limit) {
305
+ findHostsInSubtree(child, depth + 1, hosts, limit);
306
+ child = child.sibling;
307
+ }
308
+ }
309
+
310
+ function collectText(fiber, d) {
311
+ if (!fiber || d > 20) return '';
312
+ var props = fiber.memoizedProps;
313
+ // Host text fibers carry the raw string as memoizedProps — needed when a
314
+ // mixed-children Text falls through to the fiber-child walk below.
315
+ if (typeof props === 'string') return props;
316
+ if (typeof props === 'number') return String(props);
317
+ if (props) {
318
+ var ch = props.children;
319
+ if (typeof ch === 'string') return ch;
320
+ if (typeof ch === 'number') return String(ch);
321
+ if (Array.isArray(ch)) {
322
+ var inline = [];
323
+ var hasElement = false;
324
+ for (var ci = 0; ci < ch.length; ci++) {
325
+ if (typeof ch[ci] === 'string') inline.push(ch[ci]);
326
+ else if (typeof ch[ci] === 'number') inline.push(String(ch[ci]));
327
+ else if (ch[ci] != null && ch[ci] !== false) hasElement = true;
328
+ }
329
+ // Mixed content ("Create " + <Text>2 digital items</Text>): fall through
330
+ // to the fiber-child walk so nested Text elements are included; the host
331
+ // text fibers re-supply the inline strings, so nothing is lost or doubled.
332
+ if (inline.length > 0 && !hasElement) return inline.join('');
333
+ }
334
+ }
335
+ var parts = [];
336
+ var child = fiber.child;
337
+ while (child) {
338
+ var t = collectText(child, d + 1);
339
+ if (t) parts.push(t);
340
+ child = child.sibling;
341
+ }
342
+ return parts.join(' ').replace(/\\s+/g, ' ').trim();
343
+ }
344
+
345
+ // ------------------------------------------------------------------
346
+ // 1. Route detection
347
+ // ------------------------------------------------------------------
348
+
349
+ var route = null;
350
+
351
+ // SDK navigation ref (highest priority — works even when NavigationContainer is wrapped)
352
+ try {
353
+ var sdk = globalThis.__EXECBRO__ || globalThis.__RN_AI_DEVTOOLS__;
354
+ var sdkNav = sdk && sdk.navigation;
355
+ if (sdkNav && typeof sdkNav.getCurrentRoute === 'function') {
356
+ var currentRoute = sdkNav.getCurrentRoute();
357
+ var rootState = typeof sdkNav.getRootState === 'function' ? sdkNav.getRootState() : null;
358
+ if (currentRoute && currentRoute.name) {
359
+ var sdkStack = [];
360
+ if (rootState && rootState.routes) {
361
+ (function collectStack(state) {
362
+ if (!state || !state.routes) return;
363
+ var idx = typeof state.index === 'number' ? state.index : state.routes.length - 1;
364
+ if (state.type === 'stack') {
365
+ // show full stack history for stack navigators
366
+ for (var i = 0; i < state.routes.length; i++) {
367
+ sdkStack.push(state.routes[i].name || state.routes[i].key || 'unknown');
368
+ }
369
+ var focused = state.routes[idx];
370
+ if (focused && focused.state) collectStack(focused.state);
371
+ } else {
372
+ // for tab/drawer just follow the focused screen
373
+ var focused = state.routes[idx];
374
+ if (focused) {
375
+ sdkStack.push(focused.name || focused.key || 'unknown');
376
+ if (focused.state) collectStack(focused.state);
377
+ }
378
+ }
379
+ })(rootState);
380
+ }
381
+ if (sdkStack.length === 0) sdkStack.push(currentRoute.name);
382
+ route = {
383
+ name: currentRoute.name,
384
+ params: currentRoute.params || null,
385
+ stack: sdkStack
386
+ };
387
+ }
388
+ }
389
+ } catch(e) {}
390
+
391
+ if (!route) try {
392
+ // React Navigation v5+: walk fiber tree for NavigationContainer ref
393
+ function findNavState(fiber, depth) {
394
+ if (!fiber || depth > 200) return null;
395
+ var name = getComponentName(fiber);
396
+ // NavigationContainer stores ref on stateNode; check state
397
+ if (name === 'NavigationContainer' || name === 'BaseNavigationContainer') {
398
+ var sn = fiber.stateNode;
399
+ if (sn && typeof sn.getRootState === 'function') {
400
+ return sn.getRootState();
401
+ }
402
+ // Hook-based: memoizedState chain
403
+ var mState = fiber.memoizedState;
404
+ while (mState) {
405
+ if (mState.memoizedState && mState.memoizedState.routes) {
406
+ return mState.memoizedState;
407
+ }
408
+ mState = mState.next;
409
+ }
410
+ }
411
+ var child = fiber.child;
412
+ while (child) {
413
+ var r = findNavState(child, depth + 1);
414
+ if (r) return r;
415
+ child = child.sibling;
416
+ }
417
+ return null;
418
+ }
419
+
420
+ // Also try __reactNavigationContainerRef global
421
+ var navState = null;
422
+ if (globalThis.__reactNavigationContainerRef && globalThis.__reactNavigationContainerRef.current) {
423
+ var ref = globalThis.__reactNavigationContainerRef.current;
424
+ if (typeof ref.getState === 'function') navState = ref.getState();
425
+ }
426
+ if (!navState) navState = findNavState(roots[0].current, 0);
427
+
428
+ // Fallback: scan all fibers for memoizedState with navigation shape
429
+ // (catches anonymous BaseNavigationContainer when displayName/name is null)
430
+ if (!navState) {
431
+ function isNavState(v) {
432
+ return v && typeof v === 'object' && Array.isArray(v.routes) && v.routes.length > 0
433
+ && typeof v.routes[0].name === 'string' && typeof v.index === 'number';
434
+ }
435
+ function findNavStateByShape(fiber, depth) {
436
+ if (!fiber || depth > 400) return null;
437
+ var s = fiber.memoizedState;
438
+ var checked = 0;
439
+ while (s && checked < 20) {
440
+ if (isNavState(s.memoizedState)) return s.memoizedState;
441
+ s = s.next;
442
+ checked++;
443
+ }
444
+ var result = findNavStateByShape(fiber.child, depth + 1);
445
+ if (result) return result;
446
+ return findNavStateByShape(fiber.sibling, depth + 1);
447
+ }
448
+ navState = findNavStateByShape(roots[0].current, 0);
449
+ }
450
+
451
+ if (navState && navState.routes) {
452
+ var fiberStack = [];
453
+ var fiberLeafParams = null;
454
+ (function collectFiberStack(state) {
455
+ if (!state || !state.routes || state.routes.length === 0) return;
456
+ var idx = (typeof state.index === 'number') ? state.index : state.routes.length - 1;
457
+ if (state.type === 'stack' || !state.type) {
458
+ for (var i = 0; i < state.routes.length; i++) {
459
+ fiberStack.push(state.routes[i].name || state.routes[i].key || 'unknown');
460
+ }
461
+ var focused = state.routes[idx];
462
+ if (focused) {
463
+ fiberLeafParams = focused.params || null;
464
+ if (focused.state) collectFiberStack(focused.state);
465
+ }
466
+ } else {
467
+ var focused = state.routes[idx];
468
+ if (focused) {
469
+ fiberStack.push(focused.name || focused.key || 'unknown');
470
+ fiberLeafParams = focused.params || null;
471
+ if (focused.state) collectFiberStack(focused.state);
472
+ }
473
+ }
474
+ })(navState);
475
+ if (fiberStack.length > 0) {
476
+ route = {
477
+ name: fiberStack[fiberStack.length - 1],
478
+ params: fiberLeafParams,
479
+ stack: fiberStack
480
+ };
481
+ }
482
+ }
483
+ } catch(e) {}
484
+
485
+ // ------------------------------------------------------------------
486
+ // 2. Overlay detection — build bounds for each overlay
487
+ // ------------------------------------------------------------------
488
+
489
+ var OVERLAY_NAMES = /^(Modal|BottomSheet|BottomSheetModal|BottomSheetView|ActionSheet|Alert)$/;
490
+ var overlayFiberMeta = []; // { type, fiberRoot, hostFibers }
491
+
492
+ function classifyOverlay(name) {
493
+ if (name === 'Modal') return 'Modal';
494
+ if (name === 'Alert') return 'Alert';
495
+ if (/ActionSheet/i.test(name)) return 'ActionSheet';
496
+ if (/BottomSheet/i.test(name)) return 'BottomSheet';
497
+ return 'Unknown';
498
+ }
499
+
500
+ // Walk to find viewport dimensions (reused for heuristic overlay detection)
501
+ var viewportW = 9999, viewportH = 9999;
502
+ var rootHostFiber = findFirstHost(roots[0].current, 0);
503
+
504
+ function walkForOverlays(fiber, depth) {
505
+ if (!fiber || depth > 5000) return;
506
+ var name = getComponentName(fiber);
507
+ var props = fiber.memoizedProps || {};
508
+
509
+ if (name && OVERLAY_NAMES.test(name)) {
510
+ // Collect host fibers in this overlay subtree
511
+ var hosts = [];
512
+ findHostsInSubtree(fiber, 0, hosts, 64);
513
+ if (hosts.length > 0) {
514
+ overlayFiberMeta.push({ type: classifyOverlay(name), fiber: fiber, hostFibers: hosts });
515
+ }
516
+ // Don't recurse deeper — nested overlays are unusual
517
+ return;
518
+ }
519
+
520
+ // Heuristic: absolute-positioned node with high zIndex covering > 40% screen
521
+ // Only fires if it has at least one pressable child
522
+ if (typeof fiber.type === 'string') {
523
+ var style = props.style;
524
+ if (style && typeof style === 'object' && !Array.isArray(style)) {
525
+ if ((style.zIndex > 999 || style.position === 'absolute') &&
526
+ typeof style.width === 'number' && typeof style.height === 'number') {
527
+ if (viewportW < 9999) {
528
+ var area = style.width * style.height;
529
+ var vArea = viewportW * viewportH;
530
+ if (area > vArea * 0.4) {
531
+ // Check if it has a pressable child
532
+ var hasPressable = false;
533
+ (function checkPress(f, d) {
534
+ if (!f || d > 10 || hasPressable) return;
535
+ if (f.memoizedProps && typeof f.memoizedProps.onPress === 'function') { hasPressable = true; return; }
536
+ checkPress(f.child, d + 1);
537
+ if (!hasPressable) checkPress(f.sibling, d);
538
+ })(fiber.child, 0);
539
+ if (hasPressable) {
540
+ var hosts2 = [];
541
+ findHostsInSubtree(fiber, 0, hosts2, 64);
542
+ if (hosts2.length > 0) {
543
+ overlayFiberMeta.push({ type: 'Unknown', fiber: fiber, hostFibers: hosts2 });
544
+ }
545
+ return;
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }
552
+
553
+ var child = fiber.child;
554
+ while (child) {
555
+ walkForOverlays(child, depth + 1);
556
+ child = child.sibling;
557
+ }
558
+ }
559
+ walkForOverlays(roots[0].current, 0);
560
+
561
+ // ------------------------------------------------------------------
562
+ // 3. Pressable extraction — reuse PressabilityDebugView logic
563
+ // (same logic as get_pressable_elements; inline to avoid second CDP call)
564
+ // ------------------------------------------------------------------
565
+
566
+ var hostFibers = [];
567
+ var fiberMeta = [];
568
+ // A count badge ("1", "99+") is the only text on icon buttons like a cart — treat it
569
+ // as no-own-label so the icon child still surfaces (the count is kept as nearby text).
570
+ var COUNT_BADGE = /^\\d{1,3}\\+?$/;
571
+
572
+ var RN_PRIMITIVES = /^(Animated\\(.*|withAnimated.*|AnimatedComponent.*|ForwardRef.*|memo\\(.*|Context\\.Consumer|Context\\.Provider|ScrollViewContext(Base)?|VirtualizedListContext(Resetter)?|TextInputContext|KeyboardAvoidingViewContext|RCT.*|RNS.*|RNC.*|ViewManagerAdapter_.*|VirtualizedList.*|CellRenderer.*|FrameSizeProvider.*|MaybeScreenContainer|MaybeScreen|Navigation.*|Screen$|ScreenStack|ScreenContainer|ScreenContentWrapper|SceneView|DelayedFreeze|Freeze|Suspender|DebugContainer|StaticContainer|SafeAreaProvider.*|SafeAreaFrameContext|SafeAreaInsetsContext|ExpoRoot|ExpoRootComponent|GestureHandler.*|NativeViewGestureHandler|GestureDetector|PanGestureHandler|Reanimated.*|BottomTabNavigator|TabLayout|RouteNode|Route$|KeyboardProvider|PortalProviderComponent|BottomSheetModalProviderWrapper|ThemeContext|ThemeProvider|TextAncestorContext|PressabilityDebugView|TouchableHighlightImpl|StatusBarOverlay|BottomSheetHostingContainerComponent|BottomSheetGestureHandlersProvider|BottomSheetBackdropContainerComponent|BottomSheetContainerComponent|BottomSheetDraggableViewComponent|BottomSheetHandleContainerComponent|BottomSheetBackgroundContainerComponent|DebuggingOverlay|InspectorDeferred|Inspector|InspectorOverlay|InspectorPanel|StyleInspector|BoxInspector|BoxContainer|ElementBox|BorderBox|InspectorPanelButton)$/;
573
+ var GENERIC_COMPONENT = /^(View|TouchableOpacity|TouchableHighlight|TouchableWithoutFeedback|Pressable|TouchableNativeFeedback|Text|RCTView|RCTText|Unknown)$/;
574
+ var PDV_OWNER_COMPONENT = /^(Pressable|Touchable(Opacity|Highlight|WithoutFeedback|NativeFeedback|Bounce))$/;
575
+
576
+ var PAGE_COMPONENT = /^(.*Screen|.*Page|.*View$|.*Container$|.*Layout$|.*Root$|ExpoRoot|App$)/;
577
+
578
+ // Layout-only and touch-wrapper components skipped when scanning a pressable's
579
+ // children for a meaningful icon component name (e.g. SvgChevronBack).
580
+ var SKIP_IN_CHILD_SCAN = /^(View|Text|Image|ImageBackground|ScrollView|FlatList|SectionList|KeyboardAvoidingView|SafeAreaView|TouchableOpacity|TouchableHighlight|TouchableWithoutFeedback|TouchableNativeFeedback|Pressable|TextInput|ActivityIndicator|Switch|Modal|StatusBar|VirtualizedList|RefreshControl|Animated\\(.*|withAnimated.*|AnimatedComponent.*)$/;
581
+
582
+ function findMeaningfulChildName(fiber) {
583
+ function scan(f, d) {
584
+ if (!f || d > 12) return null;
585
+ var n = getComponentName(f);
586
+ if (n && typeof f.type !== 'string' && !RN_PRIMITIVES.test(n) && !SKIP_IN_CHILD_SCAN.test(n)) return n;
587
+ var c = f.child;
588
+ while (c) {
589
+ var r = scan(c, d + 1);
590
+ if (r) return r;
591
+ c = c.sibling;
592
+ }
593
+ return null;
594
+ }
595
+ return scan(fiber.child, 0);
596
+ }
597
+
598
+ function findMeaningfulAncestorName(fiber) {
599
+ var cur = fiber.return;
600
+ var depth = 0;
601
+ var best = null;
602
+ while (cur && depth < 20) {
603
+ var n = getComponentName(cur);
604
+ if (n && typeof cur.type !== 'string' && !RN_PRIMITIVES.test(n) && !GENERIC_COMPONENT.test(n)) {
605
+ if (PAGE_COMPONENT.test(n)) break; // stop — too high, not useful
606
+ best = n;
607
+ break;
608
+ }
609
+ cur = cur.return;
610
+ depth++;
611
+ }
612
+ return best;
613
+ }
614
+
615
+ // Nearest custom component FIBER for a pressable — its name is what an agent
616
+ // can grep for in the codebase (OrderStepRow, CheckBox, Button). Own fiber when
617
+ // the pressable itself is custom, else a capped climb over composite ancestors
618
+ // (mirrors get_pressable_elements: stopping at the first composite is wrong,
619
+ // generic wrappers like ForwardRef(View) sit in between).
620
+ function resolveComponentFiber(fiber) {
621
+ var ownName = getComponentName(fiber);
622
+ if (ownName && typeof fiber.type !== 'string' && !GENERIC_COMPONENT.test(ownName) && !RN_PRIMITIVES.test(ownName)) return fiber;
623
+ var an = fiber.return;
624
+ var composites = 0;
625
+ var dep = 0;
626
+ while (an && dep < 12 && composites < 4) {
627
+ if (typeof an.type !== 'string' && an.type !== null) {
628
+ var n = getComponentName(an);
629
+ if (n) {
630
+ composites++;
631
+ if (!RN_PRIMITIVES.test(n) && !GENERIC_COMPONENT.test(n)) return an;
632
+ }
633
+ }
634
+ an = an.return;
635
+ dep++;
636
+ }
637
+ return null;
638
+ }
639
+
640
+ function resolveComponentName(fiber) {
641
+ var cf = resolveComponentFiber(fiber);
642
+ return cf ? getComponentName(cf) : null;
643
+ }
644
+
645
+ // Event-handler props (onBack, onSelect, ...) of the custom component — context
646
+ // for what the press triggers when the handler itself is anonymous. 'same' marks
647
+ // identity with the touchable's onPress (pass-through props like onPress={onBack}),
648
+ // which is the strongest signal of which prop the handler arrived through.
649
+ function collectPropHandlers(fiber, directFn) {
650
+ var cf = resolveComponentFiber(fiber);
651
+ if (!cf || !cf.memoizedProps) return null;
652
+ var ps = cf.memoizedProps;
653
+ var out = [];
654
+ for (var k in ps) {
655
+ if (out.length >= 6) break;
656
+ if (!/^on[A-Z]/.test(k)) continue;
657
+ if (typeof ps[k] !== 'function') continue;
658
+ out.push({ p: k, n: ps[k].name || '', same: directFn ? ps[k] === directFn : false });
659
+ }
660
+ return out.length ? out : null;
661
+ }
662
+
663
+ // Raw onPress handler info — name + source head. Whether it's displayable is
664
+ // decided on the TS side (describePressHandler): Hermes bytecode bundles yield
665
+ // minified names and '[bytecode]' source, which are filtered out there.
666
+ function handlerHint(fn) {
667
+ try {
668
+ var n = fn.name || '';
669
+ var s = '';
670
+ try { s = String(fn); } catch(e2) {}
671
+ if (s.indexOf('[bytecode]') !== -1 || s.indexOf('[native code]') !== -1) s = '';
672
+ return { n: n, s: s ? s.replace(/\\s+/g, ' ').slice(0, 160) : '' };
673
+ } catch(e) { return null; }
674
+ }
675
+
676
+ var ROLE_LABELS = {
677
+ checkbox: 'Checkbox', switch: 'Switch', radio: 'Radio', button: 'Button',
678
+ image: 'Image', imagebutton: 'Image Button', link: 'Link', menuitem: 'Menu Item',
679
+ tab: 'Tab', togglebutton: 'Toggle Button', spinbutton: 'Spin Button'
680
+ };
681
+
682
+ function resolveLabel(primaryFiber, hostFiber, baseLabel, baseTestID) {
683
+ if (baseLabel) return baseLabel;
684
+ // accessibilityRole fallback
685
+ var pProps = primaryFiber ? (primaryFiber.memoizedProps || {}) : {};
686
+ var hProps = hostFiber ? (hostFiber.memoizedProps || {}) : {};
687
+ var role = (hProps.accessibilityRole || pProps.accessibilityRole || hProps.role || pProps.role || '').toLowerCase();
688
+ if (role && ROLE_LABELS[role]) {
689
+ var state = hProps.accessibilityState || pProps.accessibilityState || {};
690
+ var stateStr = '';
691
+ if (state.checked === true) stateStr = ': checked';
692
+ else if (state.checked === false) stateStr = ': unchecked';
693
+ else if (state.selected === true) stateStr = ': selected';
694
+ return '[' + ROLE_LABELS[role] + stateStr + ']';
695
+ }
696
+ // Meaningful ancestor component name fallback
697
+ var ancestorName = primaryFiber ? findMeaningfulAncestorName(primaryFiber) : null;
698
+ if (ancestorName) return '[' + ancestorName + ']';
699
+ return baseTestID || null;
700
+ }
701
+
702
+ function isScreenHidden(name, props) {
703
+ if (!props) return false;
704
+ if (name === 'MaybeScreen' && props.active === 0) return true;
705
+ if (name === 'SceneView' && props.focused === false) return true;
706
+ if (name === 'RNSScreen' && props['aria-hidden'] === true) return true;
707
+ return false;
708
+ }
709
+
710
+ function walkPressabilityDebugViews(fiber, depth, hidden, ovIdx) {
711
+ if (!fiber || depth > 5000) return;
712
+ var name = getComponentName(fiber);
713
+ var props = fiber.memoizedProps;
714
+ var nextHidden = hidden || isScreenHidden(name, props);
715
+
716
+ // Track which overlay subtree we're inside — membership by ancestry, not
717
+ // geometry. A bottom sheet's subtree includes a full-screen backdrop, so
718
+ // geometric containment wrongly swallows the underlying screen's pressables.
719
+ if (ovIdx == null) {
720
+ for (var ofi = 0; ofi < overlayFiberMeta.length; ofi++) {
721
+ if (overlayFiberMeta[ofi].fiber === fiber) { ovIdx = ofi; break; }
722
+ }
723
+ }
724
+
725
+ if (!nextHidden && name === 'PressabilityDebugView') {
726
+ var hostFiber = fiber.return;
727
+ if (hostFiber && getMeasurable(hostFiber)) {
728
+ var pressableFiber = hostFiber;
729
+ var cur2 = hostFiber.return;
730
+ var upD = 0;
731
+ while (cur2 && upD < 10) {
732
+ if (typeof cur2.type !== 'string' && cur2.type !== null) {
733
+ var cn = getComponentName(cur2);
734
+ if (cn && PDV_OWNER_COMPONENT.test(cn)) { pressableFiber = cur2; break; }
735
+ }
736
+ cur2 = cur2.return;
737
+ upD++;
738
+ }
739
+ var pProps = pressableFiber.memoizedProps || {};
740
+ var hProps = hostFiber.memoizedProps || {};
741
+ var text = collectText(pressableFiber, 0);
742
+ var testID = hProps.testID || hProps.nativeID || pProps.testID || pProps.nativeID || null;
743
+ var a11y = hProps.accessibilityLabel || pProps.accessibilityLabel || null;
744
+ var baseLabel = a11y || (text && text.length > 0 ? text.slice(0, 80) : null) || null;
745
+ var label = resolveLabel(pressableFiber, hostFiber, baseLabel, testID);
746
+ var badgeOnly = baseLabel ? COUNT_BADGE.test(baseLabel.trim()) : false;
747
+ var icon = (baseLabel && !badgeOnly) ? null : findMeaningfulChildName(pressableFiber);
748
+ if (!baseLabel && !icon) {
749
+ var ownName = getComponentName(pressableFiber);
750
+ if (ownName && !GENERIC_COMPONENT.test(ownName) && !RN_PRIMITIVES.test(ownName)) icon = ownName;
751
+ }
752
+ var hostIdx = hostFibers.length;
753
+ hostFibers.push(hostFiber);
754
+ var pressFn = (typeof pProps.onPress === 'function' && pProps.onPress) || (typeof hProps.onPress === 'function' && hProps.onPress) || null;
755
+ fiberMeta.push({ label: label, testID: testID, hostIdx: hostIdx, icon: icon, overlayIdx: ovIdx, component: resolveComponentName(pressableFiber), hasOwnLabel: !!baseLabel, handler: pressFn ? handlerHint(pressFn) : null, propHandlers: collectPropHandlers(pressableFiber, pressFn) });
756
+ }
757
+ return;
758
+ }
759
+
760
+ // Fallback: onPress-based detection when PDV not present (production builds)
761
+ if (!nextHidden && props && typeof props.onPress === 'function') {
762
+ var hosts3 = [];
763
+ findHostsInSubtree(fiber, 0, hosts3, 8);
764
+ if (hosts3.length > 0) {
765
+ var p2 = fiber.memoizedProps || {};
766
+ var text2 = collectText(fiber, 0);
767
+ var a11y2 = p2.accessibilityLabel || null;
768
+ var testID2 = p2.testID || p2.nativeID || null;
769
+ var baseLabel2 = a11y2 || (text2 && text2.length > 0 ? text2.slice(0, 80) : null) || null;
770
+ var label2 = resolveLabel(fiber, hosts3[0], baseLabel2, testID2);
771
+ var badgeOnly2 = baseLabel2 ? COUNT_BADGE.test(baseLabel2.trim()) : false;
772
+ var icon2 = (baseLabel2 && !badgeOnly2) ? null : findMeaningfulChildName(fiber);
773
+ if (!baseLabel2 && !icon2) {
774
+ var ownName2 = getComponentName(fiber);
775
+ if (ownName2 && !GENERIC_COMPONENT.test(ownName2) && !RN_PRIMITIVES.test(ownName2)) icon2 = ownName2;
776
+ }
777
+ var hostIdx2 = hostFibers.length;
778
+ hostFibers.push(hosts3[0]);
779
+ fiberMeta.push({ label: label2, testID: testID2, hostIdx: hostIdx2, icon: icon2, overlayIdx: ovIdx, component: resolveComponentName(fiber), hasOwnLabel: !!baseLabel2, handler: handlerHint(props.onPress), propHandlers: collectPropHandlers(fiber, props.onPress) });
780
+ }
781
+ }
782
+
783
+ // TextInputs — not covered by PressabilityDebugView or onPress. Label falls
784
+ // back to the placeholder so empty form fields stay identifiable.
785
+ if (!nextHidden && props && typeof props.onPress !== 'function' &&
786
+ (typeof props.onChangeText === 'function' || typeof props.onFocus === 'function')) {
787
+ var hostsI = [];
788
+ findHostsInSubtree(fiber, 0, hostsI, 8);
789
+ if (hostsI.length > 0) {
790
+ var pI = fiber.memoizedProps || {};
791
+ var textI = collectText(fiber, 0);
792
+ var placeholderI = (typeof pI.placeholder === 'string' && pI.placeholder.length > 0) ? pI.placeholder : null;
793
+ var testIDI = pI.testID || pI.nativeID || null;
794
+ var baseLabelI = pI.accessibilityLabel || (textI && textI.length > 0 ? textI.slice(0, 80) : null) || (placeholderI ? placeholderI.slice(0, 80) : null) || null;
795
+ var labelI = resolveLabel(fiber, hostsI[0], baseLabelI, testIDI);
796
+ var iconI = baseLabelI ? null : findMeaningfulChildName(fiber);
797
+ var hostIdxI = hostFibers.length;
798
+ hostFibers.push(hostsI[0]);
799
+ fiberMeta.push({ label: labelI, testID: testIDI, hostIdx: hostIdxI, icon: iconI, overlayIdx: ovIdx, component: resolveComponentName(fiber), isInput: true, hasOwnLabel: !!baseLabelI });
800
+ }
801
+ }
802
+
803
+ var child = fiber.child;
804
+ while (child) {
805
+ walkPressabilityDebugViews(child, depth + 1, nextHidden, ovIdx);
806
+ child = child.sibling;
807
+ }
808
+ }
809
+ walkPressabilityDebugViews(roots[0].current, 0, false, null);
810
+
811
+ // ------------------------------------------------------------------
812
+ // 3b. Standalone texts — proximity labels for icon-only pressables
813
+ // (checkbox/radio rows where the label is a sibling Text)
814
+ // ------------------------------------------------------------------
815
+
816
+ var textFibers = [];
817
+ var textContents = [];
818
+ var textOverlayIdx = [];
819
+
820
+ function extractTextString(fiber) {
821
+ var p = fiber.memoizedProps;
822
+ if (!p) return '';
823
+ var ch = p.children;
824
+ if (typeof ch === 'string') return ch;
825
+ if (typeof ch === 'number') return String(ch);
826
+ if (Array.isArray(ch)) {
827
+ var parts = [];
828
+ for (var k = 0; k < ch.length; k++) {
829
+ if (typeof ch[k] === 'string') parts.push(ch[k]);
830
+ else if (typeof ch[k] === 'number') parts.push(String(ch[k]));
831
+ }
832
+ if (parts.length > 0) return parts.join('');
833
+ }
834
+ return '';
835
+ }
836
+
837
+ function walkTexts(fiber, depth, insidePressable, inHidden, ovIdx) {
838
+ if (!fiber || depth > 5000) return;
839
+ var name = getComponentName(fiber);
840
+ var props = fiber.memoizedProps;
841
+ var nextHidden = inHidden || isScreenHidden(name, props);
842
+
843
+ // Overlay membership by ancestry (same as the pressable walk) so a sheet's
844
+ // text is grouped with the sheet, not flagged as blocked behind it.
845
+ if (ovIdx == null) {
846
+ for (var ofiT = 0; ofiT < overlayFiberMeta.length; ofiT++) {
847
+ if (overlayFiberMeta[ofiT].fiber === fiber) { ovIdx = ofiT; break; }
848
+ }
849
+ }
850
+
851
+ var hasOnPress = props && typeof props.onPress === 'function';
852
+ var isInputHere = props && (typeof props.onChangeText === 'function' || typeof props.onFocus === 'function');
853
+ var nextInside = insidePressable || !!hasOnPress || !!isInputHere;
854
+
855
+ // Record standalone text when outside any pressable — its own text already
856
+ // labels the pressable it belongs to. Climb to the nearest measurable host
857
+ // for proxy bounds (Fabric RCTText has no publicInstance).
858
+ if (!insidePressable && !nextHidden && name !== 'RCTText' && typeof fiber.type !== 'string') {
859
+ var str = extractTextString(fiber);
860
+ if (str && str.length > 0 && str.length <= 300) {
861
+ var up = fiber;
862
+ var upDepth = 0;
863
+ var measurableT = null;
864
+ while (up && upDepth < 20) {
865
+ if (typeof up.type === 'string' && getMeasurable(up)) {
866
+ measurableT = up;
867
+ break;
868
+ }
869
+ up = up.return;
870
+ upDepth++;
871
+ }
872
+ if (measurableT) {
873
+ textFibers.push(measurableT);
874
+ textContents.push(str);
875
+ textOverlayIdx.push(ovIdx);
876
+ }
877
+ }
878
+ }
879
+
880
+ var child = fiber.child;
881
+ while (child) {
882
+ walkTexts(child, depth + 1, nextInside, nextHidden, ovIdx);
883
+ child = child.sibling;
884
+ }
885
+ }
886
+ walkTexts(roots[0].current, 0, false, false, null);
887
+
888
+ // ------------------------------------------------------------------
889
+ // 3c. Images — host image components, with source + a11y label. Climb to
890
+ // the nearest measurable host (same proxy-bounds trick as text).
891
+ // ------------------------------------------------------------------
892
+
893
+ var imageFibers = [];
894
+ var imageMeta = []; // { src, alt }
895
+ var IMG_NAME = /^(Image|RCTImageView|ExpoImage|FastImage|ImageBackground)$/;
896
+
897
+ function imageSource(props) {
898
+ if (!props) return null;
899
+ var s = props.source;
900
+ if (s == null) return null;
901
+ if (Array.isArray(s)) s = s[0];
902
+ if (typeof s === 'number') return 'asset#' + s;
903
+ if (s && typeof s === 'object' && typeof s.uri === 'string') {
904
+ return s.uri.length > 200 ? s.uri.slice(0, 200) : s.uri;
905
+ }
906
+ if (typeof s === 'string') return s.length > 200 ? s.slice(0, 200) : s;
907
+ return null;
908
+ }
909
+
910
+ function walkImages(fiber, depth, inHidden, ovIdx) {
911
+ if (!fiber || depth > 5000) return;
912
+ var name = getComponentName(fiber);
913
+ var props = fiber.memoizedProps;
914
+ var nextHidden = inHidden || isScreenHidden(name, props);
915
+ if (ovIdx == null) {
916
+ for (var ofiI = 0; ofiI < overlayFiberMeta.length; ofiI++) {
917
+ if (overlayFiberMeta[ofiI].fiber === fiber) { ovIdx = ofiI; break; }
918
+ }
919
+ }
920
+ if (!nextHidden && name && IMG_NAME.test(name) && typeof fiber.type !== 'string') {
921
+ var up = fiber;
922
+ var upD = 0;
923
+ var measurableI = null;
924
+ while (up && upD < 20) {
925
+ if (typeof up.type === 'string' && getMeasurable(up)) { measurableI = up; break; }
926
+ up = up.return;
927
+ upD++;
928
+ }
929
+ if (measurableI) {
930
+ imageFibers.push(measurableI);
931
+ imageMeta.push({
932
+ src: imageSource(props),
933
+ alt: (props && typeof props.accessibilityLabel === 'string') ? props.accessibilityLabel.slice(0, 80) : null,
934
+ overlayIdx: ovIdx
935
+ });
936
+ }
937
+ }
938
+ var child = fiber.child;
939
+ while (child) { walkImages(child, depth + 1, nextHidden, ovIdx); child = child.sibling; }
940
+ }
941
+ walkImages(roots[0].current, 0, false, null);
942
+
943
+ // ------------------------------------------------------------------
944
+ // 4. Store everything in globalThis for the resolve call
945
+ // ------------------------------------------------------------------
946
+
947
+ // Store overlay host fibers separately
948
+ var overlayHostFibers = [];
949
+ var overlayMetaList = overlayFiberMeta.map(function(om) {
950
+ var startIdx = overlayHostFibers.length;
951
+ for (var hi = 0; hi < om.hostFibers.length; hi++) {
952
+ overlayHostFibers.push(om.hostFibers[hi]);
953
+ }
954
+ var title = collectText(om.fiber, 0);
955
+ return {
956
+ type: om.type,
957
+ title: (title && title.length > 2) ? title.slice(0, 60) : null,
958
+ hostStart: startIdx,
959
+ hostEnd: overlayHostFibers.length
960
+ };
961
+ });
962
+
963
+ // Measure root for viewport
964
+ var rootIdx = -1;
965
+ if (rootHostFiber) {
966
+ rootIdx = hostFibers.length;
967
+ hostFibers.push(rootHostFiber);
968
+ }
969
+
970
+ globalThis.__screenStateFibers = hostFibers;
971
+ globalThis.__screenStateMeta = fiberMeta;
972
+ globalThis.__screenStateMeasurements = new Array(hostFibers.length).fill(null);
973
+ globalThis.__screenStateRootIdx = rootIdx;
974
+ globalThis.__screenStateRoute = route;
975
+ globalThis.__screenStateOverlayHostFibers = overlayHostFibers;
976
+ globalThis.__screenStateOverlayMeta = overlayMetaList;
977
+ globalThis.__screenStateOverlayMeasurements = new Array(overlayHostFibers.length).fill(null);
978
+ globalThis.__screenStateTextContents = textContents;
979
+ globalThis.__screenStateTextMeasurements = new Array(textFibers.length).fill(null);
980
+ globalThis.__screenStateTextOverlayIdx = textOverlayIdx;
981
+ globalThis.__screenStateImageMeta = imageMeta;
982
+ globalThis.__screenStateImageMeasurements = new Array(imageFibers.length).fill(null);
983
+
984
+ // Dispatch all measureInWindow calls (pressables + root + overlay hosts)
985
+ for (var i = 0; i < hostFibers.length; i++) {
986
+ try {
987
+ (function(idx) {
988
+ getMeasurable(hostFibers[idx]).measureInWindow(function(fx, fy, fw, fh) {
989
+ globalThis.__screenStateMeasurements[idx] = { x: fx, y: fy, width: fw, height: fh };
990
+ });
991
+ })(i);
992
+ } catch(e) {}
993
+ }
994
+ for (var oi = 0; oi < overlayHostFibers.length; oi++) {
995
+ try {
996
+ (function(idx) {
997
+ getMeasurable(overlayHostFibers[idx]).measureInWindow(function(fx, fy, fw, fh) {
998
+ globalThis.__screenStateOverlayMeasurements[idx] = { x: fx, y: fy, width: fw, height: fh };
999
+ });
1000
+ })(oi);
1001
+ } catch(e) {}
1002
+ }
1003
+ for (var txi = 0; txi < textFibers.length; txi++) {
1004
+ try {
1005
+ (function(idx) {
1006
+ getMeasurable(textFibers[idx]).measureInWindow(function(fx, fy, fw, fh) {
1007
+ globalThis.__screenStateTextMeasurements[idx] = { x: fx, y: fy, width: fw, height: fh };
1008
+ });
1009
+ })(txi);
1010
+ } catch(e) {}
1011
+ }
1012
+ for (var imi = 0; imi < imageFibers.length; imi++) {
1013
+ try {
1014
+ (function(idx) {
1015
+ getMeasurable(imageFibers[idx]).measureInWindow(function(fx, fy, fw, fh) {
1016
+ globalThis.__screenStateImageMeasurements[idx] = { x: fx, y: fy, width: fw, height: fh };
1017
+ });
1018
+ })(imi);
1019
+ } catch(e) {}
1020
+ }
1021
+
1022
+ return { count: hostFibers.length, overlayCount: overlayFiberMeta.length };
1023
+ })()
1024
+ `;
1025
+ const dispatchResult = await executeInApp(dispatchExpression, false, { timeoutMs: 30000, originatingToolName: "get_screen_state" }, device);
1026
+ if (!dispatchResult.success)
1027
+ return dispatchResult;
1028
+ try {
1029
+ const dp = JSON.parse(dispatchResult.result || "{}");
1030
+ if (dp.error)
1031
+ return { success: false, error: dp.error };
1032
+ }
1033
+ catch { /* ignore */ }
1034
+ await delay(300);
1035
+ const resolveExpression = `
1036
+ (function() {
1037
+ var hostFibers = globalThis.__screenStateFibers;
1038
+ var meta = globalThis.__screenStateMeta;
1039
+ var measurements = globalThis.__screenStateMeasurements;
1040
+ var rootIdx = globalThis.__screenStateRootIdx;
1041
+ var route = globalThis.__screenStateRoute;
1042
+ var overlayMeta = globalThis.__screenStateOverlayMeta || [];
1043
+ var overlayMeasurements = globalThis.__screenStateOverlayMeasurements || [];
1044
+ var textContents = globalThis.__screenStateTextContents || [];
1045
+ var textMeasurements = globalThis.__screenStateTextMeasurements || [];
1046
+ var textOverlayIdx = globalThis.__screenStateTextOverlayIdx || [];
1047
+ var imageMeta = globalThis.__screenStateImageMeta || [];
1048
+ var imageMeasurements = globalThis.__screenStateImageMeasurements || [];
1049
+ globalThis.__screenStateTextContents = null;
1050
+ globalThis.__screenStateTextMeasurements = null;
1051
+ globalThis.__screenStateTextOverlayIdx = null;
1052
+ globalThis.__screenStateImageMeta = null;
1053
+ globalThis.__screenStateImageMeasurements = null;
1054
+ globalThis.__screenStateFibers = null;
1055
+ globalThis.__screenStateMeta = null;
1056
+ globalThis.__screenStateMeasurements = null;
1057
+ globalThis.__screenStateRootIdx = null;
1058
+ globalThis.__screenStateRoute = null;
1059
+ globalThis.__screenStateOverlayHostFibers = null;
1060
+ globalThis.__screenStateOverlayMeta = null;
1061
+ globalThis.__screenStateOverlayMeasurements = null;
1062
+
1063
+ if (!hostFibers || !measurements || !meta) {
1064
+ return { error: 'No measurement data. Run get_screen_state again.' };
1065
+ }
1066
+
1067
+ // Viewport
1068
+ var viewportW = 9999, viewportH = 9999;
1069
+ var rootM = (rootIdx != null && rootIdx >= 0) ? measurements[rootIdx] : null;
1070
+ if (rootM && rootM.width > 0 && rootM.height > 0) {
1071
+ viewportW = rootM.width;
1072
+ viewportH = rootM.height + (rootM.y > 0 ? rootM.y : 0);
1073
+ }
1074
+
1075
+ // Build overlay bounds by unioning their host measurements.
1076
+ // blockBounds: union of ALL hosts (incl. full-screen backdrop) — what the overlay
1077
+ // visually blocks; used to exclude unreachable root pressables.
1078
+ // contentBounds: union excluding near-viewport-sized hosts (backdrops) — the
1079
+ // actual panel; used as geometric fallback for portaled overlay content.
1080
+ var overlays = [];
1081
+ var vArea = viewportW * viewportH;
1082
+ for (var oi = 0; oi < overlayMeta.length; oi++) {
1083
+ var om = overlayMeta[oi];
1084
+ var bMinX = Infinity, bMinY = Infinity, bMaxX = -Infinity, bMaxY = -Infinity, bValid = false;
1085
+ var cMinX = Infinity, cMinY = Infinity, cMaxX = -Infinity, cMaxY = -Infinity, cValid = false;
1086
+ for (var hi = om.hostStart; hi < om.hostEnd; hi++) {
1087
+ var mm = overlayMeasurements[hi];
1088
+ if (!mm || mm.width <= 0 || mm.height <= 0) continue;
1089
+ bValid = true;
1090
+ if (mm.x < bMinX) bMinX = mm.x;
1091
+ if (mm.y < bMinY) bMinY = mm.y;
1092
+ if (mm.x + mm.width > bMaxX) bMaxX = mm.x + mm.width;
1093
+ if (mm.y + mm.height > bMaxY) bMaxY = mm.y + mm.height;
1094
+ if (mm.width * mm.height >= vArea * 0.9) continue; // backdrop-sized → block only
1095
+ cValid = true;
1096
+ if (mm.x < cMinX) cMinX = mm.x;
1097
+ if (mm.y < cMinY) cMinY = mm.y;
1098
+ if (mm.x + mm.width > cMaxX) cMaxX = mm.x + mm.width;
1099
+ if (mm.y + mm.height > cMaxY) cMaxY = mm.y + mm.height;
1100
+ }
1101
+ if (!bValid) continue;
1102
+ var blockBounds = { x: Math.round(bMinX), y: Math.round(bMinY), width: Math.round(bMaxX - bMinX), height: Math.round(bMaxY - bMinY) };
1103
+ // When every host is backdrop-sized (gorhom sheets measure only full-screen
1104
+ // containers), there is no usable content rect — geometric fallback would
1105
+ // swallow the underlying screen's pressables, so it is disabled (hasContent).
1106
+ var contentBounds = cValid
1107
+ ? { x: Math.round(cMinX), y: Math.round(cMinY), width: Math.round(cMaxX - cMinX), height: Math.round(cMaxY - cMinY) }
1108
+ : blockBounds;
1109
+ overlays.push({ origIdx: oi, type: om.type, title: om.title, blockBounds: blockBounds, contentBounds: contentBounds, hasContent: cValid, pressables: [] });
1110
+ }
1111
+
1112
+ // Build pressable list
1113
+ var allPressables = [];
1114
+ for (var i = 0; i < meta.length; i++) {
1115
+ if (i === rootIdx) continue;
1116
+ var m = measurements[i];
1117
+ if (!m || m.width <= 0 || m.height <= 0) continue;
1118
+ if (m.x + m.width < 0 || m.y + m.height < 0) continue;
1119
+ if (m.x > viewportW || m.y > viewportH) continue;
1120
+ allPressables.push({
1121
+ label: meta[i].label,
1122
+ component: meta[i].component || null,
1123
+ center: { x: Math.round(m.x + m.width / 2), y: Math.round(m.y + m.height / 2) },
1124
+ bounds: { x: Math.round(m.x), y: Math.round(m.y), width: Math.round(m.width), height: Math.round(m.height) },
1125
+ testID: meta[i].testID,
1126
+ icon: meta[i].icon || null,
1127
+ isInput: !!meta[i].isInput,
1128
+ overlayIdx: (meta[i].overlayIdx != null ? meta[i].overlayIdx : null),
1129
+ hasOwnLabel: !!meta[i].hasOwnLabel,
1130
+ handler: meta[i].handler || null,
1131
+ propHandlers: meta[i].propHandlers || null
1132
+ });
1133
+ }
1134
+
1135
+ // Attach nearbyText to pressables without their own text/a11y label.
1136
+ // Row siblings first (checkbox labels), center distance as fallback.
1137
+ var textBoxes = [];
1138
+ for (var tmi = 0; tmi < textMeasurements.length; tmi++) {
1139
+ var tm = textMeasurements[tmi];
1140
+ var tc = textContents[tmi];
1141
+ if (!tm || !tc || tm.width <= 0 || tm.height <= 0) continue;
1142
+ if (tm.x + tm.width < 0 || tm.y + tm.height < 0) continue;
1143
+ if (tm.x > viewportW || tm.y > viewportH) continue;
1144
+ textBoxes.push({ text: tc, x: tm.x, y: tm.y, width: tm.width, height: tm.height, cx: tm.x + tm.width / 2, cy: tm.y + tm.height / 2 });
1145
+ }
1146
+ for (var ni = 0; ni < allPressables.length; ni++) {
1147
+ var pn = allPressables[ni];
1148
+ if (pn.hasOwnLabel || textBoxes.length === 0) continue;
1149
+ var bestT = null;
1150
+ var bestD = Infinity;
1151
+ for (var tbi = 0; tbi < textBoxes.length; tbi++) {
1152
+ var tb = textBoxes[tbi];
1153
+ if (tb.x >= pn.bounds.x && tb.y >= pn.bounds.y &&
1154
+ tb.x + tb.width <= pn.bounds.x + pn.bounds.width &&
1155
+ tb.y + tb.height <= pn.bounds.y + pn.bounds.height) continue;
1156
+ var rowAligned = Math.abs(tb.cy - pn.center.y) <= Math.max(24, pn.bounds.height / 2);
1157
+ var gapL = pn.bounds.x - (tb.x + tb.width);
1158
+ var gapR = tb.x - (pn.bounds.x + pn.bounds.width);
1159
+ var hGap = Math.max(gapL, gapR);
1160
+ if (hGap < 0) hGap = 0;
1161
+ var d;
1162
+ if (rowAligned && hGap <= 80) {
1163
+ d = hGap;
1164
+ } else {
1165
+ var dxT = tb.cx - pn.center.x;
1166
+ var dyT = tb.cy - pn.center.y;
1167
+ d = Math.sqrt(dxT * dxT + dyT * dyT);
1168
+ if (d > 120) continue;
1169
+ }
1170
+ if (d < bestD) { bestD = d; bestT = tb; }
1171
+ }
1172
+ if (bestT) pn.nearbyText = bestT.text.slice(0, 80);
1173
+ }
1174
+
1175
+ // Assign pressables to overlays vs root:
1176
+ // 1. fiber ancestry (pressable rendered inside the overlay subtree)
1177
+ // 2. geometric containment in contentBounds (portaled overlay content)
1178
+ // 3. fully covered by blockBounds (incl. backdrop) → unreachable, drop
1179
+ // 4. otherwise root
1180
+ var rootPressables = [];
1181
+ function inside(b, ob) {
1182
+ return b.x >= ob.x && b.y >= ob.y &&
1183
+ b.x + b.width <= ob.x + ob.width &&
1184
+ b.y + b.height <= ob.y + ob.height;
1185
+ }
1186
+ for (var pi = 0; pi < allPressables.length; pi++) {
1187
+ var p = allPressables[pi];
1188
+ var assignedToOverlay = false;
1189
+ for (var ov = 0; ov < overlays.length; ov++) {
1190
+ if (p.overlayIdx === overlays[ov].origIdx ||
1191
+ (p.overlayIdx == null && overlays[ov].hasContent && inside(p.bounds, overlays[ov].contentBounds))) {
1192
+ overlays[ov].pressables.push(p);
1193
+ assignedToOverlay = true;
1194
+ break;
1195
+ }
1196
+ }
1197
+ if (!assignedToOverlay) {
1198
+ // Covered pressables stay in the list but are flagged — agents see what's
1199
+ // behind the sheet while knowing taps won't reach it until it closes.
1200
+ for (var ov2 = 0; ov2 < overlays.length; ov2++) {
1201
+ if (inside(p.bounds, overlays[ov2].blockBounds)) { p.blockedByOverlay = true; break; }
1202
+ }
1203
+ rootPressables.push(p);
1204
+ }
1205
+ }
1206
+ for (var si = 0; si < allPressables.length; si++) {
1207
+ delete allPressables[si].overlayIdx;
1208
+ delete allPressables[si].hasOwnLabel;
1209
+ }
1210
+
1211
+ // Build typed text/image lists (pair each measurement with its meta by index,
1212
+ // viewport-filter) and assign each to a reachability group via the same overlay
1213
+ // logic used for pressables (content containment vs blocking backdrop).
1214
+ var rootTexts = [], rootImages = [];
1215
+ for (var ov = 0; ov < overlays.length; ov++) { overlays[ov].texts = []; overlays[ov].images = []; }
1216
+ // Group an item: by fiber ancestry (overlayIdx) first — a sheet's own text/image
1217
+ // belongs to the sheet; else geometric containment in an overlay's content; else
1218
+ // root, flagged blocked when it sits under a blocking overlay (the screen behind).
1219
+ function pushClassified(entry, kind, ovIdx) {
1220
+ for (var a = 0; a < overlays.length; a++) {
1221
+ if (ovIdx != null && ovIdx === overlays[a].origIdx) { overlays[a][kind].push(entry); return; }
1222
+ }
1223
+ for (var c = 0; c < overlays.length; c++) {
1224
+ if (overlays[c].hasContent && inside(entry.bounds, overlays[c].contentBounds)) { overlays[c][kind].push(entry); return; }
1225
+ }
1226
+ var blk = false;
1227
+ for (var b = 0; b < overlays.length; b++) { if (inside(entry.bounds, overlays[b].blockBounds)) { blk = true; break; } }
1228
+ if (blk) entry.blockedByOverlay = true;
1229
+ (kind === 'texts' ? rootTexts : rootImages).push(entry);
1230
+ }
1231
+
1232
+ for (var ti = 0; ti < textContents.length; ti++) {
1233
+ var tm = textMeasurements[ti];
1234
+ if (!tm || tm.width <= 0 || tm.height <= 0) continue;
1235
+ if (tm.x + tm.width < 0 || tm.y + tm.height < 0) continue;
1236
+ if (tm.x > viewportW || tm.y > viewportH) continue;
1237
+ pushClassified({ text: textContents[ti],
1238
+ center: { x: Math.round(tm.x + tm.width/2), y: Math.round(tm.y + tm.height/2) },
1239
+ bounds: { x: Math.round(tm.x), y: Math.round(tm.y), width: Math.round(tm.width), height: Math.round(tm.height) } }, 'texts', textOverlayIdx[ti]);
1240
+ }
1241
+ for (var ii = 0; ii < imageMeta.length; ii++) {
1242
+ var im = imageMeasurements[ii];
1243
+ if (!im || im.width <= 0 || im.height <= 0) continue;
1244
+ if (im.x + im.width < 0 || im.y + im.height < 0) continue;
1245
+ if (im.x > viewportW || im.y > viewportH) continue;
1246
+ pushClassified({ src: imageMeta[ii].src, alt: imageMeta[ii].alt,
1247
+ center: { x: Math.round(im.x + im.width/2), y: Math.round(im.y + im.height/2) },
1248
+ bounds: { x: Math.round(im.x), y: Math.round(im.y), width: Math.round(im.width), height: Math.round(im.height) } }, 'images', imageMeta[ii].overlayIdx);
1249
+ }
1250
+
1251
+ // Sort visually (top-to-bottom, left-to-right) — walk order is mount order,
1252
+ // which puts late-mounted overlays like floating headers at the end.
1253
+ function byPosition(a, b) {
1254
+ if (a.center.y !== b.center.y) return a.center.y - b.center.y;
1255
+ return a.center.x - b.center.x;
1256
+ }
1257
+ rootPressables.sort(byPosition);
1258
+ rootTexts.sort(byPosition);
1259
+ rootImages.sort(byPosition);
1260
+ for (var so = 0; so < overlays.length; so++) {
1261
+ overlays[so].pressables.sort(byPosition);
1262
+ overlays[so].texts.sort(byPosition);
1263
+ overlays[so].images.sort(byPosition);
1264
+ }
1265
+
1266
+ // Strip bounds from overlay objects (not in public interface)
1267
+ var cleanOverlays = overlays.map(function(o) {
1268
+ return { type: o.type, title: o.title, pressables: o.pressables, texts: o.texts, images: o.images };
1269
+ });
1270
+
1271
+ return { route: route, overlays: cleanOverlays, pressables: rootPressables, texts: rootTexts, images: rootImages };
1272
+ })()
1273
+ `;
1274
+ const resolveResult = await executeInApp(resolveExpression, false, { timeoutMs: 15000, originatingToolName: "get_screen_state" }, device);
1275
+ if (!resolveResult.success)
1276
+ return resolveResult;
1277
+ let screenState;
1278
+ try {
1279
+ const parsed = JSON.parse(resolveResult.result || "{}");
1280
+ if (parsed.error)
1281
+ return { success: false, error: parsed.error };
1282
+ screenState = parseScreenStateResponse(parsed) ?? undefined;
1283
+ }
1284
+ catch {
1285
+ return { success: false, error: "Failed to parse screen state response" };
1286
+ }
1287
+ if (!screenState)
1288
+ return { success: false, error: "Empty screen state response" };
1289
+ // Deduplicate pressables by center coordinates (PDV + onPress fallback can both fire)
1290
+ const dedupPressables = (list) => {
1291
+ const seen = new Set();
1292
+ return list.filter((p) => {
1293
+ const key = `${p.center.x},${p.center.y}`;
1294
+ if (seen.has(key))
1295
+ return false;
1296
+ seen.add(key);
1297
+ return true;
1298
+ });
1299
+ };
1300
+ screenState.pressables = dedupPressables(screenState.pressables);
1301
+ for (const overlay of screenState.overlays) {
1302
+ overlay.pressables = dedupPressables(overlay.pressables);
1303
+ }
1304
+ // Dedup texts/images: a single visual element often maps to nested host nodes
1305
+ // (Image > ExpoImage) or repeated text spans that all measure to the same box.
1306
+ const dedupBy = (list, keyExtra) => {
1307
+ const seen = new Set();
1308
+ return list.filter((item) => {
1309
+ const key = `${item.center.x},${item.center.y}|${keyExtra(item)}`;
1310
+ if (seen.has(key))
1311
+ return false;
1312
+ seen.add(key);
1313
+ return true;
1314
+ });
1315
+ };
1316
+ screenState.texts = dedupBy(screenState.texts, (t) => t.text);
1317
+ screenState.images = dedupBy(screenState.images, (i) => i.src ?? "");
1318
+ for (const overlay of screenState.overlays) {
1319
+ if (overlay.texts)
1320
+ overlay.texts = dedupBy(overlay.texts, (t) => t.text);
1321
+ if (overlay.images)
1322
+ overlay.images = dedupBy(overlay.images, (i) => i.src ?? "");
1323
+ }
1324
+ // Semantic icon hints + onPress handler hints
1325
+ const decorate = (p) => {
1326
+ applyIconHintToLabel(p);
1327
+ const direct = describePressHandler(p.handler);
1328
+ const hint = direct ? `onPress=${direct}` : describePropHandlers(p.propHandlers);
1329
+ if (hint)
1330
+ p.onPressHint = hint;
1331
+ delete p.handler;
1332
+ delete p.propHandlers;
1333
+ };
1334
+ screenState.pressables.forEach(decorate);
1335
+ for (const overlay of screenState.overlays) {
1336
+ overlay.pressables.forEach(decorate);
1337
+ }
1338
+ // Apply TS-side overlay marking as a safety pass
1339
+ for (const overlay of screenState.overlays) {
1340
+ if (overlay.pressables.length === 0)
1341
+ continue;
1342
+ const minX = Math.min(...overlay.pressables.map((p) => p.bounds.x));
1343
+ const minY = Math.min(...overlay.pressables.map((p) => p.bounds.y));
1344
+ const maxX = Math.max(...overlay.pressables.map((p) => p.bounds.x + p.bounds.width));
1345
+ const maxY = Math.max(...overlay.pressables.map((p) => p.bounds.y + p.bounds.height));
1346
+ const overlayBounds = { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
1347
+ markPressablesCoveredByOverlay(screenState.pressables, overlayBounds);
1348
+ }
1349
+ const json = JSON.stringify(screenState, null, 2);
1350
+ return { success: true, result: json, screenState };
1351
+ }
1352
+ //# sourceMappingURL=screenState.js.map