rnxsim 0.1.338 → 0.1.340

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 (167) hide show
  1. package/cli/app-config.ts +21 -1
  2. package/dist-cli/bin.js +5 -5
  3. package/dist-cli/chunks/{agent-G3HSUEJN.js → agent-DZRALHKK.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-ZENL34KG.js → agent-wrapper-FFCII533.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-NTEGG7VL.js → app-fonts-P5TIE2BI.js} +2 -2
  6. package/dist-cli/chunks/{assert-RHXGX3N6.js → assert-L6YWZZH7.js} +2 -2
  7. package/dist-cli/chunks/{auth-VTG6JRJU.js → auth-2QUOSD3D.js} +2 -2
  8. package/dist-cli/chunks/{beta-AJV7FIZT.js → beta-DSQASQV7.js} +2 -2
  9. package/dist-cli/chunks/{camera-AUFHAGV5.js → camera-KONNW6GF.js} +2 -2
  10. package/dist-cli/chunks/{chunk-OHBAH7R5.js → chunk-2C7MJXES.js} +1 -1
  11. package/dist-cli/chunks/{chunk-6XWHJHRR.js → chunk-2FT3GZ2P.js} +2 -2
  12. package/dist-cli/chunks/{chunk-ZFVOCM7E.js → chunk-3KDMR5FE.js} +2 -2
  13. package/dist-cli/chunks/{chunk-NWUML3LH.js → chunk-52LBSDBQ.js} +3 -3
  14. package/dist-cli/chunks/{chunk-ETGM26S2.js → chunk-5JKZGU2L.js} +1 -1
  15. package/dist-cli/chunks/{chunk-YYJRLMSR.js → chunk-5ULMLFND.js} +1 -1
  16. package/dist-cli/chunks/{chunk-3KNPTXSK.js → chunk-6HQ2CUG5.js} +1 -1
  17. package/dist-cli/chunks/{chunk-GGDORRTI.js → chunk-7IBTDBHW.js} +2 -2
  18. package/dist-cli/chunks/{chunk-T47EKPO2.js → chunk-AV323BT6.js} +2 -2
  19. package/dist-cli/chunks/{chunk-ZERYUNU4.js → chunk-AVGWPMGX.js} +1 -1
  20. package/dist-cli/chunks/{chunk-G3W7FC3J.js → chunk-AZWECMXO.js} +2 -2
  21. package/dist-cli/chunks/{chunk-OQVGMLDW.js → chunk-BCGO3XWB.js} +2 -2
  22. package/dist-cli/chunks/{chunk-63H3GSZP.js → chunk-CA3D6BWR.js} +2 -2
  23. package/dist-cli/chunks/{chunk-Q4NOTYIM.js → chunk-CKK6IEZD.js} +1 -1
  24. package/dist-cli/chunks/{chunk-6WP2UV2D.js → chunk-CKKJUPAA.js} +1 -1
  25. package/dist-cli/chunks/{chunk-7ISR3ZYK.js → chunk-CYAEO7E3.js} +2 -2
  26. package/dist-cli/chunks/{chunk-BQG5LZKW.js → chunk-DB4DBTM2.js} +2 -2
  27. package/dist-cli/chunks/{chunk-4D345WIF.js → chunk-DEK47I44.js} +3 -3
  28. package/dist-cli/chunks/{chunk-OK6SVPSL.js → chunk-DMAUBOZ2.js} +1 -1
  29. package/dist-cli/chunks/{chunk-VYRYAB3X.js → chunk-EZ2WX6EK.js} +3 -3
  30. package/dist-cli/chunks/{chunk-BK7DKLML.js → chunk-F4SGYRAP.js} +1 -1
  31. package/dist-cli/chunks/chunk-HWIUC6SX.js +4 -0
  32. package/dist-cli/chunks/{chunk-UOJDJDCM.js → chunk-J2EHW26I.js} +2 -2
  33. package/dist-cli/chunks/{chunk-XFELRGXJ.js → chunk-JJKRVEA6.js} +1 -1
  34. package/dist-cli/chunks/{chunk-OVPCCCEU.js → chunk-JRJDACNV.js} +2 -2
  35. package/dist-cli/chunks/{chunk-BQY3EZKT.js → chunk-JX5LGYG2.js} +2 -2
  36. package/dist-cli/chunks/{chunk-3FI5EY2N.js → chunk-L6FANSWV.js} +1 -1
  37. package/dist-cli/chunks/{chunk-N4PXLKEX.js → chunk-LQIMPJRD.js} +2 -2
  38. package/dist-cli/chunks/{chunk-AVPACXQK.js → chunk-LXED7YNR.js} +1 -1
  39. package/dist-cli/chunks/{chunk-MQFPZ7KI.js → chunk-M76E72WP.js} +2 -2
  40. package/dist-cli/chunks/{chunk-4MTCA7VV.js → chunk-MKFOWHFO.js} +1 -1
  41. package/dist-cli/chunks/{chunk-6QRPJ7QO.js → chunk-MXXR5IDW.js} +3 -3
  42. package/dist-cli/chunks/{chunk-5QAP5T2V.js → chunk-MYTUISZ3.js} +2 -2
  43. package/dist-cli/chunks/{chunk-MAPLEBCD.js → chunk-NAG3Y5BF.js} +1 -1
  44. package/dist-cli/chunks/{chunk-HJLU4FAF.js → chunk-NZVA5ZGD.js} +1 -1
  45. package/dist-cli/chunks/{chunk-SVMKZXCM.js → chunk-PH37P7G2.js} +2 -2
  46. package/dist-cli/chunks/{chunk-FJXYAQK6.js → chunk-PYZHCZFD.js} +2 -2
  47. package/dist-cli/chunks/{chunk-JR4ASV7X.js → chunk-QRHLTYK7.js} +2 -2
  48. package/dist-cli/chunks/{chunk-Q53GTRNP.js → chunk-RYXIRFY2.js} +2 -2
  49. package/dist-cli/chunks/{chunk-XYABVE4V.js → chunk-TAPZRN4C.js} +1 -1
  50. package/dist-cli/chunks/{chunk-D27DTXJU.js → chunk-TRGIXJN4.js} +2 -2
  51. package/dist-cli/chunks/{chunk-ABEKWF72.js → chunk-U4ZHMDGL.js} +1 -1
  52. package/dist-cli/chunks/{chunk-FRX3JK7N.js → chunk-UH2S5SLV.js} +2 -2
  53. package/dist-cli/chunks/{chunk-2PFMT5AC.js → chunk-UKKT5KM4.js} +2 -2
  54. package/dist-cli/chunks/{chunk-OF2LP2DA.js → chunk-UOK37RTL.js} +1 -1
  55. package/dist-cli/chunks/{chunk-YUX3I7IO.js → chunk-VP7D322G.js} +1 -1
  56. package/dist-cli/chunks/{chunk-DU3JBQ5L.js → chunk-W34ZT5MF.js} +2 -2
  57. package/dist-cli/chunks/{chunk-5RB27SUB.js → chunk-WRNCAZIB.js} +2 -2
  58. package/dist-cli/chunks/{chunk-XDIAP767.js → chunk-WRPLAFZP.js} +2 -2
  59. package/dist-cli/chunks/{chunk-5RSKW7VT.js → chunk-X5C3SLYU.js} +1 -1
  60. package/dist-cli/chunks/{chunk-AFJL467O.js → chunk-YNS55EN5.js} +2 -2
  61. package/dist-cli/chunks/{chunk-WN3NNF46.js → chunk-Z7ILCEXG.js} +2 -2
  62. package/dist-cli/chunks/{chunk-NBA5FHEJ.js → chunk-ZEU5RFAH.js} +2 -2
  63. package/dist-cli/chunks/{cleanup-FQMQ47H7.js → cleanup-BPGPA6WN.js} +2 -2
  64. package/dist-cli/chunks/cli-version-GJ55D3JI.js +4 -0
  65. package/dist-cli/chunks/{compat-R5FQB2ZB.js → compat-2L5FPDKU.js} +2 -2
  66. package/dist-cli/chunks/{config-ZRS3QCQJ.js → config-NRXBYFB7.js} +2 -2
  67. package/dist-cli/chunks/{control-XTYASILQ.js → control-G5SMCB2U.js} +2 -2
  68. package/dist-cli/chunks/daemon-HDNSS5A3.js +4 -0
  69. package/dist-cli/chunks/{debug-FYSQEAS7.js → debug-CTYLINPI.js} +3 -3
  70. package/dist-cli/chunks/{desktop-VX3UUDUZ.js → desktop-JNYUDHX5.js} +3 -3
  71. package/dist-cli/chunks/{detox-BIFMEK3W.js → detox-ZWP5MUPJ.js} +2 -2
  72. package/dist-cli/chunks/{device-TRZDOVET.js → device-Y7ANIQJY.js} +2 -2
  73. package/dist-cli/chunks/{diagnose-TOIYZFHR.js → diagnose-GFPN44ER.js} +2 -2
  74. package/dist-cli/chunks/{disk-cleanup-QFZDBLIK.js → disk-cleanup-OUHB2MKC.js} +2 -2
  75. package/dist-cli/chunks/drivers-3PUAZF6B.js +4 -0
  76. package/dist-cli/chunks/{film-3PDSRZRE.js → film-RNPYZHQA.js} +3 -3
  77. package/dist-cli/chunks/flow-XQUTMOQZ.js +4 -0
  78. package/dist-cli/chunks/help-C7Y5IENX.js +4 -0
  79. package/dist-cli/chunks/{hidden-runtime-alias-OWQOMYHE.js → hidden-runtime-alias-DGMIDDY6.js} +2 -2
  80. package/dist-cli/chunks/{home-paths-QPFJMOU3.js → home-paths-YEFW63N5.js} +2 -2
  81. package/dist-cli/chunks/inspect-4NF3PPRZ.js +4 -0
  82. package/dist-cli/chunks/install-desktop-66LPKLQI.js +4 -0
  83. package/dist-cli/chunks/{login-BP6PCAAP.js → login-ASAFHSEL.js} +4 -4
  84. package/dist-cli/chunks/{logout-F6BR2WA3.js → logout-F3B5TUCU.js} +2 -2
  85. package/dist-cli/chunks/{maestro-IQTNAPMZ.js → maestro-MJD54Z7R.js} +3 -3
  86. package/dist-cli/chunks/{maestro-generate-E5ZM2CYW.js → maestro-generate-PQZ33V42.js} +3 -3
  87. package/dist-cli/chunks/{mode-2LXFTCJS.js → mode-TKOOHJNS.js} +2 -2
  88. package/dist-cli/chunks/{optional-demo-registry-SZOI4M4R.js → optional-demo-registry-VX3WVJXT.js} +2 -2
  89. package/dist-cli/chunks/{perf-EVZFEIYZ.js → perf-JRREHJB6.js} +2 -2
  90. package/dist-cli/chunks/{permissions-JCUAAO2E.js → permissions-RQZLGYVF.js} +2 -2
  91. package/dist-cli/chunks/{record-RTM7BU3G.js → record-LBNBJ6U4.js} +3 -3
  92. package/dist-cli/chunks/{report-issue-ITCSZI37.js → report-issue-O63Z4GXO.js} +2 -2
  93. package/dist-cli/chunks/reset-734HPURU.js +4 -0
  94. package/dist-cli/chunks/runtime-PRF4VZAB.js +4 -0
  95. package/dist-cli/chunks/{screenshot-command-KZWCLIE5.js → screenshot-command-OLZIGKZR.js} +3 -3
  96. package/dist-cli/chunks/{screenshot-layers-4ZPGWQA5.js → screenshot-layers-ZCKD62ME.js} +2 -2
  97. package/dist-cli/chunks/{screenshots-capture-6LP2Q7EJ.js → screenshots-capture-CJFJACD7.js} +2 -2
  98. package/dist-cli/chunks/serve-L6QW4B55.js +118 -0
  99. package/dist-cli/chunks/{setup-JS3YUIDS.js → setup-CHUHRWKS.js} +2 -2
  100. package/dist-cli/chunks/{skills-7JXM6WME.js → skills-J44O4CRY.js} +2 -2
  101. package/dist-cli/chunks/{state-VZOMFRIR.js → state-MSTCUB5E.js} +2 -2
  102. package/dist-cli/chunks/{storage-U5ORNYJL.js → storage-23Y5YSD3.js} +2 -2
  103. package/dist-cli/chunks/store-IK5DQZ2G.js +4 -0
  104. package/dist-cli/chunks/telemetry-SCC2A4KF.js +4 -0
  105. package/dist-cli/chunks/{timeline-NDQ74JBZ.js → timeline-R7VNARZ5.js} +2 -2
  106. package/dist-cli/chunks/{upgrade-QKR4MCC5.js → upgrade-YUASBYYN.js} +2 -2
  107. package/dist-cli/chunks/upload-BFCTC54P.js +4 -0
  108. package/dist-cli/chunks/{version-XI54TYIM.js → version-FSV3NQBN.js} +2 -2
  109. package/dist-cli/chunks/{web-OGA7GXQV.js → web-LZH2QIJ5.js} +2 -2
  110. package/dist-cli/chunks/{what-happened-BMSZA2Y4.js → what-happened-F45IZ34K.js} +2 -2
  111. package/dist-lib/agent-daemon-client.cjs +1 -1
  112. package/dist-lib/agent-events.cjs +1 -1
  113. package/dist-lib/agent-identity.cjs +1 -1
  114. package/dist-lib/agent-sessions.cjs +1 -1
  115. package/dist-lib/attached-projects.cjs +1 -1
  116. package/dist-lib/auth/shared-session.cjs +1 -1
  117. package/dist-lib/backend-origin.cjs +1 -1
  118. package/dist-lib/beta.cjs +1 -1
  119. package/dist-lib/beta.mjs +1 -1
  120. package/dist-lib/bridge-constants.cjs +1 -1
  121. package/dist-lib/bridge-contract.cjs +1 -1
  122. package/dist-lib/cli-constants.cjs +1 -1
  123. package/dist-lib/config.cjs +1 -1
  124. package/dist-lib/detox/index.cjs +1 -1
  125. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  126. package/dist-lib/home-paths.cjs +1 -1
  127. package/dist-lib/host/bridge-host.cjs +203 -8
  128. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  129. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  130. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  131. package/dist-lib/host/replacement-module-handler.cjs +236 -0
  132. package/dist-lib/host/websocket-proxy.cjs +1 -1
  133. package/dist-lib/index.cjs +195 -8
  134. package/dist-lib/jump-to-source-babel.cjs +1 -1
  135. package/dist-lib/menu.cjs +1 -1
  136. package/dist-lib/menu.mjs +1 -1
  137. package/dist-lib/metro-production-bundle.cjs +1 -1
  138. package/dist-lib/metro-production-bundle.mjs +1 -1
  139. package/dist-lib/metro.cjs +1 -1
  140. package/dist-lib/profiles.cjs +1 -1
  141. package/dist-lib/public-brand.cjs +1 -1
  142. package/dist-lib/react-native-host-modules.cjs +1 -1
  143. package/dist-lib/react-native-host-modules.mjs +1 -1
  144. package/dist-lib/render-mode.cjs +1 -1
  145. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  146. package/dist-lib/sdk.cjs +1 -1
  147. package/dist-lib/sdk.mjs +1 -1
  148. package/dist-lib/skills.cjs +371 -155
  149. package/dist-lib/vite.cjs +188 -1
  150. package/package.json +6 -2
  151. package/src/host/bridge-host.ts +9 -0
  152. package/src/host/replacement-module-handler.ts +220 -0
  153. package/src/vite-plugin-one.ts +7 -0
  154. package/dist-cli/chunks/chunk-K2OH5YB6.js +0 -4
  155. package/dist-cli/chunks/cli-version-D4SIGBIX.js +0 -4
  156. package/dist-cli/chunks/daemon-TEADGBF4.js +0 -4
  157. package/dist-cli/chunks/drivers-KWT23MPE.js +0 -4
  158. package/dist-cli/chunks/flow-AYXLKDJR.js +0 -4
  159. package/dist-cli/chunks/help-47DWCNK3.js +0 -4
  160. package/dist-cli/chunks/inspect-HFXM4CFS.js +0 -4
  161. package/dist-cli/chunks/install-desktop-CVEMNOP7.js +0 -4
  162. package/dist-cli/chunks/reset-VJGTLBQK.js +0 -4
  163. package/dist-cli/chunks/runtime-VJ6MCWZ4.js +0 -4
  164. package/dist-cli/chunks/serve-4UUCD73E.js +0 -44
  165. package/dist-cli/chunks/store-LQNKXV7U.js +0 -4
  166. package/dist-cli/chunks/telemetry-R6WP54HP.js +0 -4
  167. package/dist-cli/chunks/upload-AUD6TX4C.js +0 -4
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.338 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.340 | (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;
@@ -9474,9 +9474,9 @@ function safeChildPlistName(value) {
9474
9474
  name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
9475
9475
  };
9476
9476
  }
