rnxsim 0.1.344 → 0.1.345

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 (209) hide show
  1. package/README.md +59 -31
  2. package/cli/app-fonts.ts +8 -28
  3. package/cli/app-project.ts +12 -184
  4. package/cli/app-splash.ts +3 -17
  5. package/cli/bin.ts +15 -28
  6. package/cli/commands/control.ts +20 -30
  7. package/cli/commands/daemon.ts +19 -44
  8. package/cli/commands/flow.ts +0 -27
  9. package/cli/commands/install-desktop.ts +2 -16
  10. package/cli/commands/login.ts +3 -43
  11. package/cli/commands/logout.ts +0 -7
  12. package/cli/commands/serve.ts +2 -32
  13. package/cli/commands/setup.ts +20 -194
  14. package/cli/commands/telemetry.ts +7 -5
  15. package/cli/commands/upload.ts +1 -48
  16. package/cli/commands/welcome.ts +64 -0
  17. package/cli/outbound-endpoints.ts +586 -0
  18. package/cli/privacy.ts +53 -0
  19. package/cli/runtime-notes.ts +2 -2
  20. package/cli/telemetry.ts +46 -149
  21. package/dist-cli/bin.js +6 -6
  22. package/dist-cli/chunks/{agent-HTSE5FA4.js → agent-52G55XTO.js} +2 -2
  23. package/dist-cli/chunks/{agent-wrapper-L6X2AEZL.js → agent-wrapper-BOZM43ON.js} +2 -2
  24. package/dist-cli/chunks/{app-fonts-FGF3ETYH.js → app-fonts-A2L6V5EZ.js} +2 -2
  25. package/dist-cli/chunks/{assert-HA2ZYVDN.js → assert-CJKIP4LN.js} +2 -2
  26. package/dist-cli/chunks/{auth-HONDAV75.js → auth-VHHN3TOB.js} +2 -2
  27. package/dist-cli/chunks/{beta-U7EE4GMR.js → beta-EBDIGV3E.js} +2 -2
  28. package/dist-cli/chunks/{camera-RTKNUTIX.js → camera-5F4KKCQ3.js} +2 -2
  29. package/dist-cli/chunks/chunk-3DBTS4MC.js +15 -0
  30. package/dist-cli/chunks/chunk-3N7M5HMJ.js +6 -0
  31. package/dist-cli/chunks/{chunk-S7CSBQ6G.js → chunk-4BIPA7MD.js} +1 -1
  32. package/dist-cli/chunks/chunk-4OKV7T5D.js +4 -0
  33. package/dist-cli/chunks/{chunk-CNLPLCO2.js → chunk-4ZILDTZX.js} +2 -2
  34. package/dist-cli/chunks/{chunk-HRBMD2FS.js → chunk-5GXRRUOA.js} +26 -26
  35. package/dist-cli/chunks/chunk-63ASUHOV.js +4 -0
  36. package/dist-cli/chunks/{chunk-XQFDEY3F.js → chunk-7GO2DSYQ.js} +1 -1
  37. package/dist-cli/chunks/{chunk-IWR4HFC4.js → chunk-7LGINKM6.js} +2 -2
  38. package/dist-cli/chunks/{chunk-TZNRKIS3.js → chunk-7UIIAHVU.js} +2 -2
  39. package/dist-cli/chunks/{chunk-Q2B6EQPB.js → chunk-7V4KPZ7O.js} +2 -2
  40. package/dist-cli/chunks/{chunk-EPEZZ6YS.js → chunk-7YMQRA6L.js} +2 -2
  41. package/dist-cli/chunks/{chunk-IPC45HTT.js → chunk-A2Q76LJV.js} +2 -2
  42. package/dist-cli/chunks/{chunk-EH35QQG4.js → chunk-BCQV63BW.js} +45 -45
  43. package/dist-cli/chunks/{chunk-N5PFDTFL.js → chunk-BFTDL2GX.js} +17 -17
  44. package/dist-cli/chunks/chunk-BHKSCNDC.js +4 -0
  45. package/dist-cli/chunks/{chunk-6PEZSVIG.js → chunk-DGTV3KOW.js} +1 -1
  46. package/dist-cli/chunks/chunk-DHM3JDCK.js +4 -0
  47. package/dist-cli/chunks/{chunk-KT6WMCUS.js → chunk-DPP2M4AJ.js} +1 -1
  48. package/dist-cli/chunks/chunk-E2RGSCHT.js +4 -0
  49. package/dist-cli/chunks/{chunk-S6LBAUWH.js → chunk-EPLVIDPC.js} +1 -1
  50. package/dist-cli/chunks/{chunk-6NLWKL7Y.js → chunk-GKGXULJK.js} +2 -2
  51. package/dist-cli/chunks/{chunk-7V4ULF3U.js → chunk-HK7YKH6N.js} +2 -2
  52. package/dist-cli/chunks/{chunk-6E6SBYIO.js → chunk-HXE344V3.js} +1 -1
  53. package/dist-cli/chunks/{chunk-JLUEQPEF.js → chunk-JC33TOAF.js} +1 -1
  54. package/dist-cli/chunks/{chunk-7JEEO33Y.js → chunk-KA4PJNTE.js} +2 -2
  55. package/dist-cli/chunks/{chunk-K3VNCCEJ.js → chunk-KH777UAO.js} +3 -3
  56. package/dist-cli/chunks/{chunk-G3UAFZE2.js → chunk-KRZPFXVN.js} +1 -1
  57. package/dist-cli/chunks/{chunk-R3UYHE6G.js → chunk-KZFJNDH3.js} +1 -1
  58. package/dist-cli/chunks/{chunk-22WJPMTQ.js → chunk-LAQGSSTT.js} +1 -1
  59. package/dist-cli/chunks/chunk-LRM2XCEQ.js +11 -0
  60. package/dist-cli/chunks/{chunk-MWUXQIA3.js → chunk-NUPRHZQW.js} +2 -2
  61. package/dist-cli/chunks/{chunk-JFUVWIJT.js → chunk-OPHT4DUO.js} +1 -1
  62. package/dist-cli/chunks/{chunk-EN32LN2B.js → chunk-P2CGGMU2.js} +2 -2
  63. package/dist-cli/chunks/{chunk-UCVQOQCY.js → chunk-PLB6UVVX.js} +2 -2
  64. package/dist-cli/chunks/{chunk-TOHQI2II.js → chunk-PLUWN2V5.js} +1 -1
  65. package/dist-cli/chunks/{chunk-ZPTFL5FQ.js → chunk-QNBBKRCA.js} +2 -2
  66. package/dist-cli/chunks/{chunk-NRTHFEPM.js → chunk-QNRWPAOA.js} +2 -2
  67. package/dist-cli/chunks/{chunk-63NZGJ4A.js → chunk-R7ZNRGQN.js} +1 -1
  68. package/dist-cli/chunks/{chunk-FZ5DRZJE.js → chunk-RB4VFUNM.js} +3 -3
  69. package/dist-cli/chunks/chunk-RT3DXTDP.js +25 -0
  70. package/dist-cli/chunks/{chunk-KBSVSAAE.js → chunk-RTDHX6CW.js} +2 -2
  71. package/dist-cli/chunks/{chunk-OCUXAA6O.js → chunk-T7SBFG5I.js} +2 -2
  72. package/dist-cli/chunks/{chunk-GRX6NSBG.js → chunk-TEU5NGUA.js} +2 -2
  73. package/dist-cli/chunks/chunk-TMRD5MHL.js +99 -0
  74. package/dist-cli/chunks/{chunk-POOCKX5B.js → chunk-TOF5TA5X.js} +11 -11
  75. package/dist-cli/chunks/{chunk-G6IPT2PS.js → chunk-U5YHXQHH.js} +2 -2
  76. package/dist-cli/chunks/{chunk-H4J7EWZC.js → chunk-UVOEHIGP.js} +1 -1
  77. package/dist-cli/chunks/{chunk-ZZSBCGHC.js → chunk-VLBN3KRC.js} +1 -1
  78. package/dist-cli/chunks/{chunk-PNMCALX5.js → chunk-WPPGU5IK.js} +2 -2
  79. package/dist-cli/chunks/{chunk-NDGAF5OF.js → chunk-WU72KL6Z.js} +2 -2
  80. package/dist-cli/chunks/chunk-XJBFJGNT.js +4 -0
  81. package/dist-cli/chunks/{chunk-BGLWR43R.js → chunk-XXZLK4BY.js} +1 -1
  82. package/dist-cli/chunks/{chunk-CRWYKW67.js → chunk-YVSUFVVB.js} +1 -1
  83. package/dist-cli/chunks/{chunk-EZLLZDYX.js → chunk-ZMTZ5G5H.js} +2 -2
  84. package/dist-cli/chunks/{cleanup-EMYD5WZG.js → cleanup-MAVZJXVW.js} +2 -2
  85. package/dist-cli/chunks/cli-version-2B4KRNML.js +4 -0
  86. package/dist-cli/chunks/{compat-W2N5QTVG.js → compat-7AURLGCS.js} +2 -2
  87. package/dist-cli/chunks/config-TN3Y4J5N.js +13 -0
  88. package/dist-cli/chunks/{control-4SFBROUE.js → control-EV2ELU5R.js} +2 -2
  89. package/dist-cli/chunks/daemon-KKDG5MYR.js +4 -0
  90. package/dist-cli/chunks/{debug-HCR2KFUA.js → debug-JICITUB6.js} +3 -3
  91. package/dist-cli/chunks/{desktop-T2KS5PBJ.js → desktop-4F5HGLLX.js} +3 -3
  92. package/dist-cli/chunks/{detox-5S7EHINH.js → detox-ZC7NHLJI.js} +2 -2
  93. package/dist-cli/chunks/{device-LVM3MZRJ.js → device-V57GHRXX.js} +2 -2
  94. package/dist-cli/chunks/{diagnose-WK37XKLI.js → diagnose-FF4IWYXC.js} +2 -2
  95. package/dist-cli/chunks/{disk-cleanup-X7VJOXMS.js → disk-cleanup-T277L6ZO.js} +2 -2
  96. package/dist-cli/chunks/drivers-LCX7S76X.js +4 -0
  97. package/dist-cli/chunks/{film-7KLTI3ER.js → film-G7ZAPWB7.js} +3 -3
  98. package/dist-cli/chunks/flow-ONZGGFGD.js +4 -0
  99. package/dist-cli/chunks/help-DROVDXJM.js +4 -0
  100. package/dist-cli/chunks/{hidden-runtime-alias-4RVGUVFO.js → hidden-runtime-alias-VSJNNSNI.js} +2 -2
  101. package/dist-cli/chunks/{home-paths-5DHSAEGZ.js → home-paths-75HP3HKA.js} +2 -2
  102. package/dist-cli/chunks/inspect-MDA7ESGQ.js +4 -0
  103. package/dist-cli/chunks/install-desktop-EIVZHIFA.js +4 -0
  104. package/dist-cli/chunks/login-ZSIHGHUK.js +26 -0
  105. package/dist-cli/chunks/logout-Q4DXMI2C.js +4 -0
  106. package/dist-cli/chunks/{maestro-HTRLQDJE.js → maestro-LE5LCRBL.js} +3 -3
  107. package/dist-cli/chunks/{maestro-generate-GX2QNA3F.js → maestro-generate-D3ZIJCRL.js} +3 -3
  108. package/dist-cli/chunks/{mode-GM6KZHQP.js → mode-BWX6MDPJ.js} +2 -2
  109. package/dist-cli/chunks/{optional-demo-registry-B4TD7JQP.js → optional-demo-registry-6CVASL3S.js} +2 -2
  110. package/dist-cli/chunks/{perf-3PRXJQIC.js → perf-NXQZISN6.js} +2 -2
  111. package/dist-cli/chunks/{permissions-TJZIRF2S.js → permissions-5PD67RRO.js} +2 -2
  112. package/dist-cli/chunks/privacy-H5KNRNIZ.js +4 -0
  113. package/dist-cli/chunks/{record-LI55DTPE.js → record-YJF4KXMR.js} +3 -3
  114. package/dist-cli/chunks/{report-issue-TBGJVQIQ.js → report-issue-XOL5FQBG.js} +2 -2
  115. package/dist-cli/chunks/reset-5LZN5P5B.js +4 -0
  116. package/dist-cli/chunks/runtime-U36VWBH3.js +4 -0
  117. package/dist-cli/chunks/{screenshot-command-BEN7YYIF.js → screenshot-command-VRPJXWFS.js} +3 -3
  118. package/dist-cli/chunks/{screenshot-layers-3IU4KYNO.js → screenshot-layers-QP4WA2F5.js} +2 -2
  119. package/dist-cli/chunks/{screenshots-capture-ZRC54ST6.js → screenshots-capture-O2IBAVSP.js} +2 -2
  120. package/dist-cli/chunks/serve-WC6RZNJL.js +118 -0
  121. package/dist-cli/chunks/setup-A6BIG3KL.js +30 -0
  122. package/dist-cli/chunks/{skills-GKBR2HQB.js → skills-A7YC6RL5.js} +2 -2
  123. package/dist-cli/chunks/{state-LIHZJSL7.js → state-IJI5YROJ.js} +2 -2
  124. package/dist-cli/chunks/{storage-4TPN3NFB.js → storage-Z2DBO2PQ.js} +4 -4
  125. package/dist-cli/chunks/store-BYTCKNIC.js +4 -0
  126. package/dist-cli/chunks/telemetry-JLHFMD7N.js +4 -0
  127. package/dist-cli/chunks/{timeline-EX63UNWU.js → timeline-N7V2M6QA.js} +2 -2
  128. package/dist-cli/chunks/{upgrade-O6Y6EINE.js → upgrade-P2NH3BOR.js} +2 -2
  129. package/dist-cli/chunks/upload-Z2WX5DCD.js +4 -0
  130. package/dist-cli/chunks/{version-HLNL3NFB.js → version-OUHCSCUS.js} +2 -2
  131. package/dist-cli/chunks/{web-4EDPYPW7.js → web-6NRTF3UV.js} +2 -2
  132. package/dist-cli/chunks/welcome-6RS7PEJW.js +5 -0
  133. package/dist-cli/chunks/{what-happened-77VNUEPK.js → what-happened-FUEL3BEF.js} +2 -2
  134. package/dist-lib/agent-daemon-client.cjs +1 -1
  135. package/dist-lib/agent-events.cjs +1 -1
  136. package/dist-lib/agent-identity.cjs +1 -1
  137. package/dist-lib/agent-sessions.cjs +1 -1
  138. package/dist-lib/attached-projects.cjs +1 -1
  139. package/dist-lib/auth/shared-session.cjs +1 -1
  140. package/dist-lib/backend-origin.cjs +1 -1
  141. package/dist-lib/beta.cjs +1 -1
  142. package/dist-lib/beta.mjs +1 -1
  143. package/dist-lib/bridge-constants.cjs +1 -1
  144. package/dist-lib/bridge-contract.cjs +1 -1
  145. package/dist-lib/cli-constants.cjs +1 -1
  146. package/dist-lib/config.cjs +1 -1
  147. package/dist-lib/detox/index.cjs +1 -1
  148. package/dist-lib/dev-bundle-resolution.cjs +18 -4
  149. package/dist-lib/home-paths.cjs +145 -11
  150. package/dist-lib/host/bridge-host.cjs +236 -31
  151. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  152. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  153. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  154. package/dist-lib/host/replacement-module-handler.cjs +71 -4
  155. package/dist-lib/host/websocket-proxy.cjs +1 -1
  156. package/dist-lib/index.cjs +337 -37
  157. package/dist-lib/jump-to-source-babel.cjs +1 -1
  158. package/dist-lib/menu.cjs +1 -1
  159. package/dist-lib/menu.mjs +1 -1
  160. package/dist-lib/metro-production-bundle.cjs +1 -1
  161. package/dist-lib/metro-production-bundle.mjs +1 -1
  162. package/dist-lib/metro.cjs +484 -14
  163. package/dist-lib/profiles.cjs +1 -1
  164. package/dist-lib/public-brand.cjs +1 -1
  165. package/dist-lib/react-native-host-modules.cjs +1 -1
  166. package/dist-lib/react-native-host-modules.mjs +1 -1
  167. package/dist-lib/render-mode.cjs +1 -1
  168. package/dist-lib/scripts/dev-server-scanner.cjs +25 -2
  169. package/dist-lib/sdk.cjs +1 -1
  170. package/dist-lib/sdk.mjs +1 -1
  171. package/dist-lib/skills.cjs +384 -385
  172. package/dist-lib/vite.cjs +193 -37
  173. package/package.json +2 -1
  174. package/scripts/dev-server-scanner.ts +12 -5
  175. package/skills/rnx-test/SKILL.md +4 -0
  176. package/src/dev-bundle-resolution.ts +13 -6
  177. package/src/dev-server-open.ts +197 -0
  178. package/src/home-paths.ts +168 -15
  179. package/src/host/bridge-host.ts +2 -2
  180. package/src/host/replacement-module-handler.ts +68 -2
  181. package/src/metro-plugin.ts +83 -5
  182. package/src/native-dev-bundle-url.ts +22 -0
  183. package/src/vite-plugin-one.ts +42 -28
  184. package/dist-cli/chunks/chunk-3JC7H4PR.js +0 -25
  185. package/dist-cli/chunks/chunk-6DLIC7BZ.js +0 -4
  186. package/dist-cli/chunks/chunk-7TNPO2OJ.js +0 -9
  187. package/dist-cli/chunks/chunk-AMF5KTOI.js +0 -4
  188. package/dist-cli/chunks/chunk-BX5VXTOQ.js +0 -101
  189. package/dist-cli/chunks/chunk-D73H7ACZ.js +0 -4
  190. package/dist-cli/chunks/chunk-DY4O7KYI.js +0 -4
  191. package/dist-cli/chunks/chunk-GU2V4JDG.js +0 -15
  192. package/dist-cli/chunks/chunk-Z2HMSVSN.js +0 -4
  193. package/dist-cli/chunks/cli-version-CN3NTKLH.js +0 -4
  194. package/dist-cli/chunks/config-SELKGT4F.js +0 -13
  195. package/dist-cli/chunks/daemon-V2SFCU2E.js +0 -4
  196. package/dist-cli/chunks/drivers-3YFTJ5WA.js +0 -4
  197. package/dist-cli/chunks/flow-36ANTMJU.js +0 -4
  198. package/dist-cli/chunks/help-ZGL26SPK.js +0 -4
  199. package/dist-cli/chunks/inspect-R3B55RTS.js +0 -4
  200. package/dist-cli/chunks/install-desktop-TZ3H3VWK.js +0 -4
  201. package/dist-cli/chunks/login-4DFULI7S.js +0 -28
  202. package/dist-cli/chunks/logout-QMCVYMBB.js +0 -4
  203. package/dist-cli/chunks/reset-O6MW6X7X.js +0 -4
  204. package/dist-cli/chunks/runtime-JESXBHRQ.js +0 -4
  205. package/dist-cli/chunks/serve-QGKTWPNF.js +0 -118
  206. package/dist-cli/chunks/setup-3WPWATCX.js +0 -32
  207. package/dist-cli/chunks/store-VBX3L46S.js +0 -4
  208. package/dist-cli/chunks/telemetry-ACNNIQIG.js +0 -4
  209. package/dist-cli/chunks/upload-OD2UQHMM.js +0 -4
