rnxsim 0.1.313 → 0.1.314

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 (297) hide show
  1. package/LICENSE +11 -10
  2. package/README.md +5 -0
  3. package/cli/app-config.ts +65 -0
  4. package/cli/app-fonts.ts +408 -0
  5. package/cli/app-project.ts +231 -0
  6. package/cli/app-splash.ts +185 -0
  7. package/cli/app-state-reset.ts +24 -0
  8. package/cli/auth.ts +155 -0
  9. package/cli/bin.ts +594 -0
  10. package/cli/bridge-diagnostics.ts +226 -0
  11. package/cli/bridge-flow-runner.ts +2830 -0
  12. package/cli/browser-evals.ts +96 -0
  13. package/cli/commands/agent-wrapper.ts +986 -0
  14. package/cli/commands/agent.ts +423 -0
  15. package/cli/commands/app-fonts.ts +98 -0
  16. package/cli/commands/assert.ts +541 -0
  17. package/cli/commands/auth.ts +59 -0
  18. package/cli/commands/camera.ts +266 -0
  19. package/cli/commands/cleanup.ts +169 -0
  20. package/cli/commands/compat.ts +87 -0
  21. package/cli/commands/config.ts +32 -0
  22. package/cli/commands/control.ts +2142 -0
  23. package/cli/commands/cpu-profile.ts +269 -0
  24. package/cli/commands/daemon-mac-app.ts +169 -0
  25. package/cli/commands/daemon.ts +874 -0
  26. package/cli/commands/debug.ts +719 -0
  27. package/cli/commands/desktop.ts +39 -0
  28. package/cli/commands/detect.ts +197 -0
  29. package/cli/commands/detox.ts +385 -0
  30. package/cli/commands/device.ts +133 -0
  31. package/cli/commands/diagnose.ts +589 -0
  32. package/cli/commands/electron.ts +95 -0
  33. package/cli/commands/film.ts +379 -0
  34. package/cli/commands/flow.ts +1124 -0
  35. package/cli/commands/inspect/actions.ts +622 -0
  36. package/cli/commands/inspect/core.ts +2405 -0
  37. package/cli/commands/inspect/count.ts +17 -0
  38. package/cli/commands/inspect/describe.ts +192 -0
  39. package/cli/commands/inspect/env.ts +23 -0
  40. package/cli/commands/inspect/find.ts +171 -0
  41. package/cli/commands/inspect/get-layout.ts +39 -0
  42. package/cli/commands/inspect/keyboard.ts +52 -0
  43. package/cli/commands/inspect/list.ts +58 -0
  44. package/cli/commands/inspect/memory.ts +215 -0
  45. package/cli/commands/inspect/redaction.ts +39 -0
  46. package/cli/commands/inspect/resolve-target.ts +82 -0
  47. package/cli/commands/inspect/screens.ts +78 -0
  48. package/cli/commands/inspect/settle.ts +22 -0
  49. package/cli/commands/inspect/settling.ts +158 -0
  50. package/cli/commands/inspect/shared.ts +353 -0
  51. package/cli/commands/inspect/sleep.ts +14 -0
  52. package/cli/commands/inspect/tree.ts +32 -0
  53. package/cli/commands/inspect/url.ts +17 -0
  54. package/cli/commands/inspect/wait-event.ts +210 -0
  55. package/cli/commands/inspect/wait-idle.ts +24 -0
  56. package/cli/commands/inspect/wait-ready.ts +74 -0
  57. package/cli/commands/inspect/wait-selector.ts +54 -0
  58. package/cli/commands/inspect/wait.ts +31 -0
  59. package/cli/commands/inspect.ts +4519 -0
  60. package/cli/commands/install-desktop.ts +351 -0
  61. package/cli/commands/login.ts +331 -0
  62. package/cli/commands/logout.ts +31 -0
  63. package/cli/commands/maestro-generate.ts +361 -0
  64. package/cli/commands/maestro.ts +453 -0
  65. package/cli/commands/mode.ts +57 -0
  66. package/cli/commands/no-bridge-hint.ts +80 -0
  67. package/cli/commands/perf.ts +66 -0
  68. package/cli/commands/permissions.ts +203 -0
  69. package/cli/commands/profile.ts +108 -0
  70. package/cli/commands/react.ts +353 -0
  71. package/cli/commands/record.ts +1434 -0
  72. package/cli/commands/report-issue.ts +305 -0
  73. package/cli/commands/reset.ts +85 -0
  74. package/cli/commands/runtime.ts +351 -0
  75. package/cli/commands/screenshot-command.ts +106 -0
  76. package/cli/commands/screenshot-layers.ts +143 -0
  77. package/cli/commands/screenshot-mode.ts +37 -0
  78. package/cli/commands/screenshot.ts +488 -0
  79. package/cli/commands/screenshots-capture.ts +607 -0
  80. package/cli/commands/screenshots.ts +127 -0
  81. package/cli/commands/serve.ts +168 -0
  82. package/cli/commands/setup.ts +545 -0
  83. package/cli/commands/shell-boolean-mode.ts +81 -0
  84. package/cli/commands/skills.ts +467 -0
  85. package/cli/commands/slides.ts +361 -0
  86. package/cli/commands/state.ts +87 -0
  87. package/cli/commands/storage.ts +58 -0
  88. package/cli/commands/telemetry.ts +54 -0
  89. package/cli/commands/three-mode.ts +763 -0
  90. package/cli/commands/timeline.ts +122 -0
  91. package/cli/commands/upgrade.ts +208 -0
  92. package/cli/commands/upload.ts +1225 -0
  93. package/cli/commands/version.ts +54 -0
  94. package/cli/commands/what-happened.ts +327 -0
  95. package/cli/current-sim.ts +204 -0
  96. package/cli/desktop-companion.ts +300 -0
  97. package/cli/drivers/electron.ts +70 -0
  98. package/cli/drivers/index.ts +20 -0
  99. package/cli/drivers/playwright-provisioning.ts +180 -0
  100. package/cli/drivers/playwright.ts +698 -0
  101. package/cli/drivers/registry.ts +65 -0
  102. package/cli/drivers/types.ts +102 -0
  103. package/cli/flow-file.ts +142 -0
  104. package/cli/flow-live-status.ts +120 -0
  105. package/cli/flow-session.ts +187 -0
  106. package/cli/help.ts +80 -0
  107. package/cli/hidden-runtime-alias.ts +19 -0
  108. package/cli/hints.ts +216 -0
  109. package/cli/inspect-notice-state.ts +114 -0
  110. package/cli/maestro-js.ts +334 -0
  111. package/cli/open-url.ts +8 -0
  112. package/cli/parent-pid.ts +204 -0
  113. package/cli/parse-args.ts +211 -0
  114. package/cli/prompt.ts +51 -0
  115. package/cli/recording-access.ts +107 -0
  116. package/cli/registry.ts +1 -0
  117. package/cli/resolve-assets.ts +63 -0
  118. package/cli/run-registry.ts +226 -0
  119. package/cli/runtime-notes.ts +66 -0
  120. package/cli/runtime-summary.ts +25 -0
  121. package/cli/setup-repository.ts +187 -0
  122. package/cli/telemetry.ts +187 -0
  123. package/cli/ws-bridge.ts +798 -0
  124. package/dist-cli/bin.js +5 -5
  125. package/dist-cli/chunks/{agent-XZ2KTPCU.js → agent-7YBDCYMA.js} +2 -2
  126. package/dist-cli/chunks/{agent-wrapper-JJYYW2WH.js → agent-wrapper-2GHFBHCR.js} +2 -2
  127. package/dist-cli/chunks/{app-fonts-IXRNQG6B.js → app-fonts-RSNVPQSU.js} +2 -2
  128. package/dist-cli/chunks/{assert-54T5SK5F.js → assert-XCMX3XJX.js} +2 -2
  129. package/dist-cli/chunks/{auth-FI5UDI45.js → auth-B442HRAX.js} +2 -2
  130. package/dist-cli/chunks/{beta-JV6UKADW.js → beta-XJ55JK3M.js} +2 -2
  131. package/dist-cli/chunks/camera-UGYSSLIK.js +33 -0
  132. package/dist-cli/chunks/{chunk-3NV2NCNX.js → chunk-277AEQZX.js} +2 -2
  133. package/dist-cli/chunks/{chunk-2YR5BGA5.js → chunk-2JNSK774.js} +2 -2
  134. package/dist-cli/chunks/{chunk-RSZWCKNT.js → chunk-32WOTSTR.js} +3 -3
  135. package/dist-cli/chunks/{chunk-WEXDAC74.js → chunk-3S753SNQ.js} +2 -2
  136. package/dist-cli/chunks/{chunk-IJO63TDP.js → chunk-46ZOLOYA.js} +2 -2
  137. package/dist-cli/chunks/{chunk-WUSWBCWA.js → chunk-5L7ELDQL.js} +8 -9
  138. package/dist-cli/chunks/{chunk-WF3T4SVI.js → chunk-7OOPFSQS.js} +2 -2
  139. package/dist-cli/chunks/{chunk-TZFFR3SD.js → chunk-7SV3RPRW.js} +2 -2
  140. package/dist-cli/chunks/{chunk-WWZIXIRD.js → chunk-7ZC35MOU.js} +1 -1
  141. package/dist-cli/chunks/chunk-AMG5E6CC.js +9 -0
  142. package/dist-cli/chunks/{chunk-WINYQ44O.js → chunk-APWNH3A4.js} +1 -1
  143. package/dist-cli/chunks/chunk-B57XUKY3.js +4 -0
  144. package/dist-cli/chunks/{chunk-YDGQTMQL.js → chunk-C2NL26TD.js} +1 -1
  145. package/dist-cli/chunks/{chunk-NMF2ZMZQ.js → chunk-D2FNUWAB.js} +4 -4
  146. package/dist-cli/chunks/{chunk-YIFT42WN.js → chunk-E5T4XSJ3.js} +2 -2
  147. package/dist-cli/chunks/{chunk-46EUUFJ5.js → chunk-EAC34EQS.js} +1 -1
  148. package/dist-cli/chunks/{chunk-OVFJFXUD.js → chunk-EG32ML36.js} +2 -2
  149. package/dist-cli/chunks/{chunk-5YJCOWCH.js → chunk-FXUAC6D5.js} +1 -1
  150. package/dist-cli/chunks/chunk-GQSL4USA.js +6 -0
  151. package/dist-cli/chunks/{chunk-VFCMSYZK.js → chunk-HAXW27SS.js} +2 -2
  152. package/dist-cli/chunks/{chunk-2D2UPBBR.js → chunk-IZAHPAN6.js} +1 -1
  153. package/dist-cli/chunks/{chunk-7GN3LVWB.js → chunk-J62KM5TB.js} +2 -2
  154. package/dist-cli/chunks/{chunk-BTWORNNG.js → chunk-JEMCD5E4.js} +1 -1
  155. package/dist-cli/chunks/{chunk-DCEMHR2Y.js → chunk-JZS3Q37N.js} +2 -2
  156. package/dist-cli/chunks/{chunk-D4FFVGI5.js → chunk-KR4JON7D.js} +1 -1
  157. package/dist-cli/chunks/chunk-KWCYKQIQ.js +4 -0
  158. package/dist-cli/chunks/{chunk-VNQEB4L7.js → chunk-MCWPL644.js} +2 -2
  159. package/dist-cli/chunks/chunk-MJYK3N2I.js +4 -0
  160. package/dist-cli/chunks/{chunk-5TEF3ET3.js → chunk-O6TRIZNS.js} +2 -2
  161. package/dist-cli/chunks/{chunk-QKDWYITG.js → chunk-P7XL2E73.js} +3 -3
  162. package/dist-cli/chunks/{chunk-BBULZ7CG.js → chunk-PFQTUKQ4.js} +62 -87
  163. package/dist-cli/chunks/{chunk-GGRX24GF.js → chunk-PG5RZCTN.js} +2 -2
  164. package/dist-cli/chunks/{chunk-W6K4EFPH.js → chunk-QGRI2Z4M.js} +2 -2
  165. package/dist-cli/chunks/{chunk-ZMJD5GEC.js → chunk-QLXXE7GE.js} +1 -1
  166. package/dist-cli/chunks/{chunk-VZXWHRUZ.js → chunk-QOJJJWJE.js} +89 -133
  167. package/dist-cli/chunks/{chunk-OZSSI4WN.js → chunk-RWZY5427.js} +2 -2
  168. package/dist-cli/chunks/{chunk-UC6U3MML.js → chunk-RZKU2K3J.js} +2 -2
  169. package/dist-cli/chunks/{chunk-IJ5CAZZC.js → chunk-SBV4IK4H.js} +1 -1
  170. package/dist-cli/chunks/{chunk-DZS6WPUI.js → chunk-SGMVFFMK.js} +1 -1
  171. package/dist-cli/chunks/{chunk-OHAZNXLK.js → chunk-TAX4UT2N.js} +1 -1
  172. package/dist-cli/chunks/{chunk-5DHC6KHQ.js → chunk-TUOFAWXT.js} +1 -1
  173. package/dist-cli/chunks/{chunk-GASE6UBA.js → chunk-UHZLOHGP.js} +1 -1
  174. package/dist-cli/chunks/{chunk-F5ZRSS3C.js → chunk-VC7V76U3.js} +1 -1
  175. package/dist-cli/chunks/{chunk-RTN5C5RL.js → chunk-VQVMLW4U.js} +1 -1
  176. package/dist-cli/chunks/{chunk-WMIIKMGK.js → chunk-VUKKYPZN.js} +2 -2
  177. package/dist-cli/chunks/{chunk-5TPRP5QT.js → chunk-WGGRJDRE.js} +1 -1
  178. package/dist-cli/chunks/chunk-X6H76EKP.js +15 -0
  179. package/dist-cli/chunks/chunk-XLZ5FNRT.js +27 -0
  180. package/dist-cli/chunks/{chunk-HI5TFJWN.js → chunk-XULEACM4.js} +2 -2
  181. package/dist-cli/chunks/{chunk-MJRLLB4R.js → chunk-YFSDM7AX.js} +4 -4
  182. package/dist-cli/chunks/chunk-YWI3UEVX.js +5 -0
  183. package/dist-cli/chunks/{chunk-XEVZYVIW.js → chunk-ZBSJO4NB.js} +10 -9
  184. package/dist-cli/chunks/{cleanup-P27PA6JI.js → cleanup-EYLGCA6Z.js} +2 -2
  185. package/dist-cli/chunks/cli-version-LL2UGIHE.js +4 -0
  186. package/dist-cli/chunks/{compat-ZD65FED3.js → compat-TLJYHB4E.js} +2 -2
  187. package/dist-cli/chunks/{config-XMJRNM2A.js → config-4JWUOEXK.js} +2 -2
  188. package/dist-cli/chunks/{control-KMIQT3QP.js → control-HPAOYF4N.js} +2 -2
  189. package/dist-cli/chunks/daemon-OYLASXLE.js +4 -0
  190. package/dist-cli/chunks/{debug-PT4HOP7N.js → debug-4BKXF6KI.js} +5 -5
  191. package/dist-cli/chunks/{desktop-S3FG72AK.js → desktop-ZQ6ZD2S6.js} +3 -3
  192. package/dist-cli/chunks/{detox-B3D4IFCN.js → detox-WNPASSS3.js} +2 -2
  193. package/dist-cli/chunks/{device-XBNDSB2R.js → device-BXLXVG3V.js} +2 -2
  194. package/dist-cli/chunks/{diagnose-HMQXJE5N.js → diagnose-3QX7W5RW.js} +2 -2
  195. package/dist-cli/chunks/{disk-cleanup-BLCZ5BSZ.js → disk-cleanup-KSWKI7WB.js} +2 -2
  196. package/dist-cli/chunks/drivers-EPIEFF7P.js +4 -0
  197. package/dist-cli/chunks/{film-BJGTBYZB.js → film-GDMR33VO.js} +3 -3
  198. package/dist-cli/chunks/flow-NKMPBYCJ.js +4 -0
  199. package/dist-cli/chunks/help-OGCBHOKA.js +4 -0
  200. package/dist-cli/chunks/{hidden-runtime-alias-ANOYADHM.js → hidden-runtime-alias-S2GTDX3T.js} +2 -2
  201. package/dist-cli/chunks/home-paths-QRCDLTTV.js +4 -0
  202. package/dist-cli/chunks/inspect-FUYMOZPY.js +4 -0
  203. package/dist-cli/chunks/install-desktop-FR6YKW7Y.js +4 -0
  204. package/dist-cli/chunks/{login-FJ737MWG.js → login-IJAPUZHI.js} +4 -4
  205. package/dist-cli/chunks/{logout-ZCNMMHMY.js → logout-QMXDFU2X.js} +2 -2
  206. package/dist-cli/chunks/{maestro-SZTNKLDF.js → maestro-ZXU3YCVX.js} +3 -3
  207. package/dist-cli/chunks/{maestro-generate-DCFAIZ4H.js → maestro-generate-PYB5QY7K.js} +3 -3
  208. package/dist-cli/chunks/{mode-GRMQCRXR.js → mode-WGUCL5FZ.js} +2 -2
  209. package/dist-cli/chunks/{optional-demo-registry-W36EWFFB.js → optional-demo-registry-WH2O6H36.js} +2 -2
  210. package/dist-cli/chunks/{perf-QYBAAUZG.js → perf-TOD3UFAH.js} +2 -2
  211. package/dist-cli/chunks/{permissions-3QCQ6VF4.js → permissions-I5BRJGTB.js} +2 -2
  212. package/dist-cli/chunks/{record-QPPC2S4E.js → record-ZYL2FYSK.js} +3 -3
  213. package/dist-cli/chunks/{report-issue-7NMFP4HK.js → report-issue-TAI6DYZO.js} +2 -2
  214. package/dist-cli/chunks/reset-7YGYKQPQ.js +4 -0
  215. package/dist-cli/chunks/runtime-B4JO6QRI.js +4 -0
  216. package/dist-cli/chunks/{screenshot-command-67AECJFB.js → screenshot-command-7ANLODZY.js} +7 -7
  217. package/dist-cli/chunks/{screenshot-layers-ASWBYPJL.js → screenshot-layers-A7FYXSVU.js} +3 -3
  218. package/dist-cli/chunks/{screenshots-capture-PXA3HFQK.js → screenshots-capture-WT2ZY6CB.js} +2 -2
  219. package/dist-cli/chunks/serve-TG5WKA4V.js +44 -0
  220. package/dist-cli/chunks/{setup-7DWPMRSB.js → setup-PCWLD22V.js} +2 -2
  221. package/dist-cli/chunks/{skills-S3Y22TUA.js → skills-27ZHWCQS.js} +2 -2
  222. package/dist-cli/chunks/state-ZQVY46ZO.js +14 -0
  223. package/dist-cli/chunks/{storage-XUIMJWAJ.js → storage-OYC57C4X.js} +6 -6
  224. package/dist-cli/chunks/store-32HSPZHI.js +4 -0
  225. package/dist-cli/chunks/telemetry-PBJR7XHR.js +4 -0
  226. package/dist-cli/chunks/{timeline-TMPLQPSP.js → timeline-RAJJFQT6.js} +2 -2
  227. package/dist-cli/chunks/{upgrade-7HDSIM7K.js → upgrade-OEFNZRIP.js} +2 -2
  228. package/dist-cli/chunks/upload-LQJITLKK.js +4 -0
  229. package/dist-cli/chunks/version-NIXTY6PL.js +6 -0
  230. package/dist-cli/chunks/{web-DG3WBYD3.js → web-XBUTBVGR.js} +2 -2
  231. package/dist-cli/chunks/{what-happened-XFVUTZR7.js → what-happened-YNHRFUDX.js} +3 -3
  232. package/dist-lib/agent-daemon-client.cjs +1 -1
  233. package/dist-lib/agent-events.cjs +1 -1
  234. package/dist-lib/agent-identity.cjs +1 -1
  235. package/dist-lib/agent-sessions.cjs +1 -1
  236. package/dist-lib/attached-projects.cjs +1 -1
  237. package/dist-lib/auth/shared-session.cjs +1 -1
  238. package/dist-lib/backend-origin.cjs +1 -1
  239. package/dist-lib/beta.cjs +1 -1
  240. package/dist-lib/beta.mjs +1 -1
  241. package/dist-lib/bridge-constants.cjs +1 -1
  242. package/dist-lib/bridge-contract.cjs +20 -0
  243. package/dist-lib/cli-constants.cjs +1 -1
  244. package/dist-lib/config.cjs +1 -1
  245. package/dist-lib/detox/index.cjs +1 -1
  246. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  247. package/dist-lib/home-paths.cjs +67 -28
  248. package/dist-lib/host/bridge-host.cjs +140 -12
  249. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  250. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  251. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  252. package/dist-lib/host/websocket-proxy.cjs +1 -1
  253. package/dist-lib/index.cjs +2815 -40
  254. package/dist-lib/jump-to-source-babel.cjs +1 -1
  255. package/dist-lib/menu.cjs +1 -1
  256. package/dist-lib/menu.mjs +1 -1
  257. package/dist-lib/metro.cjs +1 -1
  258. package/dist-lib/profiles.cjs +1 -1
  259. package/dist-lib/public-brand.cjs +1 -1
  260. package/dist-lib/render-mode.cjs +1 -1
  261. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  262. package/dist-lib/sdk.cjs +2549 -2061
  263. package/dist-lib/sdk.mjs +2543 -2061
  264. package/dist-lib/skills.cjs +480 -280
  265. package/dist-lib/vite.cjs +1 -1
  266. package/package.json +8 -2
  267. package/src/bridge-constants.ts +3 -4
  268. package/src/bridge-contract.ts +251 -0
  269. package/src/connect.ts +83 -0
  270. package/src/disk-cleanup.ts +30 -0
  271. package/src/home-paths.ts +81 -38
  272. package/src/host/bridge-host.ts +134 -6
  273. package/src/index.ts +27 -1
  274. package/src/sdk.ts +8 -0
  275. package/src/sim-client.ts +660 -0
  276. package/dist-cli/chunks/camera-VL73YIKP.js +0 -22
  277. package/dist-cli/chunks/chunk-4NPPOV2N.js +0 -5
  278. package/dist-cli/chunks/chunk-FSUYIVJ6.js +0 -9
  279. package/dist-cli/chunks/chunk-G2WW6L2C.js +0 -23
  280. package/dist-cli/chunks/chunk-KTHV3RUS.js +0 -26
  281. package/dist-cli/chunks/chunk-LF2ZVT7O.js +0 -6
  282. package/dist-cli/chunks/chunk-NFK7T35W.js +0 -4
  283. package/dist-cli/chunks/chunk-TIVZIMMW.js +0 -4
  284. package/dist-cli/chunks/cli-version-WWLPBDQ7.js +0 -4
  285. package/dist-cli/chunks/daemon-G2ME7NLB.js +0 -4
  286. package/dist-cli/chunks/drivers-LDECZGP2.js +0 -4
  287. package/dist-cli/chunks/flow-UEQNVTU7.js +0 -4
  288. package/dist-cli/chunks/help-T5FYSVGB.js +0 -4
  289. package/dist-cli/chunks/home-paths-GT3LFNOR.js +0 -4
  290. package/dist-cli/chunks/inspect-ZA6XF5LD.js +0 -4
  291. package/dist-cli/chunks/install-desktop-TIMUDHPL.js +0 -4
  292. package/dist-cli/chunks/runtime-XOAXMSTU.js +0 -4
  293. package/dist-cli/chunks/serve-BI2NBAXG.js +0 -44
  294. package/dist-cli/chunks/store-JTHEJLAZ.js +0 -4
  295. package/dist-cli/chunks/telemetry-ZYJGD2DB.js +0 -4
  296. package/dist-cli/chunks/upload-GMSZPWM6.js +0 -4
  297. package/dist-cli/chunks/version-HOCHZ37L.js +0 -6
