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,203 @@
1
+ import {
2
+ callInBridge,
3
+ callInBridgeWrite,
4
+ createBridgeFromParsed,
5
+ parseBridgeCliArgs,
6
+ } from '../ws-bridge'
7
+ import type {
8
+ AppSettingsSnapshot,
9
+ SystemPermissionApp,
10
+ SystemPermissionKind,
11
+ SystemPermissionMutation,
12
+ SystemPermissionStatus,
13
+ } from '@sootsim/globals'
14
+
15
+ interface PermissionsOptions {
16
+ port?: number
17
+ verbose?: boolean
18
+ }
19
+
20
+ const STATUSES: readonly SystemPermissionStatus[] = [
21
+ 'not-determined',
22
+ 'restricted',
23
+ 'denied',
24
+ 'authorized',
25
+ 'limited',
26
+ 'provisional',
27
+ 'ephemeral',
28
+ 'unavailable',
29
+ ]
30
+
31
+ const KINDS: readonly SystemPermissionKind[] = [
32
+ 'app-tracking-transparency',
33
+ 'bluetooth',
34
+ 'calendars',
35
+ 'camera',
36
+ 'contacts',
37
+ 'face-id',
38
+ 'local-network',
39
+ 'location-always',
40
+ 'location-when-in-use',
41
+ 'media-library',
42
+ 'microphone',
43
+ 'motion',
44
+ 'notifications',
45
+ 'photo-library',
46
+ 'photo-library-add-only',
47
+ 'reminders',
48
+ 'siri',
49
+ 'speech-recognition',
50
+ ]
51
+
52
+ function printHelp(): void {
53
+ console.log(`
54
+ rnxsim permissions — inspect and change simulated operating-system permissions
55
+
56
+ usage:
57
+ rnxsim permissions list [--json]
58
+ rnxsim permissions get <app-id> [--json]
59
+ rnxsim permissions set <app-id> <kind> <status> [--once] [--accuracy full|reduced] [--json]
60
+ rnxsim permissions reset <app-id> [kind] [--json]
61
+ `)
62
+ }
63
+
64
+ function print(value: unknown, json: boolean): void {
65
+ console.log(json ? JSON.stringify(value, null, 2) : value)
66
+ }
67
+
68
+ function flagValue(args: string[], flag: string): string | undefined {
69
+ const index = args.indexOf(flag)
70
+ return index >= 0 ? args[index + 1] : undefined
71
+ }
72
+
73
+ function permissionKind(value: string): SystemPermissionKind | null {
74
+ return KINDS.find((candidate) => candidate === value) ?? null
75
+ }
76
+
77
+ function permissionStatus(value: string): SystemPermissionStatus | null {
78
+ return STATUSES.find((candidate) => candidate === value) ?? null
79
+ }
80
+
81
+ function mutationFor(
82
+ status: SystemPermissionStatus,
83
+ once: boolean,
84
+ accuracy: 'full' | 'reduced' | undefined,
85
+ ): SystemPermissionMutation {
86
+ switch (status) {
87
+ case 'authorized':
88
+ return {
89
+ status,
90
+ ...(once ? { authorizationScope: 'once' } : null),
91
+ ...(accuracy ? { locationAccuracy: accuracy } : null),
92
+ }
93
+ case 'not-determined':
94
+ case 'restricted':
95
+ case 'denied':
96
+ case 'limited':
97
+ case 'provisional':
98
+ case 'ephemeral':
99
+ case 'unavailable':
100
+ return { status }
101
+ }
102
+ }
103
+
104
+ export async function runPermissions(
105
+ args: string[],
106
+ opts: PermissionsOptions,
107
+ ): Promise<number> {
108
+ if (args.includes('--help') || args.includes('-h')) {
109
+ printHelp()
110
+ return 0
111
+ }
112
+ const parsed = parseBridgeCliArgs(args, {
113
+ port: opts.port,
114
+ stripBooleanFlags: ['--json', '--once'],
115
+ stripValueFlags: ['--accuracy'],
116
+ })
117
+ const [command, appId, kindValue, statusValue] = parsed.positional
118
+ if (!command) {
119
+ printHelp()
120
+ return 1
121
+ }
122
+ const json = args.includes('--json')
123
+ const bridge = createBridgeFromParsed(parsed)
124
+ try {
125
+ if (command === 'list') {
126
+ const apps = await callInBridge<readonly SystemPermissionApp[]>(
127
+ bridge,
128
+ 'SootSim.bridges.test.permissionListApps',
129
+ )
130
+ print(
131
+ json ? apps : apps.map((app) => `${app.appId}\t${app.displayName}`).join('\n'),
132
+ json,
133
+ )
134
+ return 0
135
+ }
136
+ if (!appId) throw new Error(`${command} requires an app id`)
137
+ if (command === 'get') {
138
+ const snapshot = await callInBridge<AppSettingsSnapshot>(
139
+ bridge,
140
+ 'SootSim.bridges.test.permissionGetAppSettings',
141
+ appId,
142
+ )
143
+ print(snapshot, json)
144
+ return 0
145
+ }
146
+ if (command === 'reset') {
147
+ if (kindValue) {
148
+ const kind = permissionKind(kindValue)
149
+ if (!kind) throw new Error(`unknown permission kind: ${kindValue}`)
150
+ await callInBridgeWrite<AppSettingsSnapshot>(
151
+ bridge,
152
+ 'SootSim.bridges.test.permissionSetAppPermission',
153
+ appId,
154
+ kind,
155
+ { status: 'not-determined' },
156
+ )
157
+ } else {
158
+ await callInBridgeWrite<void>(
159
+ bridge,
160
+ 'SootSim.bridges.test.permissionResetApp',
161
+ appId,
162
+ )
163
+ }
164
+ const snapshot = await callInBridge<AppSettingsSnapshot>(
165
+ bridge,
166
+ 'SootSim.bridges.test.permissionGetAppSettings',
167
+ appId,
168
+ )
169
+ print(snapshot, json)
170
+ return 0
171
+ }
172
+ if (command !== 'set') throw new Error(`unknown permissions command: ${command}`)
173
+ if (!kindValue || !statusValue) {
174
+ throw new Error('set requires an app id, permission kind, and status')
175
+ }
176
+ const kind = permissionKind(kindValue)
177
+ if (!kind) throw new Error(`unknown permission kind: ${kindValue}`)
178
+ const status = permissionStatus(statusValue)
179
+ if (!status) throw new Error(`unknown permission status: ${statusValue}`)
180
+ const accuracyValue = flagValue(args, '--accuracy')
181
+ const accuracy =
182
+ accuracyValue === 'full' || accuracyValue === 'reduced' ? accuracyValue : undefined
183
+ if (accuracyValue && !accuracy) {
184
+ throw new Error(`unknown location accuracy: ${accuracyValue}`)
185
+ }
186
+ const snapshot = await callInBridgeWrite<AppSettingsSnapshot>(
187
+ bridge,
188
+ 'SootSim.bridges.test.permissionSetAppPermission',
189
+ appId,
190
+ kind,
191
+ mutationFor(status, args.includes('--once'), accuracy),
192
+ )
193
+ print(snapshot, json)
194
+ return 0
195
+ } catch (error) {
196
+ console.error(
197
+ ` permissions failed: ${error instanceof Error ? error.message : error}`,
198
+ )
199
+ return 1
200
+ } finally {
201
+ bridge.close()
202
+ }
203
+ }
@@ -0,0 +1,108 @@
1
+ // sootsim storage profile — manage isolated app storage profiles.
2
+
3
+ import {
4
+ clearProfileStorage,
5
+ createProfile,
6
+ deleteProfile,
7
+ ensureProfile,
8
+ listProfiles,
9
+ } from '../../src/profiles'
10
+
11
+ interface ProfileOptions {
12
+ port?: number
13
+ verbose?: boolean
14
+ }
15
+
16
+ function printHelp() {
17
+ console.log(`
18
+ rnxsim storage profile — manage isolated storage profiles
19
+
20
+ usage:
21
+ rnxsim storage profile ls
22
+ rnxsim storage profile create <id>
23
+ rnxsim storage profile clear <id>
24
+ rnxsim storage profile delete <id>
25
+
26
+ profiles isolate cookies, localStorage, IndexedDB, cache, permissions, and
27
+ service workers in Electron and Playwright launches. Plain browser-tab launches
28
+ cannot honor profiles and will fail clearly if a profile is requested.
29
+
30
+ examples:
31
+ rnxsim storage profile ls
32
+ rnxsim storage profile create qa
33
+ rnxsim open 8081 --profile qa
34
+ rnxsim open 8081 --profile qa --driver playwright
35
+ rnxsim storage profile clear qa
36
+ rnxsim storage profile delete qa
37
+ `)
38
+ }
39
+
40
+ export async function runProfile(args: string[], _opts: ProfileOptions): Promise<number> {
41
+ if (args.includes('--help') || args.includes('-h')) {
42
+ printHelp()
43
+ return 0
44
+ }
45
+
46
+ const subcommand = args[0] ?? 'ls'
47
+ try {
48
+ switch (subcommand) {
49
+ case 'ls':
50
+ case 'list': {
51
+ const profiles = listProfiles()
52
+ for (const profile of profiles) {
53
+ console.log(` ${profile.id}`)
54
+ }
55
+ return 0
56
+ }
57
+ case 'create': {
58
+ const id = args[1]
59
+ if (!id) {
60
+ console.error(' profile create expects <id>')
61
+ return 1
62
+ }
63
+ const profile = createProfile(id)
64
+ console.log(` created profile: ${profile.id}`)
65
+ return 0
66
+ }
67
+ case 'ensure': {
68
+ const id = args[1]
69
+ if (!id) {
70
+ console.error(' profile ensure expects <id>')
71
+ return 1
72
+ }
73
+ const profile = ensureProfile(id)
74
+ console.log(` profile: ${profile.id}`)
75
+ return 0
76
+ }
77
+ case 'clear': {
78
+ const id = args[1]
79
+ if (!id) {
80
+ console.error(' profile clear expects <id>')
81
+ return 1
82
+ }
83
+ ensureProfile(id)
84
+ clearProfileStorage(id)
85
+ console.log(` cleared profile: ${id}`)
86
+ return 0
87
+ }
88
+ case 'delete':
89
+ case 'rm': {
90
+ const id = args[1]
91
+ if (!id) {
92
+ console.error(' profile delete expects <id>')
93
+ return 1
94
+ }
95
+ const profile = deleteProfile(id)
96
+ console.log(` deleted profile: ${profile.id}`)
97
+ return 0
98
+ }
99
+ default:
100
+ console.error(` unknown profile command: ${subcommand}`)
101
+ printHelp()
102
+ return 1
103
+ }
104
+ } catch (err) {
105
+ console.error(` profile failed: ${err instanceof Error ? err.message : String(err)}`)
106
+ return 1
107
+ }
108
+ }
@@ -0,0 +1,353 @@
1
+ import {
2
+ callInBridge,
3
+ callInBridgeWrite,
4
+ createBridgeFromParsed,
5
+ parseBridgeCliArgs,
6
+ } from '../ws-bridge'
7
+
8
+ interface ReactOptions {
9
+ port?: number
10
+ verbose?: boolean
11
+ }
12
+
13
+ interface SlowRow {
14
+ displayName: string
15
+ totalMs: number
16
+ avgMs: number
17
+ commitCount: number
18
+ slowestCommit: number
19
+ slowestMs: number
20
+ }
21
+
22
+ interface RerenderRow {
23
+ displayName: string
24
+ count: number
25
+ renders?: number
26
+ causes: Record<string, number>
27
+ }
28
+
29
+ interface TreeRow {
30
+ id: number
31
+ displayName: string
32
+ kind: string
33
+ depth: number
34
+ childCount: number
35
+ }
36
+
37
+ function printHelp() {
38
+ console.log(`
39
+ rnxsim perf react — inspect React component render cost in the tenant worker
40
+
41
+ usage:
42
+ rnxsim perf react profile start [--include-props] [--max-commits N]
43
+ rnxsim perf react profile stop
44
+ rnxsim perf react summary [--limit 10] [--json]
45
+ rnxsim perf react slow [--limit 5] [--json]
46
+ rnxsim perf react rerenders [--limit 5] [--json]
47
+ rnxsim perf react tree [--depth 3] [--find <name>] [--json]
48
+ rnxsim perf react why <fiber-id> [--json]
49
+
50
+ \`react summary\` is the demo-friendly shortcut: it runs both slow and
51
+ rerenders in one round-trip, prints them as a single table per side,
52
+ and surfaces the duration-zero warning prominently when the bundle is
53
+ running without React profiler timers.
54
+
55
+ examples:
56
+ rnxsim perf react profile start
57
+ rnxsim do tap-text Inbox
58
+ rnxsim perf react profile stop
59
+ rnxsim perf react summary --limit 10
60
+ rnxsim perf react slow --limit 10
61
+ rnxsim perf react rerenders --json
62
+ `)
63
+ }
64
+
65
+ function valueOf(args: string[], flag: string): string | undefined {
66
+ const idx = args.indexOf(flag)
67
+ if (idx >= 0 && idx + 1 < args.length) return args[idx + 1]
68
+ const prefix = `${flag}=`
69
+ const found = args.find((arg) => arg.startsWith(prefix))
70
+ return found ? found.slice(prefix.length) : undefined
71
+ }
72
+
73
+ function numberFlag(args: string[], flag: string, fallback: number): number {
74
+ const raw = valueOf(args, flag)
75
+ if (raw === undefined) return fallback
76
+ const value = Number(raw)
77
+ return Number.isFinite(value) && value > 0 ? Math.round(value) : fallback
78
+ }
79
+
80
+ function formatTable(headers: string[], rows: string[][]): string {
81
+ const widths = headers.map((h, i) =>
82
+ Math.max(h.length, ...rows.map((row) => row[i]?.length ?? 0)),
83
+ )
84
+ const line = (cells: string[]) =>
85
+ cells
86
+ .map((cell, i) => cell.padEnd(widths[i]))
87
+ .join(' ')
88
+ .trimEnd()
89
+ return [
90
+ line(headers),
91
+ line(headers.map((h) => '-'.repeat(h.length))),
92
+ ...rows.map(line),
93
+ ]
94
+ .map((row) => ` ${row}`)
95
+ .join('\n')
96
+ }
97
+
98
+ function printJson(value: unknown) {
99
+ console.log(JSON.stringify(value, null, 2))
100
+ }
101
+
102
+ function printSlow(result: {
103
+ rows?: SlowRow[]
104
+ commits?: number
105
+ error?: string
106
+ durationWarning?: string
107
+ }) {
108
+ if (result.error) console.error(` warning: ${result.error}`)
109
+ if (result.durationWarning) console.error(` warning: ${result.durationWarning}`)
110
+ const rows = result.rows ?? []
111
+ if (rows.length === 0) {
112
+ console.log(` no React render samples yet (${result.commits ?? 0} commit(s))`)
113
+ return
114
+ }
115
+ console.log(
116
+ formatTable(
117
+ ['component', 'total', 'avg', 'commits', 'slowest'],
118
+ rows.map((row) => [
119
+ row.displayName,
120
+ `${row.totalMs.toFixed(2)}ms`,
121
+ `${row.avgMs.toFixed(2)}ms`,
122
+ String(row.commitCount),
123
+ `#${row.slowestCommit} ${row.slowestMs.toFixed(2)}ms`,
124
+ ]),
125
+ ),
126
+ )
127
+ }
128
+
129
+ function printRerenders(result: {
130
+ rows?: RerenderRow[]
131
+ commits?: number
132
+ error?: string
133
+ }) {
134
+ if (result.error) console.error(` warning: ${result.error}`)
135
+ const rows = result.rows ?? []
136
+ if (rows.length === 0) {
137
+ console.log(` no React render samples yet (${result.commits ?? 0} commit(s))`)
138
+ return
139
+ }
140
+ console.log(
141
+ formatTable(
142
+ ['component', 'renders', 'causes'],
143
+ rows.map((row) => {
144
+ const causes = Object.entries(row.causes ?? {})
145
+ .filter(([, count]) => count > 0)
146
+ .sort((a, b) => b[1] - a[1])
147
+ .slice(0, 4)
148
+ .map(([cause, count]) => `${cause}:${count}`)
149
+ .join(', ')
150
+ return [row.displayName, String(row.renders ?? row.count), causes || '-']
151
+ }),
152
+ ),
153
+ )
154
+ }
155
+
156
+ function printTree(result: { rows?: TreeRow[]; roots?: number; error?: string }) {
157
+ if (result.error) console.error(` warning: ${result.error}`)
158
+ const rows = result.rows ?? []
159
+ if (rows.length === 0) {
160
+ console.log(` no React tree data yet (${result.roots ?? 0} root(s))`)
161
+ return
162
+ }
163
+ for (const row of rows) {
164
+ const indent = ' '.repeat(row.depth)
165
+ console.log(
166
+ ` ${indent}@${row.id} ${row.displayName} [${row.kind}] children=${row.childCount}`,
167
+ )
168
+ }
169
+ }
170
+
171
+ function printWhy(result: { sample?: any; error?: string }) {
172
+ if (result.error) {
173
+ console.error(` ${result.error}`)
174
+ return
175
+ }
176
+ const sample = result.sample
177
+ if (!sample) {
178
+ console.log(' no sample')
179
+ return
180
+ }
181
+ console.log(` @${sample.fiberId} ${sample.displayName}`)
182
+ console.log(` duration: ${Number(sample.actualDuration ?? 0).toFixed(2)}ms`)
183
+ console.log(` causes: ${(sample.causes ?? []).join(', ') || '-'}`)
184
+ if (sample.propDiffs?.length) {
185
+ console.log(' props:')
186
+ for (const diff of sample.propDiffs) {
187
+ const values =
188
+ 'old' in diff || 'new' in diff
189
+ ? ` ${JSON.stringify(diff.old)} → ${JSON.stringify(diff.new)}`
190
+ : ''
191
+ console.log(` ${diff.key}${values}`)
192
+ }
193
+ }
194
+ if (sample.parentChain?.length) {
195
+ console.log(` parents: ${sample.parentChain.join(' ← ')}`)
196
+ }
197
+ }
198
+
199
+ export async function runReact(args: string[], opts: ReactOptions): Promise<number> {
200
+ const parsed = parseBridgeCliArgs(args, {
201
+ port: opts.port,
202
+ stripBooleanFlags: ['--json', '--include-props', '--help', '-h'],
203
+ stripValueFlags: ['--limit', '--depth', '--find', '--max-commits'],
204
+ })
205
+
206
+ if (args.includes('--help') || args.includes('-h')) {
207
+ printHelp()
208
+ return 0
209
+ }
210
+
211
+ const [first, second] = parsed.positional
212
+ const json = args.includes('--json')
213
+ const bridge = createBridgeFromParsed(parsed)
214
+
215
+ try {
216
+ if (first === 'profile' && second === 'start') {
217
+ const result = await callInBridgeWrite(
218
+ bridge,
219
+ 'SootSim.bridges.reactProfile.start',
220
+ {
221
+ includeProps: args.includes('--include-props'),
222
+ maxCommits: numberFlag(args, '--max-commits', 2000),
223
+ },
224
+ )
225
+ if (json) printJson(result)
226
+ else console.log(' React profile started')
227
+ return 0
228
+ }
229
+
230
+ if (first === 'profile' && second === 'stop') {
231
+ const result = (await callInBridgeWrite(
232
+ bridge,
233
+ 'SootSim.bridges.reactProfile.stop',
234
+ )) as { commits?: number; error?: string }
235
+ if (json) printJson(result)
236
+ else {
237
+ console.log(` React profile stopped (${result.commits ?? 0} commit(s))`)
238
+ if (result.error) console.error(` warning: ${result.error}`)
239
+ }
240
+ return result.error ? 1 : 0
241
+ }
242
+
243
+ if (first === 'summary') {
244
+ // run slow + rerenders in parallel against the existing bridge.
245
+ // demo-friendly: one command, one table per dimension, plus a
246
+ // single duration-zero warning that's easy to call out on stage.
247
+ const limit = numberFlag(args, '--limit', 10)
248
+ const [slowResult, rerendersResult] = (await Promise.all([
249
+ callInBridge(bridge, 'SootSim.bridges.reactProfile.slow', { limit }),
250
+ callInBridge(bridge, 'SootSim.bridges.reactProfile.rerenders', { limit }),
251
+ ])) as [
252
+ {
253
+ rows?: SlowRow[]
254
+ commits?: number
255
+ error?: string
256
+ durationWarning?: string
257
+ },
258
+ { rows?: RerenderRow[]; commits?: number; error?: string },
259
+ ]
260
+ if (json) {
261
+ printJson({
262
+ commits: slowResult.commits ?? rerendersResult.commits ?? 0,
263
+ slow: slowResult,
264
+ rerenders: rerendersResult,
265
+ })
266
+ return 0
267
+ }
268
+ const commits = slowResult.commits ?? rerendersResult.commits ?? 0
269
+ console.log(` React profile summary (${commits} commit(s)):`)
270
+ if (slowResult.error) console.error(` warning: ${slowResult.error}`)
271
+ if (slowResult.durationWarning) {
272
+ console.error(` warning: ${slowResult.durationWarning}`)
273
+ }
274
+ if (rerendersResult.error) {
275
+ console.error(` warning: ${rerendersResult.error}`)
276
+ }
277
+ console.log('\n slowest renders:')
278
+ printSlow(slowResult)
279
+ console.log('\n most rerenders:')
280
+ printRerenders(rerendersResult)
281
+ // hint about the actualDuration-zero limitation when the slow
282
+ // table is empty/zero — the demo-stage signal is "no timer
283
+ // data, expect rerenders rows only".
284
+ const slowestRow = slowResult.rows?.[0]
285
+ const allZero =
286
+ slowResult.rows && slowResult.rows.length > 0
287
+ ? slowResult.rows.every((r) => r.totalMs <= 0 && r.slowestMs <= 0)
288
+ : false
289
+ if (allZero && !slowResult.durationWarning) {
290
+ console.error(
291
+ `\n warning: every commit reports actualDuration=0ms — the React profiler timer is disabled in this bundle (rerender counts are still accurate; ${slowestRow?.displayName ? `top-listed: ${slowestRow.displayName}` : 'no slow signal'}).`,
292
+ )
293
+ }
294
+ return 0
295
+ }
296
+
297
+ if (first === 'slow') {
298
+ const result = (await callInBridge(bridge, 'SootSim.bridges.reactProfile.slow', {
299
+ limit: numberFlag(args, '--limit', 10),
300
+ })) as {
301
+ rows?: SlowRow[]
302
+ commits?: number
303
+ error?: string
304
+ durationWarning?: string
305
+ }
306
+ if (json) printJson(result)
307
+ else printSlow(result)
308
+ return 0
309
+ }
310
+
311
+ if (first === 'rerenders') {
312
+ const result = (await callInBridge(
313
+ bridge,
314
+ 'SootSim.bridges.reactProfile.rerenders',
315
+ { limit: numberFlag(args, '--limit', 10) },
316
+ )) as { rows?: RerenderRow[]; commits?: number; error?: string }
317
+ if (json) printJson(result)
318
+ else printRerenders(result)
319
+ return 0
320
+ }
321
+
322
+ if (first === 'tree') {
323
+ const result = (await callInBridge(bridge, 'SootSim.bridges.reactProfile.tree', {
324
+ depth: numberFlag(args, '--depth', 3),
325
+ find: valueOf(args, '--find'),
326
+ })) as { rows?: TreeRow[]; roots?: number; error?: string }
327
+ if (json) printJson(result)
328
+ else printTree(result)
329
+ return 0
330
+ }
331
+
332
+ if (first === 'why') {
333
+ const fiberId = Number(second)
334
+ if (!Number.isFinite(fiberId) || fiberId <= 0) {
335
+ console.error(' usage: rnxsim perf react why <fiber-id>')
336
+ return 1
337
+ }
338
+ const result = (await callInBridge(
339
+ bridge,
340
+ 'SootSim.bridges.reactProfile.why',
341
+ Math.round(fiberId),
342
+ )) as { sample?: unknown; error?: string }
343
+ if (json) printJson(result)
344
+ else printWhy(result)
345
+ return result.error ? 1 : 0
346
+ }
347
+
348
+ printHelp()
349
+ return first ? 1 : 0
350
+ } finally {
351
+ bridge.close()
352
+ }
353
+ }