@@ -188,10 +188,15 @@ export async function ensureBridgeForOpen(
188
188
  preferredPort: number,
189
189
  explicitPort = false,
190
190
  ): Promise<number> {
191
- if (await canConnectToBridge(preferredPort, 250)) return preferredPort
192
-
193
191
  const lock = readDaemonLockfile()
194
192
  assertExplicitBridgeLock(preferredPort, explicitPort, lock)
193
+ const preferredWorld = worldForBridgePort(preferredPort)
194
+ if (
195
+ (explicitPort || preferredWorld !== null) &&
196
+ (await canConnectToBridge(preferredPort, 250))
197
+ ) {
198
+ return preferredPort
199
+ }
195
200
  if (
196
201
  lock &&
197
202
  isDaemonLockfileFresh(lock) &&
@@ -227,12 +232,6 @@ export async function ensureBridgeForOpen(
227
232
  )
228
233
  return nextLock.bridgePort
229
234
  }
230
- if (await canConnectToBridge(preferredPort, 250)) {
231
- console.error(
232
- ` started local bridge on port ${preferredPort}; run \`sootsim setup\` to install the background daemon`,
233
- )
234
- return preferredPort
235
- }
236
235
  if (childExit) {
237
236
  throw new Error(`rnx bridge exited before becoming ready (exit ${childExit})`)
238
237
  }
@@ -542,13 +541,9 @@ function parseOpenRuntimeConfig(args: string[]): SootSimConfig | undefined {
542
541
  async function resolveOpenAppProject(
543
542
  resolvedBundle?: ResolvedDevBundle,
544
543
  ): Promise<ResolvedAppProject | null> {
545
- if (resolvedBundle) {
546
- const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl)
547
- if (advertisedRoot) {
548
- return resolveAppProject(advertisedRoot, { trustStart: true })
549
- }
550
- }
551
- return resolveAppProject(process.env.CONTRAST_REPO_DIR || process.cwd())
544
+ if (!resolvedBundle) return null
545
+ const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl)
546
+ return advertisedRoot ? resolveAppProject(advertisedRoot) : null
552
547
  }
