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.
- package/README.md +59 -31
- package/cli/app-fonts.ts +8 -28
- package/cli/app-project.ts +12 -184
- package/cli/app-splash.ts +3 -17
- package/cli/bin.ts +15 -28
- package/cli/commands/control.ts +20 -30
- package/cli/commands/daemon.ts +19 -44
- package/cli/commands/flow.ts +0 -27
- package/cli/commands/install-desktop.ts +2 -16
- package/cli/commands/login.ts +3 -43
- package/cli/commands/logout.ts +0 -7
- package/cli/commands/serve.ts +2 -32
- package/cli/commands/setup.ts +20 -194
- package/cli/commands/telemetry.ts +7 -5
- package/cli/commands/upload.ts +1 -48
- package/cli/commands/welcome.ts +64 -0
- package/cli/outbound-endpoints.ts +586 -0
- package/cli/privacy.ts +53 -0
- package/cli/runtime-notes.ts +2 -2
- package/cli/telemetry.ts +46 -149
- package/dist-cli/bin.js +6 -6
- package/dist-cli/chunks/{agent-HTSE5FA4.js → agent-52G55XTO.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-L6X2AEZL.js → agent-wrapper-BOZM43ON.js} +2 -2
- package/dist-cli/chunks/{app-fonts-FGF3ETYH.js → app-fonts-A2L6V5EZ.js} +2 -2
- package/dist-cli/chunks/{assert-HA2ZYVDN.js → assert-CJKIP4LN.js} +2 -2
- package/dist-cli/chunks/{auth-HONDAV75.js → auth-VHHN3TOB.js} +2 -2
- package/dist-cli/chunks/{beta-U7EE4GMR.js → beta-EBDIGV3E.js} +2 -2
- package/dist-cli/chunks/{camera-RTKNUTIX.js → camera-5F4KKCQ3.js} +2 -2
- package/dist-cli/chunks/chunk-3DBTS4MC.js +15 -0
- package/dist-cli/chunks/chunk-3N7M5HMJ.js +6 -0
- package/dist-cli/chunks/{chunk-S7CSBQ6G.js → chunk-4BIPA7MD.js} +1 -1
- package/dist-cli/chunks/chunk-4OKV7T5D.js +4 -0
- package/dist-cli/chunks/{chunk-CNLPLCO2.js → chunk-4ZILDTZX.js} +2 -2
- package/dist-cli/chunks/{chunk-HRBMD2FS.js → chunk-5GXRRUOA.js} +26 -26
- package/dist-cli/chunks/chunk-63ASUHOV.js +4 -0
- package/dist-cli/chunks/{chunk-XQFDEY3F.js → chunk-7GO2DSYQ.js} +1 -1
- package/dist-cli/chunks/{chunk-IWR4HFC4.js → chunk-7LGINKM6.js} +2 -2
- package/dist-cli/chunks/{chunk-TZNRKIS3.js → chunk-7UIIAHVU.js} +2 -2
- package/dist-cli/chunks/{chunk-Q2B6EQPB.js → chunk-7V4KPZ7O.js} +2 -2
- package/dist-cli/chunks/{chunk-EPEZZ6YS.js → chunk-7YMQRA6L.js} +2 -2
- package/dist-cli/chunks/{chunk-IPC45HTT.js → chunk-A2Q76LJV.js} +2 -2
- package/dist-cli/chunks/{chunk-EH35QQG4.js → chunk-BCQV63BW.js} +45 -45
- package/dist-cli/chunks/{chunk-N5PFDTFL.js → chunk-BFTDL2GX.js} +17 -17
- package/dist-cli/chunks/chunk-BHKSCNDC.js +4 -0
- package/dist-cli/chunks/{chunk-6PEZSVIG.js → chunk-DGTV3KOW.js} +1 -1
- package/dist-cli/chunks/chunk-DHM3JDCK.js +4 -0
- package/dist-cli/chunks/{chunk-KT6WMCUS.js → chunk-DPP2M4AJ.js} +1 -1
- package/dist-cli/chunks/chunk-E2RGSCHT.js +4 -0
- package/dist-cli/chunks/{chunk-S6LBAUWH.js → chunk-EPLVIDPC.js} +1 -1
- package/dist-cli/chunks/{chunk-6NLWKL7Y.js → chunk-GKGXULJK.js} +2 -2
- package/dist-cli/chunks/{chunk-7V4ULF3U.js → chunk-HK7YKH6N.js} +2 -2
- package/dist-cli/chunks/{chunk-6E6SBYIO.js → chunk-HXE344V3.js} +1 -1
- package/dist-cli/chunks/{chunk-JLUEQPEF.js → chunk-JC33TOAF.js} +1 -1
- package/dist-cli/chunks/{chunk-7JEEO33Y.js → chunk-KA4PJNTE.js} +2 -2
- package/dist-cli/chunks/{chunk-K3VNCCEJ.js → chunk-KH777UAO.js} +3 -3
- package/dist-cli/chunks/{chunk-G3UAFZE2.js → chunk-KRZPFXVN.js} +1 -1
- package/dist-cli/chunks/{chunk-R3UYHE6G.js → chunk-KZFJNDH3.js} +1 -1
- package/dist-cli/chunks/{chunk-22WJPMTQ.js → chunk-LAQGSSTT.js} +1 -1
- package/dist-cli/chunks/chunk-LRM2XCEQ.js +11 -0
- package/dist-cli/chunks/{chunk-MWUXQIA3.js → chunk-NUPRHZQW.js} +2 -2
- package/dist-cli/chunks/{chunk-JFUVWIJT.js → chunk-OPHT4DUO.js} +1 -1
- package/dist-cli/chunks/{chunk-EN32LN2B.js → chunk-P2CGGMU2.js} +2 -2
- package/dist-cli/chunks/{chunk-UCVQOQCY.js → chunk-PLB6UVVX.js} +2 -2
- package/dist-cli/chunks/{chunk-TOHQI2II.js → chunk-PLUWN2V5.js} +1 -1
- package/dist-cli/chunks/{chunk-ZPTFL5FQ.js → chunk-QNBBKRCA.js} +2 -2
- package/dist-cli/chunks/{chunk-NRTHFEPM.js → chunk-QNRWPAOA.js} +2 -2
- package/dist-cli/chunks/{chunk-63NZGJ4A.js → chunk-R7ZNRGQN.js} +1 -1
- package/dist-cli/chunks/{chunk-FZ5DRZJE.js → chunk-RB4VFUNM.js} +3 -3
- package/dist-cli/chunks/chunk-RT3DXTDP.js +25 -0
- package/dist-cli/chunks/{chunk-KBSVSAAE.js → chunk-RTDHX6CW.js} +2 -2
- package/dist-cli/chunks/{chunk-OCUXAA6O.js → chunk-T7SBFG5I.js} +2 -2
- package/dist-cli/chunks/{chunk-GRX6NSBG.js → chunk-TEU5NGUA.js} +2 -2
- package/dist-cli/chunks/chunk-TMRD5MHL.js +99 -0
- package/dist-cli/chunks/{chunk-POOCKX5B.js → chunk-TOF5TA5X.js} +11 -11
- package/dist-cli/chunks/{chunk-G6IPT2PS.js → chunk-U5YHXQHH.js} +2 -2
- package/dist-cli/chunks/{chunk-H4J7EWZC.js → chunk-UVOEHIGP.js} +1 -1
- package/dist-cli/chunks/{chunk-ZZSBCGHC.js → chunk-VLBN3KRC.js} +1 -1
- package/dist-cli/chunks/{chunk-PNMCALX5.js → chunk-WPPGU5IK.js} +2 -2
- package/dist-cli/chunks/{chunk-NDGAF5OF.js → chunk-WU72KL6Z.js} +2 -2
- package/dist-cli/chunks/chunk-XJBFJGNT.js +4 -0
- package/dist-cli/chunks/{chunk-BGLWR43R.js → chunk-XXZLK4BY.js} +1 -1
- package/dist-cli/chunks/{chunk-CRWYKW67.js → chunk-YVSUFVVB.js} +1 -1
- package/dist-cli/chunks/{chunk-EZLLZDYX.js → chunk-ZMTZ5G5H.js} +2 -2
- package/dist-cli/chunks/{cleanup-EMYD5WZG.js → cleanup-MAVZJXVW.js} +2 -2
- package/dist-cli/chunks/cli-version-2B4KRNML.js +4 -0
- package/dist-cli/chunks/{compat-W2N5QTVG.js → compat-7AURLGCS.js} +2 -2
- package/dist-cli/chunks/config-TN3Y4J5N.js +13 -0
- package/dist-cli/chunks/{control-4SFBROUE.js → control-EV2ELU5R.js} +2 -2
- package/dist-cli/chunks/daemon-KKDG5MYR.js +4 -0
- package/dist-cli/chunks/{debug-HCR2KFUA.js → debug-JICITUB6.js} +3 -3
- package/dist-cli/chunks/{desktop-T2KS5PBJ.js → desktop-4F5HGLLX.js} +3 -3
- package/dist-cli/chunks/{detox-5S7EHINH.js → detox-ZC7NHLJI.js} +2 -2
- package/dist-cli/chunks/{device-LVM3MZRJ.js → device-V57GHRXX.js} +2 -2
- package/dist-cli/chunks/{diagnose-WK37XKLI.js → diagnose-FF4IWYXC.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-X7VJOXMS.js → disk-cleanup-T277L6ZO.js} +2 -2
- package/dist-cli/chunks/drivers-LCX7S76X.js +4 -0
- package/dist-cli/chunks/{film-7KLTI3ER.js → film-G7ZAPWB7.js} +3 -3
- package/dist-cli/chunks/flow-ONZGGFGD.js +4 -0
- package/dist-cli/chunks/help-DROVDXJM.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-4RVGUVFO.js → hidden-runtime-alias-VSJNNSNI.js} +2 -2
- package/dist-cli/chunks/{home-paths-5DHSAEGZ.js → home-paths-75HP3HKA.js} +2 -2
- package/dist-cli/chunks/inspect-MDA7ESGQ.js +4 -0
- package/dist-cli/chunks/install-desktop-EIVZHIFA.js +4 -0
- package/dist-cli/chunks/login-ZSIHGHUK.js +26 -0
- package/dist-cli/chunks/logout-Q4DXMI2C.js +4 -0
- package/dist-cli/chunks/{maestro-HTRLQDJE.js → maestro-LE5LCRBL.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-GX2QNA3F.js → maestro-generate-D3ZIJCRL.js} +3 -3
- package/dist-cli/chunks/{mode-GM6KZHQP.js → mode-BWX6MDPJ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-B4TD7JQP.js → optional-demo-registry-6CVASL3S.js} +2 -2
- package/dist-cli/chunks/{perf-3PRXJQIC.js → perf-NXQZISN6.js} +2 -2
- package/dist-cli/chunks/{permissions-TJZIRF2S.js → permissions-5PD67RRO.js} +2 -2
- package/dist-cli/chunks/privacy-H5KNRNIZ.js +4 -0
- package/dist-cli/chunks/{record-LI55DTPE.js → record-YJF4KXMR.js} +3 -3
- package/dist-cli/chunks/{report-issue-TBGJVQIQ.js → report-issue-XOL5FQBG.js} +2 -2
- package/dist-cli/chunks/reset-5LZN5P5B.js +4 -0
- package/dist-cli/chunks/runtime-U36VWBH3.js +4 -0
- package/dist-cli/chunks/{screenshot-command-BEN7YYIF.js → screenshot-command-VRPJXWFS.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-3IU4KYNO.js → screenshot-layers-QP4WA2F5.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-ZRC54ST6.js → screenshots-capture-O2IBAVSP.js} +2 -2
- package/dist-cli/chunks/serve-WC6RZNJL.js +118 -0
- package/dist-cli/chunks/setup-A6BIG3KL.js +30 -0
- package/dist-cli/chunks/{skills-GKBR2HQB.js → skills-A7YC6RL5.js} +2 -2
- package/dist-cli/chunks/{state-LIHZJSL7.js → state-IJI5YROJ.js} +2 -2
- package/dist-cli/chunks/{storage-4TPN3NFB.js → storage-Z2DBO2PQ.js} +4 -4
- package/dist-cli/chunks/store-BYTCKNIC.js +4 -0
- package/dist-cli/chunks/telemetry-JLHFMD7N.js +4 -0
- package/dist-cli/chunks/{timeline-EX63UNWU.js → timeline-N7V2M6QA.js} +2 -2
- package/dist-cli/chunks/{upgrade-O6Y6EINE.js → upgrade-P2NH3BOR.js} +2 -2
- package/dist-cli/chunks/upload-Z2WX5DCD.js +4 -0
- package/dist-cli/chunks/{version-HLNL3NFB.js → version-OUHCSCUS.js} +2 -2
- package/dist-cli/chunks/{web-4EDPYPW7.js → web-6NRTF3UV.js} +2 -2
- package/dist-cli/chunks/welcome-6RS7PEJW.js +5 -0
- package/dist-cli/chunks/{what-happened-77VNUEPK.js → what-happened-FUEL3BEF.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +18 -4
- package/dist-lib/home-paths.cjs +145 -11
- package/dist-lib/host/bridge-host.cjs +236 -31
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +71 -4
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +337 -37
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +484 -14
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +25 -2
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +384 -385
- package/dist-lib/vite.cjs +193 -37
- package/package.json +2 -1
- package/scripts/dev-server-scanner.ts +12 -5
- package/skills/rnx-test/SKILL.md +4 -0
- package/src/dev-bundle-resolution.ts +13 -6
- package/src/dev-server-open.ts +197 -0
- package/src/home-paths.ts +168 -15
- package/src/host/bridge-host.ts +2 -2
- package/src/host/replacement-module-handler.ts +68 -2
- package/src/metro-plugin.ts +83 -5
- package/src/native-dev-bundle-url.ts +22 -0
- package/src/vite-plugin-one.ts +42 -28
- package/dist-cli/chunks/chunk-3JC7H4PR.js +0 -25
- package/dist-cli/chunks/chunk-6DLIC7BZ.js +0 -4
- package/dist-cli/chunks/chunk-7TNPO2OJ.js +0 -9
- package/dist-cli/chunks/chunk-AMF5KTOI.js +0 -4
- package/dist-cli/chunks/chunk-BX5VXTOQ.js +0 -101
- package/dist-cli/chunks/chunk-D73H7ACZ.js +0 -4
- package/dist-cli/chunks/chunk-DY4O7KYI.js +0 -4
- package/dist-cli/chunks/chunk-GU2V4JDG.js +0 -15
- package/dist-cli/chunks/chunk-Z2HMSVSN.js +0 -4
- package/dist-cli/chunks/cli-version-CN3NTKLH.js +0 -4
- package/dist-cli/chunks/config-SELKGT4F.js +0 -13
- package/dist-cli/chunks/daemon-V2SFCU2E.js +0 -4
- package/dist-cli/chunks/drivers-3YFTJ5WA.js +0 -4
- package/dist-cli/chunks/flow-36ANTMJU.js +0 -4
- package/dist-cli/chunks/help-ZGL26SPK.js +0 -4
- package/dist-cli/chunks/inspect-R3B55RTS.js +0 -4
- package/dist-cli/chunks/install-desktop-TZ3H3VWK.js +0 -4
- package/dist-cli/chunks/login-4DFULI7S.js +0 -28
- package/dist-cli/chunks/logout-QMCVYMBB.js +0 -4
- package/dist-cli/chunks/reset-O6MW6X7X.js +0 -4
- package/dist-cli/chunks/runtime-JESXBHRQ.js +0 -4
- package/dist-cli/chunks/serve-QGKTWPNF.js +0 -118
- package/dist-cli/chunks/setup-3WPWATCX.js +0 -32
- package/dist-cli/chunks/store-VBX3L46S.js +0 -4
- package/dist-cli/chunks/telemetry-ACNNIQIG.js +0 -4
- package/dist-cli/chunks/upload-OD2UQHMM.js +0 -4
package/cli/commands/setup.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
316
|
-
current: boolean,
|
|
317
|
-
configured: boolean,
|
|
229
|
+
current: ReturnType<typeof readPrivacyPreferences>,
|
|
318
230
|
): Promise<boolean> {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (
|
|
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
|
|
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
|
|
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(`
|
|
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
|
|
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;
|
|
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
|
-
|
|
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({
|
|
37
|
-
console.log('
|
|
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({
|
|
43
|
-
console.log('
|
|
44
|
+
writePrivacyPreferences({ productAnalytics: false, crashReports: false })
|
|
45
|
+
console.log(' bounded diagnostics OFF')
|
|
44
46
|
console.log(` config: ${configFilePath()}`)
|
|
45
47
|
return
|
|
46
48
|
|
package/cli/commands/upload.ts
CHANGED
|
@@ -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:
|
|
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
|
+
}
|