rnxsim 0.1.376 → 0.1.378
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -25
- package/cli/app-config.ts +9 -12
- package/cli/app-fonts.ts +3 -3
- package/cli/app-project.ts +8 -8
- package/cli/auth.ts +7 -9
- package/cli/bin.ts +16 -31
- package/cli/bridge-flow-runner.ts +3 -3
- package/cli/browser-backend.ts +44 -0
- package/cli/command-contract.ts +221 -0
- package/cli/command-registry.ts +291 -0
- package/cli/commands/agent-wrapper.ts +2 -2
- package/cli/commands/app-fonts.ts +2 -2
- package/cli/commands/assert.ts +3 -3
- package/cli/commands/auth.ts +1 -1
- package/cli/commands/box/cloud-box.ts +1 -1
- package/cli/commands/box/plane-share.ts +2 -2
- package/cli/commands/box.ts +4 -6
- package/cli/commands/compat.ts +1 -1
- package/cli/commands/config.ts +2 -2
- package/cli/commands/control.ts +29 -29
- package/cli/commands/cpu-profile.ts +7 -7
- package/cli/commands/daemon-mac-app.ts +7 -7
- package/cli/commands/daemon.ts +10 -10
- package/cli/commands/debug.ts +11 -11
- package/cli/commands/detox.ts +13 -13
- package/cli/commands/diagnose.ts +6 -6
- package/cli/commands/do-chain.ts +1 -2
- package/cli/commands/electron.ts +1 -3
- package/cli/commands/film.ts +3 -3
- package/cli/commands/flow.ts +43 -43
- package/cli/commands/inspect/count.ts +1 -1
- package/cli/commands/inspect/describe.ts +1 -1
- package/cli/commands/inspect/env.ts +2 -2
- package/cli/commands/inspect/get-layout.ts +1 -1
- package/cli/commands/inspect/keyboard.ts +1 -1
- package/cli/commands/inspect/list.ts +1 -1
- package/cli/commands/inspect/memory.ts +1 -1
- package/cli/commands/inspect/resolve-target.ts +1 -1
- package/cli/commands/inspect/screens.ts +1 -1
- package/cli/commands/inspect/tree.ts +1 -1
- package/cli/commands/inspect/url.ts +1 -1
- package/cli/commands/inspect/wait-event.ts +5 -5
- package/cli/commands/inspect.ts +34 -34
- package/cli/commands/install-desktop.ts +3 -3
- package/cli/commands/login.ts +6 -6
- package/cli/commands/maestro-generate.ts +5 -5
- package/cli/commands/maestro.ts +5 -5
- package/cli/commands/profile.ts +1 -1
- package/cli/commands/record.ts +9 -9
- package/cli/commands/runtime.ts +18 -18
- package/cli/commands/screenshot-command.ts +1 -1
- package/cli/commands/screenshot-layers.ts +5 -5
- package/cli/commands/screenshot-mode.ts +1 -1
- package/cli/commands/screenshot.ts +8 -8
- package/cli/commands/screenshots-capture.ts +5 -5
- package/cli/commands/serve.ts +3 -3
- package/cli/commands/setup.ts +20 -12
- package/cli/commands/skills.ts +5 -5
- package/cli/commands/slides.ts +1 -1
- package/cli/commands/telemetry.ts +1 -1
- package/cli/commands/three-mode.ts +1 -1
- package/cli/commands/timeline.ts +8 -8
- package/cli/commands/upgrade.ts +116 -131
- package/cli/commands/upload.ts +12 -12
- package/cli/commands/version.ts +7 -7
- package/cli/commands/what-happened.ts +9 -9
- package/cli/current-sim.ts +3 -3
- package/cli/desktop-companion.ts +1 -1
- package/cli/drivers/playwright.ts +9 -9
- package/cli/drivers/registry.ts +1 -1
- package/cli/drivers/types.ts +1 -1
- package/cli/flow-file.ts +2 -2
- package/cli/flow-session.ts +1 -1
- package/cli/help-core.ts +136 -0
- package/cli/help.ts +17 -53
- package/cli/hints.ts +5 -5
- package/cli/inspect-notice-state.ts +1 -1
- package/cli/maestro-js.ts +1 -1
- package/cli/outbound-endpoints.ts +23 -5
- package/cli/parse-args.ts +19 -66
- package/cli/recording-access.ts +1 -1
- package/cli/registry.ts +1 -0
- package/cli/run-registry.ts +1 -1
- package/cli/run-rnx-core.ts +148 -0
- package/cli/run-rnx.ts +6 -9
- package/cli/runtime-notes.ts +3 -3
- package/cli/standalone.ts +4 -0
- package/cli/ws-bridge.ts +8 -8
- package/detox/config-loader.ts +2 -2
- package/detox/index.ts +8 -8
- package/detox/jest-preset.cjs +1 -1
- package/detox/navigation.ts +2 -2
- package/dist-lib/agent-daemon-client.cjs +5 -5
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +2 -2
- package/dist-lib/agent-sessions.cjs +10 -10
- package/dist-lib/attached-projects.cjs +6 -6
- package/dist-lib/auth/shared-session.cjs +6 -6
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +25 -25
- package/dist-lib/detox/index.cjs +73 -31
- package/dist-lib/detox/jest-preset.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +29 -29
- package/dist-lib/host/bridge-host.cjs +128 -49
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +14 -14
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +8 -8
- package/dist-lib/profiles.cjs +12 -12
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +8 -8
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +329 -160
- package/dist-lib/vite.cjs +9 -9
- package/package.json +4 -11
- package/scripts/dev-server-scanner.ts +2 -2
- package/scripts/optional-demo-registry.ts +1 -1
- package/skills/contrast/SKILL.md +3 -3
- package/skills/rnx-debug/SKILL.md +1 -1
- package/skills/rnx-test/SKILL.md +2 -2
- package/src/agent-identity.ts +1 -1
- package/src/agent-sessions.ts +7 -5
- package/src/cli-version.ts +12 -4
- package/src/config.ts +26 -28
- package/src/disk-cleanup.ts +11 -11
- package/src/home-paths.ts +28 -28
- package/src/host/bridge-host.ts +16 -16
- package/src/metro-plugin.ts +2 -2
- package/src/profiles.ts +2 -2
- package/src/runtime-assets.ts +7 -7
- package/src/runtime-delivery.ts +13 -13
- package/src/screenshots/orchestrate.ts +1 -1
- package/src/screenshots/schema.ts +2 -2
- package/src/skills/builtin/a11y-review.ts +2 -2
- package/src/skills/builtin/compat-check.ts +2 -2
- package/src/skills/builtin/maestro-test.ts +2 -2
- package/src/skills/builtin/perf-profile.ts +2 -2
- package/src/skills/builtin/screenshot-all.ts +2 -2
- package/src/skills/builtin/visual-diff.ts +2 -2
- package/src/skills/registry.ts +8 -8
- package/src/skills/types.ts +1 -1
- package/src/vite-plugin-one.ts +3 -3
- package/src/vite-plugin.ts +15 -2
- package/dist-cli/bin.js +0 -15
- package/dist-cli/chunks/agent-H42FCKFF.js +0 -48
- package/dist-cli/chunks/agent-wrapper-BBZKTZS6.js +0 -17
- package/dist-cli/chunks/app-fonts-43VXIKF4.js +0 -4
- package/dist-cli/chunks/assert-IXOLVO5Z.js +0 -49
- package/dist-cli/chunks/auth-KFMFB6FU.js +0 -12
- package/dist-cli/chunks/beta-5AO3SJB7.js +0 -4
- package/dist-cli/chunks/box-ZHM66L6K.js +0 -1730
- package/dist-cli/chunks/camera-FNJVFCDQ.js +0 -33
- package/dist-cli/chunks/chunk-37MCSPTE.js +0 -71
- package/dist-cli/chunks/chunk-3PEMSUAQ.js +0 -30
- package/dist-cli/chunks/chunk-4TQ5HOK3.js +0 -7
- package/dist-cli/chunks/chunk-5YZYDEMI.js +0 -4
- package/dist-cli/chunks/chunk-6CV3R3XD.js +0 -15
- package/dist-cli/chunks/chunk-7LGK5XU6.js +0 -4
- package/dist-cli/chunks/chunk-7R2TK2NY.js +0 -4
- package/dist-cli/chunks/chunk-7VZZQQEE.js +0 -497
- package/dist-cli/chunks/chunk-AFOVILIL.js +0 -130
- package/dist-cli/chunks/chunk-BEU7CD7E.js +0 -9
- package/dist-cli/chunks/chunk-CE4JQJ6Y.js +0 -6
- package/dist-cli/chunks/chunk-CIE6CZXL.js +0 -142
- package/dist-cli/chunks/chunk-CSJ7L7ZL.js +0 -312
- package/dist-cli/chunks/chunk-CWCQP53A.js +0 -27
- package/dist-cli/chunks/chunk-DCS5FK5N.js +0 -7
- package/dist-cli/chunks/chunk-DEV3E3MV.js +0 -4
- package/dist-cli/chunks/chunk-DGJMIVZM.js +0 -5
- package/dist-cli/chunks/chunk-DGX3MN65.js +0 -5
- package/dist-cli/chunks/chunk-DNPQMTW5.js +0 -4
- package/dist-cli/chunks/chunk-DOVBJBVD.js +0 -5
- package/dist-cli/chunks/chunk-DPBJ3S3J.js +0 -3
- package/dist-cli/chunks/chunk-FVZBGPCU.js +0 -4
- package/dist-cli/chunks/chunk-GDKMOIUT.js +0 -4
- package/dist-cli/chunks/chunk-GIF2NJCS.js +0 -32
- package/dist-cli/chunks/chunk-GZE57ORL.js +0 -4
- package/dist-cli/chunks/chunk-H3U56DKI.js +0 -24
- package/dist-cli/chunks/chunk-HZLOYAPH.js +0 -4
- package/dist-cli/chunks/chunk-J2IKAEU2.js +0 -4
- package/dist-cli/chunks/chunk-JXAXYK7W.js +0 -11
- package/dist-cli/chunks/chunk-KJE2O2GK.js +0 -4
- package/dist-cli/chunks/chunk-KMNVDZZI.js +0 -423
- package/dist-cli/chunks/chunk-LC3QRIRB.js +0 -10
- package/dist-cli/chunks/chunk-LGFTAQYC.js +0 -4
- package/dist-cli/chunks/chunk-LQMUA5IY.js +0 -4
- package/dist-cli/chunks/chunk-MFIQTWC5.js +0 -4
- package/dist-cli/chunks/chunk-MGALNF2F.js +0 -7
- package/dist-cli/chunks/chunk-MLBZZHOY.js +0 -4
- package/dist-cli/chunks/chunk-NNRF7GIB.js +0 -107
- package/dist-cli/chunks/chunk-NORLYTTO.js +0 -7
- package/dist-cli/chunks/chunk-P6KVGV3H.js +0 -14
- package/dist-cli/chunks/chunk-PAJTUK33.js +0 -4
- package/dist-cli/chunks/chunk-QELIC5XP.js +0 -4
- package/dist-cli/chunks/chunk-QRDF33WD.js +0 -11
- package/dist-cli/chunks/chunk-R76BA7C7.js +0 -535
- package/dist-cli/chunks/chunk-RVEB4CZ2.js +0 -4
- package/dist-cli/chunks/chunk-SK4M7NXT.js +0 -5
- package/dist-cli/chunks/chunk-SKMG5DD7.js +0 -5
- package/dist-cli/chunks/chunk-TEESPOYR.js +0 -4
- package/dist-cli/chunks/chunk-TH2UFGVP.js +0 -4
- package/dist-cli/chunks/chunk-TLP3T3VO.js +0 -4
- package/dist-cli/chunks/chunk-TZUABDIJ.js +0 -38
- package/dist-cli/chunks/chunk-UB2W6OQM.js +0 -99
- package/dist-cli/chunks/chunk-UYVXALPB.js +0 -506
- package/dist-cli/chunks/chunk-VQDYFFIG.js +0 -5
- package/dist-cli/chunks/chunk-VWCNJPCJ.js +0 -5
- package/dist-cli/chunks/chunk-VZIK4WIS.js +0 -74
- package/dist-cli/chunks/chunk-W3FNXAQP.js +0 -4
- package/dist-cli/chunks/chunk-XCDNVNP3.js +0 -4
- package/dist-cli/chunks/chunk-XSVILA4Z.js +0 -4
- package/dist-cli/chunks/chunk-XUTJ7ZWD.js +0 -4
- package/dist-cli/chunks/chunk-YTXY3MHW.js +0 -4
- package/dist-cli/chunks/chunk-ZF7PVX44.js +0 -28
- package/dist-cli/chunks/chunk-ZSSG7OR7.js +0 -4
- package/dist-cli/chunks/cleanup-MLOK2OZA.js +0 -25
- package/dist-cli/chunks/cli-version-OBNR366V.js +0 -4
- package/dist-cli/chunks/compat-SHMFSKU7.js +0 -23
- package/dist-cli/chunks/config-TPEAEUJ2.js +0 -13
- package/dist-cli/chunks/connect-3LEXWTE5.js +0 -4
- package/dist-cli/chunks/control-Z3FWA6BO.js +0 -4
- package/dist-cli/chunks/daemon-RSVYSC65.js +0 -4
- package/dist-cli/chunks/debug-GUVAK2KR.js +0 -200
- package/dist-cli/chunks/desktop-OOP2PTKP.js +0 -31
- package/dist-cli/chunks/detox-C2ILVBEC.js +0 -52
- package/dist-cli/chunks/device-NXIQQJWR.js +0 -18
- package/dist-cli/chunks/diagnose-2JBGYE5L.js +0 -43
- package/dist-cli/chunks/disk-cleanup-VURWJYQV.js +0 -4
- package/dist-cli/chunks/do-chain-DJ4UQC7A.js +0 -5
- package/dist-cli/chunks/drivers-JMA2OIKU.js +0 -4
- package/dist-cli/chunks/env-KTNPKEZR.js +0 -4
- package/dist-cli/chunks/film-DCPS7EID.js +0 -74
- package/dist-cli/chunks/flow-4DZ7B2OA.js +0 -4
- package/dist-cli/chunks/help-34CJMQY2.js +0 -4
- package/dist-cli/chunks/hidden-runtime-alias-HHT2C7WE.js +0 -4
- package/dist-cli/chunks/home-paths-KTPGCPMS.js +0 -4
- package/dist-cli/chunks/inspect-JF5WYJRD.js +0 -4
- package/dist-cli/chunks/install-desktop-ZIC4CDXI.js +0 -4
- package/dist-cli/chunks/login-TTJAOI2Q.js +0 -26
- package/dist-cli/chunks/logout-ERAQ6SKW.js +0 -4
- package/dist-cli/chunks/maestro-W46QCF77.js +0 -108
- package/dist-cli/chunks/maestro-generate-VBLM3MTU.js +0 -36
- package/dist-cli/chunks/mode-ZEDZK7R7.js +0 -26
- package/dist-cli/chunks/optional-demo-registry-ZUTPSVYQ.js +0 -4
- package/dist-cli/chunks/perf-YVT2WXT4.js +0 -48
- package/dist-cli/chunks/permissions-L7VVDHFP.js +0 -13
- package/dist-cli/chunks/platform-7TJOU2FB.js +0 -6
- package/dist-cli/chunks/privacy-57UOTB5J.js +0 -4
- package/dist-cli/chunks/record-VXG37P7U.js +0 -72
- package/dist-cli/chunks/report-issue-WNNOBZHC.js +0 -29
- package/dist-cli/chunks/reset-H5NBFE5U.js +0 -4
- package/dist-cli/chunks/resolve-target-57TK5WLE.js +0 -4
- package/dist-cli/chunks/runtime-QU2NIF2K.js +0 -4
- package/dist-cli/chunks/screenshot-command-AN56TTG7.js +0 -159
- package/dist-cli/chunks/screenshot-layers-3W5R7DB2.js +0 -20
- package/dist-cli/chunks/screenshots-capture-6AWJY7XZ.js +0 -42
- package/dist-cli/chunks/serve-GLYO5Q7J.js +0 -56
- package/dist-cli/chunks/setup-UA2HLD7S.js +0 -4
- package/dist-cli/chunks/sim-client-5C2RDQQO.js +0 -4
- package/dist-cli/chunks/skills-EYXWBRNQ.js +0 -50
- package/dist-cli/chunks/state-REJ7W6K3.js +0 -14
- package/dist-cli/chunks/storage-CFMDHI3V.js +0 -37
- package/dist-cli/chunks/store-XMCUA45G.js +0 -4
- package/dist-cli/chunks/telemetry-FBL3NAKB.js +0 -4
- package/dist-cli/chunks/timeline-HMCHN5FO.js +0 -24
- package/dist-cli/chunks/upgrade-2QSPAA3P.js +0 -7
- package/dist-cli/chunks/upload-DUQBKZYV.js +0 -4
- package/dist-cli/chunks/version-IOA6QFGB.js +0 -6
- package/dist-cli/chunks/web-NCGUYVCJ.js +0 -4
- package/dist-cli/chunks/welcome-QYGSQCWQ.js +0 -5
- package/dist-cli/chunks/what-happened-YTOUK4LO.js +0 -25
- package/dist-cli/chunks/ws-bridge-OF4OZARG.js +0 -4
- package/scripts/postinstall.cjs +0 -3
- package/scripts/preuninstall.cjs +0 -118
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.378 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -126,17 +126,17 @@ function launchRnxDesktop(bundleUrl, appName) {
|
|
|
126
126
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
127
127
|
var import_node_os = require("node:os");
|
|
128
128
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
129
|
-
var
|
|
129
|
+
var RNX_HOME_ENV = "RNX_HOME";
|
|
130
130
|
var ACTIVE_RUNTIME_FILE = "active";
|
|
131
131
|
var DAEMON_LOCKFILE = "daemon.json";
|
|
132
132
|
var DAEMON_HEARTBEAT_STALE_MS = 3e4;
|
|
133
|
-
function
|
|
134
|
-
const override = process.env[
|
|
133
|
+
function rnxHomeDir() {
|
|
134
|
+
const override = process.env[RNX_HOME_ENV];
|
|
135
135
|
if (override && override.length > 0) return import_node_path2.default.resolve(override);
|
|
136
|
-
return import_node_path2.default.join((0, import_node_os.homedir)(), ".
|
|
136
|
+
return import_node_path2.default.join((0, import_node_os.homedir)(), ".rnx");
|
|
137
137
|
}
|
|
138
138
|
function runtimesDir() {
|
|
139
|
-
return import_node_path2.default.join(
|
|
139
|
+
return import_node_path2.default.join(rnxHomeDir(), "runtimes");
|
|
140
140
|
}
|
|
141
141
|
function runtimeDir(version) {
|
|
142
142
|
return import_node_path2.default.join(runtimesDir(), version);
|
|
@@ -145,7 +145,7 @@ function activeRuntimeFile() {
|
|
|
145
145
|
return import_node_path2.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
|
|
146
146
|
}
|
|
147
147
|
function daemonLockfilePath() {
|
|
148
|
-
return import_node_path2.default.join(
|
|
148
|
+
return import_node_path2.default.join(rnxHomeDir(), DAEMON_LOCKFILE);
|
|
149
149
|
}
|
|
150
150
|
function readActiveRuntime() {
|
|
151
151
|
try {
|
|
@@ -417,7 +417,7 @@ function findMonorepoRoot() {
|
|
|
417
417
|
return null;
|
|
418
418
|
}
|
|
419
419
|
function resolveDevCheckoutRuntimeRoot() {
|
|
420
|
-
if (process.env.
|
|
420
|
+
if (process.env.RNX_HOME && readActiveRuntime()) return null;
|
|
421
421
|
const root = findMonorepoRoot();
|
|
422
422
|
if (!root) return null;
|
|
423
423
|
const devBuild = import_path.default.join(root, "public/sootsim");
|
|
@@ -654,7 +654,7 @@ function rnxPlugin(options = {}) {
|
|
|
654
654
|
const port = configuredPort;
|
|
655
655
|
const sootsimUrl = `http://localhost:${port}${prefix}/`;
|
|
656
656
|
console.log(`[rnx] serving at ${sootsimUrl}`);
|
|
657
|
-
if (appName && !process.env.CI && !process.env.
|
|
657
|
+
if (appName && !process.env.CI && !process.env.RNX_NO_OPEN) {
|
|
658
658
|
server.httpServer?.once("listening", () => {
|
|
659
659
|
const openPort = listeningPort();
|
|
660
660
|
launchRnxDesktop(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rnxsim",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.378",
|
|
4
4
|
"description": "rnx CLI, Vite and Metro plugins, and agent skills for driving React Native apps in the browser.",
|
|
5
5
|
"author": "Tamagui LLC",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -179,12 +179,7 @@
|
|
|
179
179
|
},
|
|
180
180
|
"./package.json": "./package.json"
|
|
181
181
|
},
|
|
182
|
-
"bin": {
|
|
183
|
-
"rnx": "dist-cli/bin.js",
|
|
184
|
-
"rnxsim": "dist-cli/bin.js"
|
|
185
|
-
},
|
|
186
182
|
"files": [
|
|
187
|
-
"dist-cli/",
|
|
188
183
|
"dist-lib/",
|
|
189
184
|
"src/",
|
|
190
185
|
"cli/",
|
|
@@ -192,8 +187,6 @@
|
|
|
192
187
|
"scripts/dev-server-scanner.ts",
|
|
193
188
|
"scripts/optional-demo-registry.ts",
|
|
194
189
|
"detox/",
|
|
195
|
-
"scripts/postinstall.cjs",
|
|
196
|
-
"scripts/preuninstall.cjs",
|
|
197
190
|
"README.md",
|
|
198
191
|
"LICENSE"
|
|
199
192
|
],
|
|
@@ -201,9 +194,9 @@
|
|
|
201
194
|
"build": "bun scripts/build-cli.ts",
|
|
202
195
|
"build:cli": "bun scripts/build-cli.ts",
|
|
203
196
|
"build:cli-binary": "bun scripts/build-cli-binary.ts",
|
|
204
|
-
"
|
|
205
|
-
"
|
|
206
|
-
"
|
|
197
|
+
"smoke:cli-binary": "bun scripts/smoke-cli-binary.ts",
|
|
198
|
+
"publish:cli-binary": "bun scripts/publish-cli-binaries.ts",
|
|
199
|
+
"pack:smoke": "bun scripts/pack-smoke.ts"
|
|
207
200
|
},
|
|
208
201
|
"dependencies": {
|
|
209
202
|
"@expo/plist": "^0.5.4",
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
LOOPBACK_PROBE_HOSTNAMES,
|
|
25
25
|
normalizeHostname,
|
|
26
26
|
} from '../src/backend-origin.ts'
|
|
27
|
-
import {
|
|
27
|
+
import { applyRNXConfigToUrl } from '../src/config.ts'
|
|
28
28
|
import {
|
|
29
29
|
alignLoopbackBundleUrlWithProbe,
|
|
30
30
|
normalizeNativeDevBundleUrl,
|
|
@@ -571,7 +571,7 @@ function withRuntimeConfig(port: number, bundleUrl: string, projectCwd?: string)
|
|
|
571
571
|
? knownApps[0]
|
|
572
572
|
: undefined
|
|
573
573
|
const configured = knownApp?.runtimeConfig
|
|
574
|
-
?
|
|
574
|
+
? applyRNXConfigToUrl(bundleUrl, knownApp.runtimeConfig)
|
|
575
575
|
: bundleUrl
|
|
576
576
|
return normalizeNativeDevBundleUrl(configured)
|
|
577
577
|
}
|
|
@@ -63,7 +63,7 @@ export interface OptionalDemoApp {
|
|
|
63
63
|
dir: string
|
|
64
64
|
preferredPort: number
|
|
65
65
|
framework: 'expo' | 'one' | 'rock'
|
|
66
|
-
runtimeConfig?: import('../src/config.ts').
|
|
66
|
+
runtimeConfig?: import('../src/config.ts').RNXConfig
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
let cached: OptionalDemoApp[] | null = null
|
package/skills/contrast/SKILL.md
CHANGED
|
@@ -60,7 +60,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
60
60
|
| `rnx version` | show the CLI + engine runtime versions you are running |
|
|
61
61
|
| `rnx upgrade` | update the rnx CLI and engine runtime to the latest |
|
|
62
62
|
| `rnx serve` | run the rnx bridge in the foreground |
|
|
63
|
-
| `rnx runtime` | manage engine runtimes under ~/.
|
|
63
|
+
| `rnx runtime` | manage engine runtimes under ~/.rnx/runtimes/ |
|
|
64
64
|
| `rnx auth` | inspect active CLI auth |
|
|
65
65
|
| `rnx login` | sign in for preview uploads |
|
|
66
66
|
| `rnx logout` | clear the local desktop auth session |
|
|
@@ -115,7 +115,7 @@ commands in your own `sleep` or chain `do settle` "just to be safe"**.
|
|
|
115
115
|
`type-into`, `key`, `key-sequence`, `keycode`, `drag`, `swipe`,
|
|
116
116
|
`long-press`, `touch`, `gesture`, `pinch`, `scroll`, `shell`)
|
|
117
117
|
the CLI polls the layout hash until it is stable for two consecutive
|
|
118
|
-
frames. budget: **400 ms for agents** (`
|
|
118
|
+
frames. budget: **400 ms for agents** (`RNX_AGENT=1`, set by the
|
|
119
119
|
harness), 200 ms for humans.
|
|
120
120
|
|
|
121
121
|
what this means:
|
|
@@ -126,7 +126,7 @@ what this means:
|
|
|
126
126
|
`⚠ auto-wait timed out after Nms — next command may see mid-animation
|
|
127
127
|
state`, or when the transition you care about lasts longer than ~400 ms
|
|
128
128
|
(full stack navigation, crossfades, video load).
|
|
129
|
-
- opt-out: `--no-wait` on a single command, `
|
|
129
|
+
- opt-out: `--no-wait` on a single command, `RNX_NO_AUTO_WAIT=1`
|
|
130
130
|
for a whole lane.
|
|
131
131
|
- if a read keeps racing its write, the fix is **never** a blind `sleep` —
|
|
132
132
|
prefer `wait selector`, `wait ready`, `wait idle`, or a longer
|
|
@@ -129,7 +129,7 @@ rnx do settle 5 # wait up to 5s for layout stability
|
|
|
129
129
|
rnx wait idle --max-ms 5000 # same thing under the `wait` verb
|
|
130
130
|
rnx wait idle --strict # also require animation flags clear
|
|
131
131
|
rnx do tap-id play --no-wait # skip auto-settle on one command
|
|
132
|
-
|
|
132
|
+
RNX_NO_AUTO_WAIT=1 rnx ... # disable auto-settle for a lane
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
## branch — debugging
|
package/skills/rnx-test/SKILL.md
CHANGED
|
@@ -12,7 +12,7 @@ Detox runs existing imperative Jest suites through the rnx driver.
|
|
|
12
12
|
> needs a connected, pinned sim. if `rnx describe` errors, load
|
|
13
13
|
> `/rnx-setup` first.
|
|
14
14
|
|
|
15
|
-
Set `
|
|
15
|
+
Set `RNX_NO_OPEN=1` before starting an app dev server for a Detox,
|
|
16
16
|
Maestro, or iOS-only pass. Apps can opt into a named Electron window through
|
|
17
17
|
the official Vite or Metro plugin, and test-only work must not open that window.
|
|
18
18
|
|
|
@@ -236,7 +236,7 @@ upstream detox surface.
|
|
|
236
236
|
### one-line install
|
|
237
237
|
|
|
238
238
|
```js
|
|
239
|
-
//
|
|
239
|
+
// rnx-detox.config.cjs
|
|
240
240
|
module.exports = {
|
|
241
241
|
preset: 'rnxsim/detox/jest-preset',
|
|
242
242
|
rootDir: __dirname,
|
package/src/agent-identity.ts
CHANGED
|
@@ -6,7 +6,7 @@ export function agentSessionIdFromCliIdentity(identity: string | null): string |
|
|
|
6
6
|
if (colon < 0) return identity.trim() || null
|
|
7
7
|
const source = identity.slice(0, colon)
|
|
8
8
|
const value = identity.slice(colon + 1).trim()
|
|
9
|
-
return source === '
|
|
9
|
+
return source === 'RNX_CLI_IDENTITY' && value ? value : null
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function teamMachineSessionIdFromCliIdentity(
|
package/src/agent-sessions.ts
CHANGED
|
@@ -67,7 +67,7 @@ export function pidIsAlive(pid: number | undefined, sessionId?: string): boolean
|
|
|
67
67
|
|
|
68
68
|
/** figure out how to re-invoke the sootsim CLI to run `agent-wrapper`.
|
|
69
69
|
* priority:
|
|
70
|
-
* 1.
|
|
70
|
+
* 1. RNX_BIN env var (explicit override)
|
|
71
71
|
* 2. electron prod: bundled binary under process.resourcesPath/bin/
|
|
72
72
|
* 3. workspace build artifacts (dist-bin/<binary> or dist-cli/bin.js)
|
|
73
73
|
* — shared between electron dev, the vite-plugin-hosted daemon, and
|
|
@@ -77,8 +77,8 @@ export function pidIsAlive(pid: number | undefined, sessionId?: string): boolean
|
|
|
77
77
|
* 5. CLI standalone: argv[0] is the compiled binary, no prefix needed
|
|
78
78
|
*/
|
|
79
79
|
export function resolveSootsimInvocation(): { cmd: string; prefixArgs: string[] } {
|
|
80
|
-
if (process.env.
|
|
81
|
-
return { cmd: process.env.
|
|
80
|
+
if (process.env.RNX_BIN) {
|
|
81
|
+
return { cmd: process.env.RNX_BIN, prefixArgs: [] }
|
|
82
82
|
}
|
|
83
83
|
// electron prod: packaged binary lives under Resources/bin/.
|
|
84
84
|
if (process.versions.electron) {
|
|
@@ -117,7 +117,7 @@ export function resolveSootsimInvocation(): { cmd: string; prefixArgs: string[]
|
|
|
117
117
|
// bin-shim case falls through to the error below instead of silently
|
|
118
118
|
// running `node` without args.
|
|
119
119
|
throw new Error(
|
|
120
|
-
'rnx CLI not found. set
|
|
120
|
+
'rnx CLI not found. set RNX_BIN to the path of the rnx binary, ' +
|
|
121
121
|
'or build the workspace CLI via `bun run --cwd packages/sootsim build:cli`.',
|
|
122
122
|
)
|
|
123
123
|
}
|
|
@@ -128,7 +128,9 @@ function tryWorkspaceSootsim(): { cmd: string; prefixArgs: string[] } | null {
|
|
|
128
128
|
try {
|
|
129
129
|
const sootsimDir = resolveSootsimPackageDir()
|
|
130
130
|
if (!sootsimDir) return null
|
|
131
|
-
const binaryName = `
|
|
131
|
+
const binaryName = `rnx-${
|
|
132
|
+
process.platform === 'win32' ? 'windows' : process.platform
|
|
133
|
+
}-${process.arch}${process.platform === 'win32' ? '.exe' : ''}`
|
|
132
134
|
const distBinary = path.join(sootsimDir, 'dist-bin', binaryName)
|
|
133
135
|
if (fs.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] }
|
|
134
136
|
const distBin = path.join(sootsimDir, 'dist-cli', 'bin.js')
|
package/src/cli-version.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// startup flow, and the bridge-host (which injects it into the served
|
|
4
|
-
// runtime html as window.__sootsimCliVersion).
|
|
1
|
+
// rnx cli version, resolved once and cached. standalone builds embed it so
|
|
2
|
+
// lazy command chunks do not depend on an npm package layout at runtime.
|
|
5
3
|
|
|
6
4
|
import { readFileSync } from 'node:fs'
|
|
7
5
|
import { fileURLToPath } from 'node:url'
|
|
8
6
|
import { rnxPublicBrand } from './public-brand.ts'
|
|
9
7
|
|
|
8
|
+
declare const __RNX_CLI_VERSION__: string
|
|
9
|
+
|
|
10
10
|
let cached: string | null = null
|
|
11
11
|
|
|
12
12
|
export function getCliVersion(): string {
|
|
13
13
|
if (cached != null) return cached
|
|
14
|
+
if (
|
|
15
|
+
typeof __RNX_CLI_VERSION__ !== 'undefined' &&
|
|
16
|
+
typeof __RNX_CLI_VERSION__ === 'string' &&
|
|
17
|
+
__RNX_CLI_VERSION__
|
|
18
|
+
) {
|
|
19
|
+
cached = __RNX_CLI_VERSION__
|
|
20
|
+
return cached
|
|
21
|
+
}
|
|
14
22
|
// prefer package resolution (works for npm/global installs); fall back to
|
|
15
23
|
// the package.json next to this module's source for repo / bundled runs.
|
|
16
24
|
const candidates: Array<() => string> = [
|
package/src/config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// rnx.config.ts — per-app module resolution, turbo modules, env, state, and settings.
|
|
2
2
|
//
|
|
3
3
|
// usage:
|
|
4
4
|
// import { defineConfig } from 'rnxsim/config'
|
|
@@ -17,9 +17,7 @@ export type ModuleResolution =
|
|
|
17
17
|
|
|
18
18
|
export type NativeModuleResolution = ModuleResolution | Record<string, any> // direct native module object for non-url configs
|
|
19
19
|
|
|
20
|
-
export interface
|
|
21
|
-
Settings extends Record<string, any> = Record<string, any>,
|
|
22
|
-
> {
|
|
20
|
+
export interface RNXConfig<Settings extends Record<string, any> = Record<string, any>> {
|
|
23
21
|
// host-only engine selection. omitted means the current stable runtime.
|
|
24
22
|
runtimeVersion?: string
|
|
25
23
|
modules?: Record<string, ModuleResolution>
|
|
@@ -48,11 +46,11 @@ export interface SootSimConfig<
|
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
export const
|
|
49
|
+
export const RNX_CONFIG_QUERY_PARAM = 'rnxConfig'
|
|
52
50
|
|
|
53
51
|
export function defineConfig<Settings extends Record<string, any> = Record<string, any>>(
|
|
54
|
-
config:
|
|
55
|
-
):
|
|
52
|
+
config: RNXConfig<Settings>,
|
|
53
|
+
): RNXConfig<Settings> {
|
|
56
54
|
return config
|
|
57
55
|
}
|
|
58
56
|
|
|
@@ -60,9 +58,9 @@ function hasOwnKeys(value: Record<string, unknown> | undefined): boolean {
|
|
|
60
58
|
return !!value && Object.keys(value).length > 0
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
export function
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
export function hasRNXConfig<Settings extends Record<string, any> = Record<string, any>>(
|
|
62
|
+
config?: RNXConfig<Settings> | null,
|
|
63
|
+
): config is RNXConfig<Settings> {
|
|
66
64
|
if (!config) return false
|
|
67
65
|
return (
|
|
68
66
|
(typeof config.runtimeVersion === 'string' && config.runtimeVersion.length > 0) ||
|
|
@@ -76,15 +74,15 @@ export function hasSootSimConfig<
|
|
|
76
74
|
)
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
export function
|
|
77
|
+
export function mergeRNXConfig<
|
|
80
78
|
Settings extends Record<string, any> = Record<string, any>,
|
|
81
79
|
>(
|
|
82
|
-
base?:
|
|
83
|
-
override?:
|
|
84
|
-
):
|
|
85
|
-
if (!
|
|
86
|
-
if (!
|
|
87
|
-
if (!
|
|
80
|
+
base?: RNXConfig<Settings> | null,
|
|
81
|
+
override?: RNXConfig<Settings> | null,
|
|
82
|
+
): RNXConfig<Settings> | undefined {
|
|
83
|
+
if (!hasRNXConfig(base) && !hasRNXConfig(override)) return undefined
|
|
84
|
+
if (!hasRNXConfig(base)) return override ? { ...override } : undefined
|
|
85
|
+
if (!hasRNXConfig(override)) return base ? { ...base } : undefined
|
|
88
86
|
|
|
89
87
|
return {
|
|
90
88
|
runtimeVersion: override.runtimeVersion ?? base.runtimeVersion,
|
|
@@ -106,29 +104,29 @@ export function mergeSootSimConfig<
|
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
export function
|
|
107
|
+
export function readRNXConfigFromSearchParams<
|
|
110
108
|
Settings extends Record<string, any> = Record<string, any>,
|
|
111
|
-
>(searchParams: URLSearchParams):
|
|
112
|
-
const raw = searchParams.get(
|
|
109
|
+
>(searchParams: URLSearchParams): RNXConfig<Settings> | undefined {
|
|
110
|
+
const raw = searchParams.get(RNX_CONFIG_QUERY_PARAM)
|
|
113
111
|
if (!raw) return undefined
|
|
114
112
|
try {
|
|
115
|
-
const parsed = JSON.parse(raw) as
|
|
116
|
-
return
|
|
113
|
+
const parsed = JSON.parse(raw) as RNXConfig<Settings>
|
|
114
|
+
return hasRNXConfig(parsed) ? parsed : undefined
|
|
117
115
|
} catch (error) {
|
|
118
116
|
const message = error instanceof Error ? error.message : String(error)
|
|
119
|
-
console.warn(`[rnx] invalid ${
|
|
117
|
+
console.warn(`[rnx] invalid ${RNX_CONFIG_QUERY_PARAM}: ${message}`)
|
|
120
118
|
return undefined
|
|
121
119
|
}
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
export function
|
|
122
|
+
export function applyRNXConfigToUrl<
|
|
125
123
|
Settings extends Record<string, any> = Record<string, any>,
|
|
126
|
-
>(url: string, config?:
|
|
124
|
+
>(url: string, config?: RNXConfig<Settings> | null): string {
|
|
127
125
|
const parsed = new URL(url)
|
|
128
|
-
if (
|
|
129
|
-
parsed.searchParams.set(
|
|
126
|
+
if (hasRNXConfig(config)) {
|
|
127
|
+
parsed.searchParams.set(RNX_CONFIG_QUERY_PARAM, JSON.stringify(config))
|
|
130
128
|
} else {
|
|
131
|
-
parsed.searchParams.delete(
|
|
129
|
+
parsed.searchParams.delete(RNX_CONFIG_QUERY_PARAM)
|
|
132
130
|
}
|
|
133
131
|
return parsed.toString()
|
|
134
132
|
}
|
package/src/disk-cleanup.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { isDisposableBrowserCacheDir } from './browser-cache'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { ensureRnxHome, readLiveRuntimeVersions, rnxHomeDir } from './home-paths'
|
|
5
|
+
import { rnxRuntime } from './runtime-delivery'
|
|
6
6
|
|
|
7
7
|
const AUTOMATIC_CLEANUP_GENERATION = 1
|
|
8
8
|
const AUTOMATIC_CLEANUP_COMPLETE_FILE = `automatic-cleanup-v${AUTOMATIC_CLEANUP_GENERATION}.json`
|
|
@@ -65,7 +65,7 @@ export interface AutomaticSootsimCleanupResult {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export function isAutomaticSootsimCleanupComplete(): boolean {
|
|
68
|
-
const completePath = path.join(
|
|
68
|
+
const completePath = path.join(rnxHomeDir(), AUTOMATIC_CLEANUP_COMPLETE_FILE)
|
|
69
69
|
try {
|
|
70
70
|
const parsed = JSON.parse(fs.readFileSync(completePath, 'utf8')) as {
|
|
71
71
|
generation?: unknown
|
|
@@ -80,7 +80,7 @@ export function isAutomaticSootsimCleanupComplete(): boolean {
|
|
|
80
80
|
// right now. complete means never again; a recent deferral means not yet.
|
|
81
81
|
export function shouldSkipAutomaticSootsimCleanup(now = Date.now()): boolean {
|
|
82
82
|
if (isAutomaticSootsimCleanupComplete()) return true
|
|
83
|
-
const deferredPath = path.join(
|
|
83
|
+
const deferredPath = path.join(rnxHomeDir(), AUTOMATIC_CLEANUP_DEFERRED_FILE)
|
|
84
84
|
try {
|
|
85
85
|
const parsed = JSON.parse(fs.readFileSync(deferredPath, 'utf8')) as {
|
|
86
86
|
generation?: unknown
|
|
@@ -243,11 +243,11 @@ function runtimeEntries(aggressive: boolean): {
|
|
|
243
243
|
} {
|
|
244
244
|
const inUseVersions = new Set(readLiveRuntimeVersions())
|
|
245
245
|
const protectVersions = [...inUseVersions]
|
|
246
|
-
const normal =
|
|
246
|
+
const normal = rnxRuntime.planLocalRetention({
|
|
247
247
|
retainVersions: 2,
|
|
248
248
|
protectVersions,
|
|
249
249
|
})
|
|
250
|
-
const minimal =
|
|
250
|
+
const minimal = rnxRuntime.planLocalRetention({
|
|
251
251
|
retainVersions: 1,
|
|
252
252
|
protectVersions,
|
|
253
253
|
})
|
|
@@ -262,7 +262,7 @@ function runtimeEntries(aggressive: boolean): {
|
|
|
262
262
|
const entries: SootsimCleanupEntry[] = []
|
|
263
263
|
|
|
264
264
|
for (const version of [...allVersions].sort()) {
|
|
265
|
-
const runtimePath =
|
|
265
|
+
const runtimePath = rnxRuntime.product.runtimeDir(version)
|
|
266
266
|
let state: SootsimCleanupState = 'retained'
|
|
267
267
|
let detail = 'retained runtime'
|
|
268
268
|
if (inUseVersions.has(version) && version !== normal.activeVersion) {
|
|
@@ -308,7 +308,7 @@ export function planSootsimCleanup(
|
|
|
308
308
|
options: SootsimCleanupOptions = {},
|
|
309
309
|
): SootsimCleanupPlan {
|
|
310
310
|
const aggressive = options.aggressive === true
|
|
311
|
-
const home =
|
|
311
|
+
const home = rnxHomeDir()
|
|
312
312
|
const runtimes = runtimeEntries(aggressive)
|
|
313
313
|
const entries = [
|
|
314
314
|
...runtimes.entries,
|
|
@@ -345,7 +345,7 @@ export function applySootsimCleanup(
|
|
|
345
345
|
): SootsimCleanupResult {
|
|
346
346
|
const plan = planSootsimCleanup(options)
|
|
347
347
|
const retainVersions = options.aggressive === true ? 1 : 2
|
|
348
|
-
|
|
348
|
+
rnxRuntime.pruneLocalRetention({
|
|
349
349
|
retainVersions,
|
|
350
350
|
protectVersions: readLiveRuntimeVersions(),
|
|
351
351
|
})
|
|
@@ -386,8 +386,8 @@ export function applySootsimCleanup(
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
export function applyAutomaticSootsimCleanup(): AutomaticSootsimCleanupResult {
|
|
389
|
-
|
|
390
|
-
const home =
|
|
389
|
+
ensureRnxHome()
|
|
390
|
+
const home = rnxHomeDir()
|
|
391
391
|
const completePath = path.join(home, AUTOMATIC_CLEANUP_COMPLETE_FILE)
|
|
392
392
|
const deferredPath = path.join(home, AUTOMATIC_CLEANUP_DEFERRED_FILE)
|
|
393
393
|
const lockPath = path.join(home, AUTOMATIC_CLEANUP_LOCK_FILE)
|
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()
|