rnxsim 0.1.352 → 0.1.354
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 +17 -16
- package/cli/bin.ts +5 -4
- package/cli/commands/control.ts +20 -5
- package/cli/commands/daemon-mac-app.ts +1 -1
- package/cli/commands/daemon.ts +6 -8
- package/cli/commands/install-desktop.ts +42 -32
- package/cli/commands/no-bridge-hint.ts +3 -3
- package/cli/commands/serve.ts +1 -1
- package/cli/commands/setup.ts +215 -176
- package/cli/commands/welcome.ts +9 -58
- package/cli/desktop-companion.ts +31 -16
- package/cli/prompt.ts +12 -7
- package/cli/setup-repository.ts +6 -2
- package/cli/ui.ts +68 -0
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-27WDUXK5.js → agent-FB7RPXO6.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-XAUWPZ6O.js → agent-wrapper-LFU3XEIG.js} +2 -2
- package/dist-cli/chunks/{app-fonts-COAZFLDG.js → app-fonts-FK6SETRG.js} +2 -2
- package/dist-cli/chunks/{assert-ZR2UE3EH.js → assert-3KQYZDDK.js} +2 -2
- package/dist-cli/chunks/{auth-LISHWKCC.js → auth-RFE3J27C.js} +2 -2
- package/dist-cli/chunks/{beta-AQQUYVA5.js → beta-XVY4WOYH.js} +2 -2
- package/dist-cli/chunks/{camera-KE44ZN3U.js → camera-JROBX5GM.js} +2 -2
- package/dist-cli/chunks/chunk-24DA3Y2Z.js +9 -0
- package/dist-cli/chunks/{chunk-E42ZJLPN.js → chunk-37S36DFW.js} +1 -1
- package/dist-cli/chunks/{chunk-LRKODRWI.js → chunk-3QLERZYJ.js} +2 -2
- package/dist-cli/chunks/{chunk-VQDY7NEJ.js → chunk-3RW6W3ZO.js} +1 -1
- package/dist-cli/chunks/{chunk-R4P7WO4L.js → chunk-4AQCDL24.js} +2 -2
- package/dist-cli/chunks/{chunk-M6DC6JZL.js → chunk-4OS3SXPZ.js} +2 -2
- package/dist-cli/chunks/{chunk-TF6VBUZ7.js → chunk-766UIGCS.js} +2 -2
- package/dist-cli/chunks/{chunk-PEBQKBEP.js → chunk-77CBLMD4.js} +1 -1
- package/dist-cli/chunks/{chunk-7T7DR34H.js → chunk-7WANPS3W.js} +2 -2
- package/dist-cli/chunks/{chunk-MJB6N7WS.js → chunk-ATQPDEED.js} +2 -2
- package/dist-cli/chunks/chunk-B7OMSJXC.js +15 -0
- package/dist-cli/chunks/{chunk-MJJP2BEI.js → chunk-BAWV2UEF.js} +3 -3
- package/dist-cli/chunks/{chunk-DSF4WC4X.js → chunk-BNXXNT3I.js} +2 -2
- package/dist-cli/chunks/{chunk-BZ32JGFC.js → chunk-CKKDXTKV.js} +1 -1
- package/dist-cli/chunks/{chunk-P5YC5VGA.js → chunk-CUK6Y2RR.js} +2 -2
- package/dist-cli/chunks/{chunk-XI4W6LRQ.js → chunk-ENPWD62S.js} +2 -2
- package/dist-cli/chunks/{chunk-ZK5HYQ4I.js → chunk-EWPX6LEN.js} +2 -2
- package/dist-cli/chunks/{chunk-AIGZ3TSW.js → chunk-FEHHM2LV.js} +3 -3
- package/dist-cli/chunks/{chunk-QP7KGSU4.js → chunk-FPH4TYZO.js} +3 -3
- package/dist-cli/chunks/{chunk-XHZEKHB2.js → chunk-GNKXRXND.js} +6 -6
- package/dist-cli/chunks/{chunk-3ZV4WSCR.js → chunk-GYGDIT5V.js} +2 -2
- package/dist-cli/chunks/{chunk-YAMKV3UB.js → chunk-HIYCRDUP.js} +2 -2
- package/dist-cli/chunks/{chunk-5JINX2IB.js → chunk-HUU7ZUQK.js} +2 -2
- package/dist-cli/chunks/{chunk-4AOAJXE2.js → chunk-IGV4KCCM.js} +2 -2
- package/dist-cli/chunks/{chunk-5JE5PNIV.js → chunk-IICFLREN.js} +1 -1
- package/dist-cli/chunks/chunk-IUL2WUWW.js +32 -0
- package/dist-cli/chunks/{chunk-EHQHK7KN.js → chunk-JJOHJNUQ.js} +2 -2
- package/dist-cli/chunks/{chunk-ESVF72YH.js → chunk-JT435OOM.js} +2 -2
- package/dist-cli/chunks/{chunk-R2BFC3AC.js → chunk-JT4IMNCO.js} +2 -2
- package/dist-cli/chunks/{chunk-S2PJOB2C.js → chunk-JWXAXCC6.js} +2 -2
- package/dist-cli/chunks/{chunk-CY6HBAOB.js → chunk-JXNR2KAB.js} +2 -2
- package/dist-cli/chunks/{chunk-45D2GGIA.js → chunk-LC77IVGY.js} +2 -2
- package/dist-cli/chunks/{chunk-H6MTPXZS.js → chunk-LCPZNPIB.js} +1 -1
- package/dist-cli/chunks/chunk-LETVUC6M.js +11 -0
- package/dist-cli/chunks/chunk-LRVL5MAX.js +4 -0
- package/dist-cli/chunks/{chunk-24CIPQT5.js → chunk-MIK6LMG4.js} +1 -1
- package/dist-cli/chunks/{chunk-JEPQ5YX3.js → chunk-N3CE6AZP.js} +2 -2
- package/dist-cli/chunks/{chunk-AR3CPCW3.js → chunk-OKFSCCFC.js} +1 -1
- package/dist-cli/chunks/{chunk-3Y7NWE22.js → chunk-P4GCLNFM.js} +2 -2
- package/dist-cli/chunks/{chunk-NQMZOJPX.js → chunk-PHIYWV44.js} +2 -2
- package/dist-cli/chunks/{chunk-WNJDE2JT.js → chunk-QQNNY43R.js} +1 -1
- package/dist-cli/chunks/{chunk-FHLEA4S5.js → chunk-QRYTCPNO.js} +2 -2
- package/dist-cli/chunks/{chunk-Q4ROOH3W.js → chunk-SLD2EMLZ.js} +2 -2
- package/dist-cli/chunks/{chunk-ELNSQ352.js → chunk-THFM2CFT.js} +1 -1
- package/dist-cli/chunks/{chunk-EGKGCDG5.js → chunk-TJRKLRNP.js} +1 -1
- package/dist-cli/chunks/{chunk-H4IF54WS.js → chunk-UAYXEP74.js} +1 -1
- package/dist-cli/chunks/{chunk-BQE4E24T.js → chunk-UI2IFVHB.js} +1 -1
- package/dist-cli/chunks/chunk-UVIWE3LD.js +124 -0
- package/dist-cli/chunks/chunk-UX6D4X6B.js +24 -0
- package/dist-cli/chunks/{chunk-RH6FJI5O.js → chunk-X2DJK3TB.js} +2 -2
- package/dist-cli/chunks/chunk-Y4GUWO3X.js +7 -0
- package/dist-cli/chunks/{chunk-DJAYEBF3.js → chunk-YATZ7U4S.js} +1 -1
- package/dist-cli/chunks/{chunk-RASWCAJJ.js → chunk-YIUIFZAE.js} +2 -2
- package/dist-cli/chunks/{chunk-QJTW4QQW.js → chunk-YXBNGSG6.js} +1 -1
- package/dist-cli/chunks/{chunk-2OME2KGY.js → chunk-ZJUFI3R7.js} +1 -1
- package/dist-cli/chunks/{chunk-6NSUY346.js → chunk-ZNABCRWX.js} +2 -2
- package/dist-cli/chunks/{cleanup-JUY2WU24.js → cleanup-F74ISXJC.js} +2 -2
- package/dist-cli/chunks/cli-version-VSDCFXXN.js +4 -0
- package/dist-cli/chunks/{compat-S2TBISY3.js → compat-C3RGYGXL.js} +2 -2
- package/dist-cli/chunks/{config-3PHD4J5N.js → config-CDY2RB7Q.js} +2 -2
- package/dist-cli/chunks/control-J35HAFZA.js +4 -0
- package/dist-cli/chunks/daemon-DLLEODJY.js +4 -0
- package/dist-cli/chunks/{debug-PFAJONVV.js → debug-3P2DUTUQ.js} +3 -3
- package/dist-cli/chunks/{desktop-Z7EOBMNV.js → desktop-XIXW34VW.js} +4 -4
- package/dist-cli/chunks/{detox-KRSP5SLY.js → detox-KAKTJ4P4.js} +2 -2
- package/dist-cli/chunks/{device-ZXJ7GRBO.js → device-4MAWLZMR.js} +2 -2
- package/dist-cli/chunks/{diagnose-JIMLEOEJ.js → diagnose-A3R7HUYA.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-YY7FFGVA.js → disk-cleanup-5R7JYCO6.js} +2 -2
- package/dist-cli/chunks/drivers-BB3BRKDS.js +4 -0
- package/dist-cli/chunks/{film-LKSJPU2A.js → film-GY5U752Q.js} +3 -3
- package/dist-cli/chunks/flow-ALMSRBVL.js +4 -0
- package/dist-cli/chunks/help-3ZL7MRUX.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-ZN3WZ3ND.js → hidden-runtime-alias-HSGN3GN4.js} +2 -2
- package/dist-cli/chunks/home-paths-BIUN4CBO.js +4 -0
- package/dist-cli/chunks/inspect-RCU7XVAO.js +4 -0
- package/dist-cli/chunks/install-desktop-LYVKLTCU.js +4 -0
- package/dist-cli/chunks/{login-XKLIFTAU.js → login-WKNMS4GG.js} +2 -2
- package/dist-cli/chunks/{logout-DR22RB5H.js → logout-6UFUOESK.js} +2 -2
- package/dist-cli/chunks/{maestro-SLCX6HBV.js → maestro-SJGV7B3W.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-GBFZ5INV.js → maestro-generate-PMF2LLKX.js} +3 -3
- package/dist-cli/chunks/{mode-F4R2KNXX.js → mode-MN7LZCLB.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-HM55KXGB.js → optional-demo-registry-HFA27YSP.js} +2 -2
- package/dist-cli/chunks/{perf-VBS5GEPG.js → perf-XGANSJT3.js} +2 -2
- package/dist-cli/chunks/{permissions-F46PQIUE.js → permissions-25UWEJKW.js} +2 -2
- package/dist-cli/chunks/privacy-SIDMP5EF.js +4 -0
- package/dist-cli/chunks/{record-NLZ6DFAA.js → record-MA3AI752.js} +3 -3
- package/dist-cli/chunks/{report-issue-XIE5BVR4.js → report-issue-4DTESWE2.js} +2 -2
- package/dist-cli/chunks/reset-GPHG5XN3.js +4 -0
- package/dist-cli/chunks/runtime-VOEIOODA.js +4 -0
- package/dist-cli/chunks/{screenshot-command-SD4JPNKW.js → screenshot-command-JUXMWXS5.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-X65RC3GT.js → screenshot-layers-DJF2E4PE.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-BBXN7FEZ.js → screenshots-capture-UGZU5GOW.js} +2 -2
- package/dist-cli/chunks/{serve-M6ZKMSAG.js → serve-H7GNKJSM.js} +2 -2
- package/dist-cli/chunks/setup-G2WYLPM6.js +4 -0
- package/dist-cli/chunks/{skills-KDWGQBOP.js → skills-4JGPOSFE.js} +2 -2
- package/dist-cli/chunks/{state-NWABXG2P.js → state-DEAQFKVP.js} +2 -2
- package/dist-cli/chunks/{storage-QQE3G65Q.js → storage-Y6F5NTGH.js} +2 -2
- package/dist-cli/chunks/store-3EQT7VU6.js +4 -0
- package/dist-cli/chunks/telemetry-FANCQHKG.js +4 -0
- package/dist-cli/chunks/{timeline-2VZ45MMB.js → timeline-HOHYYDOC.js} +2 -2
- package/dist-cli/chunks/{upgrade-T7PDR6T5.js → upgrade-QF5YHLSG.js} +2 -2
- package/dist-cli/chunks/upload-QKJHFAX7.js +4 -0
- package/dist-cli/chunks/{version-BX6QX5XA.js → version-PDCKYJLB.js} +2 -2
- package/dist-cli/chunks/{web-4J6JRZN2.js → web-C5EUAFFW.js} +2 -2
- package/dist-cli/chunks/welcome-3CQ2GE4F.js +5 -0
- package/dist-cli/chunks/{what-happened-CHQKFNCM.js → what-happened-L56ZFIMJ.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +2 -2
- 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 +1 -1
- package/dist-lib/home-paths.cjs +21 -1
- package/dist-lib/host/bridge-host.cjs +1 -1
- 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 +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2 -2
- 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 +2 -2
- 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 +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +87 -22
- package/dist-lib/vite.cjs +2 -2
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +3 -3
- package/skills/rnx-setup/SKILL.md +17 -5
- package/src/agent-daemon-client.ts +1 -1
- package/src/home-paths.ts +22 -0
- package/src/metro-plugin.ts +1 -1
- package/src/runtime-assets.ts +1 -1
- package/dist-cli/chunks/chunk-2JZXOHH6.js +0 -4
- package/dist-cli/chunks/chunk-2WJABJ6C.js +0 -15
- package/dist-cli/chunks/chunk-5OVXQKUP.js +0 -25
- package/dist-cli/chunks/chunk-DFTG53TX.js +0 -11
- package/dist-cli/chunks/chunk-HF2FZ2WN.js +0 -7
- package/dist-cli/chunks/chunk-S63ENXGH.js +0 -6
- package/dist-cli/chunks/chunk-UHP33XGC.js +0 -124
- package/dist-cli/chunks/cli-version-6SQSIFNQ.js +0 -4
- package/dist-cli/chunks/control-GLBCTKAA.js +0 -4
- package/dist-cli/chunks/daemon-H4OVIEMH.js +0 -4
- package/dist-cli/chunks/drivers-63LY2NCK.js +0 -4
- package/dist-cli/chunks/flow-JHKPF7BN.js +0 -4
- package/dist-cli/chunks/help-Q6OY6VVA.js +0 -4
- package/dist-cli/chunks/home-paths-UOATIRKF.js +0 -4
- package/dist-cli/chunks/inspect-DW3V2FD4.js +0 -4
- package/dist-cli/chunks/install-desktop-GWY5H22W.js +0 -4
- package/dist-cli/chunks/privacy-34FNXPJP.js +0 -4
- package/dist-cli/chunks/reset-BAGCFYTS.js +0 -4
- package/dist-cli/chunks/runtime-JTYB4CM7.js +0 -4
- package/dist-cli/chunks/setup-KTWKZOJB.js +0 -30
- package/dist-cli/chunks/store-6XW4YZM6.js +0 -4
- package/dist-cli/chunks/telemetry-MVSV7JHI.js +0 -4
- package/dist-cli/chunks/upload-RF2MNO2X.js +0 -4
- package/dist-cli/chunks/welcome-3MJHGERV.js +0 -5
package/cli/commands/setup.ts
CHANGED
|
@@ -1,36 +1,44 @@
|
|
|
1
|
-
//
|
|
1
|
+
// rnx setup owns the optional machine and repository choices. rnx itself
|
|
2
|
+
// works without project setup; bare first-run onboarding launches ConnectRN
|
|
3
|
+
// during this flow and leaves the repository choice until the end.
|
|
2
4
|
|
|
3
|
-
import fs from 'node:fs'
|
|
4
5
|
import os from 'node:os'
|
|
5
6
|
import path from 'node:path'
|
|
6
|
-
import {
|
|
7
|
-
COMPAT_RESULT_CAVEAT,
|
|
8
|
-
formatDetailedScanLines,
|
|
9
|
-
formatScanCounts,
|
|
10
|
-
scanDeps,
|
|
11
|
-
type ScanResult,
|
|
12
|
-
} from '@sootsim/compat/web'
|
|
13
7
|
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
14
8
|
import { getCliVersion } from '../../src/cli-version'
|
|
15
9
|
import {
|
|
16
10
|
readActiveRuntime,
|
|
17
11
|
readPrivacyPreferences,
|
|
12
|
+
readSimulatorDriverPreference,
|
|
18
13
|
runtimeDir,
|
|
14
|
+
type SimulatorDriverPreference,
|
|
15
|
+
writeOnboardingPreferences,
|
|
19
16
|
writePrivacyPreferences,
|
|
20
17
|
} from '../../src/home-paths'
|
|
21
18
|
import { sootsimRuntime } from '../../src/runtime-delivery'
|
|
22
|
-
import {
|
|
19
|
+
import { findDesktopCompanion } from '../desktop-companion'
|
|
20
|
+
import { confirm, select } from '../prompt'
|
|
23
21
|
import {
|
|
24
22
|
applyRepositorySetup,
|
|
25
|
-
|
|
26
|
-
findPackageRoot,
|
|
23
|
+
findRepositoryPackageRoot,
|
|
27
24
|
formatRepositoryOperations,
|
|
28
25
|
planRepositorySetup,
|
|
29
26
|
type RepositorySetupPlan,
|
|
30
27
|
} from '../setup-repository'
|
|
31
28
|
import { trackCliError } from '../telemetry'
|
|
29
|
+
import {
|
|
30
|
+
accent,
|
|
31
|
+
bold,
|
|
32
|
+
muted,
|
|
33
|
+
printBrand,
|
|
34
|
+
printPromptBlock,
|
|
35
|
+
success,
|
|
36
|
+
withSpinner,
|
|
37
|
+
} from '../ui'
|
|
38
|
+
import { runOpenCommand } from './control'
|
|
32
39
|
import { daemonInstall, getDaemonServiceStatus } from './daemon'
|
|
33
40
|
import { isAgentEnv } from './inspect/env'
|
|
41
|
+
import { runInstallDesktop } from './install-desktop'
|
|
34
42
|
|
|
35
43
|
interface SetupOptions {
|
|
36
44
|
appDir: string
|
|
@@ -41,107 +49,155 @@ interface SetupOptions {
|
|
|
41
49
|
service: boolean | undefined
|
|
42
50
|
repository: boolean | undefined
|
|
43
51
|
productAnalytics: boolean | undefined
|
|
52
|
+
simulatorDriver: SimulatorDriverPreference | undefined
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
interface SetupRunOptions {
|
|
56
|
+
launchConnectRN?: boolean
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
export interface SetupResult {
|
|
47
60
|
runtimeVersion: string
|
|
48
61
|
serviceInstalled: boolean
|
|
49
62
|
repositoryPrepared: boolean
|
|
63
|
+
simulatorDriver: SimulatorDriverPreference
|
|
50
64
|
}
|
|
51
65
|
|
|
52
|
-
export async function runSetup(
|
|
66
|
+
export async function runSetup(
|
|
67
|
+
args: string[],
|
|
68
|
+
runOptions: SetupRunOptions = {},
|
|
69
|
+
): Promise<SetupResult | undefined> {
|
|
53
70
|
if (args.includes('--help') || args.includes('-h')) {
|
|
54
71
|
printHelp()
|
|
55
72
|
return
|
|
56
73
|
}
|
|
57
74
|
|
|
58
75
|
const options = parseSetupOptions(args)
|
|
76
|
+
const launchConnectRN =
|
|
77
|
+
runOptions.launchConnectRN ??
|
|
78
|
+
(!options.ci &&
|
|
79
|
+
!options.yes &&
|
|
80
|
+
!options.json &&
|
|
81
|
+
!options.dryRun &&
|
|
82
|
+
process.stdin.isTTY)
|
|
59
83
|
try {
|
|
60
|
-
|
|
84
|
+
printIntro(options)
|
|
85
|
+
|
|
86
|
+
const packageRoot = findRepositoryPackageRoot(options.appDir)
|
|
61
87
|
const serviceStatus = getDaemonServiceStatus()
|
|
62
88
|
const privacy = readPrivacyPreferences()
|
|
63
89
|
const service = await decideService(options, serviceStatus)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
90
|
+
if (!service && !serviceStatus.installed && !options.json) {
|
|
91
|
+
console.log(` ${muted('Enable it later with')} ${accent('rnx daemon install')}`)
|
|
92
|
+
}
|
|
93
|
+
const simulatorDriver = await decideSimulatorDriver(options)
|
|
94
|
+
|
|
95
|
+
const manifest = options.json
|
|
96
|
+
? await sootsimRuntime.fetchManifest()
|
|
97
|
+
: await withSpinner('Checking the rnx runtime', () =>
|
|
98
|
+
sootsimRuntime.fetchManifest(),
|
|
99
|
+
)
|
|
100
|
+
const runtimeVersion = sootsimRuntime.resolveVersion(manifest, {
|
|
101
|
+
channel: 'stable',
|
|
102
|
+
}).version
|
|
71
103
|
const cliVersion = getCliVersion()
|
|
72
104
|
if (cliVersion === '0.0.0') {
|
|
73
105
|
throw new Error('could not resolve the installed rnx CLI version')
|
|
74
106
|
}
|
|
75
107
|
|
|
76
|
-
let
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
108
|
+
let runtimeInstalled = false
|
|
109
|
+
if (!options.dryRun) {
|
|
110
|
+
const activeRuntime = readActiveRuntime()
|
|
111
|
+
const install = () =>
|
|
112
|
+
sootsimRuntime.install({
|
|
113
|
+
version: runtimeVersion,
|
|
114
|
+
channel: 'stable',
|
|
115
|
+
setActive: true,
|
|
116
|
+
protectVersions: activeRuntime ? [activeRuntime] : [],
|
|
117
|
+
})
|
|
118
|
+
const result = options.json
|
|
119
|
+
? await install()
|
|
120
|
+
: await withSpinner(`Preparing runtime ${runtimeVersion}`, install)
|
|
121
|
+
runtimeInstalled = result.installed
|
|
82
122
|
}
|
|
83
123
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
124
|
+
let serviceInstalled = serviceStatus.installed
|
|
125
|
+
if (service && !serviceStatus.installed && !options.dryRun) {
|
|
126
|
+
if (options.json) {
|
|
127
|
+
await daemonInstall({ port: DEFAULT_SOOTSIM_BRIDGE_PORT, force: false })
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`\n ${accent('◆')} ${bold('Enabling the background service')}`)
|
|
130
|
+
await daemonInstall({ port: DEFAULT_SOOTSIM_BRIDGE_PORT, force: false })
|
|
131
|
+
}
|
|
132
|
+
serviceInstalled = true
|
|
133
|
+
}
|
|
88
134
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
if (simulatorDriver === 'electron' && !options.dryRun && !findDesktopCompanion()) {
|
|
136
|
+
await runInstallDesktop(['--yes'])
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (launchConnectRN) {
|
|
140
|
+
console.log(`\n ${accent('◆')} Opening ConnectRN`)
|
|
141
|
+
await runOpenCommand([
|
|
142
|
+
'ConnectRN',
|
|
143
|
+
'--driver',
|
|
144
|
+
simulatorDriver,
|
|
145
|
+
'--no-describe',
|
|
146
|
+
'--quiet',
|
|
147
|
+
])
|
|
99
148
|
}
|
|
100
149
|
|
|
101
|
-
|
|
150
|
+
const productAnalytics = await decidePrivacy(options, privacy)
|
|
151
|
+
const crashReports = false
|
|
152
|
+
|
|
153
|
+
const repositoryPlan = packageRoot
|
|
154
|
+
? planRepositorySetup({ appDir: packageRoot, cliVersion })
|
|
155
|
+
: null
|
|
156
|
+
const repository = await decideRepository(options, repositoryPlan)
|
|
157
|
+
if (repository && repositoryPlan) {
|
|
158
|
+
if (!options.json) {
|
|
159
|
+
for (const operation of formatRepositoryOperations(repositoryPlan)) {
|
|
160
|
+
console.log(` ${muted(options.dryRun ? 'Would run' : 'Running')} ${operation}`)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
102
163
|
await applyRepositorySetup(repositoryPlan, {
|
|
103
164
|
dryRun: options.dryRun,
|
|
104
165
|
json: options.json,
|
|
105
166
|
})
|
|
106
167
|
}
|
|
107
168
|
|
|
108
|
-
let serviceInstalled = serviceStatus.installed
|
|
109
|
-
if (service && !serviceStatus.installed && !options.dryRun) {
|
|
110
|
-
await daemonInstall({ port: DEFAULT_SOOTSIM_BRIDGE_PORT, force: false })
|
|
111
|
-
serviceInstalled = true
|
|
112
|
-
}
|
|
113
|
-
|
|
114
169
|
if (!options.dryRun) {
|
|
115
170
|
writePrivacyPreferences({ productAnalytics, crashReports })
|
|
171
|
+
writeOnboardingPreferences(simulatorDriver)
|
|
116
172
|
}
|
|
117
173
|
|
|
118
|
-
const scan = packageRoot ? scanPackage(packageRoot) : null
|
|
119
|
-
printCompatibilitySection(options, scan)
|
|
120
|
-
|
|
121
174
|
const result: SetupResult = {
|
|
122
175
|
runtimeVersion,
|
|
123
176
|
serviceInstalled,
|
|
124
|
-
repositoryPrepared:
|
|
177
|
+
repositoryPrepared: repository,
|
|
178
|
+
simulatorDriver,
|
|
125
179
|
}
|
|
126
|
-
const cache = runtimeCacheMetadata(runtimeVersion)
|
|
127
180
|
if (options.json) {
|
|
128
181
|
console.log(
|
|
129
182
|
JSON.stringify(
|
|
130
183
|
{
|
|
131
184
|
...result,
|
|
132
|
-
runtimeInstalled
|
|
185
|
+
runtimeInstalled,
|
|
133
186
|
dryRun: options.dryRun,
|
|
134
|
-
cache,
|
|
135
|
-
repositoryOperations:
|
|
136
|
-
|
|
137
|
-
|
|
187
|
+
cache: runtimeCacheMetadata(runtimeVersion),
|
|
188
|
+
repositoryOperations:
|
|
189
|
+
repository && repositoryPlan
|
|
190
|
+
? formatRepositoryOperations(repositoryPlan)
|
|
191
|
+
: [],
|
|
138
192
|
},
|
|
139
193
|
null,
|
|
140
194
|
2,
|
|
141
195
|
),
|
|
142
196
|
)
|
|
143
197
|
} else {
|
|
144
|
-
|
|
198
|
+
console.log(
|
|
199
|
+
`\n ${success('✓')} ${launchConnectRN ? 'ConnectRN is open. ' : ''}rnx is ready.`,
|
|
200
|
+
)
|
|
145
201
|
}
|
|
146
202
|
|
|
147
203
|
return result
|
|
@@ -157,20 +213,30 @@ function parseSetupOptions(args: string[]): SetupOptions {
|
|
|
157
213
|
if (appIndex >= 0 && (!appArg || appArg.startsWith('-'))) {
|
|
158
214
|
throw new Error('--app requires a directory')
|
|
159
215
|
}
|
|
160
|
-
const service = readBooleanFlag(args, '--service', '--no-service')
|
|
161
|
-
const repository = readBooleanFlag(args, '--repo', '--no-repo')
|
|
162
216
|
return {
|
|
163
217
|
appDir: path.resolve(appArg ?? process.cwd()),
|
|
164
218
|
ci: args.includes('--ci') || isAgentEnv(),
|
|
165
219
|
dryRun: args.includes('--dry-run'),
|
|
166
220
|
json: args.includes('--json'),
|
|
167
221
|
yes: args.includes('--yes') || args.includes('-y'),
|
|
168
|
-
service,
|
|
169
|
-
repository,
|
|
222
|
+
service: readBooleanFlag(args, '--service', '--no-service'),
|
|
223
|
+
repository: readBooleanFlag(args, '--repo', '--no-repo'),
|
|
170
224
|
productAnalytics: readOnOffFlag(args, '--analytics'),
|
|
225
|
+
simulatorDriver: readSimulatorDriverFlag(args),
|
|
171
226
|
}
|
|
172
227
|
}
|
|
173
228
|
|
|
229
|
+
function readSimulatorDriverFlag(args: string[]): SimulatorDriverPreference | undefined {
|
|
230
|
+
const desktop = args.includes('--desktop')
|
|
231
|
+
const browser = args.includes('--browser')
|
|
232
|
+
if (desktop && browser) {
|
|
233
|
+
throw new Error('--desktop and --browser cannot be used together')
|
|
234
|
+
}
|
|
235
|
+
if (desktop) return 'electron'
|
|
236
|
+
if (browser) return 'playwright'
|
|
237
|
+
return undefined
|
|
238
|
+
}
|
|
239
|
+
|
|
174
240
|
function readBooleanFlag(
|
|
175
241
|
args: string[],
|
|
176
242
|
positive: string,
|
|
@@ -202,26 +268,59 @@ async function decideService(
|
|
|
202
268
|
if (options.service === true) throw new Error('--ci cannot install a machine service')
|
|
203
269
|
return false
|
|
204
270
|
}
|
|
205
|
-
if (!status.supported)
|
|
206
|
-
|
|
271
|
+
if (!status.supported) {
|
|
272
|
+
if (!options.json) {
|
|
273
|
+
printPromptBlock('Background service', [
|
|
274
|
+
'The persistent service is currently available on macOS and Linux.',
|
|
275
|
+
'rnx will start the bridge when needed on this platform.',
|
|
276
|
+
])
|
|
277
|
+
}
|
|
278
|
+
return false
|
|
279
|
+
}
|
|
280
|
+
if (status.installed && options.service === undefined) {
|
|
281
|
+
if (!options.json) console.log(` ${success('✓')} Background service is ready`)
|
|
282
|
+
return true
|
|
283
|
+
}
|
|
207
284
|
if (options.service !== undefined) return options.service
|
|
208
285
|
if (options.yes) return true
|
|
209
286
|
requireInteractive(options, '--service or --no-service')
|
|
210
|
-
|
|
287
|
+
printPromptBlock('Background service', [
|
|
288
|
+
'Keeps the local bridge and runtime ready between commands.',
|
|
289
|
+
'Agent inspection, interaction, and test commands start much faster.',
|
|
290
|
+
])
|
|
291
|
+
return confirm('Enable the background service?', true)
|
|
211
292
|
}
|
|
212
293
|
|
|
213
|
-
async function
|
|
294
|
+
async function decideSimulatorDriver(
|
|
214
295
|
options: SetupOptions,
|
|
215
|
-
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
296
|
+
): Promise<SimulatorDriverPreference> {
|
|
297
|
+
if (options.simulatorDriver) return options.simulatorDriver
|
|
298
|
+
const current = readSimulatorDriverPreference()
|
|
299
|
+
if (current) return current
|
|
300
|
+
if (options.ci || options.yes) return 'playwright'
|
|
301
|
+
requireInteractive(options, '--desktop or --browser')
|
|
302
|
+
const desktopDescription =
|
|
303
|
+
process.platform === 'darwin'
|
|
304
|
+
? 'Desktop downloads a DMG and installs rnx.app.'
|
|
305
|
+
: process.platform === 'win32'
|
|
306
|
+
? 'Desktop downloads and runs the rnx installer.'
|
|
307
|
+
: 'Desktop downloads the matching rnx AppImage.'
|
|
308
|
+
const desktopChoice =
|
|
309
|
+
process.platform === 'darwin'
|
|
310
|
+
? 'Desktop app Installs rnx.app from a DMG'
|
|
311
|
+
: process.platform === 'win32'
|
|
312
|
+
? 'Desktop app Runs the rnx installer'
|
|
313
|
+
: 'Desktop app Installs the matching AppImage'
|
|
314
|
+
printPromptBlock('Simulator window', [
|
|
315
|
+
'Browser opens immediately in an isolated Chrome window.',
|
|
316
|
+
desktopDescription,
|
|
317
|
+
'The Desktop app opens in a dedicated native window.',
|
|
318
|
+
])
|
|
319
|
+
const choice = await select('Where should rnx open?', [
|
|
320
|
+
'Browser (recommended) No additional download',
|
|
321
|
+
desktopChoice,
|
|
322
|
+
])
|
|
323
|
+
return choice === 0 ? 'playwright' : 'electron'
|
|
225
324
|
}
|
|
226
325
|
|
|
227
326
|
async function decidePrivacy(
|
|
@@ -231,10 +330,32 @@ async function decidePrivacy(
|
|
|
231
330
|
if (options.productAnalytics !== undefined) return options.productAnalytics
|
|
232
331
|
if (current.configured) return current.productAnalytics
|
|
233
332
|
if (options.yes || options.ci || !process.stdin.isTTY) return false
|
|
234
|
-
|
|
235
|
-
'
|
|
236
|
-
|
|
237
|
-
|
|
333
|
+
printPromptBlock('Private by default', [
|
|
334
|
+
'Diagnostics stay off unless you opt in.',
|
|
335
|
+
'Reports can contain package compatibility or an error class.',
|
|
336
|
+
'They never contain your code or app data.',
|
|
337
|
+
])
|
|
338
|
+
return confirm('Share bounded diagnostics to improve rnx?', false)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function decideRepository(
|
|
342
|
+
options: SetupOptions,
|
|
343
|
+
plan: RepositorySetupPlan | null,
|
|
344
|
+
): Promise<boolean> {
|
|
345
|
+
if (!plan) {
|
|
346
|
+
if (options.repository === true) {
|
|
347
|
+
throw new Error('--repo requires a package.json inside a Git repository')
|
|
348
|
+
}
|
|
349
|
+
return false
|
|
350
|
+
}
|
|
351
|
+
if (plan.operations.length === 0) return true
|
|
352
|
+
if (options.repository !== undefined) return options.repository
|
|
353
|
+
if (options.yes || options.ci || !process.stdin.isTTY) return false
|
|
354
|
+
printPromptBlock('Share rnx with your team', [
|
|
355
|
+
'rnx already works here with no project setup.',
|
|
356
|
+
'This only adds an exact rnxsim dev dependency and an rnx script for teammates.',
|
|
357
|
+
])
|
|
358
|
+
return confirm(`Add rnx to ${path.basename(plan.appDir)}?`, false)
|
|
238
359
|
}
|
|
239
360
|
|
|
240
361
|
function requireInteractive(options: SetupOptions, flags: string): void {
|
|
@@ -242,16 +363,6 @@ function requireInteractive(options: SetupOptions, flags: string): void {
|
|
|
242
363
|
throw new Error(`non-interactive setup requires ${flags}, or --yes to accept defaults`)
|
|
243
364
|
}
|
|
244
365
|
|
|
245
|
-
function scanPackage(packageRoot: string): ScanResult {
|
|
246
|
-
const parsed: unknown = JSON.parse(
|
|
247
|
-
fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'),
|
|
248
|
-
)
|
|
249
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
250
|
-
throw new Error('package.json must contain an object')
|
|
251
|
-
}
|
|
252
|
-
return scanDeps(parsed)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
366
|
function runtimeCacheMetadata(runtimeVersion: string) {
|
|
256
367
|
const platform = os.platform()
|
|
257
368
|
const arch = os.arch()
|
|
@@ -264,89 +375,16 @@ function runtimeCacheMetadata(runtimeVersion: string) {
|
|
|
264
375
|
|
|
265
376
|
function printIntro(options: SetupOptions): void {
|
|
266
377
|
if (options.json) return
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function printMachineSection(
|
|
271
|
-
options: SetupOptions,
|
|
272
|
-
status: ReturnType<typeof getDaemonServiceStatus>,
|
|
273
|
-
service: boolean,
|
|
274
|
-
runtimeVersion: string,
|
|
275
|
-
): void {
|
|
276
|
-
if (options.json) return
|
|
277
|
-
console.log(`\n 1. machine`)
|
|
278
|
-
console.log(` stable runtime: ${runtimeVersion}`)
|
|
279
|
-
console.log(
|
|
280
|
-
` background service: ${status.supported ? (service ? 'install' : 'skip') : 'unsupported on this platform'}`,
|
|
281
|
-
)
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function printRepositorySection(
|
|
285
|
-
options: SetupOptions,
|
|
286
|
-
packageRoot: string | null,
|
|
287
|
-
plan: RepositorySetupPlan | null,
|
|
288
|
-
): void {
|
|
289
|
-
if (options.json) return
|
|
290
|
-
console.log(`\n 2. repository`)
|
|
291
|
-
if (!packageRoot) {
|
|
292
|
-
console.log(` no package.json found; repository preparation skipped`)
|
|
293
|
-
return
|
|
294
|
-
}
|
|
295
|
-
if (!plan) {
|
|
296
|
-
console.log(` skipped for ${packageRoot}`)
|
|
297
|
-
return
|
|
298
|
-
}
|
|
299
|
-
console.log(` package manager: ${detectPreferredPackageManager(packageRoot)}`)
|
|
300
|
-
for (const operation of formatRepositoryOperations(plan)) {
|
|
301
|
-
console.log(` ${options.dryRun ? 'would run' : 'run'}: ${operation}`)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function printPrivacySection(options: SetupOptions, productAnalytics: boolean): void {
|
|
306
|
-
if (options.json) return
|
|
307
|
-
console.log(`\n 3. privacy`)
|
|
308
|
-
console.log(` bounded diagnostics: ${productAnalytics ? 'on' : 'off'}`)
|
|
309
|
-
console.log(` package name/version/unsupported API or error class only`)
|
|
310
|
-
console.log(
|
|
311
|
-
` source, paths, project names, app content, identity, and command usage are never included`,
|
|
312
|
-
)
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function printCompatibilitySection(options: SetupOptions, scan: ScanResult | null): void {
|
|
316
|
-
if (options.json) return
|
|
317
|
-
console.log(`\n 4. compatibility`)
|
|
318
|
-
if (!scan) {
|
|
319
|
-
console.log(` no package.json found; run \`rnx compat\` inside an app later`)
|
|
320
|
-
return
|
|
321
|
-
}
|
|
322
|
-
console.log(` ${formatScanCounts(scan)}`)
|
|
323
|
-
for (const line of formatDetailedScanLines(scan)) console.log(` ${line}`)
|
|
324
|
-
console.log(` ${COMPAT_RESULT_CAVEAT}`)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function printReadySection(repository: RepositorySetupPlan | null): void {
|
|
328
|
-
console.log(`\n 5. ready`)
|
|
329
|
-
if (repository) {
|
|
330
|
-
const command =
|
|
331
|
-
repository.packageManager === 'bun'
|
|
332
|
-
? 'bun run sootsim'
|
|
333
|
-
: `${repository.packageManager} run rnx`
|
|
334
|
-
console.log(` start your app normally, then ${command} -- <port>`)
|
|
335
|
-
} else {
|
|
336
|
-
console.log(` start your app normally, then rnx open <port>`)
|
|
337
|
-
}
|
|
338
|
-
console.log(` useful next commands: rnx describe; rnx get errors; rnx compat`)
|
|
339
|
-
console.log(
|
|
340
|
-
` install agent skills with \`rnx skill install\`, then start a new session`,
|
|
341
|
-
)
|
|
342
|
-
console.log(
|
|
343
|
-
` if a concrete rnx seam is missing or broken, preview \`rnx report-issue\` and confirm separately`,
|
|
344
|
-
)
|
|
378
|
+
printBrand('Run any React Native app in a local simulator. No project setup required.')
|
|
345
379
|
}
|
|
346
380
|
|
|
347
381
|
function printHelp(): void {
|
|
348
382
|
console.log(`
|
|
349
|
-
rnx setup
|
|
383
|
+
rnx setup - configure optional local conveniences
|
|
384
|
+
|
|
385
|
+
rnx works without project setup. This command can enable the faster background
|
|
386
|
+
service, choose Browser or Desktop, configure private diagnostics, and optionally
|
|
387
|
+
add an exact rnxsim dependency plus an rnx script for teammates.
|
|
350
388
|
|
|
351
389
|
usage:
|
|
352
390
|
rnx setup
|
|
@@ -354,16 +392,17 @@ usage:
|
|
|
354
392
|
rnx setup --ci --yes --json
|
|
355
393
|
rnx setup --dry-run --yes
|
|
356
394
|
|
|
357
|
-
|
|
395
|
+
choices:
|
|
358
396
|
--service | --no-service
|
|
359
|
-
--
|
|
397
|
+
--desktop | --browser
|
|
360
398
|
--analytics on|off
|
|
399
|
+
--repo | --no-repo
|
|
361
400
|
|
|
362
401
|
automation:
|
|
363
|
-
--yes accept
|
|
402
|
+
--yes accept recommended machine defaults; diagnostics and repo changes stay off
|
|
364
403
|
--ci never prompt or install a background service
|
|
365
|
-
--json emit runtime
|
|
366
|
-
--dry-run
|
|
367
|
-
--app DIR
|
|
404
|
+
--json emit runtime and cache metadata as JSON
|
|
405
|
+
--dry-run show choices and repository operations without changing anything
|
|
406
|
+
--app DIR inspect DIR for an optional repository installation
|
|
368
407
|
`)
|
|
369
408
|
}
|
package/cli/commands/welcome.ts
CHANGED
|
@@ -1,66 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
3
|
-
import { readPrivacyPreferences } from '../../src/home-paths'
|
|
1
|
+
import { isOnboardingComplete } from '../../src/home-paths'
|
|
4
2
|
import { canPromptForPrivacyChoice } from '../privacy'
|
|
5
|
-
import {
|
|
6
|
-
import { createBridge } from '../ws-bridge'
|
|
3
|
+
import { printBrand } from '../ui'
|
|
7
4
|
import { runOpenCommand } from './control'
|
|
8
|
-
|
|
9
|
-
function serverLabel(server: DiscoveredServer): string {
|
|
10
|
-
return `${server.projectName?.trim() || server.framework} on :${server.port}`
|
|
11
|
-
}
|
|
5
|
+
import { runSetup } from './setup'
|
|
12
6
|
|
|
13
7
|
export async function runWelcome(): Promise<number> {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
` diagnostics: ${privacy.configured && privacy.productAnalytics ? 'bounded opt-in on' : 'off until you opt in'}`,
|
|
18
|
-
)
|
|
19
|
-
console.log(' looking for a running React Native app…')
|
|
20
|
-
|
|
21
|
-
const discovered = await scanDevServers({
|
|
22
|
-
excludePorts: [DEFAULT_SOOTSIM_BRIDGE_PORT],
|
|
23
|
-
})
|
|
24
|
-
const ordered = [...discovered].sort((a, b) => a.port - b.port)
|
|
25
|
-
if (ordered.length === 0) {
|
|
26
|
-
console.error(' no running React Native development server found.')
|
|
27
|
-
console.error(' start your app normally, then run `npx rnxsim` again.')
|
|
28
|
-
return 1
|
|
8
|
+
if (!isOnboardingComplete() && canPromptForPrivacyChoice()) {
|
|
9
|
+
await runSetup([], { launchConnectRN: true })
|
|
10
|
+
return 0
|
|
29
11
|
}
|
|
30
|
-
if (ordered.length > 1 && !canPromptForPrivacyChoice()) {
|
|
31
|
-
console.error(' multiple React Native development servers found.')
|
|
32
|
-
for (const server of ordered) {
|
|
33
|
-
console.error(` ${serverLabel(server)}: rnx open ${server.port}`)
|
|
34
|
-
}
|
|
35
|
-
console.error(' choose one explicitly; automated runs do not guess.')
|
|
36
|
-
return 1
|
|
37
|
-
}
|
|
38
|
-
const selectedIndex =
|
|
39
|
-
ordered.length === 1
|
|
40
|
-
? 0
|
|
41
|
-
: await select('which running app should rnx open?', ordered.map(serverLabel))
|
|
42
|
-
const selected = ordered[selectedIndex]
|
|
43
|
-
if (!selected) throw new Error('rnx app selection returned an invalid choice')
|
|
44
12
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const { runInspect } = await import('./inspect')
|
|
49
|
-
await runInspect(['wait', 'ready', '--max-ms', '120000'], { port: bridgePort })
|
|
50
|
-
const bridge = createBridge(bridgePort, { commandTimeoutMs: 45_000 })
|
|
51
|
-
try {
|
|
52
|
-
const frame: unknown = await bridge.send({ type: 'screenshot' })
|
|
53
|
-
const pngPrefix = 'data:image/png;base64,'
|
|
54
|
-
if (
|
|
55
|
-
typeof frame !== 'string' ||
|
|
56
|
-
!frame.startsWith(pngPrefix) ||
|
|
57
|
-
frame.length <= pngPrefix.length
|
|
58
|
-
) {
|
|
59
|
-
throw new Error('the simulator connected but did not produce a visible app frame')
|
|
60
|
-
}
|
|
61
|
-
} finally {
|
|
62
|
-
bridge.close()
|
|
63
|
-
}
|
|
64
|
-
}
|
|
13
|
+
printBrand('Run any React Native app in a local simulator.')
|
|
14
|
+
console.log(`\n Opening ConnectRN`)
|
|
15
|
+
await runOpenCommand(['ConnectRN', '--no-describe', '--quiet'])
|
|
65
16
|
return 0
|
|
66
17
|
}
|