rnxsim 0.1.343 → 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-RFD32ACU.js → agent-52G55XTO.js} +2 -2
  23. package/dist-cli/chunks/{agent-wrapper-2YLW2HQK.js → agent-wrapper-BOZM43ON.js} +2 -2
  24. package/dist-cli/chunks/{app-fonts-6OATDF3Y.js → app-fonts-A2L6V5EZ.js} +2 -2
  25. package/dist-cli/chunks/{assert-PSQICFOY.js → assert-CJKIP4LN.js} +2 -2
  26. package/dist-cli/chunks/{auth-XWLFKZT7.js → auth-VHHN3TOB.js} +2 -2
  27. package/dist-cli/chunks/{beta-I6WTVM6C.js → beta-EBDIGV3E.js} +2 -2
  28. package/dist-cli/chunks/{camera-45HKTLWG.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-RWYA2USN.js → chunk-4BIPA7MD.js} +1 -1
  32. package/dist-cli/chunks/chunk-4OKV7T5D.js +4 -0
  33. package/dist-cli/chunks/{chunk-T4T6DDKM.js → chunk-4ZILDTZX.js} +2 -2
  34. package/dist-cli/chunks/{chunk-R7X74I3I.js → chunk-5GXRRUOA.js} +26 -26
  35. package/dist-cli/chunks/chunk-63ASUHOV.js +4 -0
  36. package/dist-cli/chunks/{chunk-DASP2EKF.js → chunk-7GO2DSYQ.js} +1 -1
  37. package/dist-cli/chunks/{chunk-HJXIBZ35.js → chunk-7LGINKM6.js} +2 -2
  38. package/dist-cli/chunks/{chunk-2IPMH24A.js → chunk-7UIIAHVU.js} +2 -2
  39. package/dist-cli/chunks/{chunk-ES5BHPTS.js → chunk-7V4KPZ7O.js} +2 -2
  40. package/dist-cli/chunks/{chunk-FCHRGEHA.js → chunk-7YMQRA6L.js} +2 -2
  41. package/dist-cli/chunks/{chunk-DC7TS573.js → chunk-A2Q76LJV.js} +2 -2
  42. package/dist-cli/chunks/{chunk-SAUCA7SN.js → chunk-BCQV63BW.js} +45 -45
  43. package/dist-cli/chunks/{chunk-3FYJ7U3C.js → chunk-BFTDL2GX.js} +17 -17
  44. package/dist-cli/chunks/chunk-BHKSCNDC.js +4 -0
  45. package/dist-cli/chunks/{chunk-QPTJNLPT.js → chunk-DGTV3KOW.js} +1 -1
  46. package/dist-cli/chunks/chunk-DHM3JDCK.js +4 -0
  47. package/dist-cli/chunks/{chunk-TQRVLK64.js → chunk-DPP2M4AJ.js} +1 -1
  48. package/dist-cli/chunks/chunk-E2RGSCHT.js +4 -0
  49. package/dist-cli/chunks/{chunk-TQ5OPG33.js → chunk-EPLVIDPC.js} +1 -1
  50. package/dist-cli/chunks/{chunk-P3IDK7FR.js → chunk-GKGXULJK.js} +2 -2
  51. package/dist-cli/chunks/{chunk-34KDMQ6U.js → chunk-HK7YKH6N.js} +2 -2
  52. package/dist-cli/chunks/{chunk-BJUNXCPO.js → chunk-HXE344V3.js} +1 -1
  53. package/dist-cli/chunks/{chunk-HJHFC5ZZ.js → chunk-JC33TOAF.js} +1 -1
  54. package/dist-cli/chunks/{chunk-G3B2RZ47.js → chunk-KA4PJNTE.js} +2 -2
  55. package/dist-cli/chunks/{chunk-VC4TDPJQ.js → chunk-KH777UAO.js} +3 -3
  56. package/dist-cli/chunks/{chunk-4PFMDBLB.js → chunk-KRZPFXVN.js} +1 -1
  57. package/dist-cli/chunks/{chunk-6SLM6URN.js → chunk-KZFJNDH3.js} +1 -1
  58. package/dist-cli/chunks/{chunk-KLMWLQAO.js → chunk-LAQGSSTT.js} +1 -1
  59. package/dist-cli/chunks/chunk-LRM2XCEQ.js +11 -0
  60. package/dist-cli/chunks/{chunk-YKKVDKLE.js → chunk-NUPRHZQW.js} +2 -2
  61. package/dist-cli/chunks/{chunk-AKV2DGKM.js → chunk-OPHT4DUO.js} +1 -1
  62. package/dist-cli/chunks/{chunk-KON6XG4Y.js → chunk-P2CGGMU2.js} +2 -2
  63. package/dist-cli/chunks/{chunk-5FB4EA33.js → chunk-PLB6UVVX.js} +2 -2
  64. package/dist-cli/chunks/{chunk-FRRHCLG2.js → chunk-PLUWN2V5.js} +1 -1
  65. package/dist-cli/chunks/{chunk-WDA4QR6U.js → chunk-QNBBKRCA.js} +2 -2
  66. package/dist-cli/chunks/{chunk-G7S6T5OX.js → chunk-QNRWPAOA.js} +2 -2
  67. package/dist-cli/chunks/{chunk-2EVBZ37G.js → chunk-R7ZNRGQN.js} +1 -1
  68. package/dist-cli/chunks/{chunk-TMJGPUWJ.js → chunk-RB4VFUNM.js} +3 -3
  69. package/dist-cli/chunks/chunk-RT3DXTDP.js +25 -0
  70. package/dist-cli/chunks/{chunk-OYLIWHDB.js → chunk-RTDHX6CW.js} +2 -2
  71. package/dist-cli/chunks/{chunk-YLFDA4WW.js → chunk-T7SBFG5I.js} +2 -2
  72. package/dist-cli/chunks/{chunk-W7EXE22C.js → chunk-TEU5NGUA.js} +2 -2
  73. package/dist-cli/chunks/chunk-TMRD5MHL.js +99 -0
  74. package/dist-cli/chunks/{chunk-SU7RE3PV.js → chunk-TOF5TA5X.js} +11 -11
  75. package/dist-cli/chunks/{chunk-6IVEGYWV.js → chunk-U5YHXQHH.js} +2 -2
  76. package/dist-cli/chunks/{chunk-BA3HRFJ5.js → chunk-UVOEHIGP.js} +1 -1
  77. package/dist-cli/chunks/{chunk-SW4DV2TY.js → chunk-VLBN3KRC.js} +1 -1
  78. package/dist-cli/chunks/{chunk-7WKV6EKX.js → chunk-WPPGU5IK.js} +2 -2
  79. package/dist-cli/chunks/{chunk-JOE3J46E.js → chunk-WU72KL6Z.js} +2 -2
  80. package/dist-cli/chunks/chunk-XJBFJGNT.js +4 -0
  81. package/dist-cli/chunks/{chunk-3CMKNWRL.js → chunk-XXZLK4BY.js} +1 -1
  82. package/dist-cli/chunks/{chunk-BKMPV6N4.js → chunk-YVSUFVVB.js} +1 -1
  83. package/dist-cli/chunks/{chunk-RO3WVQPB.js → chunk-ZMTZ5G5H.js} +2 -2
  84. package/dist-cli/chunks/{cleanup-OU4VKFC3.js → cleanup-MAVZJXVW.js} +2 -2
  85. package/dist-cli/chunks/cli-version-2B4KRNML.js +4 -0
  86. package/dist-cli/chunks/{compat-GAEKP67T.js → compat-7AURLGCS.js} +2 -2
  87. package/dist-cli/chunks/config-TN3Y4J5N.js +13 -0
  88. package/dist-cli/chunks/{control-VQJURMFD.js → control-EV2ELU5R.js} +2 -2
  89. package/dist-cli/chunks/daemon-KKDG5MYR.js +4 -0
  90. package/dist-cli/chunks/{debug-F5N2LO4T.js → debug-JICITUB6.js} +3 -3
  91. package/dist-cli/chunks/{desktop-I4ILT4BS.js → desktop-4F5HGLLX.js} +3 -3
  92. package/dist-cli/chunks/{detox-2HMPYSP4.js → detox-ZC7NHLJI.js} +2 -2
  93. package/dist-cli/chunks/{device-5LWLOB5R.js → device-V57GHRXX.js} +2 -2
  94. package/dist-cli/chunks/{diagnose-5S4IQPAP.js → diagnose-FF4IWYXC.js} +2 -2
  95. package/dist-cli/chunks/{disk-cleanup-CJSZVJQX.js → disk-cleanup-T277L6ZO.js} +2 -2
  96. package/dist-cli/chunks/drivers-LCX7S76X.js +4 -0
  97. package/dist-cli/chunks/{film-HCPU2TDB.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-YYUEZQPR.js → hidden-runtime-alias-VSJNNSNI.js} +2 -2
  101. package/dist-cli/chunks/{home-paths-3FXISM5I.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-F5KK4RC4.js → maestro-LE5LCRBL.js} +3 -3
  107. package/dist-cli/chunks/{maestro-generate-6SUU3Y5I.js → maestro-generate-D3ZIJCRL.js} +3 -3
  108. package/dist-cli/chunks/{mode-CSWGOJLI.js → mode-BWX6MDPJ.js} +2 -2
  109. package/dist-cli/chunks/{optional-demo-registry-Y6VJ4SVV.js → optional-demo-registry-6CVASL3S.js} +2 -2
  110. package/dist-cli/chunks/{perf-NRWWAJL4.js → perf-NXQZISN6.js} +2 -2
  111. package/dist-cli/chunks/{permissions-OD62A3DJ.js → permissions-5PD67RRO.js} +2 -2
  112. package/dist-cli/chunks/privacy-H5KNRNIZ.js +4 -0
  113. package/dist-cli/chunks/{record-JZT2GM3G.js → record-YJF4KXMR.js} +3 -3
  114. package/dist-cli/chunks/{report-issue-ZWSNHOPB.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-ZGJR7ICY.js → screenshot-command-VRPJXWFS.js} +3 -3
  118. package/dist-cli/chunks/{screenshot-layers-5AQKOJZK.js → screenshot-layers-QP4WA2F5.js} +2 -2
  119. package/dist-cli/chunks/{screenshots-capture-CPTWK5Y3.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-NVWRBMEO.js → skills-A7YC6RL5.js} +2 -2
  123. package/dist-cli/chunks/{state-QGLTKN6K.js → state-IJI5YROJ.js} +2 -2
  124. package/dist-cli/chunks/{storage-OZMEZ4AV.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-EXLDREY3.js → timeline-N7V2M6QA.js} +2 -2
  128. package/dist-cli/chunks/{upgrade-4VWXQO6I.js → upgrade-P2NH3BOR.js} +2 -2
  129. package/dist-cli/chunks/upload-Z2WX5DCD.js +4 -0
  130. package/dist-cli/chunks/{version-WZM6XCD2.js → version-OUHCSCUS.js} +2 -2
  131. package/dist-cli/chunks/{web-ZYPEUVWL.js → web-6NRTF3UV.js} +2 -2
  132. package/dist-cli/chunks/welcome-6RS7PEJW.js +5 -0
  133. package/dist-cli/chunks/{what-happened-KF2HLWKW.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-44LRQEU3.js +0 -4
  185. package/dist-cli/chunks/chunk-4RKTGL63.js +0 -9
  186. package/dist-cli/chunks/chunk-5SCIDXJD.js +0 -25
  187. package/dist-cli/chunks/chunk-CUVY4A2A.js +0 -4
  188. package/dist-cli/chunks/chunk-DPJGB7MP.js +0 -101
  189. package/dist-cli/chunks/chunk-HD6P3W5R.js +0 -4
  190. package/dist-cli/chunks/chunk-HFNESSHG.js +0 -15
  191. package/dist-cli/chunks/chunk-I7HHBFSD.js +0 -4
  192. package/dist-cli/chunks/chunk-LV2G34IX.js +0 -4
  193. package/dist-cli/chunks/cli-version-REQOM22G.js +0 -4
  194. package/dist-cli/chunks/config-QTFXJKD6.js +0 -13
  195. package/dist-cli/chunks/daemon-ETA375WE.js +0 -4
  196. package/dist-cli/chunks/drivers-R4YB2XAF.js +0 -4
  197. package/dist-cli/chunks/flow-3VQL6XZT.js +0 -4
  198. package/dist-cli/chunks/help-2RYCKZ2G.js +0 -4
  199. package/dist-cli/chunks/inspect-XDSX5D6D.js +0 -4
  200. package/dist-cli/chunks/install-desktop-OKVRLL35.js +0 -4
  201. package/dist-cli/chunks/login-4VCBPAY2.js +0 -28
  202. package/dist-cli/chunks/logout-WSL5JS5R.js +0 -4
  203. package/dist-cli/chunks/reset-3C52YQCV.js +0 -4
  204. package/dist-cli/chunks/runtime-4V2RBUOR.js +0 -4
  205. package/dist-cli/chunks/serve-ERAZQGCJ.js +0 -118
  206. package/dist-cli/chunks/setup-UG6PLYIL.js +0 -32
  207. package/dist-cli/chunks/store-VPBQKKWA.js +0 -4
  208. package/dist-cli/chunks/telemetry-FRW7OCYZ.js +0 -4
  209. package/dist-cli/chunks/upload-C6676NST.js +0 -4
@@ -5,7 +5,6 @@ import os from 'node:os'
5
5
  import path from 'node:path'
6
6
  import {
7
7
  COMPAT_RESULT_CAVEAT,
8
- countScanResults,
9
8
  formatDetailedScanLines,
10
9
  formatScanCounts,
11
10
  scanDeps,
@@ -14,9 +13,7 @@ import {
14
13
  import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
15
14
  import { getCliVersion } from '../../src/cli-version'
16
15
  import {
17
- isDaemonLockfileFresh,
18
16
  readActiveRuntime,
19
- readDaemonLockfile,
20
17
  readPrivacyPreferences,
21
18
  runtimeDir,
22
19
  writePrivacyPreferences,
@@ -31,46 +28,27 @@ import {
31
28
  planRepositorySetup,
32
29
  type RepositorySetupPlan,
33
30
  } from '../setup-repository'
34
- import { trackCliEvent } from '../telemetry'
31
+ import { trackCliError } from '../telemetry'
35
32
  import { daemonInstall, getDaemonServiceStatus } from './daemon'
33
+ import { isAgentEnv } from './inspect/env'
36
34
 
37
35
  interface SetupOptions {
38
36
  appDir: string
39
37
  ci: boolean
40
38
  dryRun: boolean
41
- fromWelcome: boolean
42
39
  json: boolean
43
40
  yes: boolean
44
41
  service: boolean | undefined
45
42
  repository: boolean | undefined
46
43
  productAnalytics: boolean | undefined
47
- crashReports: boolean | undefined
48
- shareCompatibility: boolean
49
- }
50
-
51
- export interface MachineSetupStatus {
52
- daemonSupported: boolean
53
- daemonInstalled: boolean
54
- daemonRunning: boolean
55
- runtimeInstalled: boolean
56
- privacyConfigured: boolean
57
44
  }
58
45
 
59
46
  export interface SetupResult {
60
47
  runtimeVersion: string
61
48
  serviceInstalled: boolean
62
49
  repositoryPrepared: boolean
63
- compatibilityShared: boolean
64
50
  }
65
51
 
66
- type SetupStage =
67
- | 'decisions'
68
- | 'runtime'
69
- | 'repository'
70
- | 'service'
71
- | 'privacy'
72
- | 'compatibility'
73
-
74
52
  export async function runSetup(args: string[]): Promise<SetupResult | undefined> {
75
53
  if (args.includes('--help') || args.includes('-h')) {
76
54
  printHelp()
@@ -78,25 +56,14 @@ export async function runSetup(args: string[]): Promise<SetupResult | undefined>
78
56
  }
79
57
 
80
58
  const options = parseSetupOptions(args)
81
- let stage: SetupStage = 'decisions'
82
59
  try {
83
60
  const packageRoot = findPackageRoot(options.appDir)
84
61
  const serviceStatus = getDaemonServiceStatus()
85
62
  const privacy = readPrivacyPreferences()
86
63
  const service = await decideService(options, serviceStatus)
87
64
  const repository = await decideRepository(options, packageRoot)
88
- const productAnalytics = await decidePrivacy(
89
- options,
90
- 'productAnalytics',
91
- privacy.productAnalytics,
92
- privacy.configured,
93
- )
94
- const crashReports = await decidePrivacy(
95
- options,
96
- 'crashReports',
97
- privacy.crashReports,
98
- privacy.configured,
99
- )
65
+ const productAnalytics = await decidePrivacy(options, privacy)
66
+ const crashReports = false
100
67
 
101
68
  const manifest = await sootsimRuntime.fetchManifest()
102
69
  const resolvedRuntime = sootsimRuntime.resolveVersion(manifest, { channel: 'stable' })
@@ -117,9 +84,8 @@ export async function runSetup(args: string[]): Promise<SetupResult | undefined>
117
84
  printIntro(options)
118
85
  printMachineSection(options, serviceStatus, service, runtimeVersion)
119
86
  printRepositorySection(options, packageRoot, repositoryPlan)
120
- printPrivacySection(options, productAnalytics, crashReports)
87
+ printPrivacySection(options, productAnalytics)
121
88
 
122
- stage = 'runtime'
123
89
  let installed = false
124
90
  if (!options.dryRun) {
125
91
  const activeRuntime = readActiveRuntime()
@@ -132,7 +98,6 @@ export async function runSetup(args: string[]): Promise<SetupResult | undefined>
132
98
  installed = result.installed
133
99
  }
134
100
 
135
- stage = 'repository'
136
101
  if (repositoryPlan) {
137
102
  await applyRepositorySetup(repositoryPlan, {
138
103
  dryRun: options.dryRun,
@@ -140,31 +105,23 @@ export async function runSetup(args: string[]): Promise<SetupResult | undefined>
140
105
  })
141
106
  }
142
107
 
143
- stage = 'service'
144
108
  let serviceInstalled = serviceStatus.installed
145
109
  if (service && !serviceStatus.installed && !options.dryRun) {
146
110
  await daemonInstall({ port: DEFAULT_SOOTSIM_BRIDGE_PORT, force: false })
147
111
  serviceInstalled = true
148
112
  }
149
113
 
150
- stage = 'privacy'
151
114
  if (!options.dryRun) {
152
115
  writePrivacyPreferences({ productAnalytics, crashReports })
153
116
  }
154
117
 
155
- stage = 'compatibility'
156
118
  const scan = packageRoot ? scanPackage(packageRoot) : null
157
- const shareCompatibility = await decideCompatibilitySharing(options, scan)
158
- if (shareCompatibility && scan && packageRoot && !options.dryRun) {
159
- await shareCompatibilityScan(packageRoot, scan)
160
- }
161
- printCompatibilitySection(options, scan, shareCompatibility)
119
+ printCompatibilitySection(options, scan)
162
120
 
163
121
  const result: SetupResult = {
164
122
  runtimeVersion,
165
123
  serviceInstalled,
166
124
  repositoryPrepared: repositoryPlan !== null,
167
- compatibilityShared: shareCompatibility && !options.dryRun,
168
125
  }
169
126
  const cache = runtimeCacheMetadata(runtimeVersion)
170
127
  if (options.json) {
@@ -187,53 +144,13 @@ export async function runSetup(args: string[]): Promise<SetupResult | undefined>
187
144
  printReadySection(repositoryPlan)
188
145
  }
189
146
 
190
- const counts = scan ? countScanResults(scan) : null
191
- trackCliEvent({
192
- event: 'cli_setup_completed',
193
- properties: {
194
- service_installed: serviceInstalled,
195
- repository_prepared: repositoryPlan !== null,
196
- product_analytics: productAnalytics,
197
- crash_reports: crashReports,
198
- compat_supported: counts?.supported ?? 0,
199
- compat_partial: counts?.partial ?? 0,
200
- compat_unsupported: counts?.unsupported ?? 0,
201
- compat_not_yet_verified: counts?.notYetVerified ?? 0,
202
- from_welcome: options.fromWelcome,
203
- ci: options.ci,
204
- dry_run: options.dryRun,
205
- },
206
- })
207
147
  return result
208
148
  } catch (error) {
209
- const message = boundedMessage(error)
210
- trackCliEvent({
211
- event: 'cli_setup_failed',
212
- properties: { stage, message },
213
- })
149
+ trackCliError(error)
214
150
  throw error
215
151
  }
216
152
  }
217
153
 
218
- export function readMachineSetupStatus(): MachineSetupStatus {
219
- const service = getDaemonServiceStatus()
220
- const lock = readDaemonLockfile()
221
- const activeRuntime = readActiveRuntime()
222
- return {
223
- daemonSupported: service.supported,
224
- daemonInstalled: service.installed,
225
- daemonRunning: Boolean(lock && isDaemonLockfileFresh(lock)),
226
- runtimeInstalled: Boolean(activeRuntime && fs.existsSync(runtimeDir(activeRuntime))),
227
- privacyConfigured: readPrivacyPreferences().configured,
228
- }
229
- }
230
-
231
- export function shouldRunSetupForBareCommand(
232
- status: MachineSetupStatus = readMachineSetupStatus(),
233
- ): boolean {
234
- return !status.runtimeInstalled || !status.privacyConfigured
235
- }
236
-
237
154
  function parseSetupOptions(args: string[]): SetupOptions {
238
155
  const appIndex = args.indexOf('--app')
239
156
  const appArg = appIndex >= 0 ? args[appIndex + 1] : undefined
@@ -244,16 +161,13 @@ function parseSetupOptions(args: string[]): SetupOptions {
244
161
  const repository = readBooleanFlag(args, '--repo', '--no-repo')
245
162
  return {
246
163
  appDir: path.resolve(appArg ?? process.cwd()),
247
- ci: args.includes('--ci'),
164
+ ci: args.includes('--ci') || isAgentEnv(),
248
165
  dryRun: args.includes('--dry-run'),
249
- fromWelcome: args.includes('--from-welcome'),
250
166
  json: args.includes('--json'),
251
167
  yes: args.includes('--yes') || args.includes('-y'),
252
168
  service,
253
169
  repository,
254
170
  productAnalytics: readOnOffFlag(args, '--analytics'),
255
- crashReports: readOnOffFlag(args, '--crash-reports'),
256
- shareCompatibility: args.includes('--share-compat'),
257
171
  }
258
172
  }
259
173
 
@@ -312,34 +226,13 @@ async function decideRepository(
312
226
 
313
227
  async function decidePrivacy(
314
228
  options: SetupOptions,
315
- key: 'productAnalytics' | 'crashReports',
316
- current: boolean,
317
- configured: boolean,
229
+ current: ReturnType<typeof readPrivacyPreferences>,
318
230
  ): Promise<boolean> {
319
- const explicit =
320
- key === 'productAnalytics' ? options.productAnalytics : options.crashReports
321
- if (explicit !== undefined) return explicit
322
- if (configured) return current
323
- if (options.yes) return true
324
- const flag =
325
- key === 'productAnalytics' ? '--analytics on|off' : '--crash-reports on|off'
326
- requireInteractive(options, flag)
327
- const question =
328
- key === 'productAnalytics'
329
- ? 'Share bounded product analytics?'
330
- : 'Send bounded crash reports?'
331
- return confirm(question, true)
332
- }
333
-
334
- async function decideCompatibilitySharing(
335
- options: SetupOptions,
336
- scan: ScanResult | null,
337
- ): Promise<boolean> {
338
- if (!scan) return false
339
- if (options.shareCompatibility) return true
340
- if (options.yes || !process.stdin.isTTY) return false
231
+ if (options.productAnalytics !== undefined) return options.productAnalytics
232
+ if (current.configured) return current.productAnalytics
233
+ if (options.yes || options.ci || !process.stdin.isTTY) return false
341
234
  return confirm(
342
- 'Share dependency names, requested versions, framework, and this compatibility result?',
235
+ 'Share anonymous package incompatibilities and error classes to improve rnx?',
343
236
  false,
344
237
  )
345
238
  }
@@ -359,51 +252,6 @@ function scanPackage(packageRoot: string): ScanResult {
359
252
  return scanDeps(parsed)
360
253
  }
361
254
 
362
- async function shareCompatibilityScan(
363
- packageRoot: string,
364
- scan: ScanResult,
365
- ): Promise<void> {
366
- const parsed: unknown = JSON.parse(
367
- fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
368
- )
369
- if (!parsed || typeof parsed !== 'object')
370
- throw new Error('package.json must be an object')
371
- const response = await fetch('https://contrast.dev/api/scan', {
372
- method: 'POST',
373
- headers: { 'content-type': 'application/json' },
374
- body: JSON.stringify(buildCompatibilitySharePayload(parsed, scan)),
375
- signal: AbortSignal.timeout(10_000),
376
- })
377
- if (!response.ok) {
378
- throw new Error(`compatibility sharing failed with HTTP ${response.status}`)
379
- }
380
- }
381
-
382
- export function buildCompatibilitySharePayload(manifest: object, scan: ScanResult) {
383
- return {
384
- dependencies: boundedDependencies(Reflect.get(manifest, 'dependencies')),
385
- devDependencies: boundedDependencies(Reflect.get(manifest, 'devDependencies')),
386
- framework: scan.framework,
387
- result: {
388
- framework: scan.framework,
389
- rnVersion: scan.rnVersion,
390
- packages: scan.packages.slice(0, 200),
391
- },
392
- source: 'desktop',
393
- shared: true,
394
- }
395
- }
396
-
397
- function boundedDependencies(value: unknown): Record<string, string> {
398
- if (!value || typeof value !== 'object') return {}
399
- const output: Record<string, string> = {}
400
- for (const [name, version] of Object.entries(value).slice(0, 200)) {
401
- if (typeof version !== 'string') continue
402
- output[name.slice(0, 160)] = version.slice(0, 80)
403
- }
404
- return output
405
- }
406
-
407
255
  function runtimeCacheMetadata(runtimeVersion: string) {
408
256
  const platform = os.platform()
409
257
  const arch = os.arch()
@@ -416,7 +264,7 @@ function runtimeCacheMetadata(runtimeVersion: string) {
416
264
 
417
265
  function printIntro(options: SetupOptions): void {
418
266
  if (options.json) return
419
- console.log(`\n ${options.fromWelcome ? 'welcome to rnx' : 'rnx setup'}`)
267
+ console.log(`\n rnx setup`)
420
268
  }
421
269
 
422
270
  function printMachineSection(
@@ -454,31 +302,17 @@ function printRepositorySection(
454
302
  }
455
303
  }
456
304
 
457
- function printPrivacySection(
458
- options: SetupOptions,
459
- productAnalytics: boolean,
460
- crashReports: boolean,
461
- ): void {
305
+ function printPrivacySection(options: SetupOptions, productAnalytics: boolean): void {
462
306
  if (options.json) return
463
307
  console.log(`\n 3. privacy`)
464
- console.log(` product analytics: ${productAnalytics ? 'on' : 'off'}`)
465
- console.log(
466
- ` command, feature, version, platform, and bounded performance events`,
467
- )
468
- console.log(` crash reports: ${crashReports ? 'on' : 'off'}`)
469
- console.log(
470
- ` error type, message, stack, runtime version, platform, and bounded dependency summary`,
471
- )
308
+ console.log(` bounded diagnostics: ${productAnalytics ? 'on' : 'off'}`)
309
+ console.log(` package name/version/unsupported API or error class only`)
472
310
  console.log(
473
- ` source files, environment values, terminal output, app data, screenshots, and recordings are not included`,
311
+ ` source, paths, project names, app content, identity, and command usage are never included`,
474
312
  )
475
313
  }
476
314
 
477
- function printCompatibilitySection(
478
- options: SetupOptions,
479
- scan: ScanResult | null,
480
- shared: boolean,
481
- ): void {
315
+ function printCompatibilitySection(options: SetupOptions, scan: ScanResult | null): void {
482
316
  if (options.json) return
483
317
  console.log(`\n 4. compatibility`)
484
318
  if (!scan) {
@@ -488,7 +322,6 @@ function printCompatibilitySection(
488
322
  console.log(` ${formatScanCounts(scan)}`)
489
323
  for (const line of formatDetailedScanLines(scan)) console.log(` ${line}`)
490
324
  console.log(` ${COMPAT_RESULT_CAVEAT}`)
491
- console.log(` dependency sharing: ${shared ? 'yes' : 'no'}`)
492
325
  }
493
326
 
494
327
  function printReadySection(repository: RepositorySetupPlan | null): void {
@@ -511,11 +344,6 @@ function printReadySection(repository: RepositorySetupPlan | null): void {
511
344
  )
512
345
  }
513
346
 
514
- function boundedMessage(error: unknown): string {
515
- const message = error instanceof Error ? error.message : String(error)
516
- return message.replace(/(?:\/?[\w.-]+)+/g, '<path>').slice(0, 240)
517
- }
518
-
519
347
  function printHelp(): void {
520
348
  console.log(`
521
349
  rnx setup — configure a machine and optionally prepare the current repository
@@ -530,11 +358,9 @@ decisions:
530
358
  --service | --no-service
531
359
  --repo | --no-repo
532
360
  --analytics on|off
533
- --crash-reports on|off
534
- --share-compat
535
361
 
536
362
  automation:
537
- --yes accept defaults; compatibility sharing still defaults off
363
+ --yes accept setup defaults; diagnostics remain off unless explicitly enabled
538
364
  --ci never prompt or install a background service
539
365
  --json emit runtime/cache metadata as JSON
540
366
  --dry-run print exact repository operations without changing the machine
@@ -13,7 +13,9 @@ import {
13
13
 
14
14
  function printStatus(): void {
15
15
  const preferences = readPrivacyPreferences()
16
- console.log(` product analytics are ${preferences.productAnalytics ? 'ON' : 'OFF'}`)
16
+ const enabled = preferences.configured && preferences.productAnalytics
17
+ console.log(` bounded diagnostics are ${enabled ? 'ON' : 'OFF'}`)
18
+ console.log(' permitted fields: package name/version/unsupported API or error class')
17
19
  console.log(` config: ${configFilePath()}`)
18
20
  const doNotTrack = process.env.DO_NOT_TRACK
19
21
  if (doNotTrack === '1' || doNotTrack === 'true') {
@@ -33,14 +35,14 @@ export async function runTelemetry(args: string[]): Promise<void> {
33
35
  return
34
36
 
35
37
  case 'on':
36
- writePrivacyPreferences({ ...readPrivacyPreferences(), productAnalytics: true })
37
- console.log(' product analytics ON')
38
+ writePrivacyPreferences({ productAnalytics: true, crashReports: false })
39
+ console.log(' bounded diagnostics ON')
38
40
  console.log(` config: ${configFilePath()}`)
39
41
  return
40
42
 
41
43
  case 'off':
42
- writePrivacyPreferences({ ...readPrivacyPreferences(), productAnalytics: false })
43
- console.log(' product analytics OFF')
44
+ writePrivacyPreferences({ productAnalytics: false, crashReports: false })
45
+ console.log(' bounded diagnostics OFF')
44
46
  console.log(` config: ${configFilePath()}`)
45
47
  return
46
48
 
@@ -21,14 +21,12 @@ import {
21
21
  isTraceTimelineEvent,
22
22
  parseTraceTimelineJsonl,
23
23
  } from 'sootsim-engine/preview/trace'
24
- import { readSharedDesktopAuthSession } from '../../src/auth/shared-session'
25
24
  import { rnxPublicBrand } from '../../src/public-brand'
26
25
  import { fetchAppFontFiles } from '../app-fonts'
27
26
  import { fetchAppSplashImages } from '../app-splash'
28
27
  import { authHeaderValue, githubUploadIdentity, resolveCliAuth } from '../auth'
29
28
  import { openUrl } from '../open-url'
30
29
  import { resolveRunProvenance } from '../run-registry'
31
- import { flushCliTelemetry, trackCliEvent } from '../telemetry'
32
30
  import { createBridgeFromParsed, evalInBridge, parseBridgeCliArgs } from '../ws-bridge'
33
31
  import type { SootSimTimelineEvent } from '@sootsim/globals'
34
32
 
@@ -114,25 +112,11 @@ const REMOTE_DEFAULT_ORIGIN = process.env.SOOTSIM_UPLOAD_ORIGIN || 'https://cont
114
112
  // reviewers/users open SootSim preview pages on sootsim.com.
115
113
  const REMOTE_DEFAULT_PUBLIC_PREVIEW_ORIGIN =
116
114
  process.env.SOOTSIM_PREVIEW_ORIGIN || rnxPublicBrand.origin
117
- const LOCAL_DEFAULT_ORIGIN = 'https://contrast.localhost:3000'
118
- const LOCAL_UPLOAD_PROBE_TIMEOUT_MS = 2_000
119
-
120
115
  export async function resolveDefaultUploadOrigin(
121
116
  explicitOrigin?: string,
122
117
  ): Promise<string> {
123
118
  if (explicitOrigin) return explicitOrigin
124
119
  if (process.env.SOOTSIM_UPLOAD_ORIGIN) return process.env.SOOTSIM_UPLOAD_ORIGIN
125
-
126
- try {
127
- const res = await fetch(`${LOCAL_DEFAULT_ORIGIN}/api/preview/upload/init`, {
128
- method: 'OPTIONS',
129
- signal: AbortSignal.timeout(LOCAL_UPLOAD_PROBE_TIMEOUT_MS),
130
- })
131
- if (res.ok || res.status === 204 || res.status === 405) {
132
- return LOCAL_DEFAULT_ORIGIN
133
- }
134
- } catch {}
135
-
136
120
  return REMOTE_DEFAULT_ORIGIN
137
121
  }
138
122
 
@@ -188,9 +172,7 @@ usage:
188
172
  rnx record upload [--origin <url>] [--public-origin <url>] (--events <path> | --video <path>) [--screenshot <path>] [--owner <org> --repo <repo>] [--sim <sim>] [--open] [--assets-only]
189
173
 
190
174
  options:
191
- --origin <url> upload target (default: auto)
192
- prefers ${LOCAL_DEFAULT_ORIGIN} when available, otherwise
193
- falls back to ${REMOTE_DEFAULT_ORIGIN}
175
+ --origin <url> upload target (default: ${REMOTE_DEFAULT_ORIGIN})
194
176
  override with SOOTSIM_UPLOAD_ORIGIN env var
195
177
  --public-origin <url>
196
178
  public /preview link origin (default: ${REMOTE_DEFAULT_PUBLIC_PREVIEW_ORIGIN}
@@ -848,14 +830,12 @@ export async function runUpload(
848
830
  : undefined
849
831
  if (!videoContentType) {
850
832
  console.error(' preview flow videos must be mp4 or gif')
851
- await flushCliTelemetry()
852
833
  process.exit(1)
853
834
  }
854
835
  if (videoDurationMsRaw) {
855
836
  const parsed = Number(videoDurationMsRaw)
856
837
  if (!Number.isFinite(parsed) || parsed <= 0) {
857
838
  console.error(` invalid --video-duration-ms: ${videoDurationMsRaw}`)
858
- await flushCliTelemetry()
859
839
  process.exit(1)
860
840
  }
861
841
  videoDurationMs = Math.round(parsed)
@@ -871,34 +851,11 @@ export async function runUpload(
871
851
  const cliAuth = resolveCliAuth()
872
852
  const gitHubIdentity = githubUploadIdentity(cliAuth)
873
853
  const provenance = resolveRunProvenance()
874
- const sharedSession = readSharedDesktopAuthSession()
875
- trackCliEvent({
876
- event: 'preview_upload_started',
877
- identity: {
878
- userId: cliAuth?.kind === 'session' ? (sharedSession?.user?.id ?? null) : null,
879
- repoId: gitHubIdentity?.repoId ?? null,
880
- installationId: gitHubIdentity?.installationId ?? null,
881
- },
882
- properties: {
883
- origin,
884
- hasAuth: Boolean(cliAuth),
885
- authMode: cliAuth?.kind ?? 'none',
886
- bundleBytes: bundleBytes.byteLength,
887
- isTransformed,
888
- extraFiles: extrasOk.length,
889
- recordedFetches: recordedFetches.length,
890
- hasEvents: Boolean(eventsGz),
891
- traceTimelineEvents: traceTimelineEvents.length,
892
- hasScreenshot: Boolean(screenshotBytes),
893
- hasVideo: Boolean(videoBytes),
894
- },
895
- })
896
854
  if (!cliAuth) {
897
855
  console.error(' preview uploads need auth.')
898
856
  console.error(
899
857
  ' set RNX_API_KEY=sk_rnx_..., run `rnx login`, or use the Contrast github runner.',
900
858
  )
901
- await flushCliTelemetry()
902
859
  process.exit(1)
903
860
  }
904
861
  const resolvedAuthHeader = authHeaderValue(cliAuth)
@@ -1194,7 +1151,6 @@ export async function runUpload(
1194
1151
  if (e.phase === 'init' && e.status === 401) {
1195
1152
  console.error(' preview upload requires a valid login.')
1196
1153
  console.error(' run `rnx login` and retry.')
1197
- await flushCliTelemetry()
1198
1154
  process.exit(1)
1199
1155
  }
1200
1156
  if (e.status === 402) {
@@ -1202,13 +1158,11 @@ export async function runUpload(
1202
1158
  console.error(
1203
1159
  ` ${parseServerMessage(e.responseText) ?? 'preview uploads require Personal, Team, or an active trial — upgrade from the billing dialog.'}`,
1204
1160
  )
1205
- await flushCliTelemetry()
1206
1161
  process.exit(1)
1207
1162
  }
1208
1163
  // PresignedUploadError.message already carries the "<phase> failed:"
1209
1164
  // prefix — don't re-prefix it (that produced "init failed: init failed:").
1210
1165
  console.error(` ${e.message ?? `${e.phase ?? 'upload'} failed: ${String(err)}`}`)
1211
- await flushCliTelemetry()
1212
1166
  process.exit(1)
1213
1167
  }
1214
1168
 
@@ -1220,6 +1174,5 @@ export async function runUpload(
1220
1174
  await openUrl(previewUrl)
1221
1175
  }
1222
1176
 
1223
- await flushCliTelemetry()
1224
1177
  return { previewUrl, shareId: finalize.id }
1225
1178
  }
@@ -0,0 +1,64 @@
1
+ import { scanDevServers, type DiscoveredServer } from '../../scripts/dev-server-scanner'
2
+ import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
3
+ import { readPrivacyPreferences } from '../../src/home-paths'
4
+ import { canPromptForPrivacyChoice } from '../privacy'
5
+ import { select } from '../prompt'
6
+ import { createBridge } from '../ws-bridge'
7
+ import { runOpenCommand } from './control'
8
+
9
+ function serverLabel(server: DiscoveredServer): string {
10
+ return `${server.projectName?.trim() || server.framework} on :${server.port}`
11
+ }
12
+
13
+ async function chooseServer(
14
+ discovered: DiscoveredServer[],
15
+ ): Promise<DiscoveredServer | null> {
16
+ if (discovered.length === 0) return null
17
+ const ordered = [...discovered].sort((a, b) => a.port - b.port)
18
+ if (ordered.length === 1 || !canPromptForPrivacyChoice()) return ordered[0] ?? null
19
+ const selected = await select(
20
+ 'which running app should rnx open?',
21
+ ordered.map(serverLabel),
22
+ )
23
+ return ordered[selected] ?? ordered[0] ?? null
24
+ }
25
+
26
+ export async function runWelcome(): Promise<number> {
27
+ const privacy = readPrivacyPreferences()
28
+ console.log('\n welcome to rnx')
29
+ console.log(
30
+ ` diagnostics: ${privacy.configured && privacy.productAnalytics ? 'bounded opt-in on' : 'off until you opt in'}`,
31
+ )
32
+ console.log(' looking for a running React Native app…')
33
+
34
+ const selected = await chooseServer(
35
+ await scanDevServers({ excludePorts: [DEFAULT_SOOTSIM_BRIDGE_PORT] }),
36
+ )
37
+ if (!selected) {
38
+ console.error(' no running React Native development server found.')
39
+ console.error(' start your app normally, then run `npx rnxsim` again.')
40
+ return 1
41
+ }
42
+
43
+ console.log(` found ${serverLabel(selected)} · opening simulator…`)
44
+ const bridgePort = await runOpenCommand([selected.bundleUrl])
45
+ if (bridgePort !== undefined) {
46
+ const { runInspect } = await import('./inspect')
47
+ await runInspect(['wait', 'ready', '--max-ms', '120000'], { port: bridgePort })
48
+ const bridge = createBridge(bridgePort, { commandTimeoutMs: 45_000 })
49
+ try {
50
+ const frame: unknown = await bridge.send({ type: 'screenshot' })
51
+ const pngPrefix = 'data:image/png;base64,'
52
+ if (
53
+ typeof frame !== 'string' ||
54
+ !frame.startsWith(pngPrefix) ||
55
+ frame.length <= pngPrefix.length
56
+ ) {
57
+ throw new Error('the simulator connected but did not produce a visible app frame')
58
+ }
59
+ } finally {
60
+ bridge.close()
61
+ }
62
+ }
63
+ return 0
64
+ }