rnxsim 0.1.352 → 0.1.353

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 (198) hide show
  1. package/README.md +17 -16
  2. package/cli/bin.ts +5 -4
  3. package/cli/commands/control.ts +20 -5
  4. package/cli/commands/daemon-mac-app.ts +1 -1
  5. package/cli/commands/daemon.ts +6 -8
  6. package/cli/commands/install-desktop.ts +42 -32
  7. package/cli/commands/no-bridge-hint.ts +3 -3
  8. package/cli/commands/serve.ts +1 -1
  9. package/cli/commands/setup.ts +215 -176
  10. package/cli/commands/welcome.ts +9 -58
  11. package/cli/desktop-companion.ts +31 -16
  12. package/cli/prompt.ts +12 -7
  13. package/cli/setup-repository.ts +6 -2
  14. package/cli/ui.ts +68 -0
  15. package/dist-cli/bin.js +5 -5
  16. package/dist-cli/chunks/{agent-27WDUXK5.js → agent-YTAX6OQQ.js} +2 -2
  17. package/dist-cli/chunks/{agent-wrapper-XAUWPZ6O.js → agent-wrapper-2QSUXMNK.js} +2 -2
  18. package/dist-cli/chunks/{app-fonts-COAZFLDG.js → app-fonts-4EVHPXVG.js} +2 -2
  19. package/dist-cli/chunks/{assert-ZR2UE3EH.js → assert-IXMSQLVY.js} +2 -2
  20. package/dist-cli/chunks/{auth-LISHWKCC.js → auth-6QFWU2T5.js} +2 -2
  21. package/dist-cli/chunks/{beta-AQQUYVA5.js → beta-27I5WWRE.js} +2 -2
  22. package/dist-cli/chunks/{camera-KE44ZN3U.js → camera-4HFUBXPM.js} +2 -2
  23. package/dist-cli/chunks/{chunk-DJAYEBF3.js → chunk-37J74ASV.js} +1 -1
  24. package/dist-cli/chunks/{chunk-XI4W6LRQ.js → chunk-3IWR7KHR.js} +2 -2
  25. package/dist-cli/chunks/{chunk-CY6HBAOB.js → chunk-3UXMNDMH.js} +2 -2
  26. package/dist-cli/chunks/{chunk-R2BFC3AC.js → chunk-3XDGLCNP.js} +2 -2
  27. package/dist-cli/chunks/{chunk-6NSUY346.js → chunk-4IXIONDR.js} +2 -2
  28. package/dist-cli/chunks/{chunk-YAMKV3UB.js → chunk-4NPZ5FO2.js} +2 -2
  29. package/dist-cli/chunks/{chunk-QJTW4QQW.js → chunk-4PV6QASJ.js} +1 -1
  30. package/dist-cli/chunks/{chunk-PEBQKBEP.js → chunk-57YZEJ6J.js} +1 -1
  31. package/dist-cli/chunks/{chunk-4AOAJXE2.js → chunk-5DLBRZAG.js} +2 -2
  32. package/dist-cli/chunks/{chunk-7T7DR34H.js → chunk-6JBOKETZ.js} +2 -2
  33. package/dist-cli/chunks/{chunk-AR3CPCW3.js → chunk-6NE5Z6KG.js} +1 -1
  34. package/dist-cli/chunks/{chunk-RASWCAJJ.js → chunk-7FUSVOMH.js} +2 -2
  35. package/dist-cli/chunks/{chunk-5JE5PNIV.js → chunk-7SKQRS74.js} +1 -1
  36. package/dist-cli/chunks/chunk-7V5O6I4Q.js +9 -0
  37. package/dist-cli/chunks/{chunk-3Y7NWE22.js → chunk-BK5TJXUU.js} +2 -2
  38. package/dist-cli/chunks/{chunk-H4IF54WS.js → chunk-CMQIFA4L.js} +1 -1
  39. package/dist-cli/chunks/{chunk-3ZV4WSCR.js → chunk-CYS3D7RG.js} +2 -2
  40. package/dist-cli/chunks/{chunk-LRKODRWI.js → chunk-DSBUGNC5.js} +2 -2
  41. package/dist-cli/chunks/{chunk-EGKGCDG5.js → chunk-ECIDT6F5.js} +1 -1
  42. package/dist-cli/chunks/{chunk-EHQHK7KN.js → chunk-ELBDKQK2.js} +2 -2
  43. package/dist-cli/chunks/{chunk-ELNSQ352.js → chunk-GAYCF2O5.js} +1 -1
  44. package/dist-cli/chunks/{chunk-ESVF72YH.js → chunk-HVLZYUGF.js} +2 -2
  45. package/dist-cli/chunks/{chunk-5JINX2IB.js → chunk-HWMBTYJX.js} +2 -2
  46. package/dist-cli/chunks/{chunk-MJB6N7WS.js → chunk-HZTWQZUD.js} +2 -2
  47. package/dist-cli/chunks/{chunk-M6DC6JZL.js → chunk-IX7W5BXL.js} +2 -2
  48. package/dist-cli/chunks/{chunk-BZ32JGFC.js → chunk-JVVO63QH.js} +1 -1
  49. package/dist-cli/chunks/{chunk-JEPQ5YX3.js → chunk-KIQVNLVD.js} +2 -2
  50. package/dist-cli/chunks/chunk-KZLGVYCX.js +7 -0
  51. package/dist-cli/chunks/{chunk-QP7KGSU4.js → chunk-LAFKQUT7.js} +3 -3
  52. package/dist-cli/chunks/{chunk-E42ZJLPN.js → chunk-LMFAIAA5.js} +1 -1
  53. package/dist-cli/chunks/chunk-MA5E6HJR.js +15 -0
  54. package/dist-cli/chunks/chunk-OEU2MEZQ.js +124 -0
  55. package/dist-cli/chunks/{chunk-BQE4E24T.js → chunk-PBTG4UCS.js} +1 -1
  56. package/dist-cli/chunks/{chunk-XHZEKHB2.js → chunk-PNQ33FJB.js} +6 -6
  57. package/dist-cli/chunks/{chunk-MJJP2BEI.js → chunk-R4KBCGXX.js} +3 -3
  58. package/dist-cli/chunks/chunk-RMOSWLWG.js +32 -0
  59. package/dist-cli/chunks/{chunk-WNJDE2JT.js → chunk-RRX5RZI2.js} +1 -1
  60. package/dist-cli/chunks/{chunk-R4P7WO4L.js → chunk-T2ZZSSCP.js} +2 -2
  61. package/dist-cli/chunks/{chunk-DSF4WC4X.js → chunk-TX2T5KPQ.js} +2 -2
  62. package/dist-cli/chunks/{chunk-2OME2KGY.js → chunk-UEILOAPW.js} +1 -1
  63. package/dist-cli/chunks/{chunk-TF6VBUZ7.js → chunk-UNBVUOIC.js} +2 -2
  64. package/dist-cli/chunks/chunk-UQBXA3AK.js +24 -0
  65. package/dist-cli/chunks/{chunk-H6MTPXZS.js → chunk-V7X543SB.js} +1 -1
  66. package/dist-cli/chunks/{chunk-45D2GGIA.js → chunk-VLI54BKH.js} +2 -2
  67. package/dist-cli/chunks/{chunk-RH6FJI5O.js → chunk-VZDW2U64.js} +2 -2
  68. package/dist-cli/chunks/chunk-WKQ6W74M.js +11 -0
  69. package/dist-cli/chunks/{chunk-S2PJOB2C.js → chunk-WTGQUQ32.js} +2 -2
  70. package/dist-cli/chunks/{chunk-P5YC5VGA.js → chunk-WU25RTIX.js} +2 -2
  71. package/dist-cli/chunks/chunk-WV3TKN7D.js +4 -0
  72. package/dist-cli/chunks/{chunk-Q4ROOH3W.js → chunk-XVLYLZOM.js} +2 -2
  73. package/dist-cli/chunks/{chunk-VQDY7NEJ.js → chunk-YQJOM55S.js} +1 -1
  74. package/dist-cli/chunks/{chunk-AIGZ3TSW.js → chunk-YYYWU6LL.js} +3 -3
  75. package/dist-cli/chunks/{chunk-NQMZOJPX.js → chunk-ZF53H457.js} +2 -2
  76. package/dist-cli/chunks/{chunk-24CIPQT5.js → chunk-ZJ4O636U.js} +1 -1
  77. package/dist-cli/chunks/{chunk-ZK5HYQ4I.js → chunk-ZXHAAVTH.js} +2 -2
  78. package/dist-cli/chunks/{chunk-FHLEA4S5.js → chunk-ZYGWIVW4.js} +2 -2
  79. package/dist-cli/chunks/{cleanup-JUY2WU24.js → cleanup-ULH3BHAE.js} +2 -2
  80. package/dist-cli/chunks/cli-version-I2E56I4W.js +4 -0
  81. package/dist-cli/chunks/{compat-S2TBISY3.js → compat-ONN5DOHB.js} +2 -2
  82. package/dist-cli/chunks/{config-3PHD4J5N.js → config-OPZU73MX.js} +2 -2
  83. package/dist-cli/chunks/control-WNYEAI4K.js +4 -0
  84. package/dist-cli/chunks/daemon-5J6V2GLG.js +4 -0
  85. package/dist-cli/chunks/{debug-PFAJONVV.js → debug-GNI3HDAK.js} +3 -3
  86. package/dist-cli/chunks/{desktop-Z7EOBMNV.js → desktop-DF65PDJG.js} +4 -4
  87. package/dist-cli/chunks/{detox-KRSP5SLY.js → detox-N267KW2Y.js} +2 -2
  88. package/dist-cli/chunks/{device-ZXJ7GRBO.js → device-RFU44PE3.js} +2 -2
  89. package/dist-cli/chunks/{diagnose-JIMLEOEJ.js → diagnose-XR2JIGDE.js} +2 -2
  90. package/dist-cli/chunks/{disk-cleanup-YY7FFGVA.js → disk-cleanup-DPY6TYXA.js} +2 -2
  91. package/dist-cli/chunks/drivers-OIZC544W.js +4 -0
  92. package/dist-cli/chunks/{film-LKSJPU2A.js → film-NQQZPZ2W.js} +3 -3
  93. package/dist-cli/chunks/flow-3NHEHRF4.js +4 -0
  94. package/dist-cli/chunks/help-VACWNWEH.js +4 -0
  95. package/dist-cli/chunks/{hidden-runtime-alias-ZN3WZ3ND.js → hidden-runtime-alias-APCBIXJ6.js} +2 -2
  96. package/dist-cli/chunks/home-paths-27GY5EPD.js +4 -0
  97. package/dist-cli/chunks/inspect-2JELKZ5A.js +4 -0
  98. package/dist-cli/chunks/install-desktop-4R7UTGQU.js +4 -0
  99. package/dist-cli/chunks/{login-XKLIFTAU.js → login-6KIO5FR4.js} +2 -2
  100. package/dist-cli/chunks/{logout-DR22RB5H.js → logout-WMCYGTYA.js} +2 -2
  101. package/dist-cli/chunks/{maestro-SLCX6HBV.js → maestro-7QLOUZIE.js} +3 -3
  102. package/dist-cli/chunks/{maestro-generate-GBFZ5INV.js → maestro-generate-QIGCQANR.js} +3 -3
  103. package/dist-cli/chunks/{mode-F4R2KNXX.js → mode-3H662MUJ.js} +2 -2
  104. package/dist-cli/chunks/{optional-demo-registry-HM55KXGB.js → optional-demo-registry-FQV54ASP.js} +2 -2
  105. package/dist-cli/chunks/{perf-VBS5GEPG.js → perf-KC6LOGFD.js} +2 -2
  106. package/dist-cli/chunks/{permissions-F46PQIUE.js → permissions-UGVHA3L6.js} +2 -2
  107. package/dist-cli/chunks/privacy-E6KH2DRJ.js +4 -0
  108. package/dist-cli/chunks/{record-NLZ6DFAA.js → record-V72Q363I.js} +3 -3
  109. package/dist-cli/chunks/{report-issue-XIE5BVR4.js → report-issue-MILOOCMG.js} +2 -2
  110. package/dist-cli/chunks/reset-LEL5ZGFN.js +4 -0
  111. package/dist-cli/chunks/runtime-RT2OTIQC.js +4 -0
  112. package/dist-cli/chunks/{screenshot-command-SD4JPNKW.js → screenshot-command-FYMZF5AF.js} +3 -3
  113. package/dist-cli/chunks/{screenshot-layers-X65RC3GT.js → screenshot-layers-OXLW6GEJ.js} +2 -2
  114. package/dist-cli/chunks/{screenshots-capture-BBXN7FEZ.js → screenshots-capture-N3LKTUKB.js} +2 -2
  115. package/dist-cli/chunks/{serve-M6ZKMSAG.js → serve-USDREK3N.js} +2 -2
  116. package/dist-cli/chunks/setup-QC7W7NCL.js +4 -0
  117. package/dist-cli/chunks/{skills-KDWGQBOP.js → skills-3MIZF3DS.js} +2 -2
  118. package/dist-cli/chunks/{state-NWABXG2P.js → state-MCFLWQHV.js} +2 -2
  119. package/dist-cli/chunks/{storage-QQE3G65Q.js → storage-KXNS5WEC.js} +2 -2
  120. package/dist-cli/chunks/store-GL6DFPJL.js +4 -0
  121. package/dist-cli/chunks/telemetry-OOW5FMZQ.js +4 -0
  122. package/dist-cli/chunks/{timeline-2VZ45MMB.js → timeline-QJ3USMSX.js} +2 -2
  123. package/dist-cli/chunks/{upgrade-T7PDR6T5.js → upgrade-LXFD4DFX.js} +2 -2
  124. package/dist-cli/chunks/upload-EUEO4D5N.js +4 -0
  125. package/dist-cli/chunks/{version-BX6QX5XA.js → version-D5DLNPHP.js} +2 -2
  126. package/dist-cli/chunks/{web-4J6JRZN2.js → web-FRFNTTZ4.js} +2 -2
  127. package/dist-cli/chunks/welcome-YYYGS5WD.js +5 -0
  128. package/dist-cli/chunks/{what-happened-CHQKFNCM.js → what-happened-FJ6GRQAS.js} +2 -2
  129. package/dist-lib/agent-daemon-client.cjs +2 -2
  130. package/dist-lib/agent-events.cjs +1 -1
  131. package/dist-lib/agent-identity.cjs +1 -1
  132. package/dist-lib/agent-sessions.cjs +1 -1
  133. package/dist-lib/attached-projects.cjs +1 -1
  134. package/dist-lib/auth/shared-session.cjs +1 -1
  135. package/dist-lib/backend-origin.cjs +1 -1
  136. package/dist-lib/beta.cjs +1 -1
  137. package/dist-lib/beta.mjs +1 -1
  138. package/dist-lib/bridge-constants.cjs +1 -1
  139. package/dist-lib/bridge-contract.cjs +1 -1
  140. package/dist-lib/cli-constants.cjs +1 -1
  141. package/dist-lib/config.cjs +1 -1
  142. package/dist-lib/detox/index.cjs +1 -1
  143. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  144. package/dist-lib/home-paths.cjs +21 -1
  145. package/dist-lib/host/bridge-host.cjs +1 -1
  146. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  147. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  148. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  149. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  150. package/dist-lib/host/websocket-proxy.cjs +1 -1
  151. package/dist-lib/index.cjs +2 -2
  152. package/dist-lib/jump-to-source-babel.cjs +1 -1
  153. package/dist-lib/menu.cjs +1 -1
  154. package/dist-lib/menu.mjs +1 -1
  155. package/dist-lib/metro-production-bundle.cjs +1 -1
  156. package/dist-lib/metro-production-bundle.mjs +1 -1
  157. package/dist-lib/metro.cjs +2 -2
  158. package/dist-lib/profiles.cjs +1 -1
  159. package/dist-lib/public-brand.cjs +1 -1
  160. package/dist-lib/react-native-host-modules.cjs +1 -1
  161. package/dist-lib/react-native-host-modules.mjs +1 -1
  162. package/dist-lib/render-mode.cjs +1 -1
  163. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  164. package/dist-lib/sdk.cjs +1 -1
  165. package/dist-lib/sdk.mjs +1 -1
  166. package/dist-lib/skills.cjs +87 -22
  167. package/dist-lib/vite.cjs +2 -2
  168. package/package.json +1 -1
  169. package/skills/contrast/SKILL.md +3 -3
  170. package/skills/rnx-setup/SKILL.md +17 -5
  171. package/src/agent-daemon-client.ts +1 -1
  172. package/src/home-paths.ts +22 -0
  173. package/src/metro-plugin.ts +1 -1
  174. package/src/runtime-assets.ts +1 -1
  175. package/dist-cli/chunks/chunk-2JZXOHH6.js +0 -4
  176. package/dist-cli/chunks/chunk-2WJABJ6C.js +0 -15
  177. package/dist-cli/chunks/chunk-5OVXQKUP.js +0 -25
  178. package/dist-cli/chunks/chunk-DFTG53TX.js +0 -11
  179. package/dist-cli/chunks/chunk-HF2FZ2WN.js +0 -7
  180. package/dist-cli/chunks/chunk-S63ENXGH.js +0 -6
  181. package/dist-cli/chunks/chunk-UHP33XGC.js +0 -124
  182. package/dist-cli/chunks/cli-version-6SQSIFNQ.js +0 -4
  183. package/dist-cli/chunks/control-GLBCTKAA.js +0 -4
  184. package/dist-cli/chunks/daemon-H4OVIEMH.js +0 -4
  185. package/dist-cli/chunks/drivers-63LY2NCK.js +0 -4
  186. package/dist-cli/chunks/flow-JHKPF7BN.js +0 -4
  187. package/dist-cli/chunks/help-Q6OY6VVA.js +0 -4
  188. package/dist-cli/chunks/home-paths-UOATIRKF.js +0 -4
  189. package/dist-cli/chunks/inspect-DW3V2FD4.js +0 -4
  190. package/dist-cli/chunks/install-desktop-GWY5H22W.js +0 -4
  191. package/dist-cli/chunks/privacy-34FNXPJP.js +0 -4
  192. package/dist-cli/chunks/reset-BAGCFYTS.js +0 -4
  193. package/dist-cli/chunks/runtime-JTYB4CM7.js +0 -4
  194. package/dist-cli/chunks/setup-KTWKZOJB.js +0 -30
  195. package/dist-cli/chunks/store-6XW4YZM6.js +0 -4
  196. package/dist-cli/chunks/telemetry-MVSV7JHI.js +0 -4
  197. package/dist-cli/chunks/upload-RF2MNO2X.js +0 -4
  198. package/dist-cli/chunks/welcome-3MJHGERV.js +0 -5
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -10668,6 +10668,7 @@ __export(home_paths_exports, {
10668
10668
  isDaemonLockfileFresh: () => isDaemonLockfileFresh,
10669
10669
  isDevBridgeLockfileFresh: () => isDevBridgeLockfileFresh,
10670
10670
  isDevWorkstation: () => isDevWorkstation,
10671
+ isOnboardingComplete: () => isOnboardingComplete,
10671
10672
  isSootsimDevCheckout: () => isSootsimDevCheckout,
10672
10673
  profilesDir: () => profilesDir,
10673
10674
  readActiveRuntime: () => readActiveRuntime,
@@ -10677,6 +10678,7 @@ __export(home_paths_exports, {
10677
10678
  readOrCreateAnonymousId: () => readOrCreateAnonymousId,
10678
10679
  readPrivacyPreferences: () => readPrivacyPreferences,
10679
10680
  readSharedConfig: () => readSharedConfig,
10681
+ readSimulatorDriverPreference: () => readSimulatorDriverPreference,
10680
10682
  removeDaemonLockfile: () => removeDaemonLockfile,
10681
10683
  removeDevBridgeLockfile: () => removeDevBridgeLockfile,
10682
10684
  runtimeDir: () => runtimeDir,
@@ -10687,6 +10689,7 @@ __export(home_paths_exports, {
10687
10689
  writeActiveRuntime: () => writeActiveRuntime,
10688
10690
  writeDaemonLockfile: () => writeDaemonLockfile,
10689
10691
  writeDevBridgeLockfile: () => writeDevBridgeLockfile,
10692
+ writeOnboardingPreferences: () => writeOnboardingPreferences,
10690
10693
  writePrivacyPreferences: () => writePrivacyPreferences,
10691
10694
  writeRuntimeUpgradeNotice: () => writeRuntimeUpgradeNotice,
10692
10695
  writeSharedConfig: () => writeSharedConfig
@@ -10793,6 +10796,19 @@ function writeSharedConfig(patch) {
10793
10796
  import_node_fs3.default.renameSync(tmp, configFilePath());
10794
10797
  return next;
10795
10798
  }
10799
+ function isOnboardingComplete() {
10800
+ return readSharedConfig().onboardingVersion === CURRENT_ONBOARDING_VERSION;
10801
+ }
10802
+ function readSimulatorDriverPreference() {
10803
+ const driver = readSharedConfig().simulatorDriver;
10804
+ return driver === "electron" || driver === "playwright" ? driver : null;
10805
+ }
10806
+ function writeOnboardingPreferences(driver) {
10807
+ writeSharedConfig({
10808
+ onboardingVersion: CURRENT_ONBOARDING_VERSION,
10809
+ simulatorDriver: driver
10810
+ });
10811
+ }
10796
10812
  function readPrivacyPreferences() {
10797
10813
  const settings = readSharedConfig().settings;
10798
10814
  const productAnalytics = settings?.productAnalytics;
@@ -11138,7 +11154,7 @@ function removeDevBridgeLockfile(owner) {
11138
11154
  } catch {
11139
11155
  }
11140
11156
  }
11141
- var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
11157
+ var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, SOOTSIM_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, DAEMON_HEARTBEAT_STALE_MS, CURRENT_ONBOARDING_VERSION, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
11142
11158
  var init_home_paths = __esm({
11143
11159
  "src/home-paths.ts"() {
11144
11160
  "use strict";
@@ -11152,6 +11168,7 @@ var init_home_paths = __esm({
11152
11168
  DEV_BRIDGES_DIR = "dev-bridges";
11153
11169
  CONFIG_FILE = "config.json";
11154
11170
  DAEMON_HEARTBEAT_STALE_MS = 3e4;
11171
+ CURRENT_ONBOARDING_VERSION = 1;
11155
11172
  DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
11156
11173
  DAEMON_CLAIM_STALE_MS = 3e4;
11157
11174
  }
@@ -18199,9 +18216,9 @@ function findElectronBin(startDir) {
18199
18216
  function findMacApp() {
18200
18217
  const root = getSootsimRoot();
18201
18218
  const candidates = [
18202
- "/Applications/sootsim.app",
18203
- (0, import_path5.resolve)(process.env.HOME || "", "Applications/sootsim.app"),
18204
- ...root ? [(0, import_path5.resolve)(root, "app/sootsim.app")] : []
18219
+ "/Applications/rnx.app",
18220
+ (0, import_path5.resolve)(process.env.HOME || "", "Applications/rnx.app"),
18221
+ ...root ? [(0, import_path5.resolve)(root, "app/rnx.app")] : []
18205
18222
  ];
18206
18223
  const found = candidates.find((candidate) => (0, import_fs6.existsSync)(candidate));
18207
18224
  if (found) {
@@ -18230,20 +18247,17 @@ function findMacApp() {
18230
18247
  }
18231
18248
  function findFirstAppImage(dir) {
18232
18249
  if (!(0, import_fs6.existsSync)(dir)) return null;
18233
- const match = (0, import_fs6.readdirSync)(dir).filter((entry) => entry.startsWith("sootsim") && entry.endsWith(".AppImage")).sort().reverse()[0];
18250
+ const match = (0, import_fs6.readdirSync)(dir).filter((entry) => entry.startsWith("rnx") && entry.endsWith(".AppImage")).sort().reverse()[0];
18234
18251
  return match ? (0, import_path5.join)(dir, match) : null;
18235
18252
  }
18236
18253
  function findLinuxInstall() {
18237
18254
  const root = getSootsimRoot();
18238
18255
  const directCandidates = [
18239
- (0, import_path5.resolve)(process.env.HOME || "", "Applications/sootsim.AppImage"),
18240
- (0, import_path5.resolve)(process.env.HOME || "", ".local/bin/sootsim.AppImage"),
18241
- "/opt/sootsim/sootsim.AppImage",
18242
- "/opt/sootsim/sootsim",
18243
- ...root ? [
18244
- (0, import_path5.resolve)(root, "app/sootsim.AppImage"),
18245
- (0, import_path5.resolve)(root, "release/linux-unpacked/sootsim")
18246
- ] : []
18256
+ (0, import_path5.resolve)(process.env.HOME || "", "Applications/rnx.AppImage"),
18257
+ (0, import_path5.resolve)(process.env.HOME || "", ".local/bin/rnx.AppImage"),
18258
+ "/opt/rnx/rnx.AppImage",
18259
+ "/opt/rnx/rnx",
18260
+ ...root ? [(0, import_path5.resolve)(root, "app/rnx.AppImage"), (0, import_path5.resolve)(root, "release/linux-unpacked/rnx")] : []
18247
18261
  ];
18248
18262
  const directMatch = directCandidates.find((candidate) => (0, import_fs6.existsSync)(candidate));
18249
18263
  if (directMatch) {
@@ -18261,6 +18275,23 @@ function findLinuxInstall() {
18261
18275
  kind: "linux-appimage"
18262
18276
  };
18263
18277
  }
18278
+ function findWindowsInstall() {
18279
+ for (const hive of ["HKCU", "HKLM"]) {
18280
+ try {
18281
+ const output = (0, import_child_process5.execFileSync)(
18282
+ "reg",
18283
+ ["query", `${hive}\\Software\\Classes\\rnx\\shell\\open\\command`, "/ve"],
18284
+ { encoding: "utf8", timeout: 3e3 }
18285
+ );
18286
+ const executable = /"([^"\r\n]+\.exe)"/i.exec(output)?.[1];
18287
+ if (executable && (0, import_fs6.existsSync)(executable)) {
18288
+ return { path: executable, platform: "win32", kind: "win-exe" };
18289
+ }
18290
+ } catch {
18291
+ }
18292
+ }
18293
+ return null;
18294
+ }
18264
18295
  function findDesktopCompanion() {
18265
18296
  const dev = findDevElectron();
18266
18297
  if (dev) return dev;
@@ -18282,6 +18313,7 @@ function findDesktopCompanion() {
18282
18313
  }
18283
18314
  if (process.platform === "darwin") return findMacApp();
18284
18315
  if (process.platform === "linux") return findLinuxInstall();
18316
+ if (process.platform === "win32") return findWindowsInstall();
18285
18317
  return null;
18286
18318
  }
18287
18319
  async function spawnDetached(command, args, opts = {}) {
@@ -18328,7 +18360,7 @@ async function launchDesktopCompanion(url, install = findDesktopCompanion(), opt
18328
18360
  }
18329
18361
  function buildMacLaunchUrl(url, opts) {
18330
18362
  if (!opts.profileId && !opts.ephemeralProfile && !opts.ownerPid) return url;
18331
- const deepLink = new URL("sootsim://dev");
18363
+ const deepLink = new URL("rnx://dev");
18332
18364
  deepLink.searchParams.set("url", url);
18333
18365
  if (opts.profileId) deepLink.searchParams.set("profile", opts.profileId);
18334
18366
  if (opts.ephemeralProfile) deepLink.searchParams.set("ephemeral", "1");
@@ -19219,6 +19251,32 @@ var init_open_url2 = __esm({
19219
19251
  }
19220
19252
  });
19221
19253
 
19254
+ // cli/commands/inspect/env.ts
19255
+ function isAgentEnv() {
19256
+ if (process.env.SOOTSIM_AGENT === "0") return false;
19257
+ for (const name2 of AGENT_ENV_VARS) {
19258
+ const v = process.env[name2];
19259
+ if (v && v.trim() && v !== "0") return true;
19260
+ }
19261
+ return false;
19262
+ }
19263
+ var AGENT_ENV_VARS;
19264
+ var init_env = __esm({
19265
+ "cli/commands/inspect/env.ts"() {
19266
+ "use strict";
19267
+ AGENT_ENV_VARS = [
19268
+ "SOOTSIM_AGENT",
19269
+ "TM_SESSION",
19270
+ "CLAUDECODE",
19271
+ "CLAUDE_CODE_ENTRYPOINT",
19272
+ "CLAUDE_CODE_SESSION_ID",
19273
+ "CODEX_THREAD_ID",
19274
+ "CURSOR_TRACE_ID",
19275
+ "AIDER_MODEL"
19276
+ ];
19277
+ }
19278
+ });
19279
+
19222
19280
  // cli/runtime-notes.ts
19223
19281
  function isChangelogEntry(value) {
19224
19282
  if (!value || typeof value !== "object") return false;
@@ -19665,7 +19723,7 @@ async function ensureBridgeForOpen(preferredPort, explicitPort = false) {
19665
19723
  assertExplicitBridgeLock(preferredPort, explicitPort, nextLock);
19666
19724
  if (nextLock && isDaemonLockfileFresh(nextLock) && await canConnectToBridge(nextLock.bridgePort, 250)) {
19667
19725
  console.error(
19668
- ` started local bridge on port ${nextLock.bridgePort}; run \`sootsim setup\` to install the background daemon`
19726
+ ` Started a local bridge on port ${nextLock.bridgePort}. Run \`rnx daemon install\` to keep it ready between commands.`
19669
19727
  );
19670
19728
  return nextLock.bridgePort;
19671
19729
  }
@@ -20359,7 +20417,7 @@ function resolveTargetSim(sims, requestedId) {
20359
20417
  if (firstOpen) return firstOpen;
20360
20418
  throw new Error("no sim connected");
20361
20419
  }
20362
- function printOpenedSim(openUrl2, sim, mode) {
20420
+ function printOpenedSim(openUrl2, sim, mode, quiet = false) {
20363
20421
  const [printableOpenUrl, printableSimUrl] = [openUrl2, sim.url].map((value) => {
20364
20422
  if (!value) return value;
20365
20423
  try {
@@ -20372,6 +20430,10 @@ function printOpenedSim(openUrl2, sim, mode) {
20372
20430
  }
20373
20431
  return value;
20374
20432
  });
20433
+ if (quiet) {
20434
+ console.log(` Opened ConnectRN [${mode}]`);
20435
+ return;
20436
+ }
20375
20437
  console.log(
20376
20438
  ` ${mode === "current sim" ? "loaded" : "opened"}: ${printableOpenUrl} [${mode}]`
20377
20439
  );
@@ -20526,7 +20588,8 @@ async function runOpenCommand(args, opts = {}) {
20526
20588
  "--ephemeral",
20527
20589
  "--hot",
20528
20590
  "--no-hmr",
20529
- "--no-describe"
20591
+ "--no-describe",
20592
+ "--quiet"
20530
20593
  ],
20531
20594
  stripValueFlags: [
20532
20595
  "--base-url",
@@ -20539,6 +20602,7 @@ async function runOpenCommand(args, opts = {}) {
20539
20602
  ]
20540
20603
  });
20541
20604
  const requestedProfileId = args.find((_, i) => args[i - 1] === "--profile");
20605
+ const quiet = args.includes("--quiet");
20542
20606
  const ephemeralProfile = args.includes("--ephemeral");
20543
20607
  const cdpPortArg = args.find((_, i) => args[i - 1] === "--cdp-port");
20544
20608
  const cdpPort = cdpPortArg ? Number(cdpPortArg) : void 0;
@@ -20623,7 +20687,7 @@ async function runOpenCommand(args, opts = {}) {
20623
20687
  console.error(` unknown driver "${requestedDriverId}" \u2014 run \`rnx list --drivers\``);
20624
20688
  process.exit(1);
20625
20689
  }
20626
- const driverId = isDriverId(requestedDriverId) ? requestedDriverId : "playwright";
20690
+ const driverId = isDriverId(requestedDriverId) ? requestedDriverId : process.env.CI === "1" || process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true" || isAgentEnv() || !process.stdin.isTTY ? "playwright" : readSimulatorDriverPreference() || "playwright";
20627
20691
  const driverHeadless = resolveDriverHeadless(args, driverId);
20628
20692
  if (cdpPort && driverId !== "playwright") {
20629
20693
  console.error(" rnx open: --cdp-port is only honored by the playwright driver");
@@ -20635,7 +20699,7 @@ async function runOpenCommand(args, opts = {}) {
20635
20699
  console.error(" rnx open: --hot and --no-hmr cannot be combined");
20636
20700
  process.exit(1);
20637
20701
  }
20638
- const hotMode = hotFlag ? true : noHmrFlag ? false : requestedDriverId !== "playwright";
20702
+ const hotMode = hotFlag ? true : noHmrFlag ? false : driverId !== "playwright";
20639
20703
  const deviceArg = args.find((_, i) => args[i - 1] === "--device");
20640
20704
  if (deviceArg && !(deviceArg in import_settings.devices)) {
20641
20705
  console.error(` rnx open: unknown device "${deviceArg}"`);
@@ -20761,7 +20825,7 @@ async function runOpenCommand(args, opts = {}) {
20761
20825
  applySootSimConfigToUrl(resolvedBaseUrl, runtimeConfig),
20762
20826
  buildShellUrlOpts
20763
20827
  );
20764
- printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, "current sim");
20828
+ printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, "current sim", quiet);
20765
20829
  await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args);
20766
20830
  return parsed.wsPort;
20767
20831
  }
@@ -20834,7 +20898,7 @@ async function runOpenCommand(args, opts = {}) {
20834
20898
  const match = outcome.sim;
20835
20899
  saveCurrentSimId(match.id);
20836
20900
  signalDriverLaunchConnected(result);
20837
- printOpenedSim(openUrl2, match, `${driver.name} driver`);
20901
+ printOpenedSim(openUrl2, match, `${driver.name} driver`, quiet);
20838
20902
  await maybeDescribeAfterOpen(parsed.wsPort, match.id, args);
20839
20903
  return parsed.wsPort;
20840
20904
  }
@@ -21130,6 +21194,7 @@ var init_control = __esm({
21130
21194
  init_open_url2();
21131
21195
  init_ws_bridge();
21132
21196
  init_core();
21197
+ init_env();
21133
21198
  DEFAULT_DRIVER_CONNECT_TIMEOUT_MS = 12e4;
21134
21199
  DRIVER_CONNECT_INTERVAL_MS = 100;
21135
21200
  DRIVER_CONNECT_HOST_GRACE_MS = 5e3;
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.353 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -446,7 +446,7 @@ function isValidRuntimeVersion(value) {
446
446
  }
447
447
 
448
448
  // src/runtime-assets.ts
449
- var SOOTSIM_RUNTIME_MISSING_MESSAGE = "[rnx] no engine runtime installed \u2014 run `rnx setup`, or `rnx runtime install`";
449
+ var SOOTSIM_RUNTIME_MISSING_MESSAGE = "[rnx] no engine runtime installed. run `rnx runtime install`";
450
450
  var _monorepoRootCache;
451
451
  function findMonorepoRoot() {
452
452
  if (_monorepoRootCache !== void 0) return _monorepoRootCache;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnxsim",
3
- "version": "0.1.352",
3
+ "version": "0.1.353",
4
4
  "description": "rnx CLI, Vite and Metro plugins, and agent skills for driving React Native apps in the browser.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -49,11 +49,11 @@ automation, inspecting the render tree, and managing sims.
49
49
  | `rnx claim` | take an exclusive lease on a sim |
50
50
  | `rnx agent` | attached projects + local agent sessions (codex/claude) |
51
51
  | `rnx close` | close a connected sim |
52
- | `rnx setup` | check local setup and install the recommended bridge daemon |
52
+ | `rnx setup` | configure optional local conveniences |
53
53
  | `rnx compat` | check package compatibility |
54
54
  | `rnx report-issue` | send an explicitly approved compatibility report |
55
55
  | `rnx desktop` | launch or install the desktop companion |
56
- | `rnx daemon` | manage the optional background bridge service |
56
+ | `rnx daemon` | manage the recommended background bridge service |
57
57
  | `rnx version` | show the CLI + engine runtime versions you are running |
58
58
  | `rnx upgrade` | update the rnx CLI and engine runtime to the latest |
59
59
  | `rnx serve` | run the rnx bridge in the foreground |
@@ -92,7 +92,7 @@ skills for working with the rnx native preview engine:
92
92
  | --- | --- |
93
93
  | `/rnx-debug` | Debug rendering, animation, gesture, performance, and accessibility issues in a React Native app running under rnx. Reach for this whenever an animation looks wrong (janky, stutters, snaps, only updates once, or doesn't move at all), a swipe/transition/gesture misbehaves or feels broken, scrolling drops frames or feels slow, the UI renders the wrong tree/props, or a screen reader can't reach something — and drive the rnx CLI debug tooling first, not screenshots or ad-hoc logging. |
94
94
  | `/rnx-perf` | Optimize rnx engine and app performance — scroll jank, dropped frames, slow animation, idle CPU, memory growth, and "smooth normally but laggy under load" (video calls, busy machines). Covers measuring on the right thread with the right browser, proving each perf tier actually engages via its counters, a CPU-contention test harness, and the map of existing perf machinery so you improve it instead of reinventing it. For general app debugging load /rnx-debug first. |
95
- | `/rnx-setup` | Get rnx connected to your React Native app — from `rnx setup` to a driveable sim |
95
+ | `/rnx-setup` | Get rnx connected to your React Native app with no project setup |
96
96
  | `/rnx-test` | Run automated tests against your React Native app under rnx with Maestro YAML or Detox/Jest |
97
97
  | `/rnx-visual` | Pixel-level rendering comparison between rnx and native iOS — fonts, gradients, shadows, image fidelity |
98
98
 
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  name: rnx-setup
3
- description: Get rnx connected to your React Native app — from `rnx setup` to a driveable sim
3
+ description: Get rnx connected to your React Native app with no project setup
4
4
  ---
5
5
 
6
6
  # rnx setup
7
7
 
8
8
  you want to drive a React Native app with rnx from the CLI. this skill
9
- takes you from `rnx setup` to a connected, pinned sim that every other
10
- rnx skill assumes exists. no per-app rnx install is required. if
9
+ takes you from a running development server to a connected, pinned sim that
10
+ every other rnx skill assumes exists. rnx requires no project setup or per-app
11
+ install. if
11
12
  `rnx describe` already
12
13
  returns a tree, you're past this skill — load `/rnx-debug` for
13
14
  debugging or `/rnx-test` for writing tests.
@@ -58,7 +59,8 @@ debugging or `/rnx-test` for writing tests.
58
59
  ## first move
59
60
 
60
61
  ```sh
61
- rnx setup # one-time guided setup; installs daemon
62
+ rnx daemon status # the persistent service makes agent commands much faster
63
+ rnx daemon install # enable it when missing on a supported personal machine
62
64
  rnx compat --json # scan the app's native package compatibility
63
65
  rnx open 8081 # load a metro/expo dev server
64
66
  rnx list # confirm exactly one sim is reachable
@@ -66,6 +68,15 @@ rnx use <id> # pin it for the rest of the workflow
66
68
  rnx describe # smoke test — should print a render tree
67
69
  ```
68
70
 
71
+ the background service keeps the local bridge and runtime ready between
72
+ commands. without it, rnx still works by starting an on-demand bridge, but
73
+ inspect, interaction, and test commands pay repeated startup cost. if the user
74
+ declined it during onboarding, `rnx daemon install` is the direct way to enable
75
+ it. CI does not need or install the service.
76
+
77
+ bare `rnx` opens ConnectRN for a human to choose among local apps. agents and
78
+ scripts should use `rnx open <port-or-url>` so the target is explicit.
79
+
69
80
  if you do not know the port, run `rnx open` with no target and pick from
70
81
  the detected dev servers. for hosted or unusual targets, pass the URL
71
82
  explicitly:
@@ -118,7 +129,8 @@ rnx runtime list # is at least one engine runtime installed?
118
129
  rnx open <port> # does loading explicitly work?
119
130
  ```
120
131
 
121
- if daemon is down: run `rnx setup`, or `rnx serve` in another shell for
132
+ if the daemon is not installed: run `rnx daemon install`. if the registered
133
+ daemon is down, run `rnx daemon restart`, or `rnx serve` in another shell for
122
134
  a foreground bridge. if no runtime is installed, `rnx open` installs it
123
135
  before launching. if open errors with "port unreachable": confirm your dev
124
136
  server is actually serving — the bundler has to be up before rnx can
@@ -361,7 +361,7 @@ export async function ensureDaemonRunning(
361
361
  }
362
362
  if (shouldSkipPersistentDaemon()) {
363
363
  throw new AgentDaemonError(
364
- `no rnx bridge on port ${port}. run \`rnx setup\` to install the background daemon, or \`rnx serve\` in another shell.`,
364
+ `no rnx bridge on port ${port}. run \`rnx daemon install\` to enable the faster background service, or \`rnx serve\` in another shell.`,
365
365
  'DEV_HOST_REFUSED',
366
366
  )
367
367
  }
package/src/home-paths.ts CHANGED
@@ -187,6 +187,8 @@ export function configFilePath(): string {
187
187
 
188
188
  export interface SharedConfig {
189
189
  telemetry?: boolean
190
+ onboardingVersion?: number
191
+ simulatorDriver?: 'electron' | 'playwright'
190
192
  settings?: Record<string, unknown>
191
193
  [key: string]: unknown
192
194
  }
@@ -222,6 +224,26 @@ export function writeSharedConfig(patch: Partial<SharedConfig>): SharedConfig {
222
224
  return next
223
225
  }
224
226
 
227
+ const CURRENT_ONBOARDING_VERSION = 1
228
+
229
+ export type SimulatorDriverPreference = 'electron' | 'playwright'
230
+
231
+ export function isOnboardingComplete(): boolean {
232
+ return readSharedConfig().onboardingVersion === CURRENT_ONBOARDING_VERSION
233
+ }
234
+
235
+ export function readSimulatorDriverPreference(): SimulatorDriverPreference | null {
236
+ const driver = readSharedConfig().simulatorDriver
237
+ return driver === 'electron' || driver === 'playwright' ? driver : null
238
+ }
239
+
240
+ export function writeOnboardingPreferences(driver: SimulatorDriverPreference): void {
241
+ writeSharedConfig({
242
+ onboardingVersion: CURRENT_ONBOARDING_VERSION,
243
+ simulatorDriver: driver,
244
+ })
245
+ }
246
+
225
247
  export interface PrivacyPreferences {
226
248
  productAnalytics: boolean
227
249
  crashReports: boolean
@@ -1,6 +1,6 @@
1
1
  // rnx metro plugin for opt-in dev shell and production bundle integration.
2
2
  // shell assets come from an engine runtime under ~/.sootsim/runtimes/, fetched
3
- // by `sootsim runtime install` / `sootsim setup`. ordinary localhost requests
3
+ // by `rnx runtime install`. ordinary localhost requests
4
4
  // follow active; a version-owned localhost origin stays on its exact directory
5
5
  // when active changes, so one loaded shell cannot mix runtime chunk trees.
6
6
  //
@@ -9,7 +9,7 @@ import { isValidRuntimeVersion } from '@contrast/runtime-delivery'
9
9
  import { readActiveRuntime, runtimeDir } from './home-paths.ts'
10
10
 
11
11
  export const SOOTSIM_RUNTIME_MISSING_MESSAGE =
12
- '[rnx] no engine runtime installed — run `rnx setup`, or `rnx runtime install`'
12
+ '[rnx] no engine runtime installed. run `rnx runtime install`'
13
13
 
14
14
  // --- dev-checkout mode boundary --------------------------------------------
15
15
  //
@@ -1,4 +0,0 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- function p(){console.error(" no rnx desktop companion found."),console.error(""),console.error(" install the desktop app:"),console.error(" rnx desktop install"),console.error(""),console.error(" or run setup to install the background daemon:"),console.error(" rnx setup"),console.error("")}function t(r){console.error(""),console.error(` no sim is connected to the rnx bridge on port ${r}.`),console.error(""),console.error(" start your app dev server, then open it in rnx:"),console.error(" npx expo start --localhost --port 8081"),console.error(" rnx open 8081"),console.error(""),console.error(" then inspect the live app:"),console.error(" rnx describe")}async function a(r,n,s){let e=[];try{e=await r.listSims()}catch{}if(console.error(""),e.length===0){t(n);return}console.error(` no sim with id "${s}" is connected to the bridge on port ${n}.`),console.error(""),console.error(" connected sims:");for(let o of e){let i=[o.isPrimary?"primary":null,o.readyState,o.userVisible===!1?"hidden":o.userVisible===!0?"visible":null,o.userFocused?"focused":null].filter(Boolean).join(", ");console.error(` ${o.id} (${i})`)}console.error(""),console.error(" pass a valid --sim id, or run `rnx list` to see all sessions.")}export{p as a,t as b,a as c};
@@ -1,15 +0,0 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a as ue,b as Fe}from"./chunk-6NSUY346.js";import{a as qe,b as ze,d as Ye}from"./chunk-DSF4WC4X.js";import{a as Me,b as Be,c as I,d as le,e as L,f as ce,g as De,h as de,i as Le,j as Ae,l as We,m as Ke,n as Ve}from"./chunk-4AOAJXE2.js";import{b as ie,d as Re}from"./chunk-RH6FJI5O.js";import{a as He}from"./chunk-RASWCAJJ.js";import{a as je}from"./chunk-ELNSQ352.js";import{m as A}from"./chunk-TF6VBUZ7.js";import{m as Ge,p as Je}from"./chunk-H4IF54WS.js";import{b as Ue,f as Ee,g as B,h as $,i as D,k as _e,l as se,m as ae,o as Oe,p as Te,q as E,r as P,s as _}from"./chunk-EHQHK7KN.js";import{e as Qe}from"./chunk-ESVF72YH.js";import{c as Ne}from"./chunk-3Y7NWE22.js";import{f as Ce}from"./chunk-M6DC6JZL.js";import{J as re,M as oe,O as M,Q as ke,l as ne}from"./chunk-DFTG53TX.js";import{a as te}from"./chunk-BQE4E24T.js";import{spawn as rt,spawnSync as ot}from"node:child_process";import O from"node:fs";import Tt from"node:os";import C from"node:path";import{WebSocket as me}from"ws";function Ze(e){return new Error(`could not resolve a native bundle for ${e}. pass an explicit bundle URL or open Connect and choose the app there.`)}function kt(e,n){return e?.includes("/one/metro-entry.bundle")?"one":typeof n=="string"&&n?"expo":"unknown"}function Ct(e,n,t){return`${e}//${n}:${t}`}function Rt(e){if(typeof window>"u")return!1;try{let n=new URL(e);return I(n.hostname)&&I(window.location.hostname)&&n.origin!==window.location.origin}catch{return!1}}async function Xe(e,n){let t={...n,cache:n?.cache??"no-store"};return Rt(e)?fetch(`/__fetch-proxy?url=${encodeURIComponent(e)}`,t):fetch(e,t)}function Ut(e){return e==="https:"?443:80}function Et(e){let n=e.pathname||"/";return(n==="/"||n==="")&&!e.search&&!e.hash}async function et(e){try{let n=await fetch("/__server-scan",{cache:"no-store"});if(!n.ok||!(n.headers.get("content-type")||"").toLowerCase().includes("json"))return null;let t=await n.json();if(!Array.isArray(t))return null;let r=t.find(o=>!!o&&typeof o=="object"&&o.port===e&&typeof o.bundleUrl=="string");return r?{bundleUrl:de(r.bundleUrl),port:e,framework:typeof r.framework=="string"?r.framework:"unknown",projectName:typeof r.projectName=="string"?r.projectName:void 0}:null}catch{return null}}async function tt(e,n){let t=e.replace(/\/+$/,"");try{let r=await Xe(`${t}/`,{headers:{"expo-platform":"ios"}});if(r.ok){let o=await r.json(),i=o?.extra?.expoClient||o?.extra||{},s=typeof o?.launchAsset?.url=="string"?o.launchAsset.url:void 0,a=s?De(s,t):void 0;if(a||i.name)return{bundleUrl:de(a||`${t}${ce}`),port:n,framework:kt(a,i.sdkVersion),projectName:i.name}}}catch{}try{let r=await Xe(`${t}/status`);if(r.ok&&(await r.text()).includes("packager-status:running"))return{bundleUrl:`${t}${ce}`,port:n,framework:"metro"}}catch{}return null}async function _t(e,n){try{if(I(new URL(e).hostname)){let t=await et(n);if(t)return t}}catch{}return tt(e,n)}async function Ot(e){let n=await et(e);return n||((await Promise.all(Me.map(r=>tt(Be("http:",r,e),e)))).find(r=>r!==null)??null)}async function nt(e){let n=e.trim();if(/^\d+$/.test(n)){let a=parseInt(n,10),l=await Ot(a);if(l)return l;throw Ze(`localhost:${a}`)}let t=n.startsWith("http")?n:`http://${n}`,r;try{r=new URL(t)}catch{throw new Error(`could not parse "${e}". pass a dev-server port, a dev-server base URL, or a full bundle URL.`)}let o=r.protocol||"http:",i=r.port?parseInt(r.port,10):Ut(o),s=Ct(o,r.hostname,i);if(Et(r)){let a=await _t(s,i);if(a)return a;throw Ze(s)}return{bundleUrl:r.toString(),port:i,framework:"unknown"}}var Mt=12e4,it=100,Bt=5e3,st=1e4,Dt={rn:"/rn",connectrn:"/rn","connect-rn":"/rn",clock:"/app/clock","native-ui":"/app/native-ui",tamagui:"/app/tamagui",settings:"/app/settings",photos:"/app/photos",camera:"/app/camera"};function y(e){return new Promise(n=>setTimeout(n,e))}function at(e){let n=process.env[e]?.trim();if(!n)return null;let t=Number(n);return Number.isInteger(t)&&t>0?t:null}function Lt(){let e=at("SOOTSIM_DRIVER_CONNECT_TIMEOUT_MS")??at("SOOTSIM_PW_CONNECT_TIMEOUT_MS")??Mt;return{timeoutMs:e,hostTimeoutMs:e+Bt,intervalMs:it,attempts:Math.max(1,Math.ceil(e/it))}}function lt(e){return e==="electron"||e==="playwright"}function pe(e,n){return n==="playwright"?e.meta?.sootsimHostDriver==="playwright":e.userAgent?.includes("Electron/")===!0}function At(e,n){return e.includes("--headless")?!0:e.includes("--headed")?!1:n==="playwright"&&process.platform==="linux"&&!process.env.DISPLAY&&!process.env.WAYLAND_DISPLAY?(console.error(" no display detected \u2192 running playwright headless (override with --headed)"),!0):!1}function z(e){return e.trim()}var gt=/^[A-Za-z][A-Za-z0-9+.-]*:/;function Nt(e){let n=e.trim();if(!n)throw new Error("expected <url-or-route>");return gt.test(n)||n.startsWith("/")?n:`/${n}`}function Ft(e){return e!==null&&typeof e=="object"}function jt(e){let n=e.trim();return n?n.startsWith("/")?!0:gt.test(n)?!/^https?:\/\//i.test(n):!1:!1}async function Ht(e,n=!1){let t=oe();ct(e,n,t);let r=se(e);if((n||r!==null)&&await fe(e,250))return e;if(t&&M(t)&&await fe(t.bridgePort,500))return t.bridgePort;if(t&&M(t))throw new Error(`rnx bridge lockfile is fresh (port ${t.bridgePort}) but the bridge is not reachable. run \`rnx daemon restart\` or \`rnx daemon uninstall\`.`);await Wt();let o=Kt(["serve","--quiet","--port",String(e)]),i=null;o.once("exit",(a,l)=>{i=String(a??l??"unknown")}),o.unref();let s=Date.now()+st;for(;Date.now()<s;){let a=oe();if(ct(e,n,a),a&&M(a)&&await fe(a.bridgePort,250))return console.error(` started local bridge on port ${a.bridgePort}; run \`sootsim setup\` to install the background daemon`),a.bridgePort;if(i)throw new Error(`rnx bridge exited before becoming ready (exit ${i})`);await y(150)}throw new Error(`rnx bridge did not start within ${Math.round(st/1e3)}s`)}function ct(e,n,t){if(!(!n||!t||!M(t)||t.bridgePort===e))throw new Error(`${te.commandName} open: requested bridge port ${e}, but the active daemon owns port ${t.bridgePort}. explicit --port never selects another bridge; stop that daemon or use an isolated SOOTSIM_HOME.`)}async function Wt(){let e=re();if(e&&O.existsSync(ne(e)))return;console.error(" installing rnx engine runtime...");let{runRuntime:n}=await import("./runtime-JTYB4CM7.js");await n(["install"],{})}function Kt(e){let n=process.argv[1];return n&&O.existsSync(n)?rt(process.execPath,[n,...e],{detached:!0,stdio:"ignore",env:process.env}):rt(te.commandName,e,{detached:!0,stdio:"ignore",env:process.env})}function fe(e,n){return new Promise(t=>{let r=new me(`ws://127.0.0.1:${e}`,{handshakeTimeout:n}),o=!1,i=s=>{o||(o=!0,r.readyState===me.OPEN?r.close():r.readyState===me.CONNECTING&&r.terminate(),t(s))};r.once("open",()=>i(!0)),r.on("error",()=>i(!1)),setTimeout(()=>i(!1),n)})}function he(e){try{let n=new URL(e),t=n.pathname.replace(/\/+$/,"")||"/";return n.searchParams.has("open")||n.searchParams.has("port")||n.searchParams.has("bundle")||n.searchParams.has("demo")||n.pathname.includes("/sootsim/index.html")||t==="/sootsim"||n.pathname==="/__soot"||n.pathname==="/__soot/"||t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function Vt(e){try{let n=new URL(e,"http://sootsim.local");if(n.origin!=="http://sootsim.local")return!1;let t=n.pathname.replace(/\/+$/,"")||"/";return t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function qt(e,n){let t=new URL(e,"http://sootsim.local"),r=new URL(n),o=G(r.pathname),i=t.pathname.startsWith("/__soot/")?t.pathname.slice(7):t.pathname;return r.pathname=`${o}${i}`,r.search=t.search,r.hash=t.hash,r.toString()}function zt(e){try{let n=new URL(e).pathname.replace(/\/+$/,"")||"/";return/^\/preview\/[^/]+$/.test(n)||/^\/build\/.+/.test(n)}catch{return!1}}async function tr(e){let n=z(e);return(await be(n)).bundleUrl}function Gt(e){try{let n=new URL(e.startsWith("http")?e:`http://${e}`),t=n.pathname||"/";if(t!=="/"&&t!==""||n.search||n.hash||!I(n.hostname))return null;let r=n.port?Number(n.port):n.protocol==="https:"?443:80;return Number.isFinite(r)&&r>0?r:null}catch{return null}}async function be(e){let n=z(e),t=/^\d+$/.test(n)?Number(n):Gt(n);if(t&&t>0){let r=await Ae(t);if(r)return{bundleUrl:r.bundleUrl,port:r.port,framework:r.framework,projectName:r.projectName}}return nt(n)}function G(e){let n=e.replace(/\/+$/,"")||"/";return n==="/__soot"||n.startsWith("/__soot/")?"/__soot":""}function Jt(e,n){let t=z(e),r=new URL(n),o=G(r.pathname);return r.pathname=`${o}/rn`,r.searchParams.delete("bundle"),r.searchParams.delete("demo"),r.searchParams.delete("app"),r.searchParams.delete("open"),r.searchParams.delete("port"),/^\d+$/.test(t)?r.pathname=`${o}/rn/${t}`:(r.pathname=`${o}/rn`,r.searchParams.set("open",t)),r.toString()}function ht(e){let n=z(e);return/^\d+$/.test(n)||/^https?:\/\//i.test(n)?!0:/^(localhost|127\.0\.0\.1|\[::1\]|[^/]+\.localhost):\d+(?:\/.*)?$/i.test(n)}async function Qt(e,n,t={}){let r=t.resolvedBundle??await be(e),o=new URL(n),i=G(o.pathname);o.pathname=`${i}/rn`,o.searchParams.delete("open"),o.searchParams.delete("port"),o.searchParams.delete("demo"),o.searchParams.delete("app");let s=t.hot===void 0?r.bundleUrl:Le(r.bundleUrl,t.hot);return o.searchParams.set("bundle",s),o.toString()}function Yt(e){return e.startsWith("~/")?C.join(Tt.homedir(),e.slice(2)):C.isAbsolute(e)?e:C.resolve(process.cwd(),e)}function Zt(e){let n={},t={};for(let o=0;o<e.length;o++){if(e[o]==="--replace"){let i=e[o+1];i||(console.error(" rnx open: --replace expects <module>=<file>"),process.exit(1));let s=i.indexOf("=");(s<=0||s===i.length-1)&&(console.error(" rnx open: --replace expects <module>=<file>"),process.exit(1));let a=i.slice(0,s).trim(),l=Yt(i.slice(s+1).trim());O.existsSync(l)||(console.error(` rnx open: replacement file not found: ${l}`),process.exit(1)),n[a]={file:l},o++;continue}if(e[o]==="--remap"){let i=e[o+1],s=i?i.indexOf("="):-1;(!i||s<=0||s===i.length-1)&&(console.error(" rnx open: --remap expects <host:port>=<host:port>"),process.exit(1)),t[i.slice(0,s).trim()]=i.slice(s+1).trim(),o++;continue}}let r={};return Object.keys(n).length>0&&(r.modules=n),Object.keys(t).length>0&&(r.network={remap:t}),r.modules||r.network?r:void 0}async function Xt(e){if(!e)return null;let n=await Ke(e.bundleUrl);return n?je(n):null}async function en(e){if(O.existsSync(C.join(ne(e),"index.html")))return;console.error(` installing configured engine runtime ${e}...`);let n=await Ce.install({version:e,setActive:!1,protectVersions:ke()});console.error(` installed engine runtime ${n.version}`)}function tn(e,n){let t=n??(ue()?void 0:re()??void 0);if(!t)return e;let r=new URL(e);if(!I(r.hostname)){if(!n)return e;throw new Error(`runtimeVersion ${t} requires a local rnx host; got ${r.origin}`)}return r.hostname=Fe(t),r.toString()}function wt(){return _e().shellBaseUrl}function nn(e){return se(e)?.shellBaseUrl??Ue(e)??wt()}async function rn(e,n){try{let t=new URL(e),r=t.searchParams.get("bundle")||"";if(!r||!n)return e;let o=We({bundleUrl:r,projectDir:n.appDir});if(o.length===0)return e;let i=await on(o);return i.length===0?e:(t.searchParams.set("appFonts",Ve(i)),t.toString())}catch{return e}}async function on(e){let n=await Promise.all(e.map(async r=>{let o=new AbortController,i=setTimeout(()=>o.abort(),1500);try{let s=await fetch(r.url,{method:"HEAD",signal:o.signal});return s.status>=200&&s.status<400?r:null}catch{return null}finally{clearTimeout(i)}})),t=[];for(let r of n)r!==null&&t.push(r);return t}async function sn(e,n,t={}){if(!e)return new URL(n).toString();if(he(e))return new URL(e).toString();if(Vt(e))return qt(e,n);let r=Dt[e.toLowerCase()];if(r){let o=new URL(n),i=G(o.pathname);return o.pathname=`${i}${r}`,o.toString()}return ht(e)?Qt(e,n,t):Jt(e,n)}async function an(e,n){try{let t=new URL(e),r=t.searchParams.get("bundle")||"";if(!r||!n)return e;let o=qe({bundleUrl:r,projectDir:n.appDir});return!o||o.imageUrl&&!await ln(o.imageUrl)?e:(t.searchParams.set("appSplash",ze(o)),t.toString())}catch{return e}}async function ln(e){let n=new AbortController,t=setTimeout(()=>n.abort(),1500);try{let r=await fetch(e,{method:"HEAD",signal:n.signal});return r.status>=200&&r.status<400}catch{return!1}finally{clearTimeout(t)}}async function q(e,n=wt(),t={}){let r=await sn(e,n,t),o=await an(await rn(r,t.project),t.project);if(!t.device)return o;let i=new URL(o);return i.searchParams.set("device",t.device),i.toString()}function dt(e,n){let t=e?.url||e?.origin||n;try{let r=new URL(t);return r.searchParams.delete("bundle"),r.searchParams.delete("demo"),r.searchParams.delete("app"),r.searchParams.delete("open"),r.searchParams.delete("port"),r.searchParams.delete("inspectOpen"),r.searchParams.delete("appFonts"),r.searchParams.delete("appSplash"),r.toString()}catch{return n}}async function cn(e,n,t,r={}){let o=new URL(await q(e,n,r));return o.searchParams.set("inspectOpen",t),o.toString()}async function dn(e,n,t,r={}){let o=r.attempts??30,i=r.intervalMs??500,s=r.minNodeCount??10;for(let a=0;a<o;a++){let l=P(e,{commandTimeoutMs:n,simId:t,simIdSource:"flag"});try{let d=await l.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount()) || 0)()"});if(typeof d=="number"&&d>s)return{bridge:l,count:d}}catch{}l.close(),await y(i)}return null}function un(e){if(!e)return null;try{let n=new URL(e);if(n.searchParams.has("bundle")){let t=n.searchParams.get("bundle")||"";try{let r=new URL(t),o=r.pathname.length>36?`...${r.pathname.slice(-36)}`:r.pathname;return`bundle ${r.host}${o}`}catch{return"bundle"}}return n.searchParams.has("port")?`connect :${n.searchParams.get("port")||""}`:n.searchParams.has("open")?`connect ${n.searchParams.get("open")||""}`:n.searchParams.has("demo")?`demo ${n.searchParams.get("demo")||"default"}`:n.pathname.includes("/sootsim/index.html")||n.pathname==="/sootsim/"||n.pathname==="/sootsim"?"embedded rnx":null}catch{return null}}function mn(e){let n=e.indexOf(":");if(n<=0)return e.length>24?`${e.slice(0,21)}\u2026`:e;let t=e.slice(0,n),r=e.slice(n+1),o=r.length>12?`${r.slice(0,8)}\u2026`:r;return t==="TM_SESSION"||t==="CLAUDE_CODE_SESSION_ID"||t==="CODEX_THREAD_ID"?`agent ${o}`:`${t} ${o}`}function nr(e,n){if(e.length===0){console.log(" no sims connected");return}console.log(` connected sims (${e.length}):
5
- `);for(let t of e){let r=t.lockedBy&&t.lockExpiresAt?`locked by ${mn(t.lockedBy)} (${Math.max(0,Math.round((t.lockExpiresAt-Date.now())/1e3))}s)`:"",o=[t.isPrimary?"primary":"",t.id===n?"selected":"",t.readyState,t.userVisible===!1?"hidden":t.userVisible===!0?"visible":"",t.attachedCliCount&&t.attachedCliCount>0?"in use":"",t.userFocused?"focused":"",r].filter(Boolean);console.log(` ${t.id}${o.length?` [${o.join(", ")}]`:""}`);let i=un(t.url);if(i)console.log(` loaded: ${i}`);else if(t.url){let a=t.url.length>96?`${t.url.slice(0,93)}\u2026`:t.url;console.log(` url: ${a}`)}else t.origin&&console.log(` origin: ${t.origin}`);let s=pn(t);s&&console.log(` engine: ${s}`),t.title&&console.log(` title: ${t.title}`),t.visibilityState&&t.visibilityState!=="visible"&&console.log(` visibility: ${t.visibilityState}`),console.log(` connected: ${ut(Date.now()-t.connectedAt)}`),t.lastActiveAt&&t.lastActiveAt>0&&console.log(` last active: ${ut(Date.now()-t.lastActiveAt)}`)}}function pn(e){let n=e.url||e.origin||"";if(!n)return null;try{let t=new URL(n).port;return t==="5173"?"dev \u2014 local source (:5173)":t==="3000"?"Contrast app embedded (:3000)":ue()?`dev \u2014 local build (:${t||"?"})`:`runtime \u2014 published engine (:${t||"?"})`}catch{return null}}function ut(e){let n=Math.max(0,Math.round(e/1e3));return n<60?`${n}s ago`:n<3600?`${Math.round(n/60)}m ago`:n<86400?`${Math.round(n/3600)}h ago`:`${Math.round(n/86400)}d ago`}async function rr(e,n,t,r={}){let o=r.attempts??30,i=r.intervalMs??500;for(let s=0;s<o;s++){let a=P(e,{commandTimeoutMs:n});try{let d=(await a.listSims()).find(t);if(d)return d}catch{}finally{a.close()}await y(i)}return null}async function fn(e,n,t,r,o={}){let i=o.attempts??30,s=o.intervalMs??500,a=!!r&&Number.isInteger(r)&&r>1,l=()=>a&&r!==void 0&&!we(r);for(let d=0;d<i;d++){if(l())return{kind:"host-exit"};let c=P(e,{commandTimeoutMs:n});try{let g=(await c.listSims()).find(t);if(g)return l()?{kind:"host-exit"}:{kind:"match",sim:g}}catch{}finally{c.close()}if(l())return{kind:"host-exit"};await y(s)}return{kind:"timeout"}}async function gn(e,n,t,r={}){let o=r.attempts??20,i=r.intervalMs??250;for(let s=0;s<o;s++){let a=P(e,{commandTimeoutMs:n});try{let d=(await a.listSims()).find(c=>c.id===t);if(!d||d.readyState!=="open")return!0}catch{return!0}finally{a.close()}await y(i)}return!1}function hn(e){let n=e.meta;if(!n||n.sootsimHostDriver!=="playwright")return null;let t=Number(n.sootsimHostPid);return!Number.isInteger(t)||t<=1||t===process.pid?null:t}function wn(e){if(!e.connectAckFile)return!1;try{return O.writeFileSync(e.connectAckFile,`${JSON.stringify({connectedAt:Date.now(),pid:e.pid??null})}
6
- `,{flag:"w"}),!0}catch{return!1}}function mt(e){if(e.diagnosticLogPath)try{let n=O.readFileSync(e.diagnosticLogPath,"utf8").trim();if(!n){console.error(` ${C.basename(e.diagnosticLogPath)} was empty`);return}let t=n.length>4e3?`\u2026
7
- ${n.slice(-4e3)}`:n;console.error(` ${C.basename(e.diagnosticLogPath)}:`),console.error(t)}catch(n){let t=n instanceof Error?n.message:String(n);console.error(` failed to read ${C.basename(e.diagnosticLogPath)}: ${t}`)}}function we(e){try{return process.kill(e,0),!0}catch(n){return n?.code==="EPERM"}}async function bn(e,n=2500){let t=Date.now()+n;for(;Date.now()<t;){if(!we(e))return!0;await y(100)}return!we(e)}function vn(e){let n=ot("ps",["-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),t=ot("ps",["eww","-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(n.status!==0||t.status!==0)return!1;let r=(n.stdout||"").trimEnd(),o=(t.stdout||"").trimEnd();return(o.startsWith(r)?o.slice(r.length):o).includes("SOOTSIM_PW_URL=")}async function ge(e,n){let t=new Set(n),r=new Set;for(let o of e){if(!t.has(o.id))continue;let i=hn(o);i&&r.add(i)}for(let o of r){if(!vn(o)){console.log(` skipped pid ${o}: not a rnx playwright host (stale sim record)`);continue}try{process.kill(o,"SIGTERM")}catch{}if(await bn(o)){console.log(` closed playwright host process ${o}`);continue}try{process.kill(o,"SIGKILL"),console.log(` force-closed playwright host process ${o}`)}catch{}}}function J(e,n){if(n){let o=n.trim(),i=e.find(s=>s.id===o);if(!i)throw new Error(`no sim connected with id ${o}`);return i}let t=e.find(o=>o.isPrimary&&o.readyState==="open");if(t)return t;let r=e.find(o=>o.readyState==="open");if(r)return r;throw new Error("no sim connected")}function pt(e,n,t){let[r,o]=[e,n.url].map(i=>{if(!i)return i;try{let s=new URL(i);if(s.searchParams.has("sootsimConfig"))return s.searchParams.set("sootsimConfig","[redacted]"),s.toString()}catch{}return i});console.log(` ${t==="current sim"?"loaded":"opened"}: ${r} [${t}]`),console.log(` current sim: ${n.id}`),console.log(JSON.stringify({simId:n.id,url:o},null,2))}async function ft(e,n,t){if(t.includes("--no-describe"))return;let r=process.env.SOOTSIM_QUIET_TARGET_NOTICE;process.env.SOOTSIM_QUIET_TARGET_NOTICE="1";try{await yn(e,n,{stableMs:150,maxMs:400});let o=P(e,{commandTimeoutMs:3e3,simId:n,cliLabel:"open --describe",simIdSource:"flag"});try{let i=null;try{i=await o.send({type:"evaluate",code:Ge})}catch{}if(i&&!(i.flag===!0&&!i.loadingText&&Je(i))){let c=i.loadingText?`still showing "${i.loadingText}"`:i.flag!==!0?"guest ready event has not fired":i.targets<=0?"no visible app content is inspectable yet":"app tree is still stabilizing";console.log(` app still loading: ${c} (nodes: ${i.nodes}, targets: ${i.targets})`),console.log(" before interacting, run: rnx wait ready --max-ms 120000")}let a=`(async () => {
8
- const t = window.__sootsimTest
9
- const ms = window.SootSim?.bridges?.mainShell
10
- if (!t) return null
11
- let shell = null
12
- try { shell = ms?.getState ? await ms.getState() : null } catch {}
13
- const tree = await t.dumpTree(12, ${JSON.stringify({describe:!0,verbose:!1,filter:""})})
14
- return { tree, shell }
15
- })()`,l=await o.send({type:"evaluate",code:a});if(!l?.tree)return;if(console.log(""),l.shell?.state){let d=[`state=${l.shell.state}`,l.shell.activeApp?`app=${l.shell.activeApp}`:null].filter(Boolean);console.log(` shell: ${d.join(" ")}`)}console.log(l.tree)}finally{o.close()}}catch{}finally{r===void 0?delete process.env.SOOTSIM_QUIET_TARGET_NOTICE:process.env.SOOTSIM_QUIET_TARGET_NOTICE=r}}async function yn(e,n,t){let r=Date.now()+t.maxMs,o="(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()",i=P(e,{commandTimeoutMs:2e3,simId:n,simIdSource:"flag"});try{let s=-1,a=0;for(;Date.now()<r;){let l=-1;try{let d=await i.send({type:"evaluate",code:o});typeof d=="number"&&(l=d)}catch{}if(l>=0&&l===s){if(Date.now()-a>=t.stableMs)return}else s=l,a=Date.now();await y(50)}}finally{i.close()}}async function Sn(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs});t.positional.length!==1&&(console.error(" rnx open: expected exactly one <url-or-route>"),console.error(" examples: rnx open /settings | rnx open myapp://settings"),process.exit(1));let r;try{r=Nt(t.positional[0]??"")}catch(s){console.error(` rnx open: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}let o=_(t),i=t.simId?` --sim ${t.simId}`:"";try{let s=await o.send({type:"call",path:"SootSim.bridges.test.openDeepLink",args:[r]});if(Ft(s)&&s.ok===!1)throw new Error(typeof s.error=="string"?s.error:"deep-link dispatch failed");console.log(` opened deep link: ${r}`)}catch(s){console.error(` link failed: ${s instanceof Error?s.message:String(s)}`),await A(o,{errorsCommand:`rnx get errors 5${i}`,warningsCommand:`rnx get warnings 5${i}`,requestsCommand:`rnx get requests 5${i}`}),process.exit(1)}finally{o.close()}}async function or(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--new","--headless","--headed","--ephemeral","--hot","--no-hmr","--no-describe"],stripValueFlags:["--base-url","--replace","--driver","--profile","--cdp-port","--device","--viewport"]}),r=e.find((p,m)=>e[m-1]==="--profile"),o=e.includes("--ephemeral"),i=e.find((p,m)=>e[m-1]==="--cdp-port"),s=i?Number(i):void 0;i&&(!Number.isFinite(s)||s<=0)&&(console.error(` rnx open: --cdp-port must be a positive port number, got "${i}"`),process.exit(1)),r&&o&&(console.error(" rnx open: --profile cannot be combined with --ephemeral"),process.exit(1));let a=r?Ne(r).id:void 0,l=e.includes("--new")||!!a||o,d=Zt(e);l&&t.simIdSource==="flag"&&(console.error(" rnx open: --new, --profile, and --ephemeral cannot be combined with --sim"),process.exit(1));let c=t.positional[0]||"";if(jt(c)){l&&(console.error(" rnx open: deep links target the current app; remove --new, --profile, or --ephemeral"),process.exit(1)),await Sn(e,n);return}if(zt(c)){let p=(()=>{try{return I(new URL(c).hostname)}catch{return!1}})();console.log(" that\u2019s an rnx preview/build link \u2014 a full player page, not a driveable sim."),console.log(" opening it in your browser for viewing\u2026");try{await Ye(c,{background:!1})}catch(m){console.error(` could not launch a browser: ${m instanceof Error?m.message:String(m)}`),console.error(` open it yourself: ${c}`),process.exit(1)}console.log(p?" to drive it under the CLI, point `rnx open` at the app\u2019s dev port instead (e.g. `rnx open 8081`).":" the CLI can\u2019t drive a remote preview (the engine only attaches to the local bridge from localhost). to drive the app, run it locally and `rnx open <port>`.");return}let u=ht(c)?await be(c):void 0,g=await Xt(u),T=await He(g),N=T?.runtimeVersion,F=le(le(T?{...T,runtimeVersion:void 0}:void 0,n.runtimeConfig),d);N&&await en(N);let Q=e.find((p,m)=>e[m-1]==="--base-url");if(Q&&!t.explicitPort){let p=ae(Q);p&&(t.wsPort=p)}t.wsPort=await Ht(t.wsPort,t.explicitPort);let R=e.find((p,m)=>e[m-1]==="--driver")||"";R&&!lt(R)&&(console.error(` unknown driver "${R}" \u2014 run \`rnx list --drivers\``),process.exit(1));let S=lt(R)?R:"playwright",vt=At(e,S);s&&S!=="playwright"&&(console.error(" rnx open: --cdp-port is only honored by the playwright driver"),process.exit(1));let ve=e.includes("--hot"),ye=e.includes("--no-hmr");ve&&ye&&(console.error(" rnx open: --hot and --no-hmr cannot be combined"),process.exit(1));let yt=ve?!0:ye?!1:R!=="playwright",k=e.find((p,m)=>e[m-1]==="--device");k&&!(k in ie)&&(console.error(` rnx open: unknown device "${k}"`),console.error(` known devices: ${Re().join(", ")}`),process.exit(1));let Y=k?ie[k]:void 0,j=e.find((p,m)=>e[m-1]==="--viewport"),H=j?/^(\d+)x(\d+)$/.exec(j):null;j&&!H&&(console.error(` rnx open: --viewport must be <width>x<height>, got "${j}"`),process.exit(1));let St=H?{width:Number(H[1]),height:Number(H[2])}:void 0,W={hot:yt,device:k,resolvedBundle:u,project:g},xt=N?`http://localhost:${t.wsPort}/`:Q||nn(t.wsPort),x=tn(xt,N),Se=e.includes("--base-url");Oe(t.wsPort,x);let $t=B();if(!l){let p=_(t),m=t.simId?` --sim ${t.simId}`:"",ee=!1;try{let f=null,V=null;try{let h=await p.listSims();if(t.simIdSource==="saved")f=h.find(w=>w.id===$t&&w.readyState==="open"&&pe(w,S))??null,f||D();else if(t.simIdSource==="flag"&&(f=J(h,t.simId),!pe(f,S)))throw new Error(`sim ${f.id} is not managed by the ${S} driver`);if(!f&&t.simIdSource!=="flag"){V=await q(c,L(x,F),W);let w=new URL(V);w.searchParams.delete("inspectOpen"),f=h.find(v=>{if(v.readyState!=="open"||!v.url||!pe(v,S))return!1;try{let Ie=new URL(v.url);return Ie.searchParams.delete("inspectOpen"),Ie.toString()===w.toString()}catch{return!1}})??null}if(!f)if(t.simIdSource!=="flag")ee=!0;else throw new Error("no sim connected");if(!ee&&f){let w=Se||he(c)?x:dt(f,x),v=V??await q(c,L(w,F),W);p.send({type:"evaluate",simId:f.id,code:`window.location.href = ${JSON.stringify(v)}`}).catch(()=>{})}}catch(h){console.error(` open failed: ${h instanceof Error?h.message:String(h)}`),await A(p,{errorsCommand:`rnx get errors 5${m}`,warningsCommand:`rnx get warnings 5${m}`,requestsCommand:`rnx get requests 5${m}`}),process.exit(1)}if(!ee&&f){await y(1500);let h=await dn(t.wsPort,t.commandTimeoutMs,f.id);h||(console.error(" timed out waiting for current sim to load target"),process.exit(1)),h.bridge.close(),$(f.id);let w=Se||he(c)?x:dt(f,x),v=V??await q(c,L(w,F),W);return pt(v,{...f,url:v},"current sim"),await ft(t.wsPort,f.id,e),t.wsPort}}finally{p.close()}}let Pt=L(x,F),xe=`cli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,$e=await cn(c,Pt,xe,W),Pe=Ee();Pe||(console.error(" could not resolve a stable owning process; refusing unsupervised sim host"),process.exit(1));let It=p=>p.url?.includes(`inspectOpen=${xe}`)??!1,U=Qe(S);U||(console.error(` unknown driver "${S}" \u2014 run \`rnx list --drivers\``),process.exit(1));let K=Lt(),b=await U.launch({url:$e,bridgePort:ae(x)??t.wsPort,headless:vt,profileId:a,ephemeralProfile:o,cdpPort:s,device:k,ownerPid:Pe,viewport:St??(Y?{width:Y.width+120,height:Y.height+60}:void 0),connectTimeoutMs:K.hostTimeoutMs});b.launched||(console.error(` ${U.name} driver: ${b.message}`),process.exit(1));let Z=await fn(t.wsPort,t.commandTimeoutMs,It,b.pid,{attempts:K.attempts,intervalMs:K.intervalMs});if(Z.kind==="host-exit"&&(mt(b),console.error(` ${U.name} host crashed \u2014 sim is no longer attached`),process.exit(1)),Z.kind==="timeout"){if(b.pid)try{process.kill(b.pid,"SIGTERM"),console.error(` closed ${U.name} host process ${b.pid}`)}catch{}mt(b),console.error(` timed out after ${K.timeoutMs}ms waiting for opened sim to connect`),process.exit(1)}let X=Z.sim;return $(X.id),wn(b),pt($e,X,`${U.name} driver`),await ft(t.wsPort,X.id,e),t.wsPort}async function bt(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--force"]}),r=e.includes("--force"),o=_(t),i=t.simId?` --sim ${t.simId}`:"";try{try{let s=await o.listSims(),a=J(s,t.positional[0]||t.simId);if(a.lockedBy&&a.lockExpiresAt&&a.lockExpiresAt>Date.now()){let l=Math.max(0,Math.round((a.lockExpiresAt-Date.now())/1e3));a.lockedByKind==="user-active"&&(console.error(` refused: ${a.id} is locked by the active user (${l}s) \u2014 that's a live human tab`),console.error(" run `rnx open --new` for a fresh investigation sim"),process.exit(1)),r||(console.error(` refused: ${a.id} is leased by ${a.lockedBy} (${l}s)`),console.error(` \`sootsim use ${a.id} --force\` to take it, or \`rnx open --new\` for a fresh sim`),process.exit(1))}await o.focusSim(a.id),$(a.id),console.log(` using: ${a.id}`)}catch(s){console.error(` use failed: ${s instanceof Error?s.message:String(s)}`),await A(o,{errorsCommand:`rnx get errors 5${i}`,warningsCommand:`rnx get warnings 5${i}`,requestsCommand:`rnx get requests 5${i}`}),process.exit(1)}}finally{o.close()}}async function ir(e,n={}){await bt(e,n)}async function sr(e,n={}){await bt(e,n)}async function ar(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--force"]}),r=e.includes("--force"),o=_(t);try{try{let i=await o.listSims(),s=J(i,t.positional[0]||t.simId),a=r&&s.lockedBy&&s.lockedByKind!=="user-active"?s.lockedBy:null,l=await o.claim(s.id,{force:r});$(s.id);let d=Math.max(0,Math.round((l.lockExpiresAt-Date.now())/1e3)),c=l.bootedCount>0?` (booted ${l.bootedCount})`:"";console.log(` claimed: ${l.simId} [${d}s]${c}`),a&&console.log(` took over from: ${a}`)}catch(i){if(i instanceof Te){let s=Math.max(0,Math.round(i.lock.expiresInMs/1e3));console.error(` claim failed: locked by ${i.lock.by} for ${s}s more`),console.error(" use --force to take it, or `rnx open --new` for a fresh sim"),process.exit(1)}console.error(` claim failed: ${i instanceof Error?i.message:String(i)}`),process.exit(1)}}finally{o.close()}}async function xn(e,n,t,r){if(r.length===0)return{closed:[],remaining:[]};await Promise.all(r.map(i=>e.closeSim(i).catch(()=>{})));let o=new Set(r);for(let i=0;i<40;i++){let s=[];try{let a=P(n,{commandTimeoutMs:t});try{s=(await a.listSims()).filter(d=>o.has(d.id)&&d.readyState==="open").map(d=>d.id)}finally{a.close()}}catch{s=[]}if(s.length===0)return{closed:[...o],remaining:[]};if(i===39)return{closed:[...o].filter(a=>!s.includes(a)),remaining:s};await y(250)}return{closed:[...o],remaining:[]}}function $n(e,n){let t=e.filter(u=>u.readyState==="open"),r=t.map(u=>u.id),o=n.explicitKeepId?.trim()||"",i=n.savedKeepId?.trim()||"",s=i?t.some(u=>u.id===i):!1,a=i&&!s?i:null,l=null,d=null,c=null;if(n.closeOthers)if(o){let u=t.find(g=>g.id===o);u?l=u.id:d=o}else if(i&&s)l=i;else{let u=t.find(g=>g.isPrimary)??t[0]??null;u&&(l=u.id,i&&!s&&(c=u.id))}return{openIds:r,keepId:l,targets:d?[]:r.filter(u=>u!==l),staleSavedId:a,missingExplicitKeepId:d,fallbackKeepId:c}}async function lr(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--all","--others"]}),r=_(t),o=t.simId?` --sim ${t.simId}`:"",i=e.includes("--all"),s=e.includes("--others");if(i||s){try{let a=await r.listSims(),l=B(),d=t.positional[0]||(t.simIdSource==="flag"?t.simId:void 0),c=$n(a,{closeOthers:s,explicitKeepId:d,savedKeepId:l});if(c.staleSavedId&&D(),c.fallbackKeepId&&($(c.fallbackKeepId),console.log(` saved sim ${c.staleSavedId} is gone \u2014 keeping primary ${c.fallbackKeepId}`)),c.missingExplicitKeepId&&(console.error(` close failed: keep sim ${c.missingExplicitKeepId} is not connected; not closing other sims`),process.exit(1)),c.targets.length===0){console.log(c.keepId?` nothing to close \u2014 only the kept sim ${c.keepId} is connected`:c.staleSavedId?` nothing to close \u2014 no sims connected (cleared stale current sim ${c.staleSavedId})`:" nothing to close \u2014 no sims connected");return}let u=await xn(r,t.wsPort,t.commandTimeoutMs,c.targets);await ge(a,c.targets);let g=B();g&&u.closed.includes(g)&&(c.keepId?$(c.keepId):D());let T=` closed ${u.closed.length} sim(s)${c.keepId?` (kept ${c.keepId})`:""}`;console.log(T),u.remaining.length>0&&(console.error(` close failed: still connected: ${u.remaining.join(", ")}`),process.exit(1))}catch(a){console.error(` close failed: ${a instanceof Error?a.message:String(a)}`),process.exit(1)}finally{r.close()}return}try{try{let a=await r.listSims(),l=J(a,t.positional[0]||t.simId),d=a.find(u=>u.id!==l.id&&u.readyState==="open");await r.closeSim(l.id),await gn(t.wsPort,t.commandTimeoutMs,l.id)||(await ge(a,[l.id]),console.error(` close failed: ${l.id} is still connected`),process.exit(1)),await ge(a,[l.id]),B()===l.id&&(d?$(d.id):D()),console.log(` closed: ${l.id}`)}catch(a){console.error(` close failed: ${a instanceof Error?a.message:String(a)}`),await A(r,{errorsCommand:`rnx get errors 5${o}`,warningsCommand:`rnx get warnings 5${o}`,requestsCommand:`rnx get requests 5${o}`}),process.exit(1)}}finally{r.close()}}export{Lt as a,Nt as b,Ht as c,tr as d,tn as e,wt as f,nn as g,q as h,cn as i,un as j,nr as k,rr as l,fn as m,hn as n,wn as o,ge as p,Sn as q,or as r,ir as s,sr as t,ar as u,xn as v,$n as w,lr as x};
@@ -1,25 +0,0 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a as $}from"./chunk-HF2FZ2WN.js";import{a as y}from"./chunk-S63ENXGH.js";import{spawn as b,spawnSync as u}from"child_process";import{chmodSync as v,copyFileSync as S,createWriteStream as T,existsSync as f,mkdirSync as x,rmSync as w,statSync as P,unlinkSync as E}from"fs";import{tmpdir as D}from"os";import{dirname as M,join as m,resolve as k}from"path";var h="https://contrast.dev/api/electron-release";function A(){let r=process.arch;if(process.platform==="darwin"){let o=r==="arm64"?"mac-arm64":"mac-x64",t=`sootsim-latest-${o}.dmg`;return{platform:o,filename:t,url:`${h}/${t}`,install:L}}if(process.platform==="linux"){let o=r==="arm64"?"linux-arm64":"linux-x64",t=`sootsim-latest-${o}.AppImage`;return{platform:o,filename:t,url:`${h}/${t}`,install:B}}if(process.platform==="win32"){let o="sootsim-latest-win-x64.exe";return{platform:"win-x64",filename:o,url:`${h}/${o}`,install:C}}return null}async function O({url:r,dest:o,onProgress:t}){let s=await fetch(r,{redirect:"follow"});if(!s.ok)throw new Error(`${s.status} ${s.statusText} (${r})`);let e=s.headers.get("content-length"),a=e?Number(e):null;if(!s.body)throw new Error(`empty response body (${r})`);x(M(o),{recursive:!0});let i=T(o),d=s.body.getReader(),c=0;try{for(;;){let{done:n,value:l}=await d.read();if(n)break;i.write(Buffer.from(l)),c+=l.byteLength,t?.(c,a)}}finally{await new Promise((n,l)=>{i.end(p=>p?l(p):n())})}}function I(r,o){let t=(r/1048576).toFixed(1);if(!o)return` ${t} MB`;let s=Math.min(100,Math.round(r/o*100)),e=(o/(1024*1024)).toFixed(1),a=24,i=Math.round(s/100*a);return` ${"\u2588".repeat(i)+"\u2591".repeat(a-i)} ${s}% ${t} / ${e} MB`}async function L(r){let o=u("hdiutil",["attach","-nobrowse","-readonly",r],{encoding:"utf8"});if(o.status!==0)throw new Error(`hdiutil attach failed: ${o.stderr||o.stdout}`.trim());let t=o.stdout.trim().split(`
5
- `),e=t[t.length-1].split(" ").pop()?.trim();if(!e||!f(e))throw new Error(`could not determine dmg mount point (output: ${o.stdout})`);let a=m(e,"rnx.app");if(!f(a))throw u("hdiutil",["detach","-force",e]),new Error(`rnx.app not found inside ${e}`);let i="/Applications",d=k(process.env.HOME||"","Applications"),c=i;try{let g=m(i,`.sootsim-write-probe-${process.pid}`);u("touch",[g]),f(g)?w(g,{force:!0}):c=d}catch{c=d}c===d&&x(c,{recursive:!0});let n=m(c,"sootsim.app");f(n)&&w(n,{recursive:!0,force:!0});let l=u("cp",["-R",a,n]),p=u("hdiutil",["detach","-force",e]);if(l.status!==0)throw new Error(`copy to ${n} failed: ${l.stderr?.toString()||""}`.trim());return p.status!==0&&console.warn(` warning: failed to unmount ${e} (${p.stderr?.toString().trim()||"unknown error"})`),u("xattr",["-dr","com.apple.quarantine",n]),n}async function B(r){let o=k(process.env.HOME||"","Applications");x(o,{recursive:!0});let t=m(o,"sootsim.AppImage");return f(t)&&w(t,{force:!0}),S(r,t),E(r),v(t,493),t}async function C(r){return await new Promise((o,t)=>{let s=b("cmd",["/c","start",'""',"/wait",r],{stdio:"inherit"});s.once("error",t),s.once("exit",e=>{e===0?o():t(new Error(`installer exited with code ${e}`))})}),r}async function q(r){(r.includes("--help")||r.includes("-h"))&&(console.log(`
6
- rnx desktop install \u2014 download and install the optional desktop GUI
7
-
8
- the CLI + daemon are the canonical rnx surface; the GUI is optional.
9
- if you just want to drive a running metro/expo dev server from the
10
- terminal, you don't need this.
11
-
12
- usage:
13
- rnx desktop install [options]
14
-
15
- options:
16
- -y, --yes skip confirmation and install immediately
17
- --force reinstall even if the companion is already present
18
-
19
- examples:
20
- rnx desktop install
21
- rnx desktop install --yes
22
- `),process.exit(0));let o=r.includes("--yes")||r.includes("-y")||process.env.SOOTSIM_NO_PROMPT==="1"||process.env.CI==="1"||!process.stdin.isTTY,t=r.includes("--force"),s=$();if(s&&!t){console.log(` rnx desktop already installed at: ${s.path}`),console.log(" pass --force to reinstall.");return}let e=A();if(e||(console.error(` no desktop build available for ${process.platform}/${process.arch}.`),console.error(" supported: darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64"),process.exit(1)),console.log(` platform: ${e.platform}`),console.log(` download: ${e.url}`),console.log(),!o){if(!await y("download and install now?",!0)){console.log(" cancelled.");return}console.log()}let a=m(D(),`sootsim-install-${Date.now()}`),i=m(a,e.filename),d=0;process.stdout.write(` downloading ${e.filename}...
23
- `);try{await O({url:e.url,dest:i,onProgress:(n,l)=>{let p=Date.now();p-d<100&&n<(l??1/0)||(d=p,process.stdout.isTTY&&process.stdout.write(`\r\x1B[2K${I(n,l)}`))}})}catch(n){w(a,{recursive:!0,force:!0});let l=n instanceof Error?n.message:String(n);console.error(`
24
- download failed: ${l}`),console.error(` the ${e.platform} desktop build may not be published yet, or your`),console.error(" network blocked the request. check your connection and try again later;"),console.error(" the CLI + daemon work without the desktop app (run: rnx --help)."),process.exit(1)}process.stdout.isTTY&&process.stdout.write(`
25
- `);let c=P(i).size;console.log(` downloaded ${(c/(1024*1024)).toFixed(1)} MB`),console.log(),console.log(" installing...");try{let n=await e.install(i);console.log(` installed: ${n}`)}catch(n){console.error(` install failed: ${n instanceof Error?n.message:String(n)}`),console.error(` keeping download at ${i} for manual install.`),process.exit(1)}finally{w(a,{recursive:!0,force:!0})}console.log(),console.log(" next steps:"),console.log(" rnx desktop launch the desktop app"),console.log(" rnx open <target> open a demo or bundle in it")}export{q as a};
@@ -1,11 +0,0 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{randomUUID as k}from"node:crypto";import n from"node:fs";import{homedir as _}from"node:os";import i from"node:path";var $="SOOTSIM_HOME",I="active",B="daemon.json",M="dev-bridges",T="config.json",P=3e4;function s(){let e=process.env[$];return e&&e.length>0?i.resolve(e):i.join(_(),".sootsim")}function J(){if(process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1")return!1;let e=process.env.SOOTSIM_DEV;if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;let t=process.argv[1];if(!t)return!1;try{return n.realpathSync(t).includes(`${i.sep}packages${i.sep}sootsim${i.sep}`)}catch{return!1}}function U(){return process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1"?!1:process.env.IS_TAMAGUI_DEV==="1"}function oe(){return J()||U()}function S(){return i.join(s(),"runtimes")}function V(e){return i.join(S(),e)}function R(){return i.join(S(),I)}function x(){return i.join(s(),"electron")}function ce(){return i.join(x(),"userData")}function se(e){return i.join(x(),e)}function H(){return i.join(s(),"profiles")}function ue(){return i.join(s(),"camera-fixtures")}function G(){return i.join(s(),"daemon-app")}function K(){return i.join(G(),"SootSim Daemon.app")}function ae(){return i.join(K(),"Contents","MacOS","sootsim-daemon")}function X(){return i.join(s(),"cache")}function m(){return i.join(s(),B)}function p(){return i.join(s(),M)}function w(e){if(!Number.isInteger(e)||e<=0)throw new Error(`invalid development bridge port: ${e}`);return i.join(p(),`${e}.json`)}function D(){return i.join(s(),T)}function A(){try{let e=n.readFileSync(D(),"utf8"),t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function O(e){v();let t=A(),r={...t,...e};e.settings&&typeof e.settings=="object"&&(r.settings={...t.settings&&typeof t.settings=="object"?t.settings:{},...e.settings});let c=`${D()}.tmp`;return n.writeFileSync(c,`${JSON.stringify(r,null,2)}
5
- `,"utf8"),n.renameSync(c,D()),r}function fe(){let e=A().settings,t=e?.productAnalytics,r=e?.crashReports;return{productAnalytics:typeof t=="boolean"?t:!1,crashReports:typeof r=="boolean"?r:!1,configured:typeof t=="boolean"&&typeof r=="boolean"}}function le(e){O({settings:{productAnalytics:e.productAnalytics,crashReports:e.crashReports}})}function de(){let e=A().anonymousId;if(typeof e=="string"&&e.trim())return e;let t=`anon-cli-${k()}`;return O({anonymousId:t}),t}function y(){return i.join(s(),"runtime-upgraded.json")}function me(e){v();let t=`${y()}.tmp`;n.writeFileSync(t,`${JSON.stringify(e)}
6
- `,"utf8"),n.renameSync(t,y())}function pe(){try{let e=n.readFileSync(y(),"utf8");n.unlinkSync(y());let t=JSON.parse(e);return typeof t?.to!="string"||!t.to?null:{from:typeof t.from=="string"?t.from:null,to:t.to,at:typeof t.at=="number"?t.at:0}}catch{return null}}function v(){n.mkdirSync(s(),{recursive:!0}),n.mkdirSync(S(),{recursive:!0}),n.mkdirSync(x(),{recursive:!0}),n.mkdirSync(H(),{recursive:!0}),n.mkdirSync(X(),{recursive:!0})}function q(){try{let e=n.readFileSync(R(),"utf8").trim();return e.length>0?e:null}catch{return null}}function ye(e){n.mkdirSync(S(),{recursive:!0}),n.writeFileSync(R(),`${e}
7
- `,"utf8")}function ge(){let e=q();if(!e)return null;let t=V(e);try{if(n.statSync(t).isDirectory())return t}catch{}return null}var g=16*1024,z=3e4;function d(){try{let e=n.openSync(m(),"r");try{let t=Buffer.alloc(g),r=n.readSync(e,t,0,g,0),c=t.subarray(0,r).toString("utf8"),o=JSON.parse(c);return o&&o.schema===1&&typeof o.pid=="number"&&typeof o.bridgePort=="number"&&typeof o.runtimePort=="number"&&typeof o.startedAt=="number"&&typeof o.heartbeatAt=="number"&&(o.servedRuntimes===void 0||Array.isArray(o.servedRuntimes)&&o.servedRuntimes.every(u=>typeof u=="string"))?o:null}finally{n.closeSync(e)}}catch{return null}}function E(e){try{let t=JSON.parse(e);return t&&t.schema===1&&t.source==="vite-dev"&&typeof t.pid=="number"&&typeof t.bridgePort=="number"&&typeof t.runtimePort=="number"&&typeof t.cwd=="string"&&typeof t.startedAt=="number"&&typeof t.heartbeatAt=="number"&&(t.shellPort===void 0||typeof t.shellPort=="number")&&(t.servedRuntimes===void 0||Array.isArray(t.servedRuntimes)&&t.servedRuntimes.every(r=>typeof r=="string"))?t:null}catch{return null}}function W(){let e;try{e=n.readdirSync(p(),{withFileTypes:!0})}catch{return[]}let t=[];for(let r of e)if(!(!r.isFile()||!/^\d+\.json$/.test(r.name)))try{let c=i.join(p(),r.name),o=n.openSync(c,"r");try{let u=Buffer.alloc(g),a=n.readSync(o,u,0,g,0),h=E(u.subarray(0,a).toString("utf8"));h&&r.name===`${h.bridgePort}.json`&&t.push(h)}finally{n.closeSync(o)}}catch{}return t.sort((r,c)=>r.bridgePort-c.bridgePort)}function b(e,t=Date.now()){if(!e||t-e.heartbeatAt>P)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function Y(e,t=Date.now()){if(!e||t-e.heartbeatAt>P)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function Se(){let e=new Set,t=d();if(b(t)){t.activeRuntime&&e.add(t.activeRuntime);for(let r of t.servedRuntimes??[])e.add(r)}for(let r of W())if(Y(r))for(let c of r.servedRuntimes??[])e.add(c);return[...e].sort()}function Q(e){v();let t=m(),r=d();if(!r){if(j(e))return;throw new Error("another rnx daemon claimed the lockfile before this write")}if(!f(r,e))throw new Error("refusing to overwrite another rnx daemon lockfile");let c=`${t}.${e.pid}.${k()}.tmp`;n.writeFileSync(c,`${JSON.stringify(e,null,2)}
8
- `,"utf8");try{let o=d();if(!o||!f(o,e))throw new Error("rnx daemon lock ownership changed during heartbeat");n.renameSync(c,t)}finally{try{n.unlinkSync(c)}catch{}}}function ve(e){n.mkdirSync(p(),{recursive:!0});let t=w(e.bridgePort),r=`${t}.${e.pid}.tmp`;n.writeFileSync(r,`${JSON.stringify(e,null,2)}
9
- `,"utf8"),n.renameSync(r,t)}function f(e,t){return e.pid===t.pid&&e.startedAt===t.startedAt}function N(e){return e instanceof Error&&"code"in e&&Reflect.get(e,"code")==="EEXIST"}function j(e){let t=m(),r=`${t}.${e.pid}.${k()}.claim`;n.writeFileSync(r,`${JSON.stringify(e,null,2)}
10
- `,"utf8");try{return n.linkSync(r,t),!0}catch(c){if(N(c))return!1;throw c}finally{try{n.unlinkSync(r)}catch{}}}function l(){return`${m()}.claim`}function C(e){try{let t=JSON.parse(e);if(t!==null&&typeof t=="object"&&typeof Reflect.get(t,"pid")=="number"&&typeof Reflect.get(t,"startedAt")=="number"&&typeof Reflect.get(t,"createdAt")=="number")return{pid:Reflect.get(t,"pid"),startedAt:Reflect.get(t,"startedAt"),createdAt:Reflect.get(t,"createdAt")}}catch{}return null}function F(){try{return C(n.readFileSync(l(),"utf8"))}catch{return null}}function L(e,t=Date.now()){if(t-e.createdAt>z)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function Z(e){let t={pid:e.pid,startedAt:e.startedAt,createdAt:Date.now()},r=`${JSON.stringify(t)}
11
- `;for(let c=0;c<8;c++){try{return n.writeFileSync(l(),r,{encoding:"utf8",flag:"wx"}),!0}catch(a){if(!N(a))throw a}let o=F();if(o&&f(o,t))return!0;if(o&&L(o))return!1;let u;try{u=n.readFileSync(l(),"utf8");let a=C(u);if(a&&L(a))return!1;if(n.readFileSync(l(),"utf8")!==u)continue;n.unlinkSync(l())}catch{}}return!1}function ee(e){try{let t=F();if(!t||!f(t,e))return;n.unlinkSync(l())}catch{}}function he(e){if(v(),!Z(e))return!1;try{let t=d();if(t&&f(t,e))return Q(e),!0;if(t&&b(t))return!1;if(t){let r=d();if(!r||!f(r,t)||b(r))return!1;try{n.unlinkSync(m())}catch{return!1}}return j(e)}finally{ee(e)}}function De(e){try{let t=d();if(!t||!f(t,e))return;n.unlinkSync(m())}catch{}}function be(e){try{let t=w(e.bridgePort),r=E(n.readFileSync(t,"utf8"));if(r?.pid!==e.pid||r.startedAt!==e.startedAt)return;n.unlinkSync(t)}catch{}}export{$ as a,I as b,B as c,M as d,T as e,P as f,s as g,J as h,U as i,oe as j,S as k,V as l,R as m,x as n,ce as o,se as p,H as q,ue as r,G as s,K as t,ae as u,X as v,m as w,p as x,w as y,D as z,A,O as B,fe as C,le as D,de as E,y as F,me as G,pe as H,v as I,q as J,ye as K,ge as L,d as M,W as N,b as O,Y as P,Se as Q,Q as R,ve as S,he as T,De as U,be as V};
@@ -1,7 +0,0 @@
1
- /*! rnx v0.1.352 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{execFileSync as h,spawn as g}from"child_process";import{existsSync as s,readdirSync as k}from"fs";import{dirname as m,join as l,resolve as a}from"path";import{fileURLToPath as w}from"url";var c;function p(){if(c!==void 0)return c;try{c=m(w(import.meta.resolve("sootsim-engine/package.json")))}catch{c=null}return c}var v="dev.sootsim.simulator";function I(){let e=p();if(!e)return null;let n=l(e,"dist-electron/main.cjs");if(!s(n))return null;let i=P(e);return i?{path:i,platform:process.platform,kind:"dev-electron",engineDir:e}:null}function x(){let e=p();return e?s(l(e,"src-electron/main.ts")):!1}function P(e){let n=e;for(let i=0;i<6;i++){let t=l(n,"node_modules/.bin/electron");if(s(t))return t;let r=m(n);if(r===n)break;n=r}return null}function b(){let e=p(),i=["/Applications/sootsim.app",a(process.env.HOME||"","Applications/sootsim.app"),...e?[a(e,"app/sootsim.app")]:[]].find(t=>s(t));if(i)return{path:i,platform:"darwin",kind:"mac-app"};try{let t=h("mdfind",[`kMDItemCFBundleIdentifier == "${v}"`],{encoding:"utf8",timeout:3e3}).trim();if(t)return{path:t.split(`
5
- `)[0],platform:"darwin",kind:"mac-app"}}catch{}return null}function f(e){if(!s(e))return null;let n=k(e).filter(i=>i.startsWith("sootsim")&&i.endsWith(".AppImage")).sort().reverse()[0];return n?l(e,n):null}function D(){let e=p(),i=[a(process.env.HOME||"","Applications/sootsim.AppImage"),a(process.env.HOME||"",".local/bin/sootsim.AppImage"),"/opt/sootsim/sootsim.AppImage","/opt/sootsim/sootsim",...e?[a(e,"app/sootsim.AppImage"),a(e,"release/linux-unpacked/sootsim")]:[]].find(r=>s(r));if(i)return{path:i,platform:"linux",kind:i.endsWith(".AppImage")?"linux-appimage":"linux-binary"};let t=e?f(a(e,"app"))||f(a(e,"release")):null;return t?{path:t,platform:"linux",kind:"linux-appimage"}:null}function C(){let e=I();if(e)return e;if(x()){let n=p(),i=l(n,"dist-electron/main.cjs");return s(i)?console.error(` no node_modules/.bin/electron found near ${n}. run \`bun install\`.`):console.error(` dist-electron/main.cjs missing in ${n}.
6
- run: bun run --cwd packages/sootsim-engine build:electron-main
7
- (or keep it fresh with: bun run watch:sootsim:electron-main)`),null}return process.platform==="darwin"?b():process.platform==="linux"?D():null}async function d(e,n,i={}){let t=i.inheritStdio?["ignore","inherit","inherit"]:"ignore";await new Promise((r,o)=>{let u=g(e,n,{detached:!0,stdio:t});u.once("error",o),u.once("spawn",()=>{u.unref(),r()})})}async function O(e,n=C(),i={}){if(!n)return{launched:!1};let t=[];if(i.device&&t.push(`--device=${i.device}`),i.profileId&&t.push(`--profile=${i.profileId}`),i.ephemeralProfile&&t.push("--ephemeral-profile"),i.ownerPid&&i.ownerPid>1&&t.push(`--owner-pid=${i.ownerPid}`),n.kind==="mac-app"){let o=["-g","-a",n.path];return e&&o.push(A(e,i)),t.length>0&&o.push("--args",...t),await d("open",o),{launched:!0,via:"mac-app",target:n.path}}if(n.kind==="dev-electron"){let o=["--no-sandbox",n.engineDir||p()];return e&&o.push(e),t.length>0&&o.push(...t),await d(n.path,o,{inheritStdio:!0}),{launched:!0,via:"dev-electron",target:n.path}}let r=[];return e&&r.push(e),t.length>0&&r.push(...t),await d(n.path,r),{launched:!0,via:n.kind,target:n.path}}function A(e,n){if(!n.profileId&&!n.ephemeralProfile&&!n.ownerPid)return e;let i=new URL("sootsim://dev");return i.searchParams.set("url",e),n.profileId&&i.searchParams.set("profile",n.profileId),n.ephemeralProfile&&i.searchParams.set("ephemeral","1"),n.ownerPid&&n.ownerPid>1&&i.searchParams.set("ownerPid",String(n.ownerPid)),i.toString()}export{C as a,O as b};