rnxsim 0.1.376 → 0.1.378
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 +28 -25
- package/cli/app-config.ts +9 -12
- package/cli/app-fonts.ts +3 -3
- package/cli/app-project.ts +8 -8
- package/cli/auth.ts +7 -9
- package/cli/bin.ts +16 -31
- package/cli/bridge-flow-runner.ts +3 -3
- package/cli/browser-backend.ts +44 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +291 -0
- package/cli/commands/agent-wrapper.ts +2 -2
- package/cli/commands/app-fonts.ts +2 -2
- package/cli/commands/assert.ts +3 -3
- package/cli/commands/auth.ts +1 -1
- package/cli/commands/box/cloud-box.ts +1 -1
- package/cli/commands/box/plane-share.ts +2 -2
- package/cli/commands/box.ts +4 -6
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +29 -29
- package/cli/commands/cpu-profile.ts +7 -7
- package/cli/commands/daemon-mac-app.ts +7 -7
- package/cli/commands/daemon.ts +10 -10
- package/cli/commands/debug.ts +11 -11
- package/cli/commands/detox.ts +13 -13
- package/cli/commands/diagnose.ts +6 -6
- package/cli/commands/do-chain.ts +1 -2
- package/cli/commands/electron.ts +1 -3
- package/cli/commands/film.ts +3 -3
- package/cli/commands/flow.ts +43 -43
- package/cli/commands/inspect/count.ts +1 -1
- package/cli/commands/inspect/describe.ts +1 -1
- package/cli/commands/inspect/env.ts +2 -2
- package/cli/commands/inspect/get-layout.ts +1 -1
- package/cli/commands/inspect/keyboard.ts +1 -1
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/memory.ts +1 -1
- package/cli/commands/inspect/resolve-target.ts +1 -1
- package/cli/commands/inspect/screens.ts +1 -1
- package/cli/commands/inspect/tree.ts +1 -1
- package/cli/commands/inspect/url.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +5 -5
- package/cli/commands/inspect.ts +34 -34
- package/cli/commands/install-desktop.ts +3 -3
- package/cli/commands/login.ts +6 -6
- package/cli/commands/maestro-generate.ts +5 -5
- package/cli/commands/maestro.ts +5 -5
- package/cli/commands/profile.ts +1 -1
- package/cli/commands/record.ts +9 -9
- package/cli/commands/runtime.ts +18 -18
- package/cli/commands/screenshot-command.ts +1 -1
- package/cli/commands/screenshot-layers.ts +5 -5
- package/cli/commands/screenshot-mode.ts +1 -1
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +5 -5
- package/cli/commands/serve.ts +3 -3
- package/cli/commands/setup.ts +20 -12
- package/cli/commands/skills.ts +5 -5
- package/cli/commands/slides.ts +1 -1
- package/cli/commands/telemetry.ts +1 -1
- package/cli/commands/three-mode.ts +1 -1
- package/cli/commands/timeline.ts +8 -8
- package/cli/commands/upgrade.ts +116 -131
- package/cli/commands/upload.ts +12 -12
- package/cli/commands/version.ts +7 -7
- package/cli/commands/what-happened.ts +9 -9
- package/cli/current-sim.ts +3 -3
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/playwright.ts +9 -9
- package/cli/drivers/registry.ts +1 -1
- package/cli/drivers/types.ts +1 -1
- package/cli/flow-file.ts +2 -2
- package/cli/flow-session.ts +1 -1
- package/cli/help-core.ts +136 -0
- package/cli/help.ts +17 -53
- package/cli/hints.ts +5 -5
- package/cli/inspect-notice-state.ts +1 -1
- package/cli/maestro-js.ts +1 -1
- package/cli/outbound-endpoints.ts +23 -5
- package/cli/parse-args.ts +19 -66
- package/cli/recording-access.ts +1 -1
- package/cli/registry.ts +1 -0
- package/cli/run-registry.ts +1 -1
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +6 -9
- package/cli/runtime-notes.ts +3 -3
- package/cli/standalone.ts +4 -0
- package/cli/ws-bridge.ts +8 -8
- package/detox/config-loader.ts +2 -2
- package/detox/index.ts +8 -8
- package/detox/jest-preset.cjs +1 -1
- package/detox/navigation.ts +2 -2
- package/dist-lib/agent-daemon-client.cjs +5 -5
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +2 -2
- package/dist-lib/agent-sessions.cjs +10 -10
- package/dist-lib/attached-projects.cjs +6 -6
- package/dist-lib/auth/shared-session.cjs +6 -6
- 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-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +25 -25
- package/dist-lib/detox/index.cjs +73 -31
- package/dist-lib/detox/jest-preset.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +29 -29
- package/dist-lib/host/bridge-host.cjs +128 -49
- 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 +14 -14
- 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 +8 -8
- package/dist-lib/profiles.cjs +12 -12
- 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 +8 -8
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +329 -160
- package/dist-lib/vite.cjs +9 -9
- package/package.json +4 -11
- package/scripts/dev-server-scanner.ts +2 -2
- package/scripts/optional-demo-registry.ts +1 -1
- package/skills/contrast/SKILL.md +3 -3
- package/skills/rnx-debug/SKILL.md +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/agent-identity.ts +1 -1
- package/src/agent-sessions.ts +7 -5
- package/src/cli-version.ts +12 -4
- package/src/config.ts +26 -28
- package/src/disk-cleanup.ts +11 -11
- package/src/home-paths.ts +28 -28
- package/src/host/bridge-host.ts +16 -16
- package/src/metro-plugin.ts +2 -2
- package/src/profiles.ts +2 -2
- package/src/runtime-assets.ts +7 -7
- package/src/runtime-delivery.ts +13 -13
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/skills/builtin/a11y-review.ts +2 -2
- package/src/skills/builtin/compat-check.ts +2 -2
- package/src/skills/builtin/maestro-test.ts +2 -2
- package/src/skills/builtin/perf-profile.ts +2 -2
- package/src/skills/builtin/screenshot-all.ts +2 -2
- package/src/skills/builtin/visual-diff.ts +2 -2
- package/src/skills/registry.ts +8 -8
- package/src/skills/types.ts +1 -1
- package/src/vite-plugin-one.ts +3 -3
- package/src/vite-plugin.ts +15 -2
- package/dist-cli/bin.js +0 -15
- package/dist-cli/chunks/agent-H42FCKFF.js +0 -48
- package/dist-cli/chunks/agent-wrapper-BBZKTZS6.js +0 -17
- package/dist-cli/chunks/app-fonts-43VXIKF4.js +0 -4
- package/dist-cli/chunks/assert-IXOLVO5Z.js +0 -49
- package/dist-cli/chunks/auth-KFMFB6FU.js +0 -12
- package/dist-cli/chunks/beta-5AO3SJB7.js +0 -4
- package/dist-cli/chunks/box-ZHM66L6K.js +0 -1730
- package/dist-cli/chunks/camera-FNJVFCDQ.js +0 -33
- package/dist-cli/chunks/chunk-37MCSPTE.js +0 -71
- package/dist-cli/chunks/chunk-3PEMSUAQ.js +0 -30
- package/dist-cli/chunks/chunk-4TQ5HOK3.js +0 -7
- package/dist-cli/chunks/chunk-5YZYDEMI.js +0 -4
- package/dist-cli/chunks/chunk-6CV3R3XD.js +0 -15
- package/dist-cli/chunks/chunk-7LGK5XU6.js +0 -4
- package/dist-cli/chunks/chunk-7R2TK2NY.js +0 -4
- package/dist-cli/chunks/chunk-7VZZQQEE.js +0 -497
- package/dist-cli/chunks/chunk-AFOVILIL.js +0 -130
- package/dist-cli/chunks/chunk-BEU7CD7E.js +0 -9
- package/dist-cli/chunks/chunk-CE4JQJ6Y.js +0 -6
- package/dist-cli/chunks/chunk-CIE6CZXL.js +0 -142
- package/dist-cli/chunks/chunk-CSJ7L7ZL.js +0 -312
- package/dist-cli/chunks/chunk-CWCQP53A.js +0 -27
- package/dist-cli/chunks/chunk-DCS5FK5N.js +0 -7
- package/dist-cli/chunks/chunk-DEV3E3MV.js +0 -4
- package/dist-cli/chunks/chunk-DGJMIVZM.js +0 -5
- package/dist-cli/chunks/chunk-DGX3MN65.js +0 -5
- package/dist-cli/chunks/chunk-DNPQMTW5.js +0 -4
- package/dist-cli/chunks/chunk-DOVBJBVD.js +0 -5
- package/dist-cli/chunks/chunk-DPBJ3S3J.js +0 -3
- package/dist-cli/chunks/chunk-FVZBGPCU.js +0 -4
- package/dist-cli/chunks/chunk-GDKMOIUT.js +0 -4
- package/dist-cli/chunks/chunk-GIF2NJCS.js +0 -32
- package/dist-cli/chunks/chunk-GZE57ORL.js +0 -4
- package/dist-cli/chunks/chunk-H3U56DKI.js +0 -24
- package/dist-cli/chunks/chunk-HZLOYAPH.js +0 -4
- package/dist-cli/chunks/chunk-J2IKAEU2.js +0 -4
- package/dist-cli/chunks/chunk-JXAXYK7W.js +0 -11
- package/dist-cli/chunks/chunk-KJE2O2GK.js +0 -4
- package/dist-cli/chunks/chunk-KMNVDZZI.js +0 -423
- package/dist-cli/chunks/chunk-LC3QRIRB.js +0 -10
- package/dist-cli/chunks/chunk-LGFTAQYC.js +0 -4
- package/dist-cli/chunks/chunk-LQMUA5IY.js +0 -4
- package/dist-cli/chunks/chunk-MFIQTWC5.js +0 -4
- package/dist-cli/chunks/chunk-MGALNF2F.js +0 -7
- package/dist-cli/chunks/chunk-MLBZZHOY.js +0 -4
- package/dist-cli/chunks/chunk-NNRF7GIB.js +0 -107
- package/dist-cli/chunks/chunk-NORLYTTO.js +0 -7
- package/dist-cli/chunks/chunk-P6KVGV3H.js +0 -14
- package/dist-cli/chunks/chunk-PAJTUK33.js +0 -4
- package/dist-cli/chunks/chunk-QELIC5XP.js +0 -4
- package/dist-cli/chunks/chunk-QRDF33WD.js +0 -11
- package/dist-cli/chunks/chunk-R76BA7C7.js +0 -535
- package/dist-cli/chunks/chunk-RVEB4CZ2.js +0 -4
- package/dist-cli/chunks/chunk-SK4M7NXT.js +0 -5
- package/dist-cli/chunks/chunk-SKMG5DD7.js +0 -5
- package/dist-cli/chunks/chunk-TEESPOYR.js +0 -4
- package/dist-cli/chunks/chunk-TH2UFGVP.js +0 -4
- package/dist-cli/chunks/chunk-TLP3T3VO.js +0 -4
- package/dist-cli/chunks/chunk-TZUABDIJ.js +0 -38
- package/dist-cli/chunks/chunk-UB2W6OQM.js +0 -99
- package/dist-cli/chunks/chunk-UYVXALPB.js +0 -506
- package/dist-cli/chunks/chunk-VQDYFFIG.js +0 -5
- package/dist-cli/chunks/chunk-VWCNJPCJ.js +0 -5
- package/dist-cli/chunks/chunk-VZIK4WIS.js +0 -74
- package/dist-cli/chunks/chunk-W3FNXAQP.js +0 -4
- package/dist-cli/chunks/chunk-XCDNVNP3.js +0 -4
- package/dist-cli/chunks/chunk-XSVILA4Z.js +0 -4
- package/dist-cli/chunks/chunk-XUTJ7ZWD.js +0 -4
- package/dist-cli/chunks/chunk-YTXY3MHW.js +0 -4
- package/dist-cli/chunks/chunk-ZF7PVX44.js +0 -28
- package/dist-cli/chunks/chunk-ZSSG7OR7.js +0 -4
- package/dist-cli/chunks/cleanup-MLOK2OZA.js +0 -25
- package/dist-cli/chunks/cli-version-OBNR366V.js +0 -4
- package/dist-cli/chunks/compat-SHMFSKU7.js +0 -23
- package/dist-cli/chunks/config-TPEAEUJ2.js +0 -13
- package/dist-cli/chunks/connect-3LEXWTE5.js +0 -4
- package/dist-cli/chunks/control-Z3FWA6BO.js +0 -4
- package/dist-cli/chunks/daemon-RSVYSC65.js +0 -4
- package/dist-cli/chunks/debug-GUVAK2KR.js +0 -200
- package/dist-cli/chunks/desktop-OOP2PTKP.js +0 -31
- package/dist-cli/chunks/detox-C2ILVBEC.js +0 -52
- package/dist-cli/chunks/device-NXIQQJWR.js +0 -18
- package/dist-cli/chunks/diagnose-2JBGYE5L.js +0 -43
- package/dist-cli/chunks/disk-cleanup-VURWJYQV.js +0 -4
- package/dist-cli/chunks/do-chain-DJ4UQC7A.js +0 -5
- package/dist-cli/chunks/drivers-JMA2OIKU.js +0 -4
- package/dist-cli/chunks/env-KTNPKEZR.js +0 -4
- package/dist-cli/chunks/film-DCPS7EID.js +0 -74
- package/dist-cli/chunks/flow-4DZ7B2OA.js +0 -4
- package/dist-cli/chunks/help-34CJMQY2.js +0 -4
- package/dist-cli/chunks/hidden-runtime-alias-HHT2C7WE.js +0 -4
- package/dist-cli/chunks/home-paths-KTPGCPMS.js +0 -4
- package/dist-cli/chunks/inspect-JF5WYJRD.js +0 -4
- package/dist-cli/chunks/install-desktop-ZIC4CDXI.js +0 -4
- package/dist-cli/chunks/login-TTJAOI2Q.js +0 -26
- package/dist-cli/chunks/logout-ERAQ6SKW.js +0 -4
- package/dist-cli/chunks/maestro-W46QCF77.js +0 -108
- package/dist-cli/chunks/maestro-generate-VBLM3MTU.js +0 -36
- package/dist-cli/chunks/mode-ZEDZK7R7.js +0 -26
- package/dist-cli/chunks/optional-demo-registry-ZUTPSVYQ.js +0 -4
- package/dist-cli/chunks/perf-YVT2WXT4.js +0 -48
- package/dist-cli/chunks/permissions-L7VVDHFP.js +0 -13
- package/dist-cli/chunks/platform-7TJOU2FB.js +0 -6
- package/dist-cli/chunks/privacy-57UOTB5J.js +0 -4
- package/dist-cli/chunks/record-VXG37P7U.js +0 -72
- package/dist-cli/chunks/report-issue-WNNOBZHC.js +0 -29
- package/dist-cli/chunks/reset-H5NBFE5U.js +0 -4
- package/dist-cli/chunks/resolve-target-57TK5WLE.js +0 -4
- package/dist-cli/chunks/runtime-QU2NIF2K.js +0 -4
- package/dist-cli/chunks/screenshot-command-AN56TTG7.js +0 -159
- package/dist-cli/chunks/screenshot-layers-3W5R7DB2.js +0 -20
- package/dist-cli/chunks/screenshots-capture-6AWJY7XZ.js +0 -42
- package/dist-cli/chunks/serve-GLYO5Q7J.js +0 -56
- package/dist-cli/chunks/setup-UA2HLD7S.js +0 -4
- package/dist-cli/chunks/sim-client-5C2RDQQO.js +0 -4
- package/dist-cli/chunks/skills-EYXWBRNQ.js +0 -50
- package/dist-cli/chunks/state-REJ7W6K3.js +0 -14
- package/dist-cli/chunks/storage-CFMDHI3V.js +0 -37
- package/dist-cli/chunks/store-XMCUA45G.js +0 -4
- package/dist-cli/chunks/telemetry-FBL3NAKB.js +0 -4
- package/dist-cli/chunks/timeline-HMCHN5FO.js +0 -24
- package/dist-cli/chunks/upgrade-2QSPAA3P.js +0 -7
- package/dist-cli/chunks/upload-DUQBKZYV.js +0 -4
- package/dist-cli/chunks/version-IOA6QFGB.js +0 -6
- package/dist-cli/chunks/web-NCGUYVCJ.js +0 -4
- package/dist-cli/chunks/welcome-QYGSQCWQ.js +0 -5
- package/dist-cli/chunks/what-happened-YTOUK4LO.js +0 -25
- package/dist-cli/chunks/ws-bridge-OF4OZARG.js +0 -4
- package/scripts/postinstall.cjs +0 -3
- package/scripts/preuninstall.cjs +0 -118
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ React Native simulator.
|
|
|
10
10
|
contains **no rendering code**. The canvas engine (CanvasKit renderer, Yoga
|
|
11
11
|
layout, iOS/Android shell chrome, Electron shell) lives in the private
|
|
12
12
|
`sootsim-engine` workspace package and is shipped at runtime as a versioned
|
|
13
|
-
tarball, fetched from the contrast.dev CDN and unpacked into `~/.
|
|
13
|
+
tarball, fetched from the contrast.dev CDN and unpacked into `~/.rnx`.
|
|
14
14
|
|
|
15
15
|
What this package gives you:
|
|
16
16
|
|
|
@@ -87,7 +87,7 @@ graph TD
|
|
|
87
87
|
ENGINESHIM["sootsim-engine react-native shim"]
|
|
88
88
|
end
|
|
89
89
|
SKILLS["rnxsim/skills registry.ts (builtin skills)"]
|
|
90
|
-
subgraph fs["~/.
|
|
90
|
+
subgraph fs["~/.rnx (home-paths.ts)"]
|
|
91
91
|
RTDIR["runtimes/<version>/ (engine assets)"]
|
|
92
92
|
LOCK["daemon.json lockfile"]
|
|
93
93
|
CFG["config.json"]
|
|
@@ -149,7 +149,7 @@ Electron is the native desktop surface.
|
|
|
149
149
|
|
|
150
150
|
**The daemon is one process** — `SootSimBridgeHost` (`src/host/bridge-host.ts`).
|
|
151
151
|
`rnx serve` runs it in the foreground; the background daemon is the *same
|
|
152
|
-
process* wrapped with autostart and the `~/.
|
|
152
|
+
process* wrapped with autostart and the `~/.rnx/daemon.json` lockfile. It is
|
|
153
153
|
an HTTP+WS hub: sims register over WS, CLI clients connect to drive them, and
|
|
154
154
|
the host forwards each command to the targeted sim and relays the reply back. It
|
|
155
155
|
also serves the engine runtime over HTTP (with a self-update route), exposes
|
|
@@ -159,7 +159,7 @@ localhost. The `AgentHost` extension owns one FIFO reader per agent session and
|
|
|
159
159
|
fans agent events out to every subscriber.
|
|
160
160
|
|
|
161
161
|
During source development, each Vite bridge owns one
|
|
162
|
-
`~/.
|
|
162
|
+
`~/.rnx/dev-bridges/<port>.json` heartbeat record. CLI defaults select the
|
|
163
163
|
current `PORT_OFFSET`, then the current checkout, then the canonical `:7668`
|
|
164
164
|
bridge, so concurrent worktrees cannot replace or delete one another's address.
|
|
165
165
|
|
|
@@ -175,7 +175,7 @@ bridge always addresses the **shell worker**, never an undifferentiated sim.
|
|
|
175
175
|
and **`rnxsim/metro`** plugins do one thing: serve the installed runtime at
|
|
176
176
|
`/__soot/` so an app's own dev server can host the sim shell. Both accept an
|
|
177
177
|
opt-in `open` option that launches a named Electron window when the dev server
|
|
178
|
-
starts (skipped when `CI` or `
|
|
178
|
+
starts (skipped when `CI` or `RNX_NO_OPEN` is set).
|
|
179
179
|
- The internal **`sootsim()`** plugin (`src/vite-plugin.ts`) is a separate, much
|
|
180
180
|
larger RN-resolution / native-stub plugin: it aliases `react-native` to the
|
|
181
181
|
engine shim and native packages to `@sootsim/compat` stubs, applies worklets
|
|
@@ -196,20 +196,21 @@ bridge always addresses the **shell worker**, never an undifferentiated sim.
|
|
|
196
196
|
| SootSimBridgeHost (serve/daemon) | The bridge process (`rnx serve`, or autostarted as the daemon via launchd/systemd). HTTP+WS hub on `:7668`: relays commands between CLI clients and registered sims; also serves runtime HTTP, `/__server-scan`, and fetch/WS proxies. | `src/host/bridge-host.ts`, `cli/commands/serve.ts`, `cli/commands/daemon.ts`, `src/home-paths.ts` |
|
|
197
197
|
| AgentHost + sessions | Agent-routing extension of the host: owns the single FIFO reader per agent session and fans `agent:event`/`session-status` pushes to every WS subscriber. Backed by agent-sessions + attached-projects stores. | `src/host/agent-host.ts`, `src/agent-sessions.ts`, `src/attached-projects.ts`, `src/agent-daemon-client.ts` |
|
|
198
198
|
| host proxies + dev-server scan | Host-side helpers so a cross-origin tenant worker can reach local dev servers and same-origin APIs: `/__server-scan` discovers running metro/expo/vxrn/one servers; fetch + websocket proxies relay guest-app network through the daemon. | `src/host/fetch-proxy-handler.ts`, `src/host/websocket-proxy.ts`, `scripts/dev-server-scanner.ts`, `src/dev-bundle-resolution.ts` |
|
|
199
|
-
| runtime delivery + rnx home | Versioned engine runtime management. The shared machinery owns manifest fetch, sha256 verification, channels, and auto-update. rnx binds it to `https://contrast.dev` and `~/.
|
|
200
|
-
| `rnxsim/vite` + `rnxsim/metro` (runtime serving) | Published bundler plugins. Both serve the installed engine runtime at `/__soot/` from `~/.
|
|
199
|
+
| runtime delivery + rnx home | Versioned engine runtime management. The shared machinery owns manifest fetch, sha256 verification, channels, and auto-update. rnx binds it to `https://contrast.dev` and `~/.rnx/runtimes/<version>`. A repo can select `runtimeVersion` without changing the machine default. | `src/runtime-delivery.ts`, `packages/contrast-runtime-delivery/`, `src/home-paths.ts`, `src/runtime-assets.ts` |
|
|
200
|
+
| `rnxsim/vite` + `rnxsim/metro` (runtime serving) | Published bundler plugins. Both serve the installed engine runtime at `/__soot/` from `~/.rnx/runtimes/<version>` so an app's own dev server can host the sim shell; either plugin can opt into a named Electron window. | `src/vite-plugin-one.ts`, `src/metro-plugin.ts`, `src/runtime-assets.ts` |
|
|
201
201
|
| `sootsim()` vite resolver plugin (internal) | The large RN-resolution / native-stub vite plugin: aliases `react-native` to the engine shim, native packages to `@sootsim/compat` stubs, applies worklets/babel transforms, and instantiates `SootSimBridgeHost` in its dev server. Distinct from the published `rnxsim/vite` export. | `src/vite-plugin.ts`, `src/worklets-babel.ts`, `packages/compat/src/stub-manifest.ts` |
|
|
202
202
|
| skills registry | rnx agent skills (`rnx-setup`, `rnx-debug`, `rnx-test`, `rnx-visual`, and the generated `contrast` index) installable with `rnx skill`. | `skills/*.md`, `src/skills/registry.ts`, `src/skills/types.ts` |
|
|
203
203
|
|
|
204
204
|
## Getting started
|
|
205
205
|
|
|
206
206
|
```sh
|
|
207
|
-
|
|
207
|
+
curl -fsSL https://rnxsim.com/install.sh | sh
|
|
208
|
+
rnx # open ConnectRN and choose a running app in the simulator
|
|
208
209
|
rnx open /settings # dispatch a React Native deep link into that app
|
|
209
210
|
```
|
|
210
211
|
|
|
211
212
|
Start Metro, Expo, One, or another supported React Native development server
|
|
212
|
-
the way you normally do, then run `
|
|
213
|
+
the way you normally do, then run `rnx` from any directory. The simulator
|
|
213
214
|
opens ConnectRN, which shows the available local apps and lets you connect one.
|
|
214
215
|
Pass a target to `rnx open <port-or-url>` when a script or agent needs an explicit
|
|
215
216
|
selection.
|
|
@@ -223,10 +224,10 @@ requested target. Use `rnx do reload` when the target has not changed.
|
|
|
223
224
|
Reserve `--new` for a genuinely concurrent sim; repeated new browser trees
|
|
224
225
|
consume memory and CPU on shared machines.
|
|
225
226
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
The public installer places one standalone `rnx` executable in `~/.local/bin`.
|
|
228
|
+
The `rnxsim` npm package contains bundler plugins and library exports, not a CLI
|
|
229
|
+
binary. Start your Metro, Expo, or One dev server the way you already do, then
|
|
230
|
+
open it from the CLI. There is no iOS native build in the inner loop; Metro alone is
|
|
230
231
|
enough. The manifest bundle path and query remain authoritative. When both the
|
|
231
232
|
discovery request and manifest target are loopback addresses, RNX keeps the
|
|
232
233
|
loopback host that answered discovery so an IPv6-only listener is not reopened
|
|
@@ -259,7 +260,7 @@ enforced network contract is in [`specs/rnx-privacy.md`](../../specs/rnx-privacy
|
|
|
259
260
|
|
|
260
261
|
To uninstall the machine daemon and cached runtimes, run
|
|
261
262
|
`rnx daemon uninstall`. It stops current and legacy launchd / systemd
|
|
262
|
-
services, removes daemon logs, and removes `~/.
|
|
263
|
+
services, removes daemon logs, and removes `~/.rnx/` (runtimes, profiles,
|
|
263
264
|
recordings, and lockfiles). It does not remove the optional
|
|
264
265
|
`/Applications/rnx.app` desktop bundle or macOS preference plist. To inspect
|
|
265
266
|
existing disk usage before uninstalling, run `rnx cleanup`; add `--apply`
|
|
@@ -366,7 +367,7 @@ uses about 267 MiB, so the browser remains the recommended first-run path and
|
|
|
366
367
|
Electron is an opt-in desktop upgrade. The notarized CLI install did not produce
|
|
367
368
|
a Gatekeeper prompt on a clean profile. A Mac that previously ran an unsigned
|
|
368
369
|
development Electron build against the same user-data directory may ask for
|
|
369
|
-
one-time Keychain approval. `
|
|
370
|
+
one-time Keychain approval. `RNX_NO_OPEN=1` keeps the server headless. The
|
|
370
371
|
Metro wrapper also has two independent non-window opt-ins.
|
|
371
372
|
`devServer` serves the RNX shell from the Metro process. `productionBundles`
|
|
372
373
|
lets explicitly marked production bundle requests use the RNX host
|
|
@@ -442,8 +443,8 @@ rnx debug snapshot before
|
|
|
442
443
|
# reproduce the transition
|
|
443
444
|
rnx debug snapshot after
|
|
444
445
|
rnx debug diff before after
|
|
445
|
-
rnx screenshot --with-frame --output /tmp/
|
|
446
|
-
rnx record --duration 5 --output /tmp/
|
|
446
|
+
rnx screenshot --with-frame --output /tmp/rnx-framed.png
|
|
447
|
+
rnx record --duration 5 --output /tmp/rnx-anim.mp4
|
|
447
448
|
```
|
|
448
449
|
|
|
449
450
|
`rnx screenshot --with-frame` composes the real rnx shell device chrome
|
|
@@ -486,7 +487,7 @@ compose:
|
|
|
486
487
|
```
|
|
487
488
|
|
|
488
489
|
```sh
|
|
489
|
-
rnx screenshot appstore --plan .
|
|
490
|
+
rnx screenshot appstore --plan .rnx/app-store.yaml
|
|
490
491
|
```
|
|
491
492
|
|
|
492
493
|
The plan runner can reuse a visible sim for capture (`--sim a9`), stop after
|
|
@@ -533,10 +534,10 @@ rnx's CDN origin (default `https://contrast.dev`, overridable in
|
|
|
533
534
|
them to the shared delivery machinery in `@contrast/runtime-delivery` — an
|
|
534
535
|
internal workspace package the CLI bundles, so a published install has it
|
|
535
536
|
inlined. That machinery fetches `runtimes/manifest.json` + the runtime tarball,
|
|
536
|
-
verifies its sha256, and unpacks it under `~/.
|
|
537
|
+
verifies its sha256, and unpacks it under `~/.rnx`:
|
|
537
538
|
|
|
538
539
|
```
|
|
539
|
-
~/.
|
|
540
|
+
~/.rnx/
|
|
540
541
|
├── runtimes/
|
|
541
542
|
│ ├── <active>/ unpacked engine assets (served at /__soot/)
|
|
542
543
|
│ └── <rollback>/ previous version for rollback
|
|
@@ -561,7 +562,7 @@ Per-repo configuration is optional. Every installed-runtime `rnx open`
|
|
|
561
562
|
serves its selected version from a version-specific localhost origin, so a
|
|
562
563
|
background activation cannot mix an already loaded shell with chunks from the
|
|
563
564
|
next runtime. Without config, each new open selects the active stable version.
|
|
564
|
-
When `
|
|
565
|
+
When `rnx.config.ts` sets `runtimeVersion`, `rnx open` installs that
|
|
565
566
|
version without changing the machine default. App config, native-linked fonts,
|
|
566
567
|
and splash assets all resolve from the project root advertised by the selected
|
|
567
568
|
development server. Bare Metro, which has no Expo manifest project root, uses
|
|
@@ -582,13 +583,15 @@ recordings.
|
|
|
582
583
|
|
|
583
584
|
## Development and building
|
|
584
585
|
|
|
585
|
-
This package is part of the Contrast monorepo. To build the
|
|
586
|
+
This package is part of the Contrast monorepo. To build the standalone executable
|
|
587
|
+
for the current platform:
|
|
586
588
|
|
|
587
589
|
```sh
|
|
588
|
-
bun run build:cli
|
|
590
|
+
bun run build:cli-binary
|
|
589
591
|
```
|
|
590
592
|
|
|
591
|
-
The output is `dist-cli/bin.js`
|
|
592
|
-
|
|
593
|
+
The output is `dist-bin/rnx-<platform>-<arch>`. `dist-cli/bin.js` remains a
|
|
594
|
+
repository build artifact for tests and internal tooling and is not published
|
|
595
|
+
as an npm executable. Library exports build to `dist-lib/` (consumed via the
|
|
593
596
|
`exports` map: `.`, `./vite`, `./metro`, `./sdk`, `./skills`, `./detox`, and the
|
|
594
597
|
host/agent helpers). `bun run pack:smoke` validates the publishable tarball.
|
package/cli/app-config.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { isValidRuntimeVersion } from '@contrast/runtime-delivery'
|
|
|
4
4
|
import { createJiti } from 'jiti'
|
|
5
5
|
import { rnxPublicBrand } from '../src/public-brand'
|
|
6
6
|
import { resolveAppProject, type ResolvedAppProject } from './app-project'
|
|
7
|
-
import type {
|
|
7
|
+
import type { RNXConfig } from '../src/config'
|
|
8
8
|
|
|
9
9
|
const require = createRequire(import.meta.url)
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ function isOptionalRecord(value: unknown): boolean {
|
|
|
15
15
|
)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function
|
|
18
|
+
function isRNXConfig(value: unknown): value is RNXConfig {
|
|
19
19
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return false
|
|
20
20
|
const runtimeVersion = Reflect.get(value, 'runtimeVersion')
|
|
21
21
|
const network = Reflect.get(value, 'network')
|
|
@@ -34,10 +34,7 @@ function isSootSimConfig(value: unknown): value is SootSimConfig {
|
|
|
34
34
|
)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function resolveConfigReplacementFiles(
|
|
38
|
-
config: SootSimConfig,
|
|
39
|
-
configPath: string,
|
|
40
|
-
): SootSimConfig {
|
|
37
|
+
function resolveConfigReplacementFiles(config: RNXConfig, configPath: string): RNXConfig {
|
|
41
38
|
if (!config.modules) return config
|
|
42
39
|
const configDir = path.dirname(configPath)
|
|
43
40
|
return {
|
|
@@ -53,9 +50,9 @@ function resolveConfigReplacementFiles(
|
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
52
|
|
|
56
|
-
export async function
|
|
53
|
+
export async function loadRNXAppConfig(
|
|
57
54
|
project: ResolvedAppProject | null,
|
|
58
|
-
): Promise<
|
|
55
|
+
): Promise<RNXConfig | undefined> {
|
|
59
56
|
if (!project?.configPath) return undefined
|
|
60
57
|
try {
|
|
61
58
|
const jiti = createJiti(import.meta.url, {
|
|
@@ -67,7 +64,7 @@ export async function loadSootSimAppConfig(
|
|
|
67
64
|
},
|
|
68
65
|
})
|
|
69
66
|
const loaded: unknown = await jiti.import(project.configPath, { default: true })
|
|
70
|
-
if (!
|
|
67
|
+
if (!isRNXConfig(loaded)) {
|
|
71
68
|
throw new Error('the default export must be an rnx config object')
|
|
72
69
|
}
|
|
73
70
|
return resolveConfigReplacementFiles(loaded, project.configPath)
|
|
@@ -77,9 +74,9 @@ export async function loadSootSimAppConfig(
|
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
export async function
|
|
77
|
+
export async function resolveRNXAppConfig(
|
|
81
78
|
startDir: string = process.cwd(),
|
|
82
|
-
): Promise<{ project: ResolvedAppProject | null; config:
|
|
79
|
+
): Promise<{ project: ResolvedAppProject | null; config: RNXConfig | undefined }> {
|
|
83
80
|
const project = resolveAppProject(startDir)
|
|
84
|
-
return { project, config: await
|
|
81
|
+
return { project, config: await loadRNXAppConfig(project) }
|
|
85
82
|
}
|
package/cli/app-fonts.ts
CHANGED
|
@@ -260,9 +260,9 @@ export function discoverNativeLinkedAppFonts(opts: {
|
|
|
260
260
|
|
|
261
261
|
// resolve a metro dev server's project root. expo serves a manifest at the
|
|
262
262
|
// server origin carrying `extra.expoClient._internal.projectRoot` — the absolute
|
|
263
|
-
// dir of the app being served. the local `
|
|
263
|
+
// dir of the app being served. the local `rnx open <port>` path runs from the
|
|
264
264
|
// CLI's cwd, which almost never owns the bundle being opened (e.g.
|
|
265
|
-
// `
|
|
265
|
+
// `rnx open 8081` run from ~/soot against a 3pc metro), so scanning cwd for
|
|
266
266
|
// font declarations finds nothing.
|
|
267
267
|
//
|
|
268
268
|
// a bare react-native packager serves no such manifest, so the same resolver
|
|
@@ -355,7 +355,7 @@ export type FetchedAppFont = {
|
|
|
355
355
|
// fetch every config-plugin font declared on an engine `?appFonts=` wire.
|
|
356
356
|
// these typefaces live in the native binary, never in the metro bundle's
|
|
357
357
|
// __packager_asset graph, so neither asset capture nor recorded fetches see
|
|
358
|
-
// them — both the preview (`
|
|
358
|
+
// them — both the preview (`rnx record upload`) and build (`rnx app-fonts
|
|
359
359
|
// stage`) paths backfill by re-fetching the declared urls off the still-live
|
|
360
360
|
// metro. one implementation so both pipelines store identical bytes + keys.
|
|
361
361
|
export async function fetchAppFontFiles(
|
package/cli/app-project.ts
CHANGED
|
@@ -9,11 +9,11 @@ export const EXPO_APP_CONFIG_NAMES = [
|
|
|
9
9
|
'app.json',
|
|
10
10
|
] as const
|
|
11
11
|
|
|
12
|
-
export const
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
12
|
+
export const RNX_APP_CONFIG_NAMES = [
|
|
13
|
+
'rnx.config.ts',
|
|
14
|
+
'rnx.config.js',
|
|
15
|
+
'rnx.config.mjs',
|
|
16
|
+
'rnx.config.cjs',
|
|
17
17
|
] as const
|
|
18
18
|
|
|
19
19
|
export interface ResolvedAppProject {
|
|
@@ -35,8 +35,8 @@ export function findExpoAppConfig(dir: string): string | null {
|
|
|
35
35
|
return firstNamedFile(dir, EXPO_APP_CONFIG_NAMES)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export function
|
|
39
|
-
return firstNamedFile(dir,
|
|
38
|
+
export function findRNXAppConfig(dir: string): string | null {
|
|
39
|
+
return firstNamedFile(dir, RNX_APP_CONFIG_NAMES)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function resolveAppProject(projectRoot: string): ResolvedAppProject | null {
|
|
@@ -47,7 +47,7 @@ export function resolveAppProject(projectRoot: string): ResolvedAppProject | nul
|
|
|
47
47
|
return null
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const configPath =
|
|
50
|
+
const configPath = findRNXAppConfig(appDir)
|
|
51
51
|
if (
|
|
52
52
|
!configPath &&
|
|
53
53
|
!findExpoAppConfig(appDir) &&
|
package/cli/auth.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
//
|
|
1
|
+
// rnx cli auth resolution for cloud-hitting commands.
|
|
2
2
|
//
|
|
3
3
|
// priority order (first match wins):
|
|
4
|
-
// 1. RNX_API_KEY
|
|
4
|
+
// 1. RNX_API_KEY — ci path
|
|
5
5
|
// 2. CONTRAST_INSTALLATION_TOKEN/GITHUB_TOKEN + repo env — github action
|
|
6
6
|
// preview uploads from the Contrast runner, no extra secret
|
|
7
7
|
// 3. desktop session token from shared desktop auth (`rnx login`)
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { readSharedDesktopAuthSession } from '../src/auth/shared-session'
|
|
12
12
|
import { rnxExit } from './run-rnx'
|
|
13
13
|
|
|
14
|
-
export type CliApiKeyEnvName = 'RNX_API_KEY'
|
|
14
|
+
export type CliApiKeyEnvName = 'RNX_API_KEY'
|
|
15
15
|
|
|
16
16
|
export type CliAuth =
|
|
17
17
|
| { kind: 'api-key'; secret: string; source: 'env'; envName: CliApiKeyEnvName }
|
|
@@ -93,15 +93,13 @@ function resolveGitHubActionsAuth(): CliAuth | null {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function isCliApiKeySecret(secret: string): boolean {
|
|
96
|
-
return secret.startsWith('sk_rnx_')
|
|
96
|
+
return secret.startsWith('sk_rnx_')
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function readApiKeyFromEnv(): { secret: string; envName: CliApiKeyEnvName } | null {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
return null
|
|
100
|
+
const envName = 'RNX_API_KEY'
|
|
101
|
+
const secret = process.env[envName]?.trim()
|
|
102
|
+
return secret && isCliApiKeySecret(secret) ? { secret, envName } : null
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
export function resolveCliAuth(): CliAuth | null {
|
package/cli/bin.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { rnxPublicBrand } from '../src/public-brand'
|
|
10
10
|
import { parseArgs, TOP_LEVEL_RUNTIME_COMMANDS } from './parse-args'
|
|
11
11
|
import { RnxExit } from './run-rnx'
|
|
12
|
+
import { IS_STANDALONE } from './standalone'
|
|
12
13
|
|
|
13
14
|
// `./help` is loaded lazily (only on help paths) — it statically pulls the full
|
|
14
15
|
// CLI registry renderers and engine settings, which would otherwise add ~400ms
|
|
@@ -54,28 +55,8 @@ function handleTopLevelError(err: unknown): never {
|
|
|
54
55
|
process.on('unhandledRejection', handleTopLevelError)
|
|
55
56
|
process.on('uncaughtException', handleTopLevelError)
|
|
56
57
|
|
|
57
|
-
// set to `true` by build-cli-binary.ts via esbuild define. in the standalone
|
|
58
|
-
// binary, commands that rely on vite / electron / playwright from the user's
|
|
59
|
-
// node_modules can't run — gate them with a friendly message rather than
|
|
60
|
-
// letting the dynamic import fail with a confusing module-not-found error.
|
|
61
|
-
declare const __SOOTSIM_STANDALONE__: boolean | undefined
|
|
62
|
-
const IS_STANDALONE =
|
|
63
|
-
typeof __SOOTSIM_STANDALONE__ !== 'undefined' && __SOOTSIM_STANDALONE__
|
|
64
|
-
|
|
65
|
-
const STANDALONE_BLOCKED_COMMANDS = new Set(['desktop'])
|
|
66
|
-
|
|
67
|
-
function exitIfStandaloneBlocked(cmd: string): void {
|
|
68
|
-
if (!IS_STANDALONE || !STANDALONE_BLOCKED_COMMANDS.has(cmd)) return
|
|
69
|
-
process.stderr.write(
|
|
70
|
-
` ${rnxPublicBrand.commandName} ${cmd} isn't available in the standalone binary —\n` +
|
|
71
|
-
` it needs vite / electron / playwright from a project's node_modules.\n` +
|
|
72
|
-
` run the npm package instead:\n` +
|
|
73
|
-
` ${rnxPublicBrand.commandName} ${cmd}\n`,
|
|
74
|
-
)
|
|
75
|
-
process.exit(1)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
58
|
let parsed = parseArgs(process.argv)
|
|
59
|
+
for (const warning of parsed.warnings) process.stderr.write(`${warning}\n`)
|
|
79
60
|
|
|
80
61
|
// runtime actions and reads also work as hidden root aliases. resolve only
|
|
81
62
|
// after the normal parser declined the token, so a real top-level command
|
|
@@ -90,6 +71,8 @@ const isAutomaticCleanupWorker =
|
|
|
90
71
|
parsed.commandArgs.length === 1 &&
|
|
91
72
|
parsed.commandArgs[0] === '--automatic-worker'
|
|
92
73
|
const isBareWelcome = !parsed.command && parsed.commandArgs.length === 0
|
|
74
|
+
const isReadOnlyInvocation =
|
|
75
|
+
parsed.version || parsed.help || parsed.commandArgs.includes('--dry-run')
|
|
93
76
|
|
|
94
77
|
if (
|
|
95
78
|
!isAutomaticCleanupWorker &&
|
|
@@ -109,7 +92,7 @@ if (
|
|
|
109
92
|
// interactive command runs next prints it once (stderr, so --json stdout
|
|
110
93
|
// stays parseable) and deletes it. the daemon/serve processes skip it so a
|
|
111
94
|
// background process can't eat the notice before a human sees it.
|
|
112
|
-
if (parsed.command !== 'serve' && parsed.command !== 'daemon') {
|
|
95
|
+
if (!isReadOnlyInvocation && parsed.command !== 'serve' && parsed.command !== 'daemon') {
|
|
113
96
|
const { consumeRuntimeUpgradeNotice } = await import('../src/home-paths')
|
|
114
97
|
const notice = consumeRuntimeUpgradeNotice()
|
|
115
98
|
if (notice) {
|
|
@@ -126,6 +109,7 @@ async function scheduleAutomaticCleanup(): Promise<void> {
|
|
|
126
109
|
if (automaticCleanupFinished) return
|
|
127
110
|
automaticCleanupFinished = true
|
|
128
111
|
if (
|
|
112
|
+
isReadOnlyInvocation ||
|
|
129
113
|
parsed.command === 'cleanup' ||
|
|
130
114
|
parsed.command === 'serve' ||
|
|
131
115
|
parsed.command === 'agent-wrapper' ||
|
|
@@ -193,7 +177,7 @@ if (parsed.version) {
|
|
|
193
177
|
console.log(`${rnxPublicBrand.commandName} v${getCliVersion()}${suffix}`)
|
|
194
178
|
// runtime version on its own line — keeps the first line parseable while
|
|
195
179
|
// surfacing the (independently-versioned) engine runtime users actually
|
|
196
|
-
// render with. see `
|
|
180
|
+
// render with. see `rnx upgrade`.
|
|
197
181
|
const { readActiveRuntime } = await import('../src/home-paths')
|
|
198
182
|
const runtime = readActiveRuntime()
|
|
199
183
|
console.log(runtime ? `runtime v${runtime}` : 'runtime not installed')
|
|
@@ -281,8 +265,8 @@ if (
|
|
|
281
265
|
await exitWithFlush(await runReset(commandArgsWithSim, { port }))
|
|
282
266
|
}
|
|
283
267
|
// for grouping verbs, try to resolve per-verb help from the first
|
|
284
|
-
// positional arg. e.g. `
|
|
285
|
-
// not the generic `do` grouping page. bare `
|
|
268
|
+
// positional arg. e.g. `rnx do tap --help` shows tap's help page,
|
|
269
|
+
// not the generic `do` grouping page. bare `rnx do --help` falls
|
|
286
270
|
// through to runInspect which has the full verb group listing.
|
|
287
271
|
const isGroupingVerb =
|
|
288
272
|
command === 'do' ||
|
|
@@ -312,12 +296,6 @@ if (
|
|
|
312
296
|
}
|
|
313
297
|
}
|
|
314
298
|
|
|
315
|
-
// gate heavy commands in the standalone binary before any dynamic imports
|
|
316
|
-
// fire. the imports themselves would also fail (vite / electron etc. are
|
|
317
|
-
// kept external from the bundle), but the resulting module-not-found error
|
|
318
|
-
// is much harder to act on than this targeted message.
|
|
319
|
-
exitIfStandaloneBlocked(command)
|
|
320
|
-
|
|
321
299
|
// the command modules stop by throwing RnxExit rather than ending the
|
|
322
300
|
// process, because the same command has to run in a box shell and in
|
|
323
301
|
// workerd, where process.exit() cancels the whole request. this is the
|
|
@@ -453,6 +431,13 @@ try {
|
|
|
453
431
|
await exitWithFlush(typeof code === 'number' ? code : 0)
|
|
454
432
|
}
|
|
455
433
|
|
|
434
|
+
case 'web': {
|
|
435
|
+
const { getRnxCommandAvailability } = await import('./command-registry')
|
|
436
|
+
const availability = getRnxCommandAvailability('web', parsed.commandArgs, 'node')
|
|
437
|
+
console.error(` ${availability.reason ?? 'rnx web is unavailable'}`)
|
|
438
|
+
await exitWithFlush(1)
|
|
439
|
+
}
|
|
440
|
+
|
|
456
441
|
case 'box': {
|
|
457
442
|
const { runBox } = await import('./commands/box')
|
|
458
443
|
await exitWithFlush(await runBox(commandArgsWithSim, { port, verbose }))
|
|
@@ -432,7 +432,7 @@ export class SootSimBridgeFlowRunner {
|
|
|
432
432
|
screenshotPathMode?: FlowScreenshotPathMode
|
|
433
433
|
// flow-wide default for screenshot layers — applied to every
|
|
434
434
|
// takeScreenshot step unless that step has its own `layers:`. set by
|
|
435
|
-
// `
|
|
435
|
+
// `rnx maestro test --no-shell` to produce clean tenant-only captures
|
|
436
436
|
// (useful when a stuck shell overlay would otherwise pollute the
|
|
437
437
|
// demo asset set).
|
|
438
438
|
screenshotLayers?: 'full' | 'tenant' | 'shell'
|
|
@@ -688,7 +688,7 @@ export class SootSimBridgeFlowRunner {
|
|
|
688
688
|
const extension = videoMime.includes('mp4') ? 'mp4' : 'webm'
|
|
689
689
|
const outputPath = path.join(
|
|
690
690
|
this.opts.recordingOutputDir,
|
|
691
|
-
`
|
|
691
|
+
`rnx-${Date.now()}.${extension}`,
|
|
692
692
|
)
|
|
693
693
|
fs.writeFileSync(outputPath, Buffer.concat(chunks))
|
|
694
694
|
return outputPath
|
|
@@ -1573,7 +1573,7 @@ export class SootSimBridgeFlowRunner {
|
|
|
1573
1573
|
if (typeof tree === 'string') write('tree.txt', tree)
|
|
1574
1574
|
|
|
1575
1575
|
// 6. console buffer + failed requests (captured by sootsim's native-globals
|
|
1576
|
-
// hook / request recorder; same shape as `
|
|
1576
|
+
// hook / request recorder; same shape as `rnx get errors` etc.).
|
|
1577
1577
|
const consoleBuf = await safeEval<{
|
|
1578
1578
|
errors: unknown[]
|
|
1579
1579
|
warnings: unknown[]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RnxBrowserOperations,
|
|
3
|
+
RnxCommandBackend,
|
|
4
|
+
RnxCommandInvocation,
|
|
5
|
+
RnxExecutionContext,
|
|
6
|
+
} from './command-contract'
|
|
7
|
+
|
|
8
|
+
export function createRnxBrowserBackend(
|
|
9
|
+
operations: RnxBrowserOperations,
|
|
10
|
+
): RnxCommandBackend {
|
|
11
|
+
return {
|
|
12
|
+
kind: 'browser',
|
|
13
|
+
execute(invocation: RnxCommandInvocation, context: RnxExecutionContext) {
|
|
14
|
+
switch (invocation.family) {
|
|
15
|
+
case 'preview':
|
|
16
|
+
return operations.selectPreview(invocation, context)
|
|
17
|
+
case 'runtime':
|
|
18
|
+
return operations.readRuntime(invocation, context)
|
|
19
|
+
case 'tree':
|
|
20
|
+
return operations.inspectTree(invocation, context)
|
|
21
|
+
case 'layout':
|
|
22
|
+
return operations.inspectLayout(invocation, context)
|
|
23
|
+
case 'find':
|
|
24
|
+
return operations.find(invocation, context)
|
|
25
|
+
case 'wait':
|
|
26
|
+
return operations.wait(invocation, context)
|
|
27
|
+
case 'action':
|
|
28
|
+
return operations.act(invocation, context)
|
|
29
|
+
case 'screenshot':
|
|
30
|
+
return operations.screenshot(invocation, context)
|
|
31
|
+
case 'logs':
|
|
32
|
+
return operations.readLogs(invocation, context)
|
|
33
|
+
case 'network':
|
|
34
|
+
return operations.readNetwork(invocation, context)
|
|
35
|
+
case 'storage':
|
|
36
|
+
return operations.accessStorage(invocation, context)
|
|
37
|
+
case 'history':
|
|
38
|
+
return operations.readHistory(invocation, context)
|
|
39
|
+
case 'evidence':
|
|
40
|
+
return operations.collectEvidence(invocation, context)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|