rnxsim 0.1.366 → 0.1.367

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 (239) hide show
  1. package/README.md +14 -2
  2. package/cli/bin.ts +18 -0
  3. package/cli/bridge-flow-runner.ts +14 -151
  4. package/cli/commands/assert.ts +1 -1
  5. package/cli/commands/box/checkout-plane.ts +126 -0
  6. package/cli/commands/box/rnx-command.ts +68 -0
  7. package/cli/commands/box.ts +200 -0
  8. package/cli/commands/control.ts +12 -32
  9. package/cli/commands/do-chain.ts +412 -0
  10. package/cli/commands/flow.ts +0 -10
  11. package/cli/commands/inspect/core.ts +302 -725
  12. package/cli/commands/inspect/describe.ts +3 -76
  13. package/cli/commands/inspect/find.ts +3 -6
  14. package/cli/commands/inspect/get-layout.ts +14 -1
  15. package/cli/commands/inspect/resolve-target.ts +41 -47
  16. package/cli/commands/inspect/shared.ts +28 -123
  17. package/cli/commands/inspect/tree.ts +6 -15
  18. package/cli/commands/inspect/wait-ready.ts +2 -2
  19. package/cli/commands/inspect/wait-selector.ts +4 -8
  20. package/cli/commands/inspect.ts +23 -17
  21. package/cli/commands/install-desktop.ts +44 -7
  22. package/cli/commands/maestro-generate.ts +0 -2
  23. package/cli/commands/platform.ts +68 -0
  24. package/cli/commands/state.ts +5 -2
  25. package/cli/outbound-endpoints.ts +6 -1
  26. package/cli/parse-args.ts +13 -2
  27. package/cli/ws-bridge.ts +30 -2
  28. package/detox/index.ts +34 -17
  29. package/dist-cli/bin.js +5 -5
  30. package/dist-cli/chunks/{agent-SO6IOPRK.js → agent-EKKIAKP5.js} +2 -2
  31. package/dist-cli/chunks/{agent-wrapper-PMYCB2KO.js → agent-wrapper-MHLQUGA6.js} +2 -2
  32. package/dist-cli/chunks/{app-fonts-LULQGFY7.js → app-fonts-HN6ADRTQ.js} +2 -2
  33. package/dist-cli/chunks/{assert-WGNCD4ZU.js → assert-IMR6QCN6.js} +3 -3
  34. package/dist-cli/chunks/{auth-G7CCHH3M.js → auth-27LPMQNH.js} +2 -2
  35. package/dist-cli/chunks/{beta-N4LXL5TO.js → beta-6RXBB5AI.js} +2 -2
  36. package/dist-cli/chunks/box-DORLF3GP.js +1709 -0
  37. package/dist-cli/chunks/{camera-4JHCYBQS.js → camera-2G7JZ5DL.js} +2 -2
  38. package/dist-cli/chunks/{chunk-2UXU53MG.js → chunk-3QZJLNYY.js} +1 -1
  39. package/dist-cli/chunks/{chunk-YXXKSL6R.js → chunk-3VBVEDDA.js} +1 -1
  40. package/dist-cli/chunks/{chunk-ZJIS3CTW.js → chunk-4BWGLTKU.js} +2 -2
  41. package/dist-cli/chunks/chunk-4XSNO374.js +423 -0
  42. package/dist-cli/chunks/{chunk-RYIMSKDO.js → chunk-5DGMFUZG.js} +2 -2
  43. package/dist-cli/chunks/{chunk-M3BNCF7E.js → chunk-6DBS5EGX.js} +2 -2
  44. package/dist-cli/chunks/{chunk-ONORMKWX.js → chunk-6SO6I3D5.js} +2 -2
  45. package/dist-cli/chunks/chunk-75EFOPXE.js +32 -0
  46. package/dist-cli/chunks/{chunk-5NMCF5VF.js → chunk-A5AJFVOF.js} +1 -1
  47. package/dist-cli/chunks/{chunk-N3UC7HIX.js → chunk-AM2ODYAN.js} +1 -1
  48. package/dist-cli/chunks/{chunk-I6KIM6PN.js → chunk-AVOROGA3.js} +1 -1
  49. package/dist-cli/chunks/chunk-AXMMLO7D.js +130 -0
  50. package/dist-cli/chunks/{chunk-ORWP2E7R.js → chunk-BSEXEYNX.js} +2 -2
  51. package/dist-cli/chunks/{chunk-NQFJOCSF.js → chunk-CM6ZKZW7.js} +2 -2
  52. package/dist-cli/chunks/{chunk-ZMJ75EDG.js → chunk-DNVABCEC.js} +2 -2
  53. package/dist-cli/chunks/{chunk-2S7BKUP2.js → chunk-E33A4AIR.js} +2 -2
  54. package/dist-cli/chunks/{chunk-GXAB52K7.js → chunk-EFMOXYDD.js} +2 -2
  55. package/dist-cli/chunks/{chunk-TIAEYO6I.js → chunk-EV4P5UBP.js} +2 -2
  56. package/dist-cli/chunks/{chunk-JHXETDVC.js → chunk-G5IUIGGC.js} +1 -1
  57. package/dist-cli/chunks/chunk-GMLOCV3E.js +312 -0
  58. package/dist-cli/chunks/{chunk-ZLVRYXZ7.js → chunk-GRN2FHVW.js} +1 -1
  59. package/dist-cli/chunks/{chunk-A5FXX5PJ.js → chunk-HFFXPUEP.js} +1 -1
  60. package/dist-cli/chunks/chunk-HG6T4OOR.js +4 -0
  61. package/dist-cli/chunks/{chunk-OW5XHAA4.js → chunk-HNT2OXPZ.js} +1 -1
  62. package/dist-cli/chunks/chunk-IPEURNLI.js +24 -0
  63. package/dist-cli/chunks/chunk-IR44SFBA.js +5 -0
  64. package/dist-cli/chunks/chunk-JMSLXZFW.js +4 -0
  65. package/dist-cli/chunks/{chunk-EFR5DVNP.js → chunk-JPXQKLNH.js} +1 -1
  66. package/dist-cli/chunks/chunk-K3EC6JDE.js +4 -0
  67. package/dist-cli/chunks/{chunk-YGMEDJKJ.js → chunk-KHX65HAU.js} +2 -2
  68. package/dist-cli/chunks/{chunk-EQK5MJCU.js → chunk-LWOVKHRC.js} +2 -2
  69. package/dist-cli/chunks/{chunk-5OK3LCEJ.js → chunk-MQN5DWTI.js} +2 -2
  70. package/dist-cli/chunks/{chunk-TTASWLKM.js → chunk-N3BXQEUF.js} +1 -1
  71. package/dist-cli/chunks/{chunk-UCHW7ZHR.js → chunk-N5OSV26B.js} +2 -2
  72. package/dist-cli/chunks/chunk-PHNURIH3.js +4 -0
  73. package/dist-cli/chunks/{chunk-AFV32WZT.js → chunk-PP2KNVXP.js} +3 -3
  74. package/dist-cli/chunks/{chunk-XJU2QIRY.js → chunk-PROKNJVY.js} +2 -2
  75. package/dist-cli/chunks/chunk-QXLLY4IM.js +7 -0
  76. package/dist-cli/chunks/{chunk-HT6GFZOZ.js → chunk-RNQTOGM7.js} +1 -1
  77. package/dist-cli/chunks/{chunk-CN6XYYEA.js → chunk-RPNKKVBN.js} +27 -27
  78. package/dist-cli/chunks/{chunk-LN3RNW6X.js → chunk-RSNLI2NH.js} +2 -2
  79. package/dist-cli/chunks/{chunk-YCCCPFWT.js → chunk-RZGHV2WI.js} +2 -2
  80. package/dist-cli/chunks/chunk-SGGL3AFV.js +497 -0
  81. package/dist-cli/chunks/chunk-SH5ETJKG.js +4 -0
  82. package/dist-cli/chunks/{chunk-77ZHQJZR.js → chunk-T6J4YP56.js} +2 -2
  83. package/dist-cli/chunks/{chunk-MGDSJZ37.js → chunk-TWUE7WF5.js} +2 -2
  84. package/dist-cli/chunks/{chunk-SA6XVI55.js → chunk-U44VEQRN.js} +1 -1
  85. package/dist-cli/chunks/{chunk-IZKHOM37.js → chunk-URLVQHC3.js} +1 -1
  86. package/dist-cli/chunks/{chunk-GAJQSITE.js → chunk-VANZFTUE.js} +1 -1
  87. package/dist-cli/chunks/{chunk-EGAGZHO6.js → chunk-VB2YBH46.js} +1 -1
  88. package/dist-cli/chunks/{chunk-H23KWIKA.js → chunk-VFU2SJ7M.js} +2 -2
  89. package/dist-cli/chunks/{chunk-34IQM22N.js → chunk-VUBJ6FXU.js} +15 -15
  90. package/dist-cli/chunks/{chunk-NM2L2QV4.js → chunk-W5PATILQ.js} +2 -2
  91. package/dist-cli/chunks/chunk-WI5V4TYG.js +38 -0
  92. package/dist-cli/chunks/{chunk-6PL2CCGP.js → chunk-XTRHQAOV.js} +2 -2
  93. package/dist-cli/chunks/chunk-XWUTJLBM.js +27 -0
  94. package/dist-cli/chunks/{chunk-5DAIA77C.js → chunk-XYRUQQUR.js} +2 -2
  95. package/dist-cli/chunks/chunk-YBFB3RM7.js +4 -0
  96. package/dist-cli/chunks/chunk-YGQVQ2VG.js +4 -0
  97. package/dist-cli/chunks/{chunk-CTG7HBCA.js → chunk-YINACV32.js} +1 -1
  98. package/dist-cli/chunks/chunk-YV7ERO2V.js +5 -0
  99. package/dist-cli/chunks/{cleanup-KRIATKFH.js → cleanup-GVFHQ3KH.js} +2 -2
  100. package/dist-cli/chunks/cli-version-DPX5MA2M.js +4 -0
  101. package/dist-cli/chunks/{compat-6PTQ3QEA.js → compat-AYRTXYAM.js} +2 -2
  102. package/dist-cli/chunks/{config-ETGDUANO.js → config-K7LOOV62.js} +2 -2
  103. package/dist-cli/chunks/connect-H3CNY4IO.js +4 -0
  104. package/dist-cli/chunks/control-SMHZ2CF5.js +4 -0
  105. package/dist-cli/chunks/daemon-TEZUNI73.js +4 -0
  106. package/dist-cli/chunks/{debug-WIIB6ZKC.js → debug-ELGHG57T.js} +3 -3
  107. package/dist-cli/chunks/{desktop-TD7Q5LNB.js → desktop-4G7FK3MP.js} +3 -3
  108. package/dist-cli/chunks/{detox-7GNR33VM.js → detox-JKXGEJIZ.js} +2 -2
  109. package/dist-cli/chunks/{device-QOR3PGUF.js → device-IV3AR6KG.js} +2 -2
  110. package/dist-cli/chunks/{diagnose-RRCBLP6E.js → diagnose-3ERGF7EW.js} +2 -2
  111. package/dist-cli/chunks/{disk-cleanup-MJUGJPXT.js → disk-cleanup-ALFEVZ4B.js} +2 -2
  112. package/dist-cli/chunks/do-chain-K2B4OHM7.js +5 -0
  113. package/dist-cli/chunks/drivers-KJYXA3M3.js +4 -0
  114. package/dist-cli/chunks/env-2KF6IYZE.js +4 -0
  115. package/dist-cli/chunks/{film-D7Y64LID.js → film-UQXJFAD5.js} +3 -3
  116. package/dist-cli/chunks/flow-ASTUH56E.js +4 -0
  117. package/dist-cli/chunks/help-SNNYFELA.js +4 -0
  118. package/dist-cli/chunks/{hidden-runtime-alias-JGURVR2Z.js → hidden-runtime-alias-VJCWCFVO.js} +2 -2
  119. package/dist-cli/chunks/{home-paths-4ICFIGXO.js → home-paths-EGUZZ6J6.js} +2 -2
  120. package/dist-cli/chunks/inspect-XANAADQT.js +4 -0
  121. package/dist-cli/chunks/install-desktop-JKQA7UY6.js +4 -0
  122. package/dist-cli/chunks/{login-RU33QR2G.js → login-6KQGD7HK.js} +2 -2
  123. package/dist-cli/chunks/{logout-2IUG3Y5J.js → logout-2FCOVLBC.js} +2 -2
  124. package/dist-cli/chunks/{maestro-2MXTGG7I.js → maestro-HPSSEVJD.js} +3 -3
  125. package/dist-cli/chunks/{maestro-generate-2PYIFGLR.js → maestro-generate-KQQ6JHMR.js} +5 -5
  126. package/dist-cli/chunks/{mode-3DAPG3HF.js → mode-SH7KRZET.js} +2 -2
  127. package/dist-cli/chunks/{optional-demo-registry-BWSDJF2Z.js → optional-demo-registry-NAMCAVFX.js} +2 -2
  128. package/dist-cli/chunks/{perf-2TKPWB4N.js → perf-LWKAHXUL.js} +2 -2
  129. package/dist-cli/chunks/{permissions-5CSMHYNA.js → permissions-EZTKWTXV.js} +2 -2
  130. package/dist-cli/chunks/platform-KSOJIVN5.js +6 -0
  131. package/dist-cli/chunks/privacy-EJULWP7L.js +4 -0
  132. package/dist-cli/chunks/{record-I2HJCFP3.js → record-2IC7BAQN.js} +3 -3
  133. package/dist-cli/chunks/{report-issue-A4FZWBOC.js → report-issue-MMX6HOQO.js} +2 -2
  134. package/dist-cli/chunks/reset-PKFZA4NC.js +4 -0
  135. package/dist-cli/chunks/resolve-target-AFKU3BRE.js +4 -0
  136. package/dist-cli/chunks/runtime-XHWWPOIN.js +4 -0
  137. package/dist-cli/chunks/{screenshot-command-UFW5BFHP.js → screenshot-command-JYUXDVSA.js} +3 -3
  138. package/dist-cli/chunks/{screenshot-layers-5BIAL4YN.js → screenshot-layers-OGRY6AA3.js} +2 -2
  139. package/dist-cli/chunks/{screenshots-capture-EHYS3BV2.js → screenshots-capture-QHDN65XS.js} +2 -2
  140. package/dist-cli/chunks/{serve-O4FDM3AC.js → serve-W4BKAG4J.js} +3 -3
  141. package/dist-cli/chunks/setup-WJPMPSAC.js +4 -0
  142. package/dist-cli/chunks/sim-client-UOQGFBPO.js +4 -0
  143. package/dist-cli/chunks/{skills-ZK55SY32.js → skills-OPPXOD63.js} +2 -2
  144. package/dist-cli/chunks/state-TDAN7BOM.js +14 -0
  145. package/dist-cli/chunks/{storage-WP33ISEM.js → storage-CFB2YGLY.js} +2 -2
  146. package/dist-cli/chunks/store-4TEED4ZU.js +4 -0
  147. package/dist-cli/chunks/telemetry-S6N7CV6G.js +4 -0
  148. package/dist-cli/chunks/{timeline-DKGW5S4I.js → timeline-ASOOVP4C.js} +2 -2
  149. package/dist-cli/chunks/{upgrade-LL7G4B7G.js → upgrade-6MVJISHG.js} +2 -2
  150. package/dist-cli/chunks/upload-CBNIRFEW.js +4 -0
  151. package/dist-cli/chunks/{version-YLWR5G4F.js → version-5GS7CWRL.js} +2 -2
  152. package/dist-cli/chunks/{web-QELZ4CP6.js → web-QRRMYMV4.js} +2 -2
  153. package/dist-cli/chunks/welcome-33FXMAMB.js +5 -0
  154. package/dist-cli/chunks/{what-happened-MIOMZWM5.js → what-happened-GAZJGKXX.js} +2 -2
  155. package/dist-cli/chunks/ws-bridge-DIXUAPLQ.js +4 -0
  156. package/dist-lib/agent-daemon-client.cjs +1 -1
  157. package/dist-lib/agent-events.cjs +1 -1
  158. package/dist-lib/agent-identity.cjs +1 -1
  159. package/dist-lib/agent-sessions.cjs +1 -1
  160. package/dist-lib/attached-projects.cjs +1 -1
  161. package/dist-lib/auth/shared-session.cjs +1 -1
  162. package/dist-lib/backend-origin.cjs +1 -1
  163. package/dist-lib/beta.cjs +1 -1
  164. package/dist-lib/beta.mjs +1 -1
  165. package/dist-lib/bridge-constants.cjs +1 -1
  166. package/dist-lib/bridge-contract-input.cjs +336 -0
  167. package/dist-lib/bridge-contract-input.mjs +303 -0
  168. package/dist-lib/bridge-contract.cjs +29 -1
  169. package/dist-lib/bridge-contract.mjs +19 -0
  170. package/dist-lib/cli-constants.cjs +1 -1
  171. package/dist-lib/config.cjs +1 -1
  172. package/dist-lib/detox/index.cjs +32 -18
  173. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  174. package/dist-lib/home-paths.cjs +1 -1
  175. package/dist-lib/host/bridge-host.cjs +5 -1
  176. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  177. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  178. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  179. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  180. package/dist-lib/host/websocket-proxy.cjs +1 -1
  181. package/dist-lib/index.cjs +214 -594
  182. package/dist-lib/jump-to-source-babel.cjs +1 -1
  183. package/dist-lib/menu.cjs +1 -1
  184. package/dist-lib/menu.mjs +1 -1
  185. package/dist-lib/metro-production-bundle.cjs +1 -1
  186. package/dist-lib/metro-production-bundle.mjs +1 -1
  187. package/dist-lib/metro.cjs +1 -1
  188. package/dist-lib/profiles.cjs +1 -1
  189. package/dist-lib/public-brand.cjs +1 -1
  190. package/dist-lib/react-native-host-modules.cjs +1 -1
  191. package/dist-lib/react-native-host-modules.mjs +1 -1
  192. package/dist-lib/render-mode.cjs +1 -1
  193. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  194. package/dist-lib/sdk.cjs +273 -657
  195. package/dist-lib/sdk.mjs +271 -652
  196. package/dist-lib/skills.cjs +190 -287
  197. package/dist-lib/vite.cjs +1 -1
  198. package/package.json +9 -6
  199. package/skills/contrast/SKILL.md +3 -0
  200. package/skills/rnx-debug/SKILL.md +8 -0
  201. package/skills/rnx-test/SKILL.md +21 -0
  202. package/src/bridge-contract-input.ts +359 -0
  203. package/src/bridge-contract.ts +121 -1
  204. package/src/host/bridge-host.ts +7 -12
  205. package/src/index.ts +7 -0
  206. package/src/sim-client.ts +12 -3
  207. package/dist-cli/chunks/chunk-3X6IBUBX.js +0 -38
  208. package/dist-cli/chunks/chunk-7B37IZBN.js +0 -15
  209. package/dist-cli/chunks/chunk-DMPF2D24.js +0 -4
  210. package/dist-cli/chunks/chunk-DW37EVX5.js +0 -767
  211. package/dist-cli/chunks/chunk-DWFIH7CB.js +0 -32
  212. package/dist-cli/chunks/chunk-GUI3PDH2.js +0 -27
  213. package/dist-cli/chunks/chunk-KLF3K6ZZ.js +0 -4
  214. package/dist-cli/chunks/chunk-M5QCGLXR.js +0 -944
  215. package/dist-cli/chunks/chunk-M6SKQGAN.js +0 -5
  216. package/dist-cli/chunks/chunk-NAYLPOC5.js +0 -24
  217. package/dist-cli/chunks/chunk-VIND4SP3.js +0 -124
  218. package/dist-cli/chunks/chunk-XXNLYR64.js +0 -5
  219. package/dist-cli/chunks/chunk-ZFM24DOX.js +0 -4
  220. package/dist-cli/chunks/cli-version-SYGNHGFR.js +0 -4
  221. package/dist-cli/chunks/control-RBTNOLQM.js +0 -4
  222. package/dist-cli/chunks/daemon-N3SC5DK6.js +0 -4
  223. package/dist-cli/chunks/drivers-W6E3BZH4.js +0 -4
  224. package/dist-cli/chunks/flow-7QAE2V5Y.js +0 -4
  225. package/dist-cli/chunks/help-NLD6KWVG.js +0 -4
  226. package/dist-cli/chunks/inspect-C347BG52.js +0 -4
  227. package/dist-cli/chunks/install-desktop-YR6TWZYK.js +0 -4
  228. package/dist-cli/chunks/privacy-PWWC2BXO.js +0 -4
  229. package/dist-cli/chunks/reset-Y3PBPFYA.js +0 -4
  230. package/dist-cli/chunks/runtime-IC6NVVGA.js +0 -4
  231. package/dist-cli/chunks/setup-Y4QGSJBM.js +0 -4
  232. package/dist-cli/chunks/state-KFLAZNEY.js +0 -14
  233. package/dist-cli/chunks/store-VEE22CAY.js +0 -4
  234. package/dist-cli/chunks/telemetry-PZV4BISJ.js +0 -4
  235. package/dist-cli/chunks/upload-Y4C3YZDK.js +0 -4
  236. package/dist-cli/chunks/welcome-ZPKA5PZJ.js +0 -5
  237. package/dist-lib/mcp.cjs +0 -673
  238. package/dist-lib/mcp.mjs +0 -641
  239. package/src/mcp.ts +0 -791
