rnxsim 0.1.352 → 0.1.353
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-YTAX6OQQ.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-XAUWPZ6O.js → agent-wrapper-2QSUXMNK.js} +2 -2
- package/dist-cli/chunks/{app-fonts-COAZFLDG.js → app-fonts-4EVHPXVG.js} +2 -2
- package/dist-cli/chunks/{assert-ZR2UE3EH.js → assert-IXMSQLVY.js} +2 -2
- package/dist-cli/chunks/{auth-LISHWKCC.js → auth-6QFWU2T5.js} +2 -2
- package/dist-cli/chunks/{beta-AQQUYVA5.js → beta-27I5WWRE.js} +2 -2
- package/dist-cli/chunks/{camera-KE44ZN3U.js → camera-4HFUBXPM.js} +2 -2
- package/dist-cli/chunks/{chunk-DJAYEBF3.js → chunk-37J74ASV.js} +1 -1
- package/dist-cli/chunks/{chunk-XI4W6LRQ.js → chunk-3IWR7KHR.js} +2 -2
- package/dist-cli/chunks/{chunk-CY6HBAOB.js → chunk-3UXMNDMH.js} +2 -2
- package/dist-cli/chunks/{chunk-R2BFC3AC.js → chunk-3XDGLCNP.js} +2 -2
- package/dist-cli/chunks/{chunk-6NSUY346.js → chunk-4IXIONDR.js} +2 -2
- package/dist-cli/chunks/{chunk-YAMKV3UB.js → chunk-4NPZ5FO2.js} +2 -2
- package/dist-cli/chunks/{chunk-QJTW4QQW.js → chunk-4PV6QASJ.js} +1 -1
- package/dist-cli/chunks/{chunk-PEBQKBEP.js → chunk-57YZEJ6J.js} +1 -1
- package/dist-cli/chunks/{chunk-4AOAJXE2.js → chunk-5DLBRZAG.js} +2 -2
- package/dist-cli/chunks/{chunk-7T7DR34H.js → chunk-6JBOKETZ.js} +2 -2
- package/dist-cli/chunks/{chunk-AR3CPCW3.js → chunk-6NE5Z6KG.js} +1 -1
- package/dist-cli/chunks/{chunk-RASWCAJJ.js → chunk-7FUSVOMH.js} +2 -2
- package/dist-cli/chunks/{chunk-5JE5PNIV.js → chunk-7SKQRS74.js} +1 -1
- package/dist-cli/chunks/chunk-7V5O6I4Q.js +9 -0
- package/dist-cli/chunks/{chunk-3Y7NWE22.js → chunk-BK5TJXUU.js} +2 -2
- package/dist-cli/chunks/{chunk-H4IF54WS.js → chunk-CMQIFA4L.js} +1 -1
- package/dist-cli/chunks/{chunk-3ZV4WSCR.js → chunk-CYS3D7RG.js} +2 -2
- package/dist-cli/chunks/{chunk-LRKODRWI.js → chunk-DSBUGNC5.js} +2 -2
- package/dist-cli/chunks/{chunk-EGKGCDG5.js → chunk-ECIDT6F5.js} +1 -1
- package/dist-cli/chunks/{chunk-EHQHK7KN.js → chunk-ELBDKQK2.js} +2 -2
- package/dist-cli/chunks/{chunk-ELNSQ352.js → chunk-GAYCF2O5.js} +1 -1
- package/dist-cli/chunks/{chunk-ESVF72YH.js → chunk-HVLZYUGF.js} +2 -2
- package/dist-cli/chunks/{chunk-5JINX2IB.js → chunk-HWMBTYJX.js} +2 -2
- package/dist-cli/chunks/{chunk-MJB6N7WS.js → chunk-HZTWQZUD.js} +2 -2
- package/dist-cli/chunks/{chunk-M6DC6JZL.js → chunk-IX7W5BXL.js} +2 -2
- package/dist-cli/chunks/{chunk-BZ32JGFC.js → chunk-JVVO63QH.js} +1 -1
- package/dist-cli/chunks/{chunk-JEPQ5YX3.js → chunk-KIQVNLVD.js} +2 -2
- package/dist-cli/chunks/chunk-KZLGVYCX.js +7 -0
- package/dist-cli/chunks/{chunk-QP7KGSU4.js → chunk-LAFKQUT7.js} +3 -3
- package/dist-cli/chunks/{chunk-E42ZJLPN.js → chunk-LMFAIAA5.js} +1 -1
- package/dist-cli/chunks/chunk-MA5E6HJR.js +15 -0
- package/dist-cli/chunks/chunk-OEU2MEZQ.js +124 -0
- package/dist-cli/chunks/{chunk-BQE4E24T.js → chunk-PBTG4UCS.js} +1 -1
- package/dist-cli/chunks/{chunk-XHZEKHB2.js → chunk-PNQ33FJB.js} +6 -6
- package/dist-cli/chunks/{chunk-MJJP2BEI.js → chunk-R4KBCGXX.js} +3 -3
- package/dist-cli/chunks/chunk-RMOSWLWG.js +32 -0
- package/dist-cli/chunks/{chunk-WNJDE2JT.js → chunk-RRX5RZI2.js} +1 -1
- package/dist-cli/chunks/{chunk-R4P7WO4L.js → chunk-T2ZZSSCP.js} +2 -2
- package/dist-cli/chunks/{chunk-DSF4WC4X.js → chunk-TX2T5KPQ.js} +2 -2
- package/dist-cli/chunks/{chunk-2OME2KGY.js → chunk-UEILOAPW.js} +1 -1
- package/dist-cli/chunks/{chunk-TF6VBUZ7.js → chunk-UNBVUOIC.js} +2 -2
- package/dist-cli/chunks/chunk-UQBXA3AK.js +24 -0
- package/dist-cli/chunks/{chunk-H6MTPXZS.js → chunk-V7X543SB.js} +1 -1
- package/dist-cli/chunks/{chunk-45D2GGIA.js → chunk-VLI54BKH.js} +2 -2
- package/dist-cli/chunks/{chunk-RH6FJI5O.js → chunk-VZDW2U64.js} +2 -2
- package/dist-cli/chunks/chunk-WKQ6W74M.js +11 -0
- package/dist-cli/chunks/{chunk-S2PJOB2C.js → chunk-WTGQUQ32.js} +2 -2
- package/dist-cli/chunks/{chunk-P5YC5VGA.js → chunk-WU25RTIX.js} +2 -2
- package/dist-cli/chunks/chunk-WV3TKN7D.js +4 -0
- package/dist-cli/chunks/{chunk-Q4ROOH3W.js → chunk-XVLYLZOM.js} +2 -2
- package/dist-cli/chunks/{chunk-VQDY7NEJ.js → chunk-YQJOM55S.js} +1 -1
- package/dist-cli/chunks/{chunk-AIGZ3TSW.js → chunk-YYYWU6LL.js} +3 -3
- package/dist-cli/chunks/{chunk-NQMZOJPX.js → chunk-ZF53H457.js} +2 -2
- package/dist-cli/chunks/{chunk-24CIPQT5.js → chunk-ZJ4O636U.js} +1 -1
- package/dist-cli/chunks/{chunk-ZK5HYQ4I.js → chunk-ZXHAAVTH.js} +2 -2
- package/dist-cli/chunks/{chunk-FHLEA4S5.js → chunk-ZYGWIVW4.js} +2 -2
- package/dist-cli/chunks/{cleanup-JUY2WU24.js → cleanup-ULH3BHAE.js} +2 -2
- package/dist-cli/chunks/cli-version-I2E56I4W.js +4 -0
- package/dist-cli/chunks/{compat-S2TBISY3.js → compat-ONN5DOHB.js} +2 -2
- package/dist-cli/chunks/{config-3PHD4J5N.js → config-OPZU73MX.js} +2 -2
- package/dist-cli/chunks/control-WNYEAI4K.js +4 -0
- package/dist-cli/chunks/daemon-5J6V2GLG.js +4 -0
- package/dist-cli/chunks/{debug-PFAJONVV.js → debug-GNI3HDAK.js} +3 -3
- package/dist-cli/chunks/{desktop-Z7EOBMNV.js → desktop-DF65PDJG.js} +4 -4
- package/dist-cli/chunks/{detox-KRSP5SLY.js → detox-N267KW2Y.js} +2 -2
- package/dist-cli/chunks/{device-ZXJ7GRBO.js → device-RFU44PE3.js} +2 -2
- package/dist-cli/chunks/{diagnose-JIMLEOEJ.js → diagnose-XR2JIGDE.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-YY7FFGVA.js → disk-cleanup-DPY6TYXA.js} +2 -2
- package/dist-cli/chunks/drivers-OIZC544W.js +4 -0
- package/dist-cli/chunks/{film-LKSJPU2A.js → film-NQQZPZ2W.js} +3 -3
- package/dist-cli/chunks/flow-3NHEHRF4.js +4 -0
- package/dist-cli/chunks/help-VACWNWEH.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-ZN3WZ3ND.js → hidden-runtime-alias-APCBIXJ6.js} +2 -2
- package/dist-cli/chunks/home-paths-27GY5EPD.js +4 -0
- package/dist-cli/chunks/inspect-2JELKZ5A.js +4 -0
- package/dist-cli/chunks/install-desktop-4R7UTGQU.js +4 -0
- package/dist-cli/chunks/{login-XKLIFTAU.js → login-6KIO5FR4.js} +2 -2
- package/dist-cli/chunks/{logout-DR22RB5H.js → logout-WMCYGTYA.js} +2 -2
- package/dist-cli/chunks/{maestro-SLCX6HBV.js → maestro-7QLOUZIE.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-GBFZ5INV.js → maestro-generate-QIGCQANR.js} +3 -3
- package/dist-cli/chunks/{mode-F4R2KNXX.js → mode-3H662MUJ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-HM55KXGB.js → optional-demo-registry-FQV54ASP.js} +2 -2
- package/dist-cli/chunks/{perf-VBS5GEPG.js → perf-KC6LOGFD.js} +2 -2
- package/dist-cli/chunks/{permissions-F46PQIUE.js → permissions-UGVHA3L6.js} +2 -2
- package/dist-cli/chunks/privacy-E6KH2DRJ.js +4 -0
- package/dist-cli/chunks/{record-NLZ6DFAA.js → record-V72Q363I.js} +3 -3
- package/dist-cli/chunks/{report-issue-XIE5BVR4.js → report-issue-MILOOCMG.js} +2 -2
- package/dist-cli/chunks/reset-LEL5ZGFN.js +4 -0
- package/dist-cli/chunks/runtime-RT2OTIQC.js +4 -0
- package/dist-cli/chunks/{screenshot-command-SD4JPNKW.js → screenshot-command-FYMZF5AF.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-X65RC3GT.js → screenshot-layers-OXLW6GEJ.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-BBXN7FEZ.js → screenshots-capture-N3LKTUKB.js} +2 -2
- package/dist-cli/chunks/{serve-M6ZKMSAG.js → serve-USDREK3N.js} +2 -2
- package/dist-cli/chunks/setup-QC7W7NCL.js +4 -0
- package/dist-cli/chunks/{skills-KDWGQBOP.js → skills-3MIZF3DS.js} +2 -2
- package/dist-cli/chunks/{state-NWABXG2P.js → state-MCFLWQHV.js} +2 -2
- package/dist-cli/chunks/{storage-QQE3G65Q.js → storage-KXNS5WEC.js} +2 -2
- package/dist-cli/chunks/store-GL6DFPJL.js +4 -0
- package/dist-cli/chunks/telemetry-OOW5FMZQ.js +4 -0
- package/dist-cli/chunks/{timeline-2VZ45MMB.js → timeline-QJ3USMSX.js} +2 -2
- package/dist-cli/chunks/{upgrade-T7PDR6T5.js → upgrade-LXFD4DFX.js} +2 -2
- package/dist-cli/chunks/upload-EUEO4D5N.js +4 -0
- package/dist-cli/chunks/{version-BX6QX5XA.js → version-D5DLNPHP.js} +2 -2
- package/dist-cli/chunks/{web-4J6JRZN2.js → web-FRFNTTZ4.js} +2 -2
- package/dist-cli/chunks/welcome-YYYGS5WD.js +5 -0
- package/dist-cli/chunks/{what-happened-CHQKFNCM.js → what-happened-FJ6GRQAS.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/README.md
CHANGED
|
@@ -132,9 +132,10 @@ graph TD
|
|
|
132
132
|
```
|
|
133
133
|
|
|
134
134
|
**The CLI process** (`cli/bin.ts`) parses argv and lazy-imports exactly one
|
|
135
|
-
command module per run. Bare `rnx`
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
command module per run. Bare `rnx` opens ConnectRN, whose simulator UI discovers
|
|
136
|
+
running React Native development servers. The first human run offers the
|
|
137
|
+
recommended background service and optional Desktop app, then opens the simulator
|
|
138
|
+
before asking about private diagnostics or an optional repository install. `rnx open`
|
|
138
139
|
ensures the engine runtime exists and starts a local foreground bridge when no
|
|
139
140
|
daemon is reachable, then opens a `WsBridge` (`cli/ws-bridge.ts`) on **port
|
|
140
141
|
7668** and sends JSON commands. Inspection/interaction verbs live in
|
|
@@ -200,15 +201,15 @@ bridge always addresses the **shell worker**, never an undifferentiated sim.
|
|
|
200
201
|
## Getting started
|
|
201
202
|
|
|
202
203
|
```sh
|
|
203
|
-
npx rnxsim
|
|
204
|
+
npx rnxsim # open ConnectRN and choose a running app in the simulator
|
|
204
205
|
rnx open /settings # dispatch a React Native deep link into that app
|
|
205
206
|
```
|
|
206
207
|
|
|
207
208
|
Start Metro, Expo, One, or another supported React Native development server
|
|
208
|
-
the way you normally do, then run `npx rnxsim` from any directory.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
the way you normally do, then run `npx rnxsim` from any directory. The simulator
|
|
210
|
+
opens ConnectRN, which shows the available local apps and lets you connect one.
|
|
211
|
+
Pass a target to `rnx open <port-or-url>` when a script or agent needs an explicit
|
|
212
|
+
selection.
|
|
212
213
|
|
|
213
214
|
The first `rnx open` launches an isolated Chrome for Testing sim. The CLI
|
|
214
215
|
resolves Playwright from the app or CLI install, asks that exact package for
|
|
@@ -221,17 +222,17 @@ consume memory and CPU on shared machines.
|
|
|
221
222
|
|
|
222
223
|
There is no required global or per-app install. Optional global installs can
|
|
223
224
|
use `npm install --global rnxsim`, `bun add --global rnxsim`, or
|
|
224
|
-
`pnpm add --global rnxsim`.
|
|
225
|
-
|
|
226
|
-
from the CLI. There is no iOS native build in the inner loop; Metro alone is
|
|
225
|
+
`pnpm add --global rnxsim`. Start your Metro, Expo, or One dev server the way you
|
|
226
|
+
already do, then open it from the CLI. There is no iOS native build in the inner loop; Metro alone is
|
|
227
227
|
enough. The manifest bundle path and query remain authoritative. When both the
|
|
228
228
|
discovery request and manifest target are loopback addresses, RNX keeps the
|
|
229
229
|
loopback host that answered discovery so an IPv6-only listener is not reopened
|
|
230
230
|
through an unreachable IPv4 address. `rnx open` starts a local bridge when no
|
|
231
|
-
daemon is reachable
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
daemon is reachable. The background service is strongly recommended for local
|
|
232
|
+
agent work because inspect, interaction, and test commands reuse one ready bridge
|
|
233
|
+
and runtime. Enable it at any time with `rnx daemon install`; it is never required
|
|
234
|
+
in CI. The packaged Desktop app is optional and available through first-run
|
|
235
|
+
onboarding or `rnx desktop install`. Native Electron windows created by `rnx open` belong to that CLI
|
|
235
236
|
session and close when the session exits; `rnx desktop` keeps the persistent
|
|
236
237
|
desktop-app lifecycle. In Electron, `File > New Window`
|
|
237
238
|
duplicates the focused simulator, while `File > New Simulator >` opens a new
|
|
@@ -257,7 +258,7 @@ To uninstall the machine daemon and cached runtimes, run
|
|
|
257
258
|
`rnx daemon uninstall`. It stops current and legacy launchd / systemd
|
|
258
259
|
services, removes daemon logs, and removes `~/.sootsim/` (runtimes, profiles,
|
|
259
260
|
recordings, and lockfiles). It does not remove the optional
|
|
260
|
-
`/Applications/
|
|
261
|
+
`/Applications/rnx.app` desktop bundle or macOS preference plist. To inspect
|
|
261
262
|
existing disk usage before uninstalling, run `rnx cleanup`; add `--apply`
|
|
262
263
|
only after reviewing the preview.
|
|
263
264
|
|
package/cli/bin.ts
CHANGED
|
@@ -88,12 +88,15 @@ const isAutomaticCleanupWorker =
|
|
|
88
88
|
parsed.command === 'cleanup' &&
|
|
89
89
|
parsed.commandArgs.length === 1 &&
|
|
90
90
|
parsed.commandArgs[0] === '--automatic-worker'
|
|
91
|
+
const isBareWelcome = !parsed.command && parsed.commandArgs.length === 0
|
|
91
92
|
|
|
92
93
|
if (
|
|
93
94
|
!isAutomaticCleanupWorker &&
|
|
95
|
+
!isBareWelcome &&
|
|
94
96
|
!parsed.help &&
|
|
95
97
|
!parsed.version &&
|
|
96
98
|
parsed.command !== 'config' &&
|
|
99
|
+
parsed.command !== 'setup' &&
|
|
97
100
|
parsed.command !== 'telemetry'
|
|
98
101
|
) {
|
|
99
102
|
const { ensurePrivacyChoice } = await import('./privacy')
|
|
@@ -169,8 +172,6 @@ async function scheduleAutomaticCleanup(): Promise<void> {
|
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
|
|
172
|
-
// fast-exit helper: diagnostic error shapes are best-effort, but explicit exit
|
|
173
|
-
// paths still give a permitted queued diagnostic a chance to drain.
|
|
174
175
|
async function exitWithFlush(code: number): Promise<never> {
|
|
175
176
|
const { flushCliTelemetry } = await import('./telemetry')
|
|
176
177
|
await flushCliTelemetry()
|
|
@@ -228,8 +229,8 @@ if (device || theme) {
|
|
|
228
229
|
settingsStore.apply(overrides)
|
|
229
230
|
}
|
|
230
231
|
|
|
231
|
-
// no command, no args:
|
|
232
|
-
//
|
|
232
|
+
// no command, no args: guide first-time machine setup, then open ConnectRN.
|
|
233
|
+
// returning runs open ConnectRN directly; app discovery belongs inside it.
|
|
233
234
|
if (!parsed.command && parsed.commandArgs.length === 0) {
|
|
234
235
|
const { runWelcome } = await import('./commands/welcome')
|
|
235
236
|
await exitWithFlush(await runWelcome())
|
package/cli/commands/control.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
readActiveRuntime,
|
|
26
26
|
readDaemonLockfile,
|
|
27
27
|
readLiveRuntimeVersions,
|
|
28
|
+
readSimulatorDriverPreference,
|
|
28
29
|
runtimeDir,
|
|
29
30
|
} from '../../src/home-paths'
|
|
30
31
|
import { applyHotMode } from '../../src/native-dev-bundle-url'
|
|
@@ -65,6 +66,7 @@ import {
|
|
|
65
66
|
type BridgeSimInfo,
|
|
66
67
|
} from '../ws-bridge'
|
|
67
68
|
import { WAIT_READY_PROBE, readyProbeHasContent, type ReadyProbe } from './inspect/core'
|
|
69
|
+
import { isAgentEnv } from './inspect/env'
|
|
68
70
|
import type { DriverId, DriverLaunchResult } from '../drivers/types'
|
|
69
71
|
|
|
70
72
|
interface ControlCommandOptions {
|
|
@@ -228,7 +230,7 @@ export async function ensureBridgeForOpen(
|
|
|
228
230
|
(await canConnectToBridge(nextLock.bridgePort, 250))
|
|
229
231
|
) {
|
|
230
232
|
console.error(
|
|
231
|
-
`
|
|
233
|
+
` Started a local bridge on port ${nextLock.bridgePort}. Run \`rnx daemon install\` to keep it ready between commands.`,
|
|
232
234
|
)
|
|
233
235
|
return nextLock.bridgePort
|
|
234
236
|
}
|
|
@@ -1219,6 +1221,7 @@ function printOpenedSim(
|
|
|
1219
1221
|
| 'direct shell open'
|
|
1220
1222
|
| 'current sim'
|
|
1221
1223
|
| `${string} driver`,
|
|
1224
|
+
quiet = false,
|
|
1222
1225
|
) {
|
|
1223
1226
|
const [printableOpenUrl, printableSimUrl] = [openUrl, sim.url].map((value) => {
|
|
1224
1227
|
if (!value) return value
|
|
@@ -1231,6 +1234,10 @@ function printOpenedSim(
|
|
|
1231
1234
|
} catch {}
|
|
1232
1235
|
return value
|
|
1233
1236
|
})
|
|
1237
|
+
if (quiet) {
|
|
1238
|
+
console.log(` Opened ConnectRN [${mode}]`)
|
|
1239
|
+
return
|
|
1240
|
+
}
|
|
1234
1241
|
console.log(
|
|
1235
1242
|
` ${mode === 'current sim' ? 'loaded' : 'opened'}: ${printableOpenUrl} [${mode}]`,
|
|
1236
1243
|
)
|
|
@@ -1428,6 +1435,7 @@ export async function runOpenCommand(
|
|
|
1428
1435
|
'--hot',
|
|
1429
1436
|
'--no-hmr',
|
|
1430
1437
|
'--no-describe',
|
|
1438
|
+
'--quiet',
|
|
1431
1439
|
],
|
|
1432
1440
|
stripValueFlags: [
|
|
1433
1441
|
'--base-url',
|
|
@@ -1440,6 +1448,7 @@ export async function runOpenCommand(
|
|
|
1440
1448
|
],
|
|
1441
1449
|
})
|
|
1442
1450
|
const requestedProfileId = args.find((_, i) => args[i - 1] === '--profile')
|
|
1451
|
+
const quiet = args.includes('--quiet')
|
|
1443
1452
|
const ephemeralProfile = args.includes('--ephemeral')
|
|
1444
1453
|
// --cdp-port exposes Chrome's remote-debugging endpoint on the opened sim so
|
|
1445
1454
|
// it can be cpu-profiled while bridge-driven (playwright driver only).
|
|
@@ -1548,7 +1557,13 @@ export async function runOpenCommand(
|
|
|
1548
1557
|
}
|
|
1549
1558
|
const driverId: DriverId = isDriverId(requestedDriverId)
|
|
1550
1559
|
? requestedDriverId
|
|
1551
|
-
: '
|
|
1560
|
+
: process.env.CI === '1' ||
|
|
1561
|
+
process.env.CI === 'true' ||
|
|
1562
|
+
process.env.GITHUB_ACTIONS === 'true' ||
|
|
1563
|
+
isAgentEnv() ||
|
|
1564
|
+
!process.stdin.isTTY
|
|
1565
|
+
? 'playwright'
|
|
1566
|
+
: readSimulatorDriverPreference() || 'playwright'
|
|
1552
1567
|
const driverHeadless = resolveDriverHeadless(args, driverId)
|
|
1553
1568
|
if (cdpPort && driverId !== 'playwright') {
|
|
1554
1569
|
console.error(' rnx open: --cdp-port is only honored by the playwright driver')
|
|
@@ -1568,7 +1583,7 @@ export async function runOpenCommand(
|
|
|
1568
1583
|
console.error(' rnx open: --hot and --no-hmr cannot be combined')
|
|
1569
1584
|
process.exit(1)
|
|
1570
1585
|
}
|
|
1571
|
-
const hotMode = hotFlag ? true : noHmrFlag ? false :
|
|
1586
|
+
const hotMode = hotFlag ? true : noHmrFlag ? false : driverId !== 'playwright'
|
|
1572
1587
|
|
|
1573
1588
|
// --device <model> seeds the device profile for the opened sim (stamped on
|
|
1574
1589
|
// the engine URL, so both playwright and electron honor it). without it
|
|
@@ -1735,7 +1750,7 @@ export async function runOpenCommand(
|
|
|
1735
1750
|
applySootSimConfigToUrl(resolvedBaseUrl, runtimeConfig),
|
|
1736
1751
|
buildShellUrlOpts,
|
|
1737
1752
|
))
|
|
1738
|
-
printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, 'current sim')
|
|
1753
|
+
printOpenedSim(shellUrl, { ...targetSim, url: shellUrl }, 'current sim', quiet)
|
|
1739
1754
|
await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args)
|
|
1740
1755
|
return parsed.wsPort
|
|
1741
1756
|
}
|
|
@@ -1814,7 +1829,7 @@ export async function runOpenCommand(
|
|
|
1814
1829
|
const match = outcome.sim
|
|
1815
1830
|
saveCurrentSimId(match.id)
|
|
1816
1831
|
signalDriverLaunchConnected(result)
|
|
1817
|
-
printOpenedSim(openUrl, match, `${driver.name} driver
|
|
1832
|
+
printOpenedSim(openUrl, match, `${driver.name} driver`, quiet)
|
|
1818
1833
|
await maybeDescribeAfterOpen(parsed.wsPort, match.id, args)
|
|
1819
1834
|
return parsed.wsPort
|
|
1820
1835
|
}
|
|
@@ -142,7 +142,7 @@ function renderLauncherScript(
|
|
|
142
142
|
const stdout = shellSingleQuote(logDir.stdout)
|
|
143
143
|
const stderr = shellSingleQuote(logDir.stderr)
|
|
144
144
|
return `#!/bin/sh
|
|
145
|
-
#
|
|
145
|
+
# sootsim daemon launcher generated by 'rnx daemon install'.
|
|
146
146
|
# launchd spawns this; we exec the real rnx invocation in place so
|
|
147
147
|
# launchd tracks the daemon process, not the shell wrapper.
|
|
148
148
|
#
|
package/cli/commands/daemon.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// registration time, so `npm update -g sootsim` + `sootsim daemon restart`
|
|
6
6
|
// picks up the upgrade without touching the plist/unit file.
|
|
7
7
|
//
|
|
8
|
-
// `daemonInstall` is shared by `
|
|
8
|
+
// `daemonInstall` is shared by `rnx setup` and the explicit
|
|
9
9
|
// `sootsim daemon install` machine-bootstrap path.
|
|
10
10
|
//
|
|
11
11
|
// macOS: ~/Library/LaunchAgents/dev.sootsim.daemon.plist (launchd)
|
|
@@ -656,7 +656,7 @@ async function daemonRestart() {
|
|
|
656
656
|
if (process.platform === 'darwin') {
|
|
657
657
|
const path = macPlistPath()
|
|
658
658
|
if (!existsSync(path)) {
|
|
659
|
-
console.error(' daemon not registered
|
|
659
|
+
console.error(' daemon not registered. run `rnx daemon install`')
|
|
660
660
|
process.exit(1)
|
|
661
661
|
}
|
|
662
662
|
const res = spawnSync(
|
|
@@ -674,7 +674,7 @@ async function daemonRestart() {
|
|
|
674
674
|
if (process.platform === 'linux') {
|
|
675
675
|
const path = linuxUnitPath()
|
|
676
676
|
if (!existsSync(path)) {
|
|
677
|
-
console.error(' daemon not registered
|
|
677
|
+
console.error(' daemon not registered. run `rnx daemon install`')
|
|
678
678
|
process.exit(1)
|
|
679
679
|
}
|
|
680
680
|
const res = spawnSync('systemctl', ['--user', 'restart', SERVICE_NAME_LINUX], {
|
|
@@ -696,7 +696,7 @@ async function daemonStart() {
|
|
|
696
696
|
if (process.platform === 'darwin') {
|
|
697
697
|
const path = macPlistPath()
|
|
698
698
|
if (!existsSync(path)) {
|
|
699
|
-
console.error(' daemon not registered
|
|
699
|
+
console.error(' daemon not registered. run `rnx daemon install`')
|
|
700
700
|
process.exit(1)
|
|
701
701
|
}
|
|
702
702
|
const res = spawnSync(
|
|
@@ -714,7 +714,7 @@ async function daemonStart() {
|
|
|
714
714
|
if (process.platform === 'linux') {
|
|
715
715
|
const path = linuxUnitPath()
|
|
716
716
|
if (!existsSync(path)) {
|
|
717
|
-
console.error(' daemon not registered
|
|
717
|
+
console.error(' daemon not registered. run `rnx daemon install`')
|
|
718
718
|
process.exit(1)
|
|
719
719
|
}
|
|
720
720
|
const res = spawnSync('systemctl', ['--user', 'start', SERVICE_NAME_LINUX], {
|
|
@@ -788,9 +788,7 @@ async function daemonLogs(rest: string[]) {
|
|
|
788
788
|
const err = resolve(LOG_DIR, 'bridge.err.log')
|
|
789
789
|
const present = [out, err].filter((p) => existsSync(p))
|
|
790
790
|
if (present.length === 0) {
|
|
791
|
-
console.error(
|
|
792
|
-
` no daemon logs yet at ${LOG_DIR} — run \`rnx setup\` to install the daemon`,
|
|
793
|
-
)
|
|
791
|
+
console.error(` no daemon logs yet at ${LOG_DIR}. run \`rnx daemon install\``)
|
|
794
792
|
process.exit(1)
|
|
795
793
|
}
|
|
796
794
|
const args = follow
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
//
|
|
6
6
|
// fetches the right platform artifact from https://contrast.dev/api/electron-release/
|
|
7
7
|
// and installs it into the OS-native location that findDesktopCompanion() looks for:
|
|
8
|
-
//
|
|
9
|
-
// linux: ~/Applications/
|
|
8
|
+
// macos: ~/Applications/rnx.app (or /Applications if writable)
|
|
9
|
+
// linux: ~/Applications/rnx.AppImage
|
|
10
10
|
// win: spawns the NSIS installer
|
|
11
11
|
//
|
|
12
12
|
// post-install the electron-updater feed (same URL) handles upgrades inside the
|
|
@@ -27,6 +27,7 @@ import { tmpdir } from 'os'
|
|
|
27
27
|
import { dirname, join, resolve } from 'path'
|
|
28
28
|
import { findDesktopCompanion } from '../desktop-companion'
|
|
29
29
|
import { confirm } from '../prompt'
|
|
30
|
+
import { accent, bold, failure, muted, success, withSpinner } from '../ui'
|
|
30
31
|
|
|
31
32
|
const DOWNLOAD_BASE = 'https://contrast.dev/api/electron-release'
|
|
32
33
|
|
|
@@ -122,7 +123,7 @@ function renderProgress(received: number, total: number | null): string {
|
|
|
122
123
|
const totalMb = (total / (1024 * 1024)).toFixed(1)
|
|
123
124
|
const barWidth = 24
|
|
124
125
|
const filled = Math.round((pct / 100) * barWidth)
|
|
125
|
-
const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled)
|
|
126
|
+
const bar = accent('█'.repeat(filled)) + muted('░'.repeat(barWidth - filled))
|
|
126
127
|
return ` ${bar} ${pct}% ${mb} / ${totalMb} MB`
|
|
127
128
|
}
|
|
128
129
|
|
|
@@ -169,7 +170,7 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
169
170
|
mkdirSync(destRoot, { recursive: true })
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
const appDest = join(destRoot, '
|
|
173
|
+
const appDest = join(destRoot, 'rnx.app')
|
|
173
174
|
if (existsSync(appDest)) rmSync(appDest, { recursive: true, force: true })
|
|
174
175
|
|
|
175
176
|
const copy = spawnSync('cp', ['-R', appSource, appDest])
|
|
@@ -193,7 +194,7 @@ async function installMacDmg(dmgPath: string): Promise<string> {
|
|
|
193
194
|
async function installLinuxAppImage(appImagePath: string): Promise<string> {
|
|
194
195
|
const destDir = resolve(process.env.HOME || '', 'Applications')
|
|
195
196
|
mkdirSync(destDir, { recursive: true })
|
|
196
|
-
const dest = join(destDir, '
|
|
197
|
+
const dest = join(destDir, 'rnx.AppImage')
|
|
197
198
|
if (existsSync(dest)) rmSync(dest, { force: true })
|
|
198
199
|
// copyFile + unlink instead of rename: /tmp and ~/Applications are
|
|
199
200
|
// routinely on separate mounts in containers / VMs, where renameSync
|
|
@@ -217,17 +218,20 @@ async function installWindowsExe(exePath: string): Promise<string> {
|
|
|
217
218
|
else rejectPromise(new Error(`installer exited with code ${code}`))
|
|
218
219
|
})
|
|
219
220
|
})
|
|
220
|
-
|
|
221
|
+
const installed = findDesktopCompanion()
|
|
222
|
+
if (!installed) {
|
|
223
|
+
throw new Error('the installer finished but the rnx application was not registered')
|
|
224
|
+
}
|
|
225
|
+
return installed.path
|
|
221
226
|
}
|
|
222
227
|
|
|
223
228
|
export async function runInstallDesktop(args: string[]) {
|
|
224
229
|
if (args.includes('--help') || args.includes('-h')) {
|
|
225
230
|
console.log(`
|
|
226
|
-
rnx desktop install
|
|
231
|
+
rnx desktop install
|
|
227
232
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
terminal, you don't need this.
|
|
233
|
+
Download and install the optional rnx Desktop app.
|
|
234
|
+
The CLI works without it. Choose Desktop when you want a dedicated native window.
|
|
231
235
|
|
|
232
236
|
usage:
|
|
233
237
|
rnx desktop install [options]
|
|
@@ -253,28 +257,31 @@ examples:
|
|
|
253
257
|
|
|
254
258
|
const existing = findDesktopCompanion()
|
|
255
259
|
if (existing && !force) {
|
|
256
|
-
console.log(`
|
|
257
|
-
console.log('
|
|
260
|
+
console.log(` ${success('✓')} Desktop app is already installed at ${existing.path}`)
|
|
261
|
+
console.log(` ${muted('Pass --force to reinstall.')}`)
|
|
258
262
|
return
|
|
259
263
|
}
|
|
260
264
|
|
|
261
265
|
const target = detectTarget()
|
|
262
266
|
if (!target) {
|
|
263
|
-
console.error(` no desktop build available for ${process.platform}/${process.arch}.`)
|
|
264
267
|
console.error(
|
|
265
|
-
'
|
|
268
|
+
` ${failure('×')} No desktop build is available for ${process.platform}/${process.arch}.`,
|
|
269
|
+
)
|
|
270
|
+
console.error(
|
|
271
|
+
' Supported: darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64',
|
|
266
272
|
)
|
|
267
273
|
process.exit(1)
|
|
268
274
|
}
|
|
269
275
|
|
|
270
|
-
console.log(`
|
|
271
|
-
console.log(`
|
|
276
|
+
console.log(` ${bold('Desktop app')}`)
|
|
277
|
+
console.log(` Platform ${target.platform}`)
|
|
278
|
+
console.log(` Download ${target.url}`)
|
|
272
279
|
console.log()
|
|
273
280
|
|
|
274
281
|
if (!skipConfirm) {
|
|
275
|
-
const ok = await confirm('
|
|
282
|
+
const ok = await confirm('Download and install now?', true)
|
|
276
283
|
if (!ok) {
|
|
277
|
-
console.log('
|
|
284
|
+
console.log(` ${muted('Cancelled.')}`)
|
|
278
285
|
return
|
|
279
286
|
}
|
|
280
287
|
console.log()
|
|
@@ -284,7 +291,7 @@ examples:
|
|
|
284
291
|
const downloadPath = join(workDir, target.filename)
|
|
285
292
|
|
|
286
293
|
let lastDraw = 0
|
|
287
|
-
process.stdout.write(`
|
|
294
|
+
process.stdout.write(` Downloading ${target.filename}...\n`)
|
|
288
295
|
|
|
289
296
|
try {
|
|
290
297
|
await download({
|
|
@@ -302,36 +309,39 @@ examples:
|
|
|
302
309
|
} catch (err) {
|
|
303
310
|
rmSync(workDir, { recursive: true, force: true })
|
|
304
311
|
const message = err instanceof Error ? err.message : String(err)
|
|
305
|
-
console.error(`\n
|
|
312
|
+
console.error(`\n ${failure('×')} Download failed: ${message}`)
|
|
306
313
|
console.error(
|
|
307
|
-
`
|
|
314
|
+
` The ${target.platform} desktop build may not be published yet, or your`,
|
|
308
315
|
)
|
|
309
316
|
console.error(
|
|
310
|
-
' network blocked the request.
|
|
317
|
+
' network blocked the request. Check your connection and try again later.',
|
|
311
318
|
)
|
|
312
|
-
console.error('
|
|
319
|
+
console.error(' The CLI and daemon work without the desktop app. Run `rnx --help`.')
|
|
313
320
|
process.exit(1)
|
|
314
321
|
}
|
|
315
322
|
|
|
316
323
|
if (process.stdout.isTTY) process.stdout.write('\n')
|
|
317
324
|
const size = statSync(downloadPath).size
|
|
318
|
-
console.log(`
|
|
325
|
+
console.log(` ${success('✓')} Downloaded ${(size / (1024 * 1024)).toFixed(1)} MB`)
|
|
319
326
|
console.log()
|
|
320
|
-
console.log(` installing...`)
|
|
321
327
|
|
|
322
328
|
try {
|
|
323
|
-
const installedAt = await
|
|
324
|
-
|
|
329
|
+
const installedAt = await withSpinner('Installing the desktop app', () =>
|
|
330
|
+
target.install(downloadPath),
|
|
331
|
+
)
|
|
332
|
+
console.log(` Installed at ${installedAt}`)
|
|
325
333
|
} catch (err) {
|
|
326
|
-
console.error(
|
|
327
|
-
|
|
334
|
+
console.error(
|
|
335
|
+
` ${failure('×')} Install failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
336
|
+
)
|
|
337
|
+
console.error(` Keeping the download at ${downloadPath} for manual installation.`)
|
|
328
338
|
process.exit(1)
|
|
329
339
|
} finally {
|
|
330
340
|
rmSync(workDir, { recursive: true, force: true })
|
|
331
341
|
}
|
|
332
342
|
|
|
333
343
|
console.log()
|
|
334
|
-
console.log(
|
|
335
|
-
console.log('
|
|
336
|
-
console.log('
|
|
344
|
+
console.log(` ${bold('Ready')}`)
|
|
345
|
+
console.log(' rnx desktop Launch the desktop app')
|
|
346
|
+
console.log(' rnx open <target> Open a demo or bundle in it')
|
|
337
347
|
}
|
|
@@ -9,8 +9,8 @@ export function printMissingCompanionHint() {
|
|
|
9
9
|
console.error(' install the desktop app:')
|
|
10
10
|
console.error(' rnx desktop install')
|
|
11
11
|
console.error('')
|
|
12
|
-
console.error(' or
|
|
13
|
-
console.error(' rnx
|
|
12
|
+
console.error(' or install the recommended background service:')
|
|
13
|
+
console.error(' rnx daemon install')
|
|
14
14
|
console.error('')
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -23,7 +23,7 @@ export function printMissingBridgeHint(port: number) {
|
|
|
23
23
|
return
|
|
24
24
|
}
|
|
25
25
|
console.log('')
|
|
26
|
-
console.log(' run `rnx
|
|
26
|
+
console.log(' run `rnx daemon install` to enable the faster background service,')
|
|
27
27
|
console.log(' or run `rnx serve` in another shell for a foreground bridge.')
|
|
28
28
|
}
|
|
29
29
|
|
package/cli/commands/serve.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// them; electron fetches renderer assets over http from the same port.
|
|
7
7
|
//
|
|
8
8
|
// run in the foreground (ctrl-c to stop). the persistent launchd/systemd
|
|
9
|
-
// daemon installation is handled by `
|
|
9
|
+
// daemon installation is handled by `rnx daemon install`.
|
|
10
10
|
|
|
11
11
|
import { DEFAULT_SOOTSIM_BRIDGE_PORT } from '../../src/bridge-constants'
|
|
12
12
|
import {
|