rnxsim 0.1.368 → 0.1.370

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 (256) hide show
  1. package/cli/auth.ts +2 -1
  2. package/cli/bin.ts +283 -273
  3. package/cli/commands/app-fonts.ts +3 -2
  4. package/cli/commands/assert.ts +8 -7
  5. package/cli/commands/auth.ts +2 -1
  6. package/cli/commands/box/checkout-plane.ts +49 -16
  7. package/cli/commands/compat.ts +93 -4
  8. package/cli/commands/config.ts +2 -1
  9. package/cli/commands/control.ts +37 -33
  10. package/cli/commands/daemon.ts +22 -21
  11. package/cli/commands/debug.ts +17 -15
  12. package/cli/commands/detect.ts +11 -7
  13. package/cli/commands/detox.ts +5 -4
  14. package/cli/commands/device.ts +6 -5
  15. package/cli/commands/electron.ts +6 -5
  16. package/cli/commands/flow.ts +12 -11
  17. package/cli/commands/inspect/find.ts +2 -1
  18. package/cli/commands/inspect/keyboard.ts +2 -1
  19. package/cli/commands/inspect/sleep.ts +2 -1
  20. package/cli/commands/inspect/wait-event.ts +4 -3
  21. package/cli/commands/inspect/wait-idle.ts +2 -1
  22. package/cli/commands/inspect/wait-ready.ts +3 -2
  23. package/cli/commands/inspect/wait-selector.ts +4 -3
  24. package/cli/commands/inspect/wait.ts +2 -1
  25. package/cli/commands/inspect.ts +82 -80
  26. package/cli/commands/install-desktop.ts +5 -4
  27. package/cli/commands/login.ts +3 -2
  28. package/cli/commands/mode.ts +2 -1
  29. package/cli/commands/record.ts +38 -37
  30. package/cli/commands/runtime.ts +9 -8
  31. package/cli/commands/screenshot-layers.ts +4 -3
  32. package/cli/commands/screenshot-mode.ts +2 -1
  33. package/cli/commands/screenshot.ts +8 -7
  34. package/cli/commands/screenshots-capture.ts +2 -1
  35. package/cli/commands/serve.ts +5 -4
  36. package/cli/commands/shell-boolean-mode.ts +2 -1
  37. package/cli/commands/skills.ts +11 -10
  38. package/cli/commands/telemetry.ts +2 -1
  39. package/cli/commands/three-mode.ts +2 -1
  40. package/cli/commands/timeline.ts +4 -3
  41. package/cli/commands/upload.ts +14 -13
  42. package/cli/commands/what-happened.ts +2 -1
  43. package/cli/recording-access.ts +6 -5
  44. package/cli/run-rnx.ts +140 -0
  45. package/dist-cli/bin.js +6 -6
  46. package/dist-cli/chunks/{agent-GXCQMYV4.js → agent-3R4424LW.js} +2 -2
  47. package/dist-cli/chunks/{agent-wrapper-Y3PQAL6I.js → agent-wrapper-4PPWZWSY.js} +2 -2
  48. package/dist-cli/chunks/app-fonts-KYXB6CXQ.js +4 -0
  49. package/dist-cli/chunks/{assert-BSRQBRH7.js → assert-7EZOWGYQ.js} +11 -11
  50. package/dist-cli/chunks/auth-L7M36H6C.js +12 -0
  51. package/dist-cli/chunks/{beta-R4IZ5SWO.js → beta-FKAF6YWJ.js} +2 -2
  52. package/dist-cli/chunks/{box-2NQYYY3B.js → box-5Y5VBMHV.js} +62 -62
  53. package/dist-cli/chunks/{camera-ER66WWAX.js → camera-XHF2RPFG.js} +2 -2
  54. package/dist-cli/chunks/{chunk-UBH2BWCY.js → chunk-2FOGXVOK.js} +2 -2
  55. package/dist-cli/chunks/{chunk-7B22IPSC.js → chunk-3BG6UCQY.js} +2 -2
  56. package/dist-cli/chunks/{chunk-IXRVFQMT.js → chunk-3SOPYG7S.js} +2 -2
  57. package/dist-cli/chunks/{chunk-7V3S2DY2.js → chunk-3UXXYJVD.js} +1 -1
  58. package/dist-cli/chunks/{chunk-3MPFC3DS.js → chunk-5BR33NAZ.js} +1 -1
  59. package/dist-cli/chunks/{chunk-BWJOLJOK.js → chunk-5RKRVS5A.js} +2 -2
  60. package/dist-cli/chunks/{chunk-WVVAYLWZ.js → chunk-64JAEJ6N.js} +1 -1
  61. package/dist-cli/chunks/{chunk-GXHCJRKE.js → chunk-6A6L3VJR.js} +2 -2
  62. package/dist-cli/chunks/chunk-6GPS7U4X.js +74 -0
  63. package/dist-cli/chunks/{chunk-JHYXRORU.js → chunk-6S5LJV2O.js} +2 -2
  64. package/dist-cli/chunks/{chunk-TOE5O6JE.js → chunk-6W4HIWC7.js} +2 -2
  65. package/dist-cli/chunks/{chunk-ESVUVW3R.js → chunk-72S5FCBY.js} +2 -2
  66. package/dist-cli/chunks/{chunk-TC6DNQL6.js → chunk-7C7TJYZ3.js} +2 -2
  67. package/dist-cli/chunks/{chunk-M7COA4BE.js → chunk-AALKIAUZ.js} +1 -1
  68. package/dist-cli/chunks/{chunk-CKNNO6ZG.js → chunk-ARMXC3C3.js} +25 -25
  69. package/dist-cli/chunks/chunk-AVJBT5LF.js +4 -0
  70. package/dist-cli/chunks/chunk-BMIJZNKD.js +28 -0
  71. package/dist-cli/chunks/{chunk-FSPZY4AI.js → chunk-C7BA5CCM.js} +2 -2
  72. package/dist-cli/chunks/{chunk-EHA65UVJ.js → chunk-CMVRTZ5G.js} +2 -2
  73. package/dist-cli/chunks/chunk-D24EOJ4C.js +24 -0
  74. package/dist-cli/chunks/{chunk-3XMEIZEV.js → chunk-D2GZASRV.js} +1 -1
  75. package/dist-cli/chunks/{chunk-3S2J6IVC.js → chunk-DHYTRCIP.js} +2 -2
  76. package/dist-cli/chunks/{chunk-QMVBWZH2.js → chunk-DMHSD6YJ.js} +2 -2
  77. package/dist-cli/chunks/{chunk-NGWUGNPV.js → chunk-DUXHYPBP.js} +2 -2
  78. package/dist-cli/chunks/{chunk-4FLQYRGN.js → chunk-DXV37CJN.js} +1 -1
  79. package/dist-cli/chunks/{chunk-T2MGLXY5.js → chunk-EOIBLKZO.js} +2 -2
  80. package/dist-cli/chunks/{chunk-PNBQBBG5.js → chunk-EQ3OE2AV.js} +1 -1
  81. package/dist-cli/chunks/{chunk-WFAFAGMG.js → chunk-EWSWOWXK.js} +2 -2
  82. package/dist-cli/chunks/{chunk-HKQXGCQT.js → chunk-FA75F34Z.js} +1 -1
  83. package/dist-cli/chunks/{chunk-NERY6HGZ.js → chunk-FK4JSTZ3.js} +2 -2
  84. package/dist-cli/chunks/{chunk-NPSPWMBO.js → chunk-GJRLPJQL.js} +2 -2
  85. package/dist-cli/chunks/{chunk-TPIPKXJL.js → chunk-GRO74J2X.js} +1 -1
  86. package/dist-cli/chunks/chunk-H5X5FJ63.js +99 -0
  87. package/dist-cli/chunks/chunk-HEKHLQ3B.js +497 -0
  88. package/dist-cli/chunks/chunk-HQQTS2CB.js +30 -0
  89. package/dist-cli/chunks/{chunk-Q65KH25G.js → chunk-I52NT6VG.js} +1 -1
  90. package/dist-cli/chunks/{chunk-AUPJX4KI.js → chunk-IDLFVRPN.js} +1 -1
  91. package/dist-cli/chunks/{chunk-LAKWOJ5Y.js → chunk-JZLDHPB7.js} +2 -2
  92. package/dist-cli/chunks/{chunk-WJQB6AXZ.js → chunk-LIMWG54N.js} +1 -1
  93. package/dist-cli/chunks/{chunk-TE645QCO.js → chunk-LUOHRBJG.js} +1 -1
  94. package/dist-cli/chunks/{chunk-DJSPNOF6.js → chunk-LXPHL6FO.js} +2 -2
  95. package/dist-cli/chunks/{chunk-ECXDCED5.js → chunk-MDCY532E.js} +2 -2
  96. package/dist-cli/chunks/{chunk-4VA2ISWX.js → chunk-NJMU5BN6.js} +1 -1
  97. package/dist-cli/chunks/{chunk-RRALQ4WM.js → chunk-NR2V2ONN.js} +2 -2
  98. package/dist-cli/chunks/{chunk-SHMLYTNH.js → chunk-NTC46LSA.js} +2 -2
  99. package/dist-cli/chunks/{chunk-X5MXQB3L.js → chunk-O6QLKSAM.js} +10 -10
  100. package/dist-cli/chunks/{chunk-LPAOOJIW.js → chunk-OJZHECGH.js} +1 -1
  101. package/dist-cli/chunks/chunk-OTFTMGAL.js +7 -0
  102. package/dist-cli/chunks/{chunk-QKOY7UW5.js → chunk-PAUEZO6F.js} +2 -2
  103. package/dist-cli/chunks/{chunk-WXRDFUR7.js → chunk-PIZXOXBL.js} +2 -2
  104. package/dist-cli/chunks/{chunk-WF2CRNYF.js → chunk-PNOENVMJ.js} +1 -1
  105. package/dist-cli/chunks/{chunk-FDAFSRQE.js → chunk-Q4MRJ6PO.js} +2 -2
  106. package/dist-cli/chunks/{chunk-SSUPPM6K.js → chunk-RRX52O37.js} +1 -1
  107. package/dist-cli/chunks/{chunk-E6XYIIJK.js → chunk-U63T6LIQ.js} +1 -1
  108. package/dist-cli/chunks/{chunk-OZJMWTGA.js → chunk-UFVAAWGZ.js} +1 -1
  109. package/dist-cli/chunks/{chunk-GS5VUDCF.js → chunk-VVQCZ42C.js} +1 -1
  110. package/dist-cli/chunks/{chunk-MCO7V4VN.js → chunk-WFQHT4QD.js} +2 -2
  111. package/dist-cli/chunks/{chunk-JFGW75UL.js → chunk-WPV4H5S4.js} +2 -2
  112. package/dist-cli/chunks/{chunk-OXCDE3DD.js → chunk-X6WQ4YWE.js} +1 -1
  113. package/dist-cli/chunks/{chunk-FVODUDPS.js → chunk-YIZGNT7A.js} +1 -1
  114. package/dist-cli/chunks/{chunk-MGOAQHMO.js → chunk-Z2VBSNFI.js} +2 -2
  115. package/dist-cli/chunks/{chunk-GFWUIGGY.js → chunk-Z3DENGXW.js} +2 -2
  116. package/dist-cli/chunks/{cleanup-WHGLBAJ2.js → cleanup-MXMMJ7JW.js} +2 -2
  117. package/dist-cli/chunks/cli-version-MLS55UTY.js +4 -0
  118. package/dist-cli/chunks/compat-E6KE5KDI.js +23 -0
  119. package/dist-cli/chunks/config-QSLLVZDS.js +13 -0
  120. package/dist-cli/chunks/{connect-N4FV3DDV.js → connect-QE4VU6GB.js} +2 -2
  121. package/dist-cli/chunks/control-XD5F6K5T.js +4 -0
  122. package/dist-cli/chunks/daemon-UN5SE2JO.js +4 -0
  123. package/dist-cli/chunks/{debug-AHEK43AJ.js → debug-5FG3MBJS.js} +20 -20
  124. package/dist-cli/chunks/desktop-5EZX7NX5.js +31 -0
  125. package/dist-cli/chunks/detox-WJGQP5TM.js +52 -0
  126. package/dist-cli/chunks/device-D7LKCAMS.js +18 -0
  127. package/dist-cli/chunks/{diagnose-WDP3CVIX.js → diagnose-A3W6ZTGA.js} +2 -2
  128. package/dist-cli/chunks/{disk-cleanup-JRT5MKFW.js → disk-cleanup-BDRHX5ZG.js} +2 -2
  129. package/dist-cli/chunks/{do-chain-7FDMO56C.js → do-chain-RUJNRPPF.js} +2 -2
  130. package/dist-cli/chunks/drivers-3NJ5RL6X.js +4 -0
  131. package/dist-cli/chunks/{env-YIBOMB24.js → env-U67SQVTV.js} +2 -2
  132. package/dist-cli/chunks/{film-R3EQADMG.js → film-XC6UAQ3V.js} +3 -3
  133. package/dist-cli/chunks/flow-FHZZD3P6.js +4 -0
  134. package/dist-cli/chunks/help-BYYDUSXF.js +4 -0
  135. package/dist-cli/chunks/{hidden-runtime-alias-6M4UERRQ.js → hidden-runtime-alias-7S2TNZXG.js} +2 -2
  136. package/dist-cli/chunks/{home-paths-QJNOHZJO.js → home-paths-LMO5LB4F.js} +2 -2
  137. package/dist-cli/chunks/inspect-RQCTWDCC.js +4 -0
  138. package/dist-cli/chunks/install-desktop-GOWXCQUE.js +4 -0
  139. package/dist-cli/chunks/login-JIU42S4C.js +26 -0
  140. package/dist-cli/chunks/{logout-VNJX2IEW.js → logout-JTAWQXZO.js} +2 -2
  141. package/dist-cli/chunks/{maestro-SQS2OS2D.js → maestro-TYBQYOGB.js} +3 -3
  142. package/dist-cli/chunks/{maestro-generate-GWVPISG5.js → maestro-generate-YLAGWVKE.js} +3 -3
  143. package/dist-cli/chunks/mode-DV24ZRZ6.js +26 -0
  144. package/dist-cli/chunks/{optional-demo-registry-L3LRBQHG.js → optional-demo-registry-JZH66VIM.js} +2 -2
  145. package/dist-cli/chunks/{perf-XLPC4UKR.js → perf-LXXJ4EAX.js} +2 -2
  146. package/dist-cli/chunks/{permissions-QRHWVMDP.js → permissions-KAOVZUPW.js} +2 -2
  147. package/dist-cli/chunks/{platform-F47URZNB.js → platform-KW35446W.js} +3 -3
  148. package/dist-cli/chunks/privacy-MIFE72CG.js +4 -0
  149. package/dist-cli/chunks/record-EK3ETFHZ.js +72 -0
  150. package/dist-cli/chunks/report-issue-NW5PCAZF.js +29 -0
  151. package/dist-cli/chunks/reset-RZ4O5AFJ.js +4 -0
  152. package/dist-cli/chunks/resolve-target-7R5BNYMM.js +4 -0
  153. package/dist-cli/chunks/runtime-MZHLSRS6.js +4 -0
  154. package/dist-cli/chunks/{screenshot-command-RK7IJHVK.js → screenshot-command-TQSPTFT2.js} +11 -11
  155. package/dist-cli/chunks/screenshot-layers-IZP3L3AQ.js +20 -0
  156. package/dist-cli/chunks/screenshots-capture-K7LJOVAE.js +42 -0
  157. package/dist-cli/chunks/{serve-UBXNGLNP.js → serve-MMX4WXXG.js} +18 -18
  158. package/dist-cli/chunks/setup-YFP3KEQZ.js +4 -0
  159. package/dist-cli/chunks/{sim-client-VTKFEDJX.js → sim-client-KLAYIFOC.js} +2 -2
  160. package/dist-cli/chunks/skills-N4D3POIS.js +50 -0
  161. package/dist-cli/chunks/{state-273XJPUE.js → state-ES6TFQZF.js} +2 -2
  162. package/dist-cli/chunks/{storage-RTDFWIY7.js → storage-52DR5V2C.js} +2 -2
  163. package/dist-cli/chunks/store-HOL45WCI.js +4 -0
  164. package/dist-cli/chunks/telemetry-BV6OTYPF.js +4 -0
  165. package/dist-cli/chunks/timeline-NRVNB5JR.js +24 -0
  166. package/dist-cli/chunks/{upgrade-R74NVHKG.js → upgrade-LNED5YQ2.js} +2 -2
  167. package/dist-cli/chunks/upload-RXKHFIBU.js +4 -0
  168. package/dist-cli/chunks/{version-RTFCYQZ7.js → version-VEF2DYGG.js} +2 -2
  169. package/dist-cli/chunks/{web-35SSKBRU.js → web-CGDE6S73.js} +2 -2
  170. package/dist-cli/chunks/welcome-FT2AMUWW.js +5 -0
  171. package/dist-cli/chunks/what-happened-FSIDWL32.js +25 -0
  172. package/dist-cli/chunks/{ws-bridge-JXQUAWFA.js → ws-bridge-QXFQLRE7.js} +2 -2
  173. package/dist-lib/agent-daemon-client.cjs +1 -1
  174. package/dist-lib/agent-events.cjs +1 -1
  175. package/dist-lib/agent-identity.cjs +1 -1
  176. package/dist-lib/agent-sessions.cjs +1 -1
  177. package/dist-lib/attached-projects.cjs +1 -1
  178. package/dist-lib/auth/shared-session.cjs +1 -1
  179. package/dist-lib/backend-origin.cjs +1 -1
  180. package/dist-lib/beta.cjs +1 -1
  181. package/dist-lib/beta.mjs +1 -1
  182. package/dist-lib/bridge-constants.cjs +1 -1
  183. package/dist-lib/bridge-contract-input.cjs +1 -1
  184. package/dist-lib/bridge-contract-input.mjs +1 -1
  185. package/dist-lib/bridge-contract.cjs +1 -1
  186. package/dist-lib/bridge-contract.mjs +1 -1
  187. package/dist-lib/cli-constants.cjs +1 -1
  188. package/dist-lib/config.cjs +1 -1
  189. package/dist-lib/detox/index.cjs +1 -1
  190. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  191. package/dist-lib/home-paths.cjs +1 -1
  192. package/dist-lib/host/bridge-host.cjs +1 -1
  193. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  194. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  195. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  196. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  197. package/dist-lib/host/websocket-proxy.cjs +1 -1
  198. package/dist-lib/index.cjs +1 -1
  199. package/dist-lib/jump-to-source-babel.cjs +1 -1
  200. package/dist-lib/menu.cjs +1 -1
  201. package/dist-lib/menu.mjs +1 -1
  202. package/dist-lib/metro-production-bundle.cjs +1 -1
  203. package/dist-lib/metro-production-bundle.mjs +1 -1
  204. package/dist-lib/metro.cjs +1 -1
  205. package/dist-lib/profiles.cjs +1 -1
  206. package/dist-lib/public-brand.cjs +1 -1
  207. package/dist-lib/react-native-host-modules.cjs +2 -1
  208. package/dist-lib/react-native-host-modules.mjs +2 -1
  209. package/dist-lib/render-mode.cjs +1 -1
  210. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  211. package/dist-lib/sdk.cjs +1 -1
  212. package/dist-lib/sdk.mjs +1 -1
  213. package/dist-lib/skills.cjs +560 -48
  214. package/dist-lib/vite.cjs +1 -1
  215. package/package.json +1 -1
  216. package/src/react-native-host-modules.ts +1 -0
  217. package/dist-cli/chunks/app-fonts-MDD3W4VN.js +0 -4
  218. package/dist-cli/chunks/auth-SLPHDPCF.js +0 -12
  219. package/dist-cli/chunks/chunk-2YK5J2D2.js +0 -24
  220. package/dist-cli/chunks/chunk-42TLK75A.js +0 -497
  221. package/dist-cli/chunks/chunk-57LITN73.js +0 -7
  222. package/dist-cli/chunks/chunk-T4ZZ26A2.js +0 -28
  223. package/dist-cli/chunks/chunk-UXROQPIN.js +0 -30
  224. package/dist-cli/chunks/chunk-YSHJ3LMQ.js +0 -74
  225. package/dist-cli/chunks/chunk-YYPTSF6W.js +0 -99
  226. package/dist-cli/chunks/cli-version-DMXIXBIM.js +0 -4
  227. package/dist-cli/chunks/compat-MGBKGYGQ.js +0 -20
  228. package/dist-cli/chunks/config-TRDOMP4T.js +0 -13
  229. package/dist-cli/chunks/control-5GRBZVYK.js +0 -4
  230. package/dist-cli/chunks/daemon-MBT5E3ZC.js +0 -4
  231. package/dist-cli/chunks/desktop-LDRIXOVV.js +0 -31
  232. package/dist-cli/chunks/detox-6HAKYISO.js +0 -52
  233. package/dist-cli/chunks/device-QM3S7OVU.js +0 -18
  234. package/dist-cli/chunks/drivers-AJL2EVXH.js +0 -4
  235. package/dist-cli/chunks/flow-BDAA6BWL.js +0 -4
  236. package/dist-cli/chunks/help-5EJD6LJF.js +0 -4
  237. package/dist-cli/chunks/inspect-S3LR3R2A.js +0 -4
  238. package/dist-cli/chunks/install-desktop-GXE6K7BJ.js +0 -4
  239. package/dist-cli/chunks/login-ISWDW4WU.js +0 -26
  240. package/dist-cli/chunks/mode-3URDGBZB.js +0 -26
  241. package/dist-cli/chunks/privacy-BF23T67T.js +0 -4
  242. package/dist-cli/chunks/record-2DN3OUE5.js +0 -72
  243. package/dist-cli/chunks/report-issue-D3BQPSLU.js +0 -29
  244. package/dist-cli/chunks/reset-T5CNZ7D3.js +0 -4
  245. package/dist-cli/chunks/resolve-target-KAAS274S.js +0 -4
  246. package/dist-cli/chunks/runtime-AQJDBR3X.js +0 -4
  247. package/dist-cli/chunks/screenshot-layers-DP2QKSMN.js +0 -20
  248. package/dist-cli/chunks/screenshots-capture-MA7P3FUT.js +0 -42
  249. package/dist-cli/chunks/setup-GH7OW4GC.js +0 -4
  250. package/dist-cli/chunks/skills-HPK25R4B.js +0 -50
  251. package/dist-cli/chunks/store-DLKNNM4L.js +0 -4
  252. package/dist-cli/chunks/telemetry-7CWDXEOO.js +0 -4
  253. package/dist-cli/chunks/timeline-IF2PGK7C.js +0 -24
  254. package/dist-cli/chunks/upload-3JFFVCZ4.js +0 -4
  255. package/dist-cli/chunks/welcome-N5V352SE.js +0 -5
  256. package/dist-cli/chunks/what-happened-WXTP6EPR.js +0 -25
