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,266 @@
1
+ // rnxsim camera drives the host-owned camera source. fixture video uses the
2
+ // same hidden video, canvas frame pump, ImageBitmap transfer, and
3
+ // BarcodeDetector loop as a real device camera. `do scan` remains the narrow
4
+ // synthetic special case for callers that have a payload string but no media.
5
+
6
+ import { createHash, randomUUID } from 'node:crypto'
7
+ import { createReadStream } from 'node:fs'
8
+ import fs from 'node:fs/promises'
9
+ import path from 'node:path'
10
+ import { cameraFixturesDir } from '../../src/home-paths'
11
+ import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
12
+ import {
13
+ createBridgeFromParsed,
14
+ evalInBridge,
15
+ parseBridgeCliArgs,
16
+ type WsBridge,
17
+ } from '../ws-bridge'
18
+ import type { CameraCommand, CameraResult } from '../../src/bridge-contract'
19
+
20
+ const CAMERA_FIXTURE_ROUTE = '/__camera-fixtures/'
21
+ const VIDEO_EXTENSIONS = new Set(['.m4v', '.mov', '.mp4', '.webm'])
22
+
23
+ function printHelp() {
24
+ console.log(`
25
+ rnxsim camera — control the simulator camera source
26
+
27
+ usage:
28
+ rnxsim camera play <file> [--loop] [--rate <number>]
29
+ rnxsim camera stop
30
+ rnxsim camera status [--json]
31
+ rnxsim do scan <text> [--format <web-format>]
32
+
33
+ subcommands:
34
+ play <file> replace the active camera source with a local video fixture
35
+ stop clear fixture mode and restore the live camera source
36
+ status report live, fixture, or idle source state
37
+ scan <text> inject a synthetic barcode result into an active scan session
38
+
39
+ options:
40
+ --loop loop fixture playback
41
+ --rate <n> fixture playback rate (default: 1)
42
+ --format <f> synthetic BarcodeDetector format (default: qr_code)
43
+ --json print status/result as JSON
44
+ --sim <id> target a specific sim
45
+ --port <p> WS bridge port (default: 7668)
46
+
47
+ examples:
48
+ rnxsim camera play ./fixtures/qr.mp4 --loop
49
+ rnxsim camera play ./fixtures/document.webm --rate 2
50
+ rnxsim camera status
51
+ rnxsim camera stop
52
+ rnxsim do scan "https://example.com" --format qr_code
53
+ `)
54
+ }
55
+
56
+ function isCameraResult(value: unknown): value is CameraResult {
57
+ if (!value || typeof value !== 'object') return false
58
+ const ok = Reflect.get(value, 'ok')
59
+ const source = Reflect.get(value, 'source')
60
+ return (
61
+ typeof ok === 'boolean' &&
62
+ (source === 'live' || source === 'fixture' || source === 'idle')
63
+ )
64
+ }
65
+
66
+ async function sendCameraCommand(
67
+ bridge: WsBridge,
68
+ camera: CameraCommand,
69
+ ): Promise<CameraResult> {
70
+ const result: unknown = await bridge.send({ type: 'camera', camera })
71
+ if (!isCameraResult(result)) {
72
+ throw new Error('camera bridge returned an invalid result')
73
+ }
74
+ return result
75
+ }
76
+
77
+ function printCameraResult(result: CameraResult, json: boolean): void {
78
+ if (json) {
79
+ console.log(JSON.stringify(result))
80
+ return
81
+ }
82
+ if (result.source === 'fixture') {
83
+ console.log(
84
+ ` camera source: fixture (${result.url ?? 'unknown url'}, ${
85
+ result.loop ? 'looping' : 'once'
86
+ }, ${result.rate ?? 1}x)`,
87
+ )
88
+ } else if (result.source === 'live') {
89
+ console.log(' camera source: live')
90
+ } else if (result.url) {
91
+ console.log(
92
+ ` camera source: idle (fixture queued: ${result.url}, ${
93
+ result.loop ? 'looping' : 'once'
94
+ }, ${result.rate ?? 1}x)`,
95
+ )
96
+ } else {
97
+ console.log(' camera source: idle')
98
+ }
99
+ if (!result.ok && result.error) console.error(` camera failed: ${result.error}`)
100
+ }
101
+
102
+ export async function runCamera(
103
+ args: string[],
104
+ opts: { port?: number } = {},
105
+ ): Promise<number> {
106
+ const parsed = parseBridgeCliArgs(args, {
107
+ port: opts.port,
108
+ stripBooleanFlags: ['--help', '-h', '--json', '--loop'],
109
+ stripValueFlags: ['--format', '--rate'],
110
+ })
111
+ const positional = parsed.positional
112
+ const subcommand = positional[0]
113
+ if (
114
+ !subcommand ||
115
+ subcommand === 'help' ||
116
+ args.includes('--help') ||
117
+ args.includes('-h')
118
+ ) {
119
+ printHelp()
120
+ return subcommand ? 0 : 1
121
+ }
122
+
123
+ const bridge = createBridgeFromParsed(parsed)
124
+ const json = args.includes('--json')
125
+ try {
126
+ if (subcommand === 'scan') {
127
+ const text = positional[1]
128
+ if (!text) {
129
+ console.error(' usage: rnxsim do scan <text>')
130
+ return 1
131
+ }
132
+ const formatFlag = args.indexOf('--format')
133
+ const format = formatFlag >= 0 ? args[formatFlag + 1] : 'qr_code'
134
+ if (!format) {
135
+ console.error(' --format requires a value')
136
+ return 1
137
+ }
138
+ const injected = await evalInBridge<boolean>(
139
+ bridge,
140
+ `globalThis.__sootsimCameraInjectScan?.(${JSON.stringify(text)}, ${JSON.stringify(format)}) ?? false`,
141
+ )
142
+ if (!injected) {
143
+ console.error(
144
+ ' no active barcode scan session. open a scanning <CameraView> first',
145
+ )
146
+ return 1
147
+ }
148
+ console.log(` injected ${format} scan: ${text}`)
149
+ return 0
150
+ }
151
+
152
+ if (subcommand === 'status') {
153
+ const result = await sendCameraCommand(bridge, { action: 'status' })
154
+ printCameraResult(result, json)
155
+ return result.ok ? 0 : 1
156
+ }
157
+
158
+ if (subcommand === 'stop') {
159
+ const result = await sendCameraCommand(bridge, { action: 'stop' })
160
+ printCameraResult(result, json)
161
+ return result.ok ? 0 : 1
162
+ }
163
+
164
+ if (subcommand === 'play') {
165
+ const input = positional[1]
166
+ if (!input) {
167
+ console.error(' usage: rnxsim camera play <file> [--loop] [--rate <number>]')
168
+ return 1
169
+ }
170
+ const sourcePath = path.resolve(input)
171
+ const extension = path.extname(sourcePath).toLowerCase()
172
+ if (!VIDEO_EXTENSIONS.has(extension)) {
173
+ console.error(
174
+ ` unsupported camera fixture extension ${extension || '(none)'}. use mp4, webm, mov, or m4v`,
175
+ )
176
+ return 1
177
+ }
178
+ let sourceStat
179
+ try {
180
+ sourceStat = await fs.stat(sourcePath)
181
+ } catch {
182
+ console.error(` camera fixture not found: ${sourcePath}`)
183
+ return 1
184
+ }
185
+ if (!sourceStat.isFile() || sourceStat.size === 0) {
186
+ console.error(` camera fixture must be a non-empty file: ${sourcePath}`)
187
+ return 1
188
+ }
189
+
190
+ const rateFlag = args.indexOf('--rate')
191
+ const rawRate = rateFlag >= 0 ? args[rateFlag + 1] : undefined
192
+ const rate = rawRate === undefined ? 1 : Number(rawRate)
193
+ if (!Number.isFinite(rate) || rate <= 0) {
194
+ console.error(' --rate must be a positive finite number')
195
+ return 1
196
+ }
197
+
198
+ const fixtureDirectory = cameraFixturesDir()
199
+ await fs.mkdir(fixtureDirectory, { recursive: true })
200
+ const digest = createHash('sha256')
201
+ await new Promise<void>((resolve, reject) => {
202
+ const input = createReadStream(sourcePath)
203
+ input.on('data', (chunk) => digest.update(chunk))
204
+ input.once('error', reject)
205
+ input.once('end', resolve)
206
+ })
207
+ const filename = `${digest.digest('hex')}${extension}`
208
+ const servedPath = path.join(fixtureDirectory, filename)
209
+ let staged = false
210
+ try {
211
+ const servedStat = await fs.lstat(servedPath)
212
+ if (!servedStat.isFile()) {
213
+ throw new Error(`camera fixture cache entry is not a file: ${servedPath}`)
214
+ }
215
+ staged = true
216
+ } catch (error) {
217
+ if (
218
+ !error ||
219
+ typeof error !== 'object' ||
220
+ Reflect.get(error, 'code') !== 'ENOENT'
221
+ ) {
222
+ throw error
223
+ }
224
+ }
225
+ if (!staged) {
226
+ const temporaryPath = path.join(
227
+ fixtureDirectory,
228
+ `.${filename}.${process.pid}-${randomUUID()}.tmp`,
229
+ )
230
+ await fs.copyFile(sourcePath, temporaryPath)
231
+ try {
232
+ await fs.link(temporaryPath, servedPath)
233
+ } catch (error) {
234
+ if (
235
+ !error ||
236
+ typeof error !== 'object' ||
237
+ Reflect.get(error, 'code') !== 'EEXIST'
238
+ ) {
239
+ throw error
240
+ }
241
+ } finally {
242
+ await fs.unlink(temporaryPath).catch(() => {})
243
+ }
244
+ }
245
+ const url = `http://127.0.0.1:${parsed.wsPort}${CAMERA_FIXTURE_ROUTE}${filename}`
246
+ const result = await sendCameraCommand(bridge, {
247
+ action: 'play',
248
+ url,
249
+ loop: args.includes('--loop'),
250
+ rate,
251
+ })
252
+ printCameraResult(result, json)
253
+ return result.ok ? 0 : 1
254
+ }
255
+
256
+ console.error(` unknown camera subcommand: ${subcommand}`)
257
+ printHelp()
258
+ return 1
259
+ } catch (error) {
260
+ console.error(` camera failed: ${error instanceof Error ? error.message : error}`)
261
+ await printBridgeFailureDiagnostics(bridge)
262
+ return 1
263
+ } finally {
264
+ bridge.close()
265
+ }
266
+ }
@@ -0,0 +1,169 @@
1
+ import {
2
+ applyAutomaticSootsimCleanup,
3
+ applySootsimCleanup,
4
+ formatSootsimBytes,
5
+ planSootsimCleanup,
6
+ type SootsimCleanupEntry,
7
+ type SootsimCleanupKind,
8
+ } from '../../src/disk-cleanup'
9
+
10
+ const KIND_LABELS: Record<SootsimCleanupKind, string> = {
11
+ 'browser-cache': 'browser caches',
12
+ 'camera-fixture': 'staged camera fixture videos',
13
+ recording: 'recordings and captured frames',
14
+ 'runtime-archive': 'downloaded runtime archives',
15
+ 'runtime-version': 'inactive runtime versions',
16
+ }
17
+
18
+ function summarize(entries: SootsimCleanupEntry[]): string[] {
19
+ const byKind = new Map<SootsimCleanupKind, { bytes: number; count: number }>()
20
+ for (const entry of entries) {
21
+ const current = byKind.get(entry.kind) ?? { bytes: 0, count: 0 }
22
+ current.bytes += entry.bytes
23
+ current.count++
24
+ byKind.set(entry.kind, current)
25
+ }
26
+ return [...byKind]
27
+ .sort((left, right) => right[1].bytes - left[1].bytes)
28
+ .map(
29
+ ([kind, summary]) =>
30
+ ` ${KIND_LABELS[kind]}: ${formatSootsimBytes(summary.bytes)} (${summary.count} ${
31
+ summary.count === 1 ? 'item' : 'items'
32
+ })`,
33
+ )
34
+ }
35
+
36
+ function printHelp(): void {
37
+ console.log(`
38
+ rnxsim cleanup — inspect and reclaim local rnx disk usage
39
+
40
+ usage:
41
+ rnxsim cleanup
42
+ rnxsim cleanup --apply
43
+ rnxsim cleanup --aggressive
44
+ rnxsim cleanup --apply --aggressive
45
+
46
+ The default is a read-only preview. --apply removes downloaded runtime archives,
47
+ old runtimes outside a two-version rollback window, and disposable browser
48
+ caches. It never removes the active runtime, a runtime serving a connected
49
+ simulator, cookies, localStorage, IndexedDB, service workers, or other persistent
50
+ app storage.
51
+
52
+ --aggressive additionally removes the rollback runtime plus user-created
53
+ recordings and captured frames. It still preserves the active runtime and app storage.
54
+ `)
55
+ }
56
+
57
+ export async function runCleanup(args: string[]): Promise<number> {
58
+ if (args.length === 1 && args[0] === '--automatic-worker') {
59
+ try {
60
+ const result = applyAutomaticSootsimCleanup()
61
+ if (result.status === 'complete') {
62
+ process.stderr.write(
63
+ result.reclaimedBytes > 0
64
+ ? ` rnx automatic cleanup reclaimed ${formatSootsimBytes(
65
+ result.reclaimedBytes,
66
+ )}; active runtimes and app data were kept.\n`
67
+ : ' rnx automatic cleanup found no obsolete local data.\n',
68
+ )
69
+ } else if (result.status === 'deferred') {
70
+ process.stderr.write(
71
+ ` rnx automatic cleanup reclaimed ${formatSootsimBytes(
72
+ result.reclaimedBytes,
73
+ )}; ${formatSootsimBytes(
74
+ result.deferredInUseBytes,
75
+ )} is in use and will be retried on a later run.\n`,
76
+ )
77
+ }
78
+ return 0
79
+ } catch (error) {
80
+ process.stderr.write(
81
+ ` rnx automatic cleanup will retry on the next run: ${
82
+ error instanceof Error ? error.message : String(error)
83
+ }\n`,
84
+ )
85
+ return 0
86
+ }
87
+ }
88
+ if (args.includes('--help') || args.includes('-h')) {
89
+ printHelp()
90
+ return 0
91
+ }
92
+ const known = new Set(['--aggressive', '--apply'])
93
+ const unknown = args.find((arg) => !known.has(arg))
94
+ if (unknown) {
95
+ console.error(` cleanup: unknown option ${unknown}`)
96
+ printHelp()
97
+ return 1
98
+ }
99
+
100
+ const aggressive = args.includes('--aggressive')
101
+ const apply = args.includes('--apply')
102
+ const plan = planSootsimCleanup({ aggressive })
103
+ const selected = plan.entries.filter((entry) => entry.selected)
104
+ const safe = selected.filter((entry) => entry.state === 'safe')
105
+ const aggressiveOnly = plan.entries.filter(
106
+ (entry) => entry.state === 'aggressive' && entry.selected,
107
+ )
108
+ const inUse = plan.entries.filter((entry) => entry.state === 'in-use')
109
+ const inUseBrowserCaches = inUse.filter((entry) => entry.kind === 'browser-cache')
110
+ const inUseRuntimes = inUse.filter((entry) => entry.kind === 'runtime-version')
111
+ const rollback = plan.entries.find(
112
+ (entry) => entry.kind === 'runtime-version' && entry.state === 'aggressive',
113
+ )
114
+
115
+ console.log(` rnx data home: ${plan.home}`)
116
+ console.log(` current size: ${formatSootsimBytes(plan.totalBytes)}`)
117
+ console.log(` active runtime: ${plan.activeRuntime ?? '(none installed)'}`)
118
+ console.log('')
119
+ console.log(apply ? ' safe items selected for removal:' : ' safe to reclaim:')
120
+ for (const line of summarize(safe)) console.log(line)
121
+ if (safe.length === 0) console.log(' nothing')
122
+
123
+ if (aggressiveOnly.length > 0) {
124
+ console.log('')
125
+ console.log(' aggressive additions:')
126
+ for (const line of summarize(aggressiveOnly)) console.log(line)
127
+ }
128
+
129
+ console.log('')
130
+ console.log(' protected:')
131
+ if (plan.activeRuntime) console.log(` active runtime ${plan.activeRuntime} (in use)`)
132
+ for (const entry of inUseRuntimes) {
133
+ console.log(` running daemon runtime ${entry.path}`)
134
+ }
135
+ if (rollback && !aggressive) {
136
+ console.log(` rollback runtime ${rollback.path}`)
137
+ }
138
+ console.log(' cookies, localStorage, IndexedDB, service workers, and profile data')
139
+ if (!aggressive) {
140
+ console.log(' recordings and captured frames (use --aggressive to remove)')
141
+ }
142
+ if (inUseBrowserCaches.length > 0) {
143
+ console.log(
144
+ ` ${formatSootsimBytes(
145
+ inUseBrowserCaches.reduce((total, entry) => total + entry.bytes, 0),
146
+ )} ` + `of browser cache is open; close rnx and rerun cleanup`,
147
+ )
148
+ }
149
+
150
+ console.log('')
151
+ console.log(` reclaimable now: ${formatSootsimBytes(plan.reclaimableBytes)}`)
152
+ if (!apply) {
153
+ console.log(
154
+ ` preview only — run \`rnxsim cleanup --apply${
155
+ aggressive ? ' --aggressive' : ''
156
+ }\` to remove these items`,
157
+ )
158
+ return 0
159
+ }
160
+
161
+ const result = applySootsimCleanup({ aggressive })
162
+ console.log(
163
+ ` removed ${result.removedPaths.length} ${
164
+ result.removedPaths.length === 1 ? 'item' : 'items'
165
+ }; reclaimed ${formatSootsimBytes(result.reclaimedBytes)}`,
166
+ )
167
+ console.log(` remaining rnx data: ${formatSootsimBytes(result.remainingBytes)}`)
168
+ return 0
169
+ }
@@ -0,0 +1,87 @@
1
+ // sootsim compat — scan dependencies with the shared compatibility engine.
2
+
3
+ import { existsSync, readFileSync } from 'node:fs'
4
+ import { resolve } from 'node:path'
5
+ import {
6
+ COMPAT_RESULT_CAVEAT,
7
+ formatDetailedScanLines,
8
+ formatScanCounts,
9
+ scanDeps,
10
+ type ScanResult,
11
+ } from '@sootsim/compat/web'
12
+
13
+ interface PackageManifest {
14
+ name?: string
15
+ dependencies?: Record<string, string>
16
+ devDependencies?: Record<string, string>
17
+ }
18
+
19
+ export async function runCompat(args: string[]): Promise<void> {
20
+ if (args.includes('--help') || args.includes('-h')) {
21
+ console.log(`
22
+ rnxsim compat — check package compatibility
23
+
24
+ usage:
25
+ rnxsim compat [package-name]
26
+ rnxsim compat --json
27
+ rnxsim compat --brief
28
+
29
+ flags:
30
+ --json machine-readable output
31
+ --brief one-line summary
32
+ --app <dir> target directory (default: cwd)
33
+ `)
34
+ return
35
+ }
36
+
37
+ const appIndex = args.indexOf('--app')
38
+ const appDir =
39
+ appIndex >= 0 && args[appIndex + 1] ? resolve(args[appIndex + 1]) : process.cwd()
40
+ const packageName = args.find(
41
+ (arg, index) => !arg.startsWith('-') && (appIndex < 0 || index !== appIndex + 1),
42
+ )
43
+ const pkg = readPackageJson(appDir)
44
+ if (!pkg) {
45
+ console.error(` no package.json found in ${appDir}`)
46
+ process.exitCode = 1
47
+ return
48
+ }
49
+
50
+ const result = packageName ? scanOnePackage(pkg, packageName) : scanDeps(pkg)
51
+ if (args.includes('--json')) {
52
+ console.log(JSON.stringify(result, null, 2))
53
+ return
54
+ }
55
+ if (args.includes('--brief')) {
56
+ console.log(` ${formatScanCounts(result)}`)
57
+ console.log(` ${COMPAT_RESULT_CAVEAT}`)
58
+ return
59
+ }
60
+
61
+ console.log(`\n rnx compatibility report`)
62
+ console.log(` ${formatScanCounts(result)}\n`)
63
+ for (const line of formatDetailedScanLines(result)) console.log(` ${line}`)
64
+ const supported = result.packages.filter((item) => item.status === 'full').length
65
+ if (supported > 0) console.log(` supported: ${supported} packages`)
66
+ const notRelevant = result.packages.filter(
67
+ (item) => item.status === 'not-relevant',
68
+ ).length
69
+ if (notRelevant > 0) console.log(` not relevant at runtime: ${notRelevant} packages`)
70
+ if (result.packages.length === 0) {
71
+ console.log(` no React Native ecosystem packages detected`)
72
+ }
73
+ console.log(`\n ${COMPAT_RESULT_CAVEAT}\n`)
74
+ }
75
+
76
+ function readPackageJson(appDir: string): PackageManifest | null {
77
+ const packagePath = resolve(appDir, 'package.json')
78
+ if (!existsSync(packagePath)) return null
79
+ const parsed: unknown = JSON.parse(readFileSync(packagePath, 'utf8'))
80
+ return parsed && typeof parsed === 'object' ? parsed : null
81
+ }
82
+
83
+ function scanOnePackage(pkg: PackageManifest, packageName: string): ScanResult {
84
+ const version =
85
+ pkg.dependencies?.[packageName] ?? pkg.devDependencies?.[packageName] ?? '*'
86
+ return scanDeps({ dependencies: { [packageName]: version } })
87
+ }
@@ -0,0 +1,32 @@
1
+ import { runTelemetry } from './telemetry'
2
+
3
+ function printHelp(): void {
4
+ console.log(`
5
+ rnxsim config — manage local CLI preferences
6
+
7
+ usage:
8
+ rnxsim config telemetry [on|off|status]
9
+
10
+ environment:
11
+ SOOTSIM_HINTS=off suppress CLI hints
12
+ SOOTSIM_HINTS=always show every CLI hint every time
13
+ `)
14
+ }
15
+
16
+ export async function runConfig(args: string[]): Promise<void> {
17
+ if (args.includes('--help') || args.includes('-h')) {
18
+ printHelp()
19
+ return
20
+ }
21
+
22
+ const sub = args.find((arg) => !arg.startsWith('-'))
23
+ if (sub === 'telemetry') {
24
+ const index = args.indexOf(sub)
25
+ await runTelemetry([...args.slice(0, index), ...args.slice(index + 1)])
26
+ return
27
+ }
28
+
29
+ console.error(` unknown config command: ${sub ?? '(missing)'}`)
30
+ printHelp()
31
+ process.exit(1)
32
+ }