553
548
 
554
549
  async function ensureConfiguredRuntime(version: string): Promise<void> {
@@ -616,16 +611,10 @@ async function stampAppFonts(
616
611
  try {
617
612
  const url = new URL(urlStr)
618
613
  const bundleUrl = url.searchParams.get('bundle') || ''
619
- if (!bundleUrl) return urlStr
620
- // the dev server's project root identifies the exact app in a monorepo.
621
- // CONTRAST_REPO_DIR is only the fallback for servers that do not advertise
622
- // their root.
623
- const repoDir =
624
- project?.appDir ?? (await resolveMetroProjectRoot(bundleUrl)) ?? undefined
614
+ if (!bundleUrl || !project) return urlStr
625
615
  const specs = discoverNativeLinkedAppFonts({
626
616
  bundleUrl,
627
- repoDir,
628
- exactProjectDir: !!project || !!repoDir,
617
+ projectDir: project.appDir,
629
618
  })
630
619
  if (specs.length === 0) return urlStr
631
620
  const reachable = await filterReachableAppFonts(specs)
@@ -716,13 +705,10 @@ async function stampAppSplash(
716
705
  try {
717
706
  const url = new URL(urlStr)
718
707
  const bundleUrl = url.searchParams.get('bundle') || ''
719
- if (!bundleUrl) return urlStr
720
- const repoDir =
721
- project?.appDir ?? (await resolveMetroProjectRoot(bundleUrl)) ?? undefined
708
+ if (!bundleUrl || !project) return urlStr
722
709
  const spec = discoverConfigPluginAppSplash({
723
710
  bundleUrl,
724
- repoDir,
725
- exactProjectDir: !!project || !!repoDir,
711
+ projectDir: project.appDir,
726
712
  })
727
713
  if (!spec) return urlStr
728
714
  // HEAD-check the image before stamping so a typo'd/missing splash path never
@@ -1427,7 +1413,10 @@ export async function runLinkCommand(args: string[], opts: ControlCommandOptions
1427
1413
  }
1428
1414
  }
1429
1415
 
1430
- export async function runOpenCommand(args: string[], opts: ControlCommandOptions = {}) {
1416
+ export async function runOpenCommand(
1417
+ args: string[],
1418
+ opts: ControlCommandOptions = {},
1419
+ ): Promise<number | undefined> {
1431
1420
  const parsed = parseBridgeCliArgs(args, {
1432
1421
  port: opts.port,
1433
1422
  commandTimeoutMs: opts.timeoutMs,
@@ -1748,7 +1737,7 @@ export async function runOpenCommand(args: string[], opts: ControlCommandOptions
1748
1737
  ))
1749
1738
  printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, 'current sim')
1750
1739
  await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args)
1751
- return
1740
+ return parsed.wsPort
1752
1741
  }
1753
1742
  } finally {
1754
1743
  bridge.close()
@@ -1827,6 +1816,7 @@ export async function runOpenCommand(args: string[], opts: ControlCommandOptions
1827
1816
  signalDriverLaunchConnected(result)
1828
1817
  printOpenedSim(openUrl, match, `${driver.name} driver`)
1829
1818
  await maybeDescribeAfterOpen(parsed.wsPort, match.id, args)
1819
+ return parsed.wsPort
1830
1820
  }
1831
1821
 
1832
1822
  async function runUseLikeCommand(args: string[], opts: ControlCommandOptions = {}) {
@@ -37,7 +37,6 @@ import {
37
37
  } from '../../src/home-paths'
38
38
  import { rnxPublicBrand } from '../../src/public-brand'
39
39
  import { printCommandHelp } from '../help'
40
- import { flushCliTelemetry, trackCliEvent } from '../telemetry'
41
40
  import { ensureDaemonApp } from './daemon-mac-app'
42
41
 
43
42
  // minimum seconds between launchd / systemd respawns. without this, a daemon
@@ -65,49 +64,25 @@ export async function runDaemon(args: string[], opts: DaemonOptions = {}) {
65
64
  return
66
65
  }
67
66
 
68
- // emit a single observable event per subcommand. validate against the
69
- // known set so an unknown / malformed `sub` (e.g. accidental path or
70
- // shell-expanded garbage) doesn't pollute the posthog event taxonomy.
71
- // tagged with subsource so daemon traffic is filterable from regular
72
- // cli traffic.
73
- const KNOWN_SUBCOMMANDS = new Set([
74
- 'install',
75
- 'uninstall',
76
- 'restart',
77
- 'start',
78
- 'stop',
79
- 'logs',
80
- ])
81
- if (KNOWN_SUBCOMMANDS.has(sub)) {
82
- trackCliEvent({
83
- event: `daemon_${sub}`,
84
- properties: { platform: process.platform, subsource: 'daemon' },
85
- })
86
- }
87
-
88
- try {
89
- switch (sub) {
90
- case 'install':
91
- return await daemonInstall({ port, force: rest.includes('--force') })
92
- case 'uninstall':
93
- return await daemonUninstall()
94
- case 'status':
95
- return await daemonStatus()
96
- case 'restart':
97
- return await daemonRestart()
98
- case 'start':
99
- return await daemonStart()
100
- case 'stop':
101
- return await daemonStop()
102
- case 'logs':
103
- return await daemonLogs(rest)
104
- default:
105
- console.error(` unknown daemon subcommand: ${sub}`)
106
- printHelp()
107
- process.exit(1)
108
- }
109
- } finally {
110
- await flushCliTelemetry()
67
+ switch (sub) {
68
+ case 'install':
69
+ return daemonInstall({ port, force: rest.includes('--force') })
70
+ case 'uninstall':
71
+ return daemonUninstall()
72
+ case 'status':
73
+ return daemonStatus()
74
+ case 'restart':
75
+ return daemonRestart()
76
+ case 'start':
77
+ return daemonStart()
78
+ case 'stop':
79
+ return daemonStop()
80
+ case 'logs':
81
+ return daemonLogs(rest)
82
+ default:
83
+ console.error(` unknown daemon subcommand: ${sub}`)
84
+ printHelp()
85
+ process.exit(1)
111
86
  }
112
87
  }
113
88
 
@@ -23,7 +23,6 @@ import {
23
23
  keepFlowCandidate,
24
24
  startFlowSession,
25
25
  } from '../flow-session'
26
- import { flushCliTelemetry, trackCliEvent } from '../telemetry'
27
26
  import { createBridge, createBridgeFromParsed, parseBridgeCliArgs } from '../ws-bridge'
28
27
  import {
29
28
  buildShellUrl,
@@ -334,26 +333,6 @@ flow extension:
334
333
  ${steps.length} steps | ${mode}${appLabel}${record ? ' | recording' : ''}${profile ? ' | profiling' : ''}${slow ? ` | ${slow}ms delay` : ''}
335
334
  `)
336
335
 
337
- // only meter flows that will result in a cloud preview upload. plain
338
- // flow playback + local recording stay completely unmetered per the
339
- // free/pro/enterprise beta plan (local usage is free). server emits
340
- // the authoritative preview_upload events when the chained upload
341
- // actually lands.
342
- if (preview) {
343
- trackCliEvent({
344
- event: 'preview_flow_started',
345
- properties: {
346
- flowName: path.basename(flowPath),
347
- stepCount: steps.length,
348
- mode,
349
- electron: wantElectron,
350
- record,
351
- profile,
352
- previewOrigin,
353
- },
354
- })
355
- }
356
-
357
336
  let openTarget = url || targetApp || ''
358
337
  const effectiveOpenInNewSim =
359
338
  openInNewSim || (wantElectron && parsedBridgeArgs.simIdSource !== 'flag')
@@ -392,7 +371,6 @@ flow extension:
392
371
  const discovered = await discoverSootsimUrl()
393
372
  if (!discovered) {
394
373
  console.error(' error: no current sim and no sootsim target found')
395
- await flushCliTelemetry()
396
374
  process.exit(1)
397
375
  }
398
376
  openTarget = discovered
@@ -832,11 +810,6 @@ flow extension:
832
810
  saveCurrentSimId(driver.simId)
833
811
  }
834
812
 
835
- // flush before returning to caller — caller typically calls
836
- // process.exit(returnedCode), and node's `exit` hook can't await, so
837
- // without this the flow telemetry (and any chained upload's events)
838
- // get silently dropped.
839
- await flushCliTelemetry()
840
813
  return exitCode
841
814
  }
842
815
 
@@ -146,10 +146,10 @@ async function installMacDmg(dmgPath: string): Promise<string> {
146
146
  throw new Error(`could not determine dmg mount point (output: ${mountOutput.stdout})`)
147
147
  }
148
148
 
149
- const appSource = join(mountPoint, 'sootsim.app')
149
+ const appSource = join(mountPoint, 'rnx.app')
150
150
  if (!existsSync(appSource)) {
151
151
  spawnSync('hdiutil', ['detach', '-force', mountPoint])
152
- throw new Error(`sootsim.app not found inside ${mountPoint}`)
152
+ throw new Error(`rnx.app not found inside ${mountPoint}`)
153
153
  }
154
154
 
155
155
  // prefer /Applications if writable, otherwise ~/Applications (same paths
@@ -319,24 +319,10 @@ examples:
319
319
  console.log()
320
320
  console.log(` installing...`)
321
321
 
322
- const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
323
-
324
322
  try {
325
323
  const installedAt = await target.install(downloadPath)
326
- trackCliEvent({
327
- event: 'cli_install_desktop_succeeded',
328
- properties: { platform: target.platform, size_bytes: size },
329
- })
330
324
  console.log(` installed: ${installedAt}`)
331
325
  } catch (err) {
332
- trackCliEvent({
333
- event: 'cli_install_desktop_failed',
334
- properties: {
335
- platform: target.platform,
336
- error: err instanceof Error ? err.message : String(err),
337
- },
338
- })
339
- await flushCliTelemetry()
340
326
  console.error(` install failed: ${err instanceof Error ? err.message : String(err)}`)
341
327
  console.error(` keeping download at ${downloadPath} for manual install.`)
342
328
  process.exit(1)
@@ -8,22 +8,15 @@ import {
8
8
  import { rnxPublicBrand } from '../../src/public-brand'
9
9
 
10
10
  const REMOTE_DEFAULT_ORIGIN = process.env.SOOTSIM_AUTH_ORIGIN || 'https://contrast.dev'
11
- const LOCAL_DEFAULT_ORIGIN = 'https://contrast.localhost:3000'
12
11
 
13
12
  type LoginResult =
14
13
  | { ok: true; token: string; userId?: string; email?: string }
15
14
  | { ok: false; error: string }
16
15
 
17
- async function resolveDefaultAuthOrigin(explicitOrigin?: string) {
16
+ function resolveDefaultAuthOrigin(explicitOrigin?: string) {
18
17
  if (explicitOrigin) return explicitOrigin
19
18
  if (process.env.SOOTSIM_AUTH_ORIGIN) return process.env.SOOTSIM_AUTH_ORIGIN
20
19
  if (process.env.SOOTSIM_UPLOAD_ORIGIN) return process.env.SOOTSIM_UPLOAD_ORIGIN
21
-
22
- try {
23
- const res = await fetch(`${LOCAL_DEFAULT_ORIGIN}/api/auth/me`)
24
- if (res.ok) return LOCAL_DEFAULT_ORIGIN
25
- } catch {}
26
-
27
20
  return REMOTE_DEFAULT_ORIGIN
28
21
  }
29
22
 
@@ -35,9 +28,7 @@ usage:
35
28
  rnx login [--origin <url>]
36
29
 
37
30
  options:
38
- --origin <url> auth host (default: auto)
39
- prefers ${LOCAL_DEFAULT_ORIGIN} when available, otherwise
40
- falls back to ${REMOTE_DEFAULT_ORIGIN}
31
+ --origin <url> auth host (default: ${REMOTE_DEFAULT_ORIGIN})
41
32
  override with SOOTSIM_AUTH_ORIGIN env var
42
33
  -h, --help
43
34
  `)
@@ -154,9 +145,7 @@ export async function runLogin(args: string[]) {
154
145
  }
155
146
 
156
147
  const mutableArgs = [...args]
157
- const origin = await resolveDefaultAuthOrigin(
158
- extractStringFlag(mutableArgs, '--origin'),
159
- )
148
+ const origin = resolveDefaultAuthOrigin(extractStringFlag(mutableArgs, '--origin'))
160
149
 
161
150
  // in dev (localhost), skip the browser and sign in as the shared dev
162
151
  // user via POST /api/dev-login. the no-device contract is local-only, so this
@@ -177,13 +166,6 @@ export async function runLogin(args: string[]) {
177
166
  devResult.email ||
178
167
  refreshed?.user?.id ||
179
168
  devResult.userId
180
- const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
181
- trackCliEvent({
182
- event: 'cli_login_succeeded',
183
- identity: { userId: devResult.userId ?? refreshed?.user?.id ?? null },
184
- properties: { origin, mode: 'dev' },
185
- })
186
- await flushCliTelemetry()
187
169
  console.log(` signed in${label ? ` as ${label}` : ''} (dev)`)
188
170
  return
189
171
  }
@@ -192,15 +174,6 @@ export async function runLogin(args: string[]) {
192
174
 
193
175
  const state = randomBytes(16).toString('hex')
194
176
 
195
- // flush a start event BEFORE the browser wait: queued telemetry only drains
196
- // on process exit, so a login that hangs (or gets ctrl+c'd) would otherwise
197
- // leave zero trace. first-time-user hangs were invisible in posthog.
198
- {
199
- const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
200
- trackCliEvent({ event: 'cli_login_started', properties: { origin } })
201
- await flushCliTelemetry()
202
- }
203
-
204
177
  // the browser round-trip needs human action (github's authorize screen on
205
178
  // first sign-in), so the wait is generous, but it must not be infinite: a
206
179
  // closed tab, denied consent, or blocked popup used to hang the CLI forever.
@@ -295,12 +268,6 @@ export async function runLogin(args: string[]) {
295
268
  })
296
269
 
297
270
  if (!result.ok) {
298
- const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
299
- trackCliEvent({
300
- event: 'cli_login_failed',
301
- properties: { origin, error: result.error },
302
- })
303
- await flushCliTelemetry()
304
271
  console.error(` login failed: ${result.error}`)
305
272
  process.exit(1)
306
273
  }
@@ -320,12 +287,5 @@ export async function runLogin(args: string[]) {
320
287
  const refreshed = await refreshSharedDesktopAuthSession(origin)
321
288
  const label =
322
289
  refreshed?.user?.email || result.email || refreshed?.user?.id || result.userId
323
- const { trackCliEvent, flushCliTelemetry } = await import('../telemetry')
324
- trackCliEvent({
325
- event: 'cli_login_succeeded',
326
- identity: { userId: result.userId ?? refreshed?.user?.id ?? null },
327
- properties: { origin },
328
- })
329
- await flushCliTelemetry()
330
290
  console.log(` signed in${label ? ` as ${label}` : ''}`)
331
291
  }
@@ -2,7 +2,6 @@ import {
2
2
  clearSharedDesktopAuthSession,
3
3
  readSharedDesktopAuthSession,
4
4
  } from '../../src/auth/shared-session'
5
- import { flushCliTelemetry, trackCliEvent } from '../telemetry'
6
5
 
7
6
  export async function runLogout() {
8
7
  const current = readSharedDesktopAuthSession()
@@ -21,11 +20,5 @@ export async function runLogout() {
21
20
  }
22
21
 
23
22
  clearSharedDesktopAuthSession()
24
- trackCliEvent({
25
- event: 'cli_logout',
26
- identity: { userId: current.user?.id ?? null },
27
- properties: { origin: current.origin },
28
- })
29
- await flushCliTelemetry()
30
23
  console.log(' signed out')
31
24
  }
@@ -15,21 +15,8 @@ import {
15
15
  readDaemonLockfile,
16
16
  } from '../../src/home-paths'
17
17
  import { SootSimBridgeHost } from '../../src/host/bridge-host'
18
- import { flushCliTelemetry, trackCliEvent } from '../telemetry'
19
18
  import { resolveDefaultUploadOrigin } from './upload'
20
19
 
21
- // launchd sets `XPC_SERVICE_NAME` to the agent label and systemd sets
22
- // `INVOCATION_ID` for unit-managed processes. either tells us this bridge
23
- // boot is the daemon firing rather than a user running `sootsim serve`
24
- // in a terminal — useful for filtering daemon traffic in posthog.
25
- //
26
- function runningUnderDaemon(): boolean {
27
- const xpc = process.env.XPC_SERVICE_NAME || ''
28
- if (xpc.includes('dev.sootsim.daemon')) return true
29
- if (process.env.INVOCATION_ID) return true
30
- return false
31
- }
32
-
33
20
  interface ServeOptions {
34
21
  port?: number
35
22
  }
@@ -81,9 +68,8 @@ examples:
81
68
  }
82
69
 
83
70
  ensureSootsimHome()
84
- // resolve the contrast origin the same way uploads do (probe a local
85
- // :3000 stack, else prod) so served runtimes talk auth/billing/preview
86
- // to the same origin the CLI's own entitlement + upload paths use.
71
+ // use the explicit upload/auth origin when configured, otherwise production.
72
+ // never probe a local Contrast stack during bridge startup.
87
73
  const contrastOrigin = await resolveDefaultUploadOrigin()
88
74
  const host = new SootSimBridgeHost({
89
75
  port,
@@ -115,22 +101,6 @@ examples:
115
101
  for (const id of currentIds) lastSimIds.add(id)
116
102
  }, 500)
117
103
 
118
- // single boot heartbeat so we know the bridge is alive on this machine.
119
- // not periodic — frequency would pollute posthog volumes for no signal.
120
- // explicitly flush: this process pins the event loop with a never-
121
- // resolving promise (line 155), so beforeExit will not fire and the
122
- // event would otherwise sit in the queue until SIGTERM dropped it.
123
- trackCliEvent({
124
- event: 'daemon_heartbeat',
125
- properties: {
126
- bridge_port: boundPort,
127
- under_daemon: runningUnderDaemon(),
128
- platform: process.platform,
129
- subsource: 'daemon',
130
- },
131
- })
132
- void flushCliTelemetry()
133
-
134
104
  log(`rnx bridge listening on ws://localhost:${boundPort} (runtime http on same port)`)
135
105
  if (boundPort !== port) {
136
106
  log(` (preferred port ${port} was taken — fell back to ${boundPort})`)