@@ -0,0 +1,719 @@
1
+ // sootsim debug — drive __sootsimDebug.* from the terminal
2
+ //
3
+ // connects to a running sootsim instance via the WebSocket bridge and forwards
4
+ // debug channel management, tree snapshots, and on-demand inspectors without
5
+ // requiring a browser console.
6
+ //
7
+ // usage examples:
8
+ // sootsim debug enable sheets,portals,onlayout
9
+ // sootsim debug status
10
+ // sootsim debug snapshot before
11
+ // # ... tap something in the UI ...
12
+ // sootsim debug snapshot after
13
+ // sootsim debug diff before after
14
+ // sootsim debug find sheets
15
+ // sootsim debug find portals
16
+ // sootsim debug recent portals
17
+ // sootsim debug flags
18
+ //
19
+ // all commands print JSON by default so they pipe cleanly into jq.
20
+
21
+ import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
22
+ import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
23
+ import {
24
+ createBridgeFromParsed,
25
+ evalInBridge,
26
+ parseBridgeCliArgs,
27
+ type WsBridge,
28
+ } from '../ws-bridge'
29
+ import {
30
+ inspectDebugFind,
31
+ inspectDebugFlags,
32
+ inspectDebugRecent,
33
+ inspectDebugStatus,
34
+ setDebugChannels,
35
+ } from './inspect/core'
36
+ import { callTestBridge } from './inspect/shared'
37
+
38
+ interface DebugOptions {
39
+ port?: number
40
+ verbose?: boolean
41
+ }
42
+
43
+ const KNOWN_CHANNELS = [
44
+ 'portals',
45
+ 'sheets',
46
+ 'layout',
47
+ 'onlayout',
48
+ 'animated',
49
+ 'render',
50
+ 'touch',
51
+ 'yoga',
52
+ 'all',
53
+ ] as const
54
+
55
+ const SHELL_TRACE_STORE_GLOBAL = '__sootsimShellAnimationTrace'
56
+ const SHELL_TRACE_HOOK_GLOBAL = '__sootsimDebugAnimation'
57
+
58
+ function printHelp() {
59
+ console.log(`
60
+ rnxsim debug — drive __sootsimDebug from the terminal
61
+
62
+ usage:
63
+ rnxsim debug <subcommand> [args]
64
+
65
+ subcommands:
66
+ enable <channels> turn on one or more debug channels
67
+ channels: ${KNOWN_CHANNELS.slice(0, -1).join(', ')}
68
+ or 'all' for every channel
69
+ disable <channels> turn off one or more debug channels (or 'all')
70
+ toggle <channel> flip a single channel
71
+ status list currently-enabled channels
72
+ channels list every known channel name
73
+ flags print the full DEBUG flag object
74
+
75
+ state <kind> ... dump raw runtime state (diagnostic — not a getter)
76
+ kinds: shell, worker, keyboard, node <id>,
77
+ scroll <id>, scroll-hit <x> <y>,
78
+ hit <x> <y>, gesture <x> <y>
79
+
80
+ js <code> execute javascript in the running app. SootSim
81
+ is the canonical state object — reach into its
82
+ bridges / state / chrome / debug slots directly.
83
+ e.g. SootSim.bridges.test.findByText("Sign in")
84
+ eval <code> alias for js
85
+ perf <sub> shell frame profiling: start, stop, transition
86
+ memory [--watch [s]] per-worker object counts + heaps; --watch samples
87
+ every --interval seconds and reports slopes
88
+ sample-color <...> sample averaged color from canvas (same flags as
89
+ screenshot)
90
+
91
+ snapshot [label] capture a tree snapshot (layout + transform + opacity)
92
+ snapshots list taken snapshot labels
93
+ diff <a> <b> compare two snapshots by label
94
+ clear-snapshots [label] drop a snapshot (or all if no label given)
95
+
96
+ image-audit for every image the compositor actually drew, the
97
+ source pixels it landed on each device pixel. a row
98
+ whose shortfall is well under 1.0 is an image the
99
+ pipeline under-resolved; 0.5 is half resolution.
100
+ flags: --min <ratio> (default 0.98), --all, --json
101
+ exits 1 when any image is under the ratio, and 2 when
102
+ the audit observed no image draws at all
103
+
104
+ find sheets dump Sheet.Frame-shaped nodes currently in the tree
105
+ find portals dump portal-host / portal-view nodes
106
+ find boundaries dump live paint boundaries (+ why scroll rows were
107
+ rejected from the auto-retained raster tier)
108
+
109
+ trace shell [cmd] opt-in shell animation trace
110
+ cmds: on [limit], off, status, clear, [recentLimit]
111
+ trace anim <sub> opt-in per-tick animation value trace
112
+ subs: on <id|all> [limit], off [id|all],
113
+ status, clear, <id> [limit]
114
+ record [on|off] toggle event ring buffer recording
115
+ recent [channel] [n] last N events (default 50), optionally filtered
116
+ clear-events clear the event ring buffer
117
+
118
+ options:
119
+ --port <port> WS bridge port (default: ${DEFAULT_SOOTSIM_BRIDGE_PORT})
120
+ --sim <sim> target a specific connected sim
121
+ --pretty format JSON output for humans (default)
122
+ --json compact JSON output for pipelines
123
+
124
+ examples:
125
+ rnxsim debug enable sheets,portals
126
+ rnxsim debug snapshot before
127
+ rnxsim debug snapshot after
128
+ rnxsim debug diff before after
129
+ rnxsim debug image-audit per-image source pixels per device pixel
130
+ rnxsim debug find sheets | jq '.[] | select(.translateY != null)'
131
+ rnxsim debug trace shell on 240
132
+ rnxsim debug trace shell 120
133
+ rnxsim debug trace anim on 3 240
134
+ rnxsim debug trace anim 3 60
135
+ `)
136
+ }
137
+
138
+ function parseChannelList(raw: string | undefined): string[] {
139
+ if (!raw) return []
140
+ return raw
141
+ .split(',')
142
+ .map((s) => s.trim())
143
+ .filter(Boolean)
144
+ }
145
+
146
+ function fmt(value: unknown, pretty: boolean): string {
147
+ if (value === undefined) return ''
148
+ return JSON.stringify(value, null, pretty ? 2 : 0)
149
+ }
150
+
151
+ function buildShellTraceControlCode(
152
+ action: 'on' | 'off' | 'clear' | 'status',
153
+ limit = 240,
154
+ ): string {
155
+ const normalizedLimit =
156
+ Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 240
157
+ const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
158
+ const hookKey = JSON.stringify(SHELL_TRACE_HOOK_GLOBAL)
159
+ if (action === 'on') {
160
+ return `(() => {
161
+ const root = window
162
+ const store = root[${storeKey}] || (root[${storeKey}] = {
163
+ enabled: false,
164
+ limit: ${normalizedLimit},
165
+ seq: 0,
166
+ samples: [],
167
+ prevHook: undefined,
168
+ hook: undefined,
169
+ })
170
+ store.limit = ${normalizedLimit}
171
+ store.enabled = true
172
+ const currentHook = root[${hookKey}]
173
+ if (store.hook !== currentHook) {
174
+ store.prevHook = typeof currentHook === 'function' ? currentHook : undefined
175
+ }
176
+ if (typeof store.hook !== 'function') {
177
+ store.hook = (sample) => {
178
+ const target = root[${storeKey}]
179
+ if (!target || target.enabled !== true) return
180
+ const samples = Array.isArray(target.samples) ? target.samples : (target.samples = [])
181
+ target.seq = typeof target.seq === 'number' ? target.seq + 1 : 1
182
+ samples.push({ seq: target.seq, ...sample })
183
+ if (samples.length > target.limit) {
184
+ samples.splice(0, samples.length - target.limit)
185
+ }
186
+ if (typeof target.prevHook === 'function') {
187
+ try {
188
+ target.prevHook(sample)
189
+ } catch {}
190
+ }
191
+ }
192
+ }
193
+ root[${hookKey}] = store.hook
194
+ return {
195
+ enabled: true,
196
+ limit: store.limit,
197
+ count: Array.isArray(store.samples) ? store.samples.length : 0,
198
+ }
199
+ })()`
200
+ }
201
+ if (action === 'off') {
202
+ return `(() => {
203
+ const root = window
204
+ const store = root[${storeKey}]
205
+ if (!store) return { enabled: false, limit: 0, count: 0 }
206
+ store.enabled = false
207
+ if (root[${hookKey}] === store.hook) {
208
+ root[${hookKey}] = typeof store.prevHook === 'function' ? store.prevHook : undefined
209
+ }
210
+ return {
211
+ enabled: false,
212
+ limit: typeof store.limit === 'number' ? store.limit : 0,
213
+ count: Array.isArray(store.samples) ? store.samples.length : 0,
214
+ }
215
+ })()`
216
+ }
217
+ if (action === 'clear') {
218
+ return `(() => {
219
+ const store = window[${storeKey}]
220
+ if (!store) return { cleared: true, count: 0 }
221
+ store.samples = []
222
+ store.seq = 0
223
+ return {
224
+ cleared: true,
225
+ enabled: store.enabled === true,
226
+ limit: typeof store.limit === 'number' ? store.limit : 0,
227
+ count: 0,
228
+ }
229
+ })()`
230
+ }
231
+ return `(() => {
232
+ const store = window[${storeKey}]
233
+ return {
234
+ enabled: !!store?.enabled,
235
+ limit: typeof store?.limit === 'number' ? store.limit : 0,
236
+ count: Array.isArray(store?.samples) ? store.samples.length : 0,
237
+ }
238
+ })()`
239
+ }
240
+
241
+ function buildShellTraceRecentCode(limit = 50): string {
242
+ const normalizedLimit =
243
+ Number.isFinite(limit) && limit > 0 ? Math.max(1, Math.round(limit)) : 50
244
+ const storeKey = JSON.stringify(SHELL_TRACE_STORE_GLOBAL)
245
+ return `(() => {
246
+ const store = window[${storeKey}]
247
+ const all = Array.isArray(store?.samples) ? store.samples : []
248
+ const samples = all.slice(-${normalizedLimit})
249
+ const first = samples[0] ?? null
250
+ const last = samples[samples.length - 1] ?? null
251
+ const uniquePhases = [...new Set(samples.map((sample) => sample?.phase).filter(Boolean))]
252
+ const metricRange = (key) => {
253
+ const values = samples
254
+ .map((sample) => (typeof sample?.[key] === 'number' ? sample[key] : null))
255
+ .filter((value) => value != null)
256
+ if (values.length === 0) return null
257
+ return {
258
+ min: Math.min(...values),
259
+ max: Math.max(...values),
260
+ }
261
+ }
262
+ return {
263
+ enabled: !!store?.enabled,
264
+ limit: typeof store?.limit === 'number' ? store.limit : 0,
265
+ count: samples.length,
266
+ total: all.length,
267
+ summary: first && last ? {
268
+ durationMs: last.ts - first.ts,
269
+ phases: uniquePhases,
270
+ start: first,
271
+ end: last,
272
+ zoomLevel: metricRange('zoomLevel'),
273
+ horizontalZoom: metricRange('horizontalZoom'),
274
+ launchProgress: metricRange('launchProgress'),
275
+ dismissOffsetY: metricRange('dismissOffsetY'),
276
+ } : null,
277
+ samples,
278
+ }
279
+ })()`
280
+ }
281
+
282
+ async function call<T = unknown>(bridge: WsBridge, code: string): Promise<T> {
283
+ return evalInBridge<T>(bridge, code)
284
+ }
285
+
286
+ interface ImageAuditRowView {
287
+ nodeId: number
288
+ type: string
289
+ testID: string | null
290
+ sourceUri: string | null
291
+ resizeMode: string | null
292
+ sampling: string | null
293
+ vector: boolean
294
+ intrinsic: { width: number; height: number } | null
295
+ decoded: { width: number; height: number }
296
+ sampled: { width: number; height: number }
297
+ destination: { width: number; height: number }
298
+ deviceScale: number
299
+ dpr: number
300
+ needed: { width: number; height: number }
301
+ effective: { width: number; height: number }
302
+ ceiling: { width: number; height: number } | null
303
+ shortfall: number | null
304
+ }
305
+
306
+ interface ImageAuditReportView {
307
+ draws: number
308
+ rows: ImageAuditRowView[]
309
+ }
310
+
311
+ function readNumberFlag(args: string[], flag: string): number | null {
312
+ const index = args.indexOf(flag)
313
+ if (index < 0) return null
314
+ const parsed = Number(args[index + 1])
315
+ return Number.isFinite(parsed) ? parsed : null
316
+ }
317
+
318
+ // enable the audit, force one real frame, then read and stop. the screenshot
319
+ // request is what forces the frame: it runs the same publish-and-paint pass
320
+ // `sootsim screenshot` does, so the rows describe pixels that were actually
321
+ // produced rather than a tree walk's guess about them.
322
+ async function runImageAudit(bridge: WsBridge): Promise<ImageAuditReportView> {
323
+ await call(
324
+ bridge,
325
+ "window.__sootsimCompositor.getStats(false, false, undefined, 'enable').then(() => 'enabled')",
326
+ )
327
+ await bridge.send({ type: 'screenshot' })
328
+ const stats = await call<{ imageAudit?: ImageAuditReportView | null }>(
329
+ bridge,
330
+ "window.__sootsimCompositor.getStats(false, false, undefined, 'disable').then((s) => ({ imageAudit: s.imageAudit }))",
331
+ )
332
+ const report = stats?.imageAudit
333
+ if (!report) throw new Error('compositor returned no image audit')
334
+ return report
335
+ }
336
+
337
+ function ratioText(value: number | null): string {
338
+ return value === null ? ' - ' : value.toFixed(3).padStart(6)
339
+ }
340
+
341
+ function sourceText(row: ImageAuditRowView): string {
342
+ const uri = row.sourceUri ?? row.testID ?? `node ${row.nodeId}`
343
+ if (uri.length <= 58) return uri
344
+ return `...${uri.slice(-55)}`
345
+ }
346
+
347
+ function printImageAudit(
348
+ report: ImageAuditReportView,
349
+ rows: ImageAuditRowView[],
350
+ minimum: number,
351
+ ): void {
352
+ const withCeiling = report.rows.filter((row) => row.shortfall !== null)
353
+ const under = withCeiling.filter((row) => row.shortfall! < minimum)
354
+ console.log(
355
+ ` ${report.rows.length} images drawn (${report.draws} draws), ` +
356
+ `${under.length} below ${minimum} of what their source could deliver`,
357
+ )
358
+ if (rows.length === 0) {
359
+ console.log(' every image delivered its source resolution')
360
+ return
361
+ }
362
+ console.log('')
363
+ console.log(' short eff decoded source needed(dev) dest(pt) dpr image')
364
+ for (const row of rows) {
365
+ const decoded = `${row.decoded.width}x${row.decoded.height}`.padEnd(11)
366
+ const intrinsic = (
367
+ row.vector
368
+ ? 'vector'
369
+ : row.intrinsic
370
+ ? `${row.intrinsic.width}x${row.intrinsic.height}`
371
+ : '?'
372
+ ).padEnd(11)
373
+ const needed =
374
+ `${Math.round(row.needed.width)}x${Math.round(row.needed.height)}`.padEnd(12)
375
+ const dest =
376
+ `${Math.round(row.destination.width)}x${Math.round(row.destination.height)}`.padEnd(
377
+ 9,
378
+ )
379
+ console.log(
380
+ ` ${ratioText(row.shortfall)} ${ratioText(row.effective.width)} ` +
381
+ `${decoded} ${intrinsic} ${needed} ${dest} ${row.dpr.toFixed(1)} ${sourceText(row)}`,
382
+ )
383
+ }
384
+ }
385
+
386
+ export async function runDebug(args: string[], opts: DebugOptions) {
387
+ const parsed = parseBridgeCliArgs(args, {
388
+ port: opts.port,
389
+ stripBooleanFlags: ['--pretty', '--json', '--help', '-h'],
390
+ })
391
+ const positional = parsed.positional
392
+ const subcommand = positional[0]
393
+
394
+ if (!subcommand || args.includes('--help') || args.includes('-h')) {
395
+ printHelp()
396
+ process.exit(0)
397
+ }
398
+
399
+ const wsPort = parsed.wsPort
400
+ const simId = parsed.simId
401
+ const pretty = !args.includes('--json')
402
+ const simHint = simId ? ` --sim ${simId}` : ''
403
+
404
+ const sub = positional[0]
405
+ const rest = positional.slice(1)
406
+
407
+ // these subcommands are organized under `debug` for the user but their
408
+ // implementation lives in inspect.ts. forward to runInspect with the raw
409
+ // `debug` prefix intact — runInspect strips it. done before we open a
410
+ // debug-side bridge so we don't hold two bridges at once.
411
+ const INSPECT_FORWARDED = new Set([
412
+ 'state',
413
+ 'js',
414
+ 'eval',
415
+ 'perf',
416
+ 'memory',
417
+ 'sample-color',
418
+ ])
419
+ if (INSPECT_FORWARDED.has(sub)) {
420
+ const { runInspect } = await import('./inspect')
421
+ // pass the raw arg list through so every flag (--sim, --json,
422
+ // --verbose, per-subcommand flags, etc.) reaches the inspect parser
423
+ // untouched. the leading 'debug' is recognized as a verb prefix by
424
+ // runInspect and stripped.
425
+ await runInspect(['debug', ...args], {
426
+ port: opts.port,
427
+ verbose: opts.verbose,
428
+ })
429
+ return
430
+ }
431
+
432
+ const bridge = createBridgeFromParsed(parsed)
433
+
434
+ try {
435
+ switch (sub) {
436
+ case 'enable': {
437
+ const channels = parseChannelList(rest[0])
438
+ if (channels.length === 0) {
439
+ console.error(
440
+ ` usage: rnxsim debug enable <channel[,channel,...]>\n known: ${KNOWN_CHANNELS.join(', ')}`,
441
+ )
442
+ process.exit(1)
443
+ }
444
+ const active = await setDebugChannels(bridge, 'enable', channels)
445
+ console.log(fmt({ active }, pretty))
446
+ break
447
+ }
448
+
449
+ case 'disable': {
450
+ const channels = parseChannelList(rest[0])
451
+ const active = await setDebugChannels(bridge, 'disable', channels)
452
+ console.log(fmt({ active }, pretty))
453
+ break
454
+ }
455
+
456
+ case 'toggle': {
457
+ const channel = rest[0]
458
+ if (!channel) {
459
+ console.error(' usage: rnxsim debug toggle <channel>')
460
+ process.exit(1)
461
+ }
462
+ const result = await call(
463
+ bridge,
464
+ `window.__sootsimDebug.toggle(${JSON.stringify(channel)})`,
465
+ )
466
+ console.log(fmt({ [channel]: result }, pretty))
467
+ break
468
+ }
469
+
470
+ case 'status': {
471
+ const result = await inspectDebugStatus(bridge)
472
+ console.log(fmt(result, pretty))
473
+ break
474
+ }
475
+
476
+ case 'channels': {
477
+ const result = await call(bridge, 'window.__sootsimDebug.channels()')
478
+ console.log(fmt(result, pretty))
479
+ break
480
+ }
481
+
482
+ case 'flags': {
483
+ const result = await inspectDebugFlags(bridge)
484
+ console.log(fmt(result, pretty))
485
+ break
486
+ }
487
+
488
+ case 'snapshot': {
489
+ const label = rest[0]
490
+ const code = label
491
+ ? `window.__sootsimDebug.snapshot(${JSON.stringify(label)})`
492
+ : 'window.__sootsimDebug.snapshot()'
493
+ // the tree snapshot contains a Map, which doesn't serialize cleanly.
494
+ // project to the same shape the diff command will accept: label +
495
+ // size. to inspect contents, use `find sheets` / `find portals` or
496
+ // take a diff.
497
+ const result = await call<{
498
+ label: string
499
+ at: number
500
+ nodes: unknown
501
+ }>(
502
+ bridge,
503
+ `(() => { const s = ${code}; if (!s) return null; return { label: s.label, at: s.at, size: s.nodes.size }; })()`,
504
+ )
505
+ console.log(fmt(result, pretty))
506
+ break
507
+ }
508
+
509
+ case 'snapshots': {
510
+ const result = await call(bridge, 'window.__sootsimDebug.snapshots()')
511
+ console.log(fmt(result, pretty))
512
+ break
513
+ }
514
+
515
+ case 'diff': {
516
+ const a = rest[0]
517
+ const b = rest[1]
518
+ if (!a || !b) {
519
+ console.error(' usage: rnxsim debug diff <labelA> <labelB>')
520
+ process.exit(1)
521
+ }
522
+ // Maps don't serialize — project added/removed/changed arrays only
523
+ const code = `(() => {
524
+ const d = window.__sootsimDebug.diff(${JSON.stringify(a)}, ${JSON.stringify(b)});
525
+ if (!d) return null;
526
+ return {
527
+ a: d.a,
528
+ b: d.b,
529
+ counts: { added: d.added.length, removed: d.removed.length, changed: d.changed.length },
530
+ added: d.added,
531
+ removed: d.removed,
532
+ changed: d.changed,
533
+ };
534
+ })()`
535
+ const result = await call(bridge, code)
536
+ console.log(fmt(result, pretty))
537
+ break
538
+ }
539
+
540
+ case 'clear-snapshots': {
541
+ const label = rest[0]
542
+ const code = label
543
+ ? `window.__sootsimDebug.clearSnapshots(${JSON.stringify(label)})`
544
+ : 'window.__sootsimDebug.clearSnapshots()'
545
+ await call(bridge, code)
546
+ console.log(fmt({ cleared: label || 'all' }, pretty))
547
+ break
548
+ }
549
+
550
+ case 'image-audit': {
551
+ const minimum = readNumberFlag(args, '--min') ?? 0.98
552
+ const report = await runImageAudit(bridge)
553
+ if (report.draws === 0) {
554
+ console.error(
555
+ ' the audit recorded zero image draws, so an empty result proves nothing.\n' +
556
+ ' while it records, paint boundaries rebuild and raster blits are\n' +
557
+ ' bypassed, so every image on screen should reach the draw path.\n' +
558
+ ' zero draws means either nothing on screen is an image, or the audit\n' +
559
+ ' is not attached to the surface that paints.',
560
+ )
561
+ process.exit(2)
562
+ }
563
+ const under = report.rows.filter(
564
+ (row) => row.shortfall !== null && row.shortfall < minimum,
565
+ )
566
+ if (!pretty) {
567
+ console.log(fmt({ ...report, minimum, under: under.length }, false))
568
+ } else {
569
+ printImageAudit(report, args.includes('--all') ? report.rows : under, minimum)
570
+ }
571
+ if (under.length > 0) process.exit(1)
572
+ break
573
+ }
574
+
575
+ case 'find': {
576
+ const target = rest[0]
577
+ if (target === 'sheets' || target === 'portals' || target === 'boundaries') {
578
+ const result = await inspectDebugFind(bridge, target)
579
+ console.log(fmt(result, pretty))
580
+ } else {
581
+ console.error(' usage: rnxsim debug find <sheets|portals|boundaries>')
582
+ process.exit(1)
583
+ }
584
+ break
585
+ }
586
+
587
+ case 'trace': {
588
+ const traceTarget = rest[0]
589
+ const traceCommand = rest[1]
590
+ if (traceTarget === 'anim') {
591
+ // `debug trace anim on <id|all> [limit]`
592
+ // `debug trace anim off [id|all]`
593
+ // `debug trace anim <id> [limit]` → read samples
594
+ // `debug trace anim status` | `clear`
595
+ const sub = rest[1]
596
+ if (!sub || sub === '--help' || sub === '-h') {
597
+ console.error(
598
+ ' usage: rnxsim debug trace anim <on|off|status|clear|<id>> [id|limit]',
599
+ )
600
+ process.exit(1)
601
+ }
602
+ if (sub === 'on') {
603
+ const raw = rest[2] ?? 'all'
604
+ const limit = rest[3] ? Number(rest[3]) : undefined
605
+ const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
606
+ if (target !== 'all' && !Number.isFinite(target)) {
607
+ console.error(` invalid target: ${raw}`)
608
+ process.exit(1)
609
+ }
610
+ await callTestBridge(bridge, 'enableAnimationTrace', target, limit)
611
+ const listed = await callTestBridge(bridge, 'listAnimationTraces')
612
+ console.log(fmt({ enabled: target, traces: listed }, pretty))
613
+ break
614
+ }
615
+ if (sub === 'off') {
616
+ const raw = rest[2] ?? 'all'
617
+ const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
618
+ if (target !== 'all' && !Number.isFinite(target)) {
619
+ console.error(` invalid target: ${raw}`)
620
+ process.exit(1)
621
+ }
622
+ await callTestBridge(bridge, 'disableAnimationTrace', target)
623
+ console.log(fmt({ disabled: target }, pretty))
624
+ break
625
+ }
626
+ if (sub === 'status' || sub === 'clear') {
627
+ if (sub === 'clear') {
628
+ await callTestBridge(bridge, 'disableAnimationTrace', 'all')
629
+ }
630
+ const listed = await callTestBridge(bridge, 'listAnimationTraces')
631
+ console.log(fmt({ traces: listed }, pretty))
632
+ break
633
+ }
634
+ const id = Number(sub)
635
+ if (!Number.isFinite(id)) {
636
+ console.error(` invalid id: ${sub}`)
637
+ process.exit(1)
638
+ }
639
+ const limit = rest[2] ? Number(rest[2]) : undefined
640
+ const samples = await callTestBridge(bridge, 'getAnimationTrace', id, limit)
641
+ console.log(fmt({ id, samples }, pretty))
642
+ break
643
+ }
644
+ if (traceTarget !== 'shell') {
645
+ console.error(' usage: rnxsim debug trace <shell|anim> [args]')
646
+ process.exit(1)
647
+ }
648
+ if (!traceCommand || /^[0-9]+$/.test(traceCommand)) {
649
+ const recentLimit = traceCommand ? Number(traceCommand) : 50
650
+ const result = await call(bridge, buildShellTraceRecentCode(recentLimit))
651
+ console.log(fmt(result, pretty))
652
+ break
653
+ }
654
+ if (traceCommand === 'on') {
655
+ const limit = rest[2] ? Number(rest[2]) : 240
656
+ const result = await call(bridge, buildShellTraceControlCode('on', limit))
657
+ console.log(fmt(result, pretty))
658
+ break
659
+ }
660
+ if (traceCommand === 'off') {
661
+ const result = await call(bridge, buildShellTraceControlCode('off'))
662
+ console.log(fmt(result, pretty))
663
+ break
664
+ }
665
+ if (traceCommand === 'clear') {
666
+ const result = await call(bridge, buildShellTraceControlCode('clear'))
667
+ console.log(fmt(result, pretty))
668
+ break
669
+ }
670
+ if (traceCommand === 'status') {
671
+ const result = await call(bridge, buildShellTraceControlCode('status'))
672
+ console.log(fmt(result, pretty))
673
+ break
674
+ }
675
+ console.error(
676
+ ' usage: rnxsim debug trace shell [on [limit]|off|status|clear|recentLimit]',
677
+ )
678
+ process.exit(1)
679
+ }
680
+
681
+ case 'record': {
682
+ const target = rest[0]
683
+ const on = target === 'on' ? 'true' : target === 'off' ? 'false' : 'undefined'
684
+ const result = await call(bridge, `window.__sootsimDebug.record(${on})`)
685
+ console.log(fmt({ recording: result }, pretty))
686
+ break
687
+ }
688
+
689
+ case 'recent': {
690
+ const channel = rest[0]
691
+ const limit = rest[1] ? Number(rest[1]) : 50
692
+ const result = await inspectDebugRecent(bridge, channel, limit)
693
+ console.log(fmt(result, pretty))
694
+ break
695
+ }
696
+
697
+ case 'clear-events': {
698
+ await call(bridge, 'window.__sootsimDebug.clearEvents()')
699
+ console.log(fmt({ cleared: true }, pretty))
700
+ break
701
+ }
702
+
703
+ default:
704
+ console.error(` unknown subcommand: ${sub}`)
705
+ printHelp()
706
+ process.exit(1)
707
+ }
708
+ } catch (err: any) {
709
+ console.error(` debug failed: ${err.message}`)
710
+ await printBridgeFailureDiagnostics(bridge, {
711
+ errorsCommand: `rnxsim get errors 5${simHint}`,
712
+ warningsCommand: `rnxsim get warnings 5${simHint}`,
713
+ requestsCommand: `rnxsim get requests 5${simHint}`,
714
+ })
715
+ process.exit(1)
716
+ } finally {
717
+ bridge.close()
718
+ }
719
+ }