rnxsim 0.1.370 → 0.1.372

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 (207) hide show
  1. package/cli/bin.ts +2 -2
  2. package/cli/commands/box/checkout-plane.ts +65 -14
  3. package/cli/commands/box/cloud-box.ts +294 -0
  4. package/cli/commands/box/plane-share.ts +208 -0
  5. package/cli/commands/box/rnx-command.ts +2 -2
  6. package/cli/commands/box/search-command.ts +157 -0
  7. package/cli/commands/box.ts +269 -13
  8. package/cli/commands/control.ts +6 -1
  9. package/cli/outbound-endpoints.ts +37 -1
  10. package/dist-cli/bin.js +5 -5
  11. package/dist-cli/chunks/{agent-3R4424LW.js → agent-RTAKJ5UM.js} +2 -2
  12. package/dist-cli/chunks/{agent-wrapper-4PPWZWSY.js → agent-wrapper-JWRDI26D.js} +2 -2
  13. package/dist-cli/chunks/{app-fonts-KYXB6CXQ.js → app-fonts-RKO3N4PB.js} +2 -2
  14. package/dist-cli/chunks/{assert-7EZOWGYQ.js → assert-Y5LXPWC6.js} +2 -2
  15. package/dist-cli/chunks/{auth-L7M36H6C.js → auth-4SPTRWTM.js} +2 -2
  16. package/dist-cli/chunks/{beta-FKAF6YWJ.js → beta-KYS22QPY.js} +2 -2
  17. package/dist-cli/chunks/{box-5Y5VBMHV.js → box-7CK72ZPF.js} +617 -596
  18. package/dist-cli/chunks/{camera-XHF2RPFG.js → camera-RUL426MQ.js} +2 -2
  19. package/dist-cli/chunks/{chunk-EQ3OE2AV.js → chunk-2MA3Q44D.js} +1 -1
  20. package/dist-cli/chunks/{chunk-DHYTRCIP.js → chunk-2OA2WE7G.js} +2 -2
  21. package/dist-cli/chunks/{chunk-DMHSD6YJ.js → chunk-3C6LTIDV.js} +2 -2
  22. package/dist-cli/chunks/{chunk-NR2V2ONN.js → chunk-4UMODU6C.js} +2 -2
  23. package/dist-cli/chunks/{chunk-Z2VBSNFI.js → chunk-5Q6ZEZFF.js} +1 -1
  24. package/dist-cli/chunks/{chunk-LUOHRBJG.js → chunk-7FYOZQBM.js} +1 -1
  25. package/dist-cli/chunks/{chunk-Q4MRJ6PO.js → chunk-BRRWRBW7.js} +2 -2
  26. package/dist-cli/chunks/chunk-CEQXZ3GA.js +11 -0
  27. package/dist-cli/chunks/{chunk-DUXHYPBP.js → chunk-CZ2FOZVC.js} +2 -2
  28. package/dist-cli/chunks/{chunk-CMVRTZ5G.js → chunk-D5AT7UT5.js} +2 -2
  29. package/dist-cli/chunks/{chunk-D2GZASRV.js → chunk-DQOQQFMP.js} +1 -1
  30. package/dist-cli/chunks/{chunk-3UXXYJVD.js → chunk-EKSSAC4L.js} +1 -1
  31. package/dist-cli/chunks/{chunk-5BR33NAZ.js → chunk-EY5OHL2M.js} +1 -1
  32. package/dist-cli/chunks/{chunk-FK4JSTZ3.js → chunk-FOW2LPM7.js} +2 -2
  33. package/dist-cli/chunks/{chunk-WFQHT4QD.js → chunk-G5G7PQKO.js} +2 -2
  34. package/dist-cli/chunks/{chunk-WPV4H5S4.js → chunk-GPYG2L7R.js} +2 -2
  35. package/dist-cli/chunks/{chunk-3SOPYG7S.js → chunk-H2SKPUSI.js} +2 -2
  36. package/dist-cli/chunks/{chunk-6A6L3VJR.js → chunk-H567W7JT.js} +2 -2
  37. package/dist-cli/chunks/{chunk-PAUEZO6F.js → chunk-HDGZAVH3.js} +2 -2
  38. package/dist-cli/chunks/{chunk-AALKIAUZ.js → chunk-I37LRPZ3.js} +1 -1
  39. package/dist-cli/chunks/{chunk-JZLDHPB7.js → chunk-I7LRVN5M.js} +2 -2
  40. package/dist-cli/chunks/{chunk-3BG6UCQY.js → chunk-IX25FFF3.js} +11 -11
  41. package/dist-cli/chunks/{chunk-72S5FCBY.js → chunk-J2TJRPDB.js} +2 -2
  42. package/dist-cli/chunks/{chunk-RRX52O37.js → chunk-JPRHJMUJ.js} +1 -1
  43. package/dist-cli/chunks/{chunk-BMIJZNKD.js → chunk-K4TGUDY4.js} +2 -2
  44. package/dist-cli/chunks/{chunk-7C7TJYZ3.js → chunk-KSE5XGYU.js} +2 -2
  45. package/dist-cli/chunks/{chunk-OJZHECGH.js → chunk-KVVNCIJA.js} +1 -1
  46. package/dist-cli/chunks/{chunk-LXPHL6FO.js → chunk-KWLUOLYQ.js} +2 -2
  47. package/dist-cli/chunks/{chunk-C7BA5CCM.js → chunk-KXAE64HF.js} +2 -2
  48. package/dist-cli/chunks/{chunk-EWSWOWXK.js → chunk-L5BEWXQZ.js} +2 -2
  49. package/dist-cli/chunks/{chunk-D24EOJ4C.js → chunk-LAQKTHRM.js} +2 -2
  50. package/dist-cli/chunks/{chunk-IDLFVRPN.js → chunk-LWLHVF6Y.js} +1 -1
  51. package/dist-cli/chunks/{chunk-EOIBLKZO.js → chunk-MKHW3JNL.js} +2 -2
  52. package/dist-cli/chunks/{chunk-64JAEJ6N.js → chunk-MSM2E74F.js} +1 -1
  53. package/dist-cli/chunks/{chunk-DXV37CJN.js → chunk-NBEOA72C.js} +1 -1
  54. package/dist-cli/chunks/{chunk-H5X5FJ63.js → chunk-NLMDMNO6.js} +2 -2
  55. package/dist-cli/chunks/{chunk-6W4HIWC7.js → chunk-NT43X5LI.js} +2 -2
  56. package/dist-cli/chunks/{chunk-PNOENVMJ.js → chunk-NWPYM54M.js} +1 -1
  57. package/dist-cli/chunks/{chunk-O6QLKSAM.js → chunk-OLHHB6LD.js} +2 -2
  58. package/dist-cli/chunks/{chunk-MDCY532E.js → chunk-P6K6XFWE.js} +2 -2
  59. package/dist-cli/chunks/{chunk-LIMWG54N.js → chunk-PETP6LVI.js} +1 -1
  60. package/dist-cli/chunks/{chunk-YIZGNT7A.js → chunk-PKY76S57.js} +1 -1
  61. package/dist-cli/chunks/chunk-POR7R3TP.js +4 -0
  62. package/dist-cli/chunks/chunk-PUH6RQBJ.js +7 -0
  63. package/dist-cli/chunks/{chunk-NJMU5BN6.js → chunk-Q5WPPOFV.js} +1 -1
  64. package/dist-cli/chunks/{chunk-HQQTS2CB.js → chunk-Q7JSU5DI.js} +3 -3
  65. package/dist-cli/chunks/{chunk-U63T6LIQ.js → chunk-QA2PTSOC.js} +1 -1
  66. package/dist-cli/chunks/{chunk-2FOGXVOK.js → chunk-R7HMFLXI.js} +2 -2
  67. package/dist-cli/chunks/{chunk-FA75F34Z.js → chunk-RXKZJAGY.js} +1 -1
  68. package/dist-cli/chunks/{chunk-5RKRVS5A.js → chunk-SC7PGULZ.js} +2 -2
  69. package/dist-cli/chunks/{chunk-UFVAAWGZ.js → chunk-SLTEYNAE.js} +1 -1
  70. package/dist-cli/chunks/{chunk-6GPS7U4X.js → chunk-SSQCKJQZ.js} +2 -2
  71. package/dist-cli/chunks/{chunk-ARMXC3C3.js → chunk-SZX6ARJX.js} +3 -3
  72. package/dist-cli/chunks/{chunk-6S5LJV2O.js → chunk-U3XYGLXG.js} +2 -2
  73. package/dist-cli/chunks/chunk-UA5WQCBU.js +7 -0
  74. package/dist-cli/chunks/{chunk-VVQCZ42C.js → chunk-UVKX6FQ4.js} +1 -1
  75. package/dist-cli/chunks/{chunk-Z3DENGXW.js → chunk-VQQXUXXF.js} +2 -2
  76. package/dist-cli/chunks/{chunk-I52NT6VG.js → chunk-WR7LRCYW.js} +1 -1
  77. package/dist-cli/chunks/{chunk-HEKHLQ3B.js → chunk-XA4YU3A4.js} +3 -3
  78. package/dist-cli/chunks/{chunk-GRO74J2X.js → chunk-YEGWC2OY.js} +1 -1
  79. package/dist-cli/chunks/{chunk-AVJBT5LF.js → chunk-YWTBN7SD.js} +1 -1
  80. package/dist-cli/chunks/{chunk-PIZXOXBL.js → chunk-ZRQKEKHX.js} +2 -2
  81. package/dist-cli/chunks/{chunk-X6WQ4YWE.js → chunk-ZTZTRD5R.js} +1 -1
  82. package/dist-cli/chunks/{cleanup-MXMMJ7JW.js → cleanup-7ATBNZHC.js} +2 -2
  83. package/dist-cli/chunks/cli-version-D2IDQO7X.js +4 -0
  84. package/dist-cli/chunks/{compat-E6KE5KDI.js → compat-4ZC6ZMMA.js} +2 -2
  85. package/dist-cli/chunks/{config-QSLLVZDS.js → config-EOBODQ32.js} +2 -2
  86. package/dist-cli/chunks/{connect-QE4VU6GB.js → connect-ZQ72CZ7O.js} +2 -2
  87. package/dist-cli/chunks/control-FKPKLOE2.js +4 -0
  88. package/dist-cli/chunks/daemon-WFHWS3JU.js +4 -0
  89. package/dist-cli/chunks/{debug-5FG3MBJS.js → debug-7Z325GNU.js} +3 -3
  90. package/dist-cli/chunks/{desktop-5EZX7NX5.js → desktop-CR7ALX7H.js} +3 -3
  91. package/dist-cli/chunks/{detox-WJGQP5TM.js → detox-RZ37736M.js} +2 -2
  92. package/dist-cli/chunks/{device-D7LKCAMS.js → device-TA3SQP6K.js} +2 -2
  93. package/dist-cli/chunks/{diagnose-A3W6ZTGA.js → diagnose-JFKFKR3S.js} +2 -2
  94. package/dist-cli/chunks/disk-cleanup-HZM7VM4S.js +4 -0
  95. package/dist-cli/chunks/{do-chain-RUJNRPPF.js → do-chain-MTT65YNX.js} +2 -2
  96. package/dist-cli/chunks/drivers-BXEXWRVJ.js +4 -0
  97. package/dist-cli/chunks/{env-U67SQVTV.js → env-SFI24PLS.js} +2 -2
  98. package/dist-cli/chunks/{film-XC6UAQ3V.js → film-GPHSJLIH.js} +3 -3
  99. package/dist-cli/chunks/flow-FBCU3TZN.js +4 -0
  100. package/dist-cli/chunks/help-6MLROWYO.js +4 -0
  101. package/dist-cli/chunks/{hidden-runtime-alias-7S2TNZXG.js → hidden-runtime-alias-7Z6PYH53.js} +2 -2
  102. package/dist-cli/chunks/{home-paths-LMO5LB4F.js → home-paths-MEGVA6ET.js} +2 -2
  103. package/dist-cli/chunks/inspect-EWT5SXBD.js +4 -0
  104. package/dist-cli/chunks/install-desktop-IFBUH7MH.js +4 -0
  105. package/dist-cli/chunks/{login-JIU42S4C.js → login-EHUZYRAM.js} +2 -2
  106. package/dist-cli/chunks/{logout-JTAWQXZO.js → logout-WPGT62N6.js} +2 -2
  107. package/dist-cli/chunks/{maestro-TYBQYOGB.js → maestro-4HVDLCTI.js} +3 -3
  108. package/dist-cli/chunks/{maestro-generate-YLAGWVKE.js → maestro-generate-VBS2EZMM.js} +3 -3
  109. package/dist-cli/chunks/{mode-DV24ZRZ6.js → mode-MGTS4QTF.js} +2 -2
  110. package/dist-cli/chunks/{optional-demo-registry-JZH66VIM.js → optional-demo-registry-F3FQT5WT.js} +2 -2
  111. package/dist-cli/chunks/{perf-LXXJ4EAX.js → perf-47R3OEI7.js} +2 -2
  112. package/dist-cli/chunks/{permissions-KAOVZUPW.js → permissions-ZOLFZWR2.js} +2 -2
  113. package/dist-cli/chunks/{platform-KW35446W.js → platform-C4E26ZBZ.js} +3 -3
  114. package/dist-cli/chunks/privacy-WXGGG4ZI.js +4 -0
  115. package/dist-cli/chunks/{record-EK3ETFHZ.js → record-OUXWCWUF.js} +3 -3
  116. package/dist-cli/chunks/{report-issue-NW5PCAZF.js → report-issue-LJJXONXQ.js} +2 -2
  117. package/dist-cli/chunks/reset-ZZYLPETS.js +4 -0
  118. package/dist-cli/chunks/resolve-target-MVZZR2JW.js +4 -0
  119. package/dist-cli/chunks/runtime-DEC5AF3M.js +4 -0
  120. package/dist-cli/chunks/{screenshot-command-TQSPTFT2.js → screenshot-command-CUHDOS5D.js} +3 -3
  121. package/dist-cli/chunks/{screenshot-layers-IZP3L3AQ.js → screenshot-layers-DVWQVKT6.js} +2 -2
  122. package/dist-cli/chunks/{screenshots-capture-K7LJOVAE.js → screenshots-capture-GWIUJ3A6.js} +2 -2
  123. package/dist-cli/chunks/{serve-MMX4WXXG.js → serve-TX5OKGJM.js} +19 -19
  124. package/dist-cli/chunks/setup-X7LLGW67.js +4 -0
  125. package/dist-cli/chunks/{sim-client-KLAYIFOC.js → sim-client-W4WZOZ3P.js} +2 -2
  126. package/dist-cli/chunks/{skills-N4D3POIS.js → skills-TDFQAZ6A.js} +2 -2
  127. package/dist-cli/chunks/{state-ES6TFQZF.js → state-P2Z25OLQ.js} +2 -2
  128. package/dist-cli/chunks/{storage-52DR5V2C.js → storage-DWEOFXEB.js} +2 -2
  129. package/dist-cli/chunks/store-TKBLMYCV.js +4 -0
  130. package/dist-cli/chunks/telemetry-E3CBKJMD.js +4 -0
  131. package/dist-cli/chunks/{timeline-NRVNB5JR.js → timeline-55XNA4GX.js} +2 -2
  132. package/dist-cli/chunks/{upgrade-LNED5YQ2.js → upgrade-3XRCVDVC.js} +2 -2
  133. package/dist-cli/chunks/upload-QB77GSMQ.js +4 -0
  134. package/dist-cli/chunks/{version-VEF2DYGG.js → version-WTYGLXBJ.js} +2 -2
  135. package/dist-cli/chunks/{web-CGDE6S73.js → web-ZWRY3VHM.js} +2 -2
  136. package/dist-cli/chunks/welcome-7ATM5EGX.js +5 -0
  137. package/dist-cli/chunks/{what-happened-FSIDWL32.js → what-happened-Q3IGIH4K.js} +2 -2
  138. package/dist-cli/chunks/{ws-bridge-QXFQLRE7.js → ws-bridge-KCPZSBBX.js} +2 -2
  139. package/dist-lib/agent-daemon-client.cjs +1 -1
  140. package/dist-lib/agent-events.cjs +1 -1
  141. package/dist-lib/agent-identity.cjs +1 -1
  142. package/dist-lib/agent-sessions.cjs +1 -1
  143. package/dist-lib/attached-projects.cjs +1 -1
  144. package/dist-lib/auth/shared-session.cjs +1 -1
  145. package/dist-lib/backend-origin.cjs +1 -1
  146. package/dist-lib/beta.cjs +1 -1
  147. package/dist-lib/beta.mjs +1 -1
  148. package/dist-lib/bridge-constants.cjs +1 -1
  149. package/dist-lib/bridge-contract-input.cjs +1 -1
  150. package/dist-lib/bridge-contract-input.mjs +1 -1
  151. package/dist-lib/bridge-contract.cjs +1 -1
  152. package/dist-lib/bridge-contract.mjs +1 -1
  153. package/dist-lib/cli-constants.cjs +1 -1
  154. package/dist-lib/config.cjs +1 -1
  155. package/dist-lib/detox/index.cjs +1 -1
  156. package/dist-lib/dev-bundle-resolution.cjs +69 -34
  157. package/dist-lib/home-paths.cjs +1 -1
  158. package/dist-lib/host/bridge-host.cjs +430 -106
  159. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  160. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  161. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  162. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  163. package/dist-lib/host/websocket-proxy.cjs +1 -1
  164. package/dist-lib/index.cjs +1 -1
  165. package/dist-lib/jump-to-source-babel.cjs +1 -1
  166. package/dist-lib/menu.cjs +1 -1
  167. package/dist-lib/menu.mjs +1 -1
  168. package/dist-lib/metro-production-bundle.cjs +1 -1
  169. package/dist-lib/metro-production-bundle.mjs +1 -1
  170. package/dist-lib/metro.cjs +1 -1
  171. package/dist-lib/profiles.cjs +1 -1
  172. package/dist-lib/public-brand.cjs +1 -1
  173. package/dist-lib/react-native-host-modules.cjs +1 -1
  174. package/dist-lib/react-native-host-modules.mjs +1 -1
  175. package/dist-lib/render-mode.cjs +1 -1
  176. package/dist-lib/scripts/dev-server-scanner.cjs +149 -93
  177. package/dist-lib/sdk.cjs +1 -1
  178. package/dist-lib/sdk.mjs +1 -1
  179. package/dist-lib/skills.cjs +679 -307
  180. package/dist-lib/vite.cjs +1 -1
  181. package/package.json +1 -1
  182. package/scripts/dev-server-scanner.ts +275 -92
  183. package/src/dev-bundle-resolution.ts +123 -40
  184. package/src/disk-cleanup.ts +44 -0
  185. package/src/host/bridge-host.ts +11 -0
  186. package/src/host/plane-host.ts +203 -0
  187. package/dist-cli/chunks/chunk-GJRLPJQL.js +0 -6
  188. package/dist-cli/chunks/chunk-NTC46LSA.js +0 -4
  189. package/dist-cli/chunks/chunk-OTFTMGAL.js +0 -7
  190. package/dist-cli/chunks/cli-version-MLS55UTY.js +0 -4
  191. package/dist-cli/chunks/control-XD5F6K5T.js +0 -4
  192. package/dist-cli/chunks/daemon-UN5SE2JO.js +0 -4
  193. package/dist-cli/chunks/disk-cleanup-BDRHX5ZG.js +0 -4
  194. package/dist-cli/chunks/drivers-3NJ5RL6X.js +0 -4
  195. package/dist-cli/chunks/flow-FHZZD3P6.js +0 -4
  196. package/dist-cli/chunks/help-BYYDUSXF.js +0 -4
  197. package/dist-cli/chunks/inspect-RQCTWDCC.js +0 -4
  198. package/dist-cli/chunks/install-desktop-GOWXCQUE.js +0 -4
  199. package/dist-cli/chunks/privacy-MIFE72CG.js +0 -4
  200. package/dist-cli/chunks/reset-RZ4O5AFJ.js +0 -4
  201. package/dist-cli/chunks/resolve-target-7R5BNYMM.js +0 -4
  202. package/dist-cli/chunks/runtime-MZHLSRS6.js +0 -4
  203. package/dist-cli/chunks/setup-YFP3KEQZ.js +0 -4
  204. package/dist-cli/chunks/store-HOL45WCI.js +0 -4
  205. package/dist-cli/chunks/telemetry-BV6OTYPF.js +0 -4
  206. package/dist-cli/chunks/upload-RXKHFIBU.js +0 -4
  207. package/dist-cli/chunks/welcome-FT2AMUWW.js +0 -5
