rnxsim 0.1.313 → 0.1.315

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-CBU2WDKV.js} +2 -2
  126. package/dist-cli/chunks/{agent-wrapper-JJYYW2WH.js → agent-wrapper-UNB4R27L.js} +2 -2
  127. package/dist-cli/chunks/{app-fonts-IXRNQG6B.js → app-fonts-YMLRF3JD.js} +2 -2
  128. package/dist-cli/chunks/{assert-54T5SK5F.js → assert-5N6HUCL5.js} +2 -2
  129. package/dist-cli/chunks/{auth-FI5UDI45.js → auth-BHDR3A6G.js} +2 -2
  130. package/dist-cli/chunks/{beta-JV6UKADW.js → beta-LWUVCPYK.js} +2 -2
  131. package/dist-cli/chunks/camera-CNO6B2JZ.js +33 -0
  132. package/dist-cli/chunks/{chunk-ZMJD5GEC.js → chunk-25VCR44B.js} +1 -1
  133. package/dist-cli/chunks/{chunk-WUSWBCWA.js → chunk-26CSIR76.js} +8 -9
  134. package/dist-cli/chunks/{chunk-WINYQ44O.js → chunk-26WMWUH4.js} +1 -1
  135. package/dist-cli/chunks/{chunk-BTWORNNG.js → chunk-2JZ53D4A.js} +1 -1
  136. package/dist-cli/chunks/{chunk-DCEMHR2Y.js → chunk-2POODCTW.js} +2 -2
  137. package/dist-cli/chunks/{chunk-5TEF3ET3.js → chunk-4LTBK3ZN.js} +2 -2
  138. package/dist-cli/chunks/{chunk-NMF2ZMZQ.js → chunk-54MIRTFE.js} +4 -4
  139. package/dist-cli/chunks/{chunk-WEXDAC74.js → chunk-56H6EVO4.js} +2 -2
  140. package/dist-cli/chunks/{chunk-F5ZRSS3C.js → chunk-657SQG4D.js} +1 -1
  141. package/dist-cli/chunks/{chunk-IJ5CAZZC.js → chunk-6ZMRJPKI.js} +1 -1
  142. package/dist-cli/chunks/{chunk-W6K4EFPH.js → chunk-AOGGOC4V.js} +2 -2
  143. package/dist-cli/chunks/chunk-BPCDO7ST.js +15 -0
  144. package/dist-cli/chunks/{chunk-D4FFVGI5.js → chunk-C5O5CTXJ.js} +1 -1
  145. package/dist-cli/chunks/{chunk-RTN5C5RL.js → chunk-CMM64PPR.js} +1 -1
  146. package/dist-cli/chunks/{chunk-BBULZ7CG.js → chunk-D3M36D7O.js} +62 -87
  147. package/dist-cli/chunks/{chunk-5DHC6KHQ.js → chunk-DNCNFZ7V.js} +1 -1
  148. package/dist-cli/chunks/{chunk-YIFT42WN.js → chunk-FNTTIR2P.js} +2 -2
  149. package/dist-cli/chunks/chunk-H362IX2I.js +4 -0
  150. package/dist-cli/chunks/{chunk-IJO63TDP.js → chunk-J6HMTUZH.js} +2 -2
  151. package/dist-cli/chunks/{chunk-RSZWCKNT.js → chunk-JZ6VTZ5B.js} +3 -3
  152. package/dist-cli/chunks/{chunk-MJRLLB4R.js → chunk-KQSJVNFE.js} +4 -4
  153. package/dist-cli/chunks/chunk-L4JZKVCC.js +6 -0
  154. package/dist-cli/chunks/{chunk-VFCMSYZK.js → chunk-LP2BTEJ6.js} +2 -2
  155. package/dist-cli/chunks/{chunk-2YR5BGA5.js → chunk-LT6UC7I3.js} +2 -2
  156. package/dist-cli/chunks/{chunk-OVFJFXUD.js → chunk-MCKQH4AM.js} +2 -2
  157. package/dist-cli/chunks/{chunk-TZFFR3SD.js → chunk-MF7WUHQ3.js} +2 -2
  158. package/dist-cli/chunks/{chunk-46EUUFJ5.js → chunk-MSSY4EEZ.js} +1 -1
  159. package/dist-cli/chunks/{chunk-WMIIKMGK.js → chunk-N5ZCYP5F.js} +2 -2
  160. package/dist-cli/chunks/{chunk-3NV2NCNX.js → chunk-NCKAD3V7.js} +2 -2
  161. package/dist-cli/chunks/{chunk-VNQEB4L7.js → chunk-O2KRHVTU.js} +2 -2
  162. package/dist-cli/chunks/{chunk-OZSSI4WN.js → chunk-OF2HTH25.js} +2 -2
  163. package/dist-cli/chunks/{chunk-GGRX24GF.js → chunk-OXS2IWO2.js} +2 -2
  164. package/dist-cli/chunks/{chunk-WWZIXIRD.js → chunk-PVL7XSPN.js} +1 -1
  165. package/dist-cli/chunks/{chunk-DZS6WPUI.js → chunk-PVPAP3TV.js} +1 -1
  166. package/dist-cli/chunks/{chunk-5YJCOWCH.js → chunk-PXNAZYGV.js} +1 -1
  167. package/dist-cli/chunks/chunk-QR3HTFRB.js +5 -0
  168. package/dist-cli/chunks/{chunk-5TPRP5QT.js → chunk-QR7MWAWE.js} +1 -1
  169. package/dist-cli/chunks/chunk-RJIEZ2NY.js +4 -0
  170. package/dist-cli/chunks/{chunk-UC6U3MML.js → chunk-RVM4EZ4E.js} +2 -2
  171. package/dist-cli/chunks/{chunk-2D2UPBBR.js → chunk-SZKSFMWS.js} +1 -1
  172. package/dist-cli/chunks/{chunk-7GN3LVWB.js → chunk-TEL7G234.js} +2 -2
  173. package/dist-cli/chunks/{chunk-GASE6UBA.js → chunk-U2HNIHBY.js} +1 -1
  174. package/dist-cli/chunks/chunk-UROXJVY3.js +27 -0
  175. package/dist-cli/chunks/{chunk-HI5TFJWN.js → chunk-WM32MGTJ.js} +2 -2
  176. package/dist-cli/chunks/{chunk-VZXWHRUZ.js → chunk-WMZ7NJAO.js} +89 -133
  177. package/dist-cli/chunks/{chunk-XEVZYVIW.js → chunk-WUXCH6WN.js} +10 -9
  178. package/dist-cli/chunks/chunk-XOXGC3EH.js +9 -0
  179. package/dist-cli/chunks/chunk-XSSHENNY.js +4 -0
  180. package/dist-cli/chunks/{chunk-OHAZNXLK.js → chunk-XZ6O67AR.js} +1 -1
  181. package/dist-cli/chunks/{chunk-QKDWYITG.js → chunk-Y2MWQKOS.js} +3 -3
  182. package/dist-cli/chunks/{chunk-YDGQTMQL.js → chunk-YY24QI25.js} +1 -1
  183. package/dist-cli/chunks/{chunk-WF3T4SVI.js → chunk-ZWX6DDIS.js} +2 -2
  184. package/dist-cli/chunks/{cleanup-P27PA6JI.js → cleanup-F3NUJ3SL.js} +2 -2
  185. package/dist-cli/chunks/cli-version-XIW6O3FG.js +4 -0
  186. package/dist-cli/chunks/{compat-ZD65FED3.js → compat-AX2SEPTH.js} +2 -2
  187. package/dist-cli/chunks/{config-XMJRNM2A.js → config-4QQO5JVU.js} +2 -2
  188. package/dist-cli/chunks/{control-KMIQT3QP.js → control-OCKKSOWA.js} +2 -2
  189. package/dist-cli/chunks/daemon-N5VLMYKQ.js +4 -0
  190. package/dist-cli/chunks/{debug-PT4HOP7N.js → debug-T6MWVEVX.js} +5 -5
  191. package/dist-cli/chunks/{desktop-S3FG72AK.js → desktop-NCW7R7CB.js} +3 -3
  192. package/dist-cli/chunks/{detox-B3D4IFCN.js → detox-G6GITO2X.js} +2 -2
  193. package/dist-cli/chunks/{device-XBNDSB2R.js → device-7BTEJCTH.js} +2 -2
  194. package/dist-cli/chunks/{diagnose-HMQXJE5N.js → diagnose-SC5LACE3.js} +2 -2
  195. package/dist-cli/chunks/{disk-cleanup-BLCZ5BSZ.js → disk-cleanup-KK56QQZA.js} +2 -2
  196. package/dist-cli/chunks/drivers-NPGVBWMG.js +4 -0
  197. package/dist-cli/chunks/{film-BJGTBYZB.js → film-WGYEHGIA.js} +3 -3
  198. package/dist-cli/chunks/flow-KQBIBM3N.js +4 -0
  199. package/dist-cli/chunks/help-G7CAKI65.js +4 -0
  200. package/dist-cli/chunks/{hidden-runtime-alias-ANOYADHM.js → hidden-runtime-alias-CWTZWH3L.js} +2 -2
  201. package/dist-cli/chunks/home-paths-EBT4XHAS.js +4 -0
  202. package/dist-cli/chunks/inspect-CCPZXVDU.js +4 -0
  203. package/dist-cli/chunks/install-desktop-NZ3VGTQZ.js +4 -0
  204. package/dist-cli/chunks/{login-FJ737MWG.js → login-GSYOTGVQ.js} +4 -4
  205. package/dist-cli/chunks/{logout-ZCNMMHMY.js → logout-JPRIR7YK.js} +2 -2
  206. package/dist-cli/chunks/{maestro-SZTNKLDF.js → maestro-LXKDNO5M.js} +3 -3
  207. package/dist-cli/chunks/{maestro-generate-DCFAIZ4H.js → maestro-generate-5ZIKOU53.js} +3 -3
  208. package/dist-cli/chunks/{mode-GRMQCRXR.js → mode-N3QHXCES.js} +2 -2
  209. package/dist-cli/chunks/{optional-demo-registry-W36EWFFB.js → optional-demo-registry-XDH6X24N.js} +2 -2
  210. package/dist-cli/chunks/{perf-QYBAAUZG.js → perf-VOPL26FM.js} +2 -2
  211. package/dist-cli/chunks/{permissions-3QCQ6VF4.js → permissions-CZFKM4UD.js} +2 -2
  212. package/dist-cli/chunks/{record-QPPC2S4E.js → record-FODSOGMA.js} +3 -3
  213. package/dist-cli/chunks/{report-issue-7NMFP4HK.js → report-issue-FBPCZKOV.js} +2 -2
  214. package/dist-cli/chunks/reset-3H35GFO3.js +4 -0
  215. package/dist-cli/chunks/runtime-4OVFRXV5.js +4 -0
  216. package/dist-cli/chunks/{screenshot-command-67AECJFB.js → screenshot-command-7S3FYVO7.js} +7 -7
  217. package/dist-cli/chunks/{screenshot-layers-ASWBYPJL.js → screenshot-layers-CDYHPNC3.js} +3 -3
  218. package/dist-cli/chunks/{screenshots-capture-PXA3HFQK.js → screenshots-capture-EBIIY2YU.js} +2 -2
  219. package/dist-cli/chunks/serve-NELNSCZP.js +44 -0
  220. package/dist-cli/chunks/{setup-7DWPMRSB.js → setup-DF5ZDDIV.js} +2 -2
  221. package/dist-cli/chunks/{skills-S3Y22TUA.js → skills-E2QZF6WZ.js} +2 -2
  222. package/dist-cli/chunks/state-MBZDKZ7U.js +14 -0
  223. package/dist-cli/chunks/{storage-XUIMJWAJ.js → storage-J5BMNVXM.js} +6 -6
  224. package/dist-cli/chunks/store-U3DXC7HH.js +4 -0
  225. package/dist-cli/chunks/telemetry-XIPJVT5E.js +4 -0
  226. package/dist-cli/chunks/{timeline-TMPLQPSP.js → timeline-MC6N5BHY.js} +2 -2
  227. package/dist-cli/chunks/{upgrade-7HDSIM7K.js → upgrade-7UTU53DH.js} +2 -2
  228. package/dist-cli/chunks/upload-2M2KOTYI.js +4 -0
  229. package/dist-cli/chunks/version-VNACNYQK.js +6 -0
  230. package/dist-cli/chunks/{web-DG3WBYD3.js → web-MGJ2TUKR.js} +2 -2
  231. package/dist-cli/chunks/{what-happened-XFVUTZR7.js → what-happened-7DLKH3OD.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,361 @@
1
+ // sootsim screenshot slides — drive the live screenshot-mode composition from the
2
+ // terminal. same pipeline as the in-shell UI (rail/strip): every mutation
3
+ // goes through the shell's screenshotControl bridge so the browser UI
4
+ // reflects each step live, captures auto-upload, and exports are the
5
+ // composed App-Store canvases (bg + copy + posed device at export size).
6
+
7
+ import { mkdirSync, writeFileSync } from 'node:fs'
8
+ import { dirname, isAbsolute, join, resolve } from 'node:path'
9
+ import {
10
+ callInBridge,
11
+ callInBridgeWrite,
12
+ createBridgeFromParsed,
13
+ evalInBridge,
14
+ parseBridgeCliArgs,
15
+ type WsBridge,
16
+ } from '../ws-bridge'
17
+
18
+ const HELP = `
19
+ rnxsim screenshot slides — compose App Store screenshots in the live sim
20
+
21
+ usage:
22
+ rnxsim screenshot slides list slides (alias: slides list)
23
+ rnxsim screenshot slides set <n> [fields] patch a slide's copy/colors
24
+ rnxsim screenshot slides add append a blank slide (focuses it)
25
+ rnxsim screenshot slides remove <n> delete a slide
26
+ rnxsim screenshot slides move <n> <position> reorder a slide
27
+ rnxsim screenshot slides focus <n> open a slide (device flips into it)
28
+ rnxsim screenshot slides overview back to the gallery
29
+ rnxsim screenshot slides capture [<n>] capture the live frame into a slide
30
+ rnxsim screenshot slides export [<n>] [--out <dir>]
31
+ write composed App-Store PNG(s)
32
+
33
+ set fields:
34
+ --title <text> headline
35
+ --subtitle <text> subheadline
36
+ --bg-top <color> gradient top (white gray slate black cyan blue
37
+ --bg-bottom <color> gradient bottom teal green lime gold orange coral
38
+ --title-color <color> copy color override, or "auto" red berry magenta
39
+ --title-size <s> sm | md | lg | none gray-light
40
+ --underlay <s> black | white | none gray-dark …)
41
+ --shadow <s> light | medium | strong | none
42
+
43
+ notes:
44
+ slides are addressed by 1-based index. screenshot mode is auto-enabled.
45
+ capture shoots whatever the sim currently shows — navigate the app first
46
+ (rnxsim do tap-id …), then capture.
47
+
48
+ examples:
49
+ rnxsim screenshot slides set 1 --title "The ultimate MMA community." --bg-top cyan --bg-bottom black
50
+ rnxsim screenshot slides capture 1
51
+ rnxsim screenshot slides export --out ./exports
52
+ `
53
+
54
+ interface SlideRow {
55
+ index: number
56
+ id: string
57
+ title: string
58
+ subtitle: string
59
+ bgTop: string
60
+ bgBottom: string
61
+ titleColor: string | null
62
+ titleSize: string | null
63
+ titleUnderlay: string | null
64
+ titleShadow: string | null
65
+ captured: boolean
66
+ captureMode: string | null
67
+ focused: boolean
68
+ active: boolean
69
+ }
70
+
71
+ interface ControlState {
72
+ projectName: string
73
+ canvas: string
74
+ exportSize: { width: number; height: number }
75
+ deviceModel: string
76
+ slides: SlideRow[]
77
+ }
78
+
79
+ // my value flags, extracted before bridge-arg parsing.
80
+ const VALUE_FLAGS: Record<string, string> = {
81
+ '--title': 'title',
82
+ '--subtitle': 'subtitle',
83
+ '--bg-top': 'bgTop',
84
+ '--bg-bottom': 'bgBottom',
85
+ '--title-color': 'titleColor',
86
+ '--title-size': 'titleSize',
87
+ '--underlay': 'titleUnderlay',
88
+ '--shadow': 'titleShadow',
89
+ '--out': 'out',
90
+ }
91
+
92
+ function extractFlags(args: string[]): {
93
+ rest: string[]
94
+ values: Record<string, string>
95
+ json: boolean
96
+ } {
97
+ const rest: string[] = []
98
+ const values: Record<string, string> = {}
99
+ let json = false
100
+ for (let i = 0; i < args.length; i += 1) {
101
+ const arg = args[i]
102
+ if (arg === '--json') {
103
+ json = true
104
+ continue
105
+ }
106
+ const eq = arg.indexOf('=')
107
+ const flagName = eq > 0 ? arg.slice(0, eq) : arg
108
+ const key = VALUE_FLAGS[flagName]
109
+ if (key) {
110
+ if (eq > 0) {
111
+ values[key] = arg.slice(eq + 1)
112
+ } else {
113
+ values[key] = args[i + 1] ?? ''
114
+ i += 1
115
+ }
116
+ continue
117
+ }
118
+ rest.push(arg)
119
+ }
120
+ return { rest, values, json }
121
+ }
122
+
123
+ function parseSlideRef(raw: string | undefined): number | string | undefined {
124
+ if (!raw) return undefined
125
+ const n = Number(raw)
126
+ return Number.isInteger(n) && n > 0 ? n : raw
127
+ }
128
+
129
+ async function ensureScreenshotMode(bridge: WsBridge): Promise<void> {
130
+ const on = await evalInBridge<boolean>(
131
+ bridge,
132
+ `(async () => {
133
+ if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
134
+ window.dispatchEvent(new CustomEvent('sootsim:shell-command', {
135
+ detail: { type: 'fire-action', id: 'toggle-screenshot-mode' },
136
+ }))
137
+ const deadline = Date.now() + 2000
138
+ while (Date.now() < deadline) {
139
+ if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
140
+ await new Promise((r) => setTimeout(r, 40))
141
+ }
142
+ return false
143
+ })()`,
144
+ { acquireLock: true },
145
+ )
146
+ if (!on) {
147
+ throw new Error(
148
+ 'could not enable screenshot mode — is this a browser sim with the screenshot plugin? (electron has no screenshot mode)',
149
+ )
150
+ }
151
+ }
152
+
153
+ function printState(state: ControlState) {
154
+ console.log(
155
+ ` ${state.projectName} — canvas ${state.canvas} (${state.exportSize.width}×${state.exportSize.height}), device ${state.deviceModel}`,
156
+ )
157
+ for (const s of state.slides) {
158
+ const marks = [
159
+ s.focused ? 'focused' : s.active ? 'active' : null,
160
+ s.captured ? `captured${s.captureMode === '3d' ? ' 3d' : ''}` : 'no capture',
161
+ ]
162
+ .filter(Boolean)
163
+ .join(', ')
164
+ const copy = s.title ? `"${s.title}"` : '(no title)'
165
+ const style = [
166
+ `bg ${s.bgTop}→${s.bgBottom}`,
167
+ s.titleColor ? `color ${s.titleColor}` : null,
168
+ s.titleSize ? `size ${s.titleSize}` : null,
169
+ s.titleUnderlay ? `underlay ${s.titleUnderlay}` : null,
170
+ s.titleShadow ? `shadow ${s.titleShadow}` : null,
171
+ ]
172
+ .filter(Boolean)
173
+ .join(', ')
174
+ console.log(` ${s.index}. ${copy} — ${style} [${marks}]`)
175
+ if (s.subtitle) console.log(` ${s.subtitle}`)
176
+ }
177
+ }
178
+
179
+ function dataUrlToBytes(dataUrl: string): Buffer {
180
+ const m = dataUrl.match(/^data:[^;]+;base64,(.+)$/)
181
+ if (!m) throw new Error('export returned an unexpected payload')
182
+ return Buffer.from(m[1], 'base64')
183
+ }
184
+
185
+ export async function runSlides(
186
+ args: string[],
187
+ opts: { port?: number; verbose?: boolean },
188
+ ): Promise<void> {
189
+ if (args.includes('--help') || args.includes('-h')) {
190
+ console.log(HELP)
191
+ return
192
+ }
193
+ const { rest, values, json } = extractFlags(args)
194
+ const parsed = parseBridgeCliArgs(rest, {
195
+ port: opts.port,
196
+ // capture waits on focus animation + frame bake; export composes at
197
+ // full App-Store resolution — both can exceed the default 15s.
198
+ commandTimeoutMs: 45_000,
199
+ })
200
+ const sub = parsed.positional[0] ?? 'list'
201
+ const refArg = parseSlideRef(parsed.positional[1])
202
+ const positionArg = Number(parsed.positional[2])
203
+ const bridge = createBridgeFromParsed(parsed)
204
+ const emit = (state: ControlState) => {
205
+ if (json) console.log(JSON.stringify(state, null, 2))
206
+ else printState(state)
207
+ }
208
+
209
+ try {
210
+ await ensureScreenshotMode(bridge)
211
+ switch (sub) {
212
+ case 'list': {
213
+ emit(
214
+ await callInBridge<ControlState>(
215
+ bridge,
216
+ 'SootSim.bridges.screenshotControl.getState',
217
+ ),
218
+ )
219
+ break
220
+ }
221
+ case 'set': {
222
+ if (refArg == null)
223
+ throw new Error(
224
+ 'usage: rnxsim screenshot slides set <n> --title … (see --help)',
225
+ )
226
+ const patch: Record<string, string> = {}
227
+ for (const key of [
228
+ 'title',
229
+ 'subtitle',
230
+ 'bgTop',
231
+ 'bgBottom',
232
+ 'titleColor',
233
+ 'titleSize',
234
+ 'titleUnderlay',
235
+ 'titleShadow',
236
+ ]) {
237
+ if (values[key] != null) patch[key] = values[key]
238
+ }
239
+ if (Object.keys(patch).length === 0) {
240
+ throw new Error('nothing to set — pass at least one field (see --help)')
241
+ }
242
+ emit(
243
+ await callInBridgeWrite<ControlState>(
244
+ bridge,
245
+ 'SootSim.bridges.screenshotControl.setSlide',
246
+ refArg,
247
+ patch,
248
+ ),
249
+ )
250
+ break
251
+ }
252
+ case 'add': {
253
+ emit(
254
+ await callInBridgeWrite<ControlState>(
255
+ bridge,
256
+ 'SootSim.bridges.screenshotControl.addSlide',
257
+ ),
258
+ )
259
+ break
260
+ }
261
+ case 'remove': {
262
+ if (refArg == null) throw new Error('usage: rnxsim screenshot slides remove <n>')
263
+ emit(
264
+ await callInBridgeWrite<ControlState>(
265
+ bridge,
266
+ 'SootSim.bridges.screenshotControl.removeSlide',
267
+ refArg,
268
+ ),
269
+ )
270
+ break
271
+ }
272
+ case 'move': {
273
+ if (refArg == null || !Number.isInteger(positionArg) || positionArg < 1) {
274
+ throw new Error('usage: rnxsim screenshot slides move <n> <position>')
275
+ }
276
+ emit(
277
+ await callInBridgeWrite<ControlState>(
278
+ bridge,
279
+ 'SootSim.bridges.screenshotControl.moveSlide',
280
+ refArg,
281
+ positionArg,
282
+ ),
283
+ )
284
+ break
285
+ }
286
+ case 'focus': {
287
+ if (refArg == null) throw new Error('usage: rnxsim screenshot slides focus <n>')
288
+ emit(
289
+ await callInBridgeWrite<ControlState>(
290
+ bridge,
291
+ 'SootSim.bridges.screenshotControl.focusSlide',
292
+ refArg,
293
+ ),
294
+ )
295
+ break
296
+ }
297
+ case 'overview': {
298
+ emit(
299
+ await callInBridgeWrite<ControlState>(
300
+ bridge,
301
+ 'SootSim.bridges.screenshotControl.overview',
302
+ ),
303
+ )
304
+ break
305
+ }
306
+ case 'capture': {
307
+ const state = await callInBridgeWrite<ControlState>(
308
+ bridge,
309
+ 'SootSim.bridges.screenshotControl.capture',
310
+ ...(refArg != null ? [refArg] : []),
311
+ )
312
+ emit(state)
313
+ break
314
+ }
315
+ case 'export': {
316
+ const outDir = values.out
317
+ ? isAbsolute(values.out)
318
+ ? values.out
319
+ : resolve(process.cwd(), values.out)
320
+ : join(process.cwd(), 'screenshots')
321
+ const state = await callInBridge<ControlState>(
322
+ bridge,
323
+ 'SootSim.bridges.screenshotControl.getState',
324
+ )
325
+ const targets =
326
+ refArg != null
327
+ ? state.slides.filter((s) => s.index === refArg || s.id === refArg)
328
+ : state.slides.filter((s) => s.captured)
329
+ if (targets.length === 0) {
330
+ throw new Error(
331
+ refArg != null
332
+ ? `no slide ${refArg}`
333
+ : 'no captured slides to export — capture first',
334
+ )
335
+ }
336
+ const written: string[] = []
337
+ for (const slide of targets) {
338
+ const result = await callInBridge<{
339
+ name: string
340
+ width: number
341
+ height: number
342
+ dataUrl: string
343
+ }>(bridge, 'SootSim.bridges.screenshotControl.exportSlide', slide.index)
344
+ const path = join(outDir, result.name)
345
+ mkdirSync(dirname(path), { recursive: true })
346
+ writeFileSync(path, dataUrlToBytes(result.dataUrl))
347
+ written.push(path)
348
+ console.log(` saved: ${path} (${result.width}×${result.height})`)
349
+ }
350
+ if (json) console.log(JSON.stringify({ written }, null, 2))
351
+ break
352
+ }
353
+ default:
354
+ throw new Error(
355
+ `unknown subcommand "${sub}" — see rnxsim screenshot slides --help`,
356
+ )
357
+ }
358
+ } finally {
359
+ bridge.close()
360
+ }
361
+ }
@@ -0,0 +1,87 @@
1
+ import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
2
+ import { createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
3
+ import type { SimStateResult } from '../../src/bridge-contract'
4
+
5
+ function isSimStateResult(value: unknown): value is SimStateResult {
6
+ return (
7
+ !!value &&
8
+ typeof value === 'object' &&
9
+ typeof Reflect.get(value, 'capturedAt') === 'number'
10
+ )
11
+ }
12
+
13
+ function printHelp(): void {
14
+ console.log(`
15
+ rnxsim state - capture the current app state in one call
16
+
17
+ usage:
18
+ rnxsim state [--json] [--sim <id>]
19
+
20
+ options:
21
+ --json print the complete structured result, including the screenshot
22
+ --sim <id> target a specific sim
23
+ --port <p> WS bridge port
24
+ `)
25
+ }
26
+
27
+ export async function runState(
28
+ args: string[],
29
+ opts: { port?: number } = {},
30
+ ): Promise<number> {
31
+ if (args.includes('--help') || args.includes('-h')) {
32
+ printHelp()
33
+ return 0
34
+ }
35
+
36
+ const parsed = parseBridgeCliArgs(args, {
37
+ port: opts.port,
38
+ stripBooleanFlags: ['--json'],
39
+ })
40
+ if (parsed.positional.length > 0) {
41
+ console.error(` unexpected state argument: ${parsed.positional[0]}`)
42
+ return 1
43
+ }
44
+
45
+ const bridge = createBridgeFromParsed(parsed)
46
+ try {
47
+ const value: unknown = await bridge.send({ type: 'state' })
48
+ if (!isSimStateResult(value)) {
49
+ throw new Error('state bridge returned an invalid result')
50
+ }
51
+
52
+ if (args.includes('--json')) {
53
+ console.log(JSON.stringify(value))
54
+ return 0
55
+ }
56
+
57
+ const route = value.route
58
+ console.log(` route: ${route?.screen ?? route?.url ?? '(unknown)'}`)
59
+ if (route?.stack?.length) console.log(` stack: ${route.stack.join(' > ')}`)
60
+ console.log(` keyboard: ${value.keyboard?.visible ? 'visible' : 'hidden'}`)
61
+ console.log('')
62
+ console.log(typeof value.tree === 'string' ? value.tree : JSON.stringify(value.tree))
63
+ console.log('')
64
+ if (value.recentErrors?.length) {
65
+ console.log(` recent errors (${value.recentErrors.length}):`)
66
+ for (const error of value.recentErrors) {
67
+ console.log(` [${error.level}] ${error.text}`)
68
+ }
69
+ } else {
70
+ console.log(' recent errors: none')
71
+ }
72
+ const screenshotLength =
73
+ typeof value.screenshot === 'string' ? value.screenshot.length : 0
74
+ console.log(
75
+ screenshotLength > 0
76
+ ? ` screenshot: captured (${screenshotLength} characters; use --json to read it)`
77
+ : ' screenshot: unavailable',
78
+ )
79
+ return 0
80
+ } catch (error) {
81
+ console.error(` state failed: ${error instanceof Error ? error.message : error}`)
82
+ await printBridgeFailureDiagnostics(bridge)
83
+ return 1
84
+ } finally {
85
+ bridge.close()
86
+ }
87
+ }
@@ -0,0 +1,58 @@
1
+ import { runProfile } from './profile'
2
+ import { runReset } from './reset'
3
+
4
+ interface StorageOptions {
5
+ port?: number
6
+ verbose?: boolean
7
+ }
8
+
9
+ const VALUE_FLAGS = new Set(['--sim', '--port', '-p'])
10
+ const SUBCOMMANDS = new Set(['profile', 'clear'])
11
+
12
+ function findSubcommand(args: string[]): { name: string; index: number } | null {
13
+ for (let i = 0; i < args.length; i++) {
14
+ const arg = args[i]
15
+ if (arg.startsWith('-')) {
16
+ if (VALUE_FLAGS.has(arg)) i++
17
+ continue
18
+ }
19
+ return SUBCOMMANDS.has(arg) ? { name: arg, index: i } : null
20
+ }
21
+ return null
22
+ }
23
+
24
+ function printHelp(): void {
25
+ console.log(`
26
+ rnxsim storage — manage sim and app storage
27
+
28
+ usage:
29
+ rnxsim storage profile <subcommand>
30
+ rnxsim storage clear [--full] [--sim <id>] [--json]
31
+
32
+ subcommands:
33
+ profile ls
34
+ profile create <id>
35
+ profile clear <id>
36
+ profile delete <id>
37
+ clear clear the current guest app data and relaunch it
38
+ `)
39
+ }
40
+
41
+ export async function runStorage(args: string[], opts: StorageOptions): Promise<number> {
42
+ if (args.includes('--help') || args.includes('-h')) {
43
+ printHelp()
44
+ return 0
45
+ }
46
+
47
+ const sub = findSubcommand(args)
48
+ if (sub?.name === 'profile') {
49
+ return runProfile([...args.slice(0, sub.index), ...args.slice(sub.index + 1)], opts)
50
+ }
51
+ if (sub?.name === 'clear') {
52
+ return runReset([...args.slice(0, sub.index), ...args.slice(sub.index + 1)], opts)
53
+ }
54
+
55
+ console.error(` unknown storage command: ${sub?.name ?? '(missing)'}`)
56
+ printHelp()
57
+ return 1
58
+ }
@@ -0,0 +1,54 @@
1
+ // `sootsim config telemetry on|off` — retained as the command spelling for the
2
+ // product analytics preference shown by guided setup and Settings.
3
+ //
4
+ // this is the process-wide preference; `DO_NOT_TRACK=1` still forces opt-out
5
+ // for a single run regardless of what's stored (honored by isOptedOut in
6
+ // telemetry.ts, the same cross-tool signal npm/turbo/supabase use).
7
+
8
+ import {
9
+ configFilePath,
10
+ readPrivacyPreferences,
11
+ writePrivacyPreferences,
12
+ } from '../../src/home-paths'
13
+
14
+ function printStatus(): void {
15
+ const preferences = readPrivacyPreferences()
16
+ console.log(` product analytics are ${preferences.productAnalytics ? 'ON' : 'OFF'}`)
17
+ console.log(` config: ${configFilePath()}`)
18
+ const doNotTrack = process.env.DO_NOT_TRACK
19
+ if (doNotTrack === '1' || doNotTrack === 'true') {
20
+ console.log(
21
+ ` note: DO_NOT_TRACK=${doNotTrack} is set — telemetry is off for this run`,
22
+ )
23
+ }
24
+ }
25
+
26
+ export async function runTelemetry(args: string[]): Promise<void> {
27
+ const sub = args.find((a) => !a.startsWith('-'))?.toLowerCase()
28
+
29
+ switch (sub) {
30
+ case undefined:
31
+ case 'status':
32
+ printStatus()
33
+ return
34
+
35
+ case 'on':
36
+ case 'enable':
37
+ writePrivacyPreferences({ ...readPrivacyPreferences(), productAnalytics: true })
38
+ console.log(' product analytics ON')
39
+ console.log(` config: ${configFilePath()}`)
40
+ return
41
+
42
+ case 'off':
43
+ case 'disable':
44
+ writePrivacyPreferences({ ...readPrivacyPreferences(), productAnalytics: false })
45
+ console.log(' product analytics OFF')
46
+ console.log(` config: ${configFilePath()}`)
47
+ return
48
+
49
+ default:
50
+ console.error(` unknown telemetry action: ${sub}`)
51
+ console.error(' usage: rnxsim config telemetry [on|off|status]')
52
+ process.exit(1)
53
+ }
54
+ }