rnxsim 0.0.0 → 0.1.312
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 +21 -0
- package/README.md +512 -0
- package/detox/colors.ts +54 -0
- package/detox/config-loader.ts +135 -0
- package/detox/element-types.ts +39 -0
- package/detox/expectations.ts +537 -0
- package/detox/gestures.ts +480 -0
- package/detox/index.ts +2118 -0
- package/detox/jest-preset.cjs +51 -0
- package/detox/jest-setup-after-env.cjs +18 -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.ts +43 -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-cli/bin.js +15 -0
- package/dist-cli/chunks/agent-NXVDDCFG.js +48 -0
- package/dist-cli/chunks/agent-wrapper-DXJCFKL3.js +17 -0
- package/dist-cli/chunks/app-fonts-W5AJZQJF.js +4 -0
- package/dist-cli/chunks/assert-3LOJEUDT.js +49 -0
- package/dist-cli/chunks/auth-MFTYYPNX.js +12 -0
- package/dist-cli/chunks/beta-GT3NN67B.js +4 -0
- package/dist-cli/chunks/camera-6EAK7CUL.js +22 -0
- package/dist-cli/chunks/chunk-274UD5FD.js +4 -0
- package/dist-cli/chunks/chunk-2SA2VTGP.js +5 -0
- package/dist-cli/chunks/chunk-33FKQH54.js +5 -0
- package/dist-cli/chunks/chunk-37I5AIS7.js +3 -0
- package/dist-cli/chunks/chunk-3D57IBPC.js +4 -0
- package/dist-cli/chunks/chunk-4BXCZHAU.js +4 -0
- package/dist-cli/chunks/chunk-5OX7ANRA.js +5 -0
- package/dist-cli/chunks/chunk-66NF2KNG.js +9 -0
- package/dist-cli/chunks/chunk-6UKJB2VC.js +125 -0
- package/dist-cli/chunks/chunk-7INBNA3U.js +26 -0
- package/dist-cli/chunks/chunk-7VWOSTD5.js +5 -0
- package/dist-cli/chunks/chunk-AY47WKS5.js +23 -0
- package/dist-cli/chunks/chunk-B7KMNHX7.js +4 -0
- package/dist-cli/chunks/chunk-BKNOLP3J.js +4 -0
- package/dist-cli/chunks/chunk-BRIZOR4K.js +28 -0
- package/dist-cli/chunks/chunk-DM6KUAOZ.js +4 -0
- package/dist-cli/chunks/chunk-EUAVBTKU.js +4 -0
- package/dist-cli/chunks/chunk-FTC4M26Q.js +4 -0
- package/dist-cli/chunks/chunk-FWYYCUAZ.js +4 -0
- package/dist-cli/chunks/chunk-G74YIEVS.js +7 -0
- package/dist-cli/chunks/chunk-GZDHEONW.js +507 -0
- package/dist-cli/chunks/chunk-HG7ORJMT.js +5 -0
- package/dist-cli/chunks/chunk-HMDOLCKG.js +15 -0
- package/dist-cli/chunks/chunk-JG6S4RSH.js +4 -0
- package/dist-cli/chunks/chunk-KR5BGMBZ.js +4 -0
- package/dist-cli/chunks/chunk-KZW5WBGU.js +983 -0
- package/dist-cli/chunks/chunk-L24Z3CRS.js +30 -0
- package/dist-cli/chunks/chunk-LDQ7HVCW.js +4 -0
- package/dist-cli/chunks/chunk-MENV7VLD.js +4 -0
- package/dist-cli/chunks/chunk-MNGQ42QE.js +568 -0
- package/dist-cli/chunks/chunk-N6A3SXMR.js +4 -0
- package/dist-cli/chunks/chunk-NLEMQ4PY.js +6 -0
- package/dist-cli/chunks/chunk-NPVGMH2N.js +101 -0
- package/dist-cli/chunks/chunk-OR3XTXEB.js +107 -0
- package/dist-cli/chunks/chunk-PEPUGJVI.js +4 -0
- package/dist-cli/chunks/chunk-Q3RGLERJ.js +142 -0
- package/dist-cli/chunks/chunk-SI3BUTQR.js +4 -0
- package/dist-cli/chunks/chunk-T4FT6CM7.js +4 -0
- package/dist-cli/chunks/chunk-TBMVBI26.js +7 -0
- package/dist-cli/chunks/chunk-TCWQJILS.js +5 -0
- package/dist-cli/chunks/chunk-TGQNQ6XT.js +766 -0
- package/dist-cli/chunks/chunk-TYE3WBSR.js +5 -0
- package/dist-cli/chunks/chunk-U4PN6JOT.js +6 -0
- package/dist-cli/chunks/chunk-VUFRB347.js +4 -0
- package/dist-cli/chunks/chunk-VZBLFMYC.js +10 -0
- package/dist-cli/chunks/chunk-WBT32R6N.js +25 -0
- package/dist-cli/chunks/chunk-XRGEEPJ5.js +38 -0
- package/dist-cli/chunks/chunk-Y2FSZSO7.js +71 -0
- package/dist-cli/chunks/chunk-YRV7HR3P.js +74 -0
- package/dist-cli/chunks/chunk-YZRFF4YA.js +14 -0
- package/dist-cli/chunks/chunk-ZMZTHU7V.js +4 -0
- package/dist-cli/chunks/cleanup-H3GWQB63.js +25 -0
- package/dist-cli/chunks/cli-version-3QPAJ3LC.js +4 -0
- package/dist-cli/chunks/compat-5WG2XJV7.js +20 -0
- package/dist-cli/chunks/config-ANMBVVLL.js +13 -0
- package/dist-cli/chunks/control-NSGNQFJG.js +4 -0
- package/dist-cli/chunks/daemon-JHF4BJ3U.js +4 -0
- package/dist-cli/chunks/debug-CHV2O2KF.js +200 -0
- package/dist-cli/chunks/desktop-FIPIK4CH.js +31 -0
- package/dist-cli/chunks/detox-CVUJP7K6.js +52 -0
- package/dist-cli/chunks/device-6WCUM4W6.js +18 -0
- package/dist-cli/chunks/diagnose-I6EMWEII.js +43 -0
- package/dist-cli/chunks/disk-cleanup-P27CYFTN.js +4 -0
- package/dist-cli/chunks/drivers-HQ6AKZT6.js +4 -0
- package/dist-cli/chunks/film-UOQFFYNF.js +74 -0
- package/dist-cli/chunks/flow-N27MRRNL.js +4 -0
- package/dist-cli/chunks/help-SF6FEGEE.js +4 -0
- package/dist-cli/chunks/hidden-runtime-alias-NJYFSJKZ.js +4 -0
- package/dist-cli/chunks/home-paths-XOV44JEF.js +4 -0
- package/dist-cli/chunks/inspect-CWFRFQTY.js +4 -0
- package/dist-cli/chunks/install-desktop-KLQDNXZQ.js +4 -0
- package/dist-cli/chunks/login-BPFQENCX.js +28 -0
- package/dist-cli/chunks/logout-5A45ZGY7.js +4 -0
- package/dist-cli/chunks/maestro-E4CSDMLM.js +104 -0
- package/dist-cli/chunks/maestro-generate-CKMOJQX2.js +36 -0
- package/dist-cli/chunks/mode-SZYNMIQF.js +26 -0
- package/dist-cli/chunks/optional-demo-registry-FRH4SFVG.js +4 -0
- package/dist-cli/chunks/perf-VXU2XJAX.js +48 -0
- package/dist-cli/chunks/permissions-IRIAOVND.js +13 -0
- package/dist-cli/chunks/record-RY7FPLLH.js +72 -0
- package/dist-cli/chunks/report-issue-KNWXOE53.js +29 -0
- package/dist-cli/chunks/runtime-AR3GJTGK.js +4 -0
- package/dist-cli/chunks/screenshot-command-QLALR6GY.js +159 -0
- package/dist-cli/chunks/screenshot-layers-OQFMFVRL.js +20 -0
- package/dist-cli/chunks/screenshots-capture-6TSRJFGB.js +42 -0
- package/dist-cli/chunks/serve-F54J2NQO.js +44 -0
- package/dist-cli/chunks/setup-7V6UKX4U.js +32 -0
- package/dist-cli/chunks/skills-QQBOSETH.js +50 -0
- package/dist-cli/chunks/storage-TAPMKK5O.js +37 -0
- package/dist-cli/chunks/store-7NX3S43H.js +4 -0
- package/dist-cli/chunks/telemetry-E7BUK6RA.js +4 -0
- package/dist-cli/chunks/timeline-IAM564NA.js +24 -0
- package/dist-cli/chunks/upgrade-CD55QXIX.js +7 -0
- package/dist-cli/chunks/upload-GZ6LIMYM.js +4 -0
- package/dist-cli/chunks/version-3DYJ5AS3.js +6 -0
- package/dist-cli/chunks/web-6NW6YLPI.js +4 -0
- package/dist-cli/chunks/what-happened-CZZDOOVG.js +25 -0
- package/dist-lib/agent-daemon-client.cjs +468 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-identity.cjs +53 -0
- package/dist-lib/agent-sessions.cjs +725 -0
- package/dist-lib/attached-projects.cjs +526 -0
- package/dist-lib/auth/shared-session.cjs +195 -0
- package/dist-lib/backend-origin.cjs +70 -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/cli-constants.cjs +32 -0
- package/dist-lib/config.cjs +96 -0
- package/dist-lib/detox/index.cjs +2863 -0
- package/dist-lib/detox/jest-preset.cjs +51 -0
- package/dist-lib/dev-bundle-resolution.cjs +223 -0
- package/dist-lib/home-paths.cjs +421 -0
- package/dist-lib/host/bridge-host.cjs +5600 -0
- package/dist-lib/host/fetch-proxy-handler.cjs +373 -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/websocket-proxy.cjs +214 -0
- package/dist-lib/index.cjs +513 -0
- package/dist-lib/jump-to-source-babel.cjs +93 -0
- package/dist-lib/menu.cjs +620 -0
- package/dist-lib/menu.mjs +581 -0
- package/dist-lib/metro.cjs +297 -0
- package/dist-lib/profiles.cjs +246 -0
- package/dist-lib/public-brand.cjs +39 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/scripts/dev-server-scanner.cjs +1034 -0
- package/dist-lib/sdk.cjs +2333 -0
- package/dist-lib/sdk.mjs +2240 -0
- package/dist-lib/skills.cjs +23911 -0
- package/dist-lib/vite.cjs +358 -0
- package/package.json +189 -18
- package/scripts/dev-server-scanner.ts +941 -0
- package/scripts/optional-demo-registry.ts +113 -0
- package/scripts/postinstall.cjs +3 -0
- package/scripts/preuninstall.cjs +118 -0
- package/skills/contrast/SKILL.md +171 -0
- package/skills/rnx-debug/SKILL.md +425 -0
- package/skills/rnx-perf/SKILL.md +295 -0
- package/skills/rnx-setup/SKILL.md +160 -0
- package/skills/rnx-test/SKILL.md +292 -0
- package/skills/rnx-visual/SKILL.md +122 -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 +573 -0
- package/src/attached-projects.ts +539 -0
- package/src/auth/shared-session.ts +204 -0
- package/src/backend-origin.ts +49 -0
- package/src/beta.ts +19 -0
- package/src/bridge-constants.ts +171 -0
- package/src/browser-cache.ts +16 -0
- package/src/cli-constants.ts +1 -0
- package/src/cli-version.ts +32 -0
- package/src/codex-client.ts +215 -0
- package/src/config.ts +134 -0
- package/src/dev-bundle-resolution.ts +236 -0
- package/src/disk-cleanup.ts +466 -0
- package/src/home-paths.ts +552 -0
- package/src/host/agent-host.ts +666 -0
- package/src/host/bridge-host.ts +2626 -0
- package/src/host/fetch-proxy-handler.ts +397 -0
- package/src/host/fetch-proxy-overrides.ts +51 -0
- package/src/host/open-url.ts +89 -0
- package/src/host/websocket-proxy.ts +210 -0
- package/src/index.ts +12 -705
- package/src/jump-to-source-babel.ts +135 -0
- package/src/menu.ts +734 -0
- package/src/metro-plugin.ts +139 -0
- package/src/native-dev-bundle-url.ts +96 -0
- package/src/native-seam-manifest.ts +341 -0
- package/src/plist.ts +27 -0
- package/src/poll-until.ts +92 -0
- package/src/profiles.ts +179 -0
- package/src/public-brand.ts +9 -0
- package/src/render-mode.ts +27 -0
- package/src/runtime-assets.ts +228 -0
- package/src/runtime-delivery.ts +54 -0
- package/src/screenshots/compose.ts +422 -0
- package/src/screenshots/frame-compose.ts +454 -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 +7 -0
- package/src/settings-bundle.ts +418 -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/team-machine-prompt.ts +73 -0
- package/src/vite-plugin-one.ts +190 -0
- package/src/vite-plugin.ts +1750 -0
- package/src/worklets-babel.ts +134 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Tamagui LLC and sootsim contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
# rnx
|
|
2
|
+
|
|
3
|
+
The public, publishable face of rnx: a CLI, two pairs of bundler plugins, a
|
|
4
|
+
Detox/Maestro test surface, and a skills registry for driving a browser-native
|
|
5
|
+
React Native simulator.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
`rnxsim` is everything you install to *talk to* an rnx instance — it
|
|
10
|
+
contains **no rendering code**. The canvas engine (CanvasKit renderer, Yoga
|
|
11
|
+
layout, iOS/Android shell chrome, Electron shell) lives in the private
|
|
12
|
+
`sootsim-engine` workspace package and is shipped at runtime as a versioned
|
|
13
|
+
tarball, fetched from the contrast.dev CDN and unpacked into `~/.sootsim`.
|
|
14
|
+
|
|
15
|
+
What this package gives you:
|
|
16
|
+
|
|
17
|
+
- the `rnxsim` CLI — the primary debugging and automation surface (inspect the
|
|
18
|
+
UI tree, tap elements, capture flows, screenshot, record, run agents)
|
|
19
|
+
- `rnxsim/vite` and `rnxsim/metro` — bundler plugins that serve the installed
|
|
20
|
+
engine runtime from your own dev server
|
|
21
|
+
- `rnxsim/jump-to-source-babel` — an optional Babel plugin that annotates JSX
|
|
22
|
+
with source locations so inspect mode can open the selected element in your
|
|
23
|
+
editor
|
|
24
|
+
- `rnxsim/detox` — a drop-in Detox driver + jest preset
|
|
25
|
+
- `rnxsim/sdk` — the inspect/interact verbs as a programmatic API
|
|
26
|
+
- `rnxsim/skills` — a registry of Contrast-flavored automation skills
|
|
27
|
+
|
|
28
|
+
Platform status: iOS is the parity baseline. Android is bootstrapped and usable
|
|
29
|
+
for focused conformance slices (bundle/runtime identity, device profiles, shell
|
|
30
|
+
chrome, gesture + three-button nav, system UI/window metrics with cutout-safe
|
|
31
|
+
insets) but is not full parity until the Android launch gates in the Contrast
|
|
32
|
+
repo plan pass.
|
|
33
|
+
|
|
34
|
+
## What's in this package (and what's not)
|
|
35
|
+
|
|
36
|
+
| in `rnxsim` | in `sootsim-engine` (private, not published) |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| CLI, bridge client, drivers | CanvasKit renderer, Yoga layout |
|
|
39
|
+
| bridge daemon host (`SootSimBridgeHost`) | iOS/Android shell chrome, home grid, app switcher |
|
|
40
|
+
| vite/metro plugins, RN resolver, native stubs | Electron shell, wasm |
|
|
41
|
+
| Detox/Maestro runners, screenshots, skills | the actual pixels |
|
|
42
|
+
|
|
43
|
+
The engine is delivered at runtime, never bundled into this package. A
|
|
44
|
+
committed-but-unbuilt engine fix has no effect on a running sim until the
|
|
45
|
+
runtime tarball is rebuilt and re-fetched.
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
|
|
49
|
+
The architecture is a **three-tier relay**: a short-lived CLI process, a single
|
|
50
|
+
persistent bridge daemon, and the sim itself — a browser/Electron *page* that
|
|
51
|
+
internally splits into shell, compositor, and tenant workers.
|
|
52
|
+
|
|
53
|
+
```mermaid
|
|
54
|
+
graph TD
|
|
55
|
+
subgraph cli["rnxsim CLI process (short-lived, cli/)"]
|
|
56
|
+
BIN["bin.ts (dispatcher + telemetry)"]
|
|
57
|
+
SETUP["commands/setup.ts (guided daemon setup)"]
|
|
58
|
+
RUNTIMECMD["commands/runtime.ts (runtime install/use)"]
|
|
59
|
+
INSPECT["commands/inspect/* (describe/find/do/get/wait)"]
|
|
60
|
+
FLOW["bridge-flow-runner.ts (Maestro YAML)"]
|
|
61
|
+
DETOXCMD["commands/detox.ts + detox/ driver"]
|
|
62
|
+
SHOTS["commands/screenshot + record"]
|
|
63
|
+
AGENTCMD["commands/agent.ts"]
|
|
64
|
+
WSB["ws-bridge.ts (WsBridge client)"]
|
|
65
|
+
DRIVERS["drivers/* (chromium/electron/playwright/system)"]
|
|
66
|
+
end
|
|
67
|
+
subgraph daemon["bridge daemon process (persistent :7668)"]
|
|
68
|
+
HOST["SootSimBridgeHost (host/bridge-host.ts, HTTP+WS)"]
|
|
69
|
+
AGENTHOST["AgentHost (host/agent-host.ts, FIFO fan-out)"]
|
|
70
|
+
AGENTSESS["agent-sessions.ts + attached-projects.ts"]
|
|
71
|
+
SCAN["/__server-scan (dev-server-scanner.ts)"]
|
|
72
|
+
PROXY["fetch-proxy-handler + websocket-proxy"]
|
|
73
|
+
RTHTTP["runtime HTTP + self-update (runtime-delivery.ts)"]
|
|
74
|
+
end
|
|
75
|
+
subgraph sim["sim page (browser / Electron, launched by a driver)"]
|
|
76
|
+
SHELLW["shell worker (iOS chrome, home grid, app switcher)"]
|
|
77
|
+
COMPOSITORW["compositor worker (app canvases + independent rAF)"]
|
|
78
|
+
TENANTW["tenant worker (guest RN app tree)"]
|
|
79
|
+
end
|
|
80
|
+
subgraph build["build-time plugins (src/)"]
|
|
81
|
+
VITEONE["rnxsim/vite = vite-plugin-one.ts (serve runtime at /__soot/)"]
|
|
82
|
+
VITERN["sootsim() = vite-plugin.ts (RN resolver + native stubs)"]
|
|
83
|
+
METRO["rnxsim/metro = metro-plugin.ts"]
|
|
84
|
+
COMPAT["@sootsim/compat stub-manifest (native seams)"]
|
|
85
|
+
ENGINESHIM["sootsim-engine react-native shim"]
|
|
86
|
+
end
|
|
87
|
+
SKILLS["rnxsim/skills registry.ts (builtin skills)"]
|
|
88
|
+
subgraph fs["~/.sootsim (home-paths.ts)"]
|
|
89
|
+
RTDIR["runtimes/<version>/ (engine assets)"]
|
|
90
|
+
LOCK["daemon.json lockfile"]
|
|
91
|
+
CFG["config.json"]
|
|
92
|
+
end
|
|
93
|
+
CDN["contrast.dev CDN (runtimes/manifest.json + tarballs)"]
|
|
94
|
+
BIN --> SETUP
|
|
95
|
+
BIN --> RUNTIMECMD
|
|
96
|
+
BIN --> INSPECT
|
|
97
|
+
BIN --> FLOW
|
|
98
|
+
BIN --> DETOXCMD
|
|
99
|
+
BIN --> SHOTS
|
|
100
|
+
BIN --> AGENTCMD
|
|
101
|
+
SETUP --> LOCK
|
|
102
|
+
SETUP -->|"register launchd/systemd"| HOST
|
|
103
|
+
RUNTIMECMD --> RTDIR
|
|
104
|
+
RUNTIMECMD -->|"fetch runtime"| CDN
|
|
105
|
+
INSPECT --> WSB
|
|
106
|
+
FLOW --> WSB
|
|
107
|
+
SHOTS --> WSB
|
|
108
|
+
AGENTCMD --> WSB
|
|
109
|
+
DETOXCMD --> DRIVERS
|
|
110
|
+
DETOXCMD --> WSB
|
|
111
|
+
WSB -->|"JSON WS cmds"| HOST
|
|
112
|
+
HOST -->|"forward to registered sim"| SHELLW
|
|
113
|
+
SHELLW -->|"replies + pushes"| HOST
|
|
114
|
+
HOST -->|"relayed results"| WSB
|
|
115
|
+
HOST --> AGENTHOST
|
|
116
|
+
AGENTHOST --> AGENTSESS
|
|
117
|
+
AGENTCMD --> AGENTHOST
|
|
118
|
+
HOST --> SCAN
|
|
119
|
+
HOST --> PROXY
|
|
120
|
+
HOST --> RTHTTP
|
|
121
|
+
RTHTTP --> RTDIR
|
|
122
|
+
RTHTTP -->|"manifest + tarball"| CDN
|
|
123
|
+
DRIVERS -->|"open sim page URL"| SHELLW
|
|
124
|
+
SHELLW -->|"NativeUIRequest"| TENANTW
|
|
125
|
+
VITEONE -->|"serve /__soot/ from"| RTDIR
|
|
126
|
+
METRO -->|"serve /__soot/ from"| RTDIR
|
|
127
|
+
VITEONE -.->|"launch electron app"| SHELLW
|
|
128
|
+
VITERN -->|"alias react-native"| ENGINESHIM
|
|
129
|
+
VITERN -->|"alias native pkgs"| COMPAT
|
|
130
|
+
VITERN -->|"dev server hosts"| HOST
|
|
131
|
+
SKILLS --> INSPECT
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**The CLI process** (`cli/bin.ts`) parses argv, emits invocation telemetry, and
|
|
135
|
+
lazy-imports exactly one command module per run. Bare `rnxsim` and
|
|
136
|
+
`rnxsim setup` own guided one-time machine work: ask which package manager you
|
|
137
|
+
use for app commands, explain repo-pinned Node versions, recommend a global
|
|
138
|
+
`rnxsim` install, and install the faster background daemon when it is
|
|
139
|
+
missing. `rnxsim open`
|
|
140
|
+
ensures the engine runtime exists and starts a local foreground bridge when no
|
|
141
|
+
daemon is reachable, then opens a `WsBridge` (`cli/ws-bridge.ts`) on **port
|
|
142
|
+
7668** and sends JSON commands. Inspection/interaction verbs live in
|
|
143
|
+
`cli/commands/inspect/*` and are re-exported as the programmatic `rnxsim/sdk`;
|
|
144
|
+
the Maestro runner is `cli/bridge-flow-runner.ts`; the Detox compat driver
|
|
145
|
+
is in `detox/`. Test and screenshot paths additionally use `cli/drivers/*`.
|
|
146
|
+
Browser sims launch in an isolated Playwright Chrome for Testing profile;
|
|
147
|
+
Electron is the native desktop surface.
|
|
148
|
+
|
|
149
|
+
**The daemon is one process** — `SootSimBridgeHost` (`src/host/bridge-host.ts`).
|
|
150
|
+
`rnxsim serve` runs it in the foreground; the background daemon is the *same
|
|
151
|
+
process* wrapped with autostart and the `~/.sootsim/daemon.json` lockfile. It is
|
|
152
|
+
an HTTP+WS hub: sims register over WS, CLI clients connect to drive them, and
|
|
153
|
+
the host forwards each command to the targeted sim and relays the reply back. It
|
|
154
|
+
also serves the engine runtime over HTTP (with a self-update route), exposes
|
|
155
|
+
`/__server-scan` to discover local metro/expo/vxrn/one dev servers, and proxies
|
|
156
|
+
guest-app fetch/WebSocket traffic so the cross-origin tenant worker can reach
|
|
157
|
+
localhost. The `AgentHost` extension owns one FIFO reader per agent session and
|
|
158
|
+
fans agent events out to every subscriber.
|
|
159
|
+
|
|
160
|
+
**The sim** is a browser/Electron *page* launched by a CLI driver. Inside that
|
|
161
|
+
page run three workers: the **shell worker** owns device and native state, the
|
|
162
|
+
**compositor worker** paints every visible CanvasKit surface, and the **tenant
|
|
163
|
+
worker** runs the guest RN tree and sends native-UI requests to the shell. The
|
|
164
|
+
bridge always addresses the **shell worker**, never an undifferentiated sim.
|
|
165
|
+
|
|
166
|
+
**Two distinct plugin families** round it out, and they must not be conflated:
|
|
167
|
+
|
|
168
|
+
- The published **`rnxsim/vite`** (`src/vite-plugin-one.ts`, `sootsimPlugin`)
|
|
169
|
+
and **`rnxsim/metro`** plugins do one thing: serve the installed runtime at
|
|
170
|
+
`/__soot/` so an app's own dev server can host the sim shell (the vite plugin
|
|
171
|
+
can also launch the Electron app).
|
|
172
|
+
- The internal **`sootsim()`** plugin (`src/vite-plugin.ts`) is a separate, much
|
|
173
|
+
larger RN-resolution / native-stub plugin: it aliases `react-native` to the
|
|
174
|
+
engine shim and native packages to `@sootsim/compat` stubs, applies worklets
|
|
175
|
+
transforms, and is the one that instantiates `SootSimBridgeHost` inside its
|
|
176
|
+
own dev server. It is used to build the engine/shell and to load external RN
|
|
177
|
+
apps — it is **not** the published `rnxsim/vite` export.
|
|
178
|
+
|
|
179
|
+
## Key components
|
|
180
|
+
|
|
181
|
+
| component | role | key files |
|
|
182
|
+
| --- | --- | --- |
|
|
183
|
+
| rnxsim CLI (bin + dispatcher) | Short-lived terminal entry point. Parses argv, emits telemetry, lazy-imports one command per run, and routes guided setup/open/runtime/inspection flows without a hidden bootstrap path. | `cli/bin.ts`, `cli/parse-args.ts`, `cli/help.ts`, `cli/commands/setup.ts`, `cli/commands/control.ts` |
|
|
184
|
+
| 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` |
|
|
185
|
+
| 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` |
|
|
186
|
+
| 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` |
|
|
187
|
+
| 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` |
|
|
188
|
+
| SootSimBridgeHost (serve/daemon) | The bridge process (`rnxsim 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` |
|
|
189
|
+
| 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` |
|
|
190
|
+
| 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` |
|
|
191
|
+
| 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 `~/.sootsim/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`, `scripts/postinstall.cjs` |
|
|
192
|
+
| `rnxsim/vite` + `rnxsim/metro` (runtime serving) | Published bundler plugins. Both serve the installed engine runtime at `/__soot/` from `~/.sootsim/runtimes/<version>` so an app's own dev server can host the sim shell; the vite plugin can also launch the Electron app. | `src/vite-plugin-one.ts`, `src/metro-plugin.ts`, `src/runtime-assets.ts` |
|
|
193
|
+
| `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` |
|
|
194
|
+
| skills registry | rnx agent skills (`rnx-setup`, `rnx-debug`, `rnx-test`, `rnx-visual`, and the generated `contrast` index) installable with `rnxsim skill`. | `skills/*.md`, `src/skills/registry.ts`, `src/skills/types.ts` |
|
|
195
|
+
|
|
196
|
+
## Getting started
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
curl -fsSL https://rnxsim.com/install.sh | sh
|
|
200
|
+
rnxsim setup # guided one-time machine setup
|
|
201
|
+
rnxsim open 8081 # load a running metro/expo dev server
|
|
202
|
+
rnxsim open /settings # dispatch a React Native deep link into that app
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The first `sootsim open` launches an isolated Chrome for Testing sim. The CLI
|
|
206
|
+
resolves Playwright from the app or CLI install, asks that exact package for
|
|
207
|
+
its required browser executable, and runs that package's installer once when
|
|
208
|
+
the executable is absent. It never substitutes another revision found in the
|
|
209
|
+
shared Playwright cache. Later opens reuse that sim and reload it at the
|
|
210
|
+
requested target. Use `sootsim do reload` when the target has not changed.
|
|
211
|
+
Reserve `--new` for a genuinely concurrent sim; repeated new browser trees
|
|
212
|
+
consume memory and CPU on shared machines.
|
|
213
|
+
|
|
214
|
+
The public shell script is the recommended, inspectable bootstrap path;
|
|
215
|
+
`rnxsim` is the normal path afterward. Manual installs can use `npm install
|
|
216
|
+
--global rnxsim`, `bun add --global rnxsim`, or `pnpm add --global rnxsim`,
|
|
217
|
+
followed by `rnxsim setup`. There is no per-app install:
|
|
218
|
+
start your Metro, Expo, or One dev server the way you already do, then open it
|
|
219
|
+
from the CLI. There is no iOS native build in the inner loop; Metro alone is
|
|
220
|
+
enough. `rnxsim open` starts a local bridge when no daemon is reachable; the
|
|
221
|
+
guided setup installs the faster background daemon so later CLI commands reuse
|
|
222
|
+
one server. A desktop GUI (Electron) is optional on top, via `rnxsim desktop
|
|
223
|
+
install`. Native Electron windows created by `rnxsim open` belong to that CLI
|
|
224
|
+
session and close when the session exits; `rnxsim desktop` keeps the persistent
|
|
225
|
+
desktop-app lifecycle. In Electron, `File > New Window`
|
|
226
|
+
duplicates the focused simulator, while `File > New Simulator >` opens a new
|
|
227
|
+
window for a selected device (same device list as the `Window >` menu).
|
|
228
|
+
|
|
229
|
+
To uninstall the machine daemon and cached runtimes, run
|
|
230
|
+
`rnxsim daemon uninstall`. It stops current and legacy launchd / systemd
|
|
231
|
+
services, removes daemon logs, and removes `~/.sootsim/` (runtimes, profiles,
|
|
232
|
+
recordings, and lockfiles). It does not remove the optional
|
|
233
|
+
`/Applications/sootsim.app` desktop bundle or macOS preference plist. To inspect
|
|
234
|
+
existing disk usage before uninstalling, run `rnxsim cleanup`; add `--apply`
|
|
235
|
+
only after reviewing the preview.
|
|
236
|
+
|
|
237
|
+
## Jump to source in inspect mode
|
|
238
|
+
|
|
239
|
+
Inspect mode can open a selected React Native element in your editor when the
|
|
240
|
+
bundle includes source metadata. Add the optional Babel plugin to your app's
|
|
241
|
+
Metro/Babel config:
|
|
242
|
+
|
|
243
|
+
```js
|
|
244
|
+
plugins: [
|
|
245
|
+
[
|
|
246
|
+
'rnxsim/jump-to-source-babel',
|
|
247
|
+
{
|
|
248
|
+
include: [__dirname],
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
'react-native-worklets/plugin',
|
|
252
|
+
]
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The plugin adds an `srcloc="/absolute/path/App.tsx:12:3"` prop to JSX elements
|
|
256
|
+
outside `node_modules`, `dist`, and `build`. Keep it before
|
|
257
|
+
`react-native-worklets/plugin` in a custom Babel stack that lists both plugins.
|
|
258
|
+
Apps using `babel-preset-expo` omit the explicit Worklets plugin because the
|
|
259
|
+
preset configures it automatically.
|
|
260
|
+
|
|
261
|
+
## CLI
|
|
262
|
+
|
|
263
|
+
The CLI is the primary debugging surface for rnx — use it first for runtime
|
|
264
|
+
inspection, interaction, animation debugging, shell tracing, screenshots, and
|
|
265
|
+
flow capture, not just as a test runner.
|
|
266
|
+
|
|
267
|
+
```sh
|
|
268
|
+
rnxsim list # connected tabs
|
|
269
|
+
rnxsim open 8081 # load a running metro/expo dev server
|
|
270
|
+
rnxsim open /settings # route via React Native Linking
|
|
271
|
+
rnxsim describe # dump UI tree
|
|
272
|
+
rnxsim get errors 5 # recent runtime failures
|
|
273
|
+
rnxsim compat # scan native package compatibility
|
|
274
|
+
rnxsim report-issue "…" # preview an opt-in compatibility report
|
|
275
|
+
rnxsim find --testid cta # inspect one node deeply
|
|
276
|
+
rnxsim debug enable animated,layout
|
|
277
|
+
rnxsim debug trace shell on 240
|
|
278
|
+
rnxsim do tap-text "..." # interact
|
|
279
|
+
rnxsim debug snapshot before
|
|
280
|
+
rnxsim debug snapshot after
|
|
281
|
+
rnxsim debug diff before after
|
|
282
|
+
rnxsim maestro start # begin a Maestro draft
|
|
283
|
+
rnxsim maestro keep # persist the last action
|
|
284
|
+
rnxsim maestro end --output .maestro/login.yaml --validate
|
|
285
|
+
rnxsim detox # run Detox/Jest suites against rnx
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
See the full command reference via `rnxsim --help` or at
|
|
289
|
+
`src/features/site/docs/rnx/cli/` in the Contrast repo.
|
|
290
|
+
|
|
291
|
+
Sim-scoped commands use the primary fallback only when one driveable sim is
|
|
292
|
+
connected. With multiple driveable sims, the bridge lists their ids and refuses
|
|
293
|
+
to choose. Run `rnxsim use <id>` to pin later commands, or pass `--sim <id>` to
|
|
294
|
+
target one command.
|
|
295
|
+
|
|
296
|
+
## Bundler plugins (`rnxsim/vite` and `rnxsim/metro`)
|
|
297
|
+
|
|
298
|
+
These serve the installed engine runtime from your own dev server. They do
|
|
299
|
+
**not** resolve React Native or stub native modules — that is the internal
|
|
300
|
+
`sootsim()` plugin's job (see Architecture).
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
// vite.config.ts
|
|
304
|
+
import { sootsimPlugin } from 'rnxsim/vite'
|
|
305
|
+
|
|
306
|
+
export default {
|
|
307
|
+
plugins: [sootsimPlugin()],
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
// metro.config.js
|
|
313
|
+
const { withSootsim } = require('rnxsim/metro')
|
|
314
|
+
|
|
315
|
+
module.exports = withSootsim({ /* your metro config */ })
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Coming from Detox
|
|
319
|
+
|
|
320
|
+
rnx ships a drop-in Detox driver. Existing Detox test files
|
|
321
|
+
(`import { by, element, expect, device } from 'detox'`) run against rnx with
|
|
322
|
+
no code changes — just add one line to your jest config:
|
|
323
|
+
|
|
324
|
+
```js
|
|
325
|
+
// jest config
|
|
326
|
+
{ preset: 'rnxsim/detox/jest-preset' }
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Or use the CLI directly:
|
|
330
|
+
|
|
331
|
+
```sh
|
|
332
|
+
rnxsim detox # auto-discovers e2e/ tests and launches a shell
|
|
333
|
+
rnxsim detox init # scaffold a config + sample test
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
See `../../docs/migrating-from-detox.md` for details.
|
|
337
|
+
|
|
338
|
+
## Coming from Maestro
|
|
339
|
+
|
|
340
|
+
Maestro is rnx's single YAML test surface. Point it at your existing
|
|
341
|
+
`.maestro/` directory, generate a test, or author one from live actions:
|
|
342
|
+
|
|
343
|
+
```sh
|
|
344
|
+
rnxsim maestro # discover .maestro/ and run all flows
|
|
345
|
+
rnxsim maestro test .maestro/ # explicit
|
|
346
|
+
rnxsim maestro generate "verify login"
|
|
347
|
+
rnxsim maestro --list-compat # see the verb support matrix
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Most Maestro verbs work out of the box (`tapOn`, `assertVisible`, `inputText`,
|
|
351
|
+
`scrollUntilVisible`, `launchApp`, `when:`, `repeat`, `runFlow`, …). Verbs that
|
|
352
|
+
need real device hardware (GPS, radio, photo library) throw a clear error. See
|
|
353
|
+
`../../docs/migrating-from-maestro.md` for the full compat matrix.
|
|
354
|
+
|
|
355
|
+
## Screenshots and recordings
|
|
356
|
+
|
|
357
|
+
For animation-heavy debugging, the useful path is usually:
|
|
358
|
+
|
|
359
|
+
```sh
|
|
360
|
+
rnxsim debug enable animated
|
|
361
|
+
rnxsim debug trace shell on 240
|
|
362
|
+
rnxsim debug snapshot before
|
|
363
|
+
# reproduce the transition
|
|
364
|
+
rnxsim debug snapshot after
|
|
365
|
+
rnxsim debug diff before after
|
|
366
|
+
rnxsim screenshot --with-frame --output /tmp/sootsim-framed.png
|
|
367
|
+
rnxsim record --duration 5 --output /tmp/sootsim-anim.mp4
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`rnxsim screenshot --with-frame` composes the real rnx shell device chrome
|
|
371
|
+
around the raw screen bitmap (reusing the shell bezel/button geometry, excluding
|
|
372
|
+
the Electron top bar, rail gutter, and other window chrome). Flows can request
|
|
373
|
+
the framed export inline without changing Maestro syntax:
|
|
374
|
+
|
|
375
|
+
`rnxsim wait ready` and the screenshot readiness guard accept inspectable
|
|
376
|
+
native content, a populated node tree, or a live-frame channel whose publish
|
|
377
|
+
count advances across probes. Canvas-only GL, WebGPU, and video surfaces can
|
|
378
|
+
therefore prove that they are painting without weakening the boot-card guard.
|
|
379
|
+
|
|
380
|
+
```yaml
|
|
381
|
+
- takeScreenshot: hero
|
|
382
|
+
- takeScreenshot:
|
|
383
|
+
path: marketing/hero
|
|
384
|
+
withFrame: true
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
For plan-driven app-store exports, use `rnxsim screenshot appstore`:
|
|
388
|
+
|
|
389
|
+
```yaml
|
|
390
|
+
app: 8081
|
|
391
|
+
device: iphone-14
|
|
392
|
+
|
|
393
|
+
capture:
|
|
394
|
+
flow: .maestro/capture-app-store-screenshots.yaml
|
|
395
|
+
mode: raw+framed
|
|
396
|
+
|
|
397
|
+
compose:
|
|
398
|
+
canvases: [iphone-6-9, iphone-6-1]
|
|
399
|
+
background: cyan
|
|
400
|
+
text:
|
|
401
|
+
preset: bold-top
|
|
402
|
+
slides:
|
|
403
|
+
- id: splash-hero
|
|
404
|
+
screenshot: apple/iphone/en/01-splash.png
|
|
405
|
+
headline: First punch.
|
|
406
|
+
subheadline: Every pick in one place.
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
```sh
|
|
410
|
+
rnxsim screenshot appstore --plan .sootsim/app-store.yaml
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
The plan runner can reuse a visible sim for capture (`--sim a9`), stop after
|
|
414
|
+
raw/framed intermediates (`--capture-only`), or rerender final marketing
|
|
415
|
+
canvases from an existing raw directory (`--compose-only`). If your flow already
|
|
416
|
+
writes screenshots to explicit project paths, set `from:` + `pathMode: flow` so
|
|
417
|
+
`rnxsim screenshot appstore` respects the flow's own `takeScreenshot` paths
|
|
418
|
+
instead of prepending `--screenshots <rawDir>`:
|
|
419
|
+
|
|
420
|
+
```yaml
|
|
421
|
+
capture:
|
|
422
|
+
flow: .maestro/capture-app-store-screenshots.yaml
|
|
423
|
+
from: ./apps/app-store-screenshots/public/screenshots/apple/iphone/en
|
|
424
|
+
pathMode: flow
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
In the browser shell, `Screenshot Mode` turns the live shell into a simple DOM
|
|
428
|
+
composition surface: the rail + mac menu bar disappear, the device shifts down
|
|
429
|
+
with a short transition, and editable title/subtitle fields appear above the
|
|
430
|
+
frame for quick art-direction passes.
|
|
431
|
+
|
|
432
|
+
## Skills registry
|
|
433
|
+
|
|
434
|
+
`rnxsim skill install` installs rnx agent skills in the standard
|
|
435
|
+
`<skill-name>/SKILL.md` layout used by Codex and Claude Code. The bundled
|
|
436
|
+
skills cover setup, debugging/perf/accessibility, testing, visual review, and
|
|
437
|
+
the generated `contrast` command index. The published CLI registry and generated
|
|
438
|
+
website docs both come from `packages/sootsim-skills/`:
|
|
439
|
+
|
|
440
|
+
- `packages/sootsim/skills/contrast/SKILL.md` is generated from that registry
|
|
441
|
+
- `src/features/site/docs/rnx/cli/*` is generated output, not hand-edited
|
|
442
|
+
|
|
443
|
+
When command docs or examples drift, update `packages/sootsim-skills/` and run:
|
|
444
|
+
|
|
445
|
+
```sh
|
|
446
|
+
bun run generate:sootsim-docs
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Runtime delivery (the rnx home and CDN)
|
|
450
|
+
|
|
451
|
+
The engine never ships inside this package. `runtime-delivery.ts` names
|
|
452
|
+
rnx's CDN origin (default `https://contrast.dev`, overridable in
|
|
453
|
+
`config.json`), its `SOOTSIM_*` env overrides, and its hosted paths, then hands
|
|
454
|
+
them to the shared delivery machinery in `@contrast/runtime-delivery` — an
|
|
455
|
+
internal workspace package the CLI bundles, so a published install has it
|
|
456
|
+
inlined. That machinery fetches `runtimes/manifest.json` + the runtime tarball,
|
|
457
|
+
verifies its sha256, and unpacks it under `~/.sootsim`:
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
~/.sootsim/
|
|
461
|
+
├── runtimes/
|
|
462
|
+
│ ├── <active>/ unpacked engine assets (served at /__soot/)
|
|
463
|
+
│ └── <rollback>/ previous version for rollback
|
|
464
|
+
├── cache/ legacy downloads; empty after cleanup
|
|
465
|
+
├── profiles/ persistent named app storage, without browser caches
|
|
466
|
+
├── electron/userData/ desktop app storage, with bounded browser caches
|
|
467
|
+
├── daemon.json lockfile: pid, ports, active runtime, heartbeat
|
|
468
|
+
├── automatic-cleanup-v1.json completed legacy cleanup generation
|
|
469
|
+
└── config.json user prefs: update channel, cdn origin override
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
The bridge daemon serves these assets over HTTP and exposes a self-update route;
|
|
473
|
+
`rnxsim upgrade` / `rnxsim runtime` drive explicit version changes from the
|
|
474
|
+
CLI side. Installation retains the active runtime plus one rollback and removes
|
|
475
|
+
the downloaded archive after extraction. Disposable Playwright caches live in a
|
|
476
|
+
bounded per-session temporary directory; Electron's persistent HTTP cache is
|
|
477
|
+
disabled for simulator profiles and globally capped for app chrome. Cookies,
|
|
478
|
+
localStorage, IndexedDB, service workers, recordings, and captured frames are
|
|
479
|
+
user-owned data and are not removed by the default cleanup command.
|
|
480
|
+
|
|
481
|
+
Per-repo configuration is optional. Every installed-runtime `rnxsim open`
|
|
482
|
+
serves its selected version from a version-specific localhost origin, so a
|
|
483
|
+
background activation cannot mix an already loaded shell with chunks from the
|
|
484
|
+
next runtime. Without config, each new open selects the active stable version.
|
|
485
|
+
When `sootsim.config.ts` sets `runtimeVersion`, `rnxsim open` installs that
|
|
486
|
+
version without changing the machine default. Running from a monorepo root
|
|
487
|
+
resolves the only React Native app from package workspaces, then shares that app
|
|
488
|
+
root across config, font, and splash discovery. The fallback scan is bounded and
|
|
489
|
+
prunes dependency, build, native, fixture, and example trees.
|
|
490
|
+
|
|
491
|
+
The first interactive CLI command after this cleanup generation finishes its
|
|
492
|
+
requested work, then launches the same safe default plan in a detached
|
|
493
|
+
maintenance process. The app and terminal command are usable before the legacy
|
|
494
|
+
filesystem scan begins. The worker prints the reclaimed size to stderr, records
|
|
495
|
+
completion, and does not run the scan again. Open browser profiles and a runtime
|
|
496
|
+
served by a live daemon or development bridge are left untouched. The automatic
|
|
497
|
+
pass retries on a later command after they close. The explicit `rnxsim cleanup --aggressive`
|
|
498
|
+
command remains the only path that removes the rollback runtime or user-created
|
|
499
|
+
recordings.
|
|
500
|
+
|
|
501
|
+
## Development and building
|
|
502
|
+
|
|
503
|
+
This package is part of the Contrast monorepo. To build the published CLI bundle:
|
|
504
|
+
|
|
505
|
+
```sh
|
|
506
|
+
bun run build:cli
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
The output is `dist-cli/bin.js` — a single esbuild output published as the
|
|
510
|
+
`rnxsim` npm bin. Library exports build to `dist-lib/` (consumed via the
|
|
511
|
+
`exports` map: `.`, `./vite`, `./metro`, `./sdk`, `./skills`, `./detox`, and the
|
|
512
|
+
host/agent helpers). `bun run pack:smoke` validates the publishable tarball.
|
package/detox/colors.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// re-export color utilities from kitchen-sink for convenience
|
|
2
|
+
// these are the same implementations used in detox tests
|
|
3
|
+
|
|
4
|
+
import * as fs from 'fs'
|
|
5
|
+
import { PNG } from 'pngjs'
|
|
6
|
+
|
|
7
|
+
export type RGB = { r: number; g: number; b: number }
|
|
8
|
+
|
|
9
|
+
export function getDominantColor(screenshotPath: string): RGB {
|
|
10
|
+
const data = fs.readFileSync(screenshotPath)
|
|
11
|
+
const png = PNG.sync.read(data)
|
|
12
|
+
|
|
13
|
+
const startX = Math.floor(png.width * 0.25)
|
|
14
|
+
const endX = Math.floor(png.width * 0.75)
|
|
15
|
+
const startY = Math.floor(png.height * 0.25)
|
|
16
|
+
const endY = Math.floor(png.height * 0.75)
|
|
17
|
+
|
|
18
|
+
let totalR = 0,
|
|
19
|
+
totalG = 0,
|
|
20
|
+
totalB = 0,
|
|
21
|
+
count = 0
|
|
22
|
+
|
|
23
|
+
for (let y = startY; y < endY; y++) {
|
|
24
|
+
for (let x = startX; x < endX; x++) {
|
|
25
|
+
const idx = (png.width * y + x) * 4
|
|
26
|
+
totalR += png.data[idx]
|
|
27
|
+
totalG += png.data[idx + 1]
|
|
28
|
+
totalB += png.data[idx + 2]
|
|
29
|
+
count++
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
r: Math.round(totalR / count),
|
|
35
|
+
g: Math.round(totalG / count),
|
|
36
|
+
b: Math.round(totalB / count),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isBlueish(color: RGB): boolean {
|
|
41
|
+
return color.b > 100 && color.b > color.r && color.b > color.g
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isReddish(color: RGB): boolean {
|
|
45
|
+
return color.r > 100 && color.r > color.b && color.r > color.g
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isGreenish(color: RGB): boolean {
|
|
49
|
+
return color.g > 100 && color.g > color.r && color.g > color.b
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function formatRGB(color: RGB): string {
|
|
53
|
+
return `RGB(${color.r}, ${color.g}, ${color.b})`
|
|
54
|
+
}
|