peachsim 0.1.527
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/LICENSE +22 -0
- package/README.md +640 -0
- package/cli/app-config.ts +82 -0
- package/cli/app-fonts.ts +388 -0
- package/cli/app-project.ts +59 -0
- package/cli/app-splash.ts +171 -0
- package/cli/app-state-reset.ts +26 -0
- package/cli/auth.ts +184 -0
- package/cli/bin.ts +59 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2806 -0
- package/cli/browser-backend.ts +44 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/cli-update.ts +261 -0
- package/cli/cloud-client.ts +1530 -0
- package/cli/cloud-dispatch.ts +206 -0
- package/cli/cloud-session.ts +227 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +304 -0
- package/cli/commands/agent-wrapper.ts +1048 -0
- package/cli/commands/agent.ts +439 -0
- package/cli/commands/app-fonts.ts +99 -0
- package/cli/commands/assert.ts +542 -0
- package/cli/commands/auth.ts +71 -0
- package/cli/commands/box/bundle-plane.ts +71 -0
- package/cli/commands/box/checkout-plane.ts +256 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +60 -0
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +925 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +176 -0
- package/cli/commands/config.ts +34 -0
- package/cli/commands/control.ts +2154 -0
- package/cli/commands/cpu-profile.ts +941 -0
- package/cli/commands/daemon-mac-app.ts +165 -0
- package/cli/commands/daemon.ts +800 -0
- package/cli/commands/debug.ts +751 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +201 -0
- package/cli/commands/detox.ts +481 -0
- package/cli/commands/device.ts +134 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/do-chain.ts +408 -0
- package/cli/commands/electron.ts +94 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1240 -0
- package/cli/commands/inspect/actions.ts +516 -0
- package/cli/commands/inspect/core.ts +2086 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +119 -0
- package/cli/commands/inspect/env.ts +25 -0
- package/cli/commands/inspect/find.ts +169 -0
- package/cli/commands/inspect/get-layout.ts +53 -0
- package/cli/commands/inspect/keyboard.ts +54 -0
- package/cli/commands/inspect/list.ts +175 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +77 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +32 -0
- package/cli/commands/inspect/settling.ts +197 -0
- package/cli/commands/inspect/shared.ts +259 -0
- package/cli/commands/inspect/sleep.ts +15 -0
- package/cli/commands/inspect/tree.ts +23 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +211 -0
- package/cli/commands/inspect/wait-idle.ts +25 -0
- package/cli/commands/inspect/wait-ready.ts +87 -0
- package/cli/commands/inspect/wait-selector.ts +59 -0
- package/cli/commands/inspect/wait.ts +32 -0
- package/cli/commands/inspect.ts +4738 -0
- package/cli/commands/install-cli.ts +275 -0
- package/cli/commands/install-desktop.ts +385 -0
- package/cli/commands/login.ts +357 -0
- package/cli/commands/logout.ts +24 -0
- package/cli/commands/maestro-generate.ts +375 -0
- package/cli/commands/maestro.ts +536 -0
- package/cli/commands/mode.ts +58 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +67 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/platform.ts +410 -0
- package/cli/commands/preview.ts +103 -0
- package/cli/commands/profile.ts +106 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1435 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +89 -0
- package/cli/commands/runtime.ts +348 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +144 -0
- package/cli/commands/screenshot-mode.ts +38 -0
- package/cli/commands/screenshot.ts +492 -0
- package/cli/commands/screenshots-capture.ts +608 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +139 -0
- package/cli/commands/setup.ts +416 -0
- package/cli/commands/shell-boolean-mode.ts +82 -0
- package/cli/commands/skills.ts +468 -0
- package/cli/commands/slides.ts +357 -0
- package/cli/commands/state.ts +94 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +55 -0
- package/cli/commands/test.ts +535 -0
- package/cli/commands/three-mode.ts +771 -0
- package/cli/commands/timeline.ts +121 -0
- package/cli/commands/upgrade.ts +167 -0
- package/cli/commands/upload.ts +1203 -0
- package/cli/commands/version.ts +63 -0
- package/cli/commands/welcome.ts +17 -0
- package/cli/commands/what-happened.ts +328 -0
- package/cli/current-sim.ts +217 -0
- package/cli/desktop-companion.ts +315 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +184 -0
- package/cli/drivers/playwright-sim-host.ts +537 -0
- package/cli/drivers/playwright.ts +209 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-export.ts +55 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +126 -0
- package/cli/flow-session.ts +140 -0
- package/cli/help-core.ts +143 -0
- package/cli/help.ts +44 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +214 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/internal-child.ts +176 -0
- package/cli/maestro-js.ts +323 -0
- package/cli/main.ts +704 -0
- package/cli/open-url.ts +8 -0
- package/cli/outbound-endpoints.ts +830 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +189 -0
- package/cli/privacy.ts +53 -0
- package/cli/prompt.ts +56 -0
- package/cli/recording-access.ts +108 -0
- package/cli/registry.ts +2 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/rnx-in-process.ts +98 -0
- package/cli/run-registry.ts +226 -0
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +137 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/secure-file.ts +31 -0
- package/cli/self-invocation.ts +58 -0
- package/cli/send-to-box.ts +109 -0
- package/cli/setup-repository.ts +191 -0
- package/cli/shell-init.ts +98 -0
- package/cli/standalone.ts +4 -0
- package/cli/telemetry.ts +84 -0
- package/cli/ui.ts +68 -0
- package/cli/ws-bridge.ts +1020 -0
- package/detox/attempt-events.cjs +23 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +48 -0
- package/detox/expectations.ts +534 -0
- package/detox/gestures.ts +501 -0
- package/detox/index.ts +2694 -0
- package/detox/jest-preset.cjs +29 -0
- package/detox/jest-setup-after-env.cjs +22 -0
- package/detox/matchers.ts +30 -0
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/detox/navigation-lifecycle.ts +290 -0
- package/detox/navigation.ts +43 -0
- package/detox/proof-frame.cjs +114 -0
- package/detox/record-block-execution.cjs +78 -0
- package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
- package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
- package/detox/screenshots/color-test-rest-norngh.png +0 -0
- package/detox/screenshots/theme-blue-toggle.png +0 -0
- package/detox/screenshots/theme-blue.png +0 -0
- package/detox/screenshots/theme-red-toggle.png +0 -0
- package/detox/screenshots/theme-red.png +0 -0
- package/dist-lib/agent-daemon-client.cjs +502 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +759 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +208 -0
- package/dist-lib/backend-origin.cjs +88 -0
- package/dist-lib/beta.cjs +41 -0
- package/dist-lib/beta.mjs +13 -0
- package/dist-lib/bridge-constants.cjs +161 -0
- package/dist-lib/bridge-contract-input.cjs +451 -0
- package/dist-lib/bridge-contract-input.mjs +414 -0
- package/dist-lib/bridge-contract.cjs +130 -0
- package/dist-lib/bridge-contract.mjs +94 -0
- package/dist-lib/capture-contract.cjs +220 -0
- package/dist-lib/capture-contract.mjs +190 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/cloud-contract.cjs +194 -0
- package/dist-lib/cloud-contract.mjs +145 -0
- package/dist-lib/cloud.cjs +670 -0
- package/dist-lib/cloud.mjs +639 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +3789 -0
- package/dist-lib/detox/jest-preset.cjs +29 -0
- package/dist-lib/dev-bundle-resolution.cjs +290 -0
- package/dist-lib/home-paths.cjs +638 -0
- package/dist-lib/host/bridge-host.cjs +10903 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +421 -0
- package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
- package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
- package/dist-lib/host/replacement-module-handler.cjs +469 -0
- package/dist-lib/host/websocket-proxy.cjs +298 -0
- package/dist-lib/index.cjs +4268 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/jump-to-source-native.cjs +112 -0
- package/dist-lib/menu.cjs +646 -0
- package/dist-lib/menu.mjs +604 -0
- package/dist-lib/metro-fingerprint-registry.cjs +186 -0
- package/dist-lib/metro-fingerprint-registry.mjs +156 -0
- package/dist-lib/metro-production-bundle.cjs +329 -0
- package/dist-lib/metro-production-bundle.mjs +295 -0
- package/dist-lib/metro.cjs +904 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/react-native-host-modules.cjs +51 -0
- package/dist-lib/react-native-host-modules.mjs +25 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1232 -0
- package/dist-lib/sdk.cjs +2433 -0
- package/dist-lib/sdk.mjs +2336 -0
- package/dist-lib/skills.cjs +39132 -0
- package/dist-lib/swift-submit.cjs +92 -0
- package/dist-lib/swift-submit.mjs +65 -0
- package/dist-lib/swift.cjs +1646 -0
- package/dist-lib/vite.cjs +1591 -0
- package/package.json +290 -0
- package/scripts/dev-server-scanner.ts +1291 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/skills/contrast/SKILL.md +165 -0
- package/skills/rnx-debug/SKILL.md +433 -0
- package/skills/rnx-perf/SKILL.md +399 -0
- package/skills/rnx-setup/SKILL.md +172 -0
- package/skills/rnx-test/SKILL.md +321 -0
- package/skills/rnx-visual/SKILL.md +126 -0
- package/src/agent-daemon-client.ts +410 -0
- package/src/agent-events.ts +71 -0
- package/src/agent-identity.ts +23 -0
- package/src/agent-prompt.ts +71 -0
- package/src/agent-sessions.ts +580 -0
- package/src/app-url.ts +39 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +235 -0
- package/src/backend-origin.ts +70 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +175 -0
- package/src/bridge-contract-input.ts +502 -0
- package/src/bridge-contract.ts +558 -0
- package/src/browser-cache.ts +16 -0
- package/src/capture-contract.ts +587 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +40 -0
- package/src/cloud-contract.ts +274 -0
- package/src/cloud.ts +762 -0
- package/src/codex-client.ts +234 -0
- package/src/config.ts +132 -0
- package/src/connect.ts +101 -0
- package/src/dev-bundle-resolution.ts +346 -0
- package/src/dev-server-open.ts +198 -0
- package/src/disk-cleanup.ts +540 -0
- package/src/flow-timeout-scale.ts +15 -0
- package/src/home-paths.ts +806 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2788 -0
- package/src/host/fetch-proxy-handler.ts +449 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/plane-host.ts +203 -0
- package/src/host/replacement-module-handler.ts +158 -0
- package/src/host/websocket-proxy.ts +315 -0
- package/src/index.ts +71 -0
- package/src/jump-to-source-babel.ts +135 -0
- package/src/jump-to-source-native.ts +102 -0
- package/src/menu.ts +777 -0
- package/src/metro-fingerprint-registry.ts +302 -0
- package/src/metro-plugin.ts +341 -0
- package/src/metro-production-bundle.ts +471 -0
- package/src/native-dev-bundle-url.ts +118 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/playwright-host-log.ts +16 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +123 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/react-native-host-modules.ts +26 -0
- package/src/render-mode.ts +27 -0
- package/src/rolldown-plugin-swift.ts +240 -0
- package/src/runtime-assets.ts +233 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +514 -0
- package/src/screenshots/orchestrate.ts +256 -0
- package/src/screenshots/org-deck.ts +91 -0
- package/src/screenshots/registry.ts +58 -0
- package/src/screenshots/schema.ts +364 -0
- package/src/sdk.ts +15 -0
- package/src/settings-bundle.ts +418 -0
- package/src/shell-bridge-identity.ts +15 -0
- package/src/sim-client.ts +697 -0
- package/src/skills/builtin/a11y-review.ts +132 -0
- package/src/skills/builtin/compat-check.ts +71 -0
- package/src/skills/builtin/maestro-test.ts +121 -0
- package/src/skills/builtin/perf-profile.ts +90 -0
- package/src/skills/builtin/screenshot-all.ts +52 -0
- package/src/skills/builtin/visual-diff.ts +100 -0
- package/src/skills/registry.ts +107 -0
- package/src/skills/types.ts +41 -0
- package/src/swift-submit.ts +185 -0
- package/src/swift.ts +7 -0
- package/src/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +264 -0
- package/src/vite-plugin-swift.ts +620 -0
- package/src/vite-plugin.ts +1946 -0
- package/src/worklets-babel.ts +250 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Proprietary Software License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Tamagui LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This package (rnxsim) is proprietary software of Tamagui LLC, licensed under
|
|
6
|
+
the rnx Software License Agreement: https://rnxsim.com/legal/license
|
|
7
|
+
|
|
8
|
+
In summary (the agreement governs): personal, non-commercial use is free;
|
|
9
|
+
commercial use requires an active Pro subscription after a single 30-day
|
|
10
|
+
evaluation period; embedding or redistributing the software requires a
|
|
11
|
+
separate written agreement with Tamagui LLC.
|
|
12
|
+
|
|
13
|
+
Versions of this package published before this license change remain under
|
|
14
|
+
the license they were published with.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
# rnx
|
|
2
|
+
|
|
3
|
+
The source owner for the standalone `rnx` executable and the public `rnxsim`
|
|
4
|
+
integration library used to drive a browser-native React Native simulator.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
The CLI and library are separate public artifacts. The recommended installer
|
|
9
|
+
downloads one Bun-compiled `rnx` executable that needs no Node.js, npm, or Bun
|
|
10
|
+
installation. The `rnxsim` npm package contains bundler plugins, testing
|
|
11
|
+
drivers, and library exports, with no command-line binary.
|
|
12
|
+
|
|
13
|
+
The executable updates itself with `rnx upgrade`. Successful interactive human
|
|
14
|
+
commands refresh a cached stable CLI version in a detached process at most once
|
|
15
|
+
every 20 hours. A newer version produces one short notice on stderr, once per
|
|
16
|
+
version and no more than weekly. CI, agents, JSON output, pipes, and
|
|
17
|
+
noninteractive commands stay silent. Set `RNX_UPDATE_CHECK=off` to disable the
|
|
18
|
+
check and notice; `rnx version` checks explicitly, while `rnx --version` remains
|
|
19
|
+
offline.
|
|
20
|
+
|
|
21
|
+
Neither artifact contains rendering code. The canvas engine (CanvasKit
|
|
22
|
+
renderer, Yoga layout, iOS/Android shell chrome, Electron shell) lives in the
|
|
23
|
+
private `sootsim-engine` workspace package and is shipped at runtime as a
|
|
24
|
+
versioned tarball, fetched from the contrast.dev CDN and unpacked into `~/.rnx`.
|
|
25
|
+
|
|
26
|
+
What this workspace gives you:
|
|
27
|
+
|
|
28
|
+
- the standalone `rnx` CLI source and binary build, which provides the primary
|
|
29
|
+
debugging and automation surface (inspect the UI tree, tap elements, capture
|
|
30
|
+
flows, screenshot, record, run agents)
|
|
31
|
+
- `rnxsim/vite` and `rnxsim/metro` — bundler plugins that serve the installed
|
|
32
|
+
engine runtime from your own dev server
|
|
33
|
+
- `rnxsim/jump-to-source-babel` — an optional Babel plugin that annotates JSX
|
|
34
|
+
with source locations so inspect mode can open the selected element in your
|
|
35
|
+
editor
|
|
36
|
+
- `rnxsim/detox` — a drop-in Detox driver + jest preset
|
|
37
|
+
- `rnxsim/sdk` — the inspect/interact verbs as a programmatic API
|
|
38
|
+
- `rnxsim/bridge-contract-input` — parsers turning untrusted JSON into
|
|
39
|
+
bridge-contract arguments
|
|
40
|
+
- `rnxsim/skills` — a registry of Contrast-flavored automation skills
|
|
41
|
+
|
|
42
|
+
Platform status: iOS is the parity baseline. Android is bootstrapped and usable
|
|
43
|
+
for focused conformance slices (bundle/runtime identity, device profiles, shell
|
|
44
|
+
chrome, gesture + three-button nav, system UI/window metrics with cutout-safe
|
|
45
|
+
insets) but is not full parity until the Android launch gates in the Contrast
|
|
46
|
+
repo plan pass.
|
|
47
|
+
|
|
48
|
+
## What's in each distribution
|
|
49
|
+
|
|
50
|
+
| standalone `rnx` executable | `rnxsim` npm package | private engine runtime |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| CLI commands and bridge client | Vite and Metro plugins | CanvasKit renderer and Yoga layout |
|
|
53
|
+
| bridge daemon host | SDK and bridge contracts | iOS/Android shell chrome, home grid, app switcher |
|
|
54
|
+
| runtime, browser, and desktop launchers | Detox driver and Jest preset | Electron shell and wasm |
|
|
55
|
+
| Maestro, screenshots, recording, skills | native-resolution helpers and skills registry | the actual pixels |
|
|
56
|
+
|
|
57
|
+
The engine is delivered at runtime, never bundled into this package. A
|
|
58
|
+
committed-but-unbuilt engine fix has no effect on a running sim until the
|
|
59
|
+
runtime tarball is rebuilt and re-fetched.
|
|
60
|
+
|
|
61
|
+
## Architecture
|
|
62
|
+
|
|
63
|
+
The architecture is a **three-tier relay**: a short-lived CLI process, a single
|
|
64
|
+
persistent bridge daemon, and the sim itself — a browser/Electron *page* that
|
|
65
|
+
internally splits into shell, compositor, and tenant workers.
|
|
66
|
+
|
|
67
|
+
```mermaid
|
|
68
|
+
graph TD
|
|
69
|
+
subgraph cli["rnx CLI process (short-lived, cli/)"]
|
|
70
|
+
BIN["bin.ts (dispatcher + privacy choice)"]
|
|
71
|
+
SETUP["commands/setup.ts (guided daemon setup)"]
|
|
72
|
+
RUNTIMECMD["commands/runtime.ts (runtime install/use)"]
|
|
73
|
+
INSPECT["commands/inspect/* (describe/find/do/get/wait)"]
|
|
74
|
+
FLOW["bridge-flow-runner.ts (Maestro YAML)"]
|
|
75
|
+
DETOXCMD["commands/detox.ts + detox/ driver"]
|
|
76
|
+
SHOTS["commands/screenshot + record"]
|
|
77
|
+
AGENTCMD["commands/agent.ts"]
|
|
78
|
+
WSB["ws-bridge.ts (WsBridge client)"]
|
|
79
|
+
DRIVERS["drivers/* (chromium/electron/playwright/system)"]
|
|
80
|
+
end
|
|
81
|
+
subgraph daemon["bridge daemon process (persistent :7668)"]
|
|
82
|
+
HOST["SootSimBridgeHost (host/bridge-host.ts, HTTP+WS)"]
|
|
83
|
+
AGENTHOST["AgentHost (host/agent-host.ts, FIFO fan-out)"]
|
|
84
|
+
AGENTSESS["agent-sessions.ts + attached-projects.ts"]
|
|
85
|
+
SCAN["/__server-scan (dev-server-scanner.ts)"]
|
|
86
|
+
PROXY["fetch-proxy-handler + websocket-proxy"]
|
|
87
|
+
RTHTTP["runtime HTTP + self-update (runtime-delivery.ts)"]
|
|
88
|
+
end
|
|
89
|
+
subgraph sim["sim page (browser / Electron, launched by a driver)"]
|
|
90
|
+
SHELLW["shell worker (iOS chrome, home grid, app switcher)"]
|
|
91
|
+
COMPOSITORW["compositor worker (app canvases + independent rAF)"]
|
|
92
|
+
TENANTW["tenant worker (guest RN app tree)"]
|
|
93
|
+
end
|
|
94
|
+
subgraph build["build-time plugins (src/)"]
|
|
95
|
+
VITEONE["rnxsim/vite = vite-plugin-one.ts (serve runtime at /__soot/)"]
|
|
96
|
+
VITERN["sootsim() = vite-plugin.ts (RN resolver + native stubs)"]
|
|
97
|
+
METRO["rnxsim/metro = metro-plugin.ts"]
|
|
98
|
+
COMPAT["@sootsim/compat stub-manifest (native seams)"]
|
|
99
|
+
ENGINESHIM["sootsim-engine react-native shim"]
|
|
100
|
+
end
|
|
101
|
+
SKILLS["rnxsim/skills registry.ts (builtin skills)"]
|
|
102
|
+
subgraph fs["~/.rnx (home-paths.ts)"]
|
|
103
|
+
RTDIR["runtimes/<version>/ (engine assets)"]
|
|
104
|
+
LOCK["daemon.json lockfile"]
|
|
105
|
+
CFG["config.json"]
|
|
106
|
+
end
|
|
107
|
+
CDN["contrast.dev CDN (runtimes/manifest.json + tarballs)"]
|
|
108
|
+
BIN --> SETUP
|
|
109
|
+
BIN --> RUNTIMECMD
|
|
110
|
+
BIN --> INSPECT
|
|
111
|
+
BIN --> FLOW
|
|
112
|
+
BIN --> DETOXCMD
|
|
113
|
+
BIN --> SHOTS
|
|
114
|
+
BIN --> AGENTCMD
|
|
115
|
+
SETUP --> LOCK
|
|
116
|
+
SETUP -->|"register launchd/systemd"| HOST
|
|
117
|
+
RUNTIMECMD --> RTDIR
|
|
118
|
+
RUNTIMECMD -->|"fetch runtime"| CDN
|
|
119
|
+
INSPECT --> WSB
|
|
120
|
+
FLOW --> WSB
|
|
121
|
+
SHOTS --> WSB
|
|
122
|
+
AGENTCMD --> WSB
|
|
123
|
+
DETOXCMD --> DRIVERS
|
|
124
|
+
DETOXCMD --> WSB
|
|
125
|
+
WSB -->|"JSON WS cmds"| HOST
|
|
126
|
+
HOST -->|"forward to registered sim"| SHELLW
|
|
127
|
+
SHELLW -->|"replies + pushes"| HOST
|
|
128
|
+
HOST -->|"relayed results"| WSB
|
|
129
|
+
HOST --> AGENTHOST
|
|
130
|
+
AGENTHOST --> AGENTSESS
|
|
131
|
+
AGENTCMD --> AGENTHOST
|
|
132
|
+
HOST --> SCAN
|
|
133
|
+
HOST --> PROXY
|
|
134
|
+
HOST --> RTHTTP
|
|
135
|
+
RTHTTP --> RTDIR
|
|
136
|
+
RTHTTP -->|"manifest + tarball"| CDN
|
|
137
|
+
DRIVERS -->|"open sim page URL"| SHELLW
|
|
138
|
+
SHELLW -->|"NativeUIRequest"| TENANTW
|
|
139
|
+
VITEONE -->|"serve /__soot/ from"| RTDIR
|
|
140
|
+
METRO -->|"serve /__soot/ from"| RTDIR
|
|
141
|
+
VITEONE -.->|"launch electron app"| SHELLW
|
|
142
|
+
VITERN -->|"alias react-native"| ENGINESHIM
|
|
143
|
+
VITERN -->|"alias native pkgs"| COMPAT
|
|
144
|
+
VITERN -->|"dev server hosts"| HOST
|
|
145
|
+
SKILLS --> INSPECT
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**The CLI process** (`cli/bin.ts` routes, `cli/main.ts` parses argv) lazy-imports
|
|
149
|
+
exactly one command module per run. Bare `rnx` opens ConnectRN, whose simulator UI discovers
|
|
150
|
+
running React Native development servers. The first human run offers the
|
|
151
|
+
recommended background service and optional Desktop app, then opens the simulator
|
|
152
|
+
before asking about private diagnostics or an optional repository install. `rnx open`
|
|
153
|
+
ensures the engine runtime exists and starts a local foreground bridge when no
|
|
154
|
+
daemon is reachable, then opens a `WsBridge` (`cli/ws-bridge.ts`) on **port
|
|
155
|
+
7668** and sends JSON commands. Inspection/interaction verbs live in
|
|
156
|
+
`cli/commands/inspect/*` and are re-exported as the programmatic `rnxsim/sdk`;
|
|
157
|
+
the Maestro runner is `cli/bridge-flow-runner.ts`; the Detox compat driver
|
|
158
|
+
is in `detox/`. Test and screenshot paths additionally use `cli/drivers/*`.
|
|
159
|
+
Browser sims launch in an isolated Playwright Chrome for Testing profile;
|
|
160
|
+
Electron is the native desktop surface.
|
|
161
|
+
|
|
162
|
+
**The daemon is one process** — `SootSimBridgeHost` (`src/host/bridge-host.ts`).
|
|
163
|
+
`rnx serve` runs it in the foreground; the background daemon is the *same
|
|
164
|
+
process* wrapped with autostart and the `~/.rnx/daemon.json` lockfile. It is
|
|
165
|
+
an HTTP+WS hub: sims register over WS, CLI clients connect to drive them, and
|
|
166
|
+
the host forwards each command to the targeted sim and relays the reply back. It
|
|
167
|
+
also serves the engine runtime over HTTP (with a self-update route), exposes
|
|
168
|
+
`/__server-scan` to discover local metro/expo/vxrn/one dev servers, and proxies
|
|
169
|
+
guest-app fetch/WebSocket traffic so the cross-origin tenant worker can reach
|
|
170
|
+
localhost. The `AgentHost` extension owns one FIFO reader per agent session and
|
|
171
|
+
fans agent events out to every subscriber.
|
|
172
|
+
|
|
173
|
+
During source development, each Vite bridge owns one
|
|
174
|
+
`~/.rnx/dev-bridges/<port>.json` heartbeat record. CLI defaults select the
|
|
175
|
+
current `PORT_OFFSET`, then the current checkout, then the canonical `:7668`
|
|
176
|
+
bridge, so concurrent worktrees cannot replace or delete one another's address.
|
|
177
|
+
Each Vite shell also publishes its exact bridge at `/__sootsim/bridge`, so a
|
|
178
|
+
launcher that reuses a shell from another isolated `RNX_HOME` stays in that
|
|
179
|
+
shell's bridge world without reading the other process's lockfile directory.
|
|
180
|
+
|
|
181
|
+
**The sim** is a browser/Electron *page* launched by a CLI driver. Inside that
|
|
182
|
+
page run three workers: the **shell worker** owns device and native state, the
|
|
183
|
+
**compositor worker** paints every visible CanvasKit surface, and the **tenant
|
|
184
|
+
worker** runs the guest RN tree and sends native-UI requests to the shell. The
|
|
185
|
+
bridge always addresses the **shell worker**, never an undifferentiated sim.
|
|
186
|
+
|
|
187
|
+
**Two distinct plugin families** round it out, and they must not be conflated:
|
|
188
|
+
|
|
189
|
+
- The published **`rnxsim/vite`** (`src/vite-plugin-one.ts`, `rnxPlugin`)
|
|
190
|
+
and **`rnxsim/metro`** plugins do one thing: serve the installed runtime at
|
|
191
|
+
`/__soot/` so an app's own dev server can host the sim shell. The Vite plugin accepts an
|
|
192
|
+
opt-in `open` option that launches a named Electron window when the dev server
|
|
193
|
+
starts (skipped when `CI` or `RNX_NO_OPEN` is set).
|
|
194
|
+
- The internal **`sootsim()`** plugin (`src/vite-plugin.ts`) is a separate, much
|
|
195
|
+
larger RN-resolution / native-stub plugin: it aliases `react-native` to the
|
|
196
|
+
engine shim and native packages to `@sootsim/compat` stubs, applies worklets
|
|
197
|
+
transforms, and is the one that instantiates `SootSimBridgeHost` inside its
|
|
198
|
+
own dev server. It is used to build the engine/shell and to load external RN
|
|
199
|
+
apps — it is **not** the published `rnxsim/vite` export.
|
|
200
|
+
|
|
201
|
+
## Key components
|
|
202
|
+
|
|
203
|
+
| component | role | key files |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| rnx CLI (bin + dispatcher) | Short-lived terminal entry point. Parses argv, owns the private-by-default one-time choice, lazy-imports one command per run, and routes direct open/runtime/inspection flows. | `cli/bin.ts`, `cli/main.ts`, `cli/privacy.ts`, `cli/parse-args.ts`, `cli/help.ts`, `cli/commands/setup.ts`, `cli/commands/control.ts` |
|
|
206
|
+
| WsBridge client | Client side of the CLI→daemon link. Resolves the daemon port from the lockfile, opens a WS to `:7668`, sends JSON commands and awaits `{id,result}`/`{id,error}`. Used by every interactive command. | `cli/ws-bridge.ts`, `src/bridge-constants.ts`, `cli/current-sim.ts` |
|
|
207
|
+
| inspect / SDK command surface | Runtime inspection + interaction verbs (describe, find, do tap, get errors, wait, layout, settle). Re-exported as `rnxsim/sdk` so programmatic callers drive a sim the same way the CLI does. | `cli/commands/inspect/core.ts`, `cli/commands/inspect/actions.ts`, `cli/commands/inspect.ts`, `src/sdk.ts` |
|
|
208
|
+
| bridge-contract input parsers | Turn untrusted JSON into typed bridge-contract arguments, so a transport in front of a sim validates request bodies once instead of writing a second reader. | `src/bridge-contract-input.ts`, `src/bridge-contract.ts` |
|
|
209
|
+
| Maestro / Detox runners | Drop-in test compatibility. `bridge-flow-runner.ts` runs Maestro YAML and recorded flows over the bridge; `detox/` provides a `by`/`element`/`expect`/`device` driver + jest preset so existing Detox suites run unchanged. | `cli/bridge-flow-runner.ts`, `cli/commands/maestro.ts`, `cli/commands/detox.ts`, `detox/index.ts`, `detox/jest-preset.cjs` |
|
|
210
|
+
| sim drivers | Launch or attach the actual sim page. Playwright owns isolated browser profiles; Electron owns the native desktop surface. The current sim is reused unless `--new`, `--profile`, or `--ephemeral` requests a separate one. | `cli/drivers/index.ts`, `cli/drivers/registry.ts`, `cli/drivers/electron.ts`, `cli/drivers/playwright.ts` |
|
|
211
|
+
| 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` |
|
|
212
|
+
| 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` |
|
|
213
|
+
| 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` |
|
|
214
|
+
| 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` |
|
|
215
|
+
| standalone CLI delivery | Cached stable-version checks, bounded interactive notices, and verified atomic executable replacement. | `cli/cli-update.ts`, `cli/commands/upgrade.ts`, `cli/commands/version.ts`, `src/cli-version.ts` |
|
|
216
|
+
| `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; the Vite plugin can opt into a named Electron window. | `src/vite-plugin-one.ts`, `src/metro-plugin.ts`, `src/runtime-assets.ts` |
|
|
217
|
+
| `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` |
|
|
218
|
+
| 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` |
|
|
219
|
+
|
|
220
|
+
## Getting started
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
curl -fsSL https://rnxsim.com/install.sh | sh
|
|
224
|
+
rnx # open ConnectRN and choose a running app in the simulator
|
|
225
|
+
rnx open /settings # dispatch a React Native deep link into that app
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Start Metro, Expo, One, or another supported React Native development server
|
|
229
|
+
the way you normally do, then run `rnx` from any directory. The simulator
|
|
230
|
+
opens ConnectRN, which shows the available local apps and lets you connect one.
|
|
231
|
+
Pass a target to `rnx open <port-or-url>` when a script or agent needs an explicit
|
|
232
|
+
selection.
|
|
233
|
+
|
|
234
|
+
The first `rnx open` launches an isolated Chrome for Testing sim. The CLI
|
|
235
|
+
resolves Playwright from the app or CLI install, asks that exact package for
|
|
236
|
+
its required browser executable, and runs that package's installer once when
|
|
237
|
+
the executable is absent. It never substitutes another revision found in the
|
|
238
|
+
shared Playwright cache. Later opens reuse that sim and reload it at the
|
|
239
|
+
requested target. Use `rnx do reload` when the target has not changed.
|
|
240
|
+
Reserve `--new` for a genuinely concurrent sim; repeated new browser trees
|
|
241
|
+
consume memory and CPU on shared machines.
|
|
242
|
+
|
|
243
|
+
The public installer places one standalone `rnx` executable in `~/.local/bin`.
|
|
244
|
+
The `rnxsim` npm package contains bundler plugins and library exports, not a CLI
|
|
245
|
+
binary. Start your Metro, Expo, or One dev server the way you already do, then
|
|
246
|
+
open it from the CLI. There is no iOS native build in the inner loop; Metro alone is
|
|
247
|
+
enough. The manifest bundle path and query remain authoritative. When both the
|
|
248
|
+
discovery request and manifest target are loopback addresses, RNX keeps the
|
|
249
|
+
loopback host that answered discovery so an IPv6-only listener is not reopened
|
|
250
|
+
through an unreachable IPv4 address. `rnx open` starts a local bridge when no
|
|
251
|
+
daemon is reachable. The background service is strongly recommended for local
|
|
252
|
+
agent work because inspect, interaction, and test commands reuse one ready bridge
|
|
253
|
+
and runtime. Enable it at any time with `rnx daemon install`; it is never required
|
|
254
|
+
in CI. The packaged Desktop app is optional and available through first-run
|
|
255
|
+
onboarding or `rnx desktop install`. A downloaded app starts its own bundled
|
|
256
|
+
daemon on first launch, then offers **Install the rnx command** over the running
|
|
257
|
+
simulator. That action installs `~/.local/bin/rnx`, updates shell startup, and
|
|
258
|
+
hands the daemon to launchd or systemd without reloading the window. Windows
|
|
259
|
+
keeps the desktop-owned daemon because it has no daemon service yet. Native Electron windows created by `rnx open` belong to that CLI
|
|
260
|
+
session and close when the session exits; `rnx desktop` keeps the persistent
|
|
261
|
+
desktop-app lifecycle. In Electron, `File > New Window`
|
|
262
|
+
duplicates the focused simulator, while `File > New Simulator >` opens a new
|
|
263
|
+
window for a selected device (same device list as the `Window >` menu).
|
|
264
|
+
|
|
265
|
+
### Privacy
|
|
266
|
+
|
|
267
|
+
rnx sends no analytics, crash report, command event, app data, project data, or
|
|
268
|
+
identity by default. An unsigned-in interactive run may request the runtime it
|
|
269
|
+
is about to execute and the stable standalone CLI version document. The latter
|
|
270
|
+
runs after the command in a detached process at most once every 20 hours and can
|
|
271
|
+
be disabled with `RNX_UPDATE_CHECK=off`. The first human run asks once about
|
|
272
|
+
bounded diagnostics, defaults to no, and never prompts in a non-TTY shell, CI,
|
|
273
|
+
or an agent. An automated first run is declined for that process without
|
|
274
|
+
consuming the later human choice. Legacy browser and Electron telemetry senders
|
|
275
|
+
are removed rather than being enabled by this consent.
|
|
276
|
+
|
|
277
|
+
Opt-in diagnostics are limited to package name/version/unsupported API or error
|
|
278
|
+
class. rnx never sends source, file paths, project names, app content, commands,
|
|
279
|
+
identity, screenshots, or recordings as diagnostics. Cloud commands such as
|
|
280
|
+
login, upload, billing, issue reporting, generated flows, and screenshot decks
|
|
281
|
+
contact their documented service only when explicitly invoked. The complete
|
|
282
|
+
enforced network contract is in [`specs/rnx-privacy.md`](../../specs/rnx-privacy.md).
|
|
283
|
+
|
|
284
|
+
`rnx daemon uninstall` removes the machine daemon: it stops current and legacy
|
|
285
|
+
launchd / systemd services and removes their logs, launcher, and generated
|
|
286
|
+
`.app` wrapper. `~/.rnx/` survives, because runtimes, device profiles and their
|
|
287
|
+
app storage, and live dev-bridge records belong to simulators the user may
|
|
288
|
+
still be running. `rnx daemon uninstall --purge` deletes `~/.rnx/` as well.
|
|
289
|
+
Neither form removes the optional `/Applications/rnx.app` desktop bundle or the
|
|
290
|
+
macOS preference plist. To inspect existing disk usage first, run `rnx cleanup`;
|
|
291
|
+
add `--apply` only after reviewing the preview.
|
|
292
|
+
|
|
293
|
+
## Jump to source in inspect mode
|
|
294
|
+
|
|
295
|
+
Inspect mode can open a selected React Native element in your editor when the
|
|
296
|
+
bundle includes source metadata. Add the optional Babel plugin to your app's
|
|
297
|
+
Metro/Babel config:
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
plugins: [
|
|
301
|
+
[
|
|
302
|
+
'rnxsim/jump-to-source-babel',
|
|
303
|
+
{
|
|
304
|
+
include: [__dirname],
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
'react-native-worklets/plugin',
|
|
308
|
+
]
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The plugin adds an `srcloc="/absolute/path/App.tsx:12:3"` prop to JSX elements
|
|
312
|
+
outside `node_modules`, `dist`, and `build`. Keep it before
|
|
313
|
+
`react-native-worklets/plugin` in a custom Babel stack that lists both plugins.
|
|
314
|
+
Apps using `babel-preset-expo` omit the explicit Worklets plugin because the
|
|
315
|
+
preset configures it automatically.
|
|
316
|
+
|
|
317
|
+
For One's Rolldown native bundler, use the native transform in `vite.config.ts`:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
import { jumpToSourceNativePlugin } from 'rnxsim/jump-to-source-native'
|
|
321
|
+
|
|
322
|
+
one({
|
|
323
|
+
native: {
|
|
324
|
+
bundler: 'vite',
|
|
325
|
+
bundlerOptions: {
|
|
326
|
+
plugins: [jumpToSourceNativePlugin({ include: [import.meta.dirname] })],
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
})
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
This transform uses the same source props and filters without running Babel.
|
|
333
|
+
For One's `nativeTransformModules`, export
|
|
334
|
+
`createJumpToSourceNativeTransform(options)` from a module and pass its module id.
|
|
335
|
+
|
|
336
|
+
## CLI
|
|
337
|
+
|
|
338
|
+
The CLI is the primary debugging surface for rnx — use it first for runtime
|
|
339
|
+
inspection, interaction, animation debugging, shell tracing, screenshots, and
|
|
340
|
+
flow capture, not just as a test runner.
|
|
341
|
+
|
|
342
|
+
```sh
|
|
343
|
+
rnx list # connected tabs
|
|
344
|
+
rnx open 8081 # load a running metro/expo dev server
|
|
345
|
+
rnx open /settings # route via React Native Linking
|
|
346
|
+
rnx describe # dump UI tree
|
|
347
|
+
rnx get errors 5 # recent runtime failures
|
|
348
|
+
rnx compat # scan native package compatibility
|
|
349
|
+
rnx report-issue "…" # preview an opt-in compatibility report
|
|
350
|
+
rnx find --testid cta # inspect one node deeply
|
|
351
|
+
rnx debug enable animated,layout
|
|
352
|
+
rnx debug trace shell on 240
|
|
353
|
+
rnx do tap-text "..." # interact
|
|
354
|
+
rnx do tap email --then type user@example.com --then tap submit
|
|
355
|
+
rnx debug snapshot before
|
|
356
|
+
rnx debug snapshot after
|
|
357
|
+
rnx debug diff before after
|
|
358
|
+
rnx maestro start # begin a Maestro draft
|
|
359
|
+
rnx maestro keep # persist the last action
|
|
360
|
+
rnx maestro end --output .maestro/login.yaml --validate
|
|
361
|
+
rnx detox # run Detox/Jest suites against rnx
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
See the full command reference via `rnx --help` or at
|
|
365
|
+
`src/features/site/docs/rnx/cli/` in the Contrast repo.
|
|
366
|
+
|
|
367
|
+
Sim-scoped commands use the primary fallback only when one driveable sim is
|
|
368
|
+
connected. With multiple driveable sims, the bridge lists their ids and refuses
|
|
369
|
+
to choose. Run `rnx use <id>` to pin later commands, or pass `--sim <id>` to
|
|
370
|
+
target one command.
|
|
371
|
+
|
|
372
|
+
Use an inline `rnx do` chain for a short action sequence that should execute as
|
|
373
|
+
one engine batch. Repeat `--then` before each additional action. Each phrase
|
|
374
|
+
uses the same positional grammar as its standalone `do` command. Touch timing
|
|
375
|
+
stays inside the sim, the batch stops at the first failure, and `--json` prints
|
|
376
|
+
the complete per-step result. Reusable file-based flows stay in Maestro YAML.
|
|
377
|
+
|
|
378
|
+
```sh
|
|
379
|
+
rnx do tap email --then type user@example.com --then tap submit
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Bundler plugins (`rnxsim/vite` and `rnxsim/metro`)
|
|
383
|
+
|
|
384
|
+
The Vite plugin serves the installed RNX runtime from your existing dev server.
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
// vite.config.ts
|
|
388
|
+
import { rnxPlugin } from 'rnxsim/vite'
|
|
389
|
+
|
|
390
|
+
export default {
|
|
391
|
+
plugins: [rnxPlugin({ open: { appName: 'My App' } })],
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
```js
|
|
396
|
+
// metro.config.js
|
|
397
|
+
const { getDefaultConfig } = require('expo/metro-config')
|
|
398
|
+
const { withRNX } = require('rnxsim/metro')
|
|
399
|
+
|
|
400
|
+
const config = getDefaultConfig(__dirname)
|
|
401
|
+
|
|
402
|
+
module.exports = withRNX(config)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
rnx works directly with regular, unannotated Metro production JavaScript bundles
|
|
406
|
+
out of the box. It identifies modules by matching package graph fingerprints
|
|
407
|
+
against a separately updated, integrity-checked registry. Hermes bytecode is not
|
|
408
|
+
a supported input; pass rnx the JavaScript bundle produced before Hermes
|
|
409
|
+
compilation.
|
|
410
|
+
|
|
411
|
+
If an app has unusual dependencies or fingerprint inference fails, you can
|
|
412
|
+
optionally wrap your Metro configuration with `withRNX(config)`. It takes no
|
|
413
|
+
options and enables two integrations:
|
|
414
|
+
|
|
415
|
+
1. **Deterministic module identity:** appends Metro's exact module identity map
|
|
416
|
+
as a trailing `globalThis.__sootsimModulePaths = { ... }` footer to every
|
|
417
|
+
bundle. Resolution, transforms, minification, and source maps stay the app's
|
|
418
|
+
own, so the annotated bundle is the exact bundle you ship: the footer assigns
|
|
419
|
+
one unused global on a device, and Hermes drops it during bytecode compilation.
|
|
420
|
+
2. **In-browser dev shell:** serves the rnx simulator shell at `/__soot/` on
|
|
421
|
+
the Metro dev server.
|
|
422
|
+
|
|
423
|
+
The URL helpers request ordinary Metro graphs: `dev=false&minify=true` for
|
|
424
|
+
production and `dev=true&minify=false` for development.
|
|
425
|
+
|
|
426
|
+
```js
|
|
427
|
+
const {
|
|
428
|
+
toRNXProductionBundleUrl,
|
|
429
|
+
toRNXDevelopmentBundleUrl,
|
|
430
|
+
} = require('rnxsim/metro')
|
|
431
|
+
|
|
432
|
+
const productionUrl = toRNXProductionBundleUrl(
|
|
433
|
+
'http://localhost:8081/index.bundle?platform=ios',
|
|
434
|
+
)
|
|
435
|
+
const developmentUrl = toRNXDevelopmentBundleUrl(
|
|
436
|
+
'http://localhost:8081/index.bundle?platform=ios',
|
|
437
|
+
)
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## Coming from Detox
|
|
441
|
+
|
|
442
|
+
rnx ships a drop-in Detox driver. Existing Detox test files
|
|
443
|
+
(`import { by, element, expect, device } from 'detox'`) run against rnx with
|
|
444
|
+
no code changes — just add one line to your jest config:
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
// jest config
|
|
448
|
+
{ preset: 'rnxsim/detox' }
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Or use the CLI directly:
|
|
452
|
+
|
|
453
|
+
```sh
|
|
454
|
+
rnx detox # auto-discovers e2e/ tests and launches a shell
|
|
455
|
+
rnx detox init # scaffold a config + sample test
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
See `../../docs/migrating-from-detox.md` for details.
|
|
459
|
+
|
|
460
|
+
## Coming from Maestro
|
|
461
|
+
|
|
462
|
+
Maestro is rnx's single YAML test surface. Point it at your existing
|
|
463
|
+
`.maestro/` directory, generate a test, or author one from live actions:
|
|
464
|
+
|
|
465
|
+
```sh
|
|
466
|
+
rnx maestro # discover .maestro/ and run all flows
|
|
467
|
+
rnx maestro test .maestro/ # explicit
|
|
468
|
+
rnx maestro generate "verify login"
|
|
469
|
+
rnx maestro --list-compat # see the verb support matrix
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Most Maestro verbs work out of the box (`tapOn`, `assertVisible`, `inputText`,
|
|
473
|
+
`scrollUntilVisible`, `launchApp`, `when:`, `repeat`, `runFlow`, …). Verbs that
|
|
474
|
+
need real device hardware (GPS, radio, photo library) throw a clear error. See
|
|
475
|
+
`../../docs/migrating-from-maestro.md` for the full compat matrix.
|
|
476
|
+
|
|
477
|
+
## Screenshots and recordings
|
|
478
|
+
|
|
479
|
+
For animation-heavy debugging, the useful path is usually:
|
|
480
|
+
|
|
481
|
+
```sh
|
|
482
|
+
rnx debug enable animated
|
|
483
|
+
rnx debug trace shell on 240
|
|
484
|
+
rnx debug snapshot before
|
|
485
|
+
# reproduce the transition
|
|
486
|
+
rnx debug snapshot after
|
|
487
|
+
rnx debug diff before after
|
|
488
|
+
rnx screenshot --with-frame --output /tmp/rnx-framed.png
|
|
489
|
+
rnx record --duration 5 --output /tmp/rnx-anim.mp4
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`rnx screenshot --with-frame` composes the real rnx shell device chrome
|
|
493
|
+
around the raw screen bitmap (reusing the shell bezel/button geometry, excluding
|
|
494
|
+
the Electron top bar, rail gutter, and other window chrome). Flows can request
|
|
495
|
+
the framed export inline without changing Maestro syntax:
|
|
496
|
+
|
|
497
|
+
`rnx wait ready` and the screenshot readiness guard accept inspectable
|
|
498
|
+
native content, a populated node tree, or a live-frame channel whose publish
|
|
499
|
+
count advances across probes. Canvas-only GL, WebGPU, and video surfaces can
|
|
500
|
+
therefore prove that they are painting without weakening the boot-card guard.
|
|
501
|
+
|
|
502
|
+
```yaml
|
|
503
|
+
- takeScreenshot: hero
|
|
504
|
+
- takeScreenshot:
|
|
505
|
+
path: marketing/hero
|
|
506
|
+
withFrame: true
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
For plan-driven app-store exports, use `rnx screenshot appstore`:
|
|
510
|
+
|
|
511
|
+
```yaml
|
|
512
|
+
app: 8081
|
|
513
|
+
device: iphone-16
|
|
514
|
+
|
|
515
|
+
capture:
|
|
516
|
+
flow: .maestro/capture-app-store-screenshots.yaml
|
|
517
|
+
mode: raw+framed
|
|
518
|
+
|
|
519
|
+
compose:
|
|
520
|
+
canvases: [iphone-6-9, iphone-6-1]
|
|
521
|
+
background: cyan
|
|
522
|
+
text:
|
|
523
|
+
preset: bold-top
|
|
524
|
+
slides:
|
|
525
|
+
- id: splash-hero
|
|
526
|
+
screenshot: apple/iphone/en/01-splash.png
|
|
527
|
+
headline: First punch.
|
|
528
|
+
subheadline: Every pick in one place.
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
```sh
|
|
532
|
+
rnx screenshot appstore --plan .rnx/app-store.yaml
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
The plan runner can reuse a visible sim for capture (`--sim a9`), stop after
|
|
536
|
+
raw/framed intermediates (`--capture-only`), or rerender final marketing
|
|
537
|
+
canvases from an existing raw directory (`--compose-only`). If your flow already
|
|
538
|
+
writes screenshots to explicit project paths, set `from:` + `pathMode: flow` so
|
|
539
|
+
`rnx screenshot appstore` respects the flow's own `takeScreenshot` paths
|
|
540
|
+
instead of prepending `--screenshots <rawDir>`:
|
|
541
|
+
|
|
542
|
+
```yaml
|
|
543
|
+
capture:
|
|
544
|
+
flow: .maestro/capture-app-store-screenshots.yaml
|
|
545
|
+
from: ./apps/app-store-screenshots/public/screenshots/apple/iphone/en
|
|
546
|
+
pathMode: flow
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
In the browser shell, `Screenshot Mode` turns the live shell into a simple DOM
|
|
550
|
+
composition surface: the rail + mac menu bar disappear, the device shifts down
|
|
551
|
+
with a short transition, and editable title/subtitle fields appear above the
|
|
552
|
+
frame for quick art-direction passes.
|
|
553
|
+
|
|
554
|
+
## Skills registry
|
|
555
|
+
|
|
556
|
+
`rnx skill install` installs rnx agent skills in the standard
|
|
557
|
+
`<skill-name>/SKILL.md` layout used by Codex and Claude Code. The bundled
|
|
558
|
+
skills cover setup, debugging/perf/accessibility, testing, visual review, and
|
|
559
|
+
the generated `contrast` command index. The published CLI registry and generated
|
|
560
|
+
website docs both come from `packages/rnx-skills/`:
|
|
561
|
+
|
|
562
|
+
- `packages/sootsim/skills/contrast/SKILL.md` is generated from that registry
|
|
563
|
+
- `src/features/site/docs/rnx/cli/*` is generated output, not hand-edited
|
|
564
|
+
|
|
565
|
+
When command docs or examples drift, update `packages/rnx-skills/` and run:
|
|
566
|
+
|
|
567
|
+
```sh
|
|
568
|
+
bun run generate:sootsim-docs
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Runtime delivery (the rnx home and CDN)
|
|
572
|
+
|
|
573
|
+
The engine never ships inside this package. `runtime-delivery.ts` names
|
|
574
|
+
rnx's CDN origin (default `https://contrast.dev`, overridable in
|
|
575
|
+
`config.json`), its `SOOTSIM_*` env overrides, and its hosted paths, then hands
|
|
576
|
+
them to the shared delivery machinery in `@contrast/runtime-delivery` — an
|
|
577
|
+
internal workspace package the CLI bundles, so a published install has it
|
|
578
|
+
inlined. That machinery fetches `runtimes/manifest.json` + the runtime tarball,
|
|
579
|
+
verifies its sha256, and unpacks it under `~/.rnx`:
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
~/.rnx/
|
|
583
|
+
├── runtimes/
|
|
584
|
+
│ ├── <active>/ unpacked engine assets (served at /__soot/)
|
|
585
|
+
│ └── <rollback>/ previous version for rollback
|
|
586
|
+
├── cache/ legacy downloads; empty after cleanup
|
|
587
|
+
├── profiles/ persistent named app storage, without browser caches
|
|
588
|
+
├── electron/userData/ desktop app storage, with bounded browser caches
|
|
589
|
+
├── daemon.json lockfile: pid, ports, active runtime, heartbeat
|
|
590
|
+
├── cli-update.json cached standalone CLI version and notice state
|
|
591
|
+
├── automatic-cleanup-v1.json completed legacy cleanup generation
|
|
592
|
+
└── config.json user prefs: update channel, cdn origin override
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
The bridge daemon serves these assets over HTTP and exposes a self-update route;
|
|
596
|
+
`rnx upgrade` / `rnx runtime` drive explicit version changes from the
|
|
597
|
+
CLI side. Installation retains the active runtime plus one rollback and removes
|
|
598
|
+
the downloaded archive after extraction. Disposable Playwright caches live in a
|
|
599
|
+
bounded per-session temporary directory; Electron's persistent HTTP cache is
|
|
600
|
+
disabled for simulator profiles and globally capped for app chrome. Cookies,
|
|
601
|
+
localStorage, IndexedDB, service workers, recordings, and captured frames are
|
|
602
|
+
user-owned data and are not removed by the default cleanup command.
|
|
603
|
+
|
|
604
|
+
Per-repo configuration is optional. Every installed-runtime `rnx open`
|
|
605
|
+
serves its selected version from a version-specific localhost origin, so a
|
|
606
|
+
background activation cannot mix an already loaded shell with chunks from the
|
|
607
|
+
next runtime. Without config, each new open selects the active stable version.
|
|
608
|
+
When `rnx.config.ts` sets `runtimeVersion`, `rnx open` installs that
|
|
609
|
+
version without changing the machine default. App config, native-linked fonts,
|
|
610
|
+
and splash assets all resolve from the project root advertised by the selected
|
|
611
|
+
development server. Bare Metro, which has no Expo manifest project root, uses
|
|
612
|
+
the listening development process's cwd inside that same resolver. The invoking
|
|
613
|
+
CLI's cwd is never an asset/config fallback. Asset wires stay on each opened
|
|
614
|
+
project URL, so one daemon can serve several attached projects without sharing
|
|
615
|
+
font or splash state between them.
|
|
616
|
+
|
|
617
|
+
The first interactive CLI command after this cleanup generation finishes its
|
|
618
|
+
requested work, then launches the same safe default plan in a detached
|
|
619
|
+
maintenance process. The app and terminal command are usable before the legacy
|
|
620
|
+
filesystem scan begins. The worker prints the reclaimed size to stderr, records
|
|
621
|
+
completion, and does not run the scan again. Open browser profiles and a runtime
|
|
622
|
+
served by a live daemon or development bridge are left untouched. The automatic
|
|
623
|
+
pass retries on a later command after they close. The explicit `rnx cleanup --aggressive`
|
|
624
|
+
command remains the only path that removes the rollback runtime or user-created
|
|
625
|
+
recordings.
|
|
626
|
+
|
|
627
|
+
## Development and building
|
|
628
|
+
|
|
629
|
+
This package is part of the Contrast monorepo. To build the standalone executable
|
|
630
|
+
for the current platform:
|
|
631
|
+
|
|
632
|
+
```sh
|
|
633
|
+
bun run build:cli-binary
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
The output is `dist-bin/rnx-<platform>-<arch>`. `dist-cli/bin.js` remains a
|
|
637
|
+
repository build artifact for tests and internal tooling and is not published
|
|
638
|
+
as an npm executable. Library exports build to `dist-lib/` (consumed via the
|
|
639
|
+
`exports` map: `.`, `./vite`, `./metro`, `./sdk`, `./skills`, `./detox`, and the
|
|
640
|
+
host/agent helpers). `bun run pack:smoke` validates the publishable tarball.
|