@@ -37,6 +37,7 @@ import {
37
37
  } from '../../src/home-paths'
38
38
  import { rnxPublicBrand } from '../../src/public-brand'
39
39
  import { printCommandHelp } from '../help'
40
+ import { rnxExit } from '../run-rnx'
40
41
  import { ensureDaemonApp } from './daemon-mac-app'
41
42
 
42
43
  // minimum seconds between launchd / systemd respawns. without this, a daemon
@@ -82,7 +83,7 @@ export async function runDaemon(args: string[], opts: DaemonOptions = {}) {
82
83
  default:
83
84
  console.error(` unknown daemon subcommand: ${sub}`)
84
85
  printHelp()
85
- process.exit(1)
86
+ rnxExit(1)
86
87
  }
87
88
  }
88
89
 
@@ -468,7 +469,7 @@ export async function daemonInstall({ port, force }: { port: number; force: bool
468
469
 
469
470
  console.error(` background daemon is not supported on ${process.platform}`)
470
471
  console.error(` run 'rnx serve' in a persistent shell instead`)
471
- process.exit(1)
472
+ rnxExit(1)
472
473
  }
473
474
 
474
475
  // removed-path log (idempotent helpers track what they actually touched so the
@@ -649,7 +650,7 @@ async function daemonStatus() {
649
650
  return
650
651
  }
651
652
  console.error(` unsupported platform: ${process.platform}`)
652
- process.exit(1)
653
+ rnxExit(1)
653
654
  }