@@ -108,6 +108,7 @@ async function resolvePortViaServerScan(port: number): Promise<ResolvedDevBundle
108
108
  bundleUrl: string
109
109
  framework?: string
110
110
  projectName?: string
111
+ bundleUrlProvisional?: boolean
111
112
  } =>
112
113
  !!s &&
113
114
  typeof s === 'object' &&
@@ -115,6 +116,13 @@ async function resolvePortViaServerScan(port: number): Promise<ResolvedDevBundle
115
116
  typeof (s as { bundleUrl?: unknown }).bundleUrl === 'string',
116
117
  )
117
118
  if (!match) return null
119
+ // the scanner marks a bundle URL provisional when its own fast manifest
120
+ // probe got no answer and it fell back to the generic `/index.bundle`. that
121
+ // is enough to LIST the server and not enough to open it, so fall through
122
+ // to the direct probe below, which asks the manifest again with a budget
123
+ // that fits a real dev server. same rule the CLI applies in
124
+ // `resolveConnectionInputForCli`; a provisional URL must never reach a sim.
125
+ if (match.bundleUrlProvisional) return null
118
126
  return {
119
127
  // normalize exactly like the manifest-probe branch below — the scan
120
128
  // returns metro's manifest launchAsset url (lazy=true for code-split
@@ -131,38 +139,122 @@ async function resolvePortViaServerScan(port: number): Promise<ResolvedDevBundle
131
139
  }
132
140
  }
133
141
 
