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.
Files changed (295) hide show
  1. package/README.md +28 -25
  2. package/cli/app-config.ts +9 -12
  3. package/cli/app-fonts.ts +3 -3
  4. package/cli/app-project.ts +8 -8
  5. package/cli/auth.ts +7 -9
  6. package/cli/bin.ts +16 -31
  7. package/cli/bridge-flow-runner.ts +3 -3
  8. package/cli/browser-backend.ts +44 -0
  9. package/cli/command-contract.ts +221 -0
  10. package/cli/command-registry.ts +291 -0
  11. package/cli/commands/agent-wrapper.ts +2 -2
  12. package/cli/commands/app-fonts.ts +2 -2
  13. package/cli/commands/assert.ts +3 -3
  14. package/cli/commands/auth.ts +1 -1
  15. package/cli/commands/box/cloud-box.ts +1 -1
  16. package/cli/commands/box/plane-share.ts +2 -2
  17. package/cli/commands/box.ts +4 -6
  18. package/cli/commands/compat.ts +1 -1
  19. package/cli/commands/config.ts +2 -2
  20. package/cli/commands/control.ts +42 -28
  21. package/cli/commands/cpu-profile.ts +7 -7
  22. package/cli/commands/daemon-mac-app.ts +7 -7
  23. package/cli/commands/daemon.ts +10 -10
  24. package/cli/commands/debug.ts +11 -11
  25. package/cli/commands/detox.ts +13 -13
  26. package/cli/commands/diagnose.ts +6 -6
  27. package/cli/commands/do-chain.ts +1 -2
  28. package/cli/commands/electron.ts +1 -3
  29. package/cli/commands/film.ts +3 -3
  30. package/cli/commands/flow.ts +43 -43
  31. package/cli/commands/inspect/count.ts +1 -1
  32. package/cli/commands/inspect/describe.ts +1 -1
  33. package/cli/commands/inspect/env.ts +2 -2
  34. package/cli/commands/inspect/get-layout.ts +1 -1
  35. package/cli/commands/inspect/keyboard.ts +1 -1
  36. package/cli/commands/inspect/list.ts +1 -1
  37. package/cli/commands/inspect/memory.ts +1 -1
  38. package/cli/commands/inspect/resolve-target.ts +1 -1
  39. package/cli/commands/inspect/screens.ts +1 -1
  40. package/cli/commands/inspect/tree.ts +1 -1
  41. package/cli/commands/inspect/url.ts +1 -1
  42. package/cli/commands/inspect/wait-event.ts +5 -5
  43. package/cli/commands/inspect.ts +34 -34
  44. package/cli/commands/install-desktop.ts +3 -3
  45. package/cli/commands/login.ts +6 -6
  46. package/cli/commands/maestro-generate.ts +5 -5
  47. package/cli/commands/maestro.ts +5 -5
  48. package/cli/commands/profile.ts +1 -1
  49. package/cli/commands/record.ts +9 -9
  50. package/cli/commands/runtime.ts +18 -18
  51. package/cli/commands/screenshot-command.ts +1 -1
  52. package/cli/commands/screenshot-layers.ts +5 -5
  53. package/cli/commands/screenshot-mode.ts +1 -1
  54. package/cli/commands/screenshot.ts +8 -8
  55. package/cli/commands/screenshots-capture.ts +5 -5
  56. package/cli/commands/serve.ts +3 -3
  57. package/cli/commands/setup.ts +20 -12
  58. package/cli/commands/skills.ts +5 -5
  59. package/cli/commands/slides.ts +1 -1
  60. package/cli/commands/telemetry.ts +1 -1
  61. package/cli/commands/three-mode.ts +1 -1
  62. package/cli/commands/timeline.ts +8 -8
  63. package/cli/commands/upgrade.ts +116 -131
  64. package/cli/commands/upload.ts +12 -12
  65. package/cli/commands/version.ts +7 -7
  66. package/cli/commands/what-happened.ts +9 -9
  67. package/cli/current-sim.ts +3 -3
  68. package/cli/desktop-companion.ts +1 -1
  69. package/cli/drivers/playwright.ts +9 -9
  70. package/cli/drivers/registry.ts +1 -1
  71. package/cli/drivers/types.ts +1 -1
  72. package/cli/flow-file.ts +2 -2
  73. package/cli/flow-session.ts +1 -1
  74. package/cli/help-core.ts +136 -0
  75. package/cli/help.ts +17 -53
  76. package/cli/hints.ts +5 -5
  77. package/cli/inspect-notice-state.ts +1 -1
  78. package/cli/maestro-js.ts +1 -1
  79. package/cli/outbound-endpoints.ts +23 -5
  80. package/cli/parse-args.ts +19 -66
  81. package/cli/recording-access.ts +1 -1
  82. package/cli/registry.ts +1 -0
  83. package/cli/run-registry.ts +1 -1
  84. package/cli/run-rnx-core.ts +148 -0
  85. package/cli/run-rnx.ts +6 -9
  86. package/cli/runtime-notes.ts +3 -3
  87. package/cli/standalone.ts +4 -0
  88. package/cli/ws-bridge.ts +8 -8
  89. package/detox/config-loader.ts +2 -2
  90. package/detox/index.ts +8 -8
  91. package/detox/jest-preset.cjs +1 -1
  92. package/detox/navigation.ts +2 -2
  93. package/dist-lib/agent-daemon-client.cjs +5 -5
  94. package/dist-lib/agent-events.cjs +1 -1
  95. package/dist-lib/agent-identity.cjs +2 -2
  96. package/dist-lib/agent-sessions.cjs +10 -10
  97. package/dist-lib/attached-projects.cjs +6 -6
  98. package/dist-lib/auth/shared-session.cjs +6 -6
  99. package/dist-lib/backend-origin.cjs +1 -1
  100. package/dist-lib/beta.cjs +1 -1
  101. package/dist-lib/beta.mjs +1 -1
  102. package/dist-lib/bridge-constants.cjs +1 -1
  103. package/dist-lib/bridge-contract-input.cjs +1 -1
  104. package/dist-lib/bridge-contract-input.mjs +1 -1
  105. package/dist-lib/bridge-contract.cjs +1 -1
  106. package/dist-lib/bridge-contract.mjs +1 -1
  107. package/dist-lib/cli-constants.cjs +1 -1
  108. package/dist-lib/config.cjs +25 -25
  109. package/dist-lib/detox/index.cjs +9 -9
  110. package/dist-lib/detox/jest-preset.cjs +1 -1
  111. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  112. package/dist-lib/home-paths.cjs +29 -29
  113. package/dist-lib/host/bridge-host.cjs +274 -181
  114. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  117. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  118. package/dist-lib/host/websocket-proxy.cjs +1 -1
  119. package/dist-lib/index.cjs +14 -14
  120. package/dist-lib/jump-to-source-babel.cjs +1 -1
  121. package/dist-lib/menu.cjs +1 -1
  122. package/dist-lib/menu.mjs +1 -1
  123. package/dist-lib/metro-production-bundle.cjs +1 -1
  124. package/dist-lib/metro-production-bundle.mjs +1 -1
  125. package/dist-lib/metro.cjs +8 -8
  126. package/dist-lib/profiles.cjs +12 -12
  127. package/dist-lib/public-brand.cjs +1 -1
  128. package/dist-lib/react-native-host-modules.cjs +1 -1
  129. package/dist-lib/react-native-host-modules.mjs +1 -1
  130. package/dist-lib/render-mode.cjs +1 -1
  131. package/dist-lib/scripts/dev-server-scanner.cjs +25 -11
  132. package/dist-lib/sdk.cjs +1 -1
  133. package/dist-lib/sdk.mjs +1 -1
  134. package/dist-lib/skills.cjs +470 -322
  135. package/dist-lib/vite.cjs +9 -9
  136. package/package.json +4 -11
  137. package/scripts/dev-server-scanner.ts +25 -7
  138. package/scripts/optional-demo-registry.ts +1 -1
  139. package/skills/contrast/SKILL.md +3 -3
  140. package/skills/rnx-debug/SKILL.md +1 -1
  141. package/skills/rnx-test/SKILL.md +2 -2
  142. package/src/agent-identity.ts +1 -1
  143. package/src/agent-sessions.ts +7 -5
  144. package/src/cli-version.ts +12 -4
  145. package/src/config.ts +26 -28
  146. package/src/disk-cleanup.ts +11 -11
  147. package/src/home-paths.ts +28 -28
  148. package/src/host/bridge-host.ts +16 -16
  149. package/src/metro-plugin.ts +2 -2
  150. package/src/profiles.ts +2 -2
  151. package/src/runtime-assets.ts +7 -7
  152. package/src/runtime-delivery.ts +13 -13
  153. package/src/screenshots/orchestrate.ts +1 -1
  154. package/src/screenshots/schema.ts +2 -2
  155. package/src/skills/builtin/a11y-review.ts +2 -2
  156. package/src/skills/builtin/compat-check.ts +2 -2
  157. package/src/skills/builtin/maestro-test.ts +2 -2
  158. package/src/skills/builtin/perf-profile.ts +2 -2
  159. package/src/skills/builtin/screenshot-all.ts +2 -2
  160. package/src/skills/builtin/visual-diff.ts +2 -2
  161. package/src/skills/registry.ts +8 -8
  162. package/src/skills/types.ts +1 -1
  163. package/src/vite-plugin-one.ts +3 -3
  164. package/src/vite-plugin.ts +15 -2
  165. package/dist-cli/bin.js +0 -15
  166. package/dist-cli/chunks/agent-JJN7U6FR.js +0 -48
  167. package/dist-cli/chunks/agent-wrapper-AVVUJ3WF.js +0 -17
  168. package/dist-cli/chunks/app-fonts-QJ22CNAZ.js +0 -4
  169. package/dist-cli/chunks/assert-PZZKIY3K.js +0 -49
  170. package/dist-cli/chunks/auth-5AVDJO33.js +0 -12
  171. package/dist-cli/chunks/beta-PFRGP266.js +0 -4
  172. package/dist-cli/chunks/box-ILC2O7ZO.js +0 -1730
  173. package/dist-cli/chunks/camera-J3V62PP7.js +0 -33
  174. package/dist-cli/chunks/chunk-25KRGDZT.js +0 -4
  175. package/dist-cli/chunks/chunk-2BRBFLWA.js +0 -38
  176. package/dist-cli/chunks/chunk-2GXNAZHB.js +0 -74
  177. package/dist-cli/chunks/chunk-2IUMRRYV.js +0 -7
  178. package/dist-cli/chunks/chunk-4ALPWIMP.js +0 -10
  179. package/dist-cli/chunks/chunk-4CEZZKRY.js +0 -4
  180. package/dist-cli/chunks/chunk-4EUKOIAV.js +0 -4
  181. package/dist-cli/chunks/chunk-4IKE4YUS.js +0 -32
  182. package/dist-cli/chunks/chunk-4ZXR2M3D.js +0 -4
  183. package/dist-cli/chunks/chunk-5CGJFU27.js +0 -7
  184. package/dist-cli/chunks/chunk-5HHWECGT.js +0 -4
  185. package/dist-cli/chunks/chunk-5PZVYF42.js +0 -312
  186. package/dist-cli/chunks/chunk-7NCPUZ52.js +0 -27
  187. package/dist-cli/chunks/chunk-7OSIJCBR.js +0 -107
  188. package/dist-cli/chunks/chunk-AQ5TMOAI.js +0 -4
  189. package/dist-cli/chunks/chunk-BQCEI37V.js +0 -5
  190. package/dist-cli/chunks/chunk-C6B5FOP3.js +0 -4
  191. package/dist-cli/chunks/chunk-CCMZSHJB.js +0 -71
  192. package/dist-cli/chunks/chunk-CX7VCKAT.js +0 -14
  193. package/dist-cli/chunks/chunk-DQUPSAHE.js +0 -4
  194. package/dist-cli/chunks/chunk-DSD2UBZI.js +0 -4
  195. package/dist-cli/chunks/chunk-EWPAI4MO.js +0 -7
  196. package/dist-cli/chunks/chunk-EZXV6U2N.js +0 -497
  197. package/dist-cli/chunks/chunk-F5F7FIPM.js +0 -6
  198. package/dist-cli/chunks/chunk-FUTYK55H.js +0 -30
  199. package/dist-cli/chunks/chunk-FW6AN7I2.js +0 -3
  200. package/dist-cli/chunks/chunk-FZDRA7Z4.js +0 -4
  201. package/dist-cli/chunks/chunk-GDLE4NIV.js +0 -4
  202. package/dist-cli/chunks/chunk-GEX7RVHY.js +0 -5
  203. package/dist-cli/chunks/chunk-H4MYYOYJ.js +0 -5
  204. package/dist-cli/chunks/chunk-HEV7BAPE.js +0 -11
  205. package/dist-cli/chunks/chunk-HNDWYCND.js +0 -506
  206. package/dist-cli/chunks/chunk-HNPHODBD.js +0 -4
  207. package/dist-cli/chunks/chunk-HWDVC6YA.js +0 -11
  208. package/dist-cli/chunks/chunk-JOHJZUGG.js +0 -4
  209. package/dist-cli/chunks/chunk-JWUDT4QK.js +0 -5
  210. package/dist-cli/chunks/chunk-K7QQWKGE.js +0 -4
  211. package/dist-cli/chunks/chunk-LAOKTKT4.js +0 -4
  212. package/dist-cli/chunks/chunk-LD7I266X.js +0 -24
  213. package/dist-cli/chunks/chunk-LMHBU5LZ.js +0 -4
  214. package/dist-cli/chunks/chunk-LSOGXSDV.js +0 -535
  215. package/dist-cli/chunks/chunk-MP2GPO4T.js +0 -4
  216. package/dist-cli/chunks/chunk-MXJ2UWRV.js +0 -4
  217. package/dist-cli/chunks/chunk-OJNKRIZF.js +0 -15
  218. package/dist-cli/chunks/chunk-PBOWUNXO.js +0 -4
  219. package/dist-cli/chunks/chunk-PNRJFHX4.js +0 -4
  220. package/dist-cli/chunks/chunk-QJQOK34O.js +0 -28
  221. package/dist-cli/chunks/chunk-RLCQLMFF.js +0 -142
  222. package/dist-cli/chunks/chunk-S65CK3RI.js +0 -9
  223. package/dist-cli/chunks/chunk-SWBUNMQS.js +0 -4
  224. package/dist-cli/chunks/chunk-SXBFGGAM.js +0 -4
  225. package/dist-cli/chunks/chunk-T4ISWS5H.js +0 -4
  226. package/dist-cli/chunks/chunk-TPPVAA7Z.js +0 -5
  227. package/dist-cli/chunks/chunk-USM3P74H.js +0 -4
  228. package/dist-cli/chunks/chunk-V4EJJHF5.js +0 -4
  229. package/dist-cli/chunks/chunk-V7RGRZOL.js +0 -423
  230. package/dist-cli/chunks/chunk-XUBV77WH.js +0 -130
  231. package/dist-cli/chunks/chunk-XYSDYGKC.js +0 -4
  232. package/dist-cli/chunks/chunk-YNHRSDVG.js +0 -5
  233. package/dist-cli/chunks/chunk-YX52RJKO.js +0 -4
  234. package/dist-cli/chunks/chunk-Z5O5H4O7.js +0 -99
  235. package/dist-cli/chunks/chunk-Z6LOIW46.js +0 -7
  236. package/dist-cli/chunks/chunk-ZXFVBYJY.js +0 -5
  237. package/dist-cli/chunks/cleanup-KPUW4SFK.js +0 -25
  238. package/dist-cli/chunks/cli-version-APGT6GAT.js +0 -4
  239. package/dist-cli/chunks/compat-XXRFD2TW.js +0 -23
  240. package/dist-cli/chunks/config-DDMFDQ7F.js +0 -13
  241. package/dist-cli/chunks/connect-IPG47YXM.js +0 -4
  242. package/dist-cli/chunks/control-O22Z3UJ5.js +0 -4
  243. package/dist-cli/chunks/daemon-PADUIMJV.js +0 -4
  244. package/dist-cli/chunks/debug-MYIP46TM.js +0 -200
  245. package/dist-cli/chunks/desktop-ENFFBQAA.js +0 -31
  246. package/dist-cli/chunks/detox-J5WVK6OH.js +0 -52
  247. package/dist-cli/chunks/device-RAVQVL75.js +0 -18
  248. package/dist-cli/chunks/diagnose-PJMPXKJY.js +0 -43
  249. package/dist-cli/chunks/disk-cleanup-YLAY445J.js +0 -4
  250. package/dist-cli/chunks/do-chain-UBE7GIOU.js +0 -5
  251. package/dist-cli/chunks/drivers-ZFNX3T5Z.js +0 -4
  252. package/dist-cli/chunks/env-Y5XJSNRD.js +0 -4
  253. package/dist-cli/chunks/film-W3V6VURB.js +0 -74
  254. package/dist-cli/chunks/flow-VMLI7BYM.js +0 -4
  255. package/dist-cli/chunks/help-PKZCWHJJ.js +0 -4
  256. package/dist-cli/chunks/hidden-runtime-alias-S5DJ7EDF.js +0 -4
  257. package/dist-cli/chunks/home-paths-5O4IZPYV.js +0 -4
  258. package/dist-cli/chunks/inspect-LT4MXK37.js +0 -4
  259. package/dist-cli/chunks/install-desktop-EXCFMXFS.js +0 -4
  260. package/dist-cli/chunks/login-V6TZ54ZH.js +0 -26
  261. package/dist-cli/chunks/logout-SPMLFWYA.js +0 -4
  262. package/dist-cli/chunks/maestro-5ISTBAZE.js +0 -108
  263. package/dist-cli/chunks/maestro-generate-WUI64NHR.js +0 -36
  264. package/dist-cli/chunks/mode-QPNBYXUF.js +0 -26
  265. package/dist-cli/chunks/optional-demo-registry-CBSYF4CG.js +0 -4
  266. package/dist-cli/chunks/perf-T6N5PVYV.js +0 -48
  267. package/dist-cli/chunks/permissions-YZ7RRSZJ.js +0 -13
  268. package/dist-cli/chunks/platform-XDQAA72X.js +0 -6
  269. package/dist-cli/chunks/privacy-54FIGXLT.js +0 -4
  270. package/dist-cli/chunks/record-QGYXRUKP.js +0 -72
  271. package/dist-cli/chunks/report-issue-VUUTGX7V.js +0 -29
  272. package/dist-cli/chunks/reset-CGO52KBW.js +0 -4
  273. package/dist-cli/chunks/resolve-target-NNQCALDM.js +0 -4
  274. package/dist-cli/chunks/runtime-4EP6YJVL.js +0 -4
  275. package/dist-cli/chunks/screenshot-command-NZCMSJ4P.js +0 -159
  276. package/dist-cli/chunks/screenshot-layers-VMTQ6XIU.js +0 -20
  277. package/dist-cli/chunks/screenshots-capture-K3MWIDBK.js +0 -42
  278. package/dist-cli/chunks/serve-QJRIB2BV.js +0 -56
  279. package/dist-cli/chunks/setup-6XXEJQVF.js +0 -4
  280. package/dist-cli/chunks/sim-client-5YUVL45C.js +0 -4
  281. package/dist-cli/chunks/skills-T3CS7CXK.js +0 -50
  282. package/dist-cli/chunks/state-AJC3VK3G.js +0 -14
  283. package/dist-cli/chunks/storage-KVGZKC3Y.js +0 -37
  284. package/dist-cli/chunks/store-AWUMOQUH.js +0 -4
  285. package/dist-cli/chunks/telemetry-W5ZDGWK6.js +0 -4
  286. package/dist-cli/chunks/timeline-DXDCAZUA.js +0 -24
  287. package/dist-cli/chunks/upgrade-SRPTJACU.js +0 -7
  288. package/dist-cli/chunks/upload-ZDV4BFED.js +0 -4
  289. package/dist-cli/chunks/version-SOLPSBMG.js +0 -6
  290. package/dist-cli/chunks/web-RT75LD7A.js +0 -4
  291. package/dist-cli/chunks/welcome-IJ55EC7U.js +0 -5
  292. package/dist-cli/chunks/what-happened-CEIWJIWK.js +0 -25
  293. package/dist-cli/chunks/ws-bridge-YK5R3HOI.js +0 -4
  294. package/scripts/postinstall.cjs +0 -3
  295. package/scripts/preuninstall.cjs +0 -118
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.375 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.377 | (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;
@@ -113,6 +113,7 @@ var import_child_process = require("child_process");
113
113
  var import_promises2 = require("fs/promises");
114
114
  var import_http = __toESM(require("http"), 1);
115
115
  var import_net = __toESM(require("net"), 1);
116
+ var import_node_fs2 = require("node:fs");
116
117
  var import_node_path3 = require("node:path");
117
118
 
118
119
  // src/backend-origin.ts
@@ -131,20 +132,20 @@ function isLoopbackHost(hostname) {
131
132
  }
132
133
 
133
134
  // src/config.ts
134
- var SOOTSIM_CONFIG_QUERY_PARAM = "sootsimConfig";
135
+ var RNX_CONFIG_QUERY_PARAM = "rnxConfig";
135
136
  function hasOwnKeys(value) {
136
137
  return !!value && Object.keys(value).length > 0;
137
138
  }
138
- function hasSootSimConfig(config) {
139
+ function hasRNXConfig(config) {
139
140
  if (!config) return false;
140
141
  return typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
141
142
  }
142
- function applySootSimConfigToUrl(url, config) {
143
+ function applyRNXConfigToUrl(url, config) {
143
144
  const parsed = new URL(url);
144
- if (hasSootSimConfig(config)) {
145
- parsed.searchParams.set(SOOTSIM_CONFIG_QUERY_PARAM, JSON.stringify(config));
145
+ if (hasRNXConfig(config)) {
146
+ parsed.searchParams.set(RNX_CONFIG_QUERY_PARAM, JSON.stringify(config));
146
147
  } else {
147
- parsed.searchParams.delete(SOOTSIM_CONFIG_QUERY_PARAM);
148
+ parsed.searchParams.delete(RNX_CONFIG_QUERY_PARAM);
148
149
  }
149
150
  return parsed.toString();
150
151
  }
@@ -802,10 +803,23 @@ function makeResult(hostname, port, framework, owner) {
802
803
  };
803
804
  }
804
805
  function withRuntimeConfig(port, bundleUrl, projectCwd) {
805
- const knownApp = projectCwd ? optionalDemoAppsSync().find(
806
- (app) => app.preferredPort === port && (0, import_node_path3.resolve)(app.dir) === (0, import_node_path3.resolve)(projectCwd)
807
- ) : void 0;
808
- const configured = knownApp?.runtimeConfig ? applySootSimConfigToUrl(bundleUrl, knownApp.runtimeConfig) : bundleUrl;
806
+ let physicalProjectCwd;
807
+ if (projectCwd) {
808
+ try {
809
+ physicalProjectCwd = (0, import_node_fs2.realpathSync)((0, import_node_path3.resolve)(projectCwd));
810
+ } catch {
811
+ }
812
+ }
813
+ const knownApps = physicalProjectCwd ? optionalDemoAppsSync().filter((app) => {
814
+ try {
815
+ return (0, import_node_fs2.realpathSync)((0, import_node_path3.resolve)(app.dir)) === physicalProjectCwd;
816
+ } catch {
817
+ return false;
818
+ }
819
+ }) : [];
820
+ const exactKnownApps = knownApps.filter((app) => app.preferredPort === port);
821
+ const knownApp = exactKnownApps.length === 1 ? exactKnownApps[0] : exactKnownApps.length === 0 && knownApps.length === 1 ? knownApps[0] : void 0;
822
+ const configured = knownApp?.runtimeConfig ? applyRNXConfigToUrl(bundleUrl, knownApp.runtimeConfig) : bundleUrl;
809
823
  return normalizeNativeDevBundleUrl(configured);
810
824
  }
811
825
  function isDirectOneBundleUrl(bundleUrl) {
@@ -1141,7 +1155,7 @@ var SOOTSIM_BRIDGE_SIM_CLOSE_CODE = 4001;
1141
1155
  var SOOTSIM_BRIDGE_SIM_CLOSE_REASON = "sootsim close";
1142
1156
 
1143
1157
  // src/cli-version.ts
1144
- var import_node_fs2 = require("node:fs");
1158
+ var import_node_fs3 = require("node:fs");
1145
1159
  var import_node_url2 = require("node:url");
1146
1160
 
1147
1161
  // src/public-brand.ts
@@ -1159,13 +1173,17 @@ var import_meta = {};
1159
1173
  var cached2 = null;
1160
1174
  function getCliVersion() {
1161
1175
  if (cached2 != null) return cached2;
1176
+ if (typeof __RNX_CLI_VERSION__ !== "undefined" && typeof __RNX_CLI_VERSION__ === "string" && __RNX_CLI_VERSION__) {
1177
+ cached2 = __RNX_CLI_VERSION__;
1178
+ return cached2;
1179
+ }
1162
1180
  const candidates = [
1163
1181
  () => (0, import_node_url2.fileURLToPath)(import_meta.resolve(`${rnxPublicBrand.packageName}/package.json`)),
1164
1182
  () => (0, import_node_url2.fileURLToPath)(new URL("../package.json", __sootsim_import_meta_url))
1165
1183
  ];
1166
1184
  for (const resolve2 of candidates) {
1167
1185
  try {
1168
- const version = JSON.parse((0, import_node_fs2.readFileSync)(resolve2(), "utf8")).version;
1186
+ const version = JSON.parse((0, import_node_fs3.readFileSync)(resolve2(), "utf8")).version;
1169
1187
  if (typeof version === "string" && version) {
1170
1188
  cached2 = version;
1171
1189
  return cached2;
@@ -1179,19 +1197,19 @@ function getCliVersion() {
1179
1197
 
1180
1198
  // src/home-paths.ts
1181
1199
  var import_node_crypto = require("node:crypto");
1182
- var import_node_fs3 = __toESM(require("node:fs"), 1);
1200
+ var import_node_fs4 = __toESM(require("node:fs"), 1);
1183
1201
  var import_node_os = require("node:os");
1184
1202
  var import_node_path4 = __toESM(require("node:path"), 1);
1185
- var SOOTSIM_HOME_ENV = "SOOTSIM_HOME";
1203
+ var RNX_HOME_ENV = "RNX_HOME";
1186
1204
  var ACTIVE_RUNTIME_FILE = "active";
1187
1205
  var DAEMON_LOCKFILE = "daemon.json";
1188
1206
  var DEV_BRIDGES_DIR = "dev-bridges";
1189
1207
  var CONFIG_FILE = "config.json";
1190
1208
  var DAEMON_HEARTBEAT_STALE_MS = 3e4;
1191
- function sootsimHomeDir() {
1192
- const override = process.env[SOOTSIM_HOME_ENV];
1209
+ function rnxHomeDir() {
1210
+ const override = process.env[RNX_HOME_ENV];
1193
1211
  if (override && override.length > 0) return import_node_path4.default.resolve(override);
1194
- return import_node_path4.default.join((0, import_node_os.homedir)(), ".sootsim");
1212
+ return import_node_path4.default.join((0, import_node_os.homedir)(), ".rnx");
1195
1213
  }
1196
1214
  function isSootsimDevCheckout() {
1197
1215
  if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
@@ -1201,14 +1219,14 @@ function isSootsimDevCheckout() {
1201
1219
  const argv1 = process.argv[1];
1202
1220
  if (!argv1) return false;
1203
1221
  try {
1204
- const real = import_node_fs3.default.realpathSync(argv1);
1222
+ const real = import_node_fs4.default.realpathSync(argv1);
1205
1223
  return real.includes(`${import_node_path4.default.sep}packages${import_node_path4.default.sep}sootsim${import_node_path4.default.sep}`);
1206
1224
  } catch {
1207
1225
  return false;
1208
1226
  }
1209
1227
  }
1210
1228
  function runtimesDir() {
1211
- return import_node_path4.default.join(sootsimHomeDir(), "runtimes");
1229
+ return import_node_path4.default.join(rnxHomeDir(), "runtimes");
1212
1230
  }
1213
1231
  function runtimeDir(version) {
1214
1232
  return import_node_path4.default.join(runtimesDir(), version);
@@ -1217,25 +1235,25 @@ function activeRuntimeFile() {
1217
1235
  return import_node_path4.default.join(runtimesDir(), ACTIVE_RUNTIME_FILE);
1218
1236
  }
1219
1237
  function electronDir() {
1220
- return import_node_path4.default.join(sootsimHomeDir(), "electron");
1238
+ return import_node_path4.default.join(rnxHomeDir(), "electron");
1221
1239
  }
1222
1240
  function electronUserDataDir() {
1223
1241
  return import_node_path4.default.join(electronDir(), "userData");
1224
1242
  }
1225
1243
  function profilesDir() {
1226
- return import_node_path4.default.join(sootsimHomeDir(), "profiles");
1244
+ return import_node_path4.default.join(rnxHomeDir(), "profiles");
1227
1245
  }
1228
1246
  function cameraFixturesDir() {
1229
- return import_node_path4.default.join(sootsimHomeDir(), "camera-fixtures");
1247
+ return import_node_path4.default.join(rnxHomeDir(), "camera-fixtures");
1230
1248
  }
1231
1249
  function cacheDir() {
1232
- return import_node_path4.default.join(sootsimHomeDir(), "cache");
1250
+ return import_node_path4.default.join(rnxHomeDir(), "cache");
1233
1251
  }
1234
1252
  function daemonLockfilePath() {
1235
- return import_node_path4.default.join(sootsimHomeDir(), DAEMON_LOCKFILE);
1253
+ return import_node_path4.default.join(rnxHomeDir(), DAEMON_LOCKFILE);
1236
1254
  }
1237
1255
  function devBridgesDir() {
1238
- return import_node_path4.default.join(sootsimHomeDir(), DEV_BRIDGES_DIR);
1256
+ return import_node_path4.default.join(rnxHomeDir(), DEV_BRIDGES_DIR);
1239
1257
  }
1240
1258
  function devBridgeLockfilePath(bridgePort) {
1241
1259
  if (!Number.isInteger(bridgePort) || bridgePort <= 0) {
@@ -1244,11 +1262,11 @@ function devBridgeLockfilePath(bridgePort) {
1244
1262
  return import_node_path4.default.join(devBridgesDir(), `${bridgePort}.json`);
1245
1263
  }
1246
1264
  function configFilePath() {
1247
- return import_node_path4.default.join(sootsimHomeDir(), CONFIG_FILE);
1265
+ return import_node_path4.default.join(rnxHomeDir(), CONFIG_FILE);
1248
1266
  }
1249
1267
  function readSharedConfig() {
1250
1268
  try {
1251
- const raw = import_node_fs3.default.readFileSync(configFilePath(), "utf8");
1269
+ const raw = import_node_fs4.default.readFileSync(configFilePath(), "utf8");
1252
1270
  const parsed = JSON.parse(raw);
1253
1271
  return parsed && typeof parsed === "object" ? parsed : {};
1254
1272
  } catch {
@@ -1256,7 +1274,7 @@ function readSharedConfig() {
1256
1274
  }
1257
1275
  }
1258
1276
  function writeSharedConfig(patch) {
1259
- ensureSootsimHome();
1277
+ ensureRnxHome();
1260
1278
  const current = readSharedConfig();
1261
1279
  const next = { ...current, ...patch };
1262
1280
  if (patch.settings && typeof patch.settings === "object") {
@@ -1266,39 +1284,39 @@ function writeSharedConfig(patch) {
1266
1284
  };
1267
1285
  }
1268
1286
  const tmp = `${configFilePath()}.tmp`;
1269
- import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
1287
+ import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
1270
1288
  `, "utf8");
1271
- import_node_fs3.default.renameSync(tmp, configFilePath());
1289
+ import_node_fs4.default.renameSync(tmp, configFilePath());
1272
1290
  return next;
1273
1291
  }
1274
1292
  function runtimeUpgradeNoticePath() {
1275
- return import_node_path4.default.join(sootsimHomeDir(), "runtime-upgraded.json");
1293
+ return import_node_path4.default.join(rnxHomeDir(), "runtime-upgraded.json");
1276
1294
  }
1277
1295
  function writeRuntimeUpgradeNotice(notice) {
1278
- ensureSootsimHome();
1296
+ ensureRnxHome();
1279
1297
  const tmp = `${runtimeUpgradeNoticePath()}.tmp`;
1280
- import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(notice)}
1298
+ import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(notice)}
1281
1299
  `, "utf8");
1282
- import_node_fs3.default.renameSync(tmp, runtimeUpgradeNoticePath());
1300
+ import_node_fs4.default.renameSync(tmp, runtimeUpgradeNoticePath());
1283
1301
  }
1284
- function ensureSootsimHome() {
1285
- import_node_fs3.default.mkdirSync(sootsimHomeDir(), { recursive: true });
1286
- import_node_fs3.default.mkdirSync(runtimesDir(), { recursive: true });
1287
- import_node_fs3.default.mkdirSync(electronDir(), { recursive: true });
1288
- import_node_fs3.default.mkdirSync(profilesDir(), { recursive: true });
1289
- import_node_fs3.default.mkdirSync(cacheDir(), { recursive: true });
1302
+ function ensureRnxHome() {
1303
+ import_node_fs4.default.mkdirSync(rnxHomeDir(), { recursive: true });
1304
+ import_node_fs4.default.mkdirSync(runtimesDir(), { recursive: true });
1305
+ import_node_fs4.default.mkdirSync(electronDir(), { recursive: true });
1306
+ import_node_fs4.default.mkdirSync(profilesDir(), { recursive: true });
1307
+ import_node_fs4.default.mkdirSync(cacheDir(), { recursive: true });
1290
1308
  }
1291
1309
  function readActiveRuntime() {
1292
1310
  try {
1293
- const value = import_node_fs3.default.readFileSync(activeRuntimeFile(), "utf8").trim();
1311
+ const value = import_node_fs4.default.readFileSync(activeRuntimeFile(), "utf8").trim();
1294
1312
  return value.length > 0 ? value : null;
1295
1313
  } catch {
1296
1314
  return null;
1297
1315
  }
1298
1316
  }
1299
1317
  function writeActiveRuntime(version) {
1300
- import_node_fs3.default.mkdirSync(runtimesDir(), { recursive: true });
1301
- import_node_fs3.default.writeFileSync(activeRuntimeFile(), `${version}
1318
+ import_node_fs4.default.mkdirSync(runtimesDir(), { recursive: true });
1319
+ import_node_fs4.default.writeFileSync(activeRuntimeFile(), `${version}
1302
1320
  `, "utf8");
1303
1321
  }
1304
1322
  function activeRuntimeDir() {
@@ -1306,7 +1324,7 @@ function activeRuntimeDir() {
1306
1324
  if (!version) return null;
1307
1325
  const dir = runtimeDir(version);
1308
1326
  try {
1309
- if (import_node_fs3.default.statSync(dir).isDirectory()) return dir;
1327
+ if (import_node_fs4.default.statSync(dir).isDirectory()) return dir;
1310
1328
  } catch {
1311
1329
  }
1312
1330
  return null;
@@ -1315,10 +1333,10 @@ var DAEMON_LOCKFILE_MAX_BYTES = 16 * 1024;
1315
1333
  var DAEMON_CLAIM_STALE_MS = 3e4;
1316
1334
  function readDaemonLockfile() {
1317
1335
  try {
1318
- const fd = import_node_fs3.default.openSync(daemonLockfilePath(), "r");
1336
+ const fd = import_node_fs4.default.openSync(daemonLockfilePath(), "r");
1319
1337
  try {
1320
1338
  const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
1321
- const bytesRead = import_node_fs3.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
1339
+ const bytesRead = import_node_fs4.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
1322
1340
  const raw = buf.subarray(0, bytesRead).toString("utf8");
1323
1341
  const parsed = JSON.parse(raw);
1324
1342
  if (parsed && parsed.schema === 1 && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
@@ -1326,7 +1344,7 @@ function readDaemonLockfile() {
1326
1344
  }
1327
1345
  return null;
1328
1346
  } finally {
1329
- import_node_fs3.default.closeSync(fd);
1347
+ import_node_fs4.default.closeSync(fd);
1330
1348
  }
1331
1349
  } catch {
1332
1350
  return null;
@@ -1354,7 +1372,7 @@ function isDaemonLockfileFresh(lock, now = Date.now()) {
1354
1372
  }
1355
1373
  }
1356
1374
  function writeDaemonLockfile(data) {
1357
- ensureSootsimHome();
1375
+ ensureRnxHome();
1358
1376
  const lockfilePath = daemonLockfilePath();
1359
1377
  const existing = readDaemonLockfile();
1360
1378
  if (!existing) {
@@ -1365,28 +1383,28 @@ function writeDaemonLockfile(data) {
1365
1383
  throw new Error("refusing to overwrite another rnx daemon lockfile");
1366
1384
  }
1367
1385
  const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.tmp`;
1368
- import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1386
+ import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1369
1387
  `, "utf8");
1370
1388
  try {
1371
1389
  const current = readDaemonLockfile();
1372
1390
  if (!current || !sameDaemonOwner(current, data)) {
1373
1391
  throw new Error("rnx daemon lock ownership changed during heartbeat");
1374
1392
  }
1375
- import_node_fs3.default.renameSync(tmp, lockfilePath);
1393
+ import_node_fs4.default.renameSync(tmp, lockfilePath);
1376
1394
  } finally {
1377
1395
  try {
1378
- import_node_fs3.default.unlinkSync(tmp);
1396
+ import_node_fs4.default.unlinkSync(tmp);
1379
1397
  } catch {
1380
1398
  }
1381
1399
  }
1382
1400
  }
1383
1401
  function writeDevBridgeLockfile(data) {
1384
- import_node_fs3.default.mkdirSync(devBridgesDir(), { recursive: true });
1402
+ import_node_fs4.default.mkdirSync(devBridgesDir(), { recursive: true });
1385
1403
  const lockfilePath = devBridgeLockfilePath(data.bridgePort);
1386
1404
  const tmp = `${lockfilePath}.${data.pid}.tmp`;
1387
- import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1405
+ import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1388
1406
  `, "utf8");
1389
- import_node_fs3.default.renameSync(tmp, lockfilePath);
1407
+ import_node_fs4.default.renameSync(tmp, lockfilePath);
1390
1408
  }
1391
1409
  function sameDaemonOwner(left, right) {
1392
1410
  return left.pid === right.pid && left.startedAt === right.startedAt;
@@ -1397,17 +1415,17 @@ function isAlreadyExists(error) {
1397
1415
  function createDaemonLockfileExclusive(data) {
1398
1416
  const lockfilePath = daemonLockfilePath();
1399
1417
  const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.claim`;
1400
- import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1418
+ import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
1401
1419
  `, "utf8");
1402
1420
  try {
1403
- import_node_fs3.default.linkSync(tmp, lockfilePath);
1421
+ import_node_fs4.default.linkSync(tmp, lockfilePath);
1404
1422
  return true;
1405
1423
  } catch (error) {
1406
1424
  if (isAlreadyExists(error)) return false;
1407
1425
  throw error;
1408
1426
  } finally {
1409
1427
  try {
1410
- import_node_fs3.default.unlinkSync(tmp);
1428
+ import_node_fs4.default.unlinkSync(tmp);
1411
1429
  } catch {
1412
1430
  }
1413
1431
  }
@@ -1431,7 +1449,7 @@ function parseDaemonClaim(raw) {
1431
1449
  }
1432
1450
  function readDaemonClaim() {
1433
1451
  try {
1434
- return parseDaemonClaim(import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8"));
1452
+ return parseDaemonClaim(import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8"));
1435
1453
  } catch {
1436
1454
  return null;
1437
1455
  }
@@ -1455,7 +1473,7 @@ function acquireDaemonClaim(data) {
1455
1473
  `;
1456
1474
  for (let attempt = 0; attempt < 8; attempt++) {
1457
1475
  try {
1458
- import_node_fs3.default.writeFileSync(daemonClaimPath(), serialized, { encoding: "utf8", flag: "wx" });
1476
+ import_node_fs4.default.writeFileSync(daemonClaimPath(), serialized, { encoding: "utf8", flag: "wx" });
1459
1477
  return true;
1460
1478
  } catch (error) {
1461
1479
  if (!isAlreadyExists(error)) throw error;
@@ -1465,11 +1483,11 @@ function acquireDaemonClaim(data) {
1465
1483
  if (existing && isDaemonClaimFresh(existing)) return false;
1466
1484
  let before;
1467
1485
  try {
1468
- before = import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8");
1486
+ before = import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8");
1469
1487
  const latest = parseDaemonClaim(before);
1470
1488
  if (latest && isDaemonClaimFresh(latest)) return false;
1471
- if (import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8") !== before) continue;
1472
- import_node_fs3.default.unlinkSync(daemonClaimPath());
1489
+ if (import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8") !== before) continue;
1490
+ import_node_fs4.default.unlinkSync(daemonClaimPath());
1473
1491
  } catch {
1474
1492
  }
1475
1493
  }
@@ -1479,12 +1497,12 @@ function releaseDaemonClaim(owner) {
1479
1497
  try {
1480
1498
  const claim = readDaemonClaim();
1481
1499
  if (!claim || !sameDaemonOwner(claim, owner)) return;
1482
- import_node_fs3.default.unlinkSync(daemonClaimPath());
1500
+ import_node_fs4.default.unlinkSync(daemonClaimPath());
1483
1501
  } catch {
1484
1502
  }
1485
1503
  }
1486
1504
  function claimDaemonLockfile(data) {
1487
- ensureSootsimHome();
1505
+ ensureRnxHome();
1488
1506
  if (!acquireDaemonClaim(data)) return false;
1489
1507
  try {
1490
1508
  const existing = readDaemonLockfile();
@@ -1498,7 +1516,7 @@ function claimDaemonLockfile(data) {
1498
1516
  if (!latest || !sameDaemonOwner(latest, existing)) return false;
1499
1517
  if (isDaemonLockfileFresh(latest)) return false;
1500
1518
  try {
1501
- import_node_fs3.default.unlinkSync(daemonLockfilePath());
1519
+ import_node_fs4.default.unlinkSync(daemonLockfilePath());
1502
1520
  } catch {
1503
1521
  return false;
1504
1522
  }
@@ -1512,16 +1530,16 @@ function removeDaemonLockfile(owner) {
1512
1530
  try {
1513
1531
  const lockfile = readDaemonLockfile();
1514
1532
  if (!lockfile || !sameDaemonOwner(lockfile, owner)) return;
1515
- import_node_fs3.default.unlinkSync(daemonLockfilePath());
1533
+ import_node_fs4.default.unlinkSync(daemonLockfilePath());
1516
1534
  } catch {
1517
1535
  }
1518
1536
  }
1519
1537
  function removeDevBridgeLockfile(owner) {
1520
1538
  try {
1521
1539
  const lockfilePath = devBridgeLockfilePath(owner.bridgePort);
1522
- const lockfile = parseDevBridgeLockfile(import_node_fs3.default.readFileSync(lockfilePath, "utf8"));
1540
+ const lockfile = parseDevBridgeLockfile(import_node_fs4.default.readFileSync(lockfilePath, "utf8"));
1523
1541
  if (lockfile?.pid !== owner.pid || lockfile.startedAt !== owner.startedAt) return;
1524
- import_node_fs3.default.unlinkSync(lockfilePath);
1542
+ import_node_fs4.default.unlinkSync(lockfilePath);
1525
1543
  } catch {
1526
1544
  }
1527
1545
  }
@@ -1534,21 +1552,21 @@ var import_url = require("url");
1534
1552
  // ../contrast-runtime-delivery/src/index.ts
1535
1553
  var import_node_child_process = require("node:child_process");
1536
1554
  var import_node_crypto2 = __toESM(require("node:crypto"), 1);
1537
- var import_node_fs5 = __toESM(require("node:fs"), 1);
1555
+ var import_node_fs6 = __toESM(require("node:fs"), 1);
1538
1556
  var import_node_os2 = __toESM(require("node:os"), 1);
1539
1557
  var import_node_path6 = __toESM(require("node:path"), 1);
1540
1558
  var import_node_stream = require("node:stream");
1541
1559
  var import_promises3 = require("node:stream/promises");
1542
1560
 
1543
1561
  // ../contrast-runtime-delivery/src/product.ts
1544
- var import_node_fs4 = __toESM(require("node:fs"), 1);
1562
+ var import_node_fs5 = __toESM(require("node:fs"), 1);
1545
1563
  var import_node_path5 = __toESM(require("node:path"), 1);
1546
1564
  function isValidRuntimeVersion(value) {
1547
1565
  return value.length <= 100 && /^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(value);
1548
1566
  }
1549
1567
  function listInstalledRuntimes(product) {
1550
1568
  try {
1551
- return import_node_fs4.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
1569
+ return import_node_fs5.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
1552
1570
  } catch {
1553
1571
  return [];
1554
1572
  }
@@ -1584,7 +1602,7 @@ function createRuntimeDelivery(product) {
1584
1602
  function readConfig() {
1585
1603
  try {
1586
1604
  const parsed = JSON.parse(
1587
- import_node_fs5.default.readFileSync(product.configFile(), "utf8")
1605
+ import_node_fs6.default.readFileSync(product.configFile(), "utf8")
1588
1606
  );
1589
1607
  return parsed && typeof parsed === "object" ? parsed : {};
1590
1608
  } catch {
@@ -1657,7 +1675,7 @@ function createRuntimeDelivery(product) {
1657
1675
  const setActive = opts.setActive !== false;
1658
1676
  const protectVersions = [version, ...opts.protectVersions ?? []];
1659
1677
  pruneLocalRetention({ protectVersions });
1660
- if (!opts.force && import_node_fs5.default.existsSync(import_node_path6.default.join(destDir, product.installedMarker))) {
1678
+ if (!opts.force && import_node_fs6.default.existsSync(import_node_path6.default.join(destDir, product.installedMarker))) {
1661
1679
  if (setActive) product.writeActiveRuntime(version);
1662
1680
  pruneLocalRetention({ protectVersions });
1663
1681
  return {
@@ -1671,7 +1689,7 @@ function createRuntimeDelivery(product) {
1671
1689
  };
1672
1690
  }
1673
1691
  const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
1674
- const downloadDir = import_node_fs5.default.mkdtempSync(
1692
+ const downloadDir = import_node_fs6.default.mkdtempSync(
1675
1693
  import_node_path6.default.join(import_node_os2.default.tmpdir(), `${product.id}-runtime-download-`)
1676
1694
  );
1677
1695
  const runtimeArchivePath = import_node_path6.default.join(
@@ -1682,7 +1700,7 @@ function createRuntimeDelivery(product) {
1682
1700
  import_node_path6.default.dirname(destDir),
1683
1701
  `.installing-${version}-${process.pid}`
1684
1702
  );
1685
- import_node_fs5.default.rmSync(tmpDir, { recursive: true, force: true });
1703
+ import_node_fs6.default.rmSync(tmpDir, { recursive: true, force: true });
1686
1704
  try {
1687
1705
  process.stderr.write(`${product.id}: downloading runtime ${version}\u2026
1688
1706
  `);
@@ -1695,20 +1713,20 @@ function createRuntimeDelivery(product) {
1695
1713
  `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
1696
1714
  );
1697
1715
  }
1698
- import_node_fs5.default.mkdirSync(tmpDir, { recursive: true });
1716
+ import_node_fs6.default.mkdirSync(tmpDir, { recursive: true });
1699
1717
  await extractTarball(runtimeArchivePath, tmpDir);
1700
- if (!import_node_fs5.default.existsSync(import_node_path6.default.join(tmpDir, product.installedMarker))) {
1718
+ if (!import_node_fs6.default.existsSync(import_node_path6.default.join(tmpDir, product.installedMarker))) {
1701
1719
  throw new Error(
1702
1720
  `extracted tarball for runtime ${version} is missing ${product.installedMarker}`
1703
1721
  );
1704
1722
  }
1705
- import_node_fs5.default.rmSync(destDir, { recursive: true, force: true });
1706
- import_node_fs5.default.renameSync(tmpDir, destDir);
1723
+ import_node_fs6.default.rmSync(destDir, { recursive: true, force: true });
1724
+ import_node_fs6.default.renameSync(tmpDir, destDir);
1707
1725
  } catch (err) {
1708
- import_node_fs5.default.rmSync(tmpDir, { recursive: true, force: true });
1726
+ import_node_fs6.default.rmSync(tmpDir, { recursive: true, force: true });
1709
1727
  throw err;
1710
1728
  } finally {
1711
- import_node_fs5.default.rmSync(downloadDir, { recursive: true, force: true });
1729
+ import_node_fs6.default.rmSync(downloadDir, { recursive: true, force: true });
1712
1730
  }
1713
1731
  if (setActive) product.writeActiveRuntime(version);
1714
1732
  pruneLocalRetention({ protectVersions });
@@ -1730,7 +1748,7 @@ function createRuntimeDelivery(product) {
1730
1748
  const pin = resolvePin();
1731
1749
  if (pin) {
1732
1750
  const activeVersion2 = product.readActiveRuntime();
1733
- const pinInstalled = import_node_fs5.default.existsSync(
1751
+ const pinInstalled = import_node_fs6.default.existsSync(
1734
1752
  import_node_path6.default.join(product.runtimeDir(pin), product.installedMarker)
1735
1753
  );
1736
1754
  if (activeVersion2 === pin && pinInstalled) {
@@ -1780,7 +1798,7 @@ function createRuntimeDelivery(product) {
1780
1798
  }
1781
1799
  const activeVersion = product.readActiveRuntime();
1782
1800
  const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
1783
- const activeInstalled = activeDir ? import_node_fs5.default.existsSync(import_node_path6.default.join(activeDir, product.installedMarker)) : false;
1801
+ const activeInstalled = activeDir ? import_node_fs6.default.existsSync(import_node_path6.default.join(activeDir, product.installedMarker)) : false;
1784
1802
  const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
1785
1803
  if (!shouldInstall) {
1786
1804
  return {
@@ -1855,7 +1873,7 @@ function createRuntimeDelivery(product) {
1855
1873
  let removeCacheFiles = [];
1856
1874
  if (markerOffset >= 0) {
1857
1875
  try {
1858
- removeCacheFiles = import_node_fs5.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
1876
+ removeCacheFiles = import_node_fs6.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
1859
1877
  if (!entry.isFile()) return false;
1860
1878
  const complete = entry.name.startsWith(cachePrefix) && entry.name.endsWith(cacheSuffix);
1861
1879
  const partial = entry.name.startsWith(cachePrefix) && entry.name.endsWith(`${cacheSuffix}.partial`);
@@ -1875,10 +1893,10 @@ function createRuntimeDelivery(product) {
1875
1893
  function pruneLocalRetention(opts = {}) {
1876
1894
  const plan = planLocalRetention(opts);
1877
1895
  for (const version of plan.removeVersions) {
1878
- import_node_fs5.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
1896
+ import_node_fs6.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
1879
1897
  }
1880
1898
  for (const cacheFile of plan.removeCacheFiles) {
1881
- import_node_fs5.default.rmSync(cacheFile, { force: true });
1899
+ import_node_fs6.default.rmSync(cacheFile, { force: true });
1882
1900
  }
1883
1901
  return plan;
1884
1902
  }
@@ -1904,17 +1922,17 @@ async function downloadToFile(url, destPath) {
1904
1922
  if (!res.ok || !res.body) {
1905
1923
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
1906
1924
  }
1907
- import_node_fs5.default.mkdirSync(import_node_path6.default.dirname(destPath), { recursive: true });
1925
+ import_node_fs6.default.mkdirSync(import_node_path6.default.dirname(destPath), { recursive: true });
1908
1926
  const tmp = `${destPath}.partial`;
1909
1927
  try {
1910
1928
  await (0, import_promises3.pipeline)(
1911
1929
  import_node_stream.Readable.fromWeb(res.body),
1912
- import_node_fs5.default.createWriteStream(tmp)
1930
+ import_node_fs6.default.createWriteStream(tmp)
1913
1931
  );
1914
- import_node_fs5.default.renameSync(tmp, destPath);
1932
+ import_node_fs6.default.renameSync(tmp, destPath);
1915
1933
  } catch (err) {
1916
1934
  try {
1917
- import_node_fs5.default.unlinkSync(tmp);
1935
+ import_node_fs6.default.unlinkSync(tmp);
1918
1936
  } catch {
1919
1937
  }
1920
1938
  throw err;
@@ -1923,7 +1941,7 @@ async function downloadToFile(url, destPath) {
1923
1941
  function sha256File(filePath) {
1924
1942
  return new Promise((resolve2, reject) => {
1925
1943
  const hash = import_node_crypto2.default.createHash("sha256");
1926
- const stream = import_node_fs5.default.createReadStream(filePath);
1944
+ const stream = import_node_fs6.default.createReadStream(filePath);
1927
1945
  stream.on("data", (chunk) => hash.update(chunk));
1928
1946
  stream.on("error", reject);
1929
1947
  stream.on("end", () => resolve2(hash.digest("hex")));
@@ -1958,7 +1976,7 @@ function findMonorepoRoot() {
1958
1976
  return null;
1959
1977
  }
1960
1978
  function resolveDevCheckoutRuntimeRoot() {
1961
- if (process.env.SOOTSIM_HOME && readActiveRuntime()) return null;
1979
+ if (process.env.RNX_HOME && readActiveRuntime()) return null;
1962
1980
  const root = findMonorepoRoot();
1963
1981
  if (!root) return null;
1964
1982
  const devBuild = import_path.default.join(root, "public/sootsim");
@@ -2008,9 +2026,9 @@ function resolveRuntimeRootForHostname(hostname) {
2008
2026
 
2009
2027
  // src/runtime-delivery.ts
2010
2028
  var DEFAULT_RUNTIME_CDN_ORIGIN = "https://contrast.dev";
2011
- var SOOTSIM_CHANGELOG_URL = `${rnxPublicBrand.origin}/changelog`;
2012
- var SOOTSIM_RUNTIME_PRODUCT = {
2013
- id: "sootsim",
2029
+ var RNX_CHANGELOG_URL = `${rnxPublicBrand.origin}/changelog`;
2030
+ var RNX_RUNTIME_PRODUCT = {
2031
+ id: "rnx",
2014
2032
  defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
2015
2033
  manifestPath: "/runtimes/manifest.json",
2016
2034
  tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
@@ -2019,10 +2037,10 @@ var SOOTSIM_RUNTIME_PRODUCT = {
2019
2037
  // vite/metro plugins serve, so its absence means the tarball is not one.
2020
2038
  installedMarker: "index.html",
2021
2039
  env: {
2022
- cdnOrigin: "SOOTSIM_CDN_ORIGIN",
2023
- channel: "SOOTSIM_RUNTIME_CHANNEL"
2040
+ cdnOrigin: "RNX_CDN_ORIGIN",
2041
+ channel: "RNX_RUNTIME_CHANNEL"
2024
2042
  },
2025
- ensureHome: ensureSootsimHome,
2043
+ ensureHome: ensureRnxHome,
2026
2044
  configFile: configFilePath,
2027
2045
  runtimesDir,
2028
2046
  runtimeDir,
@@ -2030,16 +2048,16 @@ var SOOTSIM_RUNTIME_PRODUCT = {
2030
2048
  readActiveRuntime,
2031
2049
  writeActiveRuntime
2032
2050
  };
2033
- var sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT);
2051
+ var rnxRuntime = createRuntimeDelivery(RNX_RUNTIME_PRODUCT);
2034
2052
 
2035
2053
  // src/host/agent-host.ts
2036
- var import_node_fs8 = __toESM(require("node:fs"), 1);
2054
+ var import_node_fs9 = __toESM(require("node:fs"), 1);
2037
2055
  var import_node_path9 = __toESM(require("node:path"), 1);
2038
2056
 
2039
2057
  // src/agent-sessions.ts
2040
2058
  var import_node_child_process2 = require("node:child_process");
2041
2059
  var import_node_crypto4 = require("node:crypto");
2042
- var import_node_fs7 = __toESM(require("node:fs"), 1);
2060
+ var import_node_fs8 = __toESM(require("node:fs"), 1);
2043
2061
  var import_node_path8 = __toESM(require("node:path"), 1);
2044
2062
  var import_node_readline = __toESM(require("node:readline"), 1);
2045
2063
 
@@ -2084,7 +2102,7 @@ function encodeAgentPromptEnvelope(input) {
2084
2102
 
2085
2103
  // src/attached-projects.ts
2086
2104
  var import_node_crypto3 = require("node:crypto");
2087
- var import_node_fs6 = __toESM(require("node:fs"), 1);
2105
+ var import_node_fs7 = __toESM(require("node:fs"), 1);
2088
2106
  var import_node_path7 = __toESM(require("node:path"), 1);
2089
2107
  var overrideDir = null;
2090
2108
  function userDataDir() {
@@ -2111,7 +2129,7 @@ function loadStore() {
2111
2129
  const file = storeFile();
2112
2130
  let raw;
2113
2131
  try {
2114
- raw = import_node_fs6.default.readFileSync(file, "utf8");
2132
+ raw = import_node_fs7.default.readFileSync(file, "utf8");
2115
2133
  } catch (err) {
2116
2134
  if (err.code === "ENOENT") return cloneEmpty();
2117
2135
  throw err;
@@ -2128,7 +2146,7 @@ function loadStore() {
2128
2146
  } catch (err) {
2129
2147
  const quarantine = `${file}.corrupt-${Date.now()}`;
2130
2148
  try {
2131
- import_node_fs6.default.renameSync(file, quarantine);
2149
+ import_node_fs7.default.renameSync(file, quarantine);
2132
2150
  console.warn(
2133
2151
  `[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
2134
2152
  );
@@ -2139,16 +2157,16 @@ function loadStore() {
2139
2157
  }
2140
2158
  function writeStore(store) {
2141
2159
  const file = storeFile();
2142
- import_node_fs6.default.mkdirSync(import_node_path7.default.dirname(file), { recursive: true });
2160
+ import_node_fs7.default.mkdirSync(import_node_path7.default.dirname(file), { recursive: true });
2143
2161
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
2144
- const fd = import_node_fs6.default.openSync(tmp, "w", 384);
2162
+ const fd = import_node_fs7.default.openSync(tmp, "w", 384);
2145
2163
  try {
2146
- import_node_fs6.default.writeFileSync(fd, JSON.stringify(store, null, 2));
2147
- import_node_fs6.default.fsyncSync(fd);
2164
+ import_node_fs7.default.writeFileSync(fd, JSON.stringify(store, null, 2));
2165
+ import_node_fs7.default.fsyncSync(fd);
2148
2166
  } finally {
2149
- import_node_fs6.default.closeSync(fd);
2167
+ import_node_fs7.default.closeSync(fd);
2150
2168
  }
2151
- import_node_fs6.default.renameSync(tmp, file);
2169
+ import_node_fs7.default.renameSync(tmp, file);
2152
2170
  }
2153
2171
  function mutateStore(fn) {
2154
2172
  const store = loadStore();
@@ -2335,7 +2353,7 @@ async function seedFromDemoAppRegistry() {
2335
2353
  if (apps.length === 0) return;
2336
2354
  mutateStore((store) => {
2337
2355
  for (const app of apps) {
2338
- if (!import_node_fs6.default.existsSync(app.dir)) continue;
2356
+ if (!import_node_fs7.default.existsSync(app.dir)) continue;
2339
2357
  const cwd = import_node_path7.default.resolve(app.dir);
2340
2358
  const id = projectIdForCwd(cwd);
2341
2359
  if (store.attachedProjects.some((p) => p.id === id)) continue;
@@ -2379,13 +2397,13 @@ function pidIsAlive(pid, sessionId) {
2379
2397
  return false;
2380
2398
  }
2381
2399
  if (sessionId) {
2382
- if (!import_node_fs7.default.existsSync(sessionDir(sessionId))) return false;
2400
+ if (!import_node_fs8.default.existsSync(sessionDir(sessionId))) return false;
2383
2401
  }
2384
2402
  return true;
2385
2403
  }
2386
2404
  function resolveSootsimInvocation() {
2387
- if (process.env.SOOTSIM_BIN) {
2388
- return { cmd: process.env.SOOTSIM_BIN, prefixArgs: [] };
2405
+ if (process.env.RNX_BIN) {
2406
+ return { cmd: process.env.RNX_BIN, prefixArgs: [] };
2389
2407
  }
2390
2408
  if (process.versions.electron) {
2391
2409
  const resourcesPath = process.resourcesPath;
@@ -2395,7 +2413,7 @@ function resolveSootsimInvocation() {
2395
2413
  import_node_path8.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
2396
2414
  ];
2397
2415
  for (const c of candidates) {
2398
- if (import_node_fs7.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
2416
+ if (import_node_fs8.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
2399
2417
  }
2400
2418
  }
2401
2419
  }
@@ -2408,7 +2426,7 @@ function resolveSootsimInvocation() {
2408
2426
  }
2409
2427
  if (!argv1 || argv1.includes("/.bin/")) {
2410
2428
  throw new Error(
2411
- "rnx CLI not found. set SOOTSIM_BIN to the path of the rnx binary, or build the workspace CLI via `bun run --cwd packages/sootsim build:cli`."
2429
+ "rnx CLI not found. set RNX_BIN to the path of the rnx binary, or build the workspace CLI via `bun run --cwd packages/sootsim build:cli`."
2412
2430
  );
2413
2431
  }
2414
2432
  return { cmd: argv0, prefixArgs: [] };
@@ -2417,16 +2435,16 @@ function tryWorkspaceSootsim() {
2417
2435
  try {
2418
2436
  const sootsimDir = resolveSootsimPackageDir();
2419
2437
  if (!sootsimDir) return null;
2420
- const binaryName = `sootsim-${process.platform}-${process.arch}`;
2438
+ const binaryName = `rnx-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`;
2421
2439
  const distBinary = import_node_path8.default.join(sootsimDir, "dist-bin", binaryName);
2422
- if (import_node_fs7.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
2440
+ if (import_node_fs8.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
2423
2441
  const distBin = import_node_path8.default.join(sootsimDir, "dist-cli", "bin.js");
2424
- if (import_node_fs7.default.existsSync(distBin)) {
2442
+ if (import_node_fs8.default.existsSync(distBin)) {
2425
2443
  try {
2426
2444
  const src = import_node_path8.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
2427
- if (import_node_fs7.default.existsSync(src)) {
2428
- const srcMtime = import_node_fs7.default.statSync(src).mtimeMs;
2429
- const buildMtime = import_node_fs7.default.statSync(distBin).mtimeMs;
2445
+ if (import_node_fs8.default.existsSync(src)) {
2446
+ const srcMtime = import_node_fs8.default.statSync(src).mtimeMs;
2447
+ const buildMtime = import_node_fs8.default.statSync(distBin).mtimeMs;
2430
2448
  if (buildMtime < srcMtime) {
2431
2449
  console.warn(
2432
2450
  `[rnx] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/sootsim build:cli\`.`
@@ -2454,8 +2472,8 @@ function resolveSootsimPackageDir() {
2454
2472
  for (let i = 0; i < 8; i++) {
2455
2473
  const pkg = import_node_path8.default.join(cur, "package.json");
2456
2474
  try {
2457
- if (import_node_fs7.default.existsSync(pkg)) {
2458
- const parsed = JSON.parse(import_node_fs7.default.readFileSync(pkg, "utf8"));
2475
+ if (import_node_fs8.default.existsSync(pkg)) {
2476
+ const parsed = JSON.parse(import_node_fs8.default.readFileSync(pkg, "utf8"));
2459
2477
  if (parsed.name === rnxPublicBrand.packageName) return cur;
2460
2478
  }
2461
2479
  } catch {
@@ -2477,9 +2495,9 @@ function fileFromImportMeta() {
2477
2495
  }
2478
2496
  async function withStartLock(projectId, provider, fn) {
2479
2497
  const lockDir = import_node_path8.default.join(getUserDataDir(), "locks");
2480
- import_node_fs7.default.mkdirSync(lockDir, { recursive: true });
2498
+ import_node_fs8.default.mkdirSync(lockDir, { recursive: true });
2481
2499
  try {
2482
- import_node_fs7.default.chmodSync(lockDir, 448);
2500
+ import_node_fs8.default.chmodSync(lockDir, 448);
2483
2501
  } catch {
2484
2502
  }
2485
2503
  const lockPath = import_node_path8.default.join(lockDir, `start-${projectId}-${provider}.lock`);
@@ -2487,17 +2505,17 @@ async function withStartLock(projectId, provider, fn) {
2487
2505
  let fd = null;
2488
2506
  while (fd === null) {
2489
2507
  try {
2490
- fd = import_node_fs7.default.openSync(
2508
+ fd = import_node_fs8.default.openSync(
2491
2509
  lockPath,
2492
- import_node_fs7.constants.O_WRONLY | import_node_fs7.constants.O_CREAT | import_node_fs7.constants.O_EXCL,
2510
+ import_node_fs8.constants.O_WRONLY | import_node_fs8.constants.O_CREAT | import_node_fs8.constants.O_EXCL,
2493
2511
  384
2494
2512
  );
2495
2513
  } catch (err) {
2496
2514
  if (err.code !== "EEXIST") throw err;
2497
2515
  try {
2498
- const stale = Number(import_node_fs7.default.readFileSync(lockPath, "utf8").trim());
2516
+ const stale = Number(import_node_fs8.default.readFileSync(lockPath, "utf8").trim());
2499
2517
  if (stale && !isProcessAlive(stale)) {
2500
- import_node_fs7.default.unlinkSync(lockPath);
2518
+ import_node_fs8.default.unlinkSync(lockPath);
2501
2519
  continue;
2502
2520
  }
2503
2521
  } catch {
@@ -2511,15 +2529,15 @@ async function withStartLock(projectId, provider, fn) {
2511
2529
  }
2512
2530
  }
2513
2531
  try {
2514
- import_node_fs7.default.writeFileSync(fd, String(process.pid));
2532
+ import_node_fs8.default.writeFileSync(fd, String(process.pid));
2515
2533
  return await fn();
2516
2534
  } finally {
2517
2535
  try {
2518
- import_node_fs7.default.closeSync(fd);
2536
+ import_node_fs8.default.closeSync(fd);
2519
2537
  } catch {
2520
2538
  }
2521
2539
  try {
2522
- import_node_fs7.default.unlinkSync(lockPath);
2540
+ import_node_fs8.default.unlinkSync(lockPath);
2523
2541
  } catch {
2524
2542
  }
2525
2543
  }
@@ -2534,24 +2552,24 @@ function isProcessAlive(pid) {
2534
2552
  }
2535
2553
  function mkfifoSync(p) {
2536
2554
  const parent = import_node_path8.default.dirname(p);
2537
- import_node_fs7.default.mkdirSync(parent, { recursive: true });
2555
+ import_node_fs8.default.mkdirSync(parent, { recursive: true });
2538
2556
  try {
2539
- import_node_fs7.default.chmodSync(parent, 448);
2557
+ import_node_fs8.default.chmodSync(parent, 448);
2540
2558
  } catch {
2541
2559
  }
2542
- if (import_node_fs7.default.existsSync(p)) {
2560
+ if (import_node_fs8.default.existsSync(p)) {
2543
2561
  try {
2544
- const stat2 = import_node_fs7.default.statSync(p);
2562
+ const stat2 = import_node_fs8.default.statSync(p);
2545
2563
  if (stat2.isFIFO()) {
2546
2564
  try {
2547
- import_node_fs7.default.chmodSync(p, 384);
2565
+ import_node_fs8.default.chmodSync(p, 384);
2548
2566
  } catch {
2549
2567
  }
2550
2568
  return;
2551
2569
  }
2552
- import_node_fs7.default.unlinkSync(p);
2570
+ import_node_fs8.default.unlinkSync(p);
2553
2571
  } catch {
2554
- import_node_fs7.default.unlinkSync(p);
2572
+ import_node_fs8.default.unlinkSync(p);
2555
2573
  }
2556
2574
  }
2557
2575
  const result = (0, import_node_child_process2.spawnSync)("mkfifo", ["-m", "600", p]);
@@ -2599,9 +2617,9 @@ async function startSession(opts) {
2599
2617
  mkfifoSync(promptIn);
2600
2618
  mkfifoSync(eventsOut);
2601
2619
  const transcriptDir = import_node_path8.default.dirname(transcript);
2602
- import_node_fs7.default.mkdirSync(transcriptDir, { recursive: true });
2620
+ import_node_fs8.default.mkdirSync(transcriptDir, { recursive: true });
2603
2621
  try {
2604
- import_node_fs7.default.chmodSync(transcriptDir, 448);
2622
+ import_node_fs8.default.chmodSync(transcriptDir, 448);
2605
2623
  } catch {
2606
2624
  }
2607
2625
  const { cmd, prefixArgs } = resolveSootsimInvocation();
@@ -2652,7 +2670,7 @@ async function startSession(opts) {
2652
2670
  }
2653
2671
  }
2654
2672
  try {
2655
- import_node_fs7.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
2673
+ import_node_fs8.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
2656
2674
  } catch {
2657
2675
  }
2658
2676
  updateSessionStatus(session.id, { status: "ended" });
@@ -2680,18 +2698,18 @@ async function sendPrompt(sessionId, prompt) {
2680
2698
  );
2681
2699
  }
2682
2700
  const fifo = promptFifoPath(sessionId);
2683
- if (!import_node_fs7.default.existsSync(fifo)) {
2701
+ if (!import_node_fs8.default.existsSync(fifo)) {
2684
2702
  throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
2685
2703
  }
2686
- const fd = import_node_fs7.default.openSync(fifo, import_node_fs7.constants.O_WRONLY);
2704
+ const fd = import_node_fs8.default.openSync(fifo, import_node_fs8.constants.O_WRONLY);
2687
2705
  try {
2688
2706
  const wireText = encodeAgentPromptEnvelope(prompt);
2689
2707
  if (!wireText) {
2690
2708
  throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
2691
2709
  }
2692
- import_node_fs7.default.writeSync(fd, wireText + "\n");
2710
+ import_node_fs8.default.writeSync(fd, wireText + "\n");
2693
2711
  } finally {
2694
- import_node_fs7.default.closeSync(fd);
2712
+ import_node_fs8.default.closeSync(fd);
2695
2713
  }
2696
2714
  updateSessionStatus(sessionId, {
2697
2715
  lastPrompt: prompt.displayText ?? prompt.text,
@@ -2713,7 +2731,7 @@ async function endSession(sessionId) {
2713
2731
  const base = getUserDataDir();
2714
2732
  if (dir.startsWith(base)) {
2715
2733
  try {
2716
- import_node_fs7.default.rmSync(dir, { recursive: true, force: true });
2734
+ import_node_fs8.default.rmSync(dir, { recursive: true, force: true });
2717
2735
  } catch {
2718
2736
  }
2719
2737
  }
@@ -2721,11 +2739,11 @@ async function endSession(sessionId) {
2721
2739
  }
2722
2740
  function subscribeEvents(sessionId, onEvent) {
2723
2741
  const fifo = eventsFifoPath(sessionId);
2724
- if (!import_node_fs7.default.existsSync(fifo)) {
2742
+ if (!import_node_fs8.default.existsSync(fifo)) {
2725
2743
  throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
2726
2744
  }
2727
- const fd = import_node_fs7.default.openSync(fifo, import_node_fs7.constants.O_RDWR);
2728
- const stream = import_node_fs7.default.createReadStream("", { fd, autoClose: true });
2745
+ const fd = import_node_fs8.default.openSync(fifo, import_node_fs8.constants.O_RDWR);
2746
+ const stream = import_node_fs8.default.createReadStream("", { fd, autoClose: true });
2729
2747
  const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
2730
2748
  rl.on("line", (line) => {
2731
2749
  const event = parseAgentEventLine(line);
@@ -2736,7 +2754,7 @@ function subscribeEvents(sessionId, onEvent) {
2736
2754
  if (closed) return;
2737
2755
  closed = true;
2738
2756
  try {
2739
- import_node_fs7.default.writeSync(fd, "\n");
2757
+ import_node_fs8.default.writeSync(fd, "\n");
2740
2758
  } catch {
2741
2759
  }
2742
2760
  try {
@@ -2750,7 +2768,7 @@ function subscribeEvents(sessionId, onEvent) {
2750
2768
  };
2751
2769
  }
2752
2770
  async function waitForFirstEvent(fifo, predicate, timeoutMs) {
2753
- const fd = import_node_fs7.default.openSync(fifo, import_node_fs7.constants.O_RDWR | import_node_fs7.constants.O_NONBLOCK);
2771
+ const fd = import_node_fs8.default.openSync(fifo, import_node_fs8.constants.O_RDWR | import_node_fs8.constants.O_NONBLOCK);
2754
2772
  const buf = Buffer.alloc(8192);
2755
2773
  let leftover = "";
2756
2774
  const deadline = Date.now() + timeoutMs;
@@ -2758,7 +2776,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
2758
2776
  while (Date.now() < deadline) {
2759
2777
  let n = 0;
2760
2778
  try {
2761
- n = import_node_fs7.default.readSync(fd, buf, 0, buf.length, null);
2779
+ n = import_node_fs8.default.readSync(fd, buf, 0, buf.length, null);
2762
2780
  } catch (err) {
2763
2781
  if (err.code !== "EAGAIN") throw err;
2764
2782
  n = 0;
@@ -2778,7 +2796,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
2778
2796
  }
2779
2797
  return null;
2780
2798
  } finally {
2781
- import_node_fs7.default.closeSync(fd);
2799
+ import_node_fs8.default.closeSync(fd);
2782
2800
  }
2783
2801
  }
2784
2802
 
@@ -3067,10 +3085,10 @@ var AgentHost = class {
3067
3085
  }
3068
3086
  getTranscript(sessionId) {
3069
3087
  const p = transcriptPath(sessionId);
3070
- if (!import_node_fs8.default.existsSync(p)) {
3088
+ if (!import_node_fs9.default.existsSync(p)) {
3071
3089
  return { error: "transcript not found", code: "NO_TRANSCRIPT" };
3072
3090
  }
3073
- return import_node_fs8.default.readFileSync(p, "utf8");
3091
+ return import_node_fs9.default.readFileSync(p, "utf8");
3074
3092
  }
3075
3093
  getPaths() {
3076
3094
  const dir = getUserDataDir();
@@ -3766,13 +3784,88 @@ async function openUrl(url, options = {}) {
3766
3784
  }
3767
3785
 
3768
3786
  // src/host/plane-host.ts
3769
- var import_node_fs10 = __toESM(require("node:fs"), 1);
3787
+ var import_node_fs11 = __toESM(require("node:fs"), 1);
3770
3788
  var import_node_path11 = __toESM(require("node:path"), 1);
3771
- var import_plane = require("@contrast/harness/plane");
3789
+
3790
+ // ../contrast-harness/src/planeProtocol.ts
3791
+ var PLANE_FLAG_READ_ONLY = 1;
3792
+ var PLANE_FLAG_BINARY = 2;
3793
+ function encodeBase64(bytes) {
3794
+ let binary = "";
3795
+ const CHUNK = 32768;
3796
+ for (let i = 0; i < bytes.length; i += CHUNK) {
3797
+ binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
3798
+ }
3799
+ return btoa(binary);
3800
+ }
3801
+ function decodeBase64(value) {
3802
+ const binary = atob(value);
3803
+ const bytes = new Uint8Array(binary.length);
3804
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
3805
+ return bytes;
3806
+ }
3807
+ function indexVersion(index) {
3808
+ let a = 2166136261;
3809
+ let b = 16777619;
3810
+ for (const key of [...index.keys()].sort()) {
3811
+ const meta = index.get(key);
3812
+ if (!meta) continue;
3813
+ const line = `${key} ${meta.size} ${meta.readOnly ? 1 : 0}${meta.binary ? 1 : 0} ${meta.hash ?? ""}`;
3814
+ for (let i = 0; i < line.length; i++) {
3815
+ const c = line.charCodeAt(i);
3816
+ a = Math.imul(a ^ c, 16777619);
3817
+ b = Math.imul(b + c, 2246822507) ^ b >>> 13;
3818
+ }
3819
+ }
3820
+ return `${(a >>> 0).toString(36)}${(b >>> 0).toString(36)}-${index.size}`;
3821
+ }
3822
+ function serializeIndex(index) {
3823
+ const out = [];
3824
+ for (const [key, meta] of index) {
3825
+ const flags = (meta.readOnly ? PLANE_FLAG_READ_ONLY : 0) | (meta.binary ? PLANE_FLAG_BINARY : 0);
3826
+ out.push(meta.hash ? [key, meta.size, flags, meta.hash] : [key, meta.size, flags]);
3827
+ }
3828
+ return out;
3829
+ }
3830
+ async function dispatchPlaneCommand(plane, type, msg, mutationOptions) {
3831
+ switch (type) {
3832
+ case "plane:index":
3833
+ case "plane:refresh": {
3834
+ await plane.refresh();
3835
+ const version = indexVersion(plane.index());
3836
+ if (msg.sinceVersion && msg.sinceVersion === version) {
3837
+ return { result: { version, unchanged: true }, version };
3838
+ }
3839
+ return { result: { version, entries: serializeIndex(plane.index()) }, version };
3840
+ }
3841
+ case "plane:read":
3842
+ return { result: { content: await plane.read(String(msg.path)) } };
3843
+ case "plane:read-bytes":
3844
+ return { result: { base64: encodeBase64(await plane.readBytes(String(msg.path))) } };
3845
+ case "plane:write": {
3846
+ mutationOptions?.signal?.throwIfAborted();
3847
+ await plane.write(
3848
+ String(msg.path),
3849
+ decodeBase64(String(msg.base64 ?? "")),
3850
+ mutationOptions
3851
+ );
3852
+ const version = indexVersion(plane.index());
3853
+ return { result: { version }, version };
3854
+ }
3855
+ case "plane:delete": {
3856
+ mutationOptions?.signal?.throwIfAborted();
3857
+ await plane.delete(String(msg.path), mutationOptions);
3858
+ const version = indexVersion(plane.index());
3859
+ return { result: { version }, version };
3860
+ }
3861
+ default:
3862
+ return null;
3863
+ }
3864
+ }
3772
3865
 
3773
3866
  // cli/commands/box/checkout-plane.ts
3774
3867
  var import_node_child_process4 = require("node:child_process");
3775
- var import_node_fs9 = __toESM(require("node:fs"), 1);
3868
+ var import_node_fs10 = __toESM(require("node:fs"), 1);
3776
3869
  var import_node_path10 = __toESM(require("node:path"), 1);
3777
3870
  var CheckoutRequiresGitError = class extends Error {
3778
3871
  };
@@ -3782,14 +3875,14 @@ function looksBinary(filePath, size) {
3782
3875
  if (size === 0) return false;
3783
3876
  let fd;
3784
3877
  try {
3785
- fd = import_node_fs9.default.openSync(filePath, "r");
3878
+ fd = import_node_fs10.default.openSync(filePath, "r");
3786
3879
  const buffer = Buffer.alloc(Math.min(BINARY_SNIFF_BYTES, size));
3787
- const read = import_node_fs9.default.readSync(fd, buffer, 0, buffer.length, 0);
3880
+ const read = import_node_fs10.default.readSync(fd, buffer, 0, buffer.length, 0);
3788
3881
  return buffer.subarray(0, read).includes(0);
3789
3882
  } catch {
3790
3883
  return false;
3791
3884
  } finally {
3792
- if (fd !== void 0) import_node_fs9.default.closeSync(fd);
3885
+ if (fd !== void 0) import_node_fs10.default.closeSync(fd);
3793
3886
  }
3794
3887
  }
3795
3888
  var CheckoutFilePlane = class {
@@ -3839,7 +3932,7 @@ var CheckoutFilePlane = class {
3839
3932
  if (!relative) continue;
3840
3933
  let stat2;
3841
3934
  try {
3842
- stat2 = import_node_fs9.default.statSync(import_node_path10.default.join(this.root, relative));
3935
+ stat2 = import_node_fs10.default.statSync(import_node_path10.default.join(this.root, relative));
3843
3936
  } catch {
3844
3937
  continue;
3845
3938
  }
@@ -3866,15 +3959,15 @@ var CheckoutFilePlane = class {
3866
3959
  return resolved;
3867
3960
  }
3868
3961
  async read(planePath) {
3869
- return import_node_fs9.default.promises.readFile(this.absolute(planePath), "utf8");
3962
+ return import_node_fs10.default.promises.readFile(this.absolute(planePath), "utf8");
3870
3963
  }
3871
3964
  async readBytes(planePath) {
3872
- return import_node_fs9.default.promises.readFile(this.absolute(planePath));
3965
+ return import_node_fs10.default.promises.readFile(this.absolute(planePath));
3873
3966
  }
3874
3967
  async write(planePath, content) {
3875
3968
  const absolute = this.absolute(planePath);
3876
- await import_node_fs9.default.promises.mkdir(import_node_path10.default.dirname(absolute), { recursive: true });
3877
- await import_node_fs9.default.promises.writeFile(absolute, content);
3969
+ await import_node_fs10.default.promises.mkdir(import_node_path10.default.dirname(absolute), { recursive: true });
3970
+ await import_node_fs10.default.promises.writeFile(absolute, content);
3878
3971
  this.entries.set(planePath, {
3879
3972
  size: content.byteLength,
3880
3973
  readOnly: false,
@@ -3883,7 +3976,7 @@ var CheckoutFilePlane = class {
3883
3976
  });
3884
3977
  }
3885
3978
  async delete(planePath) {
3886
- await import_node_fs9.default.promises.rm(this.absolute(planePath), { force: true });
3979
+ await import_node_fs10.default.promises.rm(this.absolute(planePath), { force: true });
3887
3980
  this.entries.delete(planePath);
3888
3981
  }
3889
3982
  };
@@ -3979,7 +4072,7 @@ var PlaneHost = class {
3979
4072
  const entry = {
3980
4073
  root,
3981
4074
  plane,
3982
- version: (0, import_plane.indexVersion)(plane.index()),
4075
+ version: indexVersion(plane.index()),
3983
4076
  sockets: /* @__PURE__ */ new Set([ws])
3984
4077
  };
3985
4078
  this.open.set(planeId, entry);
@@ -3993,7 +4086,7 @@ var PlaneHost = class {
3993
4086
  }
3994
4087
  default: {
3995
4088
  const entry = this.entry(msg);
3996
- const handled = await (0, import_plane.dispatchPlaneCommand)(entry.plane, type, msg);
4089
+ const handled = await dispatchPlaneCommand(entry.plane, type, msg);
3997
4090
  if (!handled) throw new Error(`unknown plane command: ${type}`);
3998
4091
  if (handled.version) entry.version = handled.version;
3999
4092
  return handled.result;
@@ -4012,11 +4105,11 @@ var PlaneHost = class {
4012
4105
  const resolved = import_node_path11.default.resolve(root);
4013
4106
  let real;
4014
4107
  try {
4015
- real = import_node_fs10.default.realpathSync(resolved);
4108
+ real = import_node_fs11.default.realpathSync(resolved);
4016
4109
  } catch {
4017
4110
  throw new Error(`no such directory: ${resolved}`);
4018
4111
  }
4019
- if (!import_node_fs10.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
4112
+ if (!import_node_fs11.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
4020
4113
  return real;
4021
4114
  }
4022
4115
  respond(ws, id, result) {
@@ -4747,7 +4840,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
4747
4840
  return;
4748
4841
  }
4749
4842
  if (msg.type === "runtime:list") {
4750
- const versions = sootsimRuntime.listInstalled();
4843
+ const versions = rnxRuntime.listInstalled();
4751
4844
  const active = this.getActiveRuntime();
4752
4845
  const reply = {
4753
4846
  type: "runtime:list:ok",
@@ -4764,7 +4857,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
4764
4857
  }
4765
4858
  if (msg.type === "runtime:use") {
4766
4859
  const version = typeof msg.version === "string" ? msg.version : "";
4767
- const installed = sootsimRuntime.listInstalled();
4860
+ const installed = rnxRuntime.listInstalled();
4768
4861
  if (!installed.includes(version)) {
4769
4862
  try {
4770
4863
  ws.send(
@@ -5127,7 +5220,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5127
5220
  this.wsHeartbeatTimer.unref();
5128
5221
  if (this.shouldWriteLockfile) {
5129
5222
  try {
5130
- ensureSootsimHome();
5223
+ ensureRnxHome();
5131
5224
  const claimed = claimDaemonLockfile(this.buildLockfileSnapshot());
5132
5225
  if (!claimed) {
5133
5226
  throw new Error(
@@ -5257,7 +5350,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5257
5350
  return this.inflightScan;
5258
5351
  }
5259
5352
  // serves one staged camera fixture. addressed by basename inside
5260
- // ~/.sootsim/camera-fixtures, never by a caller-supplied path, so there is
5353
+ // ~/.rnx/camera-fixtures, never by a caller-supplied path, so there is
5261
5354
  // no traversal surface to defend: a name that is not a plain basename is
5262
5355
  // rejected outright. range support is not optional here — chrome asks for
5263
5356
  // byte ranges on media and cannot seek or loop a fixture without it.
@@ -5367,8 +5460,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5367
5460
  }
5368
5461
  startRuntimeUpdater() {
5369
5462
  if (!this.shouldWriteLockfile || this.runtimeUpdateTimer) return;
5370
- if (import_fs2.default.existsSync(import_path2.default.join(sootsimHomeDir(), "runtime-update-disabled"))) return;
5371
- if (process.env.SOOTSIM_HOME && isSootsimDevCheckout() && !readActiveRuntime()) {
5463
+ if (import_fs2.default.existsSync(import_path2.default.join(rnxHomeDir(), "runtime-update-disabled"))) return;
5464
+ if (process.env.RNX_HOME && isSootsimDevCheckout() && !readActiveRuntime()) {
5372
5465
  return;
5373
5466
  }
5374
5467
  void this.runRuntimeUpdate("startup");
@@ -5385,7 +5478,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5385
5478
  if (reason === "startup") {
5386
5479
  process.stderr.write("rnx: checking for runtime updates\u2026\n");
5387
5480
  }
5388
- const result = await sootsimRuntime.updateToLatest({
5481
+ const result = await rnxRuntime.updateToLatest({
5389
5482
  protectVersions: this.connectedRuntimeVersions()
5390
5483
  });
5391
5484
  if (!result.updated || !result.latestVersion) {