654
655
 
655
656
  async function daemonRestart() {
@@ -657,7 +658,7 @@ async function daemonRestart() {
657
658
  const path = macPlistPath()
658
659
  if (!existsSync(path)) {
659
660
  console.error(' daemon not registered. run `rnx daemon install`')
660
- process.exit(1)
661
+ rnxExit(1)
661
662
  }
662
663
  const res = spawnSync(
663
664
  'launchctl',
@@ -666,7 +667,7 @@ async function daemonRestart() {
666
667
  )
667
668
  if (res.status !== 0) {
668
669
  console.error(` kickstart failed: ${res.stderr?.trim()}`)
669
- process.exit(1)
670
+ rnxExit(1)
670
671
  }
671
672
  console.log(' restarted')
672
673
  return
@@ -675,7 +676,7 @@ async function daemonRestart() {
675
676
  const path = linuxUnitPath()
676
677
  if (!existsSync(path)) {
677
678
  console.error(' daemon not registered. run `rnx daemon install`')
678
- process.exit(1)
679
+ rnxExit(1)
679
680
  }
680
681
  const res = spawnSync('systemctl', ['--user', 'restart', SERVICE_NAME_LINUX], {
681
682
  stdio: 'pipe',
@@ -683,13 +684,13 @@ async function daemonRestart() {
683
684
  })
684
685
  if (res.status !== 0) {
685
686
  console.error(` restart failed: ${res.stderr?.trim()}`)
686
- process.exit(1)
687
+ rnxExit(1)
687
688
  }
688
689
  console.log(' restarted')
689
690
  return
690
691
  }
691
692
  console.error(` unsupported platform: ${process.platform}`)
692
- process.exit(1)
693
+ rnxExit(1)
693
694
  }
694
695
 
695
696
  async function daemonStart() {
@@ -697,7 +698,7 @@ async function daemonStart() {
697
698
  const path = macPlistPath()
698
699
  if (!existsSync(path)) {
699
700
  console.error(' daemon not registered. run `rnx daemon install`')
700
- process.exit(1)
701
+ rnxExit(1)
701
702
  }
702
703
  const res = spawnSync(
703
704
  'launchctl',
@@ -706,7 +707,7 @@ async function daemonStart() {
706
707
  )
707
708
  if (res.status !== 0) {
708
709
  console.error(` start failed: ${res.stderr?.trim()}`)
709
- process.exit(1)
710
+ rnxExit(1)
710
711
  }
711
712
  console.log(' started')
712
713
  return
@@ -715,7 +716,7 @@ async function daemonStart() {
715
716
  const path = linuxUnitPath()
716
717
  if (!existsSync(path)) {
717
718
  console.error(' daemon not registered. run `rnx daemon install`')
718
- process.exit(1)
719
+ rnxExit(1)
719
720
  }
720
721
  const res = spawnSync('systemctl', ['--user', 'start', SERVICE_NAME_LINUX], {
721
722
  stdio: 'pipe',
@@ -723,13 +724,13 @@ async function daemonStart() {
723
724
  })
724
725
  if (res.status !== 0) {
725
726
  console.error(` start failed: ${res.stderr?.trim()}`)
726
- process.exit(1)
727
+ rnxExit(1)
727
728
  }
728
729
  console.log(' started')
729
730
  return
730
731
  }
731
732
  console.error(` unsupported platform: ${process.platform}`)
732
- process.exit(1)
733
+ rnxExit(1)
733
734
  }
734
735
 
735
736
  async function daemonStop() {
@@ -737,7 +738,7 @@ async function daemonStop() {
737
738
  const path = macPlistPath()
738
739
  if (!existsSync(path)) {
739
740
  console.error(' daemon not registered — nothing to stop')
740
- process.exit(1)
741
+ rnxExit(1)
741
742
  }
742
743
  const res = spawnSync(
743
744
  'launchctl',
@@ -746,7 +747,7 @@ async function daemonStop() {
746
747
  )
747
748
  if (res.status !== 0) {
748
749
  console.error(` stop failed: ${res.stderr?.trim()}`)
749
- process.exit(1)
750
+ rnxExit(1)
750
751
  }
751
752
  console.log(' stopped')
752
753
  return
@@ -755,7 +756,7 @@ async function daemonStop() {
755
756
  const path = linuxUnitPath()
756
757
  if (!existsSync(path)) {
757
758
  console.error(' daemon not registered — nothing to stop')
758
- process.exit(1)
759
+ rnxExit(1)
759
760
  }
760
761
  const res = spawnSync('systemctl', ['--user', 'stop', SERVICE_NAME_LINUX], {
761
762
  stdio: 'pipe',
@@ -763,13 +764,13 @@ async function daemonStop() {
763
764
  })
764
765
  if (res.status !== 0) {
765
766
  console.error(` stop failed: ${res.stderr?.trim()}`)
766
- process.exit(1)
767
+ rnxExit(1)
767
768
  }
768
769
  console.log(' stopped')
769
770
  return
770
771
  }
771
772
  console.error(` unsupported platform: ${process.platform}`)
772
- process.exit(1)
773
+ rnxExit(1)
773
774
  }
774
775
 
775
776
  // tail the daemon's logs. macOS reads the launchd-redirected files directly
@@ -789,7 +790,7 @@ async function daemonLogs(rest: string[]) {
789
790
  const present = [out, err].filter((p) => existsSync(p))
790
791
  if (present.length === 0) {
791
792
  console.error(` no daemon logs yet at ${LOG_DIR}. run \`rnx daemon install\``)
792
- process.exit(1)
793
+ rnxExit(1)
793
794
  }
794
795
  const args = follow
795
796
  ? ['-n', String(lines), '-F', ...present]
@@ -829,11 +830,11 @@ async function daemonLogs(rest: string[]) {
829
830
  ` could not read --user journal for ${unit} (this user isn't in the systemd-journal group yet).\n` +
830
831
  ` run: sudo journalctl _SYSTEMD_USER_UNIT=${unit} -n ${lines} --no-pager`,
831
832
  )
832
- process.exit(1)
833
+ rnxExit(1)
833
834
  }
834
835
 
835
836
  console.error(` unsupported platform: ${process.platform}`)
836
- process.exit(1)
837
+ rnxExit(1)
837
838
  }
838
839
 
839
840
  function readPlistBinary(path: string): string | null {
@@ -20,6 +20,7 @@
20
20
 
21
21
  import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
22
22
  import { printBridgeFailureDiagnostics } from '../bridge-diagnostics'
23
+ import { rethrowIfExit, rnxExit } from '../run-rnx'
23
24
  import {
24
25
  createBridgeFromParsed,
25
26
  evalInBridge,
@@ -399,7 +400,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
399
400
 
400
401
  if (!subcommand || args.includes('--help') || args.includes('-h')) {
401
402
  printHelp()
402
- process.exit(0)
403
+ rnxExit(0)
403
404
  }
404
405
 
405
406
  const wsPort = parsed.wsPort
@@ -438,7 +439,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
438
439
  console.error(
439
440
  ` usage: rnx debug enable <channel[,channel,...]>\n known: ${KNOWN_CHANNELS.join(', ')}`,
440
441
  )
441
- process.exit(1)
442
+ rnxExit(1)
442
443
  }
443
444
  const active = await setDebugChannels(bridge, 'enable', channels)
444
445
  console.log(fmt({ active }, pretty))
@@ -456,7 +457,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
456
457
  const channel = rest[0]
457
458
  if (!channel) {
458
459
  console.error(' usage: rnx debug toggle <channel>')
459
- process.exit(1)
460
+ rnxExit(1)
460
461
  }
461
462
  const result = await call(
462
463
  bridge,
@@ -516,7 +517,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
516
517
  const b = rest[1]
517
518
  if (!a || !b) {
518
519
  console.error(' usage: rnx debug diff <labelA> <labelB>')
519
- process.exit(1)
520
+ rnxExit(1)
520
521
  }
521
522
  // Maps don't serialize — project added/removed/changed arrays only
522
523
  const code = `(() => {
@@ -557,7 +558,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
557
558
  ' zero draws means either nothing on screen is an image, or the audit\n' +
558
559
  ' is not attached to the surface that paints.',
559
560
  )
560
- process.exit(2)
561
+ rnxExit(2)
561
562
  }
562
563
  const under = report.rows.filter(
563
564
  (row) => row.shortfall !== null && row.shortfall < minimum,
@@ -567,7 +568,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
567
568
  } else {
568
569
  printImageAudit(report, args.includes('--all') ? report.rows : under, minimum)
569
570
  }
570
- if (under.length > 0) process.exit(1)
571
+ if (under.length > 0) rnxExit(1)
571
572
  break
572
573
  }
573
574
 
@@ -578,7 +579,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
578
579
  console.log(fmt(result, pretty))
579
580
  } else {
580
581
  console.error(' usage: rnx debug find <sheets|portals|boundaries>')
581
- process.exit(1)
582
+ rnxExit(1)
582
583
  }
583
584
  break
584
585
  }
@@ -596,7 +597,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
596
597
  console.error(
597
598
  ' usage: rnx debug trace anim <on|off|status|clear|<id>> [id|limit]',
598
599
  )
599
- process.exit(1)
600
+ rnxExit(1)
600
601
  }
601
602
  if (sub === 'on') {
602
603
  const raw = rest[2] ?? 'all'
@@ -604,7 +605,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
604
605
  const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
605
606
  if (target !== 'all' && !Number.isFinite(target)) {
606
607
  console.error(` invalid target: ${raw}`)
607
- process.exit(1)
608
+ rnxExit(1)
608
609
  }
609
610
  await callTestBridge(bridge, 'enableAnimationTrace', target, limit)
610
611
  const listed = await callTestBridge(bridge, 'listAnimationTraces')
@@ -616,7 +617,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
616
617
  const target: number | 'all' = raw === 'all' ? 'all' : Number(raw)
617
618
  if (target !== 'all' && !Number.isFinite(target)) {
618
619
  console.error(` invalid target: ${raw}`)
619
- process.exit(1)
620
+ rnxExit(1)
620
621
  }
621
622
  await callTestBridge(bridge, 'disableAnimationTrace', target)
622
623
  console.log(fmt({ disabled: target }, pretty))
@@ -633,7 +634,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
633
634
  const id = Number(sub)
634
635
  if (!Number.isFinite(id)) {
635
636
  console.error(` invalid id: ${sub}`)
636
- process.exit(1)
637
+ rnxExit(1)
637
638
  }
638
639
  const limit = rest[2] ? Number(rest[2]) : undefined
639
640
  const samples = await callTestBridge(bridge, 'getAnimationTrace', id, limit)
@@ -642,7 +643,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
642
643
  }
643
644
  if (traceTarget !== 'shell') {
644
645
  console.error(' usage: rnx debug trace <shell|anim> [args]')
645
- process.exit(1)
646
+ rnxExit(1)
646
647
  }
647
648
  if (!traceCommand || /^[0-9]+$/.test(traceCommand)) {
648
649
  const recentLimit = traceCommand ? Number(traceCommand) : 50
@@ -674,7 +675,7 @@ export async function runDebug(args: string[], opts: DebugOptions) {
674
675
  console.error(
675
676
  ' usage: rnx debug trace shell [on [limit]|off|status|clear|recentLimit]',
676
677
  )
677
- process.exit(1)
678
+ rnxExit(1)
678
679
  }
679
680
 
680
681
  case 'record': {
@@ -702,16 +703,17 @@ export async function runDebug(args: string[], opts: DebugOptions) {
702
703
  default:
703
704
  console.error(` unknown subcommand: ${sub}`)
704
705
  printHelp()
705
- process.exit(1)
706
+ rnxExit(1)
706
707
  }
707
708
  } catch (err: any) {
709
+ rethrowIfExit(err)
708
710
  console.error(` debug failed: ${err.message}`)
709
711
  await printBridgeFailureDiagnostics(bridge, {
710
712
  errorsCommand: `rnx get errors 5${simHint}`,
711
713
  warningsCommand: `rnx get warnings 5${simHint}`,
712
714
  requestsCommand: `rnx get requests 5${simHint}`,
713
715
  })
714
- process.exit(1)
716
+ rnxExit(1)
715
717
  } finally {
716
718
  bridge.close()
717
719
  }
@@ -13,7 +13,6 @@ export interface DetectedProject {
13
13
  framework: Framework
14
14
  hasViteConfig: boolean
15
15
  hasMetroConfig: boolean
16
- hasSootsimDependency: boolean
17
16
  devCommand: string | null
18
17
  }
19
18
 
@@ -24,6 +23,8 @@ export interface DetectedWorkspace {
24
23
  apps: DetectedProject[]
25
24
  }
26
25
 
26
+ const CONFIG_EXTENSIONS = ['ts', 'js', 'cjs', 'mjs', 'mts', 'cts']
27
+
27
28
  export function findProjectRoot(cwd: string): string {
28
29
  let dir = cwd
29
30
  while (true) {
@@ -102,12 +103,15 @@ export function detectProject(dir: string): DetectedProject | null {
102
103
  dir,
103
104
  name: pkg.name || basename(dir),
104
105
  framework,
105
- hasViteConfig:
106
- existsSync(join(dir, 'vite.config.ts')) || existsSync(join(dir, 'vite.config.js')),
107
- hasMetroConfig:
108
- existsSync(join(dir, 'metro.config.js')) ||
109
- existsSync(join(dir, 'metro.config.ts')),
110
- hasSootsimDependency: Boolean(deps.sootsim),
106
+ // a config file is a config file whatever module system it declares. real
107
+ // apps write .cjs as often as .js, and missing one reads as "this project
108
+ // has no bundler config" and sends the user to create a second one.
109
+ hasViteConfig: CONFIG_EXTENSIONS.some((ext) =>
110
+ existsSync(join(dir, `vite.config.${ext}`)),
111
+ ),
112
+ hasMetroConfig: CONFIG_EXTENSIONS.some((ext) =>
113
+ existsSync(join(dir, `metro.config.${ext}`)),
114
+ ),
111
115
  devCommand: pkg.scripts?.dev || null,
112
116
  }
113
117
  }
@@ -18,6 +18,7 @@ import { dirname, resolve, join, relative } from 'path'
18
18
  import { rnxPublicBrand } from '../../src/public-brand'
19
19
  import { resolveCliAuth } from '../auth'
20
20
  import { registerRun, shouldRegisterRun } from '../run-registry'
21
+ import { rnxExit } from '../run-rnx'
21
22
  import { discoverSootsimUrl } from './flow'
22
23
  import { resolveDefaultUploadOrigin } from './upload'
23
24
 
@@ -57,7 +58,7 @@ expected port. disable with --no-launch if you're managing the shell yourself.
57
58
  export async function runDetox(args: string[], opts: RunDetoxOpts = {}): Promise<void> {
58
59
  if (args.includes('--help') || args.includes('-h')) {
59
60
  console.log(HELP)
60
- process.exit(0)
61
+ rnxExit(0)
61
62
  }
62
63
 
63
64
  if (args[0] === 'init') {
@@ -125,7 +126,7 @@ export async function runDetox(args: string[], opts: RunDetoxOpts = {}): Promise
125
126
  ` error: no detox tests found. expected one of: ${detoxDirs.join(', ')}\n` +
126
127
  ` run 'rnx detox init' to scaffold a starter suite.`,
127
128
  )
128
- process.exit(1)
129
+ rnxExit(1)
129
130
  }
130
131
 
131
132
  // auto-launch: make sure a sootsim shell is reachable before running jest.
@@ -278,7 +279,7 @@ export async function runDetox(args: string[], opts: RunDetoxOpts = {}): Promise
278
279
  })
279
280
  if (run) console.log(` run: ${run.id}`)
280
281
  }
281
- process.exit(code)
282
+ rnxExit(code)
282
283
  }
283
284
 
284
285
  type JestRunSummary = {
@@ -410,5 +411,5 @@ describe('example', () => {
410
411
  console.log(`\n next:`)
411
412
  console.log(` rnx detox # run the sample`)
412
413
  console.log(` rnx detox --watch`)
413
- process.exit(0)
414
+ rnxExit(0)
414
415
  }
@@ -4,6 +4,7 @@ import {
4
4
  listSelectableDeviceModels,
5
5
  type DeviceModel,
6
6
  } from 'sootsim-engine/settings'
7
+ import { rnxExit } from '../run-rnx'
7
8
  import {
8
9
  callInBridge,
9
10
  createBridgeFromParsed,
@@ -74,7 +75,7 @@ async function readCurrentDevice(
74
75
  export async function runDeviceCommand(args: string[], opts: DeviceCommandOptions) {
75
76
  if (args.includes('--help') || args.includes('-h')) {
76
77
  usage()
77
- process.exit(0)
78
+ rnxExit(0)
78
79
  }
79
80
 
80
81
  const subcommand = args[0]
@@ -83,7 +84,7 @@ export async function runDeviceCommand(args: string[], opts: DeviceCommandOption
83
84
  const current = await readCurrentDevice(parsed)
84
85
  if (!current) {
85
86
  console.error(' error: could not read current device from the target sim')
86
- process.exit(1)
87
+ rnxExit(1)
87
88
  }
88
89
  console.log(
89
90
  ` ${current.model} ${current.width}x${current.height} pt ${current.width * current.scale}x${current.height * current.scale} px ${current.name}`,
@@ -101,12 +102,12 @@ export async function runDeviceCommand(args: string[], opts: DeviceCommandOption
101
102
  const model = args[1]
102
103
  if (!model) {
103
104
  console.error(' error: device set expects a model')
104
- process.exit(1)
105
+ rnxExit(1)
105
106
  }
106
107
  if (!(model in devices)) {
107
108
  console.error(` error: unknown device "${model}"`)
108
109
  console.error(' run `rnx device list` to see valid models')
109
- process.exit(1)
110
+ rnxExit(1)
110
111
  }
111
112
  const parsed = parseBridgeCliArgs(args, { port: opts.port })
112
113
  const bridge = createBridgeFromParsed(parsed)
@@ -129,5 +130,5 @@ export async function runDeviceCommand(args: string[], opts: DeviceCommandOption
129
130
 
130
131
  usage()
131
132
  console.error(` unknown subcommand: ${subcommand}`)
132
- process.exit(1)
133
+ rnxExit(1)
133
134
  }
@@ -7,6 +7,7 @@ import { ensureProfile } from '../../src/profiles'
7
7
  import { findDesktopCompanion } from '../desktop-companion'
8
8
  import { electronDriver } from '../drivers'
9
9
  import { confirm } from '../prompt'
10
+ import { rnxExit } from '../run-rnx'
10
11
  import { buildShellUrl } from './control'
11
12
  import { printMissingCompanionHint } from './no-bridge-hint'
12
13
 
@@ -22,7 +23,7 @@ function parseInlinePort(args: string[]): number | undefined {
22
23
  const port = raw ? Number(raw) : Number.NaN
23
24
  if (!Number.isInteger(port) || port <= 0) {
24
25
  console.error(` invalid --port value: ${raw || '(missing)'}`)
25
- process.exit(1)
26
+ rnxExit(1)
26
27
  }
27
28
  return port
28
29
  }
@@ -53,14 +54,14 @@ examples:
53
54
  rnx desktop --port 5173
54
55
  rnx desktop --profile qa
55
56
  `)
56
- process.exit(0)
57
+ rnxExit(0)
57
58
  }
58
59
 
59
60
  const profileArg = args.find((_, i) => args[i - 1] === '--profile')
60
61
  const ephemeralProfile = args.includes('--ephemeral')
61
62
  if (profileArg && ephemeralProfile) {
62
63
  console.error(' rnx desktop: --profile cannot be combined with --ephemeral')
63
- process.exit(1)
64
+ rnxExit(1)
64
65
  }
65
66
  const profileId = profileArg ? ensureProfile(profileArg).id : undefined
66
67
  let install = findDesktopCompanion()
@@ -76,7 +77,7 @@ examples:
76
77
  await runInstallDesktop(['--yes'])
77
78
  install = findDesktopCompanion()
78
79
  }
79
- if (!install) process.exit(1)
80
+ if (!install) rnxExit(1)
80
81
  }
81
82
  console.log(` launching ${install.path}`)
82
83
 
@@ -89,7 +90,7 @@ examples:
89
90
  })
90
91
  if (!result.launched) {
91
92
  console.error(` ${result.message}`)
92
- process.exit(1)
93
+ rnxExit(1)
93
94
  }
94
95
  console.log(` ${result.message}`)
95
96
  }
@@ -23,6 +23,7 @@ import {
23
23
  keepFlowCandidate,
24
24
  startFlowSession,
25
25
  } from '../flow-session'
26
+ import { rnxExit } from '../run-rnx'
26
27
  import { createBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
27
28
  import {
28
29
  buildShellUrl,
@@ -176,13 +177,13 @@ flow extension:
176
177
  path: marketing/hero
177
178
  withFrame: true
178
179
  `)
179
- process.exit(0)
180
+ rnxExit(0)
180
181
  }
181
182
 
182
183
  const flowPath = args[0]
183
184
  if (!fs.existsSync(flowPath)) {
184
185
  console.error(` error: ${flowPath} not found`)
185
- process.exit(1)
186
+ rnxExit(1)
186
187
  }
187
188
 
188
189
  const getFlag = (name: string) => args.find((_, i) => args[i - 1] === name)
@@ -240,7 +241,7 @@ flow extension:
240
241
  : ''
241
242
  if (previewBillingKind && previewBillingKind !== 'test_run') {
242
243
  console.error(` error: invalid --billing-kind: ${previewBillingKind}`)
243
- process.exit(1)
244
+ rnxExit(1)
244
245
  }
245
246
  const replaceArgs = args.flatMap((arg, index) =>
246
247
  args[index - 1] === '--replace' ? ['--replace', arg] : [],
@@ -271,7 +272,7 @@ flow extension:
271
272
  const { frontmatter, steps } = parseFlowFile(flowContent)
272
273
  if (steps.length === 0) {
273
274
  console.error(' error: flow file must contain a YAML array of steps')
274
- process.exit(1)
275
+ rnxExit(1)
275
276
  }
276
277
  const targetDevice = deviceOverride || frontmatter.device || ''
277
278
  const targetTheme = frontmatter.theme || ''
@@ -323,7 +324,7 @@ flow extension:
323
324
  console.error(
324
325
  ' error: desktop companion not found. install or build it first with `bun run build:electron`',
325
326
  )
326
- process.exit(1)
327
+ rnxExit(1)
327
328
  }
328
329
 
329
330
  const mode = wantElectron ? 'desktop companion' : 'bridge'
@@ -371,7 +372,7 @@ flow extension:
371
372
  const discovered = await discoverSootsimUrl()
372
373
  if (!discovered) {
373
374
  console.error(' error: no current sim and no sootsim target found')
374
- process.exit(1)
375
+ rnxExit(1)
375
376
  }
376
377
  openTarget = discovered
377
378
  }
@@ -934,7 +935,7 @@ async function runFlowSession(args: string[]) {
934
935
  const result = keepFlowCandidate()
935
936
  if (!result.active) {
936
937
  console.error(' no active flow draft — run `sootsim maestro start` first')
937
- process.exit(1)
938
+ rnxExit(1)
938
939
  }
939
940
  if (!result.kept) {
940
941
  console.log(' no pending action to keep')
@@ -963,7 +964,7 @@ async function runFlowSession(args: string[]) {
963
964
  )
964
965
  if (!result.active) {
965
966
  console.error(' no active flow draft — run `sootsim maestro start` first')
966
- process.exit(1)
967
+ rnxExit(1)
967
968
  }
968
969
  if (!result.valid) {
969
970
  console.error(' flow draft is not valid:')
@@ -971,7 +972,7 @@ async function runFlowSession(args: string[]) {
971
972
  console.error(
972
973
  ' draft preserved — keep at least one real interaction or run `sootsim maestro start` to reset',
973
974
  )
974
- process.exit(1)
975
+ rnxExit(1)
975
976
  }
976
977
 
977
978
  if (validate) {
@@ -1016,13 +1017,13 @@ async function runFlowSession(args: string[]) {
1016
1017
  const flowPath = args[1]
1017
1018
  if (!flowPath || flowPath.startsWith('-')) {
1018
1019
  console.error(' usage: sootsim maestro validate <path>')
1019
- process.exit(1)
1020
+ rnxExit(1)
1020
1021
  }
1021
1022
  const issues = validateFlowFile(flowPath)
1022
1023
  if (issues.length > 0) {
1023
1024
  console.error(` x ${flowPath} failed validation:`)
1024
1025
  for (const issue of issues) console.error(` - ${issue}`)
1025
- process.exit(1)
1026
+ rnxExit(1)
1026
1027
  }
1027
1028
  console.log(` + ${flowPath} looks valid`)
1028
1029
  return
@@ -1,4 +1,5 @@
1
1
  import { maybeHint } from '../../hints'
2
+ import { rnxExit } from '../../run-rnx'
2
3
  import { inspectFind, inspectNodeCount, rankInteractive, tapCommandForNode } from './core'
3
4
  import { printJson, wantsJson } from './shared'
4
5
  import type { WsBridge } from '../../ws-bridge'
@@ -56,7 +57,7 @@ export async function runFindSubcommand(opts: {
56
57
  '<text> | --text <t> | --testid <id> | --role <r> | --type <t> | --pressable | --visible | --interactive-targets',
57
58
  ),
58
59
  )
59
- process.exit(1)
60
+ rnxExit(1)
60
61
  }
61
62
  const { mode, result } = found
62
63
  const jsonOut = wantsJson(args)
@@ -5,6 +5,7 @@
5
5
  // id (if any). reads from `__sootsimKeyboard.getLayout()`, which is
6
6
  // populated by shell-worker `keyboard.layout` broadcasts.
7
7
 
8
+ import { rnxExit } from '../../run-rnx'
8
9
  import { inspectKeyboard } from './core'
9
10
  import type { WsBridge } from '../../ws-bridge'
10
11
 
@@ -16,7 +17,7 @@ export async function runKeyboardSubcommand(
16
17
 
17
18
  if ('error' in result) {
18
19
  console.error(result.error)
19
- process.exit(1)
20
+ rnxExit(1)
20
21
  }
21
22
 
22
23
  if (opts.json) {
@@ -1,3 +1,4 @@
1
+ import { rnxExit } from '../../run-rnx'
1
2
  import { sleep } from './shared'
2
3
 
3
4
  export async function runSleepSubcommand(opts: {
@@ -7,7 +8,7 @@ export async function runSleepSubcommand(opts: {
7
8
  const seconds = opts.positional[1] ? Number(opts.positional[1]) : 0.5
8
9
  if (!Number.isFinite(seconds) || seconds < 0) {
9
10
  console.error(opts.inspectUsage('sleep', '[seconds]'))
10
- process.exit(1)
11
+ rnxExit(1)
11
12
  }
12
13
  await sleep(seconds * 1000)
13
14
  console.log(` slept ${seconds}s`)
@@ -20,6 +20,7 @@
20
20
  // human-paced UI events we care about and stays compatible with the
21
21
  // existing query surface.
22
22
 
23
+ import { rnxExit } from '../../run-rnx'
23
24
  import type { WsBridge } from '../../ws-bridge'
24
25
  import type {
25
26
  SootSimTimelineEvent,
@@ -120,7 +121,7 @@ export async function runWaitEventSubcommand(opts: WaitEventOptions): Promise<vo
120
121
  '<kind> [--max-ms 5000] [--filter <substring>] [--equals <exact>] [--since now|cursor]',
121
122
  ),
122
123
  )
123
- process.exit(1)
124
+ rnxExit(1)
124
125
  }
125
126
  if (!KNOWN_KINDS.has(kind)) {
126
127
  console.error(
@@ -171,7 +172,7 @@ export async function runWaitEventSubcommand(opts: WaitEventOptions): Promise<vo
171
172
  console.error(
172
173
  ` could not query timeline: ${result && 'error' in result ? result.error : 'unknown'}`,
173
174
  )
174
- process.exit(1)
175
+ rnxExit(1)
175
176
  }
176
177
  const evts = result.result.events ?? []
177
178
  for (const ev of evts) {
@@ -206,5 +207,5 @@ export async function runWaitEventSubcommand(opts: WaitEventOptions): Promise<vo
206
207
  ` ⚠ wait event ${kind} timed out after ${elapsed}ms${filter ? ` (filter: ${filter})` : ''}${equals ? ` (equals: ${equals})` : ''}`,
207
208
  )
208
209
  }
209
- process.exit(1)
210
+ rnxExit(1)
210
211
  }