142
+ // how a dev server answered `GET /`, which is the one request that tells the
143
+ // two kinds of dev server apart. an Expo or One server answers with its
144
+ // manifest. a vanilla Metro server answers with Metro's own HTML landing page
145
+ // and has no manifest to serve. NO answer is neither: a One server that is
146
+ // still starting leaves `/` hanging until its manifest middleware is up, while
147
+ // `/status` already reports packager-status:running. reading that silence as
148
+ // "this server has no manifest" opens the app on `<base>/index.bundle` — a
149
+ // second entry point, with its own module graph, that the app's manifest never
150
+ // named — so Metro builds the whole app twice and the connection is labelled
151
+ // `metro` instead of its real framework.
152
+ type ManifestProbe =
153
+ | { state: 'resolved'; bundle: ResolvedDevBundle }
154
+ | { state: 'no-manifest' }
155
+ | { state: 'no-answer' }
156
+
157
+ // a `/` that has not answered in this long is a server still coming up, not a
158
+ // server telling us what it is. without it an unresponsive dev server hangs
159
+ // the caller for as long as it feels like.
160
+ const MANIFEST_PROBE_TIMEOUT_MS = 5_000
161
+ // how long to keep asking a confirmed-running packager for its manifest.
162
+ const MANIFEST_BOOT_BUDGET_MS = 30_000
163
+ const MANIFEST_BOOT_RETRY_MS = 1_000
164
+
165
+ async function probeExpoManifest(
166
+ normalizedBaseUrl: string,
167
+ port: number,
168
+ ): Promise<ManifestProbe> {
169
+ let body: string
170
+ // the deadline means STOP WAITING, not KILL THE REQUEST. `AbortSignal.timeout`
171
+ // does the second: it tears down a dev server that is still assembling its
172
+ // manifest, which fires "Cannot pipe to a closed or destroyed stream" into
173
+ // One's manifest middleware and can exit the user's dev server. so nothing
174
+ // here aborts. we race the probe against the budget, answer `no-answer` on
175
+ // time, and let the request run itself out in the background, discarded.
176
+ const pending = fetchDevProbe(`${normalizedBaseUrl}/`, {
177
+ headers: { 'expo-platform': 'ios' },
178
+ }).then(
179
+ async (res) => (res.ok ? { ok: true as const, body: await res.text() } : null),
180
+ () => undefined,
181
+ )
182
+ const answered = await Promise.race([
183
+ pending,
184
+ new Promise<'timeout'>((resolve) =>
185
+ setTimeout(() => resolve('timeout'), MANIFEST_PROBE_TIMEOUT_MS).unref?.(),
186
+ ),
187
+ ])
188
+ if (answered === 'timeout' || answered === undefined) return { state: 'no-answer' }
189
+ if (answered === null) return { state: 'no-manifest' }
190
+ body = answered.body
191
+ if (!body.trim()) return { state: 'no-answer' }
192
+
193
+ let manifest: any
194
+ try {
195
+ manifest = JSON.parse(body)
196
+ } catch {
197
+ // a page rather than a manifest — Metro's landing page, or an app's own
198
+ // SSR html. that is a real answer: this server serves no manifest.
199
+ return { state: 'no-manifest' }
200
+ }
201
+
202
+ const client = manifest?.extra?.expoClient || manifest?.extra || {}
203
+ const rawLaunchUrl =
204
+ typeof manifest?.launchAsset?.url === 'string' ? manifest.launchAsset.url : undefined
205
+ const launchUrl = rawLaunchUrl
206
+ ? alignLoopbackBundleUrlWithProbe(rawLaunchUrl, normalizedBaseUrl)
207
+ : undefined
208
+ if (!launchUrl && !client.name) return { state: 'no-manifest' }
209
+
210
+ return {
211
+ state: 'resolved',
212
+ bundle: {
213
+ bundleUrl: normalizeNativeDevBundleUrl(
214
+ launchUrl || `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`,
215
+ ),
216
+ port,
217
+ framework: inferManifestFramework(launchUrl, client.sdkVersion),
218
+ projectName: client.name,
219
+ },
220
+ }
221
+ }
222
+
223
+ async function isPackagerRunning(normalizedBaseUrl: string): Promise<boolean> {
224
+ try {
225
+ const res = await fetchDevProbe(`${normalizedBaseUrl}/status`)
226
+ if (!res.ok) return false
227
+ return (await res.text()).includes('packager-status:running')
228
+ } catch {
229
+ return false
230
+ }
231
+ }
232
+
134
233
  async function probeBaseUrlBundleDirect(
135
234
  baseUrl: string,
136
235
  port: number,
137
236
  ): Promise<ResolvedDevBundle | null> {
138
237
  const normalizedBaseUrl = baseUrl.replace(/\/+$/, '')
139
238
 
140
- try {
141
- const manifestRes = await fetchDevProbe(`${normalizedBaseUrl}/`, {
142
- headers: { 'expo-platform': 'ios' },
143
- })
144
- if (manifestRes.ok) {
145
- const manifest = await manifestRes.json()
146
- const client = manifest?.extra?.expoClient || manifest?.extra || {}
147
- const rawLaunchUrl =
148
- typeof manifest?.launchAsset?.url === 'string'
149
- ? manifest.launchAsset.url
150
- : undefined
151
- const launchUrl = rawLaunchUrl
152
- ? alignLoopbackBundleUrlWithProbe(rawLaunchUrl, normalizedBaseUrl)
153
- : undefined
154
- if (launchUrl || client.name) {
155
- return {
156
- bundleUrl: normalizeNativeDevBundleUrl(
157
- launchUrl || `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`,
158
- ),
159
- port,
160
- framework: inferManifestFramework(launchUrl, client.sdkVersion),
161
- projectName: client.name,
162
- }
163
- }
239
+ let manifest = await probeExpoManifest(normalizedBaseUrl, port)
240
+ let packagerConfirmed = false
241
+
242
+ // nothing answered `/`. that is either a closed address — the other loopback
243
+ // family, a dead port — or a packager whose manifest middleware has not come
244
+ // up yet. `/status` separates them, and only the second is worth waiting on.
245
+ if (manifest.state === 'no-answer') {
246
+ packagerConfirmed = await isPackagerRunning(normalizedBaseUrl)
247
+ if (!packagerConfirmed) return null
248
+ const deadline = Date.now() + MANIFEST_BOOT_BUDGET_MS
249
+ while (manifest.state === 'no-answer' && Date.now() < deadline) {
250
+ await new Promise((resolve) => setTimeout(resolve, MANIFEST_BOOT_RETRY_MS))
251
+ manifest = await probeExpoManifest(normalizedBaseUrl, port)
164
252
  }
165
- } catch {}
253
+ }
254
+
255
+ if (manifest.state === 'resolved') return manifest.bundle
256
+ // a server that never says what it is gets no guessed entry point.
257
+ if (manifest.state === 'no-answer') return null
166
258
 
167
259
  // vanilla Metro (or any non-Expo dev server) — packager-status:running on
168
260
  // /status is the canonical signature. we previously also did `HEAD
@@ -176,21 +268,12 @@ async function probeBaseUrlBundleDirect(
176
268
  // the Expo manifest probe above already returns the correct launchAsset.url
177
269
  // for One apps (which serve the Expo manifest format via vxrn), so we
178
270
  // drop the bespoke One probe entirely.
179
- try {
180
- const statusRes = await fetchDevProbe(`${normalizedBaseUrl}/status`)
181
- if (statusRes.ok) {
182
- const text = await statusRes.text()
183
- if (text.includes('packager-status:running')) {
184
- return {
185
- bundleUrl: `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`,
186
- port,
187
- framework: 'metro',
188
- }
189
- }
190
- }
191
- } catch {}
192
-
193
- return null
271
+ if (!packagerConfirmed && !(await isPackagerRunning(normalizedBaseUrl))) return null
272
+ return {
273
+ bundleUrl: `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`,
274
+ port,
275
+ framework: 'metro',
276
+ }
194
277
  }
195
278
 
196
279
  async function probeBaseUrlBundle(
@@ -8,6 +8,17 @@ const AUTOMATIC_CLEANUP_GENERATION = 1
8
8
  const AUTOMATIC_CLEANUP_COMPLETE_FILE = `automatic-cleanup-v${AUTOMATIC_CLEANUP_GENERATION}.json`
9
9
  const AUTOMATIC_CLEANUP_LOCK_FILE = `automatic-cleanup-v${AUTOMATIC_CLEANUP_GENERATION}.lock`
10
10
  const AUTOMATIC_CLEANUP_LOCK_STALE_MS = 6 * 60 * 60 * 1000
11
+ // a deferral is recorded so the retry does not happen on literally every
12
+ // command. cleanup defers whenever anything is in use, and on a machine that
13
+ // always has a sim or daemon running that is the permanent state: the complete
14
+ // marker is never written, so every rnx invocation spawned a detached worker
15
+ // that rescanned the home directory, reclaimed nothing, and printed the same
16
+ // "N is in use and will be retried on a later run" line into the caller's
17
+ // stderr. measured on this machine: an identical 662.2 MiB across every
18
+ // invocation over several hours. the retry itself is right, its cadence was
19
+ // not, so it is throttled rather than removed.
20
+ const AUTOMATIC_CLEANUP_DEFERRED_FILE = `automatic-cleanup-v${AUTOMATIC_CLEANUP_GENERATION}.deferred.json`
21
+ const AUTOMATIC_CLEANUP_DEFER_RETRY_MS = 30 * 60 * 1000
11
22
 
12
23
  export type SootsimCleanupKind =
13
24
  | 'browser-cache'
@@ -65,6 +76,26 @@ export function isAutomaticSootsimCleanupComplete(): boolean {
65
76
  }
66
77
  }
67
78
 
79
+ // what the CLI asks before spawning a worker: is there anything for one to do
80
+ // right now. complete means never again; a recent deferral means not yet.
81
+ export function shouldSkipAutomaticSootsimCleanup(now = Date.now()): boolean {
82
+ if (isAutomaticSootsimCleanupComplete()) return true
83
+ const deferredPath = path.join(sootsimHomeDir(), AUTOMATIC_CLEANUP_DEFERRED_FILE)
84
+ try {
85
+ const parsed = JSON.parse(fs.readFileSync(deferredPath, 'utf8')) as {
86
+ generation?: unknown
87
+ attemptedAt?: unknown
88
+ }
89
+ if (parsed.generation !== AUTOMATIC_CLEANUP_GENERATION) return false
90
+ if (typeof parsed.attemptedAt !== 'number') return false
91
+ // a clock that moved backwards must not park cleanup forever
92
+ const age = now - parsed.attemptedAt
93
+ return age >= 0 && age < AUTOMATIC_CLEANUP_DEFER_RETRY_MS
94
+ } catch {
95
+ return false
96
+ }
97
+ }
98
+
68
99
  export function formatSootsimBytes(bytes: number): string {
69
100
  if (bytes < 1024) return `${bytes} B`
70
101
  const units = ['KiB', 'MiB', 'GiB', 'TiB']
@@ -358,6 +389,7 @@ export function applyAutomaticSootsimCleanup(): AutomaticSootsimCleanupResult {
358
389
  ensureSootsimHome()
359
390
  const home = sootsimHomeDir()
360
391
  const completePath = path.join(home, AUTOMATIC_CLEANUP_COMPLETE_FILE)
392
+ const deferredPath = path.join(home, AUTOMATIC_CLEANUP_DEFERRED_FILE)
361
393
  const lockPath = path.join(home, AUTOMATIC_CLEANUP_LOCK_FILE)
362
394
 
363
395
  if (isAutomaticSootsimCleanupComplete()) {
@@ -462,6 +494,17 @@ export function applyAutomaticSootsimCleanup(): AutomaticSootsimCleanupResult {
462
494
  0,
463
495
  )
464
496
  if (deferredInUseBytes > 0) {
497
+ const deferredTmp = `${deferredPath}.${process.pid}.tmp`
498
+ fs.writeFileSync(
499
+ deferredTmp,
500
+ `${JSON.stringify({
501
+ generation: AUTOMATIC_CLEANUP_GENERATION,
502
+ attemptedAt: Date.now(),
503
+ deferredInUseBytes,
504
+ })}\n`,
505
+ 'utf8',
506
+ )
507
+ fs.renameSync(deferredTmp, deferredPath)
465
508
  return {
466
509
  status: 'deferred',
467
510
  reclaimedBytes: result.reclaimedBytes,
@@ -481,6 +524,7 @@ export function applyAutomaticSootsimCleanup(): AutomaticSootsimCleanupResult {
481
524
  'utf8',
482
525
  )
483
526
  fs.renameSync(tmp, completePath)
527
+ fs.rmSync(deferredPath, { force: true })
484
528
  return {
485
529
  status: 'complete',
486
530
  reclaimedBytes: result.reclaimedBytes,
@@ -49,6 +49,7 @@ import {
49
49
  isFetchProxyRequestUrl,
50
50
  } from './fetch-proxy-handler.ts'
51
51
  import { openUrl as openUrlInBrowser, type OpenUrlOptions } from './open-url.ts'
52
+ import { PlaneHost } from './plane-host'
52
53
  import {
53
54
  handleReplacementModuleRequest,
54
55
  isReplacementModuleRequestUrl,
@@ -389,6 +390,7 @@ export class SootSimBridgeHost {
389
390
  private nextCliFallbackId = 1
390
391
  private cliIdleTimer: NodeJS.Timeout | null = null
391
392
  private agentHost: AgentHost
393
+ private planeHost = new PlaneHost()
392
394
  private static CLI_IDLE_TIMEOUT_MS = 60_000
393
395
  private static CLI_LEASE_TTL_MS = 600_000
394
396
  private static USER_ACTIVE_LEASE_TTL_MS = 8_000
@@ -670,6 +672,14 @@ export class SootSimBridgeHost {
670
672
  return
671
673
  }
672
674
 
675
+ // plane:* is the project file plane, routed the same way and for the
676
+ // same reason: the CLI, a box, and a browser tab all speak one
677
+ // envelope. see plans/rnx-cloud/transport-decision.md.
678
+ if (typeof msg.type === 'string' && msg.type.startsWith('plane:')) {
679
+ void this.planeHost.handleMessage(ws, msg)
680
+ return
681
+ }
682
+
673
683
  // runtime:* messages manage installed engine runtimes. list / use
674
684
  // are handled in-daemon; install runs entirely inside the CLI so
675
685
  // we don't need a daemon-side handler for it.
@@ -1068,6 +1078,7 @@ export class SootSimBridgeHost {
1068
1078
  // always drop agent subscriptions first — the FIFO refcount needs
1069
1079
  // to settle before any later broadcast fan-out fires.
1070
1080
  this.agentHost.unregisterSocket(ws)
1081
+ this.planeHost.unregisterSocket(ws)
1071
1082
  if (role === 'sim' && sim) {
1072
1083
  this.rememberDisconnectedSim(sim)
1073
1084
  if (this.primarySimId === sim.id) {
@@ -0,0 +1,203 @@
1
+ // `plane:*` — the project file plane over the loopback bridge, so a browser
2
+ // tab can reach a real local box. the envelope and its constraints are decided
3
+ // in plans/rnx-cloud/transport-decision.md; this is the local half.
4
+ //
5
+ // the vocabulary is exactly ProjectFilePlane's members, because the point is
6
+ // that a remote plane is a third provider behind that seam rather than a
7
+ // second file API. it is remotable without changing the interface because
8
+ // `index()` is synchronous but `refresh()` is the async step the contract
9
+ // already requires before an index read: a remote plane refreshes into a local
10
+ // cache and reads that.
11
+ //
12
+ // WHY A ROOT MUST BE REGISTERED FIRST. this listener is loopback-only, but a
13
+ // WebSocket to 127.0.0.1 is not subject to CORS, so any page the user visits
14
+ // can open one. if `plane:open` took an arbitrary path, that page could read
15
+ // any file on the machine through this daemon. a root is reachable only while
16
+ // a box has registered it, and the registration dies with its socket.
17
+
18
+ import fs from 'node:fs'
19
+ import path from 'node:path'
20
+ import { dispatchPlaneCommand, indexVersion } from '@contrast/harness/plane'
21
+ import { CheckoutFilePlane } from '../../cli/commands/box/checkout-plane'
22
+ import type { ProjectFilePlane } from '@contrast/harness/plane'
23
+ import type { WebSocket } from 'ws'
24
+
25
+ const WS_OPEN = 1
26
+
27
+ interface OpenPlane {
28
+ root: string
29
+ plane: ProjectFilePlane
30
+ version: string
31
+ sockets: Set<WebSocket>
32
+ }
33
+
34
+ export class PlaneNotRegisteredError extends Error {}
35
+
36
+ export class PlaneHost {
37
+ // roots a box authorized, each tied to the socket that authorized it
38
+ private registered = new Map<string, Set<WebSocket>>()
39
+ private open = new Map<string, OpenPlane>()
40
+ private byRoot = new Map<string, string>()
41
+ private nextPlaneId = 1
42
+
43
+ /** handle a plane:* message. returns true iff it was one. */
44
+ async handleMessage(ws: WebSocket, msg: unknown): Promise<boolean> {
45
+ if (typeof msg !== 'object' || msg === null) return false
46
+ const record: Record<string, unknown> = { ...msg }
47
+ const type = record.type
48
+ if (typeof type !== 'string' || !type.startsWith('plane:')) return false
49
+ const id = record.id
50
+ try {
51
+ this.respond(ws, id, await this.dispatch(ws, type, record))
52
+ } catch (err) {
53
+ const code =
54
+ err instanceof PlaneNotRegisteredError ? 'plane-not-registered' : undefined
55
+ this.respondError(ws, id, err instanceof Error ? err.message : String(err), code)
56
+ }
57
+ return true
58
+ }
59
+
60
+ unregisterSocket(ws: WebSocket): void {
61
+ for (const [root, sockets] of [...this.registered]) {
62
+ if (!sockets.delete(ws)) continue
63
+ if (sockets.size > 0) continue
64
+ // the box that authorized this root is gone, so drop the plane with it
65
+ // rather than leaving a reachable handle behind.
66
+ this.registered.delete(root)
67
+ const planeId = this.byRoot.get(root)
68
+ if (planeId) {
69
+ this.open.delete(planeId)
70
+ this.byRoot.delete(root)
71
+ }
72
+ }
73
+ for (const [planeId, entry] of [...this.open]) {
74
+ entry.sockets.delete(ws)
75
+ if (entry.sockets.size === 0 && !this.registered.has(entry.root)) {
76
+ this.open.delete(planeId)
77
+ this.byRoot.delete(entry.root)
78
+ }
79
+ }
80
+ }
81
+
82
+ /** roots currently reachable, for the daemon's status output. */
83
+ registeredRoots(): string[] {
84
+ return [...this.registered.keys()]
85
+ }
86
+
87
+ private async dispatch(
88
+ ws: WebSocket,
89
+ type: string,
90
+ msg: Record<string, unknown>,
91
+ ): Promise<unknown> {
92
+ switch (type) {
93
+ case 'plane:register': {
94
+ const root = this.realRoot(String(msg.root ?? ''))
95
+ const sockets = this.registered.get(root) ?? new Set<WebSocket>()
96
+ sockets.add(ws)
97
+ this.registered.set(root, sockets)
98
+ // `holders` INCLUDING this one, because two boxes over one checkout is
99
+ // a mistake only the daemon can see: CheckoutFilePlane re-runs
100
+ // `git ls-files` before every command, so each box changes the file
101
+ // set the other is working from mid-run. the daemon reports it rather
102
+ // than refusing, because a box whose socket dropped and reconnected
103
+ // can briefly race its own stale entry, and a refusal there would
104
+ // brick a legitimate restart. the caller decides; see box.ts, which
105
+ // already refuses a box inside a box for the same reason.
106
+ return { root, holders: sockets.size }
107
+ }
108
+ // READ ONLY, and that is the whole point of it existing beside the
109
+ // `holders` field on plane:register.
110
+ //
111
+ // registration is the AUTHORIZATION step: it is what permits any page on
112
+ // this machine to open that root over a loopback socket that CORS does
113
+ // not protect. so a caller asking "is anyone else in this checkout"
114
+ // cannot be made to authorize the root in order to find out, even
115
+ // briefly. it also means the count is the honest one: no box reads 0 and
116
+ // a single box reads 1, where asking through register would have made
117
+ // every answer one higher and forced a threshold that counts the asker.
118
+ case 'plane:status': {
119
+ const root = this.realRoot(String(msg.root ?? ''))
120
+ const sockets = this.registered.get(root)
121
+ return { root, holders: sockets?.size ?? 0, registered: Boolean(sockets) }
122
+ }
123
+ case 'plane:open': {
124
+ const root = this.realRoot(String(msg.root ?? ''))
125
+ if (!this.registered.has(root)) {
126
+ throw new PlaneNotRegisteredError(
127
+ `no box has registered ${root}; start one with \`rnx box\` there`,
128
+ )
129
+ }
130
+ const existingId = this.byRoot.get(root)
131
+ const existing = existingId ? this.open.get(existingId) : undefined
132
+ if (existingId && existing) {
133
+ existing.sockets.add(ws)
134
+ return { planeId: existingId, version: existing.version }
135
+ }
136
+ const plane = new CheckoutFilePlane(root)
137
+ await plane.refresh()
138
+ const planeId = `plane-${this.nextPlaneId++}`
139
+ const entry: OpenPlane = {
140
+ root,
141
+ plane,
142
+ version: indexVersion(plane.index()),
143
+ sockets: new Set([ws]),
144
+ }
145
+ this.open.set(planeId, entry)
146
+ this.byRoot.set(root, planeId)
147
+ return { planeId, version: entry.version }
148
+ }
149
+ case 'plane:close': {
150
+ const entry = this.open.get(String(msg.planeId ?? ''))
151
+ if (entry) entry.sockets.delete(ws)
152
+ return { ok: true }
153
+ }
154
+ default: {
155
+ const entry = this.entry(msg)
156
+ const handled = await dispatchPlaneCommand(entry.plane, type, msg)
157
+ if (!handled) throw new Error(`unknown plane command: ${type}`)
158
+ // no companion change event on a write. the write lands on the real
159
+ // checkout and the dev server's own watcher sees it, so a notification
160
+ // here would be a second channel for something the filesystem already
161
+ // reports. the cloud placement, whose store nothing can watch, is where
162
+ // a write has to fan one out.
163
+ if (handled.version) entry.version = handled.version
164
+ return handled.result
165
+ }
166
+ }
167
+ }
168
+
169
+ private entry(msg: Record<string, unknown>): OpenPlane {
170
+ const entry = this.open.get(String(msg.planeId ?? ''))
171
+ if (!entry) throw new Error(`unknown planeId: ${String(msg.planeId)}`)
172
+ return entry
173
+ }
174
+
175
+ // resolve symlinks and relative segments before comparing, so a registered
176
+ // root and an opened one cannot disagree about the same directory.
177
+ private realRoot(root: string): string {
178
+ if (!root) throw new Error('root is required')
179
+ const resolved = path.resolve(root)
180
+ let real: string
181
+ try {
182
+ real = fs.realpathSync(resolved)
183
+ } catch {
184
+ throw new Error(`no such directory: ${resolved}`)
185
+ }
186
+ if (!fs.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`)
187
+ return real
188
+ }
189
+
190
+ private respond(ws: WebSocket, id: unknown, result: unknown): void {
191
+ if (ws.readyState !== WS_OPEN) return
192
+ try {
193
+ ws.send(JSON.stringify({ id, result }))
194
+ } catch {}
195
+ }
196
+
197
+ private respondError(ws: WebSocket, id: unknown, error: string, code?: string): void {
198
+ if (ws.readyState !== WS_OPEN) return
199
+ try {
200
+ ws.send(JSON.stringify({ id, error, ...(code ? { code } : {}) }))
201
+ } catch {}
202
+ }
203
+ }
@@ -1,6 +0,0 @@
1
- /*! rnx v0.1.370 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{b as C}from"./chunk-FA75F34Z.js";import{f as h}from"./chunk-DHYTRCIP.js";import{L as B,T as b,g as S}from"./chunk-U63T6LIQ.js";import o from"node:fs";import c from"node:path";var g=1,k=`automatic-cleanup-v${g}.json`,x=`automatic-cleanup-v${g}.lock`,A=360*60*1e3;function w(){let i=c.join(S(),k);try{return JSON.parse(o.readFileSync(i,"utf8")).generation===g}catch{return!1}}function $(i){if(i<1024)return`${i} B`;let e=["KiB","MiB","GiB","TiB"],n=i/1024,r=e[0];for(let s=1;s<e.length&&n>=1024;s++)n/=1024,r=e[s];return`${n.toFixed(n>=10?1:2)} ${r}`}function p(i){let e;try{e=o.lstatSync(i)}catch{return 0}let n=e.blocks>0?e.blocks*512:e.size;if(!e.isDirectory()||e.isSymbolicLink())return n;let r=n;try{for(let s of o.readdirSync(i))r+=p(c.join(i,s))}catch{}return r}function E(i){for(let e of["SingletonLock","SingletonSocket","lockfile"])try{if(o.lstatSync(c.join(i,e)))return!0}catch{}return!1}function v(i,e){let n;try{n=o.readdirSync(i,{withFileTypes:!0})}catch{return[]}let r=E(e),s=[];for(let t of n){if(!t.isDirectory()||t.isSymbolicLink())continue;let a=c.join(i,t.name);if(C(t.name)){s.push({path:a,bytes:p(a),kind:"browser-cache",state:r?"in-use":"safe",selected:!r,detail:r?"browser profile is open; close it before cleanup":"disposable browser HTTP, bytecode, or GPU cache"});continue}s.push(...v(a,e))}return s}function P(i){let e=c.join(i,"profiles","playwright"),n;try{n=o.readdirSync(e,{withFileTypes:!0})}catch{return[]}return n.flatMap(r=>{if(!r.isDirectory()||r.isSymbolicLink())return[];let s=c.join(e,r.name);return v(s,s)})}function L(i){let e=c.join(i,"electron","userData");return v(e,e)}function R(i,e){let n=c.join(i,"recordings"),r;try{r=o.readdirSync(n,{withFileTypes:!0})}catch{return[]}return r.map(s=>{let t=c.join(n,s.name);return{path:t,bytes:p(t),kind:"recording",state:"aggressive",selected:e,detail:"user-created recording or captured-frame output"}})}function T(i,e){let n=c.join(i,"camera-fixtures"),r;try{r=o.readdirSync(n,{withFileTypes:!0})}catch{return[]}return r.map(s=>{let t=c.join(n,s.name);return{path:t,bytes:p(t),kind:"camera-fixture",state:"aggressive",selected:e,detail:"staged camera fixture video"}})}function U(i){let e=new Set(b()),n=[...e],r=h.planLocalRetention({retainVersions:2,protectVersions:n}),s=h.planLocalRetention({retainVersions:1,protectVersions:n}),t=new Set(r.removeVersions),a=new Set(s.removeVersions),l=new Set([...r.keepVersions,...r.removeVersions,...s.keepVersions,...s.removeVersions]),m=[];for(let u of[...l].sort()){let d=h.product.runtimeDir(u),y="retained",f="retained runtime";e.has(u)&&u!==r.activeVersion?(y="in-use",f="runtime is serving a connected simulator"):t.has(u)?(y="safe",f="inactive runtime outside the two-version rollback window"):a.has(u)?(y="aggressive",f="most recent rollback runtime"):u===r.activeVersion&&(f="active runtime; always protected"),m.push({path:d,bytes:p(d),kind:"runtime-version",state:y,selected:y==="safe"||y==="aggressive"&&i,detail:f})}for(let u of r.removeCacheFiles)m.push({path:u,bytes:p(u),kind:"runtime-archive",state:"safe",selected:!0,detail:"downloaded archive is unnecessary after successful extraction"});return{activeRuntime:r.activeVersion,entries:m}}function D(i={}){let e=i.aggressive===!0,n=S(),r=U(e),s=[...r.entries,...P(n),...L(n),...R(n,e),...T(n,e)].sort((t,a)=>a.bytes-t.bytes||t.path.localeCompare(a.path));return{home:n,activeRuntime:r.activeRuntime,entries:s,reclaimableBytes:s.reduce((t,a)=>t+(a.selected?a.bytes:0),0),protectedBytes:s.reduce((t,a)=>t+(a.selected?0:a.bytes),0),totalBytes:p(n)}}function I(i,e){let n=c.relative(i,e);if(!n||n.startsWith("..")||c.isAbsolute(n))throw new Error(`refusing cleanup target outside the rnx data home: ${e}`)}function V(i={}){let e=D(i),n=i.aggressive===!0?1:2;h.pruneLocalRetention({retainVersions:n,protectVersions:b()});for(let t of e.entries)if(t.selected&&!(t.kind==="runtime-archive"||t.kind==="runtime-version")){if(t.kind==="browser-cache"){let l=c.relative(e.home,t.path).split(c.sep),m=l[0]==="profiles"&&l[1]==="playwright"&&l[2]?c.join(e.home,"profiles","playwright",l[2]):l[0]==="electron"&&l[1]==="userData"?c.join(e.home,"electron","userData"):null;if(m&&E(m)){t.state="in-use",t.selected=!1,t.detail="browser profile opened while cleanup was starting";continue}}I(e.home,t.path),o.rmSync(t.path,{recursive:!0,force:!0})}let r=e.entries.filter(t=>t.selected&&!o.existsSync(t.path)).map(t=>t.path),s=p(e.home);return{...e,removedPaths:r,reclaimedBytes:Math.max(0,e.totalBytes-s),remainingBytes:s}}function M(){B();let i=S(),e=c.join(i,k),n=c.join(i,x);if(w())return{status:"already-complete",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};let r=null;for(let s=0;s<2&&r===null;s++)try{let t=o.openSync(n,"wx");try{o.writeFileSync(t,`${JSON.stringify({pid:process.pid,startedAt:Date.now()})}
5
- `,"utf8"),r=t}catch(a){o.closeSync(t);try{o.unlinkSync(n)}catch{}throw a}}catch(t){if((t instanceof Error&&"code"in t?t.code:null)!=="EEXIST")throw t;let l=0,m=0,u=null;try{u=o.lstatSync(n);let d=JSON.parse(o.readFileSync(n,"utf8"));l=typeof d.pid=="number"?d.pid:0,m=typeof d.startedAt=="number"?d.startedAt:0}catch{}if(l>0&&m>0&&Date.now()-m<A)try{return process.kill(l,0),{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0}}catch{}if(!u)continue;try{let d=o.lstatSync(n);if(d.dev!==u.dev||d.ino!==u.ino)return{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};o.unlinkSync(n)}catch{}}if(r===null)return{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};try{if(w())return{status:"already-complete",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};let s=V(),t=s.entries.reduce((l,m)=>l+(m.state==="in-use"?m.bytes:0),0);if(t>0)return{status:"deferred",reclaimedBytes:s.reclaimedBytes,remainingBytes:s.remainingBytes,deferredInUseBytes:t};let a=`${e}.${process.pid}.tmp`;return o.writeFileSync(a,`${JSON.stringify({generation:g,completedAt:Date.now(),reclaimedBytes:s.reclaimedBytes})}
6
- `,"utf8"),o.renameSync(a,e),{status:"complete",reclaimedBytes:s.reclaimedBytes,remainingBytes:s.remainingBytes,deferredInUseBytes:0}}finally{o.closeSync(r);try{o.unlinkSync(n)}catch{}}}export{w as a,$ as b,D as c,V as d,M as e};
@@ -1,4 +0,0 @@
1
- /*! rnx v0.1.370 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a as i}from"./chunk-6W4HIWC7.js";var c=["ghs_","ghp_","gho_","ghu_","github_pat_"];function p(n){return!!(n&&n.length>=20&&c.some(e=>n.startsWith(e)))}function a(){let n=process.env.CONTRAST_INSTALLATION_TOKEN?.trim(),e=process.env.GITHUB_TOKEN?.trim(),t=n||e;if(!p(t))return null;let r=(process.env.CONTRAST_REPO||process.env.GITHUB_REPOSITORY||"").trim();if(!r)return null;let[o,s]=r.includes("/")?r.split("/",2):[null,null],u=(process.env.CONTRAST_REPO_ID||process.env.GITHUB_REPOSITORY_ID||"").trim(),l=(process.env.CONTRAST_INSTALLATION_ID||process.env.GITHUB_APP_INSTALLATION_ID||"").trim();return{kind:"github",token:t,repoId:r,repositoryId:u||null,owner:o||null,repo:s||null,installationId:l||null,source:n?"contrast-runner":"github-actions"}}function d(n){return n.startsWith("sk_rnx_")||n.startsWith("sk_sootsim_")}function I(){for(let n of["RNX_API_KEY","SOOTSIM_API_KEY"]){let e=process.env[n]?.trim();if(e&&d(e))return{secret:e,envName:n}}return null}function h(){let n=I();if(n)return{kind:"api-key",secret:n.secret,source:"env",envName:n.envName};let e=a();if(e)return e;let t=i();return t?.token?{kind:"session",token:t.token,origin:t.origin}:null}function T(n){return n.kind==="api-key"?`Bearer ${n.secret}`:`Bearer ${n.token}`}function k(n){return!n||n.kind!=="github"?null:{repoId:n.repoId,owner:n.owner??void 0,repo:n.repo??void 0,installationId:n.installationId}}export{h as a,T as b,k as c};
@@ -1,7 +0,0 @@
1
- /*! rnx v0.1.370 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a as fe,b as ze}from"./chunk-6S5LJV2O.js";import{e as rt}from"./chunk-DMHSD6YJ.js";import{c as Ve}from"./chunk-PAUEZO6F.js";import{a as Ze,b as et,d as ot}from"./chunk-6A6L3VJR.js";import{a as Ne,c as Fe,d as k,e as ue,f as L,g as me,h as je,i as pe,j as He,k as We,m as Je,n as Ye,o as Xe}from"./chunk-3BG6UCQY.js";import{m as A}from"./chunk-NR2V2ONN.js";import{a as Ke,b as qe}from"./chunk-D2GZASRV.js";import{h as tt,p as nt}from"./chunk-AALKIAUZ.js";import{a as Qe}from"./chunk-WFQHT4QD.js";import{a as Ge}from"./chunk-EQ3OE2AV.js";import{b as le,e as Oe}from"./chunk-CMVRTZ5G.js";import{b as Be,f as _e,g as _,h as P,i as D,n as De,o as ce,p as de,r as Le,s as Ae,t as E,u as I,v as T}from"./chunk-EOIBLKZO.js";import{b as z,c as u}from"./chunk-AVJBT5LF.js";import{f as Me}from"./chunk-DHYTRCIP.js";import{a as Te}from"./chunk-IDLFVRPN.js";import{D as Re,M as se,P as ae,R as B,T as Ee,l as ie}from"./chunk-U63T6LIQ.js";import{a as oe}from"./chunk-64JAEJ6N.js";import{spawn as dt,spawnSync as ut}from"node:child_process";import M from"node:fs";import Nt from"node:os";import U from"node:path";import{WebSocket as ge}from"ws";function it(e){return new Error(`could not resolve a native bundle for ${e}. pass an explicit bundle URL or open Connect and choose the app there.`)}function Mt(e,n){return e?.includes("/one/metro-entry.bundle")?"one":typeof n=="string"&&n?"expo":"unknown"}function Ot(e,n,t){return`${e}//${n}:${t}`}function Bt(e){if(typeof window>"u")return!1;try{let n=new URL(e);return k(n.hostname)&&k(window.location.hostname)&&n.origin!==window.location.origin}catch{return!1}}async function st(e,n){let t={...n,cache:n?.cache??"no-store"};return Bt(e)?fetch(`/__fetch-proxy?url=${encodeURIComponent(e)}`,t):fetch(e,t)}function _t(e){return e==="https:"?443:80}function Dt(e){let n=e.pathname||"/";return(n==="/"||n==="")&&!e.search&&!e.hash}async function at(e){try{let n=await fetch("/__server-scan",{cache:"no-store"});if(!n.ok||!(n.headers.get("content-type")||"").toLowerCase().includes("json"))return null;let t=await n.json();if(!Array.isArray(t))return null;let r=t.find(o=>!!o&&typeof o=="object"&&o.port===e&&typeof o.bundleUrl=="string");return r?{bundleUrl:pe(r.bundleUrl),port:e,framework:typeof r.framework=="string"?r.framework:"unknown",projectName:typeof r.projectName=="string"?r.projectName:void 0}:null}catch{return null}}async function lt(e,n){let t=e.replace(/\/+$/,"");try{let r=await st(`${t}/`,{headers:{"expo-platform":"ios"}});if(r.ok){let o=await r.json(),i=o?.extra?.expoClient||o?.extra||{},a=typeof o?.launchAsset?.url=="string"?o.launchAsset.url:void 0,s=a?je(a,t):void 0;if(s||i.name)return{bundleUrl:pe(s||`${t}${me}`),port:n,framework:Mt(s,i.sdkVersion),projectName:i.name}}}catch{}try{let r=await st(`${t}/status`);if(r.ok&&(await r.text()).includes("packager-status:running"))return{bundleUrl:`${t}${me}`,port:n,framework:"metro"}}catch{}return null}async function Lt(e,n){try{if(k(new URL(e).hostname)){let t=await at(n);if(t)return t}}catch{}return lt(e,n)}async function At(e){let n=await at(e);return n||((await Promise.all(Ne.map(r=>lt(Fe("http:",r,e),e)))).find(r=>r!==null)??null)}async function ct(e){let n=e.trim();if(/^\d+$/.test(n)){let s=parseInt(n,10),l=await At(s);if(l)return l;throw it(`localhost:${s}`)}let t=n.startsWith("http")?n:`http://${n}`,r;try{r=new URL(t)}catch{throw new Error(`could not parse "${e}". pass a dev-server port, a dev-server base URL, or a full bundle URL.`)}let o=r.protocol||"http:",i=r.port?parseInt(r.port,10):_t(o),a=Ot(o,r.hostname,i);if(Dt(r)){let s=await Lt(a,i);if(s)return s;throw it(a)}return{bundleUrl:r.toString(),port:i,framework:"unknown"}}var Ft=12e4,mt=100,jt=5e3,pt=1e4,Ht={rn:"/rn",connectrn:"/rn","connect-rn":"/rn",clock:"/app/clock","native-ui":"/app/native-ui",tamagui:"/app/tamagui",settings:"/app/settings",photos:"/app/photos",camera:"/app/camera"};function $(e){return new Promise(n=>setTimeout(n,e))}function ft(e){let n=process.env[e]?.trim();if(!n)return null;let t=Number(n);return Number.isInteger(t)&&t>0?t:null}function Wt(){let e=ft("SOOTSIM_DRIVER_CONNECT_TIMEOUT_MS")??ft("SOOTSIM_PW_CONNECT_TIMEOUT_MS")??Ft;return{timeoutMs:e,hostTimeoutMs:e+jt,intervalMs:mt,attempts:Math.max(1,Math.ceil(e/mt))}}function gt(e){return e==="electron"||e==="playwright"}function he(e,n){return n==="playwright"?e.meta?.sootsimHostDriver==="playwright":e.userAgent?.includes("Electron/")===!0}function Kt(e,n){return e.includes("--headless")?!0:e.includes("--headed")?!1:n==="playwright"&&process.platform==="linux"&&!process.env.DISPLAY&&!process.env.WAYLAND_DISPLAY?(console.error(" no display detected \u2192 running playwright headless (override with --headed)"),!0):!1}function Q(e){return e.trim()}async function qt(e,n=!1){let t=ae();ht(e,n,t);let r=ce(e);if((n||r!==null)&&await we(e,250))return e;if(t&&B(t)&&await we(t.bridgePort,500))return t.bridgePort;if(t&&B(t))throw new Error(`rnx bridge lockfile is fresh (port ${t.bridgePort}) but the bridge is not reachable. run \`rnx daemon restart\` or \`rnx daemon uninstall\`.`);await Vt();let o=zt(["serve","--quiet","--port",String(e)]),i=null;o.once("exit",(s,l)=>{i=String(s??l??"unknown")}),o.unref();let a=Date.now()+pt;for(;Date.now()<a;){let s=ae();if(ht(e,n,s),s&&B(s)&&await we(s.bridgePort,250))return console.error(` Started a local bridge on port ${s.bridgePort}. Run \`rnx daemon install\` to keep it ready between commands.`),s.bridgePort;if(i)throw new Error(`rnx bridge exited before becoming ready (exit ${i})`);await $(150)}throw new Error(`rnx bridge did not start within ${Math.round(pt/1e3)}s`)}function ht(e,n,t){if(!(!n||!t||!B(t)||t.bridgePort===e))throw new Error(`${oe.commandName} open: requested bridge port ${e}, but the active daemon owns port ${t.bridgePort}. explicit --port never selects another bridge; stop that daemon or use an isolated SOOTSIM_HOME.`)}async function Vt(){let e=se();if(e&&M.existsSync(ie(e)))return;console.error(" installing rnx engine runtime...");let{runRuntime:n}=await import("./runtime-MZHLSRS6.js");await n(["install"],{})}function zt(e){let n=process.argv[1];return n&&M.existsSync(n)?dt(process.execPath,[n,...e],{detached:!0,stdio:"ignore",env:process.env}):dt(oe.commandName,e,{detached:!0,stdio:"ignore",env:process.env})}function we(e,n){return new Promise(t=>{let r=new ge(`ws://127.0.0.1:${e}`,{handshakeTimeout:n}),o=!1,i=a=>{o||(o=!0,r.readyState===ge.OPEN?r.close():r.readyState===ge.CONNECTING&&r.terminate(),t(a))};r.once("open",()=>i(!0)),r.on("error",()=>i(!1)),setTimeout(()=>i(!1),n)})}function ve(e){try{let n=new URL(e),t=n.pathname.replace(/\/+$/,"")||"/";return n.searchParams.has("open")||n.searchParams.has("port")||n.searchParams.has("bundle")||n.searchParams.has("demo")||n.pathname.includes("/sootsim/index.html")||t==="/sootsim"||n.pathname==="/__soot"||n.pathname==="/__soot/"||t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function Gt(e){try{let n=new URL(e,"http://sootsim.local");if(n.origin!=="http://sootsim.local")return!1;let t=n.pathname.replace(/\/+$/,"")||"/";return t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function Qt(e,n){let t=new URL(e,"http://sootsim.local"),r=new URL(n),o=J(r.pathname),i=t.pathname.startsWith("/__soot/")?t.pathname.slice(7):t.pathname;return r.pathname=`${o}${i}`,r.search=t.search,r.hash=t.hash,r.toString()}function Jt(e){try{let n=new URL(e).pathname.replace(/\/+$/,"")||"/";return/^\/preview\/[^/]+$/.test(n)||/^\/build\/.+/.test(n)}catch{return!1}}async function ar(e){let n=Q(e);return(await Se(n)).bundleUrl}function Yt(e){try{let n=new URL(e.startsWith("http")?e:`http://${e}`),t=n.pathname||"/";if(t!=="/"&&t!==""||n.search||n.hash||!k(n.hostname))return null;let r=n.port?Number(n.port):n.protocol==="https:"?443:80;return Number.isFinite(r)&&r>0?r:null}catch{return null}}async function Se(e){let n=Q(e),t=/^\d+$/.test(n)?Number(n):Yt(n);if(t&&t>0){let r=await We(t);if(r)return{bundleUrl:r.bundleUrl,port:r.port,framework:r.framework,projectName:r.projectName}}return ct(n)}function J(e){let n=e.replace(/\/+$/,"")||"/";return n==="/__soot"||n.startsWith("/__soot/")?"/__soot":""}function Xt(e,n){let t=Q(e),r=new URL(n),o=J(r.pathname);return r.pathname=`${o}/rn`,r.searchParams.delete("bundle"),r.searchParams.delete("demo"),r.searchParams.delete("app"),r.searchParams.delete("open"),r.searchParams.delete("port"),/^\d+$/.test(t)?r.pathname=`${o}/rn/${t}`:(r.pathname=`${o}/rn`,r.searchParams.set("open",t)),r.toString()}function $t(e){let n=Q(e);return/^\d+$/.test(n)||/^https?:\/\//i.test(n)?!0:/^(localhost|127\.0\.0\.1|\[::1\]|[^/]+\.localhost):\d+(?:\/.*)?$/i.test(n)}async function Zt(e,n,t={}){let r=t.resolvedBundle??await Se(e),o=new URL(n),i=J(o.pathname);o.pathname=`${i}/rn`,o.searchParams.delete("open"),o.searchParams.delete("port"),o.searchParams.delete("demo"),o.searchParams.delete("app");let a=t.hot===void 0?r.bundleUrl:He(r.bundleUrl,t.hot);return o.searchParams.set("bundle",a),o.toString()}function en(e){return e.startsWith("~/")?U.join(Nt.homedir(),e.slice(2)):U.isAbsolute(e)?e:U.resolve(process.cwd(),e)}function tn(e){let n={},t={};for(let o=0;o<e.length;o++){if(e[o]==="--replace"){let i=e[o+1];i||(console.error(" rnx open: --replace expects <module>=<file>"),u(1));let a=i.indexOf("=");(a<=0||a===i.length-1)&&(console.error(" rnx open: --replace expects <module>=<file>"),u(1));let s=i.slice(0,a).trim(),l=en(i.slice(a+1).trim());M.existsSync(l)||(console.error(` rnx open: replacement file not found: ${l}`),u(1)),n[s]={file:l},o++;continue}if(e[o]==="--remap"){let i=e[o+1],a=i?i.indexOf("="):-1;(!i||a<=0||a===i.length-1)&&(console.error(" rnx open: --remap expects <host:port>=<host:port>"),u(1)),t[i.slice(0,a).trim()]=i.slice(a+1).trim(),o++;continue}}let r={};return Object.keys(n).length>0&&(r.modules=n),Object.keys(t).length>0&&(r.network={remap:t}),r.modules||r.network?r:void 0}async function nn(e){if(!e)return null;let n=await Ye(e.bundleUrl);return n?Ge(n):null}async function rn(e){if(M.existsSync(U.join(ie(e),"index.html")))return;console.error(` installing configured engine runtime ${e}...`);let n=await Me.install({version:e,setActive:!1,protectVersions:Ee()});console.error(` installed engine runtime ${n.version}`)}function on(e,n){let t=n??(fe()?void 0:se()??void 0);if(!t)return e;let r=new URL(e);if(!k(r.hostname)){if(!n)return e;throw new Error(`runtimeVersion ${t} requires a local rnx host; got ${r.origin}`)}return r.hostname=ze(t),r.toString()}function xt(){return De().shellBaseUrl}function sn(e){return ce(e)?.shellBaseUrl??Be(e)??xt()}async function an(e,n){try{let t=new URL(e),r=t.searchParams.get("bundle")||"";if(!r||!n)return e;let o=Je({bundleUrl:r,projectDir:n.appDir});if(o.length===0)return e;let i=await ln(o);return i.length===0?e:(t.searchParams.set("appFonts",Xe(i)),t.toString())}catch{return e}}async function ln(e){let n=await Promise.all(e.map(async r=>{let o=new AbortController,i=setTimeout(()=>o.abort(),1500);try{let a=await fetch(r.url,{method:"HEAD",signal:o.signal});return a.status>=200&&a.status<400?r:null}catch{return null}finally{clearTimeout(i)}})),t=[];for(let r of n)r!==null&&t.push(r);return t}async function cn(e,n,t={}){if(!e)return new URL(n).toString();if(ve(e))return new URL(e).toString();if(Gt(e))return Qt(e,n);let r=Ht[e.toLowerCase()];if(r){let o=new URL(n),i=J(o.pathname);return o.pathname=`${i}${r}`,o.toString()}return $t(e)?Zt(e,n,t):Xt(e,n)}async function dn(e,n){try{let t=new URL(e),r=t.searchParams.get("bundle")||"";if(!r||!n)return e;let o=Ze({bundleUrl:r,projectDir:n.appDir});return!o||o.imageUrl&&!await un(o.imageUrl)?e:(t.searchParams.set("appSplash",et(o)),t.toString())}catch{return e}}async function un(e){let n=new AbortController,t=setTimeout(()=>n.abort(),1500);try{let r=await fetch(e,{method:"HEAD",signal:n.signal});return r.status>=200&&r.status<400}catch{return!1}finally{clearTimeout(t)}}async function G(e,n=xt(),t={}){let r=await cn(e,n,t),o=await dn(await an(r,t.project),t.project);if(!t.device)return o;let i=new URL(o);return i.searchParams.set("device",t.device),i.toString()}function wt(e,n){let t=e?.url||e?.origin||n;try{let r=new URL(t);return r.searchParams.delete("bundle"),r.searchParams.delete("demo"),r.searchParams.delete("app"),r.searchParams.delete("open"),r.searchParams.delete("port"),r.searchParams.delete("inspectOpen"),r.searchParams.delete("appFonts"),r.searchParams.delete("appSplash"),r.toString()}catch{return n}}async function mn(e,n,t,r={}){let o=new URL(await G(e,n,r));return o.searchParams.set("inspectOpen",t),o.toString()}async function pn(e,n,t,r={}){let o=r.attempts??30,i=r.intervalMs??500,a=r.minNodeCount??10;for(let s=0;s<o;s++){let l=I(e,{commandTimeoutMs:n,simId:t,simIdSource:"flag"});try{let d=await l.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount()) || 0)()"});if(typeof d=="number"&&d>a)return{bridge:l,count:d}}catch{}l.close(),await $(i)}return null}function fn(e){if(!e)return null;try{let n=new URL(e);if(n.searchParams.has("bundle")){let t=n.searchParams.get("bundle")||"";try{let r=new URL(t),o=r.pathname.length>36?`...${r.pathname.slice(-36)}`:r.pathname;return`bundle ${r.host}${o}`}catch{return"bundle"}}return n.searchParams.has("port")?`connect :${n.searchParams.get("port")||""}`:n.searchParams.has("open")?`connect ${n.searchParams.get("open")||""}`:n.searchParams.has("demo")?`demo ${n.searchParams.get("demo")||"default"}`:n.pathname.includes("/sootsim/index.html")||n.pathname==="/sootsim/"||n.pathname==="/sootsim"?"embedded rnx":null}catch{return null}}function gn(e){let n=e.indexOf(":");if(n<=0)return e.length>24?`${e.slice(0,21)}\u2026`:e;let t=e.slice(0,n),r=e.slice(n+1),o=r.length>12?`${r.slice(0,8)}\u2026`:r;return t==="TM_SESSION"||t==="CLAUDE_CODE_SESSION_ID"||t==="CODEX_THREAD_ID"?`agent ${o}`:`${t} ${o}`}function lr(e,n){if(e.length===0){console.log(" no sims connected");return}console.log(` connected sims (${e.length}):
5
- `);for(let t of e){let r=t.lockedBy&&t.lockExpiresAt?`locked by ${gn(t.lockedBy)} (${Math.max(0,Math.round((t.lockExpiresAt-Date.now())/1e3))}s)`:"",o=[t.isPrimary?"primary":"",t.id===n?"selected":"",t.readyState,t.userVisible===!1?"hidden":t.userVisible===!0?"visible":"",t.attachedCliCount&&t.attachedCliCount>0?"in use":"",t.userFocused?"focused":"",r].filter(Boolean);console.log(` ${t.id}${o.length?` [${o.join(", ")}]`:""}`);let i=fn(t.url);if(i)console.log(` loaded: ${i}`);else if(t.url){let s=t.url.length>96?`${t.url.slice(0,93)}\u2026`:t.url;console.log(` url: ${s}`)}else t.origin&&console.log(` origin: ${t.origin}`);let a=hn(t);a&&console.log(` engine: ${a}`),t.title&&console.log(` title: ${t.title}`),t.visibilityState&&t.visibilityState!=="visible"&&console.log(` visibility: ${t.visibilityState}`),console.log(` connected: ${bt(Date.now()-t.connectedAt)}`),t.lastActiveAt&&t.lastActiveAt>0&&console.log(` last active: ${bt(Date.now()-t.lastActiveAt)}`)}}function hn(e){let n=e.url||e.origin||"";if(!n)return null;try{let t=new URL(n).port;return t==="5173"?"dev \u2014 local source (:5173)":t==="3000"?"Contrast app embedded (:3000)":fe()?`dev \u2014 local build (:${t||"?"})`:`runtime \u2014 published engine (:${t||"?"})`}catch{return null}}function bt(e){let n=Math.max(0,Math.round(e/1e3));return n<60?`${n}s ago`:n<3600?`${Math.round(n/60)}m ago`:n<86400?`${Math.round(n/3600)}h ago`:`${Math.round(n/86400)}d ago`}async function cr(e,n,t,r={}){let o=r.attempts??30,i=r.intervalMs??500;for(let a=0;a<o;a++){let s=I(e,{commandTimeoutMs:n});try{let d=(await s.listSims()).find(t);if(d)return d}catch{}finally{s.close()}await $(i)}return null}async function wn(e,n,t,r,o={}){let i=o.attempts??30,a=o.intervalMs??500,s=!!r&&Number.isInteger(r)&&r>1,l=()=>s&&r!==void 0&&!ye(r);for(let d=0;d<i;d++){if(l())return{kind:"host-exit"};let m=I(e,{commandTimeoutMs:n});try{let h=(await m.listSims()).find(t);if(h)return l()?{kind:"host-exit"}:{kind:"match",sim:h}}catch{}finally{m.close()}if(l())return{kind:"host-exit"};await $(a)}return{kind:"timeout"}}async function bn(e,n,t,r={}){let o=r.attempts??20,i=r.intervalMs??250;for(let a=0;a<o;a++){let s=I(e,{commandTimeoutMs:n});try{let d=(await s.listSims()).find(m=>m.id===t);if(!d||d.readyState!=="open")return!0}catch{return!0}finally{s.close()}await $(i)}return!1}function vn(e){let n=e.meta;if(!n||n.sootsimHostDriver!=="playwright")return null;let t=Number(n.sootsimHostPid);return!Number.isInteger(t)||t<=1||t===process.pid?null:t}function yn(e){if(!e.connectAckFile)return!1;try{return M.writeFileSync(e.connectAckFile,`${JSON.stringify({connectedAt:Date.now(),pid:e.pid??null})}
6
- `,{flag:"w"}),!0}catch{return!1}}function vt(e){if(e.diagnosticLogPath)try{let n=M.readFileSync(e.diagnosticLogPath,"utf8").trim();if(!n){console.error(` ${U.basename(e.diagnosticLogPath)} was empty`);return}let t=n.length>4e3?`\u2026
7
- ${n.slice(-4e3)}`:n;console.error(` ${U.basename(e.diagnosticLogPath)}:`),console.error(t)}catch(n){let t=n instanceof Error?n.message:String(n);console.error(` failed to read ${U.basename(e.diagnosticLogPath)}: ${t}`)}}function ye(e){try{return process.kill(e,0),!0}catch(n){return n?.code==="EPERM"}}async function Sn(e,n=2500){let t=Date.now()+n;for(;Date.now()<t;){if(!ye(e))return!0;await $(100)}return!ye(e)}function $n(e){let n=ut("ps",["-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),t=ut("ps",["eww","-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(n.status!==0||t.status!==0)return!1;let r=(n.stdout||"").trimEnd(),o=(t.stdout||"").trimEnd();return(o.startsWith(r)?o.slice(r.length):o).includes("SOOTSIM_PW_URL=")}async function be(e,n){let t=new Set(n),r=new Set;for(let o of e){if(!t.has(o.id))continue;let i=vn(o);i&&r.add(i)}for(let o of r){if(!$n(o)){console.log(` skipped pid ${o}: not a rnx playwright host (stale sim record)`);continue}try{process.kill(o,"SIGTERM")}catch{}if(await Sn(o)){console.log(` closed playwright host process ${o}`);continue}try{process.kill(o,"SIGKILL"),console.log(` force-closed playwright host process ${o}`)}catch{}}}function Y(e,n){if(n){let o=n.trim(),i=e.find(a=>a.id===o);if(!i)throw new Error(`no sim connected with id ${o}`);return i}let t=e.find(o=>o.isPrimary&&o.readyState==="open");if(t)return t;let r=e.find(o=>o.readyState==="open");if(r)return r;throw new Error("no sim connected")}function yt(e,n,t,r=!1){let[o,i]=[e,n.url].map(a=>{if(!a)return a;try{let s=new URL(a);if(s.searchParams.has("sootsimConfig"))return s.searchParams.set("sootsimConfig","[redacted]"),s.toString()}catch{}return a});if(r){console.log(` Opened ConnectRN [${t}]`);return}console.log(` ${t==="current sim"?"loaded":"opened"}: ${o} [${t}]`),console.log(` current sim: ${n.id}`),console.log(JSON.stringify({simId:n.id,url:i},null,2))}async function St(e,n,t){if(t.includes("--no-describe"))return;let r=process.env.SOOTSIM_QUIET_TARGET_NOTICE;process.env.SOOTSIM_QUIET_TARGET_NOTICE="1";try{await xn(e,n,{stableMs:150,maxMs:400});let o=I(e,{commandTimeoutMs:3e3,simId:n,cliLabel:"open --describe",simIdSource:"flag"});try{let i=null;try{i=await nt(o,1)}catch{}if(i&&!i.ready){let s=i.loadingText?`still showing "${i.loadingText}"`:i.flag!==!0?"guest ready event has not fired":i.targets<=0?"no visible app content is inspectable yet":"app tree is still stabilizing";console.log(` app still loading: ${s} (nodes: ${i.nodes}, targets: ${i.targets})`),console.log(" before interacting, run: rnx wait ready --max-ms 120000")}let a=await tt(o,{describe:!0,verbose:!1,filter:"",compact:!0,hideXy:!1,maxDepth:12});if(!a?.tree)return;console.log(""),console.log(a.tree)}finally{o.close()}}catch{}finally{r===void 0?delete process.env.SOOTSIM_QUIET_TARGET_NOTICE:process.env.SOOTSIM_QUIET_TARGET_NOTICE=r}}async function xn(e,n,t){let r=Date.now()+t.maxMs,o="(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()",i=I(e,{commandTimeoutMs:2e3,simId:n,simIdSource:"flag"});try{let a=-1,s=0;for(;Date.now()<r;){let l=-1;try{let d=await i.send({type:"evaluate",code:o});typeof d=="number"&&(l=d)}catch{}if(l>=0&&l===a){if(Date.now()-s>=t.stableMs)return}else a=l,s=Date.now();await $(50)}}finally{i.close()}}async function Pn(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs});t.positional.length!==1&&(console.error(" rnx open: expected exactly one <url-or-route>"),console.error(" examples: rnx open /settings | rnx open myapp://settings"),u(1));let r=T(t),o=t.simId?` --sim ${t.simId}`:"";try{let i=await qe(r,t.positional[0]??"");console.log(` opened deep link: ${i}`)}catch(i){console.error(` link failed: ${i instanceof Error?i.message:String(i)}`),await A(r,{errorsCommand:`rnx get errors 5${o}`,warningsCommand:`rnx get warnings 5${o}`,requestsCommand:`rnx get requests 5${o}`}),u(1)}finally{r.close()}}async function dr(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--new","--headless","--headed","--ephemeral","--hot","--no-hmr","--no-describe","--quiet"],stripValueFlags:["--base-url","--replace","--driver","--profile","--cdp-port","--device","--viewport"]}),r=e.find((f,p)=>e[p-1]==="--profile"),o=e.includes("--quiet"),i=e.includes("--ephemeral"),a=e.find((f,p)=>e[p-1]==="--cdp-port"),s=a?Number(a):void 0;a&&(!Number.isFinite(s)||s<=0)&&(console.error(` rnx open: --cdp-port must be a positive port number, got "${a}"`),u(1)),r&&i&&(console.error(" rnx open: --profile cannot be combined with --ephemeral"),u(1));let l=r?Ve(r).id:void 0,d=e.includes("--new")||!!l||i,m=tn(e);d&&t.simIdSource==="flag"&&(console.error(" rnx open: --new, --profile, and --ephemeral cannot be combined with --sim"),u(1));let c=t.positional[0]||"";if(Ke(c)){d&&(console.error(" rnx open: deep links target the current app; remove --new, --profile, or --ephemeral"),u(1)),await Pn(e,n);return}if(Jt(c)){let f=(()=>{try{return k(new URL(c).hostname)}catch{return!1}})();console.log(" that\u2019s an rnx preview/build link \u2014 a full player page, not a driveable sim."),console.log(" opening it in your browser for viewing\u2026");try{await ot(c,{background:!1})}catch(p){console.error(` could not launch a browser: ${p instanceof Error?p.message:String(p)}`),console.error(` open it yourself: ${c}`),u(1)}console.log(f?" to drive it under the CLI, point `rnx open` at the app\u2019s dev port instead (e.g. `rnx open 8081`).":" the CLI can\u2019t drive a remote preview (the engine only attaches to the local bridge from localhost). to drive the app, run it locally and `rnx open <port>`.");return}let h=$t(c)?await Se(c):void 0,N=await nn(h),X=await Qe(N),F=X?.runtimeVersion,j=ue(ue(X?{...X,runtimeVersion:void 0}:void 0,n.runtimeConfig),m);F&&await rn(F);let Z=e.find((f,p)=>e[p-1]==="--base-url");if(Z&&!t.explicitPort){let f=de(Z);f&&(t.wsPort=f)}t.wsPort=await qt(t.wsPort,t.explicitPort);let O=e.find((f,p)=>e[p-1]==="--driver")||"";O&&!gt(O)&&(console.error(` unknown driver "${O}" \u2014 run \`rnx list --drivers\``),u(1));let v=gt(O)?O:process.env.CI==="1"||process.env.CI==="true"||process.env.GITHUB_ACTIONS==="true"||Te()||!process.stdin.isTTY?"playwright":Re()||"playwright",It=Kt(e,v);s&&v!=="playwright"&&(console.error(" rnx open: --cdp-port is only honored by the playwright driver"),u(1));let $e=e.includes("--hot"),xe=e.includes("--no-hmr");$e&&xe&&(console.error(" rnx open: --hot and --no-hmr cannot be combined"),u(1));let kt=$e?!0:xe?!1:v!=="playwright",C=e.find((f,p)=>e[p-1]==="--device");C&&!(C in le)&&(console.error(` rnx open: unknown device "${C}"`),console.error(` known devices: ${Oe().join(", ")}`),u(1));let ee=C?le[C]:void 0,H=e.find((f,p)=>e[p-1]==="--viewport"),W=H?/^(\d+)x(\d+)$/.exec(H):null;H&&!W&&(console.error(` rnx open: --viewport must be <width>x<height>, got "${H}"`),u(1));let Ct=W?{width:Number(W[1]),height:Number(W[2])}:void 0,K={hot:kt,device:C,resolvedBundle:h,project:N},Ut=F?`http://localhost:${t.wsPort}/`:Z||sn(t.wsPort),x=on(Ut,F),Pe=e.includes("--base-url");Le(t.wsPort,x);let Rt=_();if(!d){let f=T(t),p=t.simId?` --sim ${t.simId}`:"",re=!1;try{let g=null,V=null;try{let w=await f.listSims();if(t.simIdSource==="saved")g=w.find(b=>b.id===Rt&&b.readyState==="open"&&he(b,v))??null,g||D();else if(t.simIdSource==="flag"&&(g=Y(w,t.simId),!he(g,v)))throw new Error(`sim ${g.id} is not managed by the ${v} driver`);if(!g&&t.simIdSource!=="flag"){V=await G(c,L(x,j),K);let b=new URL(V);b.searchParams.delete("inspectOpen"),g=w.find(S=>{if(S.readyState!=="open"||!S.url||!he(S,v))return!1;try{let Ue=new URL(S.url);return Ue.searchParams.delete("inspectOpen"),Ue.toString()===b.toString()}catch{return!1}})??null}if(!g)if(t.simIdSource!=="flag")re=!0;else throw new Error("no sim connected");if(!re&&g){let b=Pe||ve(c)?x:wt(g,x),S=V??await G(c,L(b,j),K);f.send({type:"evaluate",simId:g.id,code:`window.location.href = ${JSON.stringify(S)}`}).catch(()=>{})}}catch(w){console.error(` open failed: ${w instanceof Error?w.message:String(w)}`),await A(f,{errorsCommand:`rnx get errors 5${p}`,warningsCommand:`rnx get warnings 5${p}`,requestsCommand:`rnx get requests 5${p}`}),u(1)}if(!re&&g){await $(1500);let w=await pn(t.wsPort,t.commandTimeoutMs,g.id);w||(console.error(" timed out waiting for current sim to load target"),u(1)),w.bridge.close(),P(g.id);let b=Pe||ve(c)?x:wt(g,x),S=V??await G(c,L(b,j),K);return yt(S,{...g,url:S},"current sim",o),await St(t.wsPort,g.id,e),t.wsPort}}finally{f.close()}}let Et=L(x,j),Ie=`cli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,ke=await mn(c,Et,Ie,K),Ce=_e();Ce||(console.error(" could not resolve a stable owning process; refusing unsupervised sim host"),u(1));let Tt=f=>f.url?.includes(`inspectOpen=${Ie}`)??!1,R=rt(v);R||(console.error(` unknown driver "${v}" \u2014 run \`rnx list --drivers\``),u(1));let q=Wt(),y=await R.launch({url:ke,bridgePort:de(x)??t.wsPort,headless:It,profileId:l,ephemeralProfile:i,cdpPort:s,device:C,ownerPid:Ce,viewport:Ct??(ee?{width:ee.width+120,height:ee.height+60}:void 0),connectTimeoutMs:q.hostTimeoutMs});y.launched||(console.error(` ${R.name} driver: ${y.message}`),u(1));let te=await wn(t.wsPort,t.commandTimeoutMs,Tt,y.pid,{attempts:q.attempts,intervalMs:q.intervalMs});if(te.kind==="host-exit"&&(vt(y),console.error(` ${R.name} host crashed \u2014 sim is no longer attached`),u(1)),te.kind==="timeout"){if(y.pid)try{process.kill(y.pid,"SIGTERM"),console.error(` closed ${R.name} host process ${y.pid}`)}catch{}vt(y),console.error(` timed out after ${q.timeoutMs}ms waiting for opened sim to connect`),u(1)}let ne=te.sim;return P(ne.id),yn(y),yt(ke,ne,`${R.name} driver`,o),await St(t.wsPort,ne.id,e),t.wsPort}async function Pt(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--force"]}),r=e.includes("--force"),o=T(t),i=t.simId?` --sim ${t.simId}`:"";try{try{let a=await o.listSims(),s=Y(a,t.positional[0]||t.simId);if(s.lockedBy&&s.lockExpiresAt&&s.lockExpiresAt>Date.now()){let l=Math.max(0,Math.round((s.lockExpiresAt-Date.now())/1e3));s.lockedByKind==="user-active"&&(console.error(` refused: ${s.id} is locked by the active user (${l}s) \u2014 that's a live human tab`),console.error(" run `rnx open --new` for a fresh investigation sim"),u(1)),r||(console.error(` refused: ${s.id} is leased by ${s.lockedBy} (${l}s)`),console.error(` \`sootsim use ${s.id} --force\` to take it, or \`rnx open --new\` for a fresh sim`),u(1))}await o.focusSim(s.id),P(s.id),console.log(` using: ${s.id}`)}catch(a){z(a),console.error(` use failed: ${a instanceof Error?a.message:String(a)}`),await A(o,{errorsCommand:`rnx get errors 5${i}`,warningsCommand:`rnx get warnings 5${i}`,requestsCommand:`rnx get requests 5${i}`}),u(1)}}finally{o.close()}}async function ur(e,n={}){await Pt(e,n)}async function mr(e,n={}){await Pt(e,n)}async function pr(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--force"]}),r=e.includes("--force"),o=T(t);try{try{let i=await o.listSims(),a=Y(i,t.positional[0]||t.simId),s=r&&a.lockedBy&&a.lockedByKind!=="user-active"?a.lockedBy:null,l=await o.claim(a.id,{force:r});P(a.id);let d=Math.max(0,Math.round((l.lockExpiresAt-Date.now())/1e3)),m=l.bootedCount>0?` (booted ${l.bootedCount})`:"";console.log(` claimed: ${l.simId} [${d}s]${m}`),s&&console.log(` took over from: ${s}`)}catch(i){if(i instanceof Ae){let a=Math.max(0,Math.round(i.lock.expiresInMs/1e3));console.error(` claim failed: locked by ${i.lock.by} for ${a}s more`),console.error(" use --force to take it, or `rnx open --new` for a fresh sim"),u(1)}console.error(` claim failed: ${i instanceof Error?i.message:String(i)}`),u(1)}}finally{o.close()}}async function In(e,n,t,r){if(r.length===0)return{closed:[],remaining:[]};await Promise.all(r.map(i=>e.closeSim(i).catch(()=>{})));let o=new Set(r);for(let i=0;i<40;i++){let a=[];try{let s=I(n,{commandTimeoutMs:t});try{a=(await s.listSims()).filter(d=>o.has(d.id)&&d.readyState==="open").map(d=>d.id)}finally{s.close()}}catch{a=[]}if(a.length===0)return{closed:[...o],remaining:[]};if(i===39)return{closed:[...o].filter(s=>!a.includes(s)),remaining:a};await $(250)}return{closed:[...o],remaining:[]}}function kn(e,n){let t=e.filter(c=>c.readyState==="open"),r=t.map(c=>c.id),o=n.explicitKeepId?.trim()||"",i=n.savedKeepId?.trim()||"",a=i?t.some(c=>c.id===i):!1,s=i&&!a?i:null,l=null,d=null,m=null;if(n.closeOthers)if(o){let c=t.find(h=>h.id===o);c?l=c.id:d=o}else if(i&&a)l=i;else{let c=t.find(h=>h.isPrimary)??t[0]??null;c&&(l=c.id,i&&!a&&(m=c.id))}return{openIds:r,keepId:l,targets:d?[]:r.filter(c=>c!==l),staleSavedId:s,missingExplicitKeepId:d,fallbackKeepId:m}}async function fr(e,n={}){let t=E(e,{port:n.port,commandTimeoutMs:n.timeoutMs,stripBooleanFlags:["--all","--others"]}),r=T(t),o=t.simId?` --sim ${t.simId}`:"",i=e.includes("--all"),a=e.includes("--others");if(i||a){try{let s=await r.listSims(),l=_(),d=t.positional[0]||(t.simIdSource==="flag"?t.simId:void 0),m=kn(s,{closeOthers:a,explicitKeepId:d,savedKeepId:l});if(m.staleSavedId&&D(),m.fallbackKeepId&&(P(m.fallbackKeepId),console.log(` saved sim ${m.staleSavedId} is gone \u2014 keeping primary ${m.fallbackKeepId}`)),m.missingExplicitKeepId&&(console.error(` close failed: keep sim ${m.missingExplicitKeepId} is not connected; not closing other sims`),u(1)),m.targets.length===0){console.log(m.keepId?` nothing to close \u2014 only the kept sim ${m.keepId} is connected`:m.staleSavedId?` nothing to close \u2014 no sims connected (cleared stale current sim ${m.staleSavedId})`:" nothing to close \u2014 no sims connected");return}let c=await In(r,t.wsPort,t.commandTimeoutMs,m.targets);await be(s,m.targets);let h=_();h&&c.closed.includes(h)&&(m.keepId?P(m.keepId):D());let N=` closed ${c.closed.length} sim(s)${m.keepId?` (kept ${m.keepId})`:""}`;console.log(N),c.remaining.length>0&&(console.error(` close failed: still connected: ${c.remaining.join(", ")}`),u(1))}catch(s){z(s),console.error(` close failed: ${s instanceof Error?s.message:String(s)}`),u(1)}finally{r.close()}return}try{try{let s=await r.listSims(),l=Y(s,t.positional[0]||t.simId),d=s.find(c=>c.id!==l.id&&c.readyState==="open");await r.closeSim(l.id),await bn(t.wsPort,t.commandTimeoutMs,l.id)||(await be(s,[l.id]),console.error(` close failed: ${l.id} is still connected`),u(1)),await be(s,[l.id]),_()===l.id&&(d?P(d.id):D()),console.log(` closed: ${l.id}`)}catch(s){z(s),console.error(` close failed: ${s instanceof Error?s.message:String(s)}`),await A(r,{errorsCommand:`rnx get errors 5${o}`,warningsCommand:`rnx get warnings 5${o}`,requestsCommand:`rnx get requests 5${o}`}),u(1)}}finally{r.close()}}export{Wt as a,qt as b,ar as c,on as d,xt as e,sn as f,G as g,mn as h,fn as i,lr as j,cr as k,wn as l,vn as m,yn as n,be as o,Pn as p,dr as q,ur as r,mr as s,pr as t,In as u,kn as v,fr as w};
@@ -1,4 +0,0 @@
1
- /*! rnx v0.1.370 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a}from"./chunk-MDCY532E.js";import"./chunk-64JAEJ6N.js";import"./chunk-I52NT6VG.js";export{a as getCliVersion};
@@ -1,4 +0,0 @@
1
- /*! rnx v0.1.370 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w}from"./chunk-OTFTMGAL.js";import"./chunk-6S5LJV2O.js";import"./chunk-3UXXYJVD.js";import"./chunk-DMHSD6YJ.js";import"./chunk-PAUEZO6F.js";import"./chunk-6A6L3VJR.js";import"./chunk-3BG6UCQY.js";import"./chunk-5BR33NAZ.js";import"./chunk-NR2V2ONN.js";import"./chunk-D2GZASRV.js";import"./chunk-AALKIAUZ.js";import"./chunk-EWSWOWXK.js";import"./chunk-PNOENVMJ.js";import"./chunk-WFQHT4QD.js";import"./chunk-EQ3OE2AV.js";import"./chunk-JZLDHPB7.js";import"./chunk-CMVRTZ5G.js";import"./chunk-EOIBLKZO.js";import"./chunk-OJZHECGH.js";import"./chunk-AVJBT5LF.js";import"./chunk-FA75F34Z.js";import"./chunk-DHYTRCIP.js";import"./chunk-IDLFVRPN.js";import"./chunk-U63T6LIQ.js";import"./chunk-64JAEJ6N.js";import"./chunk-I52NT6VG.js";export{d as applyRuntimeGenerationOrigin,h as buildOpenUrl,g as buildShellUrl,u as closeSimsBulk,b as ensureBridgeForOpen,v as planBulkCloseTargets,m as playwrightHostPidForSim,j as printConnectedSims,c as resolveBundleTarget,e as resolveDefaultShellBaseUrl,a as resolveDriverConnectWaitOptions,f as resolveShellBaseUrlForBridgePort,t as runClaimCommand,w as runCloseCommand,s as runFocusCommand,p as runLinkCommand,q as runOpenCommand,r as runUseCommand,n as signalDriverLaunchConnected,i as summarizeSimUrl,o as terminatePlaywrightHostsForSims,k as waitForSimMatch,l as waitForSimMatchOrHostExit};