package/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.366 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.367 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __defProp = Object.defineProperty;
@@ -26,9 +26,6 @@ __export(sdk_exports, {
26
26
  LAYOUT_GET_NATIVE_EVAL: () => LAYOUT_GET_NATIVE_EVAL,
27
27
  MERGED_CONSOLE_COUNT_EVAL: () => MERGED_CONSOLE_COUNT_EVAL,
28
28
  NOISY_TIMELINE_KINDS: () => NOISY_TIMELINE_KINDS,
29
- READY_CONTENT_NODE_FLOOR: () => READY_CONTENT_NODE_FLOOR,
30
- READY_NODE_STABLE_MS: () => READY_NODE_STABLE_MS,
31
- READY_PROBE_POLL_MS: () => READY_PROBE_POLL_MS,
32
29
  SimClient: () => SimClient,
33
30
  SimClientError: () => SimClientError,
34
31
  SimConnectError: () => SimConnectError,
@@ -37,8 +34,6 @@ __export(sdk_exports, {
37
34
  SimReadyTimeoutError: () => SimReadyTimeoutError,
38
35
  SimResetError: () => SimResetError,
39
36
  SimTapError: () => SimTapError,
40
- WAIT_READY_PROBE: () => WAIT_READY_PROBE,
41
- WAIT_READY_PROGRESS_INTERVAL_MS: () => WAIT_READY_PROGRESS_INTERVAL_MS,
42
37
  buildSimOpenUrl: () => buildSimOpenUrl,
43
38
  clearConsole: () => clearConsole,
44
39
  clearLogs: () => clearLogs,
@@ -46,6 +41,7 @@ __export(sdk_exports, {
46
41
  detectOpenNativeUI: () => detectOpenNativeUI,
47
42
  filterLogEntries: () => filterLogEntries,
48
43
  formatLayoutElements: () => formatLayoutElements,
44
+ formatSemanticTree: () => formatSemanticTree,
49
45
  formatTimelineEvent: () => formatTimelineEvent,
50
46
  formatTimelineEvents: () => formatTimelineEvents,
51
47
  formatTimelinePayload: () => formatTimelinePayload,
@@ -78,6 +74,7 @@ __export(sdk_exports, {
78
74
  isInspectModeActive: () => isInspectModeActive,
79
75
  isInspectPickCommand: () => isInspectPickCommand,
80
76
  isShellCommandUnavailable: () => isShellCommandUnavailable,
77
+ isSimSemanticTree: () => isSimSemanticTree,
81
78
  isTapSuccess: () => isTapSuccess,
82
79
  layoutGetNativeEval: () => layoutGetNativeEval,
83
80
  rankInteractive: () => rankInteractive,
@@ -751,6 +748,15 @@ async function tapBest(bridge, query, opts = {}) {
751
748
  });
752
749
  }
753
750
 
751
+ // src/bridge-contract.ts
752
+ var SEMANTIC_READY_CONTENT_NODE_FLOOR = 100;
753
+ function readyProbeHasContent(probe) {
754
+ return probe.liveFrameActive || probe.targets > 0 || probe.nodes >= SEMANTIC_READY_CONTENT_NODE_FLOOR;
755
+ }
756
+ function readyProbeHasTargetContent(probe) {
757
+ return probe.liveFrameActive || probe.targets > 0;
758
+ }
759
+
754
760
  // cli/commands/inspect/core.ts
755
761
  function resolveMaxMsFlag(args, fallbackMs) {
756
762
  const aliases = ["--max-ms", "--maxMs", "--maxms", "--max_ms"];
@@ -790,121 +796,116 @@ async function shouldSkipAutoSettleForInspectPick(bridge, subcommand) {
790
796
  }
791
797
  }
792
798
  async function inspectNodeCount(bridge) {
793
- const count = await bridge.send({
794
- type: "evaluate",
795
- code: "(async () => await window.__sootsimTest.getNodeCount())()"
799
+ const result = await bridge.send({
800
+ type: "query",
801
+ query: { kind: "count" }
796
802
  });
797
- return { nodes: typeof count === "number" ? count : 0 };
803
+ return { nodes: isSemanticQueryResult(result) ? result.total : 0 };
798
804
  }
799
- async function inspectTree(bridge, depth = 5, opts) {
800
- const optsArg = opts?.format ? `, ${JSON.stringify(opts)}` : "";
801
- const tree = await bridge.send({
802
- type: "evaluate",
803
- code: `(async () => await window.__sootsimTest.dumpTree(${depth}${optsArg}))()`
805
+ async function inspectTree(bridge, depth = 5) {
806
+ const result = await bridge.send({
807
+ type: "query",
808
+ query: { kind: "tree", depth }
804
809
  });
805
- if (opts?.format === "boxes" && typeof tree === "string") {
806
- try {
807
- return { depth, tree: JSON.parse(tree) };
808
- } catch {
809
- return { depth, tree };
810
- }
811
- }
810
+ const tree = isSemanticQueryResult(result) ? result.nodes : [];
812
811
  return { depth, tree };
813
812
  }
814
813
  async function inspectUrl(bridge) {
815
814
  const url = await bridge.send({ type: "evaluate", code: "window.location.href" });
816
815
  return { url: typeof url === "string" ? url : "" };
817
816
  }
818
- async function inspectDescribe(bridge, dumpOpts) {
819
- const dumpDepth = dumpOpts.maxDepth ?? 12;
820
- const code = `(async () => {
821
- const t = window.__sootsimTest
822
- const mainShell = window.SootSim?.bridges?.mainShell
823
- const kb = window.__sootsimKeyboard
824
- if (!t) return { error: 'no test bridge' }
825
-
826
- let shell = null
827
- try {
828
- shell = typeof mainShell?.getState === 'function' ? await mainShell.getState() : null
829
- } catch {}
830
-
831
- const opts = ${JSON.stringify(dumpOpts)}
832
- const needsRecursiveDump =
833
- opts.verbose || opts.subtreeRoot || opts.includeOccluded || opts.maxDepth != null
834
- const globToRegex = (glob) => {
835
- const escaped = String(glob).replace(/[.+^$(){}|[\\]\\\\]/g, '\\\\$&')
836
- const body = escaped.replace(/\\*/g, '.*').replace(/\\?/g, '.')
837
- return new RegExp('^' + body + '$', 'i')
838
- }
839
- // clipping a describe line is a DISPLAY decision. opts.fullText (set by
840
- // \`describe --json\`) keeps the real string, so a bundle-eval stack or a
841
- // red-box message reaches the caller whole instead of ending in an
842
- // ellipsis nothing downstream can undo.
843
- const clipForDisplay = (value, max) => {
844
- const text = typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : ''
845
- if (opts.fullText || text.length <= max) return text
846
- return text.slice(0, max - 1).trimEnd() + '\u2026'
817
+ function isSemanticGeometry(value) {
818
+ return value !== null && typeof value === "object" && [
819
+ Reflect.get(value, "x"),
820
+ Reflect.get(value, "y"),
821
+ Reflect.get(value, "width"),
822
+ Reflect.get(value, "height")
823
+ ].every(
824
+ (coordinate) => typeof coordinate === "number" ? Number.isFinite(coordinate) : false
825
+ );
826
+ }
827
+ function isSimSemanticTree(value) {
828
+ if (!Array.isArray(value)) return false;
829
+ return value.every((node) => {
830
+ if (node === null || typeof node !== "object" || !Number.isInteger(Reflect.get(node, "nodeId")) || typeof Reflect.get(node, "type") !== "string" || !isSemanticGeometry(Reflect.get(node, "geometry"))) {
831
+ return false;
832
+ }
833
+ for (const key of ["testID", "text", "role", "label"]) {
834
+ const value2 = Reflect.get(node, key);
835
+ if (value2 !== void 0 && typeof value2 !== "string") return false;
836
+ }
837
+ const pressable = Reflect.get(node, "pressable");
838
+ if (pressable !== void 0 && pressable !== true) return false;
839
+ const children = Reflect.get(node, "children");
840
+ return children === void 0 || isSimSemanticTree(children);
841
+ });
842
+ }
843
+ function isSemanticQueryResult(value) {
844
+ const total = value !== null && typeof value === "object" ? Reflect.get(value, "total") : void 0;
845
+ return value !== null && typeof value === "object" && typeof total === "number" && Number.isInteger(total) && total >= 0 && isSimSemanticTree(Reflect.get(value, "nodes"));
846
+ }
847
+ function globRegex(glob) {
848
+ const escaped = glob.replace(/[.+^$(){}|[\]\\]/g, "\\$&");
849
+ return new RegExp(`^${escaped.replace(/\*/g, ".*").replace(/\?/g, ".")}$`, "i");
850
+ }
851
+ function formatSemanticTree(nodes, opts = {}) {
852
+ const filter = opts.filter?.toLowerCase() ?? "";
853
+ const testIDRegex = opts.testIdLike ? globRegex(opts.testIdLike) : null;
854
+ const onlyRegex = opts.onlyGlob ? globRegex(opts.onlyGlob) : null;
855
+ const lines = [];
856
+ const visit = (node, indent) => {
857
+ const joined = [node.role, node.label, node.text, node.testID].filter((value) => typeof value === "string").join(" ");
858
+ const matches = (!filter || joined.toLowerCase().includes(filter)) && (!testIDRegex || testIDRegex.test(node.testID ?? "")) && (!onlyRegex || onlyRegex.test(joined));
859
+ if (matches) {
860
+ const parts = [
861
+ node.role ? `[${node.role}]` : node.pressable ? "[tap]" : `<${node.type}>`
862
+ ];
863
+ if (node.text) {
864
+ const text = opts.fullText || node.text.length <= 50 ? node.text : `${node.text.slice(0, 49).trimEnd()}\u2026`;
865
+ parts.push(JSON.stringify(text));
847
866
  }
848
- const formatInspectableTree = async () => {
849
- if (typeof t.listInspectable !== 'function') return null
850
- const list = await t.listInspectable({})
851
- if (!Array.isArray(list)) return null
852
- const filter = typeof opts.filter === 'string' ? opts.filter.toLowerCase() : ''
853
- const testIdRegex = opts.testIdLike ? globToRegex(opts.testIdLike) : null
854
- const onlyRegex = opts.onlyGlob ? globToRegex(opts.onlyGlob) : null
855
- const lines = []
856
- let matched = 0
857
- for (const node of list) {
858
- const testID = node?.testID || node?.testId || ''
859
- const role = node?.role || ''
860
- const label = node?.accessibilityLabel || node?.label || ''
861
- const text = node?.text || ''
862
- if (testIdRegex && !testIdRegex.test(testID)) continue
863
- const joined = [role, label, text, testID].filter(Boolean).join(' ')
864
- if (onlyRegex && !onlyRegex.test(joined)) continue
865
- if (filter && !joined.toLowerCase().includes(filter)) continue
866
- matched++
867
-
868
- const type = String(node?.type || 'node').toLowerCase()
869
- const handlers = Array.isArray(node?.handlers) ? node.handlers : []
870
- const parts = []
871
- if (role) parts.push('[' + role + ']')
872
- else if (handlers.length > 0) parts.push('[tap]')
873
- else parts.push('<' + type + '>')
874
- const visibleText = clipForDisplay(text, 50)
875
- if (visibleText) parts.push(JSON.stringify(visibleText))
876
- if (testID) parts.push('#' + testID)
877
- if (label && label !== text) {
878
- parts.push('label=' + JSON.stringify(clipForDisplay(label, 50)))
879
- }
880
- if (!opts.hideXy) {
881
- const abs = node?.absolute || {}
882
- const layout = node?.layout || {}
883
- const x = Math.round(Number(abs.x) || 0)
884
- const y = Math.round(Number(abs.y) || 0)
885
- const w = Math.round(Number(layout.width) || 0)
886
- const h = Math.round(Number(layout.height) || 0)
887
- parts.push('@(' + x + ',' + y + ') ' + w + 'x' + h)
888
- }
889
- if (handlers.length > 0) parts.push('(tap)')
890
- lines.push(' ' + parts.join(' '))
891
- }
892
- return { tree: lines.join('\\n'), matched }
867
+ if (node.testID) parts.push(`#${node.testID}`);
868
+ if (node.label && node.label !== node.text) {
869
+ parts.push(`label=${JSON.stringify(node.label)}`);
893
870
  }
894
-
895
- let tree = ''
896
- const compactResult = needsRecursiveDump ? null : await formatInspectableTree()
897
- if (compactResult) {
898
- tree = compactResult.tree
899
- } else {
900
- tree = await t.dumpTree(${dumpDepth}, opts)
871
+ if (!opts.hideXy) {
872
+ const geometry = node.geometry;
873
+ parts.push(
874
+ `@(${Math.round(geometry.x)},${Math.round(geometry.y)}) ${Math.round(geometry.width)}x${Math.round(geometry.height)}`
875
+ );
901
876
  }
902
- const nodeCount = (await t.getNodeCount?.()) || 0
903
- const keyboard = kb && typeof kb.getLayout === 'function' ? kb.getLayout() : null
904
- return { tree, shell, nodeCount, keyboard }
905
- })()`;
906
- const result = await bridge.send({ type: "evaluate", code });
907
- return result ?? {};
877
+ if (node.pressable) parts.push("(tap)");
878
+ lines.push(`${" ".repeat(indent + 1)}${parts.join(" ")}`);
879
+ }
880
+ for (const child of node.children ?? []) visit(child, indent + 1);
881
+ };
882
+ let roots = nodes;
883
+ if (opts.subtreeRoot) {
884
+ const pending = [...nodes];
885
+ let found;
886
+ while (pending.length > 0 && !found) {
887
+ const candidate = pending.shift();
888
+ if (!candidate) continue;
889
+ if (candidate.testID === opts.subtreeRoot) found = candidate;
890
+ else pending.push(...candidate.children ?? []);
891
+ }
892
+ if (!found) return `__SUBTREE_NOT_FOUND__:${opts.subtreeRoot}`;
893
+ roots = [found];
894
+ }
895
+ for (const root of roots) visit(root, 0);
896
+ return lines.join("\n");
897
+ }
898
+ async function inspectDescribe(bridge, dumpOpts) {
899
+ const dumpDepth = dumpOpts.maxDepth ?? 12;
900
+ const result = await bridge.send({
901
+ type: "query",
902
+ query: { kind: "tree", depth: dumpDepth }
903
+ });
904
+ if (!isSemanticQueryResult(result)) return {};
905
+ return {
906
+ tree: formatSemanticTree(result.nodes, dumpOpts),
907
+ nodeCount: result.total
908
+ };
908
909
  }
909
910
  function scoreLayoutTextContrast(input) {
910
911
  const required = input.fontSize >= 18 || input.fontSize >= 14 && (input.fontWeight ?? 400) >= 700 ? 3 : 4.5;
@@ -1119,9 +1120,6 @@ function layoutGetNativeEval(opts = {}) {
1119
1120
  type: typeof n.type === 'string' ? n.type : 'node',
1120
1121
  text,
1121
1122
  box: { x: round(abs.x), y: round(abs.y), w: round(layout.width), h: round(layout.height) },
1122
- borderRadius: 0,
1123
- padding: { t: 0, r: 0, b: 0, l: 0 },
1124
- fontSize: 0,
1125
1123
  }
1126
1124
  if (!includeStyle) return base
1127
1125
  // computedStyle has the resolved values; style is the curated subset \u2014
@@ -1192,6 +1190,32 @@ function layoutGetNativeEval(opts = {}) {
1192
1190
  }
1193
1191
  var LAYOUT_GET_NATIVE_EVAL = layoutGetNativeEval();
1194
1192
  async function inspectGetLayout(bridge, opts = {}) {
1193
+ if (!opts.styling) {
1194
+ const result = await bridge.send({
1195
+ type: "query",
1196
+ query: { kind: "find", selector: { visible: true } }
1197
+ });
1198
+ if (!isSemanticQueryResult(result)) return [];
1199
+ const filter = opts.filter?.trim().toLowerCase() ?? "";
1200
+ return result.nodes.filter((node) => {
1201
+ if (!filter) return true;
1202
+ return [node.text, node.testID, node.role, node.type].some(
1203
+ (value) => typeof value === "string" && value.toLowerCase().includes(filter)
1204
+ );
1205
+ }).map((node) => ({
1206
+ nodeId: node.nodeId,
1207
+ ...node.testID ? { testID: node.testID } : {},
1208
+ ...node.role ? { role: node.role } : {},
1209
+ type: node.type,
1210
+ ...node.text ? { text: node.text } : {},
1211
+ box: {
1212
+ x: Math.round(node.geometry.x),
1213
+ y: Math.round(node.geometry.y),
1214
+ w: Math.round(node.geometry.width),
1215
+ h: Math.round(node.geometry.height)
1216
+ }
1217
+ }));
1218
+ }
1195
1219
  const raw = await bridge.send({
1196
1220
  type: "evaluate",
1197
1221
  code: layoutGetNativeEval(opts)
@@ -1203,13 +1227,17 @@ function formatLayoutElements(elements, opts) {
1203
1227
  const lines = elements.map((el) => {
1204
1228
  const ident = el.testID ? `#${el.testID}` : el.selector ? el.selector : el.role ? `[${el.role}]` : `<${el.type}>`;
1205
1229
  const parts = [ident, `@(${el.box.x},${el.box.y})`, `${el.box.w}x${el.box.h}`];
1206
- if (el.borderRadius > 0) parts.push(`radius:${el.borderRadius}`);
1230
+ if (el.borderRadius !== void 0 && el.borderRadius > 0) {
1231
+ parts.push(`radius:${el.borderRadius}`);
1232
+ }
1207
1233
  const p = el.padding;
1208
- if (p.t || p.r || p.b || p.l) {
1234
+ if (p && (p.t || p.r || p.b || p.l)) {
1209
1235
  const uniform = p.t === p.r && p.r === p.b && p.b === p.l;
1210
1236
  parts.push(uniform ? `pad:${p.t}` : `pad:${p.t},${p.r},${p.b},${p.l}`);
1211
1237
  }
1212
- if (el.fontSize > 0) parts.push(`font:${el.fontSize}`);
1238
+ if (el.fontSize !== void 0 && el.fontSize > 0) {
1239
+ parts.push(`font:${el.fontSize}`);
1240
+ }
1213
1241
  if (opts?.styling) {
1214
1242
  if (el.fontWeight) parts.push(`weight:${el.fontWeight}`);
1215
1243
  if (el.color) parts.push(`color:${el.color}`);
@@ -1236,246 +1264,80 @@ function formatLayoutElements(elements, opts) {
1236
1264
  });
1237
1265
  return lines.join("\n");
1238
1266
  }
1239
- var INSPECT_A11Y_CODE = `(async () => {
1240
- const t = window.__sootsimTest
1241
- if (!t) return []
1242
-
1243
- const readLayout = (n) => n?.layout || null
1244
- const readAbs = (n) => n?.absolutePosition || n?.absolute || null
1245
- const readRole = (n) => n?.accessibilityRole || n?.role || null
1246
- const readLabel = (n) => n?.accessibilityLabel || n?.label || n?.text || null
1247
- const readHint = (n) => n?.accessibilityHint || n?.hint || null
1248
- const readState = (n) => n?.accessibilityState || n?.state || null
1249
- const readTestId = (n) => n?.testID || n?.testId || null
1250
- const readType = (n) => typeof n?.type === 'string' ? n.type.toLowerCase() : n?.type
1251
- const readPressable = (n) => {
1252
- if (n?.pressable) return true
1253
- const handlers = Array.isArray(n?.handlers) ? n.handlers : []
1254
- const role = readRole(n)
1255
- return handlers.length > 0 || role === 'button' || role === 'link' || role === 'tab'
1256
- }
1257
- const isTextInput = (n) => n?.isTextInput === true
1258
- const isTextNode = (n) => readType(n) === 'text'
1259
- const isVisibleTarget = (n) => {
1260
- const layout = readLayout(n)
1261
- if (!layout || layout.width <= 0 || layout.height <= 0) return false
1262
- const abs = readAbs(n)
1263
- if (!abs) return true
1264
- const device = n?.device || {}
1265
- const screenW = Number(device.width) || window.innerWidth || 0
1266
- const screenH = Number(device.height) || window.innerHeight || 0
1267
- return (
1268
- abs.x + layout.width > 0 &&
1269
- abs.y + layout.height > 0 &&
1270
- abs.x < screenW &&
1271
- abs.y < screenH
1272
- )
1273
- }
1274
- const hasAccessibleSignal = (n) => {
1275
- const role = readRole(n)
1276
- const label = readLabel(n)
1277
- const hint = readHint(n)
1278
- if (role) return true
1279
- if (hint) return true
1280
- if (isTextInput(n)) return true
1281
- if (readPressable(n)) return true
1282
- if (isTextNode(n) && n?.text) return true
1283
- if (typeof label === 'string' && label.length <= 30 && label !== n?.text) return true
1284
- return false
1285
- }
1286
- const normalize = (n) => {
1287
- const layout = readLayout(n)
1288
- const abs = readAbs(n)
1289
- const role = readRole(n) || (readPressable(n) ? 'button' : isTextInput(n) ? 'textfield' : isTextNode(n) ? 'statictext' : 'none')
1290
- return {
1291
- role,
1292
- label: readLabel(n),
1293
- hint: readHint(n),
1294
- state: readState(n),
1295
- testID: readTestId(n),
1296
- position: abs ? { x: Math.round(abs.x), y: Math.round(abs.y) } : null,
1297
- size: layout ? { w: Math.round(layout.width), h: Math.round(layout.height) } : null,
1298
- }
1299
- }
1300
-
1301
- if (typeof t.listInspectable === 'function') {
1302
- const list = await t.listInspectable({})
1303
- if (Array.isArray(list)) {
1304
- return list.filter(n => isVisibleTarget(n) && hasAccessibleSignal(n)).map(normalize)
1305
- }
1306
- }
1307
-
1308
- const all = await t.queryAll({ pruneHidden: true })
1309
- return all
1310
- .filter(n => isVisibleTarget(n) && hasAccessibleSignal(n))
1311
- .map(normalize)
1312
- })()`;
1313
1267
  async function inspectAccessibilityTree(bridge) {
1314
- const nodes = await bridge.send({ type: "evaluate", code: INSPECT_A11Y_CODE });
1315
- return Array.isArray(nodes) ? nodes : [];
1316
- }
1317
- var FIND_INSPECTABLE_TARGETS = `
1318
- const fromInspectable = async () => {
1319
- if (typeof t.listInspectable !== 'function') return null
1320
- const list = await t.listInspectable({})
1321
- if (!Array.isArray(list)) return null
1322
- return list.map((n) => {
1323
- const role = n.accessibilityRole ?? n.role
1324
- const label = n.accessibilityLabel ?? n.label
1325
- const layout = n.layout
1326
- const absolutePosition = n.absolutePosition ?? n.absolute
1327
- const screenW = Number(n.device?.width) || window.innerWidth || 0
1328
- const screenH = Number(n.device?.height) || window.innerHeight || 0
1329
- const visibleFrame = layout && absolutePosition
1330
- ? {
1331
- x: Math.max(0, absolutePosition.x),
1332
- y: Math.max(0, absolutePosition.y),
1333
- width: Math.max(
1334
- 0,
1335
- Math.min(screenW, absolutePosition.x + layout.width) -
1336
- Math.max(0, absolutePosition.x),
1337
- ),
1338
- height: Math.max(
1339
- 0,
1340
- Math.min(screenH, absolutePosition.y + layout.height) -
1341
- Math.max(0, absolutePosition.y),
1342
- ),
1343
- }
1344
- : null
1345
- const handlers = Array.isArray(n.handlers) ? n.handlers : []
1346
- const pressable =
1347
- handlers.length > 0 ||
1348
- role === 'button' ||
1349
- role === 'link' ||
1350
- role === 'tab'
1351
- return {
1352
- type: typeof n.type === 'string' ? n.type.toLowerCase() : n.type,
1353
- id: n.id ?? n.nodeId,
1354
- nodeId: n.nodeId,
1355
- testID: n.testID ?? n.testId,
1356
- text: n.text,
1357
- layout,
1358
- absolutePosition,
1359
- visibleFrame,
1360
- style: n.computedStyle ?? n.style ?? {},
1361
- childCount: n.childCount ?? 0,
1362
- pressed: n.pressed ?? false,
1363
- pressable,
1364
- isTextInput: n.isTextInput ?? false,
1365
- accessible: n.accessible ?? true,
1366
- accessibilityLabel: label,
1367
- accessibilityRole: role,
1368
- accessibilityHint: n.accessibilityHint,
1369
- accessibilityState: n.accessibilityState,
1370
- accessibilityValue: n.accessibilityValue,
1371
- }
1372
- })
1373
- }
1374
- const isVisibleTarget = (n) => {
1375
- if (!n?.layout) return false
1376
- const frame = n.visibleFrame
1377
- if (frame) return frame.width > 0 && frame.height > 0
1378
- const abs = n.absolutePosition
1379
- if (!abs) return n.layout.width > 0 && n.layout.height > 0
1380
- const screenW = window.innerWidth || 0
1381
- const screenH = window.innerHeight || 0
1382
- return (
1383
- abs.x + n.layout.width > 0 &&
1384
- abs.y + n.layout.height > 0 &&
1385
- abs.x < screenW &&
1386
- abs.y < screenH
1387
- )
1268
+ const result = await bridge.send({
1269
+ type: "query",
1270
+ query: { kind: "find", selector: { visible: true } }
1271
+ });
1272
+ if (!isSemanticQueryResult(result)) return [];
1273
+ return result.nodes.flatMap((node) => {
1274
+ if (!node.role && !node.label && !node.text && !node.pressable) return [];
1275
+ return [
1276
+ {
1277
+ role: node.role ?? (node.pressable ? "button" : node.type === "text" ? "statictext" : "none"),
1278
+ label: node.label ?? node.text ?? null,
1279
+ hint: null,
1280
+ state: null,
1281
+ testID: node.testID ?? null,
1282
+ position: {
1283
+ x: Math.round(node.geometry.x),
1284
+ y: Math.round(node.geometry.y)
1285
+ },
1286
+ size: {
1287
+ w: Math.round(node.geometry.width),
1288
+ h: Math.round(node.geometry.height)
1289
+ }
1388
1290
  }
1389
- `;
1291
+ ];
1292
+ });
1293
+ }
1390
1294
  function resolveFindMode(q) {
1391
1295
  if (q.testId) {
1392
- return {
1393
- mode: "testid",
1394
- code: `(async () => {
1395
- const t = window.__sootsimTest
1396
- if (!t) return null
1397
- return (await t.findByTestId(${JSON.stringify(q.testId)})) || (await t.findById(${JSON.stringify(q.testId)}))
1398
- })()`
1399
- };
1296
+ return { mode: "testid", selector: { testID: q.testId } };
1400
1297
  }
1401
1298
  if (q.role) {
1402
- return {
1403
- mode: "role",
1404
- code: `(async () => {
1405
- const t = window.__sootsimTest
1406
- if (!t) return []
1407
- return await t.queryAll({ hasRole: ${JSON.stringify(q.role)}, pruneHidden: true })
1408
- })()`
1409
- };
1299
+ return { mode: "role", selector: { role: q.role } };
1410
1300
  }
1411
1301
  if (q.type) {
1412
- return {
1413
- mode: "type",
1414
- code: `(async () => {
1415
- const t = window.__sootsimTest
1416
- if (!t) return []
1417
- return await t.queryAll({ type: ${JSON.stringify(q.type)}, pruneHidden: true })
1418
- })()`
1419
- };
1302
+ return { mode: "type", selector: { type: q.type } };
1420
1303
  }
1421
1304
  if (q.pressable) {
1422
- return {
1423
- mode: "pressable",
1424
- code: `(async () => {
1425
- const t = window.__sootsimTest
1426
- if (!t) return []
1427
- ${FIND_INSPECTABLE_TARGETS}
1428
- const inspectable = await fromInspectable()
1429
- if (inspectable) return inspectable.filter(n => n.pressable && isVisibleTarget(n))
1430
- const all = await t.queryAll({ pruneHidden: true })
1431
- return all.filter(n => n.pressable && isVisibleTarget(n))
1432
- })()`
1433
- };
1305
+ return { mode: "pressable", selector: { pressable: true } };
1434
1306
  }
1435
1307
  if (q.interactive) {
1436
- return {
1437
- mode: "interactive-targets",
1438
- code: `(async () => {
1439
- const t = window.__sootsimTest
1440
- if (!t) return []
1441
- ${FIND_INSPECTABLE_TARGETS}
1442
- const inspectable = await fromInspectable()
1443
- if (inspectable) {
1444
- return inspectable.filter(n => n.pressable && isVisibleTarget(n))
1445
- }
1446
- const all = await t.queryAll({ pruneHidden: true })
1447
- return all.filter(n => n.pressable && isVisibleTarget(n))
1448
- })()`
1449
- };
1308
+ return { mode: "interactive-targets", selector: { pressable: true } };
1450
1309
  }
1451
1310
  if (q.visible) {
1452
- return {
1453
- mode: "visible",
1454
- code: `(async () => {
1455
- const t = window.__sootsimTest
1456
- if (!t) return []
1457
- const all = await t.queryAll({ pruneHidden: true })
1458
- return all.filter(n => n.layout && n.layout.width > 0 && n.layout.height > 0)
1459
- })()`
1460
- };
1311
+ return { mode: "visible", selector: { visible: true } };
1461
1312
  }
1462
1313
  if (q.text) {
1463
- return {
1464
- mode: "text",
1465
- code: `(async () => {
1466
- const t = window.__sootsimTest
1467
- if (!t) return null
1468
- return await t.findByText(${JSON.stringify(q.text)})
1469
- })()`
1470
- };
1314
+ return { mode: "text", selector: { text: q.text } };
1471
1315
  }
1472
1316
  return null;
1473
1317
  }
1474
1318
  async function inspectFind(bridge, q) {
1475
1319
  const resolved = resolveFindMode(q);
1476
1320
  if (!resolved) return null;
1477
- const result = await bridge.send({ type: "evaluate", code: resolved.code });
1478
- return { mode: resolved.mode, result };
1321
+ const result = await bridge.send({
1322
+ type: "query",
1323
+ query: { kind: "find", selector: resolved.selector }
1324
+ });
1325
+ if (!isSemanticQueryResult(result)) return { mode: resolved.mode, result: [] };
1326
+ const nodes = result.nodes.map(
1327
+ (node) => ({
1328
+ type: node.type,
1329
+ nodeId: node.nodeId,
1330
+ ...node.testID ? { testID: node.testID } : {},
1331
+ ...node.text ? { text: node.text } : {},
1332
+ ...node.pressable ? { pressable: true } : {},
1333
+ ...node.role ? { accessibilityRole: node.role } : {},
1334
+ ...node.label ? { accessibilityLabel: node.label } : {},
1335
+ absolutePosition: { x: node.geometry.x, y: node.geometry.y },
1336
+ layout: { width: node.geometry.width, height: node.geometry.height }
1337
+ })
1338
+ );
1339
+ const resultValue = resolved.mode === "testid" || resolved.mode === "text" ? nodes[0] ?? null : nodes;
1340
+ return { mode: resolved.mode, result: resultValue };
1479
1341
  }
1480
1342
  function rankInteractive(nodes) {
1481
1343
  return [...nodes].sort((a, b) => scoreInteractive(b) - scoreInteractive(a));
@@ -1509,158 +1371,6 @@ function shellEscape(value) {
1509
1371
  if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
1510
1372
  return `'${value.replace(/'/g, `'\\''`)}'`;
1511
1373
  }
1512
- var WAIT_READY_PROBE = `(async () => {
1513
- const t = window.__sootsimTest
1514
- let nodes = 0
1515
- try { nodes = (await t?.getNodeCount?.()) || 0 } catch {}
1516
- let targets = 0
1517
- let liveFrameActive = false
1518
- let liveFrameChannels = 0
1519
- let liveFramePublishes = 0
1520
- let loadingText = ''
1521
- const cleanText = (value) =>
1522
- typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : ''
1523
- const loadingSignal = (value) => {
1524
- const text = cleanText(value)
1525
- if (!text) return ''
1526
- return /^(opening app\\b|looking for your app\\b|building bundle\\b|preparing rnx runtime\\b|loading native bundle\\b|loading rnx stubs\\b|loading bundle loader\\b|loading native stubs\\b|loading compat bridge\\b|loading react-native shim\\b|loading react bridge\\b|loading reconciler\\b|loading replacement modules\\b|injecting rnx modules\\b|warming sqlite engine\\b|capturing root component\\b|reloading app\\b|loading(?:[.!\u2026]*)?$|connecting(?:[.!\u2026]*)?$)/i.test(text)
1527
- ? text
1528
- : ''
1529
- }
1530
- try {
1531
- const loading = window.__sootsimConnectRNLoading
1532
- if (loading && loading.active === true) {
1533
- loadingText = [loading.title, loading.detail].map(cleanText).filter(Boolean).join(' ')
1534
- }
1535
- } catch {}
1536
- try {
1537
- if (typeof t?.listInspectable === 'function') {
1538
- const list = await t.listInspectable({})
1539
- if (Array.isArray(list)) {
1540
- const screenW = window.innerWidth || 0
1541
- const screenH = window.innerHeight || 0
1542
- const isVisible = (n) => {
1543
- const layout = n?.layout
1544
- if (!layout || layout.width <= 0 || layout.height <= 0) return false
1545
- const abs = n?.absolutePosition || n?.absolute
1546
- if (!abs) return true
1547
- const device = n?.device || {}
1548
- const w = Number(device.width) || screenW
1549
- const h = Number(device.height) || screenH
1550
- return (
1551
- abs.x + layout.width > 0 &&
1552
- abs.y + layout.height > 0 &&
1553
- abs.x < w &&
1554
- abs.y < h
1555
- )
1556
- }
1557
- const hasContentSignal = (n) => {
1558
- const role = n?.accessibilityRole || n?.role
1559
- const label = cleanText(n?.accessibilityLabel || n?.label)
1560
- const handlers = Array.isArray(n?.handlers) ? n.handlers : []
1561
- const text = cleanText(n?.text)
1562
- const testID = cleanText(n?.testID || n?.testId)
1563
- const loading = loadingSignal(text) || loadingSignal(label) || loadingSignal(testID)
1564
- if (!loadingText && loading) {
1565
- loadingText = loading
1566
- }
1567
- if (handlers.length > 0) return true
1568
- if (role) return true
1569
- if (n?.isTextInput) return true
1570
- if (text) return true
1571
- if (label) return true
1572
- if (testID && !/^splash|loading/i.test(testID)) return true
1573
- return false
1574
- }
1575
- targets = list.filter(n => isVisible(n) && hasContentSignal(n)).length
1576
- }
1577
- }
1578
- } catch {}
1579
- try {
1580
- const stats = await t?.getImageLoaderStats?.()
1581
- const presentation = stats?.liveFramePresentation
1582
- liveFrameChannels = Number(presentation?.activeChannels) || 0
1583
- liveFramePublishes = Number(presentation?.publishes) || 0
1584
- const previous = window.__sootsimWaitReadyLiveFramePublishes
1585
- liveFrameActive =
1586
- liveFrameChannels > 0 &&
1587
- typeof previous === 'number' &&
1588
- liveFramePublishes > previous
1589
- window.__sootsimWaitReadyLiveFramePublishes = liveFramePublishes
1590
- } catch {}
1591
- let externalReady = null
1592
- let externalStatus = ''
1593
- let externalError = ''
1594
- let suppressedEntryError = ''
1595
- try {
1596
- const getExternalAppState = t?.getExternalAppState
1597
- const external = typeof getExternalAppState === 'function'
1598
- ? await Promise.race([
1599
- getExternalAppState(),
1600
- new Promise((resolve) => setTimeout(
1601
- () => resolve({
1602
- state: {
1603
- ready: false,
1604
- loading: true,
1605
- status: 'waiting for tenant worker...',
1606
- },
1607
- }),
1608
- 1000,
1609
- )),
1610
- ])
1611
- : null
1612
- const state = external?.state
1613
- if (state && typeof state === 'object') {
1614
- externalReady = state.ready === true
1615
- if (typeof state.status === 'string') externalStatus = state.status
1616
- if (typeof state.error === 'string') externalError = state.error
1617
- }
1618
- if (!externalError && Array.isArray(external?.entryErrors)) {
1619
- // suppressed-and-continued entry errors (bundle-loader's patched __r
1620
- // swallows entry throws and moves on) must NOT gate readiness \u2014 the
1621
- // app frequently runs fine after one (e.g. metro's "Unknown named
1622
- // module" probing noise). they surface separately as a diagnostic
1623
- // for the timeout path.
1624
- const isReal = (item) => item && typeof item.message === 'string' && item.message.trim()
1625
- const fatal = external.entryErrors.find((item) => isReal(item) && item.suppressed !== true)
1626
- if (fatal) externalError = fatal.message
1627
- const suppressed = external.entryErrors.find((item) => isReal(item) && item.suppressed === true)
1628
- if (suppressed) suppressedEntryError = suppressed.message
1629
- }
1630
- // once the app has errored its last status ("injecting sootsim
1631
- // modules...") is stale \u2014 reporting it makes a dead app read as one that
1632
- // is still booting.
1633
- if (externalError) loadingText = ''
1634
- else if (externalReady === false && externalStatus) loadingText = externalStatus
1635
- } catch {}
1636
- let errors = 0
1637
- try { errors = window.__sootsimConsole?.count?.()?.errors ?? 0 } catch {}
1638
- return {
1639
- flag: (window).__sootsimExternalAppReady,
1640
- at: (window).__sootsimExternalAppReadyAt || 0,
1641
- nodes,
1642
- targets,
1643
- liveFrameActive,
1644
- liveFrameChannels,
1645
- liveFramePublishes,
1646
- errors,
1647
- loadingText,
1648
- externalReady,
1649
- externalStatus,
1650
- externalError,
1651
- suppressedEntryError,
1652
- }
1653
- })()`;
1654
- var READY_CONTENT_NODE_FLOOR = 100;
1655
- var READY_NODE_STABLE_MS = 750;
1656
- var WAIT_READY_PROGRESS_INTERVAL_MS = 2e3;
1657
- var READY_PROBE_POLL_MS = 150;
1658
- function readyProbeHasContent(probe) {
1659
- return probe.liveFrameActive || probe.targets > 0 || probe.nodes >= READY_CONTENT_NODE_FLOOR;
1660
- }
1661
- function readyProbeHasTargetContent(probe) {
1662
- return probe.liveFrameActive || probe.targets > 0;
1663
- }
1664
1374
  function waitReadyReason(status) {
1665
1375
  if (status.bridgeError) {
1666
1376
  return `sim unreachable: ${status.bridgeError} \u2014 the target tab is closed or no sim is connected (check \`rnx list\`, reopen with \`rnx open\`)`;
@@ -1670,155 +1380,69 @@ function waitReadyReason(status) {
1670
1380
  }
1671
1381
  async function inspectWaitReady(bridge, timeoutMs = 2e4, options = {}) {
1672
1382
  const start = Date.now();
1673
- const deadline = start + timeoutMs;
1674
- const progressIntervalMs = options.progressIntervalMs ?? WAIT_READY_PROGRESS_INTERVAL_MS;
1675
- let nextProgressAt = start + progressIntervalMs;
1676
- let lastNodes = -1;
1677
- let nodeStableSince = start;
1678
- let bridgeError = "";
1679
- let last = {
1680
- flag: void 0,
1681
- at: 0,
1682
- nodes: 0,
1683
- targets: 0,
1684
- liveFrameActive: false,
1685
- liveFrameChannels: 0,
1686
- liveFramePublishes: 0,
1687
- errors: 0,
1688
- loadingText: "",
1689
- externalReady: null,
1690
- externalStatus: "",
1691
- externalError: "",
1692
- suppressedEntryError: ""
1693
- };
1694
- while (Date.now() < deadline) {
1695
- try {
1696
- last = await bridge.send({ type: "evaluate", code: WAIT_READY_PROBE }) ?? last;
1697
- bridgeError = "";
1698
- } catch (error) {
1699
- bridgeError = error instanceof Error ? error.message : String(error);
1700
- if (bridgeError.startsWith("multiple sims are connected:") || bridgeError.startsWith("saved sim ")) {
1701
- throw error;
1702
- }
1383
+ let result;
1384
+ try {
1385
+ result = await bridge.send(
1386
+ {
1387
+ type: "waitFor",
1388
+ waitForOptions: { condition: { type: "ready" }, timeoutMs }
1389
+ },
1390
+ { timeoutMs: timeoutMs + 1e3 }
1391
+ );
1392
+ } catch (error) {
1393
+ const bridgeError = error instanceof Error ? error.message : String(error);
1394
+ if (bridgeError.startsWith("multiple sims are connected:") || bridgeError.startsWith("saved sim ")) {
1395
+ throw error;
1703
1396
  }
1704
- const now = Date.now();
1705
- const status2 = {
1706
- ready: false,
1707
- elapsedMs: now - start,
1708
- nodes: last.nodes,
1709
- targets: last.targets,
1710
- liveFrameActive: last.liveFrameActive,
1711
- liveFrameChannels: last.liveFrameChannels,
1712
- liveFramePublishes: last.liveFramePublishes,
1713
- flag: last.flag,
1714
- loadingText: last.loadingText,
1715
- externalReady: last.externalReady,
1716
- externalStatus: last.externalStatus,
1717
- externalError: last.externalError,
1718
- suppressedEntryError: last.suppressedEntryError,
1719
- errors: last.errors,
1720
- bridgeError
1397
+ result = {
1398
+ matched: false,
1399
+ elapsedMs: Date.now() - start,
1400
+ polls: 0,
1401
+ error: bridgeError
1721
1402
  };
1722
- if (last.nodes !== lastNodes) {
1723
- lastNodes = last.nodes;
1724
- nodeStableSince = now;
1725
- }
1726
- const hasReadySignal = last.flag === true && readyProbeHasContent(last);
1727
- const hasRenderedContentWithoutReadySignal = last.flag !== true && readyProbeHasTargetContent(last);
1728
- if ((hasReadySignal || hasRenderedContentWithoutReadySignal) && last.externalReady !== false && !last.externalError && !last.loadingText) {
1729
- if (now - nodeStableSince >= READY_NODE_STABLE_MS) {
1730
- return {
1731
- ...status2,
1732
- ready: true
1733
- };
1734
- }
1735
- }
1736
- if (last.externalError) return status2;
1737
- if (options.onProgress && progressIntervalMs > 0 && now >= nextProgressAt) {
1738
- options.onProgress(status2);
1739
- do {
1740
- nextProgressAt += progressIntervalMs;
1741
- } while (now >= nextProgressAt);
1742
- }
1743
- await new Promise((r) => setTimeout(r, READY_PROBE_POLL_MS));
1744
1403
  }
1404
+ const probe = result.probe;
1745
1405
  const status = {
1746
- ready: false,
1747
- elapsedMs: Date.now() - start,
1748
- nodes: last.nodes,
1749
- targets: last.targets,
1750
- liveFrameActive: last.liveFrameActive,
1751
- liveFrameChannels: last.liveFrameChannels,
1752
- liveFramePublishes: last.liveFramePublishes,
1753
- flag: last.flag,
1754
- loadingText: last.loadingText,
1755
- externalReady: last.externalReady,
1756
- externalStatus: last.externalStatus,
1757
- externalError: last.externalError,
1758
- suppressedEntryError: last.suppressedEntryError,
1759
- errors: last.errors,
1760
- bridgeError
1406
+ ready: result.matched,
1407
+ elapsedMs: result.elapsedMs,
1408
+ nodes: probe?.nodes ?? 0,
1409
+ targets: probe?.targets ?? 0,
1410
+ liveFrameActive: probe?.liveFrameActive ?? false,
1411
+ liveFrameChannels: probe?.liveFrameChannels ?? 0,
1412
+ liveFramePublishes: probe?.liveFramePublishes ?? 0,
1413
+ flag: probe?.flag,
1414
+ loadingText: probe?.loadingText ?? "",
1415
+ externalReady: probe?.externalReady ?? null,
1416
+ externalStatus: probe?.externalStatus ?? "",
1417
+ externalError: probe?.externalError ?? "",
1418
+ suppressedEntryError: probe?.suppressedEntryError ?? "",
1419
+ errors: probe?.errors ?? 0,
1420
+ bridgeError: result.error ?? ""
1761
1421
  };
1762
- if (options.onProgress && progressIntervalMs > 0 && Date.now() >= nextProgressAt) {
1763
- options.onProgress(status);
1764
- }
1422
+ if (!status.ready && options.onProgress) options.onProgress(status);
1765
1423
  return status;
1766
1424
  }
1767
1425
  async function inspectWaitSelector(bridge, testId, timeoutMs = 5e3, opts = {}) {
1768
1426
  const gone = opts.gone === true;
1769
1427
  const result = await bridge.send(
1770
1428
  {
1771
- type: "evaluate",
1772
- code: `(async () => {
1773
- const start = Date.now()
1774
- const deadline = start + ${timeoutMs}
1775
- const gone = ${gone}
1776
- const ID = ${JSON.stringify(testId)}
1777
- const present = (node) => !!(node && node.layout && node.layout.width > 0 && node.layout.height > 0)
1778
- const find = async () => {
1779
- const t = window.__sootsimTest
1780
- if (!t) return undefined // bridge not ready \u2014 indeterminate, not "gone"
1781
- try {
1782
- // gone-mode confirms a gate/screen LEFT \u2014 it only needs structural
1783
- // existence + layout, NOT the full-tree occlusion pass (pruneHidden).
1784
- // that pass (computeOccludedInspectNodeIds) walks the whole tree and
1785
- // does O(n\xB2)-ish rect-occlusion testing EVERY poll; on a large
1786
- // post-login app tree it costs seconds per poll, so --gone can never
1787
- // get two clean "absent" polls inside budget and falsely reports the
1788
- // gate as still blocked \u2014 the root cause of the 3pc PR-preview outage.
1789
- // presence-mode keeps pruneHidden so "appeared" still means
1790
- // visibly-reachable. a departed gate is unmounted or zero-sized, so the
1791
- // cheap structural+layout check is correct here and ~O(n) cheap.
1792
- const matches = await t.queryAll?.(gone ? { hasId: ID } : { hasId: ID, pruneHidden: true })
1793
- if (!Array.isArray(matches)) return undefined
1794
- return matches.find(present) || null
1795
- } catch {
1796
- return undefined
1797
- }
1798
- }
1799
- let goneStreak = 0
1800
- while (Date.now() < deadline) {
1801
- const node = await find()
1802
- if (gone) {
1803
- if (node === null) {
1804
- goneStreak += 1
1805
- if (goneStreak >= 2) return { found: true, elapsed: Date.now() - start }
1806
- } else {
1807
- goneStreak = 0
1808
- }
1809
- } else if (present(node)) {
1810
- return { found: true, node, elapsed: Date.now() - start }
1811
- }
1812
- await new Promise((r) => setTimeout(r, 80))
1429
+ type: "waitFor",
1430
+ waitForOptions: {
1431
+ condition: { type: gone ? "absent" : "present", testID: testId },
1432
+ timeoutMs
1813
1433
  }
1814
- return { found: false, elapsed: Date.now() - start }
1815
- })()`
1816
1434
  },
1817
- {
1818
- timeoutMs: timeoutMs + 1e3
1819
- }
1435
+ { timeoutMs: timeoutMs + 1e3 }
1820
1436
  );
1821
- return result ?? { found: false, elapsed: timeoutMs };
1437
+ if (result?.error) throw new Error(result.error);
1438
+ if (result?.node && !isSimSemanticTree([result.node])) {
1439
+ throw new Error("waitFor returned an invalid semantic node");
1440
+ }
1441
+ return {
1442
+ found: result?.matched === true,
1443
+ ...result?.node ? { node: result.node } : {},
1444
+ elapsed: result?.elapsedMs ?? timeoutMs
1445
+ };
1822
1446
  }
1823
1447
  function consoleEntriesEval(level, limit) {
1824
1448
  const getter = level === "error" ? "getErrors" : "getWarnings";
@@ -2281,38 +1905,30 @@ function formatTimelineEvents(events) {
2281
1905
 
2282
1906
  // cli/commands/inspect/resolve-target.ts
2283
1907
  async function resolveTargetCoords(bridge, target) {
2284
- const arg = JSON.stringify(target.value);
2285
- const findExpr = target.mode === "testid" ? `(await t.findByTestId(${arg})) || (await t.findById(${arg}))` : `await t.findByText(${arg})`;
2286
1908
  const result = await bridge.send({
2287
- type: "evaluate",
2288
- code: `(async () => {
2289
- const t = window.__sootsimTest
2290
- if (!t) return null
2291
- const n = ${findExpr}
2292
- if (!n || !n.absolutePosition || !n.layout) return null
2293
- const resolved =
2294
- typeof n.nodeId === 'number' && typeof t.resolveTapTarget === 'function'
2295
- ? await t.resolveTapTarget(n.nodeId)
2296
- : null
2297
- const cx =
2298
- typeof resolved?.cx === 'number'
2299
- ? resolved.cx
2300
- : n.absolutePosition.x + (n.layout.width || 0) / 2
2301
- const cy =
2302
- typeof resolved?.cy === 'number'
2303
- ? resolved.cy
2304
- : n.absolutePosition.y + (n.layout.height || 0) / 2
2305
- return {
2306
- x: cx,
2307
- y: cy,
2308
- id: n.id ?? null,
2309
- testID: n.testID ?? null,
2310
- text: ${JSON.stringify(target.mode === "text")} ? ${arg} : (n.text ?? n.accessibilityLabel ?? null),
2311
- type: n.type ?? null,
2312
- }
2313
- })()`
1909
+ type: "resolve",
1910
+ selector: target.mode === "testid" ? { testID: target.value } : { text: target.value }
2314
1911
  });
2315
- return result ?? null;
1912
+ if (result === null) return null;
1913
+ if (typeof result !== "object") throw new Error("resolve returned an invalid result");
1914
+ const match = Reflect.get(result, "match");
1915
+ const resolvedTarget = Reflect.get(result, "target");
1916
+ const semanticNodes = [match, resolvedTarget];
1917
+ const point = Reflect.get(result, "point");
1918
+ const x = point !== null && typeof point === "object" ? Reflect.get(point, "x") : void 0;
1919
+ const y = point !== null && typeof point === "object" ? Reflect.get(point, "y") : void 0;
1920
+ if (!isSimSemanticTree(semanticNodes) || typeof x !== "number" || !Number.isFinite(x) || typeof y !== "number" || !Number.isFinite(y)) {
1921
+ throw new Error("resolve returned an invalid result");
1922
+ }
1923
+ const semanticMatch = semanticNodes[0];
1924
+ if (!semanticMatch) throw new Error("resolve returned an invalid result");
1925
+ return {
1926
+ x,
1927
+ y,
1928
+ testID: semanticMatch.testID ?? null,
1929
+ text: semanticMatch.text ?? (target.mode === "text" ? target.value : semanticMatch.label),
1930
+ type: semanticMatch.type
1931
+ };
2316
1932
  }
2317
1933
 
2318
1934
  // src/app-url.ts
@@ -2550,9 +2166,12 @@ var SimClient = class {
2550
2166
  }
2551
2167
  async tree(depth = 5) {
2552
2168
  const { tree } = await inspectTree(this, depth);
2553
- return tree;
2169
+ return Array.isArray(tree) ? tree : [];
2170
+ }
2171
+ resolve(selector) {
2172
+ return this.send({ type: "resolve", selector });
2554
2173
  }
2555
- /** compact visible-UI dump with shell + keyboard state, as the CLI prints. */
2174
+ /** compact visible semantic tree, formatted as the CLI prints it. */
2556
2175
  describe(opts = {}) {
2557
2176
  return inspectDescribe(this, {
2558
2177
  describe: true,
@@ -2782,9 +2401,6 @@ var SimClient = class {
2782
2401
  LAYOUT_GET_NATIVE_EVAL,
2783
2402
  MERGED_CONSOLE_COUNT_EVAL,
2784
2403
  NOISY_TIMELINE_KINDS,
2785
- READY_CONTENT_NODE_FLOOR,
2786
- READY_NODE_STABLE_MS,
2787
- READY_PROBE_POLL_MS,
2788
2404
  SimClient,
2789
2405
  SimClientError,
2790
2406
  SimConnectError,
@@ -2793,8 +2409,6 @@ var SimClient = class {
2793
2409
  SimReadyTimeoutError,
2794
2410
  SimResetError,
2795
2411
  SimTapError,
2796
- WAIT_READY_PROBE,
2797
- WAIT_READY_PROGRESS_INTERVAL_MS,
2798
2412
  buildSimOpenUrl,
2799
2413
  clearConsole,
2800
2414
  clearLogs,
@@ -2802,6 +2416,7 @@ var SimClient = class {
2802
2416
  detectOpenNativeUI,
2803
2417
  filterLogEntries,
2804
2418
  formatLayoutElements,
2419
+ formatSemanticTree,
2805
2420
  formatTimelineEvent,
2806
2421
  formatTimelineEvents,
2807
2422
  formatTimelinePayload,
@@ -2834,6 +2449,7 @@ var SimClient = class {
2834
2449
  isInspectModeActive,
2835
2450
  isInspectPickCommand,
2836
2451
  isShellCommandUnavailable,
2452
+ isSimSemanticTree,
2837
2453
  isTapSuccess,
2838
2454
  layoutGetNativeEval,
2839
2455
  rankInteractive,