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,545 @@
1
+ // sootsim setup — the single guided machine and repository onboarding flow.
2
+
3
+ import fs from 'node:fs'
4
+ import os from 'node:os'
5
+ import path from 'node:path'
6
+ import {
7
+ COMPAT_RESULT_CAVEAT,
8
+ countScanResults,
9
+ formatDetailedScanLines,
10
+ formatScanCounts,
11
+ scanDeps,
12
+ type ScanResult,
13
+ } from '@sootsim/compat/web'
14
+ import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
15
+ import { getCliVersion } from '../../src/cli-version'
16
+ import {
17
+ isDaemonLockfileFresh,
18
+ readActiveRuntime,
19
+ readDaemonLockfile,
20
+ readPrivacyPreferences,
21
+ runtimeDir,
22
+ writePrivacyPreferences,
23
+ } from '../../src/home-paths'
24
+ import { sootsimRuntime } from '../../src/runtime-delivery'
25
+ import { confirm } from '../prompt'
26
+ import {
27
+ applyRepositorySetup,
28
+ detectPreferredPackageManager,
29
+ findPackageRoot,
30
+ formatRepositoryOperations,
31
+ planRepositorySetup,
32
+ type RepositorySetupPlan,
33
+ } from '../setup-repository'
34
+ import { trackCliEvent } from '../telemetry'
35
+ import { daemonInstall, getDaemonServiceStatus } from './daemon'
36
+
37
+ interface SetupOptions {
38
+ appDir: string
39
+ ci: boolean
40
+ dryRun: boolean
41
+ fromWelcome: boolean
42
+ json: boolean
43
+ yes: boolean
44
+ service: boolean | undefined
45
+ repository: boolean | undefined
46
+ productAnalytics: boolean | undefined
47
+ crashReports: boolean | undefined
48
+ shareCompatibility: boolean
49
+ }
50
+
51
+ export interface MachineSetupStatus {
52
+ daemonSupported: boolean
53
+ daemonInstalled: boolean
54
+ daemonRunning: boolean
55
+ runtimeInstalled: boolean
56
+ privacyConfigured: boolean
57
+ }
58
+
59
+ export interface SetupResult {
60
+ runtimeVersion: string
61
+ serviceInstalled: boolean
62
+ repositoryPrepared: boolean
63
+ compatibilityShared: boolean
64
+ }
65
+
66
+ type SetupStage =
67
+ | 'decisions'
68
+ | 'runtime'
69
+ | 'repository'
70
+ | 'service'
71
+ | 'privacy'
72
+ | 'compatibility'
73
+
74
+ export async function runSetup(args: string[]): Promise<SetupResult | undefined> {
75
+ if (args.includes('--help') || args.includes('-h')) {
76
+ printHelp()
77
+ return
78
+ }
79
+
80
+ const options = parseSetupOptions(args)
81
+ let stage: SetupStage = 'decisions'
82
+ try {
83
+ const packageRoot = findPackageRoot(options.appDir)
84
+ const serviceStatus = getDaemonServiceStatus()
85
+ const privacy = readPrivacyPreferences()
86
+ const service = await decideService(options, serviceStatus)
87
+ const repository = await decideRepository(options, packageRoot)
88
+ const productAnalytics = await decidePrivacy(
89
+ options,
90
+ 'productAnalytics',
91
+ privacy.productAnalytics,
92
+ privacy.configured,
93
+ )
94
+ const crashReports = await decidePrivacy(
95
+ options,
96
+ 'crashReports',
97
+ privacy.crashReports,
98
+ privacy.configured,
99
+ )
100
+
101
+ const manifest = await sootsimRuntime.fetchManifest()
102
+ const resolvedRuntime = sootsimRuntime.resolveVersion(manifest, { channel: 'stable' })
103
+ const runtimeVersion = resolvedRuntime.version
104
+ const cliVersion = getCliVersion()
105
+ if (cliVersion === '0.0.0') {
106
+ throw new Error('could not resolve the installed rnxsim CLI version')
107
+ }
108
+
109
+ let repositoryPlan: RepositorySetupPlan | null = null
110
+ if (repository && packageRoot) {
111
+ repositoryPlan = planRepositorySetup({
112
+ appDir: packageRoot,
113
+ cliVersion,
114
+ })
115
+ }
116
+
117
+ printIntro(options)
118
+ printMachineSection(options, serviceStatus, service, runtimeVersion)
119
+ printRepositorySection(options, packageRoot, repositoryPlan)
120
+ printPrivacySection(options, productAnalytics, crashReports)
121
+
122
+ stage = 'runtime'
123
+ let installed = false
124
+ if (!options.dryRun) {
125
+ const activeRuntime = readActiveRuntime()
126
+ const result = await sootsimRuntime.install({
127
+ version: runtimeVersion,
128
+ channel: 'stable',
129
+ setActive: true,
130
+ protectVersions: activeRuntime ? [activeRuntime] : [],
131
+ })
132
+ installed = result.installed
133
+ }
134
+
135
+ stage = 'repository'
136
+ if (repositoryPlan) {
137
+ await applyRepositorySetup(repositoryPlan, {
138
+ dryRun: options.dryRun,
139
+ json: options.json,
140
+ })
141
+ }
142
+
143
+ stage = 'service'
144
+ let serviceInstalled = serviceStatus.installed
145
+ if (service && !serviceStatus.installed && !options.dryRun) {
146
+ await daemonInstall({ port: DEFAULT_SOOTSIM_BRIDGE_PORT, force: false })
147
+ serviceInstalled = true
148
+ }
149
+
150
+ stage = 'privacy'
151
+ if (!options.dryRun) {
152
+ writePrivacyPreferences({ productAnalytics, crashReports })
153
+ }
154
+
155
+ stage = 'compatibility'
156
+ const scan = packageRoot ? scanPackage(packageRoot) : null
157
+ const shareCompatibility = await decideCompatibilitySharing(options, scan)
158
+ if (shareCompatibility && scan && packageRoot && !options.dryRun) {
159
+ await shareCompatibilityScan(packageRoot, scan)
160
+ }
161
+ printCompatibilitySection(options, scan, shareCompatibility)
162
+
163
+ const result: SetupResult = {
164
+ runtimeVersion,
165
+ serviceInstalled,
166
+ repositoryPrepared: repositoryPlan !== null,
167
+ compatibilityShared: shareCompatibility && !options.dryRun,
168
+ }
169
+ const cache = runtimeCacheMetadata(runtimeVersion)
170
+ if (options.json) {
171
+ console.log(
172
+ JSON.stringify(
173
+ {
174
+ ...result,
175
+ runtimeInstalled: options.dryRun ? false : installed,
176
+ dryRun: options.dryRun,
177
+ cache,
178
+ repositoryOperations: repositoryPlan
179
+ ? formatRepositoryOperations(repositoryPlan)
180
+ : [],
181
+ },
182
+ null,
183
+ 2,
184
+ ),
185
+ )
186
+ } else {
187
+ printReadySection(repositoryPlan)
188
+ }
189
+
190
+ const counts = scan ? countScanResults(scan) : null
191
+ trackCliEvent({
192
+ event: 'cli_setup_completed',
193
+ properties: {
194
+ service_installed: serviceInstalled,
195
+ repository_prepared: repositoryPlan !== null,
196
+ product_analytics: productAnalytics,
197
+ crash_reports: crashReports,
198
+ compat_supported: counts?.supported ?? 0,
199
+ compat_partial: counts?.partial ?? 0,
200
+ compat_unsupported: counts?.unsupported ?? 0,
201
+ compat_not_yet_verified: counts?.notYetVerified ?? 0,
202
+ from_welcome: options.fromWelcome,
203
+ ci: options.ci,
204
+ dry_run: options.dryRun,
205
+ },
206
+ })
207
+ return result
208
+ } catch (error) {
209
+ const message = boundedMessage(error)
210
+ trackCliEvent({
211
+ event: 'cli_setup_failed',
212
+ properties: { stage, message },
213
+ })
214
+ throw error
215
+ }
216
+ }
217
+
218
+ export function readMachineSetupStatus(): MachineSetupStatus {
219
+ const service = getDaemonServiceStatus()
220
+ const lock = readDaemonLockfile()
221
+ const activeRuntime = readActiveRuntime()
222
+ return {
223
+ daemonSupported: service.supported,
224
+ daemonInstalled: service.installed,
225
+ daemonRunning: Boolean(lock && isDaemonLockfileFresh(lock)),
226
+ runtimeInstalled: Boolean(activeRuntime && fs.existsSync(runtimeDir(activeRuntime))),
227
+ privacyConfigured: readPrivacyPreferences().configured,
228
+ }
229
+ }
230
+
231
+ export function shouldRunSetupForBareCommand(
232
+ status: MachineSetupStatus = readMachineSetupStatus(),
233
+ ): boolean {
234
+ return !status.runtimeInstalled || !status.privacyConfigured
235
+ }
236
+
237
+ function parseSetupOptions(args: string[]): SetupOptions {
238
+ const appIndex = args.indexOf('--app')
239
+ const appArg = appIndex >= 0 ? args[appIndex + 1] : undefined
240
+ if (appIndex >= 0 && (!appArg || appArg.startsWith('-'))) {
241
+ throw new Error('--app requires a directory')
242
+ }
243
+ const service = readBooleanFlag(args, '--service', '--no-service')
244
+ const repository = readBooleanFlag(args, '--repo', '--no-repo')
245
+ return {
246
+ appDir: path.resolve(appArg ?? process.cwd()),
247
+ ci: args.includes('--ci'),
248
+ dryRun: args.includes('--dry-run'),
249
+ fromWelcome: args.includes('--from-welcome'),
250
+ json: args.includes('--json'),
251
+ yes: args.includes('--yes') || args.includes('-y'),
252
+ service,
253
+ repository,
254
+ productAnalytics: readOnOffFlag(args, '--analytics'),
255
+ crashReports: readOnOffFlag(args, '--crash-reports'),
256
+ shareCompatibility: args.includes('--share-compat'),
257
+ }
258
+ }
259
+
260
+ function readBooleanFlag(
261
+ args: string[],
262
+ positive: string,
263
+ negative: string,
264
+ ): boolean | undefined {
265
+ if (args.includes(positive) && args.includes(negative)) {
266
+ throw new Error(`${positive} and ${negative} cannot be used together`)
267
+ }
268
+ if (args.includes(positive)) return true
269
+ if (args.includes(negative)) return false
270
+ return undefined
271
+ }
272
+
273
+ function readOnOffFlag(args: string[], name: string): boolean | undefined {
274
+ const equals = args.find((arg) => arg.startsWith(`${name}=`))
275
+ const index = args.indexOf(name)
276
+ const raw = equals?.slice(name.length + 1) ?? (index >= 0 ? args[index + 1] : undefined)
277
+ if (raw === undefined) return undefined
278
+ if (raw === 'on' || raw === 'yes' || raw === 'true') return true
279
+ if (raw === 'off' || raw === 'no' || raw === 'false') return false
280
+ throw new Error(`${name} must be on or off`)
281
+ }
282
+
283
+ async function decideService(
284
+ options: SetupOptions,
285
+ status: ReturnType<typeof getDaemonServiceStatus>,
286
+ ): Promise<boolean> {
287
+ if (options.ci) {
288
+ if (options.service === true) throw new Error('--ci cannot install a machine service')
289
+ return false
290
+ }
291
+ if (!status.supported) return false
292
+ if (status.installed && options.service === undefined) return true
293
+ if (options.service !== undefined) return options.service
294
+ if (options.yes) return true
295
+ requireInteractive(options, '--service or --no-service')
296
+ return confirm('Install the background service and shared managed runtime?', true)
297
+ }
298
+
299
+ async function decideRepository(
300
+ options: SetupOptions,
301
+ packageRoot: string | null,
302
+ ): Promise<boolean> {
303
+ if (!packageRoot) {
304
+ if (options.repository === true) throw new Error('--repo requires a package.json')
305
+ return false
306
+ }
307
+ if (options.repository !== undefined) return options.repository
308
+ if (options.yes) return true
309
+ requireInteractive(options, '--repo or --no-repo')
310
+ return confirm(`Prepare ${packageRoot} for reproducible rnx runs?`, true)
311
+ }
312
+
313
+ async function decidePrivacy(
314
+ options: SetupOptions,
315
+ key: 'productAnalytics' | 'crashReports',
316
+ current: boolean,
317
+ configured: boolean,
318
+ ): Promise<boolean> {
319
+ const explicit =
320
+ key === 'productAnalytics' ? options.productAnalytics : options.crashReports
321
+ if (explicit !== undefined) return explicit
322
+ if (configured) return current
323
+ if (options.yes) return true
324
+ const flag =
325
+ key === 'productAnalytics' ? '--analytics on|off' : '--crash-reports on|off'
326
+ requireInteractive(options, flag)
327
+ const question =
328
+ key === 'productAnalytics'
329
+ ? 'Share bounded product analytics?'
330
+ : 'Send bounded crash reports?'
331
+ return confirm(question, true)
332
+ }
333
+
334
+ async function decideCompatibilitySharing(
335
+ options: SetupOptions,
336
+ scan: ScanResult | null,
337
+ ): Promise<boolean> {
338
+ if (!scan) return false
339
+ if (options.shareCompatibility) return true
340
+ if (options.yes || !process.stdin.isTTY) return false
341
+ return confirm(
342
+ 'Share dependency names, requested versions, framework, and this compatibility result?',
343
+ false,
344
+ )
345
+ }
346
+
347
+ function requireInteractive(options: SetupOptions, flags: string): void {
348
+ if (process.stdin.isTTY && !options.ci) return
349
+ throw new Error(`non-interactive setup requires ${flags}, or --yes to accept defaults`)
350
+ }
351
+
352
+ function scanPackage(packageRoot: string): ScanResult {
353
+ const parsed: unknown = JSON.parse(
354
+ fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
355
+ )
356
+ if (!parsed || typeof parsed !== 'object') {
357
+ throw new Error('package.json must contain an object')
358
+ }
359
+ return scanDeps(parsed)
360
+ }
361
+
362
+ async function shareCompatibilityScan(
363
+ packageRoot: string,
364
+ scan: ScanResult,
365
+ ): Promise<void> {
366
+ const parsed: unknown = JSON.parse(
367
+ fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
368
+ )
369
+ if (!parsed || typeof parsed !== 'object')
370
+ throw new Error('package.json must be an object')
371
+ const response = await fetch('https://contrast.dev/api/scan', {
372
+ method: 'POST',
373
+ headers: { 'content-type': 'application/json' },
374
+ body: JSON.stringify(buildCompatibilitySharePayload(parsed, scan)),
375
+ signal: AbortSignal.timeout(10_000),
376
+ })
377
+ if (!response.ok) {
378
+ throw new Error(`compatibility sharing failed with HTTP ${response.status}`)
379
+ }
380
+ }
381
+
382
+ export function buildCompatibilitySharePayload(manifest: object, scan: ScanResult) {
383
+ return {
384
+ dependencies: boundedDependencies(Reflect.get(manifest, 'dependencies')),
385
+ devDependencies: boundedDependencies(Reflect.get(manifest, 'devDependencies')),
386
+ framework: scan.framework,
387
+ result: {
388
+ framework: scan.framework,
389
+ rnVersion: scan.rnVersion,
390
+ packages: scan.packages.slice(0, 200),
391
+ },
392
+ source: 'desktop',
393
+ shared: true,
394
+ }
395
+ }
396
+
397
+ function boundedDependencies(value: unknown): Record<string, string> {
398
+ if (!value || typeof value !== 'object') return {}
399
+ const output: Record<string, string> = {}
400
+ for (const [name, version] of Object.entries(value).slice(0, 200)) {
401
+ if (typeof version !== 'string') continue
402
+ output[name.slice(0, 160)] = version.slice(0, 80)
403
+ }
404
+ return output
405
+ }
406
+
407
+ function runtimeCacheMetadata(runtimeVersion: string) {
408
+ const platform = os.platform()
409
+ const arch = os.arch()
410
+ return {
411
+ path: runtimeDir(runtimeVersion),
412
+ key: `sootsim-runtime-${platform}-${arch}-${runtimeVersion}`,
413
+ inputs: { platform, arch, runtimeVersion },
414
+ }
415
+ }
416
+
417
+ function printIntro(options: SetupOptions): void {
418
+ if (options.json) return
419
+ console.log(`\n ${options.fromWelcome ? 'welcome to rnx' : 'rnxsim setup'}`)
420
+ }
421
+
422
+ function printMachineSection(
423
+ options: SetupOptions,
424
+ status: ReturnType<typeof getDaemonServiceStatus>,
425
+ service: boolean,
426
+ runtimeVersion: string,
427
+ ): void {
428
+ if (options.json) return
429
+ console.log(`\n 1. machine`)
430
+ console.log(` stable runtime: ${runtimeVersion}`)
431
+ console.log(
432
+ ` background service: ${status.supported ? (service ? 'install' : 'skip') : 'unsupported on this platform'}`,
433
+ )
434
+ }
435
+
436
+ function printRepositorySection(
437
+ options: SetupOptions,
438
+ packageRoot: string | null,
439
+ plan: RepositorySetupPlan | null,
440
+ ): void {
441
+ if (options.json) return
442
+ console.log(`\n 2. repository`)
443
+ if (!packageRoot) {
444
+ console.log(` no package.json found; repository preparation skipped`)
445
+ return
446
+ }
447
+ if (!plan) {
448
+ console.log(` skipped for ${packageRoot}`)
449
+ return
450
+ }
451
+ console.log(` package manager: ${detectPreferredPackageManager(packageRoot)}`)
452
+ for (const operation of formatRepositoryOperations(plan)) {
453
+ console.log(` ${options.dryRun ? 'would run' : 'run'}: ${operation}`)
454
+ }
455
+ }
456
+
457
+ function printPrivacySection(
458
+ options: SetupOptions,
459
+ productAnalytics: boolean,
460
+ crashReports: boolean,
461
+ ): void {
462
+ if (options.json) return
463
+ console.log(`\n 3. privacy`)
464
+ console.log(` product analytics: ${productAnalytics ? 'on' : 'off'}`)
465
+ console.log(
466
+ ` command, feature, version, platform, and bounded performance events`,
467
+ )
468
+ console.log(` crash reports: ${crashReports ? 'on' : 'off'}`)
469
+ console.log(
470
+ ` error type, message, stack, runtime version, platform, and bounded dependency summary`,
471
+ )
472
+ console.log(
473
+ ` source files, environment values, terminal output, app data, screenshots, and recordings are not included`,
474
+ )
475
+ }
476
+
477
+ function printCompatibilitySection(
478
+ options: SetupOptions,
479
+ scan: ScanResult | null,
480
+ shared: boolean,
481
+ ): void {
482
+ if (options.json) return
483
+ console.log(`\n 4. compatibility`)
484
+ if (!scan) {
485
+ console.log(` no package.json found; run \`rnxsim compat\` inside an app later`)
486
+ return
487
+ }
488
+ console.log(` ${formatScanCounts(scan)}`)
489
+ for (const line of formatDetailedScanLines(scan)) console.log(` ${line}`)
490
+ console.log(` ${COMPAT_RESULT_CAVEAT}`)
491
+ console.log(` dependency sharing: ${shared ? 'yes' : 'no'}`)
492
+ }
493
+
494
+ function printReadySection(repository: RepositorySetupPlan | null): void {
495
+ console.log(`\n 5. ready`)
496
+ if (repository) {
497
+ const command =
498
+ repository.packageManager === 'bun'
499
+ ? 'bun run sootsim'
500
+ : `${repository.packageManager} run rnxsim`
501
+ console.log(` start your app normally, then ${command} -- <port>`)
502
+ } else {
503
+ console.log(` start your app normally, then rnxsim open <port>`)
504
+ }
505
+ console.log(
506
+ ` useful next commands: rnxsim describe; rnxsim get errors; rnxsim compat`,
507
+ )
508
+ console.log(
509
+ ` install agent skills with \`rnxsim skill install\`, then start a new session`,
510
+ )
511
+ console.log(
512
+ ` if a concrete rnx seam is missing or broken, preview \`rnxsim report-issue\` and confirm separately`,
513
+ )
514
+ }
515
+
516
+ function boundedMessage(error: unknown): string {
517
+ const message = error instanceof Error ? error.message : String(error)
518
+ return message.replace(/(?:\/?[\w.-]+)+/g, '<path>').slice(0, 240)
519
+ }
520
+
521
+ function printHelp(): void {
522
+ console.log(`
523
+ rnxsim setup — configure a machine and optionally prepare the current repository
524
+
525
+ usage:
526
+ rnxsim setup
527
+ rnxsim setup --yes
528
+ rnxsim setup --ci --yes --json
529
+ rnxsim setup --dry-run --yes
530
+
531
+ decisions:
532
+ --service | --no-service
533
+ --repo | --no-repo
534
+ --analytics on|off
535
+ --crash-reports on|off
536
+ --share-compat
537
+
538
+ automation:
539
+ --yes accept defaults; compatibility sharing still defaults off
540
+ --ci never prompt or install a background service
541
+ --json emit runtime/cache metadata as JSON
542
+ --dry-run print exact repository operations without changing the machine
543
+ --app DIR use DIR as the repository search start
544
+ `)
545
+ }
@@ -0,0 +1,81 @@
1
+ import { callInBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
2
+
3
+ export type ShellBooleanModeAction = 'on' | 'off' | 'toggle'
4
+
5
+ export interface ShellBooleanModeOptions {
6
+ port?: number
7
+ verbose?: boolean
8
+ }
9
+
10
+ export interface ShellBooleanModeConfig {
11
+ modeKey: string
12
+ displayName: string
13
+ actionId: string
14
+ }
15
+
16
+ export interface ShellBooleanModeResult {
17
+ current: boolean
18
+ target: boolean
19
+ changed: boolean
20
+ }
21
+
22
+ export function parseShellBooleanModeAction(args: string[]): ShellBooleanModeAction {
23
+ const action = args[0]?.toLowerCase() ?? 'toggle'
24
+ if (action !== 'on' && action !== 'off' && action !== 'toggle') {
25
+ console.error(` unknown argument: "${action}" (expected on | off | toggle)`)
26
+ process.exit(1)
27
+ }
28
+ return action
29
+ }
30
+
31
+ export async function runShellBooleanMode(
32
+ args: string[],
33
+ opts: ShellBooleanModeOptions,
34
+ config: ShellBooleanModeConfig,
35
+ ): Promise<ShellBooleanModeResult> {
36
+ const parsed = parseBridgeCliArgs(args, { port: opts.port })
37
+ const action = parseShellBooleanModeAction(parsed.positional)
38
+ const bridge = createBridgeFromParsed({ ...parsed, commandTimeoutMs: 5000 })
39
+ try {
40
+ const settings = await callInBridge<Record<string, unknown>>(
41
+ bridge,
42
+ 'SootSim.bridges.settings.get',
43
+ )
44
+ const current = Boolean(settings?.[config.modeKey])
45
+ const target = action === 'on' ? true : action === 'off' ? false : !current
46
+ if (current === target) {
47
+ console.log(` ${config.displayName}: already ${target ? 'on' : 'off'}`)
48
+ return { current, target, changed: false }
49
+ }
50
+ const changed = await bridge.send({
51
+ type: 'evaluate',
52
+ acquireLock: true,
53
+ code: `(async () => {
54
+ const modeKey = ${JSON.stringify(config.modeKey)}
55
+ const target = ${JSON.stringify(target)}
56
+ window.dispatchEvent(new CustomEvent('sootsim:shell-command', {
57
+ detail: { type: 'fire-action', id: ${JSON.stringify(config.actionId)} },
58
+ }))
59
+ const deadline = Date.now() + 1200
60
+ while (Date.now() < deadline) {
61
+ if (Boolean(window.SootSim?.bridges?.settings?.get?.()?.[modeKey]) === target) {
62
+ return true
63
+ }
64
+ await new Promise((resolve) => setTimeout(resolve, 40))
65
+ }
66
+ return false
67
+ })()`,
68
+ })
69
+ if (!changed) {
70
+ throw new Error(
71
+ `${config.displayName} did not change to ${target ? 'on' : 'off'}; the live shell may not support this mode`,
72
+ )
73
+ }
74
+ console.log(
75
+ ` ${config.displayName}: ${current ? 'on' : 'off'} -> ${target ? 'on' : 'off'}`,
76
+ )
77
+ return { current, target, changed: true }
78
+ } finally {
79
+ bridge.close()
80
+ }
81
+ }