rnxsim 0.1.375 → 0.1.377
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -25
- package/cli/app-config.ts +9 -12
- package/cli/app-fonts.ts +3 -3
- package/cli/app-project.ts +8 -8
- package/cli/auth.ts +7 -9
- package/cli/bin.ts +16 -31
- package/cli/bridge-flow-runner.ts +3 -3
- package/cli/browser-backend.ts +44 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +291 -0
- package/cli/commands/agent-wrapper.ts +2 -2
- package/cli/commands/app-fonts.ts +2 -2
- package/cli/commands/assert.ts +3 -3
- package/cli/commands/auth.ts +1 -1
- package/cli/commands/box/cloud-box.ts +1 -1
- package/cli/commands/box/plane-share.ts +2 -2
- package/cli/commands/box.ts +4 -6
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +42 -28
- package/cli/commands/cpu-profile.ts +7 -7
- package/cli/commands/daemon-mac-app.ts +7 -7
- package/cli/commands/daemon.ts +10 -10
- package/cli/commands/debug.ts +11 -11
- package/cli/commands/detox.ts +13 -13
- package/cli/commands/diagnose.ts +6 -6
- package/cli/commands/do-chain.ts +1 -2
- package/cli/commands/electron.ts +1 -3
- package/cli/commands/film.ts +3 -3
- package/cli/commands/flow.ts +43 -43
- package/cli/commands/inspect/count.ts +1 -1
- package/cli/commands/inspect/describe.ts +1 -1
- package/cli/commands/inspect/env.ts +2 -2
- package/cli/commands/inspect/get-layout.ts +1 -1
- package/cli/commands/inspect/keyboard.ts +1 -1
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/memory.ts +1 -1
- package/cli/commands/inspect/resolve-target.ts +1 -1
- package/cli/commands/inspect/screens.ts +1 -1
- package/cli/commands/inspect/tree.ts +1 -1
- package/cli/commands/inspect/url.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +5 -5
- package/cli/commands/inspect.ts +34 -34
- package/cli/commands/install-desktop.ts +3 -3
- package/cli/commands/login.ts +6 -6
- package/cli/commands/maestro-generate.ts +5 -5
- package/cli/commands/maestro.ts +5 -5
- package/cli/commands/profile.ts +1 -1
- package/cli/commands/record.ts +9 -9
- package/cli/commands/runtime.ts +18 -18
- package/cli/commands/screenshot-command.ts +1 -1
- package/cli/commands/screenshot-layers.ts +5 -5
- package/cli/commands/screenshot-mode.ts +1 -1
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +5 -5
- package/cli/commands/serve.ts +3 -3
- package/cli/commands/setup.ts +20 -12
- package/cli/commands/skills.ts +5 -5
- package/cli/commands/slides.ts +1 -1
- package/cli/commands/telemetry.ts +1 -1
- package/cli/commands/three-mode.ts +1 -1
- package/cli/commands/timeline.ts +8 -8
- package/cli/commands/upgrade.ts +116 -131
- package/cli/commands/upload.ts +12 -12
- package/cli/commands/version.ts +7 -7
- package/cli/commands/what-happened.ts +9 -9
- package/cli/current-sim.ts +3 -3
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/playwright.ts +9 -9
- package/cli/drivers/registry.ts +1 -1
- package/cli/drivers/types.ts +1 -1
- package/cli/flow-file.ts +2 -2
- package/cli/flow-session.ts +1 -1
- package/cli/help-core.ts +136 -0
- package/cli/help.ts +17 -53
- package/cli/hints.ts +5 -5
- package/cli/inspect-notice-state.ts +1 -1
- package/cli/maestro-js.ts +1 -1
- package/cli/outbound-endpoints.ts +23 -5
- package/cli/parse-args.ts +19 -66
- package/cli/recording-access.ts +1 -1
- package/cli/registry.ts +1 -0
- package/cli/run-registry.ts +1 -1
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +6 -9
- package/cli/runtime-notes.ts +3 -3
- package/cli/standalone.ts +4 -0
- package/cli/ws-bridge.ts +8 -8
- package/detox/config-loader.ts +2 -2
- package/detox/index.ts +8 -8
- package/detox/jest-preset.cjs +1 -1
- package/detox/navigation.ts +2 -2
- package/dist-lib/agent-daemon-client.cjs +5 -5
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +2 -2
- package/dist-lib/agent-sessions.cjs +10 -10
- package/dist-lib/attached-projects.cjs +6 -6
- package/dist-lib/auth/shared-session.cjs +6 -6
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +25 -25
- package/dist-lib/detox/index.cjs +9 -9
- package/dist-lib/detox/jest-preset.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +29 -29
- package/dist-lib/host/bridge-host.cjs +274 -181
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +14 -14
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +8 -8
- package/dist-lib/profiles.cjs +12 -12
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +25 -11
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +470 -322
- package/dist-lib/vite.cjs +9 -9
- package/package.json +4 -11
- package/scripts/dev-server-scanner.ts +25 -7
- package/scripts/optional-demo-registry.ts +1 -1
- package/skills/contrast/SKILL.md +3 -3
- package/skills/rnx-debug/SKILL.md +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/agent-identity.ts +1 -1
- package/src/agent-sessions.ts +7 -5
- package/src/cli-version.ts +12 -4
- package/src/config.ts +26 -28
- package/src/disk-cleanup.ts +11 -11
- package/src/home-paths.ts +28 -28
- package/src/host/bridge-host.ts +16 -16
- package/src/metro-plugin.ts +2 -2
- package/src/profiles.ts +2 -2
- package/src/runtime-assets.ts +7 -7
- package/src/runtime-delivery.ts +13 -13
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/skills/builtin/a11y-review.ts +2 -2
- package/src/skills/builtin/compat-check.ts +2 -2
- package/src/skills/builtin/maestro-test.ts +2 -2
- package/src/skills/builtin/perf-profile.ts +2 -2
- package/src/skills/builtin/screenshot-all.ts +2 -2
- package/src/skills/builtin/visual-diff.ts +2 -2
- package/src/skills/registry.ts +8 -8
- package/src/skills/types.ts +1 -1
- package/src/vite-plugin-one.ts +3 -3
- package/src/vite-plugin.ts +15 -2
- package/dist-cli/bin.js +0 -15
- package/dist-cli/chunks/agent-JJN7U6FR.js +0 -48
- package/dist-cli/chunks/agent-wrapper-AVVUJ3WF.js +0 -17
- package/dist-cli/chunks/app-fonts-QJ22CNAZ.js +0 -4
- package/dist-cli/chunks/assert-PZZKIY3K.js +0 -49
- package/dist-cli/chunks/auth-5AVDJO33.js +0 -12
- package/dist-cli/chunks/beta-PFRGP266.js +0 -4
- package/dist-cli/chunks/box-ILC2O7ZO.js +0 -1730
- package/dist-cli/chunks/camera-J3V62PP7.js +0 -33
- package/dist-cli/chunks/chunk-25KRGDZT.js +0 -4
- package/dist-cli/chunks/chunk-2BRBFLWA.js +0 -38
- package/dist-cli/chunks/chunk-2GXNAZHB.js +0 -74
- package/dist-cli/chunks/chunk-2IUMRRYV.js +0 -7
- package/dist-cli/chunks/chunk-4ALPWIMP.js +0 -10
- package/dist-cli/chunks/chunk-4CEZZKRY.js +0 -4
- package/dist-cli/chunks/chunk-4EUKOIAV.js +0 -4
- package/dist-cli/chunks/chunk-4IKE4YUS.js +0 -32
- package/dist-cli/chunks/chunk-4ZXR2M3D.js +0 -4
- package/dist-cli/chunks/chunk-5CGJFU27.js +0 -7
- package/dist-cli/chunks/chunk-5HHWECGT.js +0 -4
- package/dist-cli/chunks/chunk-5PZVYF42.js +0 -312
- package/dist-cli/chunks/chunk-7NCPUZ52.js +0 -27
- package/dist-cli/chunks/chunk-7OSIJCBR.js +0 -107
- package/dist-cli/chunks/chunk-AQ5TMOAI.js +0 -4
- package/dist-cli/chunks/chunk-BQCEI37V.js +0 -5
- package/dist-cli/chunks/chunk-C6B5FOP3.js +0 -4
- package/dist-cli/chunks/chunk-CCMZSHJB.js +0 -71
- package/dist-cli/chunks/chunk-CX7VCKAT.js +0 -14
- package/dist-cli/chunks/chunk-DQUPSAHE.js +0 -4
- package/dist-cli/chunks/chunk-DSD2UBZI.js +0 -4
- package/dist-cli/chunks/chunk-EWPAI4MO.js +0 -7
- package/dist-cli/chunks/chunk-EZXV6U2N.js +0 -497
- package/dist-cli/chunks/chunk-F5F7FIPM.js +0 -6
- package/dist-cli/chunks/chunk-FUTYK55H.js +0 -30
- package/dist-cli/chunks/chunk-FW6AN7I2.js +0 -3
- package/dist-cli/chunks/chunk-FZDRA7Z4.js +0 -4
- package/dist-cli/chunks/chunk-GDLE4NIV.js +0 -4
- package/dist-cli/chunks/chunk-GEX7RVHY.js +0 -5
- package/dist-cli/chunks/chunk-H4MYYOYJ.js +0 -5
- package/dist-cli/chunks/chunk-HEV7BAPE.js +0 -11
- package/dist-cli/chunks/chunk-HNDWYCND.js +0 -506
- package/dist-cli/chunks/chunk-HNPHODBD.js +0 -4
- package/dist-cli/chunks/chunk-HWDVC6YA.js +0 -11
- package/dist-cli/chunks/chunk-JOHJZUGG.js +0 -4
- package/dist-cli/chunks/chunk-JWUDT4QK.js +0 -5
- package/dist-cli/chunks/chunk-K7QQWKGE.js +0 -4
- package/dist-cli/chunks/chunk-LAOKTKT4.js +0 -4
- package/dist-cli/chunks/chunk-LD7I266X.js +0 -24
- package/dist-cli/chunks/chunk-LMHBU5LZ.js +0 -4
- package/dist-cli/chunks/chunk-LSOGXSDV.js +0 -535
- package/dist-cli/chunks/chunk-MP2GPO4T.js +0 -4
- package/dist-cli/chunks/chunk-MXJ2UWRV.js +0 -4
- package/dist-cli/chunks/chunk-OJNKRIZF.js +0 -15
- package/dist-cli/chunks/chunk-PBOWUNXO.js +0 -4
- package/dist-cli/chunks/chunk-PNRJFHX4.js +0 -4
- package/dist-cli/chunks/chunk-QJQOK34O.js +0 -28
- package/dist-cli/chunks/chunk-RLCQLMFF.js +0 -142
- package/dist-cli/chunks/chunk-S65CK3RI.js +0 -9
- package/dist-cli/chunks/chunk-SWBUNMQS.js +0 -4
- package/dist-cli/chunks/chunk-SXBFGGAM.js +0 -4
- package/dist-cli/chunks/chunk-T4ISWS5H.js +0 -4
- package/dist-cli/chunks/chunk-TPPVAA7Z.js +0 -5
- package/dist-cli/chunks/chunk-USM3P74H.js +0 -4
- package/dist-cli/chunks/chunk-V4EJJHF5.js +0 -4
- package/dist-cli/chunks/chunk-V7RGRZOL.js +0 -423
- package/dist-cli/chunks/chunk-XUBV77WH.js +0 -130
- package/dist-cli/chunks/chunk-XYSDYGKC.js +0 -4
- package/dist-cli/chunks/chunk-YNHRSDVG.js +0 -5
- package/dist-cli/chunks/chunk-YX52RJKO.js +0 -4
- package/dist-cli/chunks/chunk-Z5O5H4O7.js +0 -99
- package/dist-cli/chunks/chunk-Z6LOIW46.js +0 -7
- package/dist-cli/chunks/chunk-ZXFVBYJY.js +0 -5
- package/dist-cli/chunks/cleanup-KPUW4SFK.js +0 -25
- package/dist-cli/chunks/cli-version-APGT6GAT.js +0 -4
- package/dist-cli/chunks/compat-XXRFD2TW.js +0 -23
- package/dist-cli/chunks/config-DDMFDQ7F.js +0 -13
- package/dist-cli/chunks/connect-IPG47YXM.js +0 -4
- package/dist-cli/chunks/control-O22Z3UJ5.js +0 -4
- package/dist-cli/chunks/daemon-PADUIMJV.js +0 -4
- package/dist-cli/chunks/debug-MYIP46TM.js +0 -200
- package/dist-cli/chunks/desktop-ENFFBQAA.js +0 -31
- package/dist-cli/chunks/detox-J5WVK6OH.js +0 -52
- package/dist-cli/chunks/device-RAVQVL75.js +0 -18
- package/dist-cli/chunks/diagnose-PJMPXKJY.js +0 -43
- package/dist-cli/chunks/disk-cleanup-YLAY445J.js +0 -4
- package/dist-cli/chunks/do-chain-UBE7GIOU.js +0 -5
- package/dist-cli/chunks/drivers-ZFNX3T5Z.js +0 -4
- package/dist-cli/chunks/env-Y5XJSNRD.js +0 -4
- package/dist-cli/chunks/film-W3V6VURB.js +0 -74
- package/dist-cli/chunks/flow-VMLI7BYM.js +0 -4
- package/dist-cli/chunks/help-PKZCWHJJ.js +0 -4
- package/dist-cli/chunks/hidden-runtime-alias-S5DJ7EDF.js +0 -4
- package/dist-cli/chunks/home-paths-5O4IZPYV.js +0 -4
- package/dist-cli/chunks/inspect-LT4MXK37.js +0 -4
- package/dist-cli/chunks/install-desktop-EXCFMXFS.js +0 -4
- package/dist-cli/chunks/login-V6TZ54ZH.js +0 -26
- package/dist-cli/chunks/logout-SPMLFWYA.js +0 -4
- package/dist-cli/chunks/maestro-5ISTBAZE.js +0 -108
- package/dist-cli/chunks/maestro-generate-WUI64NHR.js +0 -36
- package/dist-cli/chunks/mode-QPNBYXUF.js +0 -26
- package/dist-cli/chunks/optional-demo-registry-CBSYF4CG.js +0 -4
- package/dist-cli/chunks/perf-T6N5PVYV.js +0 -48
- package/dist-cli/chunks/permissions-YZ7RRSZJ.js +0 -13
- package/dist-cli/chunks/platform-XDQAA72X.js +0 -6
- package/dist-cli/chunks/privacy-54FIGXLT.js +0 -4
- package/dist-cli/chunks/record-QGYXRUKP.js +0 -72
- package/dist-cli/chunks/report-issue-VUUTGX7V.js +0 -29
- package/dist-cli/chunks/reset-CGO52KBW.js +0 -4
- package/dist-cli/chunks/resolve-target-NNQCALDM.js +0 -4
- package/dist-cli/chunks/runtime-4EP6YJVL.js +0 -4
- package/dist-cli/chunks/screenshot-command-NZCMSJ4P.js +0 -159
- package/dist-cli/chunks/screenshot-layers-VMTQ6XIU.js +0 -20
- package/dist-cli/chunks/screenshots-capture-K3MWIDBK.js +0 -42
- package/dist-cli/chunks/serve-QJRIB2BV.js +0 -56
- package/dist-cli/chunks/setup-6XXEJQVF.js +0 -4
- package/dist-cli/chunks/sim-client-5YUVL45C.js +0 -4
- package/dist-cli/chunks/skills-T3CS7CXK.js +0 -50
- package/dist-cli/chunks/state-AJC3VK3G.js +0 -14
- package/dist-cli/chunks/storage-KVGZKC3Y.js +0 -37
- package/dist-cli/chunks/store-AWUMOQUH.js +0 -4
- package/dist-cli/chunks/telemetry-W5ZDGWK6.js +0 -4
- package/dist-cli/chunks/timeline-DXDCAZUA.js +0 -24
- package/dist-cli/chunks/upgrade-SRPTJACU.js +0 -7
- package/dist-cli/chunks/upload-ZDV4BFED.js +0 -4
- package/dist-cli/chunks/version-SOLPSBMG.js +0 -6
- package/dist-cli/chunks/web-RT75LD7A.js +0 -4
- package/dist-cli/chunks/welcome-IJ55EC7U.js +0 -5
- package/dist-cli/chunks/what-happened-CEIWJIWK.js +0 -25
- package/dist-cli/chunks/ws-bridge-YK5R3HOI.js +0 -4
- package/scripts/postinstall.cjs +0 -3
- package/scripts/preuninstall.cjs +0 -118
package/src/home-paths.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// canonical filesystem layout under ~/.
|
|
1
|
+
// canonical filesystem layout under ~/.rnx/. shared by the CLI and the
|
|
2
2
|
// electron main process so every surface agrees where runtimes, the daemon
|
|
3
3
|
// lockfile, and caches live.
|
|
4
4
|
//
|
|
5
|
-
// ~/.
|
|
5
|
+
// ~/.rnx/
|
|
6
6
|
// ├── runtimes/
|
|
7
7
|
// │ ├── <version>/ unpacked dist/ of sootsim-engine
|
|
8
8
|
// │ └── active text file with the active version string (win-safe
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// ├── profiles/
|
|
13
13
|
// │ └── profiles.json storage profile metadata
|
|
14
14
|
// ├── cache/
|
|
15
|
-
// │ └──
|
|
15
|
+
// │ └── rnx-runtime-<version>.tar.gz
|
|
16
16
|
// ├── daemon.json lockfile: pid, ports, active runtime, heartbeat
|
|
17
17
|
// ├── dev-bridges/ live Vite dev bridge records, keyed by bound port
|
|
18
18
|
// ├── runtime-upgraded.json one-shot notice written by the daemon's
|
|
@@ -28,17 +28,17 @@ import fs from 'node:fs'
|
|
|
28
28
|
import { homedir } from 'node:os'
|
|
29
29
|
import path from 'node:path'
|
|
30
30
|
|
|
31
|
-
export const
|
|
31
|
+
export const RNX_HOME_ENV = 'RNX_HOME'
|
|
32
32
|
export const ACTIVE_RUNTIME_FILE = 'active'
|
|
33
33
|
export const DAEMON_LOCKFILE = 'daemon.json'
|
|
34
34
|
export const DEV_BRIDGES_DIR = 'dev-bridges'
|
|
35
35
|
export const CONFIG_FILE = 'config.json'
|
|
36
36
|
export const DAEMON_HEARTBEAT_STALE_MS = 30_000
|
|
37
37
|
|
|
38
|
-
export function
|
|
39
|
-
const override = process.env[
|
|
38
|
+
export function rnxHomeDir(): string {
|
|
39
|
+
const override = process.env[RNX_HOME_ENV]
|
|
40
40
|
if (override && override.length > 0) return path.resolve(override)
|
|
41
|
-
return path.join(homedir(), '.
|
|
41
|
+
return path.join(homedir(), '.rnx')
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// detect when sootsim is running from a source checkout (the Contrast monorepo)
|
|
@@ -101,7 +101,7 @@ export function shouldSkipPersistentDaemon(): boolean {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
export function runtimesDir(): string {
|
|
104
|
-
return path.join(
|
|
104
|
+
return path.join(rnxHomeDir(), 'runtimes')
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export function runtimeDir(version: string): string {
|
|
@@ -113,7 +113,7 @@ export function activeRuntimeFile(): string {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
export function electronDir(): string {
|
|
116
|
-
return path.join(
|
|
116
|
+
return path.join(rnxHomeDir(), 'electron')
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
export function electronUserDataDir(): string {
|
|
@@ -125,14 +125,14 @@ export function electronVersionDir(version: string): string {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export function profilesDir(): string {
|
|
128
|
-
return path.join(
|
|
128
|
+
return path.join(rnxHomeDir(), 'profiles')
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
// video fixtures staged for `rnx camera play`. the CLI copies the user's
|
|
132
132
|
// file in here and the daemon serves it by basename from this one directory,
|
|
133
133
|
// so the route can never be talked into reading anywhere else on disk.
|
|
134
134
|
export function cameraFixturesDir(): string {
|
|
135
|
-
return path.join(
|
|
135
|
+
return path.join(rnxHomeDir(), 'camera-fixtures')
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// the launchd-managed daemon spawns ProgramArguments[0] directly, and macOS
|
|
@@ -142,27 +142,27 @@ export function cameraFixturesDir(): string {
|
|
|
142
142
|
// an ad-hoc-signed .app bundle here gives BTM a CFBundleDisplayName to
|
|
143
143
|
// read instead.
|
|
144
144
|
export function daemonAppDir(): string {
|
|
145
|
-
return path.join(
|
|
145
|
+
return path.join(rnxHomeDir(), 'daemon-app')
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
export function daemonAppBundlePath(): string {
|
|
149
|
-
return path.join(daemonAppDir(), '
|
|
149
|
+
return path.join(daemonAppDir(), 'RNX Daemon.app')
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
export function daemonAppLauncherPath(): string {
|
|
153
|
-
return path.join(daemonAppBundlePath(), 'Contents', 'MacOS', '
|
|
153
|
+
return path.join(daemonAppBundlePath(), 'Contents', 'MacOS', 'rnx-daemon')
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
export function cacheDir(): string {
|
|
157
|
-
return path.join(
|
|
157
|
+
return path.join(rnxHomeDir(), 'cache')
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
export function daemonLockfilePath(): string {
|
|
161
|
-
return path.join(
|
|
161
|
+
return path.join(rnxHomeDir(), DAEMON_LOCKFILE)
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
export function devBridgesDir(): string {
|
|
165
|
-
return path.join(
|
|
165
|
+
return path.join(rnxHomeDir(), DEV_BRIDGES_DIR)
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
export function devBridgeLockfilePath(bridgePort: number): string {
|
|
@@ -173,12 +173,12 @@ export function devBridgeLockfilePath(bridgePort: number): string {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
export function configFilePath(): string {
|
|
176
|
-
return path.join(
|
|
176
|
+
return path.join(rnxHomeDir(), CONFIG_FILE)
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
// --- shared
|
|
179
|
+
// --- shared rnx config ---------------------------------------------------
|
|
180
180
|
//
|
|
181
|
-
// ~/.
|
|
181
|
+
// ~/.rnx/config.json is the single user-level config file every rnx
|
|
182
182
|
// surface (cli, electron renderer, dev browser via electron ipc) agrees on.
|
|
183
183
|
//
|
|
184
184
|
// privacy preferences live in the nested settings object so the cli, desktop
|
|
@@ -207,7 +207,7 @@ export function readSharedConfig(): SharedConfig {
|
|
|
207
207
|
* objects (currently just `settings`) are shallow-merged so partial writes
|
|
208
208
|
* don't clobber unrelated fields. returns the new full snapshot. */
|
|
209
209
|
export function writeSharedConfig(patch: Partial<SharedConfig>): SharedConfig {
|
|
210
|
-
|
|
210
|
+
ensureRnxHome()
|
|
211
211
|
const current = readSharedConfig()
|
|
212
212
|
const next: SharedConfig = { ...current, ...patch }
|
|
213
213
|
if (patch.settings && typeof patch.settings === 'object') {
|
|
@@ -300,11 +300,11 @@ export interface RuntimeUpgradeNotice {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
export function runtimeUpgradeNoticePath(): string {
|
|
303
|
-
return path.join(
|
|
303
|
+
return path.join(rnxHomeDir(), 'runtime-upgraded.json')
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
export function writeRuntimeUpgradeNotice(notice: RuntimeUpgradeNotice): void {
|
|
307
|
-
|
|
307
|
+
ensureRnxHome()
|
|
308
308
|
const tmp = `${runtimeUpgradeNoticePath()}.tmp`
|
|
309
309
|
fs.writeFileSync(tmp, `${JSON.stringify(notice)}\n`, 'utf8')
|
|
310
310
|
fs.renameSync(tmp, runtimeUpgradeNoticePath())
|
|
@@ -328,8 +328,8 @@ export function consumeRuntimeUpgradeNotice(): RuntimeUpgradeNotice | null {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
-
export function
|
|
332
|
-
fs.mkdirSync(
|
|
331
|
+
export function ensureRnxHome(): void {
|
|
332
|
+
fs.mkdirSync(rnxHomeDir(), { recursive: true })
|
|
333
333
|
fs.mkdirSync(runtimesDir(), { recursive: true })
|
|
334
334
|
fs.mkdirSync(electronDir(), { recursive: true })
|
|
335
335
|
fs.mkdirSync(profilesDir(), { recursive: true })
|
|
@@ -434,7 +434,7 @@ interface DaemonClaim {
|
|
|
434
434
|
export function readDaemonLockfile(): DaemonLockfile | null {
|
|
435
435
|
try {
|
|
436
436
|
// cap the read so a junk/large file on the lockfile path can't OOM
|
|
437
|
-
// the CLI when someone has been messing with ~/.
|
|
437
|
+
// the CLI when someone has been messing with ~/.rnx/.
|
|
438
438
|
const fd = fs.openSync(daemonLockfilePath(), 'r')
|
|
439
439
|
try {
|
|
440
440
|
const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES)
|
|
@@ -577,7 +577,7 @@ export function readLiveRuntimeVersions(): string[] {
|
|
|
577
577
|
}
|
|
578
578
|
|
|
579
579
|
export function writeDaemonLockfile(data: DaemonLockfile): void {
|
|
580
|
-
|
|
580
|
+
ensureRnxHome()
|
|
581
581
|
const lockfilePath = daemonLockfilePath()
|
|
582
582
|
const existing = readDaemonLockfile()
|
|
583
583
|
if (!existing) {
|
|
@@ -723,7 +723,7 @@ function releaseDaemonClaim(owner: Pick<DaemonLockfile, 'pid' | 'startedAt'>): v
|
|
|
723
723
|
* process-owned election file serializes concurrent fallback-port binds;
|
|
724
724
|
* the complete lock snapshot is then installed with an exclusive hard link. */
|
|
725
725
|
export function claimDaemonLockfile(data: DaemonLockfile): boolean {
|
|
726
|
-
|
|
726
|
+
ensureRnxHome()
|
|
727
727
|
if (!acquireDaemonClaim(data)) return false
|
|
728
728
|
try {
|
|
729
729
|
const existing = readDaemonLockfile()
|
package/src/host/bridge-host.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { getCliVersion } from '../cli-version.ts'
|
|
|
16
16
|
import {
|
|
17
17
|
activeRuntimeDir as getActiveRuntimeDir,
|
|
18
18
|
claimDaemonLockfile,
|
|
19
|
-
|
|
19
|
+
ensureRnxHome,
|
|
20
20
|
isSootsimDevCheckout,
|
|
21
21
|
readActiveRuntime,
|
|
22
22
|
readSharedConfig,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
writeRuntimeUpgradeNotice,
|
|
29
29
|
writeSharedConfig,
|
|
30
30
|
cameraFixturesDir,
|
|
31
|
-
|
|
31
|
+
rnxHomeDir,
|
|
32
32
|
type DaemonLockfile,
|
|
33
33
|
type DevBridgeLockfile,
|
|
34
34
|
type SharedConfig,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
resolveRuntimeRootForHostname,
|
|
40
40
|
runtimeVersionFromHostname,
|
|
41
41
|
} from '../runtime-assets.ts'
|
|
42
|
-
import {
|
|
42
|
+
import { rnxRuntime } from '../runtime-delivery.ts'
|
|
43
43
|
import { AgentHost, type AgentHostOptions } from './agent-host.ts'
|
|
44
44
|
import {
|
|
45
45
|
handleAppApiRequest,
|
|
@@ -226,13 +226,13 @@ export interface BridgeHostOptions {
|
|
|
226
226
|
/** try preferred port, then port+1, port+2, …, up to this many attempts
|
|
227
227
|
* before giving up. defaults to 10. set 1 to disable fallback. */
|
|
228
228
|
portFallbackCount?: number
|
|
229
|
-
/** when true, write ~/.
|
|
229
|
+
/** when true, write ~/.rnx/daemon.json on successful bind + update
|
|
230
230
|
* it on a heartbeat interval + remove it on close. only the standalone
|
|
231
231
|
* `sootsim serve` process should set this — tests, vite plugin, and
|
|
232
232
|
* anything embedded should leave it off to avoid clobbering a real
|
|
233
233
|
* daemon's lockfile. defaults to false. */
|
|
234
234
|
writeLockfile?: boolean
|
|
235
|
-
/** when true, write an owner-scoped record under ~/.
|
|
235
|
+
/** when true, write an owner-scoped record under ~/.rnx/dev-bridges on
|
|
236
236
|
* successful bind, update it on a heartbeat interval, and remove only that
|
|
237
237
|
* record on close. the Vite dev shell sets this so local CLI commands can
|
|
238
238
|
* address every live source bridge without concurrent worktrees replacing
|
|
@@ -303,7 +303,7 @@ const HTTP_MIME_TYPES: Record<string, string> = {
|
|
|
303
303
|
'.mov': 'video/quicktime',
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
// `rnx camera play` stages a video under ~/.
|
|
306
|
+
// `rnx camera play` stages a video under ~/.rnx/camera-fixtures and the
|
|
307
307
|
// simulator plays it as the camera feed. the route below serves that one
|
|
308
308
|
// directory, addressed by basename only.
|
|
309
309
|
const CAMERA_FIXTURE_ROUTE = '/__camera-fixtures/'
|
|
@@ -313,7 +313,7 @@ const CAMERA_FIXTURE_ROUTE = '/__camera-fixtures/'
|
|
|
313
313
|
const CAMERA_FIXTURE_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/
|
|
314
314
|
|
|
315
315
|
/** inject host-provided globals into the served runtime html:
|
|
316
|
-
* - `window.__sootsimSharedConfig` — parsed `~/.
|
|
316
|
+
* - `window.__sootsimSharedConfig` — parsed `~/.rnx/config.json`,
|
|
317
317
|
* read during engine settingsStore module init (see
|
|
318
318
|
* settings/persistence.ts). mirrors the inject-into-html plugin in the
|
|
319
319
|
* shell vite dev server so dev and prod surfaces both produce it.
|
|
@@ -684,7 +684,7 @@ export class SootSimBridgeHost {
|
|
|
684
684
|
// are handled in-daemon; install runs entirely inside the CLI so
|
|
685
685
|
// we don't need a daemon-side handler for it.
|
|
686
686
|
if (msg.type === 'runtime:list') {
|
|
687
|
-
const versions =
|
|
687
|
+
const versions = rnxRuntime.listInstalled()
|
|
688
688
|
const active = this.getActiveRuntime()
|
|
689
689
|
const reply = {
|
|
690
690
|
type: 'runtime:list:ok',
|
|
@@ -700,7 +700,7 @@ export class SootSimBridgeHost {
|
|
|
700
700
|
}
|
|
701
701
|
if (msg.type === 'runtime:use') {
|
|
702
702
|
const version = typeof msg.version === 'string' ? msg.version : ''
|
|
703
|
-
const installed =
|
|
703
|
+
const installed = rnxRuntime.listInstalled()
|
|
704
704
|
if (!installed.includes(version)) {
|
|
705
705
|
try {
|
|
706
706
|
ws.send(
|
|
@@ -809,7 +809,7 @@ export class SootSimBridgeHost {
|
|
|
809
809
|
return
|
|
810
810
|
}
|
|
811
811
|
|
|
812
|
-
// write a partial patch into ~/.
|
|
812
|
+
// write a partial patch into ~/.rnx/config.json. fired by the
|
|
813
813
|
// engine's settingsStore when a persisted key flips in a browser
|
|
814
814
|
// tab (which has no fs access of its own). after the merge, we
|
|
815
815
|
// broadcast the new full snapshot to every connected sim so any
|
|
@@ -1140,7 +1140,7 @@ export class SootSimBridgeHost {
|
|
|
1140
1140
|
|
|
1141
1141
|
if (this.shouldWriteLockfile) {
|
|
1142
1142
|
try {
|
|
1143
|
-
|
|
1143
|
+
ensureRnxHome()
|
|
1144
1144
|
// atomic claim: bail if another fresh daemon's lockfile already
|
|
1145
1145
|
// exists (stale ones are overwritten). last line of defense
|
|
1146
1146
|
// against two daemons clobbering the same file between the
|
|
@@ -1289,7 +1289,7 @@ export class SootSimBridgeHost {
|
|
|
1289
1289
|
}
|
|
1290
1290
|
|
|
1291
1291
|
// serves one staged camera fixture. addressed by basename inside
|
|
1292
|
-
// ~/.
|
|
1292
|
+
// ~/.rnx/camera-fixtures, never by a caller-supplied path, so there is
|
|
1293
1293
|
// no traversal surface to defend: a name that is not a plain basename is
|
|
1294
1294
|
// rejected outright. range support is not optional here — chrome asks for
|
|
1295
1295
|
// byte ranges on media and cannot seek or loop a fixture without it.
|
|
@@ -1409,14 +1409,14 @@ export class SootSimBridgeHost {
|
|
|
1409
1409
|
|
|
1410
1410
|
private startRuntimeUpdater() {
|
|
1411
1411
|
if (!this.shouldWriteLockfile || this.runtimeUpdateTimer) return
|
|
1412
|
-
if (fs.existsSync(path.join(
|
|
1413
|
-
// an isolated dev daemon (explicit
|
|
1412
|
+
if (fs.existsSync(path.join(rnxHomeDir(), 'runtime-update-disabled'))) return
|
|
1413
|
+
// an isolated dev daemon (explicit RNX_HOME, dev checkout, nothing
|
|
1414
1414
|
// staged) serves the repo's public/sootsim build. auto-installing the
|
|
1415
1415
|
// published runtime here would stage it active and shadow that dev build
|
|
1416
1416
|
// (runtime-assets prefers a staged runtime under an explicit home), so the
|
|
1417
1417
|
// daemon would silently validate published code instead of the checkout.
|
|
1418
1418
|
// local-publish writes the marker above when it stages a source build.
|
|
1419
|
-
if (process.env.
|
|
1419
|
+
if (process.env.RNX_HOME && isSootsimDevCheckout() && !readActiveRuntime()) {
|
|
1420
1420
|
return
|
|
1421
1421
|
}
|
|
1422
1422
|
void this.runRuntimeUpdate('startup')
|
|
@@ -1434,7 +1434,7 @@ export class SootSimBridgeHost {
|
|
|
1434
1434
|
if (reason === 'startup') {
|
|
1435
1435
|
process.stderr.write('rnx: checking for runtime updates…\n')
|
|
1436
1436
|
}
|
|
1437
|
-
const result = await
|
|
1437
|
+
const result = await rnxRuntime.updateToLatest({
|
|
1438
1438
|
protectVersions: this.connectedRuntimeVersions(),
|
|
1439
1439
|
})
|
|
1440
1440
|
if (!result.updated || !result.latestVersion) {
|
package/src/metro-plugin.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// rnx metro plugin for opt-in dev shell and production bundle integration.
|
|
2
|
-
// shell assets come from an engine runtime under ~/.
|
|
2
|
+
// shell assets come from an engine runtime under ~/.rnx/runtimes/, fetched
|
|
3
3
|
// by `rnx runtime install`. ordinary localhost requests
|
|
4
4
|
// follow active; a version-owned localhost origin stays on its exact directory
|
|
5
5
|
// when active changes, so one loaded shell cannot mix runtime chunk trees.
|
|
@@ -423,7 +423,7 @@ export function withRNX<T extends Record<string, unknown>>(
|
|
|
423
423
|
},
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
if (appName && !process.env.CI && !process.env.
|
|
426
|
+
if (appName && !process.env.CI && !process.env.RNX_NO_OPEN) {
|
|
427
427
|
void openRnxDesktopWhenMetroIsReady({
|
|
428
428
|
port,
|
|
429
429
|
bundleUrl: resolveRnxDesktopLaunchTarget(port, bundleUrl),
|
package/src/profiles.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
2
|
import path from 'path'
|
|
3
|
-
import { electronUserDataDir,
|
|
3
|
+
import { electronUserDataDir, ensureRnxHome, profilesDir } from './home-paths'
|
|
4
4
|
|
|
5
5
|
export const DEFAULT_PROFILE_ID = 'default'
|
|
6
6
|
const PROFILE_INDEX_FILE = 'profiles.json'
|
|
@@ -105,7 +105,7 @@ function withDefault(index: ProfileIndex): ProfileIndex {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
function writeIndex(index: ProfileIndex): ProfileIndex {
|
|
108
|
-
|
|
108
|
+
ensureRnxHome()
|
|
109
109
|
const next = withDefault(index)
|
|
110
110
|
const tmp = `${profileIndexPath()}.tmp`
|
|
111
111
|
fs.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}\n`, 'utf8')
|
package/src/runtime-assets.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// helpers for serving the installed sootsim engine runtime from framework
|
|
2
2
|
// dev servers. the runtime is managed by `sootsim runtime install` and lives
|
|
3
|
-
// under ~/.
|
|
3
|
+
// under ~/.rnx/runtimes/<version>.
|
|
4
4
|
|
|
5
5
|
import fs from 'fs'
|
|
6
6
|
import path from 'path'
|
|
@@ -20,13 +20,13 @@ export const SOOTSIM_RUNTIME_MISSING_MESSAGE =
|
|
|
20
20
|
// boundary, not a preference or a runtime fallback chain — the check is
|
|
21
21
|
// structural (the monorepo layout is present next to this module) and
|
|
22
22
|
// deterministic (the dev build's files exist). it exists because the daemon and
|
|
23
|
-
// the /__soot plugin otherwise serve ~/.
|
|
23
|
+
// the /__soot plugin otherwise serve ~/.rnx/runtimes/<active>, a PUBLISHED
|
|
24
24
|
// runtime that `bun dev` never refreshes, so local engine edits are invisible
|
|
25
25
|
// until a manual publish — the silent trap that cost a full night of
|
|
26
26
|
// already-fixed bugs re-reproducing.
|
|
27
27
|
//
|
|
28
28
|
// the isolated CI headless path (scripts/local-publish-runtime.sh) sets
|
|
29
|
-
//
|
|
29
|
+
// RNX_HOME to a dedicated dir precisely to validate the published-runtime
|
|
30
30
|
// code path; keying off that EXISTING isolation env keeps it (and packaged
|
|
31
31
|
// electron with a custom home) on the installed runtime.
|
|
32
32
|
let _monorepoRootCache: string | null | undefined
|
|
@@ -52,16 +52,16 @@ function findMonorepoRoot(): string | null {
|
|
|
52
52
|
|
|
53
53
|
/** the fresh dev-stack engine build to serve when running inside the Contrast
|
|
54
54
|
* monorepo dev checkout, or null when the installed runtime should serve
|
|
55
|
-
* (published CLI, packaged electron, or an isolated
|
|
55
|
+
* (published CLI, packaged electron, or an isolated RNX_HOME). */
|
|
56
56
|
export function resolveDevCheckoutRuntimeRoot(): string | null {
|
|
57
57
|
// an explicit home that has a STAGED/active runtime is the isolation the
|
|
58
58
|
// CI/local-publish path sets up to validate the installed-runtime code path —
|
|
59
59
|
// honor that staged runtime. an explicit home with NO active runtime is just
|
|
60
|
-
// an isolated dev daemon (own lockfile, doesn't clobber ~/.
|
|
61
|
-
// still wants the dev build; and the default home (
|
|
60
|
+
// an isolated dev daemon (own lockfile, doesn't clobber ~/.rnx), which
|
|
61
|
+
// still wants the dev build; and the default home (RNX_HOME unset) always
|
|
62
62
|
// does. keying on "explicit home + a runtime deliberately staged there" keeps
|
|
63
63
|
// it structural, not a bespoke toggle.
|
|
64
|
-
if (process.env.
|
|
64
|
+
if (process.env.RNX_HOME && readActiveRuntime()) return null
|
|
65
65
|
const root = findMonorepoRoot()
|
|
66
66
|
if (!root) return null
|
|
67
67
|
const devBuild = path.join(root, 'public/sootsim')
|
package/src/runtime-delivery.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
//
|
|
1
|
+
// rnx's binding of the shared runtime-delivery machinery.
|
|
2
2
|
//
|
|
3
3
|
// the machinery itself (hosted manifest, sha256-verified tarballs, channels,
|
|
4
4
|
// channel resolution, and auto-update) lives in @contrast/runtime-delivery and
|
|
5
|
-
// knows nothing about
|
|
6
|
-
//
|
|
5
|
+
// knows nothing about rnx. this file supplies rnx's identity, public env
|
|
6
|
+
// overrides, and the contrast.dev/runtimes hosting layout.
|
|
7
7
|
//
|
|
8
8
|
// @contrast/runtime-delivery is an internal workspace package that is never
|
|
9
9
|
// published, so both the CLI bundle and dist-lib inline it (see the `alias`
|
|
@@ -14,7 +14,7 @@ import { createRuntimeDelivery, type RuntimeProduct } from '@contrast/runtime-de
|
|
|
14
14
|
import {
|
|
15
15
|
cacheDir,
|
|
16
16
|
configFilePath,
|
|
17
|
-
|
|
17
|
+
ensureRnxHome,
|
|
18
18
|
readActiveRuntime,
|
|
19
19
|
runtimeDir,
|
|
20
20
|
runtimesDir,
|
|
@@ -25,12 +25,12 @@ import { rnxPublicBrand } from './public-brand.ts'
|
|
|
25
25
|
export const DEFAULT_RUNTIME_CDN_ORIGIN = 'https://contrast.dev'
|
|
26
26
|
|
|
27
27
|
/** the official curated changelog and the machine-readable release feed. the
|
|
28
|
-
*
|
|
29
|
-
export const
|
|
30
|
-
export const
|
|
28
|
+
* rnx site is static, so its /api traffic is owned by contrast.dev. */
|
|
29
|
+
export const RNX_CHANGELOG_URL = `${rnxPublicBrand.origin}/changelog`
|
|
30
|
+
export const RNX_CHANGELOG_API_URL = 'https://contrast.dev/api/changelog/sootsim'
|
|
31
31
|
|
|
32
|
-
export const
|
|
33
|
-
id: '
|
|
32
|
+
export const RNX_RUNTIME_PRODUCT: RuntimeProduct = {
|
|
33
|
+
id: 'rnx',
|
|
34
34
|
defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
|
|
35
35
|
manifestPath: '/runtimes/manifest.json',
|
|
36
36
|
tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
|
|
@@ -39,10 +39,10 @@ export const SOOTSIM_RUNTIME_PRODUCT: RuntimeProduct = {
|
|
|
39
39
|
// vite/metro plugins serve, so its absence means the tarball is not one.
|
|
40
40
|
installedMarker: 'index.html',
|
|
41
41
|
env: {
|
|
42
|
-
cdnOrigin: '
|
|
43
|
-
channel: '
|
|
42
|
+
cdnOrigin: 'RNX_CDN_ORIGIN',
|
|
43
|
+
channel: 'RNX_RUNTIME_CHANNEL',
|
|
44
44
|
},
|
|
45
|
-
ensureHome:
|
|
45
|
+
ensureHome: ensureRnxHome,
|
|
46
46
|
configFile: configFilePath,
|
|
47
47
|
runtimesDir,
|
|
48
48
|
runtimeDir,
|
|
@@ -51,4 +51,4 @@ export const SOOTSIM_RUNTIME_PRODUCT: RuntimeProduct = {
|
|
|
51
51
|
writeActiveRuntime,
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
export const
|
|
54
|
+
export const rnxRuntime = createRuntimeDelivery(RNX_RUNTIME_PRODUCT)
|
|
@@ -244,7 +244,7 @@ export async function runScreenshotsPlanFromExistingRaw(
|
|
|
244
244
|
plan.capture.rawDir = rawDir
|
|
245
245
|
plan.capture.flowPath = null
|
|
246
246
|
plan.capture.fromDir = rawDir
|
|
247
|
-
const framedDir = path.join(tmpdir(), '
|
|
247
|
+
const framedDir = path.join(tmpdir(), 'rnx-screenshots-framed')
|
|
248
248
|
plan.capture.framedDir = framedDir
|
|
249
249
|
const framedSources = await buildFramedSources(plan)
|
|
250
250
|
const capture = writeCaptureManifest(plan, framedSources, plan.deviceModel)
|
|
@@ -246,7 +246,7 @@ export function loadScreenshotsPlan(planPath: string): NormalizedScreenshotsPlan
|
|
|
246
246
|
const deviceModel = readDeviceModel(root.device, null)
|
|
247
247
|
const captureOutDir = resolvePlanPath(
|
|
248
248
|
planDir,
|
|
249
|
-
readString(capture.out, path.join('.
|
|
249
|
+
readString(capture.out, path.join('.rnx', 'screenshots', 'capture')),
|
|
250
250
|
)
|
|
251
251
|
const captureFrom = readOptionalString(capture.from)
|
|
252
252
|
const flowPath = readOptionalString(capture.flow)
|
|
@@ -335,7 +335,7 @@ export function loadScreenshotsPlan(planPath: string): NormalizedScreenshotsPlan
|
|
|
335
335
|
compose: {
|
|
336
336
|
outDir: resolvePlanPath(
|
|
337
337
|
planDir,
|
|
338
|
-
readString(compose.out, path.join('.
|
|
338
|
+
readString(compose.out, path.join('.rnx', 'screenshots', 'exports')),
|
|
339
339
|
),
|
|
340
340
|
locale: readString(compose.locale, 'en'),
|
|
341
341
|
canvases: normalizeCanvasList(compose.canvases),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// built-in skill: accessibility audit
|
|
2
2
|
|
|
3
3
|
import { launchReapedChrome } from '../../../../../scripts/lib/reap-browser'
|
|
4
|
-
import type {
|
|
4
|
+
import type { RNXSkill } from '../types'
|
|
5
5
|
|
|
6
|
-
export const skill:
|
|
6
|
+
export const skill: RNXSkill = {
|
|
7
7
|
name: 'a11y-review',
|
|
8
8
|
description: 'Check the app for accessibility issues',
|
|
9
9
|
type: 'review',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// built-in skill: package compatibility check
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { RNXSkill } from '../types'
|
|
4
4
|
|
|
5
|
-
export const skill:
|
|
5
|
+
export const skill: RNXSkill = {
|
|
6
6
|
name: 'compat-check',
|
|
7
7
|
description: 'Check package compatibility with rnx',
|
|
8
8
|
type: 'review',
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// built-in skill: run Maestro tests against the app
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { RNXSkill } from '../types'
|
|
4
4
|
|
|
5
5
|
function sleep(ms: number) {
|
|
6
6
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export const skill:
|
|
9
|
+
export const skill: RNXSkill = {
|
|
10
10
|
name: 'maestro-test',
|
|
11
11
|
description: 'Run Maestro YAML tests against the app',
|
|
12
12
|
type: 'testing',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// built-in skill: performance profiling
|
|
2
2
|
|
|
3
3
|
import { launchReapedChrome } from '../../../../../scripts/lib/reap-browser'
|
|
4
|
-
import type {
|
|
4
|
+
import type { RNXSkill } from '../types'
|
|
5
5
|
|
|
6
6
|
interface OverlayProfile {
|
|
7
7
|
syncCount?: number
|
|
@@ -9,7 +9,7 @@ interface OverlayProfile {
|
|
|
9
9
|
[key: string]: unknown
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export const skill:
|
|
12
|
+
export const skill: RNXSkill = {
|
|
13
13
|
name: 'perf-profile',
|
|
14
14
|
description: 'Profile render performance of the app',
|
|
15
15
|
type: 'performance',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// built-in skill: capture all screens in light/dark mode
|
|
2
2
|
|
|
3
3
|
import { launchReapedChrome } from '../../../../../scripts/lib/reap-browser'
|
|
4
|
-
import type {
|
|
4
|
+
import type { RNXSkill } from '../types'
|
|
5
5
|
|
|
6
|
-
export const skill:
|
|
6
|
+
export const skill: RNXSkill = {
|
|
7
7
|
name: 'screenshot-all',
|
|
8
8
|
description: 'Capture screenshots of all screens in the app',
|
|
9
9
|
type: 'screenshot',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// built-in skill: visual diff against baselines
|
|
2
2
|
|
|
3
3
|
import { launchReapedChrome } from '../../../../../scripts/lib/reap-browser'
|
|
4
|
-
import type {
|
|
4
|
+
import type { RNXSkill } from '../types'
|
|
5
5
|
|
|
6
|
-
export const skill:
|
|
6
|
+
export const skill: RNXSkill = {
|
|
7
7
|
name: 'visual-diff',
|
|
8
8
|
description: 'Compare current rendering against baseline screenshots',
|
|
9
9
|
type: 'review',
|
package/src/skills/registry.ts
CHANGED
|
@@ -8,9 +8,9 @@ import { skill as maestroTestSkill } from './builtin/maestro-test'
|
|
|
8
8
|
import { skill as perfProfileSkill } from './builtin/perf-profile'
|
|
9
9
|
import { skill as screenshotAllSkill } from './builtin/screenshot-all'
|
|
10
10
|
import { skill as visualDiffSkill } from './builtin/visual-diff'
|
|
11
|
-
import type {
|
|
11
|
+
import type { RNXSkill, SkillContext } from './types'
|
|
12
12
|
|
|
13
|
-
const _skills: Map<string,
|
|
13
|
+
const _skills: Map<string, RNXSkill> = new Map()
|
|
14
14
|
const BUILTIN_SKILLS = [
|
|
15
15
|
a11yReviewSkill,
|
|
16
16
|
compatCheckSkill,
|
|
@@ -21,20 +21,20 @@ const BUILTIN_SKILLS = [
|
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
export const skillRegistry = {
|
|
24
|
-
register(skill:
|
|
24
|
+
register(skill: RNXSkill) {
|
|
25
25
|
_skills.set(skill.name, skill)
|
|
26
26
|
},
|
|
27
27
|
|
|
28
|
-
get(name: string):
|
|
28
|
+
get(name: string): RNXSkill | undefined {
|
|
29
29
|
return _skills.get(name)
|
|
30
30
|
},
|
|
31
31
|
|
|
32
|
-
listAll():
|
|
32
|
+
listAll(): RNXSkill[] {
|
|
33
33
|
return Array.from(_skills.values())
|
|
34
34
|
},
|
|
35
35
|
|
|
36
36
|
// match skills by natural language query against triggers
|
|
37
|
-
match(query: string):
|
|
37
|
+
match(query: string): RNXSkill[] {
|
|
38
38
|
const q = query.toLowerCase()
|
|
39
39
|
return this.listAll().filter((skill) =>
|
|
40
40
|
skill.triggers.some((trigger) => q.includes(trigger.toLowerCase())),
|
|
@@ -48,9 +48,9 @@ export const skillRegistry = {
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
|
|
51
|
-
// load skills from a project manifest (
|
|
51
|
+
// load skills from a project manifest (rnx-skills.json)
|
|
52
52
|
async loadFromManifest(projectDir: string) {
|
|
53
|
-
const manifestPath = path.join(projectDir, '
|
|
53
|
+
const manifestPath = path.join(projectDir, 'rnx-skills.json')
|
|
54
54
|
if (!fs.existsSync(manifestPath)) return
|
|
55
55
|
|
|
56
56
|
try {
|
package/src/skills/types.ts
CHANGED
package/src/vite-plugin-one.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// sootsim plugin for One/Vite — serves the installed sootsim runtime at /__soot/
|
|
2
|
-
// from ~/.
|
|
2
|
+
// from ~/.rnx/runtimes/<version>. version-owned localhost origins remain
|
|
3
3
|
// bound to that directory across an active-runtime update.
|
|
4
4
|
//
|
|
5
5
|
// usage in vite.config.ts:
|
|
@@ -36,7 +36,7 @@ export interface RnxPluginOptions {
|
|
|
36
36
|
// disable sootsim
|
|
37
37
|
enabled?: boolean
|
|
38
38
|
// launch the sootsim simulator loading this server's bundle once the dev
|
|
39
|
-
// server is listening. skipped when CI or
|
|
39
|
+
// server is listening. skipped when CI or RNX_NO_OPEN is set.
|
|
40
40
|
open?: RnxDesktopOpenOption
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -220,7 +220,7 @@ export function rnxPlugin(options: RnxPluginOptions = {}): Plugin {
|
|
|
220
220
|
const sootsimUrl = `http://localhost:${port}${prefix}/`
|
|
221
221
|
console.log(`[rnx] serving at ${sootsimUrl}`)
|
|
222
222
|
|
|
223
|
-
if (appName && !process.env.CI && !process.env.
|
|
223
|
+
if (appName && !process.env.CI && !process.env.RNX_NO_OPEN) {
|
|
224
224
|
server.httpServer?.once('listening', () => {
|
|
225
225
|
const openPort = listeningPort()
|
|
226
226
|
launchRnxDesktop(
|