9477
- async function readableSettingsBundle(path17) {
9477
+ async function readableSettingsBundle(path19) {
9478
9478
  try {
9479
- const root = await (0, import_promises.stat)((0, import_node_path.join)(path17, "Root.plist"));
9479
+ const root = await (0, import_promises.stat)((0, import_node_path.join)(path19, "Root.plist"));
9480
9480
  return root.isFile() && root.size <= MAX_PLIST_BYTES;
9481
9481
  } catch {
9482
9482
  return false;
@@ -9521,11 +9521,11 @@ async function settingsBundleFingerprint(bundlePath) {
9521
9521
  return null;
9522
9522
  }
9523
9523
  }
9524
- async function parsePlistRecord(path17) {
9524
+ async function parsePlistRecord(path19) {
9525
9525
  try {
9526
- const metadata = await (0, import_promises.stat)(path17);
9526
+ const metadata = await (0, import_promises.stat)(path19);
9527
9527
  if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
9528
- const source = await (0, import_promises.readFile)(path17, "utf8");
9528
+ const source = await (0, import_promises.readFile)(path19, "utf8");
9529
9529
  const parsed = parsePlistSource(source);
9530
9530
  return isRecord2(parsed) ? parsed : null;
9531
9531
  } catch {
@@ -9804,10 +9804,10 @@ function tcpPing(port, timeout = TCP_GATE_MS) {
9804
9804
  sock.connect(port, "localhost");
9805
9805
  });
9806
9806
  }
9807
- function httpGet(port, path17, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
9807
+ function httpGet(port, path19, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
9808
9808
  return new Promise((resolve7) => {
9809
9809
  const req = import_http.default.request(
9810
- { hostname: "localhost", port, path: path17, method, timeout, headers },
9810
+ { hostname: "localhost", port, path: path19, method, timeout, headers },
9811
9811
  (res) => {
9812
9812
  let body = "";
9813
9813
  res.on("data", (c) => body += c.toString());
@@ -13064,6 +13064,203 @@ var init_open_url = __esm({
13064
13064
  }
13065
13065
  });
13066
13066
 
13067
+ // src/host/replacement-module-handler.ts
13068
+ function getReplacementLoader(filePath) {
13069
+ const ext = import_node_path10.default.extname(filePath).toLowerCase();
13070
+ switch (ext) {
13071
+ case ".js":
13072
+ return "js";
13073
+ case ".jsx":
13074
+ return "jsx";
13075
+ case ".ts":
13076
+ return "ts";
13077
+ case ".tsx":
13078
+ return "tsx";
13079
+ default:
13080
+ return null;
13081
+ }
13082
+ }
13083
+ function reactRuntimeSource(reactBridgeUrl) {
13084
+ if (reactBridgeUrl) {
13085
+ return `export * from ${JSON.stringify(reactBridgeUrl)};
13086
+ import React from ${JSON.stringify(reactBridgeUrl)};
13087
+ export default React;
13088
+ `;
13089
+ }
13090
+ return `const bridge = globalThis.__sootsim_react_bridge
13091
+ if (!bridge) throw new Error('[rnx] replacement React bridge is not ready')
13092
+ export default bridge.default
13093
+ export const Activity = bridge.Activity
13094
+ export const Children = bridge.Children
13095
+ export const Component = bridge.Component
13096
+ export const Fragment = bridge.Fragment
13097
+ export const Profiler = bridge.Profiler
13098
+ export const PureComponent = bridge.PureComponent
13099
+ export const StrictMode = bridge.StrictMode
13100
+ export const Suspense = bridge.Suspense
13101
+ export const __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = bridge.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE
13102
+ export const __COMPILER_RUNTIME = bridge.__COMPILER_RUNTIME
13103
+ export const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = bridge.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
13104
+ export const act = bridge.act
13105
+ export const cache = bridge.cache
13106
+ export const cacheSignal = bridge.cacheSignal
13107
+ export const captureOwnerStack = bridge.captureOwnerStack
13108
+ export const cloneElement = bridge.cloneElement
13109
+ export const createContext = bridge.createContext
13110
+ export const createElement = bridge.createElement
13111
+ export const createRef = bridge.createRef
13112
+ export const forwardRef = bridge.forwardRef
13113
+ export const isValidElement = bridge.isValidElement
13114
+ export const lazy = bridge.lazy
13115
+ export const memo = bridge.memo
13116
+ export const startTransition = bridge.startTransition
13117
+ export const unstable_useCacheRefresh = bridge.unstable_useCacheRefresh
13118
+ export const use = bridge.use
13119
+ export const useActionState = bridge.useActionState
13120
+ export const useCallback = bridge.useCallback
13121
+ export const useContext = bridge.useContext
13122
+ export const useDebugValue = bridge.useDebugValue
13123
+ export const useDeferredValue = bridge.useDeferredValue
13124
+ export const useEffect = bridge.useEffect
13125
+ export const useEffectEvent = bridge.useEffectEvent
13126
+ export const useId = bridge.useId
13127
+ export const useImperativeHandle = bridge.useImperativeHandle
13128
+ export const useInsertionEffect = bridge.useInsertionEffect
13129
+ export const useLayoutEffect = bridge.useLayoutEffect
13130
+ export const useMemo = bridge.useMemo
13131
+ export const useOptimistic = bridge.useOptimistic
13132
+ export const useReducer = bridge.useReducer
13133
+ export const useRef = bridge.useRef
13134
+ export const useState = bridge.useState
13135
+ export const useSyncExternalStore = bridge.useSyncExternalStore
13136
+ export const useTransition = bridge.useTransition
13137
+ export const version = bridge.version
13138
+ `;
13139
+ }
13140
+ function reactNativeRuntimeSource() {
13141
+ return `const rn = globalThis.__sootsim_components__ || {}
13142
+ export default rn
13143
+ export const View = rn.View
13144
+ export const Text = rn.Text
13145
+ export const Image = rn.Image
13146
+ export const ScrollView = rn.ScrollView
13147
+ export const FlatList = rn.FlatList
13148
+ export const Pressable = rn.Pressable
13149
+ export const TouchableOpacity = rn.TouchableOpacity
13150
+ export const TouchableWithoutFeedback = rn.TouchableWithoutFeedback
13151
+ export const TouchableHighlight = rn.TouchableHighlight
13152
+ export const TextInput = rn.TextInput
13153
+ export const ActivityIndicator = rn.ActivityIndicator
13154
+ export const KeyboardAvoidingView = rn.KeyboardAvoidingView
13155
+ export const Button = rn.Button
13156
+ export const Modal = rn.Modal
13157
+ export const Switch = rn.Switch
13158
+ export const StyleSheet = rn.StyleSheet
13159
+ export const Platform = rn.Platform
13160
+ export const Keyboard = rn.Keyboard
13161
+ export const Dimensions = rn.Dimensions
13162
+ export const Appearance = rn.Appearance
13163
+ `;
13164
+ }
13165
+ function sendJavaScript(req, res, source) {
13166
+ res.writeHead(200, {
13167
+ "Content-Type": "application/javascript; charset=utf-8",
13168
+ "Cache-Control": "no-cache"
13169
+ });
13170
+ res.end(req.method === "HEAD" ? void 0 : source);
13171
+ }
13172
+ function isReplacementModuleRequestUrl(rawUrl) {
13173
+ if (!rawUrl) return false;
13174
+ try {
13175
+ const pathname = new URL(rawUrl, "http://rnx.local").pathname;
13176
+ return pathname === REPLACEMENT_MODULE_ROUTE || pathname.startsWith(`${REPLACEMENT_RUNTIME_PREFIX}/`);
13177
+ } catch {
13178
+ return false;
13179
+ }
13180
+ }
13181
+ async function handleReplacementModuleRequest(req, res, options = {}) {
13182
+ const rawUrl = req.url || "";
13183
+ let url;
13184
+ try {
13185
+ url = new URL(rawUrl, "http://rnx.local");
13186
+ } catch {
13187
+ return false;
13188
+ }
13189
+ if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react`) {
13190
+ sendJavaScript(req, res, reactRuntimeSource(options.reactBridgeUrl));
13191
+ return true;
13192
+ }
13193
+ if (url.pathname === `${REPLACEMENT_RUNTIME_PREFIX}/react-native`) {
13194
+ sendJavaScript(req, res, reactNativeRuntimeSource());
13195
+ return true;
13196
+ }
13197
+ if (url.pathname !== REPLACEMENT_MODULE_ROUTE) return false;
13198
+ const targetPath = url.searchParams.get("path");
13199
+ if (!targetPath) {
13200
+ res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
13201
+ res.end("missing path param");
13202
+ return true;
13203
+ }
13204
+ const loader = getReplacementLoader(targetPath);
13205
+ if (!loader) {
13206
+ res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
13207
+ res.end("replacement files must be .js, .jsx, .ts, or .tsx");
13208
+ return true;
13209
+ }
13210
+ try {
13211
+ await import_promises5.default.access(targetPath);
13212
+ } catch (error) {
13213
+ const message = error instanceof Error ? error.message : String(error);
13214
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
13215
+ res.end(`replacement file not found: ${message}`);
13216
+ return true;
13217
+ }
13218
+ try {
13219
+ const result = await (0, import_esbuild.build)({
13220
+ entryPoints: [targetPath],
13221
+ bundle: true,
13222
+ write: false,
13223
+ format: "esm",
13224
+ platform: "browser",
13225
+ target: "es2022",
13226
+ jsx: "transform",
13227
+ jsxFactory: "React.createElement",
13228
+ jsxFragment: "React.Fragment",
13229
+ tsconfigRaw: { compilerOptions: { jsx: "react" } },
13230
+ sourcemap: "inline",
13231
+ logLevel: "silent",
13232
+ external: ["react", "react-native"]
13233
+ });
13234
+ const bundledCode = result.outputFiles[0]?.text ?? "";
13235
+ const hasReactBinding = /\bimport\s+(?:\*\s+as\s+React|React(?:\s*,|\s+from)|\{[^}]*\bdefault\s+as\s+React\b)/.test(
13236
+ bundledCode
13237
+ );
13238
+ const reactImport = /\bReact\.(?:createElement|Fragment)\b/.test(bundledCode) && !hasReactBinding ? `import * as React from '${REPLACEMENT_RUNTIME_PREFIX}/react';
13239
+ ` : "";
13240
+ const runtimeCode = (reactImport + bundledCode).replace(
13241
+ /from\s*["']react-native["']/g,
13242
+ `from '${REPLACEMENT_RUNTIME_PREFIX}/react-native'`
13243
+ ).replace(/from\s*["']react["']/g, `from '${REPLACEMENT_RUNTIME_PREFIX}/react'`);
13244
+ sendJavaScript(req, res, runtimeCode);
13245
+ } catch (error) {
13246
+ const message = error instanceof Error ? error.message : String(error);
13247
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
13248
+ res.end(`replacement bundle failed: ${message}`);
13249
+ }
13250
+ return true;
13251
+ }
13252
+ var import_promises5, import_node_path10, import_esbuild, REPLACEMENT_MODULE_ROUTE, REPLACEMENT_RUNTIME_PREFIX;
13253
+ var init_replacement_module_handler = __esm({
13254
+ "src/host/replacement-module-handler.ts"() {
13255
+ "use strict";
13256
+ import_promises5 = __toESM(require("node:fs/promises"), 1);
13257
+ import_node_path10 = __toESM(require("node:path"), 1);
13258
+ import_esbuild = require("esbuild");
13259
+ REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
13260
+ REPLACEMENT_RUNTIME_PREFIX = "/__sootsim-replacement-runtime";
13261
+ }
13262
+ });
13263
+
13067
13264
  // src/host/websocket-proxy.ts
13068
13265
  function rejectUpgrade(socket, status, message) {
13069
13266
  try {
@@ -13304,6 +13501,7 @@ var init_bridge_host = __esm({
13304
13501
  init_agent_host();
13305
13502
  init_fetch_proxy_handler();
13306
13503
  init_open_url();
13504
+ init_replacement_module_handler();
13307
13505
  init_websocket_proxy();
13308
13506
  SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY = "require-corp";
13309
13507
  WRITE_COMMAND_TYPES = /* @__PURE__ */ new Set([
@@ -14346,6 +14544,10 @@ var init_bridge_host = __esm({
14346
14544
  if (isAppApiRequestUrl(req.url) && handleAppApiRequest(req, res)) {
14347
14545
  return;
14348
14546
  }
14547
+ if (isReplacementModuleRequestUrl(req.url)) {
14548
+ void handleReplacementModuleRequest(req, res);
14549
+ return;
14550
+ }
14349
14551
  const method = (req.method || "GET").toUpperCase();
14350
14552
  let url;
14351
14553
  try {
@@ -15339,7 +15541,7 @@ var init_cli_constants = __esm({
15339
15541
 
15340
15542
  // cli/parent-pid.ts
15341
15543
  function getParentPid(pid) {
15342
- if (!cached3) cached3 = build();
15544
+ if (!cached3) cached3 = build2();
15343
15545
  try {
15344
15546
  return cached3(pid);
15345
15547
  } catch {
@@ -15371,7 +15573,7 @@ function buildComm() {
15371
15573
  }
15372
15574
  return () => null;
15373
15575
  }
15374
- function build() {
15576
+ function build2() {
15375
15577
  const envPpid = Number(process.env.PPID);
15376
15578
  if (Number.isFinite(envPpid) && envPpid > 1 && envPpid !== process.ppid) {
15377
15579
  return () => envPpid;
@@ -15648,17 +15850,17 @@ function liveDevBridgeLockfiles() {
15648
15850
  return readDevBridgeLockfiles().filter((lockfile) => isDevBridgeLockfileFresh(lockfile));
15649
15851
  }
15650
15852
  function checkoutRoot(cwd) {
15651
- let current = import_node_path10.default.resolve(cwd);
15853
+ let current = import_node_path11.default.resolve(cwd);
15652
15854
  while (true) {
15653
- if (import_node_fs9.default.existsSync(import_node_path10.default.join(current, ".git"))) return current;
15654
- const parent = import_node_path10.default.dirname(current);
15855
+ if (import_node_fs9.default.existsSync(import_node_path11.default.join(current, ".git"))) return current;
15856
+ const parent = import_node_path11.default.dirname(current);
15655
15857
  if (parent === current) return null;
15656
15858
  current = parent;
15657
15859
  }
15658
15860
  }
15659
15861
  function pathContains(parent, child) {
15660
- const relative = import_node_path10.default.relative(parent, child);
15661
- return relative === "" || relative !== ".." && !relative.startsWith(`..${import_node_path10.default.sep}`) && !import_node_path10.default.isAbsolute(relative);
15862
+ const relative = import_node_path11.default.relative(parent, child);
15863
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${import_node_path11.default.sep}`) && !import_node_path11.default.isAbsolute(relative);
15662
15864
  }
15663
15865
  function resolveDefaultDevBridgeLockfile() {
15664
15866
  const lockfiles = liveDevBridgeLockfiles();
@@ -16081,18 +16283,18 @@ async function evalInBridge(bridge, code, opts = {}) {
16081
16283
  if (opts.acquireLock) payload.acquireLock = true;
16082
16284
  return bridge.send(payload);
16083
16285
  }
16084
- async function callInBridge(bridge, path17, ...args) {
16085
- return bridge.send({ type: "call", path: path17, args });
16286
+ async function callInBridge(bridge, path19, ...args) {
16287
+ return bridge.send({ type: "call", path: path19, args });
16086
16288
  }
16087
- async function callInBridgeWrite(bridge, path17, ...args) {
16088
- return bridge.send({ type: "call", path: path17, args, acquireLock: true });
16289
+ async function callInBridgeWrite(bridge, path19, ...args) {
16290
+ return bridge.send({ type: "call", path: path19, args, acquireLock: true });
16089
16291
  }
16090
- var import_node_fs9, import_node_path10, import_ws3, resolvedWorld, BridgeSimLockedError;
16292
+ var import_node_fs9, import_node_path11, import_ws3, resolvedWorld, BridgeSimLockedError;
16091
16293
  var init_ws_bridge = __esm({
16092
16294
  "cli/ws-bridge.ts"() {
16093
16295
  "use strict";
16094
16296
  import_node_fs9 = __toESM(require("node:fs"), 1);
16095
- import_node_path10 = __toESM(require("node:path"), 1);
16297
+ import_node_path11 = __toESM(require("node:path"), 1);
16096
16298
  import_ws3 = require("ws");
16097
16299
  init_bridge_constants();
16098
16300
  init_cli_constants();
@@ -16147,8 +16349,8 @@ function getDefaultPortForProtocol(protocol) {
16147
16349
  return protocol === "https:" ? 443 : 80;
16148
16350
  }
16149
16351
  function isBaseServerUrl(url) {
16150
- const path17 = url.pathname || "/";
16151
- return (path17 === "/" || path17 === "") && !url.search && !url.hash;
16352
+ const path19 = url.pathname || "/";
16353
+ return (path19 === "/" || path19 === "") && !url.search && !url.hash;
16152
16354
  }
16153
16355
  async function resolvePortViaServerScan(port) {
16154
16356
  try {
@@ -16368,7 +16570,7 @@ var init_profiles = __esm({
16368
16570
  // cli/app-project.ts
16369
16571
  function firstNamedFile(dir, names) {
16370
16572
  for (const name2 of names) {
16371
- const candidate = import_node_path11.default.join(dir, name2);
16573
+ const candidate = import_node_path12.default.join(dir, name2);
16372
16574
  try {
16373
16575
  if (import_node_fs10.default.statSync(candidate).isFile()) return candidate;
16374
16576
  } catch {
@@ -16384,7 +16586,7 @@ function findSootSimAppConfig(dir) {
16384
16586
  }
16385
16587
  function readWorkspacePatterns(rootDir) {
16386
16588
  try {
16387
- const value = JSON.parse(import_node_fs10.default.readFileSync(import_node_path11.default.join(rootDir, "package.json"), "utf8"));
16589
+ const value = JSON.parse(import_node_fs10.default.readFileSync(import_node_path12.default.join(rootDir, "package.json"), "utf8"));
16388
16590
  if (!value || typeof value !== "object") return [];
16389
16591
  const workspaces = Reflect.get(value, "workspaces");
16390
16592
  if (Array.isArray(workspaces)) {
@@ -16406,7 +16608,7 @@ function workspaceDirectories(rootDir) {
16406
16608
  complete = false;
16407
16609
  break;
16408
16610
  }
16409
- if (!pattern || import_node_path11.default.isAbsolute(pattern)) continue;
16611
+ if (!pattern || import_node_path12.default.isAbsolute(pattern)) continue;
16410
16612
  const segments = pattern.split(/[\\/]+/).filter(Boolean);
16411
16613
  if (segments.length === 0 || segments.length > MAX_SCAN_DEPTH) continue;
16412
16614
  if (segments.some((segment) => segment === ".." || segment === "**")) continue;
@@ -16429,10 +16631,10 @@ function workspaceDirectories(rootDir) {
16429
16631
  for (const entry of entries) {
16430
16632
  if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
16431
16633
  if (entry.name.startsWith(".") || SKIP_DIR_NAMES.has(entry.name)) continue;
16432
- next.push(import_node_path11.default.join(parent, entry.name));
16634
+ next.push(import_node_path12.default.join(parent, entry.name));
16433
16635
  }
16434
16636
  } else if (!segment.includes("*")) {
16435
- const candidate = import_node_path11.default.join(parent, segment);
16637
+ const candidate = import_node_path12.default.join(parent, segment);
16436
16638
  try {
16437
16639
  const stat2 = import_node_fs10.default.lstatSync(candidate);
16438
16640
  if (stat2.isDirectory() && !stat2.isSymbolicLink()) next.push(candidate);
@@ -16478,22 +16680,22 @@ function boundedConfigDirectories(rootDir) {
16478
16680
  complete = false;
16479
16681
  break;
16480
16682
  }
16481
- queue.push({ dir: import_node_path11.default.join(current.dir, entry.name), depth: current.depth + 1 });
16683
+ queue.push({ dir: import_node_path12.default.join(current.dir, entry.name), depth: current.depth + 1 });
16482
16684
  }
16483
16685
  }
16484
16686
  return { directories: matches, complete: complete && nextIndex === queue.length };
16485
16687
  }
16486
16688
  function resolveAppProject(startDir, opts = {}) {
16487
- const rootDir = import_node_path11.default.resolve(startDir);
16689
+ const rootDir = import_node_path12.default.resolve(startDir);
16488
16690
  const rootConfigPath = findSootSimAppConfig(rootDir);
16489
16691
  if (findExpoAppConfig(rootDir) || opts.trustStart && import_node_fs10.default.existsSync(rootDir)) {
16490
16692
  let configPath = rootConfigPath;
16491
16693
  if (!configPath && opts.trustStart) {
16492
- let parent = import_node_path11.default.dirname(rootDir);
16493
- for (let depth = 0; depth < MAX_SCAN_DEPTH && parent !== import_node_path11.default.dirname(parent); depth++) {
16694
+ let parent = import_node_path12.default.dirname(rootDir);
16695
+ for (let depth = 0; depth < MAX_SCAN_DEPTH && parent !== import_node_path12.default.dirname(parent); depth++) {
16494
16696
  configPath = findSootSimAppConfig(parent);
16495
16697
  if (configPath) break;
16496
- parent = import_node_path11.default.dirname(parent);
16698
+ parent = import_node_path12.default.dirname(parent);
16497
16699
  }
16498
16700
  }
16499
16701
  return { appDir: rootDir, configPath };
@@ -16525,12 +16727,12 @@ function resolveAppProject(startDir, opts = {}) {
16525
16727
  if (rootConfigPath) return { appDir: rootDir, configPath: rootConfigPath };
16526
16728
  return null;
16527
16729
  }
16528
- var import_node_fs10, import_node_path11, EXPO_APP_CONFIG_NAMES, SOOTSIM_APP_CONFIG_NAMES, SKIP_DIR_NAMES, MAX_SCANNED_DIRECTORIES, MAX_SCAN_DEPTH;
16730
+ var import_node_fs10, import_node_path12, EXPO_APP_CONFIG_NAMES, SOOTSIM_APP_CONFIG_NAMES, SKIP_DIR_NAMES, MAX_SCANNED_DIRECTORIES, MAX_SCAN_DEPTH;
16529
16731
  var init_app_project = __esm({
16530
16732
  "cli/app-project.ts"() {
16531
16733
  "use strict";
16532
16734
  import_node_fs10 = __toESM(require("node:fs"), 1);
16533
- import_node_path11 = __toESM(require("node:path"), 1);
16735
+ import_node_path12 = __toESM(require("node:path"), 1);
16534
16736
  EXPO_APP_CONFIG_NAMES = [
16535
16737
  "app.config.js",
16536
16738
  "app.config.ts",
@@ -16579,6 +16781,19 @@ function isSootSimConfig(value) {
16579
16781
  const network = Reflect.get(value, "network");
16580
16782
  return (runtimeVersion === void 0 || typeof runtimeVersion === "string" && runtimeVersion === runtimeVersion.trim() && isValidRuntimeVersion(runtimeVersion)) && isOptionalRecord(Reflect.get(value, "modules")) && isOptionalRecord(Reflect.get(value, "turboModules")) && isOptionalRecord(Reflect.get(value, "nativeModules")) && isOptionalRecord(Reflect.get(value, "env")) && isOptionalRecord(network) && isOptionalRecord(Reflect.get(value, "settings")) && isOptionalRecord(Reflect.get(value, "initialState"));
16581
16783
  }
16784
+ function resolveConfigReplacementFiles(config, configPath) {
16785
+ if (!config.modules) return config;
16786
+ const configDir = import_node_path13.default.dirname(configPath);
16787
+ return {
16788
+ ...config,
16789
+ modules: Object.fromEntries(
16790
+ Object.entries(config.modules).map(([name2, resolution]) => [
16791
+ name2,
16792
+ resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file: import_node_path13.default.resolve(configDir, resolution.file) } : resolution
16793
+ ])
16794
+ )
16795
+ };
16796
+ }
16582
16797
  async function loadSootSimAppConfig(project) {
16583
16798
  if (!project?.configPath) return void 0;
16584
16799
  try {
@@ -16594,7 +16809,7 @@ async function loadSootSimAppConfig(project) {
16594
16809
  if (!isSootSimConfig(loaded)) {
16595
16810
  throw new Error("the default export must be an rnx config object");
16596
16811
  }
16597
- return loaded;
16812
+ return resolveConfigReplacementFiles(loaded, project.configPath);
16598
16813
  } catch (error) {
16599
16814
  const message = error instanceof Error ? error.message : String(error);
16600
16815
  throw new Error(`could not load ${project.configPath}: ${message}`);
@@ -16604,11 +16819,12 @@ async function resolveSootSimAppConfig(startDir = process.cwd()) {
16604
16819
  const project = resolveAppProject(startDir);
16605
16820
  return { project, config: await loadSootSimAppConfig(project) };
16606
16821
  }
16607
- var import_node_module, import_jiti, require2;
16822
+ var import_node_module, import_node_path13, import_jiti, require2;
16608
16823
  var init_app_config = __esm({
16609
16824
  "cli/app-config.ts"() {
16610
16825
  "use strict";
16611
16826
  import_node_module = require("node:module");
16827
+ import_node_path13 = __toESM(require("node:path"), 1);
16612
16828
  init_src();
16613
16829
  import_jiti = require("jiti");
16614
16830
  init_public_brand();
@@ -16631,7 +16847,7 @@ function localOriginOf(value) {
16631
16847
  }
16632
16848
  function hasPackageJson(dir) {
16633
16849
  try {
16634
- return import_node_fs11.default.statSync(import_node_path12.default.join(dir, "package.json")).isFile();
16850
+ return import_node_fs11.default.statSync(import_node_path14.default.join(dir, "package.json")).isFile();
16635
16851
  } catch {
16636
16852
  return false;
16637
16853
  }
@@ -16640,7 +16856,7 @@ function discoverNativeLinkedAppFonts(opts) {
16640
16856
  const metroOrigin = localOriginOf(opts.bundleUrl);
16641
16857
  if (!metroOrigin) return [];
16642
16858
  const explicit = opts.repoDir || process.env.CONTRAST_REPO_DIR;
16643
- const startDir = explicit ? import_node_path12.default.resolve(explicit) : process.cwd();
16859
+ const startDir = explicit ? import_node_path14.default.resolve(explicit) : process.cwd();
16644
16860
  if (!explicit && !hasPackageJson(startDir)) return [];
16645
16861
  const project = resolveAppProject(startDir, { trustStart: opts.exactProjectDir });
16646
16862
  const selectedAppDir = project?.appDir ?? null;
@@ -16692,7 +16908,7 @@ function discoverNativeLinkedAppFonts(opts) {
16692
16908
  }
16693
16909
  for (const entry of entries) {
16694
16910
  if (entry.isSymbolicLink()) continue;
16695
- const fullPath = import_node_path12.default.join(current.dir, entry.name);
16911
+ const fullPath = import_node_path14.default.join(current.dir, entry.name);
16696
16912
  if (entry.isDirectory()) {
16697
16913
  if (current.depth < 4 && pending.length < 64 && !entry.name.startsWith(".")) {
16698
16914
  pending.push({ dir: fullPath, depth: current.depth + 1 });
@@ -16700,15 +16916,15 @@ function discoverNativeLinkedAppFonts(opts) {
16700
16916
  continue;
16701
16917
  }
16702
16918
  if (!entry.isFile() || !/\.(ttf|otf|woff|woff2)$/i.test(entry.name)) continue;
16703
- const relative = import_node_path12.default.relative(root, fullPath).split(import_node_path12.default.sep).join("/");
16704
- fontPaths.push(import_node_path12.default.posix.join(metroPathPrefix, relative));
16919
+ const relative = import_node_path14.default.relative(root, fullPath).split(import_node_path14.default.sep).join("/");
16920
+ fontPaths.push(import_node_path14.default.posix.join(metroPathPrefix, relative));
16705
16921
  if (fontPaths.length >= 256) break;
16706
16922
  }
16707
16923
  }
16708
16924
  };
16709
16925
  try {
16710
16926
  const packageJson = JSON.parse(
16711
- import_node_fs11.default.readFileSync(import_node_path12.default.join(selectedAppDir, "package.json"), "utf8")
16927
+ import_node_fs11.default.readFileSync(import_node_path14.default.join(selectedAppDir, "package.json"), "utf8")
16712
16928
  );
16713
16929
  const dependencyNames = /* @__PURE__ */ new Set();
16714
16930
  for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
@@ -16723,24 +16939,24 @@ function discoverNativeLinkedAppFonts(opts) {
16723
16939
  const config = Reflect.get(packageJson, "reactNativeVectorIcons");
16724
16940
  const configuredFontDir = config && typeof config === "object" ? Reflect.get(config, "fontDir") : null;
16725
16941
  const configuredDir = typeof configuredFontDir === "string" ? configuredFontDir : "rnvi-fonts";
16726
- const root = import_node_path12.default.resolve(selectedAppDir, configuredDir);
16727
- const relativeRoot = import_node_path12.default.relative(selectedAppDir, root);
16728
- if (!relativeRoot.startsWith("..") && !import_node_path12.default.isAbsolute(relativeRoot)) {
16729
- collectFontFiles(root, relativeRoot.split(import_node_path12.default.sep).join("/"));
16942
+ const root = import_node_path14.default.resolve(selectedAppDir, configuredDir);
16943
+ const relativeRoot = import_node_path14.default.relative(selectedAppDir, root);
16944
+ if (!relativeRoot.startsWith("..") && !import_node_path14.default.isAbsolute(relativeRoot)) {
16945
+ collectFontFiles(root, relativeRoot.split(import_node_path14.default.sep).join("/"));
16730
16946
  }
16731
- const vectorIconRequire = (0, import_node_module2.createRequire)(import_node_path12.default.join(selectedAppDir, "package.json"));
16947
+ const vectorIconRequire = (0, import_node_module2.createRequire)(import_node_path14.default.join(selectedAppDir, "package.json"));
16732
16948
  for (const dependencyName of vectorIconDependencies) {
16733
16949
  try {
16734
16950
  const entryPath = vectorIconRequire.resolve(dependencyName);
16735
- const dependencyPath = dependencyName.split("/").join(import_node_path12.default.sep);
16736
- const marker = `${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}${dependencyPath}${import_node_path12.default.sep}`;
16951
+ const dependencyPath = dependencyName.split("/").join(import_node_path14.default.sep);
16952
+ const marker = `${import_node_path14.default.sep}node_modules${import_node_path14.default.sep}${dependencyPath}${import_node_path14.default.sep}`;
16737
16953
  const markerIndex = entryPath.lastIndexOf(marker);
16738
16954
  if (markerIndex === -1) continue;
16739
16955
  const packageRoot = entryPath.slice(0, markerIndex + marker.length - 1);
16740
16956
  const fontsDir = dependencyName === "react-native-vector-icons" ? "Fonts" : "fonts";
16741
16957
  collectFontFiles(
16742
- import_node_path12.default.join(packageRoot, fontsDir),
16743
- import_node_path12.default.posix.join("node_modules", dependencyName, fontsDir)
16958
+ import_node_path14.default.join(packageRoot, fontsDir),
16959
+ import_node_path14.default.posix.join("node_modules", dependencyName, fontsDir)
16744
16960
  );
16745
16961
  } catch {
16746
16962
  }
@@ -16749,32 +16965,32 @@ function discoverNativeLinkedAppFonts(opts) {
16749
16965
  } catch {
16750
16966
  }
16751
16967
  try {
16752
- const configPath = import_node_path12.default.join(selectedAppDir, "react-native.config.js");
16968
+ const configPath = import_node_path14.default.join(selectedAppDir, "react-native.config.js");
16753
16969
  if (import_node_fs11.default.statSync(configPath).isFile()) {
16754
- const appConfigRequire = (0, import_node_module2.createRequire)(import_node_path12.default.join(selectedAppDir, "package.json"));
16970
+ const appConfigRequire = (0, import_node_module2.createRequire)(import_node_path14.default.join(selectedAppDir, "package.json"));
16755
16971
  const rnConfig = appConfigRequire(configPath);
16756
16972
  const assets = rnConfig && typeof rnConfig === "object" ? Reflect.get(rnConfig, "assets") : null;
16757
16973
  if (Array.isArray(assets)) {
16758
16974
  for (const assetDir of assets) {
16759
16975
  if (typeof assetDir !== "string") continue;
16760
- const root = import_node_path12.default.resolve(selectedAppDir, assetDir);
16761
- const relativeRoot = import_node_path12.default.relative(selectedAppDir, root);
16762
- if (relativeRoot.startsWith("..") || import_node_path12.default.isAbsolute(relativeRoot)) continue;
16763
- collectFontFiles(root, relativeRoot.split(import_node_path12.default.sep).join("/"));
16976
+ const root = import_node_path14.default.resolve(selectedAppDir, assetDir);
16977
+ const relativeRoot = import_node_path14.default.relative(selectedAppDir, root);
16978
+ if (relativeRoot.startsWith("..") || import_node_path14.default.isAbsolute(relativeRoot)) continue;
16979
+ collectFontFiles(root, relativeRoot.split(import_node_path14.default.sep).join("/"));
16764
16980
  }
16765
16981
  }
16766
16982
  }
16767
16983
  } catch {
16768
16984
  }
16769
16985
  if (platform === "ios") {
16770
- const iosDir = import_node_path12.default.join(selectedAppDir, "ios");
16986
+ const iosDir = import_node_path14.default.join(selectedAppDir, "ios");
16771
16987
  try {
16772
16988
  const targetDirs = import_node_fs11.default.readdirSync(iosDir, { withFileTypes: true }).filter(
16773
16989
  (entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
16774
16990
  ).slice(0, 64);
16775
- const plistPaths = [import_node_path12.default.join(iosDir, "Info.plist")];
16991
+ const plistPaths = [import_node_path14.default.join(iosDir, "Info.plist")];
16776
16992
  for (const entry of targetDirs) {
16777
- plistPaths.push(import_node_path12.default.join(iosDir, entry.name, "Info.plist"));
16993
+ plistPaths.push(import_node_path14.default.join(iosDir, entry.name, "Info.plist"));
16778
16994
  }
16779
16995
  for (const plistPath of plistPaths) {
16780
16996
  let parsed;
@@ -16789,12 +17005,12 @@ function discoverNativeLinkedAppFonts(opts) {
16789
17005
  for (const declaredFont of declaredFonts) {
16790
17006
  if (typeof declaredFont !== "string") continue;
16791
17007
  const candidates = [
16792
- import_node_path12.default.resolve(import_node_path12.default.dirname(plistPath), declaredFont),
16793
- import_node_path12.default.resolve(iosDir, declaredFont)
17008
+ import_node_path14.default.resolve(import_node_path14.default.dirname(plistPath), declaredFont),
17009
+ import_node_path14.default.resolve(iosDir, declaredFont)
16794
17010
  ];
16795
17011
  const fontPath = candidates.find((candidate) => {
16796
- const relative = import_node_path12.default.relative(selectedAppDir, candidate);
16797
- if (relative.startsWith("..") || import_node_path12.default.isAbsolute(relative)) return false;
17012
+ const relative = import_node_path14.default.relative(selectedAppDir, candidate);
17013
+ if (relative.startsWith("..") || import_node_path14.default.isAbsolute(relative)) return false;
16798
17014
  try {
16799
17015
  return import_node_fs11.default.statSync(candidate).isFile();
16800
17016
  } catch {
@@ -16803,7 +17019,7 @@ function discoverNativeLinkedAppFonts(opts) {
16803
17019
  });
16804
17020
  if (!fontPath) continue;
16805
17021
  fontPaths.push(
16806
- import_node_path12.default.relative(selectedAppDir, fontPath).split(import_node_path12.default.sep).join("/")
17022
+ import_node_path14.default.relative(selectedAppDir, fontPath).split(import_node_path14.default.sep).join("/")
16807
17023
  );
16808
17024
  }
16809
17025
  }
@@ -16842,13 +17058,13 @@ async function resolveMetroProjectRoot(bundleUrl, opts) {
16842
17058
  function encodeAppFontsWire(specs) {
16843
17059
  return specs.map((spec) => `${encodeURIComponent(spec.url)}::${encodeURIComponent(spec.family)}`).join(",");
16844
17060
  }
16845
- var import_node_fs11, import_node_module2, import_node_path12, import_config_plugin_fonts, require3;
17061
+ var import_node_fs11, import_node_module2, import_node_path14, import_config_plugin_fonts, require3;
16846
17062
  var init_app_fonts = __esm({
16847
17063
  "cli/app-fonts.ts"() {
16848
17064
  "use strict";
16849
17065
  import_node_fs11 = __toESM(require("node:fs"), 1);
16850
17066
  import_node_module2 = require("node:module");
16851
- import_node_path12 = __toESM(require("node:path"), 1);
17067
+ import_node_path14 = __toESM(require("node:path"), 1);
16852
17068
  import_config_plugin_fonts = require("sootsim-engine/engine/config-plugin-fonts");
16853
17069
  init_dev_server_scanner();
16854
17070
  init_plist();
@@ -16871,7 +17087,7 @@ function localOriginOf2(value) {
16871
17087
  }
16872
17088
  function hasPackageJson2(dir) {
16873
17089
  try {
16874
- return import_node_fs12.default.statSync(import_node_path13.default.join(dir, "package.json")).isFile();
17090
+ return import_node_fs12.default.statSync(import_node_path15.default.join(dir, "package.json")).isFile();
16875
17091
  } catch {
16876
17092
  return false;
16877
17093
  }
@@ -16880,7 +17096,7 @@ function discoverConfigPluginAppSplash(opts) {
16880
17096
  const metroOrigin = localOriginOf2(opts.bundleUrl);
16881
17097
  if (!metroOrigin) return null;
16882
17098
  const explicit = opts.repoDir || process.env.CONTRAST_REPO_DIR;
16883
- const startDir = explicit ? import_node_path13.default.resolve(explicit) : process.cwd();
17099
+ const startDir = explicit ? import_node_path15.default.resolve(explicit) : process.cwd();
16884
17100
  if (!explicit && !hasPackageJson2(startDir)) return null;
16885
17101
  const project = resolveAppProject(startDir, { trustStart: opts.exactProjectDir });
16886
17102
  const selectedAppDir = project?.appDir ?? null;
@@ -16914,13 +17130,13 @@ function discoverConfigPluginAppSplash(opts) {
16914
17130
  function encodeAppSplashWire(spec) {
16915
17131
  return encodeURIComponent(JSON.stringify(spec));
16916
17132
  }
16917
- var import_node_fs12, import_node_module3, import_node_path13, import_config_plugin_splash, require4;
17133
+ var import_node_fs12, import_node_module3, import_node_path15, import_config_plugin_splash, require4;
16918
17134
  var init_app_splash = __esm({
16919
17135
  "cli/app-splash.ts"() {
16920
17136
  "use strict";
16921
17137
  import_node_fs12 = __toESM(require("node:fs"), 1);
16922
17138
  import_node_module3 = require("node:module");
16923
- import_node_path13 = __toESM(require("node:path"), 1);
17139
+ import_node_path15 = __toESM(require("node:path"), 1);
16924
17140
  import_config_plugin_splash = require("sootsim-engine/engine/config-plugin-splash");
16925
17141
  init_app_project();
16926
17142
  require4 = (0, import_node_module3.createRequire)(__sootsim_import_meta_url);
@@ -17950,7 +18166,7 @@ function resolvePlaywright() {
17950
18166
  binPath = typeof named === "string" ? named : typeof first === "string" ? first : null;
17951
18167
  }
17952
18168
  if (!binPath) continue;
17953
- const cliPath = (0, import_node_path14.join)((0, import_node_path14.dirname)(packageJsonPath), binPath);
18169
+ const cliPath = (0, import_node_path16.join)((0, import_node_path16.dirname)(packageJsonPath), binPath);
17954
18170
  if (!(0, import_node_fs13.existsSync)(cliPath)) continue;
17955
18171
  return {
17956
18172
  spec,
@@ -18029,14 +18245,14 @@ ${detail}` : ""}`
18029
18245
  }
18030
18246
  return { ok: true, executablePath: after.executablePath, installed: true };
18031
18247
  }
18032
- var import_node_child_process5, import_node_fs13, import_node_module4, import_node_path14, PLAYWRIGHT_BROWSER_PROBE;
18248
+ var import_node_child_process5, import_node_fs13, import_node_module4, import_node_path16, PLAYWRIGHT_BROWSER_PROBE;
18033
18249
  var init_playwright_provisioning = __esm({
18034
18250
  "cli/drivers/playwright-provisioning.ts"() {
18035
18251
  "use strict";
18036
18252
  import_node_child_process5 = require("node:child_process");
18037
18253
  import_node_fs13 = require("node:fs");
18038
18254
  import_node_module4 = require("node:module");
18039
- import_node_path14 = require("node:path");
18255
+ import_node_path16 = require("node:path");
18040
18256
  PLAYWRIGHT_BROWSER_PROBE = `
18041
18257
  const { existsSync } = require('node:fs');
18042
18258
  const modulePath = process.env.SOOTSIM_PW_MODULE;
@@ -19338,10 +19554,10 @@ async function buildResolvedBundleOpenUrl(target, baseUrl, opts = {}) {
19338
19554
  }
19339
19555
  function normalizeReplacementPath(filePath) {
19340
19556
  if (filePath.startsWith("~/")) {
19341
- return import_node_path15.default.join(import_node_os3.default.homedir(), filePath.slice(2));
19557
+ return import_node_path17.default.join(import_node_os3.default.homedir(), filePath.slice(2));
19342
19558
  }
19343
- if (import_node_path15.default.isAbsolute(filePath)) return filePath;
19344
- return import_node_path15.default.resolve(process.cwd(), filePath);
19559
+ if (import_node_path17.default.isAbsolute(filePath)) return filePath;
19560
+ return import_node_path17.default.resolve(process.cwd(), filePath);
19345
19561
  }
19346
19562
  function parseOpenRuntimeConfig(args) {
19347
19563
  const modules = {};
@@ -19395,7 +19611,7 @@ async function resolveOpenAppProject(resolvedBundle) {
19395
19611
  return resolveAppProject(process.env.CONTRAST_REPO_DIR || process.cwd());
19396
19612
  }
19397
19613
  async function ensureConfiguredRuntime(version) {
19398
- if (import_node_fs14.default.existsSync(import_node_path15.default.join(runtimeDir(version), "index.html"))) return;
19614
+ if (import_node_fs14.default.existsSync(import_node_path17.default.join(runtimeDir(version), "index.html"))) return;
19399
19615
  console.error(` installing configured engine runtime ${version}...`);
19400
19616
  const result = await sootsimRuntime.install({
19401
19617
  version,
@@ -19775,17 +19991,17 @@ function printDriverDiagnosticLogTail(result) {
19775
19991
  try {
19776
19992
  const detail = import_node_fs14.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
19777
19993
  if (!detail) {
19778
- console.error(` ${import_node_path15.default.basename(result.diagnosticLogPath)} was empty`);
19994
+ console.error(` ${import_node_path17.default.basename(result.diagnosticLogPath)} was empty`);
19779
19995
  return;
19780
19996
  }
19781
19997
  const shown = detail.length > 4e3 ? `\u2026
19782
19998
  ${detail.slice(-4e3)}` : detail;
19783
- console.error(` ${import_node_path15.default.basename(result.diagnosticLogPath)}:`);
19999
+ console.error(` ${import_node_path17.default.basename(result.diagnosticLogPath)}:`);
19784
20000
  console.error(shown);
19785
20001
  } catch (err) {
19786
20002
  const message = err instanceof Error ? err.message : String(err);
19787
20003
  console.error(
19788
- ` failed to read ${import_node_path15.default.basename(result.diagnosticLogPath)}: ${message}`
20004
+ ` failed to read ${import_node_path17.default.basename(result.diagnosticLogPath)}: ${message}`
19789
20005
  );
19790
20006
  }
19791
20007
  }
@@ -20602,14 +20818,14 @@ async function runCloseCommand(args, opts = {}) {
20602
20818
  bridge.close();
20603
20819
  }
20604
20820
  }
20605
- var import_node_child_process6, import_node_fs14, import_node_os3, import_node_path15, import_settings, import_ws5, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEEP_LINK_SCHEME_RE;
20821
+ var import_node_child_process6, import_node_fs14, import_node_os3, import_node_path17, import_settings, import_ws5, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEEP_LINK_SCHEME_RE;
20606
20822
  var init_control = __esm({
20607
20823
  "cli/commands/control.ts"() {
20608
20824
  "use strict";
20609
20825
  import_node_child_process6 = require("node:child_process");
20610
20826
  import_node_fs14 = __toESM(require("node:fs"), 1);
20611
20827
  import_node_os3 = __toESM(require("node:os"), 1);
20612
- import_node_path15 = __toESM(require("node:path"), 1);
20828
+ import_node_path17 = __toESM(require("node:path"), 1);
20613
20829
  import_settings = require("sootsim-engine/settings");
20614
20830
  import_ws5 = require("ws");
20615
20831
  init_dev_server_scanner();
@@ -21391,14 +21607,14 @@ process.stdin.on('end', async () => {
21391
21607
  function getBaseDir() {
21392
21608
  const explicit = process.env[SESSION_FILE_ENV];
21393
21609
  if (explicit?.trim()) {
21394
- return (0, import_node_path16.dirname)((0, import_node_path16.resolve)(explicit));
21610
+ return (0, import_node_path18.dirname)((0, import_node_path18.resolve)(explicit));
21395
21611
  }
21396
21612
  return electronUserDataDir();
21397
21613
  }
21398
21614
  function getSharedDesktopAuthFilePath() {
21399
21615
  const explicit = process.env[SESSION_FILE_ENV];
21400
- if (explicit?.trim()) return (0, import_node_path16.resolve)(explicit);
21401
- return (0, import_node_path16.join)(getBaseDir(), "desktop-auth.json");
21616
+ if (explicit?.trim()) return (0, import_node_path18.resolve)(explicit);
21617
+ return (0, import_node_path18.join)(getBaseDir(), "desktop-auth.json");
21402
21618
  }
21403
21619
  function normalizeUser(input) {
21404
21620
  if (!input || typeof input !== "object") return null;
@@ -21459,12 +21675,12 @@ function readSharedDesktopAuthSession() {
21459
21675
  return null;
21460
21676
  }
21461
21677
  }
21462
- var import_node_fs15, import_node_path16, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
21678
+ var import_node_fs15, import_node_path18, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
21463
21679
  var init_shared_session = __esm({
21464
21680
  "src/auth/shared-session.ts"() {
21465
21681
  "use strict";
21466
21682
  import_node_fs15 = require("node:fs");
21467
- import_node_path16 = require("node:path");
21683
+ import_node_path18 = require("node:path");
21468
21684
  init_home_paths();
21469
21685
  SESSION_VERSION = 1;
21470
21686
  SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
@@ -21727,16 +21943,16 @@ function resolveFlowScreenshotPath(screenshotDir, name2) {
21727
21943
  }
21728
21944
  function resolveProjectRelativeFlowBase(flowDir) {
21729
21945
  if (!flowDir) return process.cwd();
21730
- return path15.basename(flowDir) === ".maestro" ? path15.dirname(flowDir) : flowDir;
21946
+ return path17.basename(flowDir) === ".maestro" ? path17.dirname(flowDir) : flowDir;
21731
21947
  }
21732
21948
  function resolveFlowScreenshotPathWithMode(screenshotDir, name2, opts) {
21733
21949
  const normalizedName = name2.endsWith(".png") ? name2 : `${name2}.png`;
21734
- if (path15.isAbsolute(normalizedName)) return normalizedName;
21950
+ if (path17.isAbsolute(normalizedName)) return normalizedName;
21735
21951
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
21736
21952
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
21737
- return path15.resolve(baseDir, normalizedName);
21953
+ return path17.resolve(baseDir, normalizedName);
21738
21954
  }
21739
- return path15.join(screenshotDir, normalizedName);
21955
+ return path17.join(screenshotDir, normalizedName);
21740
21956
  }
21741
21957
  function normalizeFlowScreenshotSpec(step) {
21742
21958
  if (typeof step === "string") {
@@ -21793,12 +22009,12 @@ function parseFlowSteps(content) {
21793
22009
  const parsed = import_yaml.default.parse(candidate);
21794
22010
  return Array.isArray(parsed) ? parsed : [];
21795
22011
  }
21796
- var fs16, path15, import_settings3, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
22012
+ var fs17, path17, import_settings3, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
21797
22013
  var init_bridge_flow_runner = __esm({
21798
22014
  "cli/bridge-flow-runner.ts"() {
21799
22015
  "use strict";
21800
- fs16 = __toESM(require("fs"), 1);
21801
- path15 = __toESM(require("path"), 1);
22016
+ fs17 = __toESM(require("fs"), 1);
22017
+ path17 = __toESM(require("path"), 1);
21802
22018
  import_settings3 = require("sootsim-engine/settings");
21803
22019
  import_yaml = __toESM(require("yaml"), 1);
21804
22020
  init_frame_compose();
@@ -22095,14 +22311,14 @@ var init_bridge_flow_runner = __esm({
22095
22311
  if (chunks.length === 0) {
22096
22312
  throw new Error("recording requested but no video buffer was produced");
22097
22313
  }
22098
- fs16.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
22314
+ fs17.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
22099
22315
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
22100
22316
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
22101
- const outputPath = path15.join(
22317
+ const outputPath = path17.join(
22102
22318
  this.opts.recordingOutputDir,
22103
22319
  `sootsim-${Date.now()}.${extension}`
22104
22320
  );
22105
- fs16.writeFileSync(outputPath, Buffer.concat(chunks));
22321
+ fs17.writeFileSync(outputPath, Buffer.concat(chunks));
22106
22322
  return outputPath;
22107
22323
  }
22108
22324
  async waitForRecordingTail(opts) {
@@ -22605,7 +22821,7 @@ var init_bridge_flow_runner = __esm({
22605
22821
  flowDir: this.opts.flowDir
22606
22822
  }
22607
22823
  );
22608
- fs16.mkdirSync(path15.dirname(outputPath), { recursive: true });
22824
+ fs17.mkdirSync(path17.dirname(outputPath), { recursive: true });
22609
22825
  const layers = spec.layers ?? this.opts.screenshotLayers;
22610
22826
  const screenshotRequest = {
22611
22827
  type: "screenshot",
@@ -22621,11 +22837,11 @@ var init_bridge_flow_runner = __esm({
22621
22837
  throw new Error("could not read current device model for framed screenshot");
22622
22838
  }
22623
22839
  const framed = await composeFramedScreenshot(rawBuffer, model);
22624
- fs16.writeFileSync(outputPath, framed);
22840
+ fs17.writeFileSync(outputPath, framed);
22625
22841
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
22626
22842
  return outputPath;
22627
22843
  }
22628
- fs16.writeFileSync(outputPath, rawBuffer);
22844
+ fs17.writeFileSync(outputPath, rawBuffer);
22629
22845
  console.log(`[flow] screenshot: ${outputPath}`);
22630
22846
  return outputPath;
22631
22847
  }
@@ -22641,22 +22857,22 @@ var init_bridge_flow_runner = __esm({
22641
22857
  return model;
22642
22858
  }
22643
22859
  async captureScreenshot(outputPath) {
22644
- fs16.mkdirSync(path15.dirname(outputPath), { recursive: true });
22860
+ fs17.mkdirSync(path17.dirname(outputPath), { recursive: true });
22645
22861
  const dataUrl = await this.bridge.send({
22646
22862
  type: "screenshot",
22647
22863
  simId: this.opts.simId
22648
22864
  });
22649
22865
  const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
22650
- fs16.writeFileSync(outputPath, Buffer.from(base64, "base64"));
22866
+ fs17.writeFileSync(outputPath, Buffer.from(base64, "base64"));
22651
22867
  }
22652
22868
  // writes a per-failure debug bundle: screenshot + structured describe
22653
22869
  // + a11y tree + console errors/warnings + failed network requests +
22654
22870
  // shell state, all under one directory so post-mortem is one grep away.
22655
22871
  async captureFailureBundle(outputDir, context) {
22656
- fs16.mkdirSync(outputDir, { recursive: true });
22872
+ fs17.mkdirSync(outputDir, { recursive: true });
22657
22873
  const write = (name2, content) => {
22658
22874
  try {
22659
- fs16.writeFileSync(path15.join(outputDir, name2), content);
22875
+ fs17.writeFileSync(path17.join(outputDir, name2), content);
22660
22876
  } catch {
22661
22877
  }
22662
22878
  };
@@ -23175,8 +23391,8 @@ var init_bridge_flow_runner = __esm({
23175
23391
  runScript(target) {
23176
23392
  const spec = typeof target === "string" ? { file: target } : target;
23177
23393
  if (!spec.file) throw new Error("runScript requires a file");
23178
- const scriptPath = path15.resolve(this.opts.flowDir, spec.file);
23179
- const source = fs16.readFileSync(scriptPath, "utf8");
23394
+ const scriptPath = path17.resolve(this.opts.flowDir, spec.file);
23395
+ const source = fs17.readFileSync(scriptPath, "utf8");
23180
23396
  this.js.evaluate(source, { env: spec.env });
23181
23397
  console.log(`[flow] runScript: ${spec.file} done`);
23182
23398
  }
@@ -23470,10 +23686,10 @@ var init_bridge_flow_runner = __esm({
23470
23686
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
23471
23687
  }
23472
23688
  if (file) {
23473
- const flowPath = path15.resolve(this.opts.flowDir, file);
23474
- const flowContent = fs16.readFileSync(flowPath, "utf8");
23689
+ const flowPath = path17.resolve(this.opts.flowDir, file);
23690
+ const flowContent = fs17.readFileSync(flowPath, "utf8");
23475
23691
  const previousDir = this.opts.flowDir;
23476
- this.opts.flowDir = path15.dirname(flowPath);
23692
+ this.opts.flowDir = path17.dirname(flowPath);
23477
23693
  try {
23478
23694
  await this.runFlow(parseFlowSteps(flowContent));
23479
23695
  } finally {
@@ -23628,8 +23844,8 @@ __export(registry_exports, {
23628
23844
  skillRegistry: () => skillRegistry
23629
23845
  });
23630
23846
  module.exports = __toCommonJS(registry_exports);
23631
- var fs17 = __toESM(require("fs"), 1);
23632
- var path16 = __toESM(require("path"), 1);
23847
+ var fs18 = __toESM(require("fs"), 1);
23848
+ var path18 = __toESM(require("path"), 1);
23633
23849
 
23634
23850
  // src/skills/builtin/a11y-review.ts
23635
23851
  init_reap_browser();
@@ -23648,8 +23864,8 @@ var skill = {
23648
23864
  },
23649
23865
  async execute(params, context) {
23650
23866
  const { chromium } = await import("playwright");
23651
- const path17 = await import("path");
23652
- const fs18 = await import("fs");
23867
+ const path19 = await import("path");
23868
+ const fs19 = await import("fs");
23653
23869
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
23654
23870
  headless: true
23655
23871
  });
@@ -23704,9 +23920,9 @@ var skill = {
23704
23920
  warnings: issues.filter((i) => i.severity === "warning").length,
23705
23921
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
23706
23922
  };
23707
- const reportPath = path17.join(context.outputDir, "a11y-report.json");
23708
- fs18.mkdirSync(path17.dirname(reportPath), { recursive: true });
23709
- fs18.writeFileSync(reportPath, JSON.stringify(report, null, 2));
23923
+ const reportPath = path19.join(context.outputDir, "a11y-report.json");
23924
+ fs19.mkdirSync(path19.dirname(reportPath), { recursive: true });
23925
+ fs19.writeFileSync(reportPath, JSON.stringify(report, null, 2));
23710
23926
  return {
23711
23927
  success: issues.filter((i) => i.severity === "error").length === 0,
23712
23928
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -23739,14 +23955,14 @@ var skill2 = {
23739
23955
  }
23740
23956
  },
23741
23957
  async execute(params, context) {
23742
- const fs18 = await import("node:fs");
23743
- const path17 = await import("node:path");
23958
+ const fs19 = await import("node:fs");
23959
+ const path19 = await import("node:path");
23744
23960
  const { COMPAT_RESULT_CAVEAT: COMPAT_RESULT_CAVEAT2, formatPackageStatus: formatPackageStatus2, formatScanCounts: formatScanCounts2, scanDeps: scanDeps2 } = await Promise.resolve().then(() => (init_web(), web_exports));
23745
- const packagePath = path17.join(context.projectDir, "package.json");
23746
- if (!fs18.existsSync(packagePath)) {
23961
+ const packagePath = path19.join(context.projectDir, "package.json");
23962
+ if (!fs19.existsSync(packagePath)) {
23747
23963
  return { success: false, message: "No package.json found" };
23748
23964
  }
23749
- const parsed = JSON.parse(fs18.readFileSync(packagePath, "utf8"));
23965
+ const parsed = JSON.parse(fs19.readFileSync(packagePath, "utf8"));
23750
23966
  if (!parsed || typeof parsed !== "object") {
23751
23967
  return { success: false, message: "package.json is not an object" };
23752
23968
  }
@@ -23758,9 +23974,9 @@ var skill2 = {
23758
23974
  }) : scanDeps2(parsed);
23759
23975
  const packageResult = params.packageName ? scan.packages[0] : void 0;
23760
23976
  const message = packageResult ? `${params.packageName}: ${formatPackageStatus2(packageResult)}. ${COMPAT_RESULT_CAVEAT2}` : `${formatScanCounts2(scan)}. ${COMPAT_RESULT_CAVEAT2}`;
23761
- const reportPath = path17.join(context.outputDir, "compat-report.json");
23762
- fs18.mkdirSync(path17.dirname(reportPath), { recursive: true });
23763
- fs18.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
23977
+ const reportPath = path19.join(context.outputDir, "compat-report.json");
23978
+ fs19.mkdirSync(path19.dirname(reportPath), { recursive: true });
23979
+ fs19.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
23764
23980
  `);
23765
23981
  return {
23766
23982
  success: true,
@@ -23804,8 +24020,8 @@ var skill3 = {
23804
24020
  record: { type: "boolean", description: "Record video of the flow" }
23805
24021
  },
23806
24022
  async execute(params, context) {
23807
- const fs18 = await import("fs");
23808
- const path17 = await import("path");
24023
+ const fs19 = await import("fs");
24024
+ const path19 = await import("path");
23809
24025
  const yaml2 = await import("yaml");
23810
24026
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
23811
24027
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -23815,7 +24031,7 @@ var skill3 = {
23815
24031
  const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
23816
24032
  host.start({ silent: true });
23817
24033
  try {
23818
- const flowContent = fs18.readFileSync(params.flowPath, "utf8");
24034
+ const flowContent = fs19.readFileSync(params.flowPath, "utf8");
23819
24035
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
23820
24036
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
23821
24037
  const steps = yaml2.parse(stepsBody);
@@ -23842,7 +24058,7 @@ var skill3 = {
23842
24058
  });
23843
24059
  const driver = new SootSimBridgeFlowRunner2(bridge, {
23844
24060
  screenshotDir: context.outputDir,
23845
- flowDir: path17.dirname(path17.resolve(params.flowPath)),
24061
+ flowDir: path19.dirname(path19.resolve(params.flowPath)),
23846
24062
  simId,
23847
24063
  recordingOutputDir: params.record ? context.outputDir : void 0
23848
24064
  });
@@ -23864,7 +24080,7 @@ var skill3 = {
23864
24080
  simId,
23865
24081
  videoPath: videoPath || void 0
23866
24082
  },
23867
- artifacts: videoPath ? [{ type: "video", name: path17.basename(videoPath), path: videoPath }] : void 0
24083
+ artifacts: videoPath ? [{ type: "video", name: path19.basename(videoPath), path: videoPath }] : void 0
23868
24084
  };
23869
24085
  } finally {
23870
24086
  try {
@@ -23911,8 +24127,8 @@ var skill4 = {
23911
24127
  },
23912
24128
  async execute(params, context) {
23913
24129
  const { chromium } = await import("playwright");
23914
- const path17 = await import("path");
23915
- const fs18 = await import("fs");
24130
+ const path19 = await import("path");
24131
+ const fs19 = await import("fs");
23916
24132
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
23917
24133
  headless: true
23918
24134
  });
@@ -23938,9 +24154,9 @@ var skill4 = {
23938
24154
  ...profile,
23939
24155
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
23940
24156
  };
23941
- const reportPath = path17.join(context.outputDir, "perf-report.json");
23942
- fs18.mkdirSync(path17.dirname(reportPath), { recursive: true });
23943
- fs18.writeFileSync(reportPath, JSON.stringify(report, null, 2));
24157
+ const reportPath = path19.join(context.outputDir, "perf-report.json");
24158
+ fs19.mkdirSync(path19.dirname(reportPath), { recursive: true });
24159
+ fs19.writeFileSync(reportPath, JSON.stringify(report, null, 2));
23944
24160
  return {
23945
24161
  success: true,
23946
24162
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -23973,8 +24189,8 @@ var skill5 = {
23973
24189
  },
23974
24190
  async execute(params, context) {
23975
24191
  const { chromium } = await import("playwright");
23976
- const path17 = await import("path");
23977
- const fs18 = await import("fs");
24192
+ const path19 = await import("path");
24193
+ const fs19 = await import("fs");
23978
24194
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
23979
24195
  headless: true
23980
24196
  });
@@ -23982,8 +24198,8 @@ var skill5 = {
23982
24198
  try {
23983
24199
  await page.goto(context.url, { waitUntil: "networkidle" });
23984
24200
  await page.waitForTimeout(2e3);
23985
- const outputPath = path17.join(context.outputDir, `${params.name}.png`);
23986
- fs18.mkdirSync(path17.dirname(outputPath), { recursive: true });
24201
+ const outputPath = path19.join(context.outputDir, `${params.name}.png`);
24202
+ fs19.mkdirSync(path19.dirname(outputPath), { recursive: true });
23987
24203
  await page.screenshot({ path: outputPath });
23988
24204
  return {
23989
24205
  success: true,
@@ -24024,8 +24240,8 @@ var skill6 = {
24024
24240
  },
24025
24241
  async execute(params, context) {
24026
24242
  const { chromium } = await import("playwright");
24027
- const path17 = await import("path");
24028
- const fs18 = await import("fs");
24243
+ const path19 = await import("path");
24244
+ const fs19 = await import("fs");
24029
24245
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
24030
24246
  headless: true
24031
24247
  });
@@ -24033,14 +24249,14 @@ var skill6 = {
24033
24249
  try {
24034
24250
  await page.goto(context.url, { waitUntil: "networkidle" });
24035
24251
  await page.waitForTimeout(2e3);
24036
- const currentPath = path17.join(context.outputDir, `${params.name}-current.png`);
24037
- fs18.mkdirSync(path17.dirname(currentPath), { recursive: true });
24252
+ const currentPath = path19.join(context.outputDir, `${params.name}-current.png`);
24253
+ fs19.mkdirSync(path19.dirname(currentPath), { recursive: true });
24038
24254
  await page.screenshot({ path: currentPath });
24039
24255
  try {
24040
24256
  const { PNG } = await import("pngjs");
24041
24257
  const pixelmatch = (await import("pixelmatch")).default;
24042
- const baseline = PNG.sync.read(fs18.readFileSync(params.baseline));
24043
- const current = PNG.sync.read(fs18.readFileSync(currentPath));
24258
+ const baseline = PNG.sync.read(fs19.readFileSync(params.baseline));
24259
+ const current = PNG.sync.read(fs19.readFileSync(currentPath));
24044
24260
  const { width, height } = baseline;
24045
24261
  const diff = new PNG({ width, height });
24046
24262
  const numDiffPixels = pixelmatch(
@@ -24051,8 +24267,8 @@ var skill6 = {
24051
24267
  height,
24052
24268
  { threshold: params.threshold || 0.1 }
24053
24269
  );
24054
- const diffPath = path17.join(context.outputDir, `${params.name}-diff.png`);
24055
- fs18.writeFileSync(diffPath, PNG.sync.write(diff));
24270
+ const diffPath = path19.join(context.outputDir, `${params.name}-diff.png`);
24271
+ fs19.writeFileSync(diffPath, PNG.sync.write(diff));
24056
24272
  const totalPixels = width * height;
24057
24273
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
24058
24274
  return {
@@ -24116,10 +24332,10 @@ var skillRegistry = {
24116
24332
  },
24117
24333
  // load skills from a project manifest (sootsim-skills.json)
24118
24334
  async loadFromManifest(projectDir) {
24119
- const manifestPath = path16.join(projectDir, "sootsim-skills.json");
24120
- if (!fs17.existsSync(manifestPath)) return;
24335
+ const manifestPath = path18.join(projectDir, "sootsim-skills.json");
24336
+ if (!fs18.existsSync(manifestPath)) return;
24121
24337
  try {
24122
- const manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf8"));
24338
+ const manifest = JSON.parse(fs18.readFileSync(manifestPath, "utf8"));
24123
24339
  if (Array.isArray(manifest.skills)) {
24124
24340
  for (const entry of manifest.skills) {
24125
24341
  if (typeof entry === "string") {
@@ -24130,7 +24346,7 @@ var skillRegistry = {
24130
24346
  }
24131
24347
  } else if (entry.file) {
24132
24348
  try {
24133
- const mod = await import(path16.resolve(projectDir, entry.file));
24349
+ const mod = await import(path18.resolve(projectDir, entry.file));
24134
24350
  if (mod.skill) this.register(mod.skill);
24135
24351
  } catch {
24136
24352
  }
@@ -24143,10 +24359,10 @@ var skillRegistry = {
24143
24359
  // auto-discover skills based on project dependencies
24144
24360
  suggestSkills(projectDir) {
24145
24361
  const suggestions = [];
24146
- const pkgPath = path16.join(projectDir, "package.json");
24147
- if (!fs17.existsSync(pkgPath)) return suggestions;
24362
+ const pkgPath = path18.join(projectDir, "package.json");
24363
+ if (!fs18.existsSync(pkgPath)) return suggestions;
24148
24364
  try {
24149
- const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf8"));
24365
+ const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
24150
24366
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
24151
24367
  if (deps["detox"] || deps["maestro"]) {
24152
24368
  suggestions.push("maestro-test");