rnxsim 0.0.0 → 0.1.312

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 (228) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +512 -0
  3. package/detox/colors.ts +54 -0
  4. package/detox/config-loader.ts +135 -0
  5. package/detox/element-types.ts +39 -0
  6. package/detox/expectations.ts +537 -0
  7. package/detox/gestures.ts +480 -0
  8. package/detox/index.ts +2118 -0
  9. package/detox/jest-preset.cjs +51 -0
  10. package/detox/jest-setup-after-env.cjs +18 -0
  11. package/detox/matchers.ts +30 -0
  12. package/detox/motion-change.cjs +109 -0
  13. package/detox/motion-change.d.cts +35 -0
  14. package/detox/navigation.ts +43 -0
  15. package/detox/screenshots/animated-color-test-rest-norngh.png +0 -0
  16. package/detox/screenshots/color-test-after-drag-norngh.png +0 -0
  17. package/detox/screenshots/color-test-rest-norngh.png +0 -0
  18. package/detox/screenshots/theme-blue-toggle.png +0 -0
  19. package/detox/screenshots/theme-blue.png +0 -0
  20. package/detox/screenshots/theme-red-toggle.png +0 -0
  21. package/detox/screenshots/theme-red.png +0 -0
  22. package/dist-cli/bin.js +15 -0
  23. package/dist-cli/chunks/agent-NXVDDCFG.js +48 -0
  24. package/dist-cli/chunks/agent-wrapper-DXJCFKL3.js +17 -0
  25. package/dist-cli/chunks/app-fonts-W5AJZQJF.js +4 -0
  26. package/dist-cli/chunks/assert-3LOJEUDT.js +49 -0
  27. package/dist-cli/chunks/auth-MFTYYPNX.js +12 -0
  28. package/dist-cli/chunks/beta-GT3NN67B.js +4 -0
  29. package/dist-cli/chunks/camera-6EAK7CUL.js +22 -0
  30. package/dist-cli/chunks/chunk-274UD5FD.js +4 -0
  31. package/dist-cli/chunks/chunk-2SA2VTGP.js +5 -0
  32. package/dist-cli/chunks/chunk-33FKQH54.js +5 -0
  33. package/dist-cli/chunks/chunk-37I5AIS7.js +3 -0
  34. package/dist-cli/chunks/chunk-3D57IBPC.js +4 -0
  35. package/dist-cli/chunks/chunk-4BXCZHAU.js +4 -0
  36. package/dist-cli/chunks/chunk-5OX7ANRA.js +5 -0
  37. package/dist-cli/chunks/chunk-66NF2KNG.js +9 -0
  38. package/dist-cli/chunks/chunk-6UKJB2VC.js +125 -0
  39. package/dist-cli/chunks/chunk-7INBNA3U.js +26 -0
  40. package/dist-cli/chunks/chunk-7VWOSTD5.js +5 -0
  41. package/dist-cli/chunks/chunk-AY47WKS5.js +23 -0
  42. package/dist-cli/chunks/chunk-B7KMNHX7.js +4 -0
  43. package/dist-cli/chunks/chunk-BKNOLP3J.js +4 -0
  44. package/dist-cli/chunks/chunk-BRIZOR4K.js +28 -0
  45. package/dist-cli/chunks/chunk-DM6KUAOZ.js +4 -0
  46. package/dist-cli/chunks/chunk-EUAVBTKU.js +4 -0
  47. package/dist-cli/chunks/chunk-FTC4M26Q.js +4 -0
  48. package/dist-cli/chunks/chunk-FWYYCUAZ.js +4 -0
  49. package/dist-cli/chunks/chunk-G74YIEVS.js +7 -0
  50. package/dist-cli/chunks/chunk-GZDHEONW.js +507 -0
  51. package/dist-cli/chunks/chunk-HG7ORJMT.js +5 -0
  52. package/dist-cli/chunks/chunk-HMDOLCKG.js +15 -0
  53. package/dist-cli/chunks/chunk-JG6S4RSH.js +4 -0
  54. package/dist-cli/chunks/chunk-KR5BGMBZ.js +4 -0
  55. package/dist-cli/chunks/chunk-KZW5WBGU.js +983 -0
  56. package/dist-cli/chunks/chunk-L24Z3CRS.js +30 -0
  57. package/dist-cli/chunks/chunk-LDQ7HVCW.js +4 -0
  58. package/dist-cli/chunks/chunk-MENV7VLD.js +4 -0
  59. package/dist-cli/chunks/chunk-MNGQ42QE.js +568 -0
  60. package/dist-cli/chunks/chunk-N6A3SXMR.js +4 -0
  61. package/dist-cli/chunks/chunk-NLEMQ4PY.js +6 -0
  62. package/dist-cli/chunks/chunk-NPVGMH2N.js +101 -0
  63. package/dist-cli/chunks/chunk-OR3XTXEB.js +107 -0
  64. package/dist-cli/chunks/chunk-PEPUGJVI.js +4 -0
  65. package/dist-cli/chunks/chunk-Q3RGLERJ.js +142 -0
  66. package/dist-cli/chunks/chunk-SI3BUTQR.js +4 -0
  67. package/dist-cli/chunks/chunk-T4FT6CM7.js +4 -0
  68. package/dist-cli/chunks/chunk-TBMVBI26.js +7 -0
  69. package/dist-cli/chunks/chunk-TCWQJILS.js +5 -0
  70. package/dist-cli/chunks/chunk-TGQNQ6XT.js +766 -0
  71. package/dist-cli/chunks/chunk-TYE3WBSR.js +5 -0
  72. package/dist-cli/chunks/chunk-U4PN6JOT.js +6 -0
  73. package/dist-cli/chunks/chunk-VUFRB347.js +4 -0
  74. package/dist-cli/chunks/chunk-VZBLFMYC.js +10 -0
  75. package/dist-cli/chunks/chunk-WBT32R6N.js +25 -0
  76. package/dist-cli/chunks/chunk-XRGEEPJ5.js +38 -0
  77. package/dist-cli/chunks/chunk-Y2FSZSO7.js +71 -0
  78. package/dist-cli/chunks/chunk-YRV7HR3P.js +74 -0
  79. package/dist-cli/chunks/chunk-YZRFF4YA.js +14 -0
  80. package/dist-cli/chunks/chunk-ZMZTHU7V.js +4 -0
  81. package/dist-cli/chunks/cleanup-H3GWQB63.js +25 -0
  82. package/dist-cli/chunks/cli-version-3QPAJ3LC.js +4 -0
  83. package/dist-cli/chunks/compat-5WG2XJV7.js +20 -0
  84. package/dist-cli/chunks/config-ANMBVVLL.js +13 -0
  85. package/dist-cli/chunks/control-NSGNQFJG.js +4 -0
  86. package/dist-cli/chunks/daemon-JHF4BJ3U.js +4 -0
  87. package/dist-cli/chunks/debug-CHV2O2KF.js +200 -0
  88. package/dist-cli/chunks/desktop-FIPIK4CH.js +31 -0
  89. package/dist-cli/chunks/detox-CVUJP7K6.js +52 -0
  90. package/dist-cli/chunks/device-6WCUM4W6.js +18 -0
  91. package/dist-cli/chunks/diagnose-I6EMWEII.js +43 -0
  92. package/dist-cli/chunks/disk-cleanup-P27CYFTN.js +4 -0
  93. package/dist-cli/chunks/drivers-HQ6AKZT6.js +4 -0
  94. package/dist-cli/chunks/film-UOQFFYNF.js +74 -0
  95. package/dist-cli/chunks/flow-N27MRRNL.js +4 -0
  96. package/dist-cli/chunks/help-SF6FEGEE.js +4 -0
  97. package/dist-cli/chunks/hidden-runtime-alias-NJYFSJKZ.js +4 -0
  98. package/dist-cli/chunks/home-paths-XOV44JEF.js +4 -0
  99. package/dist-cli/chunks/inspect-CWFRFQTY.js +4 -0
  100. package/dist-cli/chunks/install-desktop-KLQDNXZQ.js +4 -0
  101. package/dist-cli/chunks/login-BPFQENCX.js +28 -0
  102. package/dist-cli/chunks/logout-5A45ZGY7.js +4 -0
  103. package/dist-cli/chunks/maestro-E4CSDMLM.js +104 -0
  104. package/dist-cli/chunks/maestro-generate-CKMOJQX2.js +36 -0
  105. package/dist-cli/chunks/mode-SZYNMIQF.js +26 -0
  106. package/dist-cli/chunks/optional-demo-registry-FRH4SFVG.js +4 -0
  107. package/dist-cli/chunks/perf-VXU2XJAX.js +48 -0
  108. package/dist-cli/chunks/permissions-IRIAOVND.js +13 -0
  109. package/dist-cli/chunks/record-RY7FPLLH.js +72 -0
  110. package/dist-cli/chunks/report-issue-KNWXOE53.js +29 -0
  111. package/dist-cli/chunks/runtime-AR3GJTGK.js +4 -0
  112. package/dist-cli/chunks/screenshot-command-QLALR6GY.js +159 -0
  113. package/dist-cli/chunks/screenshot-layers-OQFMFVRL.js +20 -0
  114. package/dist-cli/chunks/screenshots-capture-6TSRJFGB.js +42 -0
  115. package/dist-cli/chunks/serve-F54J2NQO.js +44 -0
  116. package/dist-cli/chunks/setup-7V6UKX4U.js +32 -0
  117. package/dist-cli/chunks/skills-QQBOSETH.js +50 -0
  118. package/dist-cli/chunks/storage-TAPMKK5O.js +37 -0
  119. package/dist-cli/chunks/store-7NX3S43H.js +4 -0
  120. package/dist-cli/chunks/telemetry-E7BUK6RA.js +4 -0
  121. package/dist-cli/chunks/timeline-IAM564NA.js +24 -0
  122. package/dist-cli/chunks/upgrade-CD55QXIX.js +7 -0
  123. package/dist-cli/chunks/upload-GZ6LIMYM.js +4 -0
  124. package/dist-cli/chunks/version-3DYJ5AS3.js +6 -0
  125. package/dist-cli/chunks/web-6NW6YLPI.js +4 -0
  126. package/dist-cli/chunks/what-happened-CZZDOOVG.js +25 -0
  127. package/dist-lib/agent-daemon-client.cjs +468 -0
  128. package/dist-lib/agent-events.cjs +48 -0
  129. package/dist-lib/agent-identity.cjs +53 -0
  130. package/dist-lib/agent-sessions.cjs +725 -0
  131. package/dist-lib/attached-projects.cjs +526 -0
  132. package/dist-lib/auth/shared-session.cjs +195 -0
  133. package/dist-lib/backend-origin.cjs +70 -0
  134. package/dist-lib/beta.cjs +41 -0
  135. package/dist-lib/beta.mjs +13 -0
  136. package/dist-lib/bridge-constants.cjs +161 -0
  137. package/dist-lib/cli-constants.cjs +32 -0
  138. package/dist-lib/config.cjs +96 -0
  139. package/dist-lib/detox/index.cjs +2863 -0
  140. package/dist-lib/detox/jest-preset.cjs +51 -0
  141. package/dist-lib/dev-bundle-resolution.cjs +223 -0
  142. package/dist-lib/home-paths.cjs +421 -0
  143. package/dist-lib/host/bridge-host.cjs +5600 -0
  144. package/dist-lib/host/fetch-proxy-handler.cjs +373 -0
  145. package/dist-lib/host/fetch-proxy-overrides.cjs +63 -0
  146. package/dist-lib/host/fetch-proxy-overrides.mjs +37 -0
  147. package/dist-lib/host/websocket-proxy.cjs +214 -0
  148. package/dist-lib/index.cjs +513 -0
  149. package/dist-lib/jump-to-source-babel.cjs +93 -0
  150. package/dist-lib/menu.cjs +620 -0
  151. package/dist-lib/menu.mjs +581 -0
  152. package/dist-lib/metro.cjs +297 -0
  153. package/dist-lib/profiles.cjs +246 -0
  154. package/dist-lib/public-brand.cjs +39 -0
  155. package/dist-lib/render-mode.cjs +54 -0
  156. package/dist-lib/scripts/dev-server-scanner.cjs +1034 -0
  157. package/dist-lib/sdk.cjs +2333 -0
  158. package/dist-lib/sdk.mjs +2240 -0
  159. package/dist-lib/skills.cjs +23911 -0
  160. package/dist-lib/vite.cjs +358 -0
  161. package/package.json +189 -18
  162. package/scripts/dev-server-scanner.ts +941 -0
  163. package/scripts/optional-demo-registry.ts +113 -0
  164. package/scripts/postinstall.cjs +3 -0
  165. package/scripts/preuninstall.cjs +118 -0
  166. package/skills/contrast/SKILL.md +171 -0
  167. package/skills/rnx-debug/SKILL.md +425 -0
  168. package/skills/rnx-perf/SKILL.md +295 -0
  169. package/skills/rnx-setup/SKILL.md +160 -0
  170. package/skills/rnx-test/SKILL.md +292 -0
  171. package/skills/rnx-visual/SKILL.md +122 -0
  172. package/src/agent-daemon-client.ts +410 -0
  173. package/src/agent-events.ts +71 -0
  174. package/src/agent-identity.ts +23 -0
  175. package/src/agent-prompt.ts +71 -0
  176. package/src/agent-sessions.ts +573 -0
  177. package/src/attached-projects.ts +539 -0
  178. package/src/auth/shared-session.ts +204 -0
  179. package/src/backend-origin.ts +49 -0
  180. package/src/beta.ts +19 -0
  181. package/src/bridge-constants.ts +171 -0
  182. package/src/browser-cache.ts +16 -0
  183. package/src/cli-constants.ts +1 -0
  184. package/src/cli-version.ts +32 -0
  185. package/src/codex-client.ts +215 -0
  186. package/src/config.ts +134 -0
  187. package/src/dev-bundle-resolution.ts +236 -0
  188. package/src/disk-cleanup.ts +466 -0
  189. package/src/home-paths.ts +552 -0
  190. package/src/host/agent-host.ts +666 -0
  191. package/src/host/bridge-host.ts +2626 -0
  192. package/src/host/fetch-proxy-handler.ts +397 -0
  193. package/src/host/fetch-proxy-overrides.ts +51 -0
  194. package/src/host/open-url.ts +89 -0
  195. package/src/host/websocket-proxy.ts +210 -0
  196. package/src/index.ts +12 -705
  197. package/src/jump-to-source-babel.ts +135 -0
  198. package/src/menu.ts +734 -0
  199. package/src/metro-plugin.ts +139 -0
  200. package/src/native-dev-bundle-url.ts +96 -0
  201. package/src/native-seam-manifest.ts +341 -0
  202. package/src/plist.ts +27 -0
  203. package/src/poll-until.ts +92 -0
  204. package/src/profiles.ts +179 -0
  205. package/src/public-brand.ts +9 -0
  206. package/src/render-mode.ts +27 -0
  207. package/src/runtime-assets.ts +228 -0
  208. package/src/runtime-delivery.ts +54 -0
  209. package/src/screenshots/compose.ts +422 -0
  210. package/src/screenshots/frame-compose.ts +454 -0
  211. package/src/screenshots/orchestrate.ts +256 -0
  212. package/src/screenshots/org-deck.ts +91 -0
  213. package/src/screenshots/registry.ts +58 -0
  214. package/src/screenshots/schema.ts +364 -0
  215. package/src/sdk.ts +7 -0
  216. package/src/settings-bundle.ts +418 -0
  217. package/src/skills/builtin/a11y-review.ts +132 -0
  218. package/src/skills/builtin/compat-check.ts +71 -0
  219. package/src/skills/builtin/maestro-test.ts +121 -0
  220. package/src/skills/builtin/perf-profile.ts +90 -0
  221. package/src/skills/builtin/screenshot-all.ts +52 -0
  222. package/src/skills/builtin/visual-diff.ts +100 -0
  223. package/src/skills/registry.ts +107 -0
  224. package/src/skills/types.ts +41 -0
  225. package/src/team-machine-prompt.ts +73 -0
  226. package/src/vite-plugin-one.ts +190 -0
  227. package/src/vite-plugin.ts +1750 -0
  228. package/src/worklets-babel.ts +134 -0
@@ -0,0 +1,159 @@
1
+ /*! rnx v0.1.312 | (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 ne,b as se,f as ie}from"./chunk-MNGQ42QE.js";import"./chunk-BRIZOR4K.js";import{a as v}from"./chunk-2SA2VTGP.js";import"./chunk-KZW5WBGU.js";import"./chunk-LDQ7HVCW.js";import{a as te}from"./chunk-Q3RGLERJ.js";import{a as ee}from"./chunk-Y2FSZSO7.js";import"./chunk-NPVGMH2N.js";import{a as re,b as oe}from"./chunk-BKNOLP3J.js";import"./chunk-HMDOLCKG.js";import"./chunk-SI3BUTQR.js";import"./chunk-274UD5FD.js";import"./chunk-XRGEEPJ5.js";import{r as K,s as X}from"./chunk-TGQNQ6XT.js";import"./chunk-GZDHEONW.js";import"./chunk-G74YIEVS.js";import"./chunk-T4FT6CM7.js";import"./chunk-YZRFF4YA.js";import"./chunk-4BXCZHAU.js";import"./chunk-FWYYCUAZ.js";import"./chunk-AY47WKS5.js";import"./chunk-3D57IBPC.js";import{h as A,i as J,j as B,k as Z,l as Q,m as M,n as $}from"./chunk-7INBNA3U.js";import"./chunk-PEPUGJVI.js";import"./chunk-N6A3SXMR.js";import"./chunk-TCWQJILS.js";import"./chunk-B7KMNHX7.js";import"./chunk-U4PN6JOT.js";import"./chunk-HG7ORJMT.js";import"./chunk-TYE3WBSR.js";import{b as F,e as P,f as j,g as I,h as L,i as U,j as R}from"./chunk-5OX7ANRA.js";import"./chunk-33FKQH54.js";import"./chunk-7VWOSTD5.js";import"./chunk-6UKJB2VC.js";import"./chunk-66NF2KNG.js";import"./chunk-ZMZTHU7V.js";import"./chunk-MENV7VLD.js";import{mkdirSync as ce,writeFileSync as ae}from"fs";import{dirname as ue,resolve as de}from"path";async function pe(e,t){let r=Le(e);(r.includes("--help")||r.includes("-h"))&&(console.log(`
5
+ rnxsim screenshot \u2014 capture the canvas as a PNG
6
+
7
+ usage:
8
+ rnxsim screenshot [output] [options]
9
+ rnxsim screenshot [options] --output <path>
10
+
11
+ options:
12
+ --output <path> output file path (default: /tmp/sootsim-inspect.png)
13
+ first positional arg works too: \`screenshot /tmp/x.png\`
14
+ --with-frame wrap the captured screen in a tight device frame
15
+ --no-frame capture the raw screen bitmap (default)
16
+ --no-shell tenant-only capture (no status bar, keyboard, toasts,
17
+ notification center, or other shell overlays). use for
18
+ clean app screenshots when a shell surface is in the way.
19
+ --shell-only capture only the shell chrome, no tenant content
20
+ --allow-loading capture after caller-owned readiness checks even when
21
+ visible app copy matches a generic loading phrase
22
+ --area x,y,w,h crop to a logical rnx rect
23
+ --id <testID> crop to a node's bounding box
24
+ --text <text> crop to a node found by text content
25
+ --gallery crawl and capture multiple screens as HTML gallery
26
+ --themes capture light and dark variants
27
+
28
+ examples:
29
+ rnxsim screenshot
30
+ rnxsim screenshot --no-shell --output app.png
31
+ rnxsim screenshot --with-frame --output framed.png
32
+ rnxsim screenshot --area 0,200,393,400 --output hero.png
33
+ rnxsim screenshot --id loginButton --output button.png
34
+ `),process.exit(0));let i=Ue(r);if(i.length>0){for(let{flag:h,suggestion:w}of i)console.error(w?` unknown flag: ${h} (did you mean ${w}?)`:` unknown flag: ${h}`);console.error(" run `rnxsim screenshot --help` for the list of supported flags"),process.exit(1)}let o=r.includes("--gallery"),s=r.includes("--themes"),n=r.includes("--allow-loading"),a=ze(r),l=_e(r);if(o||s)return a&&(console.error(" --with-frame is not supported with --gallery / --themes"),process.exit(1)),le(r,t);a&&r.some(h=>h==="--area"||h==="--id"||h==="--text")&&(console.error(" --with-frame only supports full-screen capture for now"),console.error(" remove --area / --id / --text, or capture raw and compose later"),process.exit(1));let c=A(r,{port:t.port,stripBooleanFlags:["--with-frame","--no-frame","--no-shell","--shell-only","--allow-loading"],stripValueFlags:["--output","--area","--id","--text"]}),u=he(r),d=await Be(r);if(await Ae(c.wsPort)){try{await Oe(c,u,d,a,l,n)}catch(h){console.error(` screenshot failed: ${h instanceof Error?h.message:String(h)}`),process.exit(1)}return}a&&(console.error(" --with-frame requires a running rnx bridge"),console.error(" open the app in a live sim first, then rerun the command"),process.exit(1)),d&&(console.error(" --area / --id / --text require a running rnx bridge"),console.error(" start one with `rnxsim serve`, `rnxsim desktop`, or your project dev server"),process.exit(1)),await le(r,t)}async function Ae(e){let t=J(e,{commandTimeoutMs:1e3});try{return await t.listSims(),!0}catch{return!1}finally{t.close()}}async function Be(e){let t=e.find((o,s)=>e[s-1]==="--area");if(t){let o=t.split(",").map(c=>Number(c.trim()));if(o.length!==4||o.some(c=>!Number.isFinite(c)))throw new Error(`--area expects x,y,w,h (got "${t}")`);let[s,n,a,l]=o;return{x:s,y:n,w:a,h:l}}let r=e.find((o,s)=>e[s-1]==="--id"),i=e.find((o,s)=>e[s-1]==="--text");return r||i?{__matcher:{id:r,text:i}}:null}async function Oe(e,t,r,i,o,s){let n=B({...e,commandTimeoutMs:45e3});try{if((await Z(n)).hidden&&process.stderr.write(` \u26A0 screenshot will capture the LAST PAINTED canvas \u2014 likely stale.
35
+ navigation/\`shell\` commands sent before this screenshot may not
36
+ have repainted yet. focus the tab manually or \`rnxsim --sim <id>\`
37
+ to target a visible sim before capturing.
38
+
39
+ `),!s){let f=Number(process.env.CONTRAST_SCREENSHOT_READY_MAX_MS)||9e4,x=await X(n,f);if(!x.ready&&x.externalError)process.stderr.write(` \u26A0 capturing an ERROR screen. the app failed to load: ${x.externalError}
40
+ this is failure evidence, not app content. never use it as a baseline.
41
+
42
+ `);else if(!x.ready)throw new Error(`app not ready to capture after ${Math.round(x.elapsedMs/1e3)}s (${K(x)}); refusing to capture the boot/loading card. retry once the app paints.`)}let l=r,c=r?.__matcher;if(c){let f=await n.send({type:"evaluate",code:ee(c)});if(!f)throw new Error(c.id?`no node with id "${c.id}"`:`no node matching text "${c.text}"`);l=f}let u=l?{x:l.x,y:l.y,w:l.w,h:l.h}:void 0,d={type:"screenshot"};o&&(d.layers=o),u&&(d.crop=u);let m=await n.send(d);if(typeof m!="string"||m.length<="data:image/png;base64,".length)throw new Error("screenshot capture returned no image data \u2014 the sim is connected but not painting; check `rnxsim get errors`");let w=m.replace(/^data:image\/png;base64,/,"");u&&console.log(` area: x=${u.x} y=${u.y} w=${u.w} h=${u.h}`),o&&console.log(` layers: ${o}`);let p=de(process.cwd(),t||"/tmp/sootsim-inspect.png");ce(ue(p),{recursive:!0});let y=Buffer.from(w,"base64");if(i){let f=await Te(n);if(!f)throw new Error("could not read current device model from the target sim");let x=await ne(y,f);ae(p,x),console.log(` frame: ${f}`)}else ae(p,y);console.log(` saved: ${p}`)}finally{n.close()}}async function Te(e){let t=await M(e,"SootSim.bridges.settings.get")??{deviceModel:null},r=typeof t.deviceModel=="string"?t.deviceModel:null;return!r||!(r in F)?null:r}function ze(e){let t=!1;for(let r of e)r==="--with-frame"&&(t=!0),r==="--no-frame"&&(t=!1);return t}function _e(e){if(e.includes("--shell-only"))return"shell";if(e.includes("--no-shell"))return"tenant"}var je=new Set(["--help","-h","--verbose","-v","--with-frame","--no-frame","--no-shell","--shell-only","--allow-loading","--gallery","--themes"]),me=new Set(["--output","--area","--id","--text","--url","--port","--timeout","--sim"]),Ie={"--rect":"--area","--crop":"--area","--region":"--area","--bounds":"--area","--box":"--area","--xywh":"--area","--out":"--output","-o":"--output","--file":"--output","--path":"--output","--testid":"--id","--test-id":"--id","--test_id":"--id"};function Le(e){let t=[],r={"-o":"--output","--out":"--output","--file":"--output","--path":"--output","--testid":"--id","--test-id":"--id","--test_id":"--id","--rect":"--area","--crop":"--area","--region":"--area","--bounds":"--area","--box":"--area","--xywh":"--area"};for(let i of e){let o=r[i];t.push(o??i)}return t}function Ue(e){let t=[];for(let r=0;r<e.length;r++){let i=e[r];if(i.startsWith("-")){if(me.has(i)){r++;continue}je.has(i)||t.push({flag:i,suggestion:Ie[i]})}}return t}function he(e){let t=e.find((r,i)=>e[i-1]==="--output");if(t)return t;for(let r=0;r<e.length;r++){let i=e[r];if(i.startsWith("-")){me.has(i)&&r++;continue}return i}}async function le(e,t){let r=he(e)||"sootsim-screenshot.png",i=e.includes("--gallery"),o=e.find((a,l)=>e[l-1]==="--url")||`http://localhost:${t.port||5173}`,{chromium:s}=await import("playwright"),n=await v(a=>s.launch(a),{headless:!0});try{if(i)console.log(" capturing gallery..."),console.log(" (gallery mode not yet implemented)");else{let a=await n.newPage({viewport:{width:500,height:900}});await a.goto(o,{waitUntil:"networkidle"}),await a.waitForTimeout(2e3);let l=de(process.cwd(),r);ce(ue(l),{recursive:!0}),await a.screenshot({path:l}),console.log(` saved: ${l}`),await a.close()}}catch(a){console.error(` screenshot failed: ${a.message}`),process.exitCode=1}finally{await n.close()}}import{mkdirSync as V,readFileSync as et,writeFileSync as Me}from"fs";import{tmpdir as tr}from"os";import z from"path";import{mkdirSync as ge,readFileSync as He,writeFileSync as we}from"fs";import H from"path";function fe(e){return e.replace(/\\/g,"/").replace(/\.png$/i,"").trim().split("/").filter(Boolean).join("--").replace(/[^A-Za-z0-9-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"slide"}function Y(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function Ye(e){let t=e.trim();return/^#[0-9a-f]{3}$/i.test(t)?`#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`:t}function O(e,t){let r=Ye(e),i=Math.max(0,Math.min(1,t)),o=r.match(/^#([0-9a-f]{6})$/i);if(o){let s=o[1],n=Number.parseInt(s.slice(0,2),16),a=Number.parseInt(s.slice(2,4),16),l=Number.parseInt(s.slice(4,6),16);return`rgba(${n}, ${a}, ${l}, ${i})`}return r.startsWith("rgb(")?r.replace(/^rgb\((.+)\)$/i,`rgba($1, ${i})`):r}function Ge(e){if(e.type==="solid")return e.color||"#000000";let t=e.direction??180,r=e.stops?.map(i=>`${i.color} ${i.offset}%`).join(", ")||"#000000 0%, #111111 100%";return`linear-gradient(${t}deg, ${r})`}function We(e){let t=e.glow;return t?`radial-gradient(circle at 50% 24%, ${O(t,.46)} 0%, ${O(t,.2)} 24%, rgba(0,0,0,0) 62%)`:"none"}function G(e){switch(e){case"tilted-left":return"perspective(2400px) rotateY(10deg) rotateZ(-2deg)";case"tilted-right":return"perspective(2400px) rotateY(-10deg) rotateZ(2deg)";case"cut-bottom":return"translateY(10%) scale(1.08)";case"cut-top":return"translateY(-16%) scale(1.08)";case"straight":default:return"none"}}function ye(...e){let t=e.map(r=>r.trim()).filter(r=>r.length>0&&r!=="none");return t.length>0?t.join(" "):"none"}function W(e){let t=O(e.color,e.opacity),r=O(e.color,e.opacity*.52);return`drop-shadow(0 34px ${e.spread}px ${r}) drop-shadow(0 0 ${e.blur}px ${t})`}function q(e,t){return!t.glow||e.color&&e.color!==P.color?e:{...e,color:t.glow}}function qe(e,t){if(e==="editorial-left"){let o=Math.round(t.height*.056),s=Math.round(t.height*.022);return{copyStyle:["position:absolute",`top:${Math.round(t.height*.12)}px`,`left:${Math.round(t.width*.085)}px`,`width:${Math.round(t.width*.42)}px`,"text-align:left","z-index:3"].join(";"),titleStyle:`font-size:${o}px;line-height:0.92;`,subStyle:`font-size:${s}px;line-height:1.36;max-width:${Math.round(t.width*.36)}px;`,eyebrowStyle:"align-items:flex-start;",deviceStyle:(n,a,l)=>{let c=Math.round(t.width*.68*(a.scale??n.scale)),u=Math.round(t.height*(.03+n.offsetY+(a.offsetY??0))),d=a.pose||n.pose||"tilted-right",m=q(n.shadow,l);return["position:absolute",`top:${Math.round(t.height*.18)+u}px`,`left:${Math.round(t.width*.56)}px`,`width:${c}px`,"transform-origin:center center",`transform:${G(d)}`,`filter:${W(m)}`,"z-index:2"].join(";")}}}if(e==="minimal-bottom"){let o=Math.round(t.height*.041),s=Math.round(t.height*.019);return{copyStyle:["position:absolute",`left:${Math.round(t.width*.12)}px`,`right:${Math.round(t.width*.12)}px`,`bottom:${Math.round(t.height*.085)}px`,"text-align:center","z-index:3"].join(";"),titleStyle:`font-size:${o}px;line-height:0.96;`,subStyle:`font-size:${s}px;line-height:1.34;max-width:${Math.round(t.width*.56)}px;margin:0 auto;`,eyebrowStyle:"align-items:center;",deviceStyle:(n,a,l)=>{let c=Math.round(t.width*.84*(a.scale??n.scale)),u=Math.round(t.height*(n.offsetY+(a.offsetY??0))),d=a.pose||n.pose,m=q(n.shadow,l);return["position:absolute",`top:${Math.round(t.height*.075)+u}px`,"left:50%",`width:${c}px`,"transform-origin:center center",`transform:${ye("translateX(-50%)",G(d))}`,`filter:${W(m)}`,"z-index:2"].join(";")}}}let r=Math.round(t.height*.04),i=Math.round(t.height*.019);return{copyStyle:["position:absolute",`top:${Math.round(t.height*.084)}px`,"left:50%",`width:${Math.round(t.width*.88)}px`,"transform:translateX(-50%)","text-align:center","z-index:3"].join(";"),titleStyle:`font-size:${r}px;line-height:0.92;`,subStyle:`font-size:${i}px;line-height:1.34;max-width:${Math.round(t.width*.6)}px;margin:0 auto;`,eyebrowStyle:"align-items:center;",deviceStyle:(o,s,n)=>{let a=Math.round(t.width*.64*(s.scale??o.scale)),l=Math.round(t.height*(o.offsetY+(s.offsetY??0))),c=s.pose||o.pose,u=q(o.shadow,n);return["position:absolute",`top:${Math.round(t.height*.28)+l}px`,"left:50%",`width:${a}px`,"transform-origin:center top",`transform:${ye("translateX(-50%)",G(c))}`,`filter:${W(u)}`,"z-index:2"].join(";")}}}function Ve({canvas:e,compose:t,slide:r,imageDataUrl:i}){let o=r.background??t.background,s=qe(t.text.preset,e),n=t.text.preset!=="none"&&!!(r.eyebrow||r.headline||r.subheadline),a=s.deviceStyle(t.frame,r,o),l=r.headline?`<div style="font-weight:780;white-space:pre-line;text-wrap:balance;${s.titleStyle}">${Y(r.headline)}</div>`:"",c=r.subheadline?`<div style="margin-top:${Math.round(e.height*.018)}px;color:${t.text.subColor};white-space:pre-line;text-wrap:balance;${s.subStyle}">${Y(r.subheadline)}</div>`:"",u=r.eyebrow?`<div style="display:flex;${s.eyebrowStyle}margin-bottom:${Math.round(e.height*.016)}px;"><div style="font-size:${Math.round(e.height*.014)}px;font-weight:700;letter-spacing:0.18em;text-transform:uppercase;color:${t.text.eyebrowColor};">${Y(r.eyebrow)}</div></div>`:"";return`<!doctype html>
43
+ <html>
44
+ <head>
45
+ <meta charset="utf-8" />
46
+ <style>
47
+ html, body {
48
+ margin: 0;
49
+ width: ${e.width}px;
50
+ height: ${e.height}px;
51
+ overflow: hidden;
52
+ background: transparent;
53
+ }
54
+ body {
55
+ font-family: "SF Pro Display", "Helvetica Neue", system-ui, sans-serif;
56
+ }
57
+ #canvas {
58
+ position: relative;
59
+ width: ${e.width}px;
60
+ height: ${e.height}px;
61
+ overflow: hidden;
62
+ background: ${Ge(o)};
63
+ color: ${t.text.color};
64
+ isolation: isolate;
65
+ }
66
+ #glow {
67
+ position: absolute;
68
+ inset: 0;
69
+ background: ${We(o)};
70
+ pointer-events: none;
71
+ }
72
+ #copy {
73
+ ${s.copyStyle};
74
+ }
75
+ #device {
76
+ ${a};
77
+ }
78
+ #device img {
79
+ display: block;
80
+ width: 100%;
81
+ height: auto;
82
+ }
83
+ </style>
84
+ </head>
85
+ <body>
86
+ <div id="canvas">
87
+ <div id="glow"></div>
88
+ ${n?`<div id="copy">${u}${l}${c}</div>`:""}
89
+ <div id="device"><img src="${i}" alt="" /></div>
90
+ </div>
91
+ </body>
92
+ </html>`}async function be(e,t,r){let i=[],o=r??await(async()=>{let{chromium:n}=await import("playwright");return v(a=>n.launch(a),{headless:!0})})();try{let n=await o.newContext({viewport:{width:1280,height:720}});try{for(let a of t){let c=`data:image/png;base64,${He(a.imagePath).toString("base64")}`;for(let u of e.canvases){let d=await n.newPage();try{await d.setViewportSize({width:u.width,height:u.height}),await d.setContent(Ve({canvas:u,compose:e,slide:a.slide,imageDataUrl:c}),{waitUntil:"load"}),await d.waitForTimeout(20);let m=H.join(e.outDir,u.name,e.locale);ge(m,{recursive:!0});let h=H.join(m,`${a.slide.assetKey}.png`),w=await d.screenshot({type:"png",clip:{x:0,y:0,width:u.width,height:u.height}});we(h,w),i.push({slideId:a.slide.id,canvas:u.name,locale:e.locale,outputPath:h,sourcePath:a.imagePath})}finally{await d.close()}}}}finally{await n.close()}}finally{!r&&typeof o.close=="function"&&await o.close()}ge(e.outDir,{recursive:!0});let s=H.join(e.outDir,"manifest.json");return we(s,JSON.stringify({generatedAt:new Date().toISOString(),locale:e.locale,outputs:i},null,2)),{manifestPath:s,outputs:i.map(n=>n.outputPath),entries:i}}function N(e){return typeof e=="string"&&e.length>0?e:void 0}async function Se(e){let r=`${e.origin.replace(/\/$/,"")}/api/sootsim/screenshot-decks?org=${encodeURIComponent(e.org)}&repo=${encodeURIComponent(e.repo)}`,i=await fetch(r,{headers:{Authorization:e.authHeader}});if(!i.ok){let a=await i.text().catch(()=>"");throw new Error(`org deck fetch failed (${i.status} ${i.statusText}) for ${e.org}/${e.repo}${a?` \u2014 ${a.slice(0,200)}`:""}`)}let s=(await i.json()).decks?.[0];if(!s||!s.config||typeof s.config!="object")return null;let n=s.config.frames;return Array.isArray(n)?n.map(a=>{let l=a??{};return{title:N(l.title),subtitle:N(l.subtitle),bgTop:N(l.bgTop),bgBottom:N(l.bgBottom),titleColor:N(l.titleColor)}}):null}function xe(e,t){e.compose.slides.forEach((r,i)=>{let o=t[i];if(o&&(o.title!=null&&(r.headline=o.title),o.subtitle!=null&&(r.subheadline=o.subtitle),o.bgTop&&o.bgBottom)){let s={type:"gradient",direction:180,stops:[{offset:0,color:I(o.bgTop)},{offset:1,color:I(o.bgBottom)}]};r.background=s}})}import{readFileSync as Ke}from"fs";import k from"path";function g(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function T(e,t){if(!g(e))throw new Error(`${t} must be an object`);return e}function b(e,t=""){return typeof e=="string"?e:t}function S(e){return typeof e=="string"&&e.trim().length>0?e.trim():null}function Pe(e,t){return typeof e=="boolean"?e:t}function C(e,t){return typeof e=="number"&&Number.isFinite(e)?e:t}function $e(e,t){return typeof e!="string"||e.trim().length===0?t:Object.prototype.hasOwnProperty.call(F,e)?e:null}function ke(e,t){if(typeof e=="string"){let o=R(e);if(!o)throw new Error(`unknown background preset: ${e}`);return o}if(!g(e))return U(t);let r=e.type==="solid"||e.type==="gradient"?e.type:t.type;if(r==="solid")return{type:r,color:b(e.color,t.color??"#000000"),glow:S(e.glow)??t.glow};let i=Array.isArray(e.stops)?e.stops.map(o=>{if(!g(o))return null;let s=C(o.offset,Number.NaN),n=S(o.color);return!Number.isFinite(s)||!n?null:{offset:s,color:n}}).filter(o=>!!o):t.stops?.map(o=>({...o}))??[];return{type:r,direction:C(e.direction,t.direction??180),glow:S(e.glow)??t.glow,stops:i.length>0?i:t.stops?.map(o=>({...o}))??[]}}function Xe(e){let r=(Array.isArray(e)?e:["iphone-6-9"]).map(i=>{if(typeof i!="string")throw new Error("compose.canvases entries must be strings");let o=L(i);if(!o)throw new Error(`unknown canvas preset: ${i}`);return o});if(r.length===0)throw new Error("compose.canvases must include at least one preset");return r}function Je(e){switch(e){case"editorial-left":case"minimal-bottom":case"none":case"bold-top":return e;default:return"bold-top"}}function Ze(e){switch(e){case"plan":case"flow":case"auto":return e;default:return"auto"}}function ve(e){switch(e){case"straight":case"tilted-left":case"tilted-right":case"cut-bottom":case"cut-top":return e;default:return}}function D(e,t){return k.isAbsolute(t)?t:k.resolve(e,t)}function Qe(e,t){if(!Array.isArray(e)||e.length===0)throw new Error("compose.slides must be a non-empty array");return e.map((r,i)=>{let o=T(r,`compose.slides[${i}]`),s=S(o.screenshot);if(!s)throw new Error(`compose.slides[${i}].screenshot is required`);let n=S(o.id),a=fe(n||s);return{id:n||a,assetKey:a,screenshot:s,headline:b(o.headline),subheadline:b(o.subheadline),eyebrow:b(o.eyebrow),pose:ve(o.pose),scale:typeof o.scale=="number"&&Number.isFinite(o.scale)?o.scale:void 0,offsetY:typeof o.offsetY=="number"&&Number.isFinite(o.offsetY)?o.offsetY:void 0,background:o.theme||o.background?ke(o.theme??o.background,t):void 0}})}function Ce(e){let t=k.resolve(e),r=k.dirname(t),i=te.parse(Ke(t,"utf8")),o=T(i,"screenshots plan"),s=T(o.capture??{},"capture"),n=T(o.compose??{},"compose"),a=typeof o.app=="number"?String(o.app):S(o.app),l=$e(o.device,null),c=D(r,b(s.out,k.join(".sootsim","screenshots","capture"))),u=S(s.from),d=S(s.flow);if(!u&&!d)throw new Error("capture.flow or capture.from is required");let m=s.mode==="raw"||s.mode==="framed"||s.mode==="raw+framed"?s.mode:"raw+framed",h=Ze(s.pathMode),w=ke(n.background??"cyan",R("cyan")),p={show:Pe(n.frame&&g(n.frame)?n.frame.show:void 0,!0),style:$e(n.frame&&g(n.frame)?n.frame.style:null,null)||l||j,pose:ve(n.frame&&g(n.frame)?n.frame.pose:void 0)||"straight",scale:C(n.frame&&g(n.frame)?n.frame.scale:void 0,1),offsetY:C(n.frame&&g(n.frame)?n.frame.offsetY:void 0,0),shadow:{color:b(n.frame&&g(n.frame)&&g(n.frame.shadow)?n.frame.shadow.color:void 0,P.color),blur:C(n.frame&&g(n.frame)&&g(n.frame.shadow)?n.frame.shadow.blur:void 0,P.blur),spread:C(n.frame&&g(n.frame)&&g(n.frame.shadow)?n.frame.shadow.spread:void 0,P.spread),opacity:C(n.frame&&g(n.frame)&&g(n.frame.shadow)?n.frame.shadow.opacity:void 0,P.opacity)}};return{planPath:t,planDir:r,appTarget:a,deviceModel:l,capture:{flowPath:d?D(r,d):null,fromDir:u?D(r,u):null,outDir:c,rawDir:u?D(r,u):k.join(c,"raw"),framedDir:k.join(c,"framed"),mode:m,pathMode:h,simId:S(s.sim),openInNewSim:Pe(s.new,!1)},compose:{outDir:D(r,b(n.out,k.join(".sootsim","screenshots","exports"))),locale:b(n.locale,"en"),canvases:Xe(n.canvases),frame:p,background:w,text:{preset:Je(n.text&&g(n.text)?n.text.preset:void 0),color:b(n.text&&g(n.text)?n.text.color:void 0,"#ffffff"),subColor:b(n.text&&g(n.text)?n.text.subColor:void 0,"rgba(232,240,247,0.86)"),eyebrowColor:b(n.text&&g(n.text)?n.text.eyebrowColor:void 0,"rgba(229,242,255,0.72)")},slides:Qe(n.slides,w)}}}function tt(e){return e.capture.pathMode==="plan"||e.capture.pathMode==="flow"?e.capture.pathMode:e.capture.fromDir?"flow":"plan"}function rt(e,t){if(!e.capture.flowPath)throw new Error("capture flow path is required to build flow args");let r=[e.capture.flowPath],i=tt(e);r.push("--screenshots",e.capture.rawDir),i==="flow"&&r.push("--screenshot-paths","flow");let o=t.appTarget??e.appTarget,s=t.deviceModel??e.deviceModel,n=t.simId??e.capture.simId;return o&&r.push("--url",o),s&&r.push("--device",s),n&&r.push("--sim",n),e.capture.openInNewSim&&r.push("--new"),r}function _(e,t){return z.isAbsolute(t)?t:z.join(e.capture.rawDir,t)}function ot(e){return z.join(e.capture.outDir,"manifest.json")}async function nt(e,t){if(!e.capture.flowPath)return;V(e.capture.rawDir,{recursive:!0});let r=rt(e,t),i=await ie(r);if(i!==0)throw new Error(`flow capture failed with exit code ${i}`)}async function st(e,t){let r=new Map;V(e.capture.framedDir,{recursive:!0});let i=t??await(async()=>{let{chromium:o}=await import("playwright");return v(s=>o.launch(s),{headless:!0})})();try{let o=await se(i);try{for(let s of e.compose.slides){let n=_(e,s.screenshot),a=et(n),l=await o.compose(a,e.compose.frame.style),c=z.join(e.capture.framedDir,`${s.assetKey}.png`);Me(c,l),r.set(s.id,c)}}finally{await o.close()}}finally{!t&&typeof i.close=="function"&&await i.close()}return r}function it(e,t,r){let i=[],o=[];V(e.capture.outDir,{recursive:!0});let s=ot(e),n=e.compose.slides.map(a=>{let l=_(e,a.screenshot),c=t.get(a.id)??null;return i.push(l),c&&o.push(c),{id:a.id,screenshot:a.screenshot,rawPath:l,framedPath:c}});return Me(s,JSON.stringify({generatedAt:new Date().toISOString(),deviceModel:r,mode:e.capture.mode,rawDir:e.capture.rawDir,framedDir:e.capture.framedDir,slides:n},null,2)),{manifestPath:s,rawDir:e.capture.rawDir,framedDir:e.capture.framedDir,rawFiles:i,framedFiles:o}}function at(e,t){return e.compose.slides.map(r=>({slide:r,imagePath:e.compose.frame.show===!0?t.get(r.id)??_(e,r.screenshot):_(e,r.screenshot)}))}async function Ne(e,t={}){let r=Ce(e);t.orgDeckFrames&&t.orgDeckFrames.length>0&&xe(r,t.orgDeckFrames);let i=t.deviceModel??r.deviceModel;t.composeOnly||await nt(r,t);let o=r.capture.mode!=="raw"||!t.captureOnly&&r.compose.frame.show===!0,n=o||!t.captureOnly?await(async()=>{let{chromium:a}=await import("playwright");return v(l=>a.launch(l),{headless:!0})})():null;try{let a=o?await st(r,n??void 0):new Map,l=it(r,a,i);if(t.captureOnly)return{plan:r,capture:l,compose:null};let c=at(r,a),u=await be(r.compose,c,n??void 0);return{plan:r,capture:l,compose:u}}finally{n&&typeof n.close=="function"&&await n.close()}}async function De(e,t={}){if(e.includes("--help")||e.includes("-h"))return console.log(`
93
+ rnxsim screenshot appstore \u2014 capture and compose app-store screenshot sets
94
+
95
+ usage:
96
+ rnxsim screenshot appstore --plan <plan.yaml> [options]
97
+
98
+ options:
99
+ --plan <path> screenshot plan yaml
100
+ --sim <id> reuse a live sim for capture
101
+ --app <target> override plan app target (port, url, or shell url)
102
+ --device <model> override plan capture device for this run
103
+ --org <slug> overlay copy/colors from a team's org screenshot deck
104
+ --repo <name> repo for --org (both required to pull the org deck)
105
+ --api-origin <url> contrast origin to fetch the deck from (default: the
106
+ signed-in session origin, else https://contrast.dev)
107
+ --capture-only stop after raw/framed intermediates
108
+ --compose-only skip flow capture, reuse existing raw screenshots
109
+
110
+ examples:
111
+ rnxsim screenshot appstore --plan app-store.yaml
112
+ rnxsim screenshot appstore --plan app-store.yaml --sim a9
113
+ rnxsim screenshot appstore --plan app-store.yaml --org acme --repo mobile
114
+ `),0;let r=p=>e.find((y,f)=>e[f-1]===p),i=new Set(["--plan","--sim","--app","--device","--org","--repo","--api-origin"]),o=e.filter((p,y)=>{if(p.startsWith("-"))return!1;let f=e[y-1];return!f||!i.has(f)}),s=r("--plan")||o[0];if(!s)return console.error(" error: screenshots plan path is required (`--plan <path>`)."),1;let n=r("--sim")?.trim()||null,a=r("--app")?.trim()||null,l=r("--device")?.trim()||null,c=r("--org")?.trim()||null,u=r("--repo")?.trim()||null,d=r("--api-origin")?.trim()||null,m=e.includes("--capture-only"),h=e.includes("--compose-only"),w=null;if(c||u){if(!c||!u)return console.error(" error: --org and --repo must be passed together."),1;let p=re();if(!p)return console.error(" error: --org/--repo needs auth \u2014 run `rnxsim login` or set RNX_API_KEY."),1;let y=d||(p.kind==="session"?p.origin:"https://contrast.dev");try{w=await Se({org:c,repo:u,origin:y,authHeader:oe(p)})}catch(f){return console.error(` ${f.message}`),1}!w||w.length===0?console.log(` note: no org deck for ${c}/${u} \u2014 composing with the plan's copy/colors.`):console.log(` org deck: ${w.length} slide(s) from ${c}/${u}`)}try{let p=await Ne(s,{simId:n,appTarget:a,deviceModel:l,captureOnly:m,composeOnly:h,orgDeckFrames:w});return console.log(` capture manifest: ${p.capture.manifestPath}`),p.compose?(console.log(` compose manifest: ${p.compose.manifestPath}`),console.log(` exports: ${p.compose.outputs.length}`)):console.log(" compose skipped"),0}catch(p){return console.error(` screenshots failed: ${p.message}`),1}}import{mkdirSync as lt,writeFileSync as ct}from"node:fs";import{dirname as ut,isAbsolute as dt,join as Ee,resolve as pt}from"node:path";var mt=`
115
+ rnxsim screenshot slides \u2014 compose App Store screenshots in the live sim
116
+
117
+ usage:
118
+ rnxsim screenshot slides list slides (alias: slides list)
119
+ rnxsim screenshot slides set <n> [fields] patch a slide's copy/colors
120
+ rnxsim screenshot slides add append a blank slide (focuses it)
121
+ rnxsim screenshot slides remove <n> delete a slide
122
+ rnxsim screenshot slides move <n> <position> reorder a slide
123
+ rnxsim screenshot slides focus <n> open a slide (device flips into it)
124
+ rnxsim screenshot slides overview back to the gallery
125
+ rnxsim screenshot slides capture [<n>] capture the live frame into a slide
126
+ rnxsim screenshot slides export [<n>] [--out <dir>]
127
+ write composed App-Store PNG(s)
128
+
129
+ set fields:
130
+ --title <text> headline
131
+ --subtitle <text> subheadline
132
+ --bg-top <color> gradient top (white gray slate black cyan blue
133
+ --bg-bottom <color> gradient bottom teal green lime gold orange coral
134
+ --title-color <color> copy color override, or "auto" red berry magenta
135
+ --title-size <s> sm | md | lg | none gray-light
136
+ --underlay <s> black | white | none gray-dark \u2026)
137
+ --shadow <s> light | medium | strong | none
138
+
139
+ notes:
140
+ slides are addressed by 1-based index. screenshot mode is auto-enabled.
141
+ capture shoots whatever the sim currently shows \u2014 navigate the app first
142
+ (rnxsim do tap-id \u2026), then capture.
143
+
144
+ examples:
145
+ rnxsim screenshot slides set 1 --title "The ultimate MMA community." --bg-top cyan --bg-bottom black
146
+ rnxsim screenshot slides capture 1
147
+ rnxsim screenshot slides export --out ./exports
148
+ `,ht={"--title":"title","--subtitle":"subtitle","--bg-top":"bgTop","--bg-bottom":"bgBottom","--title-color":"titleColor","--title-size":"titleSize","--underlay":"titleUnderlay","--shadow":"titleShadow","--out":"out"};function ft(e){let t=[],r={},i=!1;for(let o=0;o<e.length;o+=1){let s=e[o];if(s==="--json"){i=!0;continue}let n=s.indexOf("="),a=n>0?s.slice(0,n):s,l=ht[a];if(l){n>0?r[l]=s.slice(n+1):(r[l]=e[o+1]??"",o+=1);continue}t.push(s)}return{rest:t,values:r,json:i}}function gt(e){if(!e)return;let t=Number(e);return Number.isInteger(t)&&t>0?t:e}async function wt(e){if(!await Q(e,`(async () => {
149
+ if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
150
+ window.dispatchEvent(new CustomEvent('sootsim:shell-command', {
151
+ detail: { type: 'fire-action', id: 'toggle-screenshot-mode' },
152
+ }))
153
+ const deadline = Date.now() + 2000
154
+ while (Date.now() < deadline) {
155
+ if (window.SootSim?.bridges?.settings?.get?.()?.screenshotMode) return true
156
+ await new Promise((r) => setTimeout(r, 40))
157
+ }
158
+ return false
159
+ })()`,{acquireLock:!0}))throw new Error("could not enable screenshot mode \u2014 is this a browser sim with the screenshot plugin? (electron has no screenshot mode)")}function yt(e){console.log(` ${e.projectName} \u2014 canvas ${e.canvas} (${e.exportSize.width}\xD7${e.exportSize.height}), device ${e.deviceModel}`);for(let t of e.slides){let r=[t.focused?"focused":t.active?"active":null,t.captured?`captured${t.captureMode==="3d"?" 3d":""}`:"no capture"].filter(Boolean).join(", "),i=t.title?`"${t.title}"`:"(no title)",o=[`bg ${t.bgTop}\u2192${t.bgBottom}`,t.titleColor?`color ${t.titleColor}`:null,t.titleSize?`size ${t.titleSize}`:null,t.titleUnderlay?`underlay ${t.titleUnderlay}`:null,t.titleShadow?`shadow ${t.titleShadow}`:null].filter(Boolean).join(", ");console.log(` ${t.index}. ${i} \u2014 ${o} [${r}]`),t.subtitle&&console.log(` ${t.subtitle}`)}}function bt(e){let t=e.match(/^data:[^;]+;base64,(.+)$/);if(!t)throw new Error("export returned an unexpected payload");return Buffer.from(t[1],"base64")}async function Fe(e,t){if(e.includes("--help")||e.includes("-h")){console.log(mt);return}let{rest:r,values:i,json:o}=ft(e),s=A(r,{port:t.port,commandTimeoutMs:45e3}),n=s.positional[0]??"list",a=gt(s.positional[1]),l=Number(s.positional[2]),c=B(s),u=d=>{o?console.log(JSON.stringify(d,null,2)):yt(d)};try{switch(await wt(c),n){case"list":{u(await M(c,"SootSim.bridges.screenshotControl.getState"));break}case"set":{if(a==null)throw new Error("usage: rnxsim screenshot slides set <n> --title \u2026 (see --help)");let d={};for(let m of["title","subtitle","bgTop","bgBottom","titleColor","titleSize","titleUnderlay","titleShadow"])i[m]!=null&&(d[m]=i[m]);if(Object.keys(d).length===0)throw new Error("nothing to set \u2014 pass at least one field (see --help)");u(await $(c,"SootSim.bridges.screenshotControl.setSlide",a,d));break}case"add":{u(await $(c,"SootSim.bridges.screenshotControl.addSlide"));break}case"remove":{if(a==null)throw new Error("usage: rnxsim screenshot slides remove <n>");u(await $(c,"SootSim.bridges.screenshotControl.removeSlide",a));break}case"move":{if(a==null||!Number.isInteger(l)||l<1)throw new Error("usage: rnxsim screenshot slides move <n> <position>");u(await $(c,"SootSim.bridges.screenshotControl.moveSlide",a,l));break}case"focus":{if(a==null)throw new Error("usage: rnxsim screenshot slides focus <n>");u(await $(c,"SootSim.bridges.screenshotControl.focusSlide",a));break}case"overview":{u(await $(c,"SootSim.bridges.screenshotControl.overview"));break}case"capture":{let d=await $(c,"SootSim.bridges.screenshotControl.capture",...a!=null?[a]:[]);u(d);break}case"export":{let d=i.out?dt(i.out)?i.out:pt(process.cwd(),i.out):Ee(process.cwd(),"screenshots"),m=await M(c,"SootSim.bridges.screenshotControl.getState"),h=a!=null?m.slides.filter(p=>p.index===a||p.id===a):m.slides.filter(p=>p.captured);if(h.length===0)throw new Error(a!=null?`no slide ${a}`:"no captured slides to export \u2014 capture first");let w=[];for(let p of h){let y=await M(c,"SootSim.bridges.screenshotControl.exportSlide",p.index),f=Ee(d,y.name);lt(ut(f),{recursive:!0}),ct(f,bt(y.dataUrl)),w.push(f),console.log(` saved: ${f} (${y.width}\xD7${y.height})`)}o&&console.log(JSON.stringify({written:w},null,2));break}default:throw new Error(`unknown subcommand "${n}" \u2014 see rnxsim screenshot slides --help`)}}finally{c.close()}}var St=new Set(["--sim","--port","-p","--output","-o","--out","--plan","--app","--device","--org","--repo","--api-origin","--branch","--platform","--slides","--shell-origin","--timeout","--ids","--out-dir"]),xt=new Set(["capture","slides","appstore","layers"]);function Re(e){for(let t=0;t<e.length;t++){let r=e[t];if(r.startsWith("-")){St.has(r)&&t++;continue}return xt.has(r)?{name:r,index:t}:null}return null}function E(e,t){return[...e.slice(0,t),...e.slice(t+1)]}function Pt(e){let t=[];for(let r=0;r<e.length;r++){if(e[r]==="--sim"){r++;continue}t.push(e[r])}return t}async function xr(e,t){let r=Re(e);if(!r||r.name==="capture"){await pe(r?E(e,r.index):e,t);return}if(r.name==="slides"){await Fe(E(e,r.index),t);return}if(r.name==="layers"){let{runScreenshotLayers:s}=await import("./screenshot-layers-OQFMFVRL.js");await s(E(e,r.index),t);return}let i=E(e,r.index),o=Re(i);if(o?.name==="capture")try{let{runScreenshotsCapture:s}=await import("./screenshots-capture-6TSRJFGB.js");return await s(Pt(E(i,o.index)))}catch(s){if(s instanceof Error&&"code"in s&&s.code==="ERR_MODULE_NOT_FOUND")return console.error("screenshot appstore capture is repo-only tooling \u2014 it needs the rnx workspace (playwright is not shipped with the published CLI)."),1;throw s}return De(i,t)}export{xr as runScreenshotCommand};
@@ -0,0 +1,20 @@
1
+ /*! rnx v0.1.312 | (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 S}from"./chunk-Y2FSZSO7.js";import"./chunk-274UD5FD.js";import{r as y,s as v}from"./chunk-TGQNQ6XT.js";import"./chunk-4BXCZHAU.js";import{h as w,j as b,m as I}from"./chunk-7INBNA3U.js";import"./chunk-TYE3WBSR.js";import{b as m}from"./chunk-5OX7ANRA.js";import"./chunk-33FKQH54.js";import"./chunk-7VWOSTD5.js";import"./chunk-66NF2KNG.js";import"./chunk-MENV7VLD.js";import{mkdirSync as B,writeFileSync as R}from"fs";import{resolve as f}from"path";async function L(s,$){(s.includes("--help")||s.includes("-h"))&&(console.log(`
5
+ sootsim screenshot layers \u2014 export a screen as engine-isolated layers
6
+
7
+ usage:
8
+ sootsim screenshot layers --ids <testID,testID,...> [--out-dir <dir>]
9
+
10
+ options:
11
+ --ids <list> comma-separated testIDs of the subtrees to isolate
12
+ --out-dir <dir> output directory (default: /tmp/sootsim-layers)
13
+
14
+ output:
15
+ full.png the normal frame
16
+ base.png the frame re-rendered with every listed subtree hidden
17
+ layer-<id>.png each subtree rendered alone on a transparent frame
18
+ manifest.json device metrics + logical rect per layer
19
+ `),process.exit(0));let u=s.find((r,n)=>s[n-1]==="--ids");u||(console.error(" --ids is required (comma-separated testIDs)"),process.exit(1));let i=u.split(",").map(r=>r.trim()).filter(Boolean);i.length===0&&(console.error(" --ids resolved to an empty list"),process.exit(1));let D=s.find((r,n)=>s[n-1]==="--out-dir"),c=f(process.cwd(),D??"/tmp/sootsim-layers"),M=w(s,{port:$.port,stripValueFlags:["--ids","--out-dir"]}),o=b({...M,commandTimeoutMs:45e3});try{let r=await v(o,9e4);if(!r.ready)throw new Error(`app not ready to capture after ${Math.round(r.elapsedMs/1e3)}s (${y(r)})`);let n={};for(let e of i){let t=await o.send({type:"evaluate",code:S({id:e})});if(!t)throw new Error(`no node with testID "${e}"`);n[e]=t}B(c,{recursive:!0});let l=(e,t)=>{if(typeof t!="string"||!t.startsWith("data:image/png;base64,"))throw new Error(`capture for ${e} returned no image data`);let h=f(c,e);R(h,Buffer.from(t.slice(22),"base64")),console.log(` saved: ${h}`)};l("full.png",await o.send({type:"screenshot"})),l("base.png",await o.send({type:"screenshot",captureFilter:{hideTestIds:i}}));for(let e of i)l(`layer-${e}.png`,await o.send({type:"screenshot",captureFilter:{soloTestId:e,hideTestIds:i.filter(t=>t!==e)}}));let p=await I(o,"SootSim.bridges.settings.get")??{deviceModel:null},a=typeof p.deviceModel=="string"&&p.deviceModel in m?p.deviceModel:null,d=a?m[a]:null,x={device:d?{model:a,width:d.width,height:d.height,scale:d.scale}:{model:a},layers:i.map(e=>({testId:e,rect:n[e]}))},g=f(c,"manifest.json");R(g,`${JSON.stringify(x,null,2)}
20
+ `),console.log(` saved: ${g}`)}finally{o.close()}}export{L as runScreenshotLayers};
@@ -0,0 +1,42 @@
1
+ /*! rnx v0.1.312 | (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 U}from"./chunk-2SA2VTGP.js";import{a as M}from"./chunk-BKNOLP3J.js";import"./chunk-TCWQJILS.js";import"./chunk-66NF2KNG.js";import{a as F}from"./chunk-ZMZTHU7V.js";import"./chunk-MENV7VLD.js";import{execSync as N}from"node:child_process";import{mkdirSync as O,mkdtempSync as E,rmSync as j,writeFileSync as G}from"node:fs";import{tmpdir as q}from"node:os";import{dirname as B,isAbsolute as L,join as I,resolve as z}from"node:path";import{chromium as W}from"playwright-core";var H=`
5
+ rnxsim screenshot appstore capture \u2014 headlessly capture + upload App Store slides
6
+
7
+ usage:
8
+ rnxsim screenshot appstore capture --org <org> --repo <repo> [options]
9
+
10
+ what it does:
11
+ boots the org-mode build shell in headless GPU Chrome (authed via your
12
+ \`rnxsim login\` session), captures each slide through the live screenshot
13
+ composer so every slide gets editable layers (captureRef + cleanRef +
14
+ screenRef), and lets the shell auto-upload them to your org deck.
15
+
16
+ options:
17
+ --org <org> github org slug (required)
18
+ --repo <repo> repo name (required)
19
+ --branch <branch> build branch to boot (default: main)
20
+ --platform <p> ios | android (default: ios)
21
+ --slides <list> 1-based indices to capture, e.g. 1,3,5 (default: all)
22
+ --dry-run capture + report refs, do NOT upload (PUTs aborted)
23
+ --force allow overwriting a NON-EMPTY existing deck
24
+ --out <dir> also write composed App-Store PNGs locally
25
+ --shell-origin <url> origin serving /build (default: your session origin)
26
+ --api-origin <url> origin for deck/capture APIs (default: session origin)
27
+ --timeout <ms> per-step bridge timeout (default: 45000)
28
+ --json machine-readable summary
29
+
30
+ examples:
31
+ rnxsim screenshot appstore capture --org acme --repo my-app --dry-run
32
+ rnxsim screenshot appstore capture --org acme --repo my-app --branch main --force
33
+ `;function J(t){let e=a=>{let d=t.indexOf(a);return d>=0?t[d+1]:void 0},n=a=>t.includes(a),s=e("--slides"),i=s?s.split(",").map(a=>Number(a.trim())).filter(a=>Number.isInteger(a)&&a>0):null;return{org:e("--org")??"",repo:e("--repo")??"",branch:e("--branch")??"main",platform:e("--platform")??"ios",slides:i&&i.length?i:null,dryRun:n("--dry-run"),force:n("--force"),out:e("--out")??null,shellOrigin:e("--shell-origin")??null,apiOrigin:e("--api-origin")??null,timeoutMs:Number(e("--timeout")??"45000")||45e3,json:n("--json")}}function Y(){let t=M();if(t&&t.kind==="session")return{token:t.token,origin:t.origin};process.stderr.write(`
34
+ rnxsim screenshot appstore capture needs a logged-in session.
35
+ run \`rnxsim login\` first (the captured slides upload to that account).
36
+
37
+ `),process.exit(1)}function K(t){let e=t.replace(/^\[|\]$/g,"").toLowerCase();return e==="localhost"||e.endsWith(".localhost")||e==="::1"||/^127(?:\.\d{1,3}){3}$/.test(e)}function Q(t){let e=new URL(t);if(K(e.hostname)){let s=(Number(e.port)||3e3)-3e3;if(s>=0&&s<=1e3)return e.port=String(5173+s),e.origin}return e.hostname==="contrast.dev"||e.hostname.endsWith(".contrast.dev")?F.origin:t}function V(){try{return Number(N("sysctl -n vm.loadavg").toString().trim().split(/\s+/)[1])||0}catch{return 0}}async function X(t,e,n,s){let i=await fetch(`${t}/api/sootsim/screenshot-decks?org=${encodeURIComponent(n)}&repo=${encodeURIComponent(s)}`,{headers:{authorization:`Bearer ${e}`}});if(!i.ok)return[];let a=await i.json().catch(()=>null),d=[];for(let g of a?.decks??[])Array.isArray(g.config?.frames)&&d.push(...g.config.frames);return d}async function Z(t,e,n,s){let i=await fetch(`${t}/api/sootsim/screenshot-capture?ref=${encodeURIComponent(s)}&org=${encodeURIComponent(n)}`,{headers:{authorization:`Bearer ${e}`}});return i.ok?`data:image/png;base64,${Buffer.from(await i.arrayBuffer()).toString("base64")}`:null}async function _(t,e){let n=Date.now()+e;for(;Date.now()<n;){for(let s of t.frames())if(await s.evaluate(()=>!!globalThis.SootSim?.bridges?.screenshotControl).catch(()=>!1))return s;await t.waitForTimeout(250)}throw new Error("screenshot bridge never appeared \u2014 the build shell did not boot screenshot mode (check --branch/--platform has a ready build, and you are logged in)")}async function T(t){return t.evaluate(async()=>{let n=globalThis.SootSim?.bridges?.screenshotControl;if(!n)throw new Error("screenshotControl missing");return n.getState()})}async function ee(t){await t.evaluate(async()=>{let e=globalThis.SootSim?.bridges?.settings,n=Date.now()+3e3;for(;Date.now()<n;){if(e?.get?.()?.screenshotMode)return;await new Promise(s=>setTimeout(s,50))}e&&!e.get().screenshotMode&&(e.set("screenshotMode",!0),e.get().showFrame||e.set("showFrame",!0))})}async function te(t,e,n,s){await t.evaluate(async([i,a,d])=>{let g=globalThis.SootSim,h=g?.bridges?.screenshotControl;if(!h)throw new Error("screenshotControl missing");let w=b=>new Promise(u=>setTimeout(u,b));if(a){h.focusSlide(i);let b=Date.now()+3e4,u=g?.bridges?.threeMode;for(;Date.now()<b&&(u=g?.bridges?.threeMode,!(u?.setScreenImage&&u?.captureStage&&u?.getState?.()?.ready));)await w(150);await w(1e3);let c=a;u?.configure?.({colorway:c.colorway,background:c.background,...c.customGradient?{customGradient:c.customGradient}:{},setting:c.setting,focus:c.focus,environment:c.environmentActive?{pins:c.environmentPins??{},effects:c.environmentEffects??{}}:!1,pose:{phonePosition:c.phonePosition,phoneRotation:c.phoneRotation,cameraPosition:c.cameraPosition,target:c.target}}),await w(900),d&&u?.setScreenImage&&(u.setScreenImage(d),await w(1200))}await h.capture(i)},[e,n,s])}async function ge(t){if(t.includes("--help")||t.includes("-h"))return console.log(H),0;let e=J(t);if(!e.org||!e.repo)return process.stderr.write(` --org and --repo are required (see --help)
38
+ `),1;let{token:n,origin:s}=Y(),i=(e.apiOrigin??s).replace(/\/$/,""),a=(e.shellOrigin??Q(i)).replace(/\/$/,""),d=await X(i,n,e.org,e.repo);if(!e.dryRun&&!e.force&&d.length>0)return process.stderr.write(` refusing to overwrite the existing ${e.org}/${e.repo} deck (${d.length} slide(s)). re-run with --force to replace it, or --dry-run to preview.
39
+ `),1;let g=V(),h=Number(N("sysctl -n hw.ncpu").toString().trim())||8;if(g>h)return process.stderr.write(` load average ${g.toFixed(1)} exceeds ${h} cores \u2014 tear down other work first.
40
+ `),1;let w=`${a}/build/${encodeURIComponent(e.org)}/${encodeURIComponent(e.repo)}/${encodeURIComponent(e.branch)}?platform=${encodeURIComponent(e.platform)}&ssMode=1`,b=E(I(q(),"sootsim-capture-")),{browser:u,reapNow:c}=await U(o=>W.launchPersistentContext(b,o),{headless:!0,viewport:{width:393,height:852},deviceScaleFactor:3,args:["--hide-scrollbars"]});await u.addInitScript(o=>{try{localStorage.setItem("sootsim.session.token",o)}catch{}},n);let y=[],p=u.pages()[0]??await u.newPage();e.dryRun?await p.route(/\/api\/sootsim\/screenshot-(decks|capture)/,o=>o.request().method()==="PUT"?o.abort():o.continue()):p.on("response",o=>{let m=o.url();o.request().method()==="PUT"&&(m.includes("/api/sootsim/screenshot-decks")?y.push({kind:"deck",status:o.status()}):m.includes("/api/sootsim/screenshot-capture")&&y.push({kind:"capture",status:o.status()}))});let R=[];p.on("pageerror",o=>R.push(o.message));let A=p.waitForResponse(o=>o.url().includes("/api/sootsim/screenshot-decks")&&o.request().method()==="GET",{timeout:e.timeoutMs}).catch(()=>null);try{await p.goto(w,{waitUntil:"domcontentloaded",timeout:e.timeoutMs});let o=await _(p,e.timeoutMs);await ee(o),await A,await p.waitForTimeout(800);let m=await T(o);if(m.slides.length===0)return process.stderr.write(` the deck has no slides to capture \u2014 add slides in the composer first.
41
+ `),1;let $=e.slides?m.slides.filter(r=>e.slides.includes(r.index)):m.slides;console.log(` ${m.projectName} on ${m.deviceModel} \u2014 capturing ${$.length}/${m.slides.length} slide(s)${e.dryRun?" (dry-run, no upload)":""}`);for(let r of $)try{let l=d[r.index-1],f=l?.threeScene??null,C=f&&l?.screenRef?await Z(i,n,e.org,l.screenRef):null;await te(o,r.index,f,C),console.log(` \u2713 slide ${r.index} "${r.title.slice(0,40)}"`)}catch(l){console.log(` \u2717 slide ${r.index} "${r.title.slice(0,40)}" \u2014 ${l.message}`)}e.dryRun||await p.waitForTimeout(2500);let S=(await T(o)).slides.filter(r=>$.some(l=>l.id===r.id)),v=[];if(e.out){let r=L(e.out)?e.out:z(process.cwd(),e.out);for(let l of S){if(!l.captureRef)continue;let f=await o.evaluate(async k=>{let x=globalThis.SootSim?.bridges?.screenshotControl;if(!x)throw new Error("screenshotControl missing");return x.exportSlide(k)},l.index),C=f.dataUrl.match(/^data:[^;]+;base64,(.+)$/);if(C){let k=I(r,f.name);O(B(k),{recursive:!0}),G(k,Buffer.from(C[1],"base64")),v.push(k)}}}let P=S.filter(r=>r.captureRef&&r.cleanRef),D={org:e.org,repo:e.repo,branch:e.branch,dryRun:e.dryRun,slides:S.map(r=>({index:r.index,title:r.title,captureRef:!!r.captureRef,cleanRef:!!r.cleanRef,screenRef:!!r.screenRef,captureMode:r.captureMode})),editableCount:P.length,uploads:e.dryRun?"skipped (dry-run)":y,written:v,pageErrors:R.slice(0,5)};if(e.json)console.log(JSON.stringify(D,null,2));else{console.log(`
42
+ ${P.length}/${S.length} slide(s) now have editable layers (captureRef + cleanRef)`);let r=S.filter(l=>l.captureRef&&!l.cleanRef);if(r.length&&console.log(` \u26A0 ${r.length} slide(s) baked a flat capture only (no cleanRef) \u2014 typically 3d slides whose scene didn't restore for a re-bake.`),!e.dryRun){let l=y.filter(f=>f.status>=200&&f.status<300).length;console.log(` uploads: ${l}/${y.length} PUT(s) succeeded`)}v.length&&console.log(` wrote ${v.length} local PNG(s) to ${e.out}`),R.length&&console.log(` \u26A0 ${R.length} page error(s) during capture`)}return 0}finally{await u.close().catch(()=>{}),c(),j(b,{recursive:!0,force:!0})}}export{ge as runScreenshotsCapture};
@@ -0,0 +1,44 @@
1
+ /*! rnx v0.1.312 | (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 Se,c as J,d as ye,e as V,f as ve,h as be,i as P,j as we,k as Ae,l as ke,m as Te,q as Ce,t as k,u as Ie,v as Ee,w as Pe,x as Re}from"./chunk-TBMVBI26.js";import"./chunk-DM6KUAOZ.js";import{e as ge}from"./chunk-NPVGMH2N.js";import"./chunk-BKNOLP3J.js";import{a as ue,b as pe,d as me,e as L,f as he}from"./chunk-SI3BUTQR.js";import{d as fe}from"./chunk-T4FT6CM7.js";import{g as _}from"./chunk-YZRFF4YA.js";import"./chunk-FWYYCUAZ.js";import"./chunk-3D57IBPC.js";import"./chunk-7INBNA3U.js";import{a as F,b as G,c as oe,d as ae}from"./chunk-N6A3SXMR.js";import"./chunk-TCWQJILS.js";import{f as O}from"./chunk-U4PN6JOT.js";import{c as de,d as le}from"./chunk-33FKQH54.js";import"./chunk-7VWOSTD5.js";import{E as Y,G as x,H as j,I as Z,J as Q,K as ee,M as te,P as ie,Q as re,R as ne,S as $,T as se,g as q,h as z,y as W,z as X}from"./chunk-66NF2KNG.js";import{a as ce}from"./chunk-EUAVBTKU.js";import"./chunk-ZMZTHU7V.js";import"./chunk-MENV7VLD.js";import{spawn as yt}from"child_process";import C from"fs";import{createServer as vt}from"http";import b from"path";import{WebSocket as g,WebSocketServer as bt}from"ws";import Oe from"node:fs";import B from"node:path";import{spawn as Ke}from"node:child_process";function Ge(o){return typeof o.text=="string"?o.text.trim():""}function qe(o){let e=o?.trim();return e||"tm"}async function xe(o){let e=o.sessionId.trim();if(!G(e))throw new Error(`invalid Team Machine session id: ${e||"<empty>"}`);let t=Ge(o.prompt);if(!t)throw new Error("prompt text is empty");let i=qe(o.command),s=o.timeoutMs??15e3;await new Promise((n,c)=>{let r=Ke(i,["send",e,t],{stdio:["ignore","ignore","pipe"],env:process.env}),a="",d=setTimeout(()=>{try{r.kill("SIGTERM")}catch{}c(new Error(`tm send timed out after ${Math.round(s/1e3)}s`))},s);r.stderr?.setEncoding("utf8"),r.stderr?.on("data",l=>{a.length<4e3&&(a+=String(l))}),r.on("error",l=>{clearTimeout(d),c(l)}),r.on("exit",(l,u)=>{if(clearTimeout(d),l===0){n();return}let p=a.trim();c(new Error(p||`tm send exited with ${u?`signal ${u}`:`code ${l??"unknown"}`}`))})})}var M=1,ze=25;function Xe(){return[Number(process.env.VITE_PORT_WEB||process.env.PORT||3e3),Number(process.env.VITE_PORT_ZERO||7849),Number(process.env.VITE_PORT_R2||9500)].filter(o=>Number.isFinite(o)&&o>0)}var D=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;pendingSessionStates=new Map;pendingSessionPatches=new Map;sessionStatusPersistTimer=null;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof k?this.respondError(e,s,n.message,n.code):this.respondError(e,s,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await Te()}catch(e){process.stderr.write(`[sootsim-agent] seedFromDemoAppRegistry failed: ${e instanceof Error?e.message:String(e)}
5
+ `)}}close(){this.sessionStatusPersistTimer&&(clearTimeout(this.sessionStatusPersistTimer),this.sessionStatusPersistTimer=null),this.flushSessionStatuses();for(let e of this.subscriptions.values())try{e.unsubscribe()}catch{}this.subscriptions.clear(),this.sessionsBySocket.clear(),this.allSockets.clear()}async dispatch(e,t,i){switch(t){case"agent:list-projects":return V();case"agent:upsert-project":return J(i.input??{});case"agent:delete-project":return be(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return we(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-claimed-prompt":return this.sendClaimedPrompt(i);case"agent:send-prompt":{let n=String(i.sessionId),c=P(n);if(!c)throw new k("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await Ee(n,r),this.notePromptAccepted(n,r,c.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await Pe(String(i.sessionId));let s=P(String(i.sessionId));return s&&this.broadcastSessionStatus(s),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(i.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(i.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(i.sessionId));default:throw new k("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async sendClaimedPrompt(e){let t=typeof e.simId=="string"?e.simId.trim():"";if(!t)throw new k("NO_SIM","agent:send-claimed-prompt requires simId");let i=this.opts.resolveCliLease?.(t)??null;if(!i||i.kind!=="cli"||i.expiresAt<=Date.now())throw new k("NO_CLAIM",`sim ${t} has no active CLI claim`);let s=F(i.cliIdentityKey);if(!s)throw new k("UNSUPPORTED_CLAIM",`sim ${t} is claimed by a CLI identity that is not promptable`);return await xe({sessionId:s,prompt:this.normalizePromptEnvelope(e)}),{ok:!0,routed:"team-machine",sessionId:s}}async doStartSession(e){if(!ye(e.projectId))throw new k("NO_PROJECT",`no project: ${e.projectId}`);let i=await Ie(e);return this.broadcastSessionStatus(i.session),i}async autoAttachForUrl(e){let t=e.bundleUrl??"",i=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!i)return{project:null};let s=this.opts.getExcludePorts?.()??Xe(),c=(await _({excludePorts:s})).find(l=>String(l.port)===i);if(!c||!c.cwd)return{project:null};let r=V().find(l=>l.cwd===c.cwd)??null,a=Array.from(new Set([...r?.knownBundleUrls??[],c.bundleUrl,t]));return{project:J({cwd:c.cwd,name:c.projectName??B.basename(c.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[c.cwd],knownBundleUrls:a,framework:r?.framework??Ye(c.framework),bundleId:c.bundleId??r?.bundleId})}}getTranscript(e){let t=Ce(e);return Oe.existsSync(t)?Oe.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=Se();return{userDataDir:e,storeFile:B.join(e,"attached-projects.json"),sessionsDir:B.join(e,"sessions"),transcriptsDir:B.join(e,"transcripts")}}subscribeSocket(e,t){let i=this.sessionsBySocket.get(e);if(i||(i=new Set,this.sessionsBySocket.set(e,i)),i.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};i.add(t);let s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=Re(t,c=>{let r=this.coalescePromptEcho(t,c);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),c.type==="turn-completed"){let a=P(t);if(a)try{ve(a.projectId,{usd:c.costUsd,ts:c.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
6
+ `)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let c=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,c);let r=t.displayText??t.text;return this.patchSession(e,{lastPrompt:r,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:r,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:s}),{ok:!0,queued:c>1,pendingTurns:c,queueDepth:Math.max(0,c-1)}}applySessionEvent(e,t){switch(t.type){case"prompt-received":case"turn-started":this.patchSession(e,{status:"working",needsAttention:!1});return;case"turn-completed":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"idle",needsAttention:!1,lastTurnFiles:t.filesTouched,currentlyEditing:void 0});return}case"approval-needed":this.patchSession(e,{status:"needs-attention",needsAttention:!0});return;case"error":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"needs-attention",needsAttention:i<=0,currentlyEditing:void 0});return}case"exited":this.clearPromptTracking(e),this.patchSession(e,{status:"ended",needsAttention:!1,wrapperPid:void 0,currentlyEditing:void 0});return;case"ready":case"turn-reasoning":case"turn-message":case"turn-plan":case"tool-call":case"file-edited":case"file-diff-delta":return}}patchSession(e,t){let i=this.pendingSessionStates.get(e)??P(e);if(!i)return;let s=Ae(i,t);this.pendingSessionStates.set(e,s),this.pendingSessionPatches.set(e,{...this.pendingSessionPatches.get(e),...t}),this.broadcastSessionStatus(s),!this.sessionStatusPersistTimer&&(this.sessionStatusPersistTimer=setTimeout(()=>{this.sessionStatusPersistTimer=null,this.flushSessionStatuses()},ze))}flushSessionStatuses(){if(this.pendingSessionPatches.size===0)return;let e=this.pendingSessionStates,t=this.pendingSessionPatches;this.pendingSessionStates=new Map,this.pendingSessionPatches=new Map;try{ke([...t].map(([i,s])=>({id:i,patch:s})))}catch(i){for(let[s,n]of e)this.pendingSessionStates.has(s)||this.pendingSessionStates.set(s,n);for(let[s,n]of t)this.pendingSessionPatches.set(s,{...n,...this.pendingSessionPatches.get(s)});process.stderr.write(`[sootsim-agent] session status persistence failed: ${i instanceof Error?i.message:String(i)}
7
+ `)}}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let i=this.pendingPromptEchoes.get(e);if(!i||i.length===0)return t;for(;i.length>0&&Date.now()-i[0].sentAt>15e3;)i.shift();return i.length===0?(this.pendingPromptEchoes.delete(e),t):(i.shift(),i.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,i),null)}consumeSettledTurn(e){let t=Math.max(0,(this.pendingTurns.get(e)??1)-1);return t>0?this.pendingTurns.set(e,t):this.pendingTurns.delete(e),t}clearPromptTracking(e){this.pendingPromptEchoes.delete(e),this.pendingTurns.delete(e)}fanOutEvent(e,t){let i=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[s,n]of this.sessionsBySocket)if(n.has(e)&&s.readyState===M)try{s.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===M)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===M)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===M)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function Ye(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Le from"http";import Be from"https";import{finished as et,pipeline as tt}from"stream/promises";var K="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",Ze=[{hostSuffix:"uniswap.org",headers:{origin:"https://app.uniswap.org",referer:"https://app.uniswap.org/"},suppressBrowserUserAgent:!0}];function Qe(o){let e=o.toLowerCase();for(let t of Ze)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function _e(o){let e=Qe(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":K},...e?.headers}}var it=new Set(["host","origin","referer","user-agent","accept-encoding","cookie","connection","keep-alive","transfer-encoding","upgrade","content-length","sec-fetch-site","sec-fetch-mode","sec-fetch-dest","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform"]),rt={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,DELETE,PATCH,OPTIONS","access-control-allow-headers":"*","access-control-expose-headers":"*","access-control-max-age":"3600"},nt=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function Me(o){return o.protocol!=="https:"?{}:ue(o.hostname)?{rejectUnauthorized:!1}:{}}function R(o){for(let[e,t]of Object.entries(rt))o.setHeader(e,t)}function st(o,e){let t=[],i=e;i?.code&&t.push(i.code),i?.message&&t.push(i.message),i?.cause?.code&&t.push(i.cause.code),i?.cause?.message&&t.push(i.cause.message);let n=[...new Set(t.filter(Boolean))].join(" | ")||String(e);return o.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function ot(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(it.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?_e(e):{"user-agent":K}),t}function at(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(nt.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function De(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function Ne(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function He(o,e){if(o.method==="OPTIONS"){R(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((o.url||"").split("?")[1]||"").get("url");if(!i){R(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{R(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n;if(o.method!=="GET"&&o.method!=="HEAD"){let a=[];for await(let d of o)a.push(Buffer.isBuffer(d)?d:Buffer.from(d));a.length>0&&(n=Buffer.concat(a))}let c=o.method||"GET",r=async(a,d,l,u)=>{let p=a.protocol==="https:"?Be:Le,m=ot(o.headers,a);a.origin!==s.origin&&(delete m.authorization,delete m["proxy-authorization"]),d==="GET"||d==="HEAD"?(delete m["content-length"],delete m["content-type"]):l&&(m["content-length"]=String(l.byteLength));let y=await new Promise((w,A)=>{let S=p.request({hostname:a.hostname,port:a.port||(a.protocol==="https:"?443:80),path:a.pathname+a.search,method:d,headers:m,...Me(a)},w),I=()=>S.destroy(new Error("fetch proxy client disconnected"));o.once("aborted",I),S.once("close",()=>o.off("aborted",I)),S.once("error",A),l===void 0?S.end():S.end(l)}),f=y.statusCode??502,h=y.headers.location;if(h&&(f===301||f===302||f===303||f===307||f===308)){if(u>=10)throw y.destroy(),new Error("too many redirects");let w=(f===301||f===302)&&d==="POST"||f===303&&d!=="GET"&&d!=="HEAD",A=new URL(h,a);y.resume(),await et(y),await r(A,w?"GET":d,w?void 0:l,u+1);return}for(let[w,A]of Object.entries(y.headers)){let S=w.toLowerCase();A===void 0||S==="set-cookie"||S==="connection"||S==="keep-alive"||S==="proxy-authenticate"||S==="proxy-authorization"||S==="te"||S==="trailer"||S==="transfer-encoding"||S==="upgrade"||S.startsWith("access-control-")||e.setHeader(w,A)}R(e);let v=y.headers["set-cookie"]??[];v.length>0&&e.setHeader("x-sootsim-set-cookie",(Array.isArray(v)?v:[v]).join(", ")),e.statusCode=f,await tt(y,e)};try{await r(s,c,n,0)}catch(a){if(e.headersSent){e.destroy(a instanceof Error?a:new Error(String(a)));return}R(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${st(s.href,a)}`)}}function Ue(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(o.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":o.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":o.headers["access-control-request-headers"]||"*","Access-Control-Allow-Credentials":"true","Access-Control-Max-Age":"86400"}),e.end(),!0;let n;try{n=new URL(i,s)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let c=n.protocol==="https:"?Be:Le,r=at(o.headers,n),a=c.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:o.method,headers:r,...Me(n)},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return a.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),o.pipe(a),!0}import{WebSocket as T,WebSocketServer as ct}from"ws";var dt="/__websocket-proxy",lt=new Set(["host","connection","upgrade","transfer-encoding","content-length","sec-websocket-accept","sec-websocket-extensions","sec-websocket-key","sec-websocket-protocol","sec-websocket-version"]);function E(o,e,t){try{o.write(`HTTP/1.1 ${e} ${t}\r
8
+ Connection: close\r
9
+ Content-Type: text/plain\r
10
+ Content-Length: ${t.length}\r
11
+ \r
12
+ ${t}`)}catch{}o.destroy()}function ut(o){let e=o.headers.origin,t=o.headers.host;if(!e||!t)return!1;try{return new URL(e).host===t}catch{return!1}}function pt(o){if(!o)return{};let e=o.replace(/-/g,"+").replace(/_/g,"/"),t=e+"=".repeat((4-e.length%4)%4),i=JSON.parse(Buffer.from(t,"base64").toString("utf8"));if(!i||typeof i!="object"||Array.isArray(i))return{};let s={};for(let[n,c]of Object.entries(i))c!=null&&(lt.has(n.toLowerCase())||(s[n]=Array.isArray(c)?c.join(", "):String(c)));return s}function mt(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function ht(o){let e=o.headers["sec-websocket-protocol"];return(Array.isArray(e)?e.join(","):e||"").split(",").map(i=>i.trim()).filter(Boolean)}function N(o,e,t){if(!(o.readyState===T.CLOSED||o.readyState===T.CLOSING))try{o.close(e,t)}catch{o.terminate()}}function ft(o,e){let t=!1,i=(s,n,c,r)=>{t||(t=!0,N(n,c,r.toString()),s.readyState===T.OPEN&&N(s,c,r.toString()))};o.on("message",(s,n)=>{e.readyState===T.OPEN&&e.send(s,{binary:n})}),e.on("message",(s,n)=>{o.readyState===T.OPEN&&o.send(s,{binary:n})}),o.on("close",(s,n)=>i(o,e,s,n)),e.on("close",(s,n)=>i(e,o,s,n)),o.on("error",()=>N(e,1011,"proxy client error")),e.on("error",()=>N(o,1011,"upstream websocket error"))}function gt(o,e,t,i){let s={...t},n=Object.keys(s).filter(c=>c.toLowerCase()==="origin");if(i&&n.length===0)s.origin=mt(o);else if(!i)for(let c of n)delete s[c];return Object.keys(s).length===0?new T(o.href,e):new T(o.href,e,{headers:s})}function St(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===dt}catch{return!1}}function Fe(o,e,t,i=!0){if(!St(o.url))return!1;if(!ut(o))return E(e,403,"forbidden websocket proxy origin"),!0;let s,n;try{let d=new URL(o.url||"/","http://localhost"),l=d.searchParams.get("url");if(!l)return E(e,400,"missing websocket proxy url"),!0;if(s=new URL(l),s.protocol!=="ws:"&&s.protocol!=="wss:")return E(e,400,"invalid websocket proxy protocol"),!0;n=pt(d.searchParams.get("headers"))}catch{return E(e,400,"invalid websocket proxy request"),!0}let c=ht(o),r=gt(s,c,n,i),a=!1;return e.once("close",()=>{a||r.terminate()}),r.once("open",()=>{if(a)return;a=!0;let d=r.protocol;new ct({noServer:!0,clientTracking:!1,handleProtocols(u){return d||u.values().next().value||!1}}).handleUpgrade(o,e,t,u=>{ft(u,r)})}),r.once("error",()=>{a||(a=!0,E(e,502,"upstream websocket error"))}),r.once("close",()=>{a||(a=!0,E(e,502,"upstream websocket closed"))}),!0}var wt="require-corp",At=new Set(["tap","keyboard"]),kt=2e3,Tt=1e3;function Ct(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:At.has(o.type)}var We=5e3,It=3600*1e3,Et="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",Pt={".html":"text/html; charset=utf-8",".js":"application/javascript",".cjs":"application/javascript",".mjs":"application/javascript",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".wasm":"application/wasm",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2",".map":"application/json",".txt":"text/plain; charset=utf-8"};function je(o,e,t){let i;try{let a=W();i=JSON.stringify(a)}catch{i="{}"}let s=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimContrastOrigin=${JSON.stringify(t)};`:"",c=`<script>window.__sootsimSharedConfig=${i};`+s+n+`window.__sootsimCliVersion=${JSON.stringify(ce())};</script>`,r=o.toString("utf8");return r.includes("<head>")?r.replace("<head>",`<head>${c}`):r.includes("</head>")?r.replace("</head>",c+"</head>"):r.includes("</body>")?r.replace("</body>",c+"</body>"):c+r}function $e(o){typeof o=="object"&&o!==null&&"unref"in o&&o.unref()}var H=class o{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextSimNumber=161;sims=new Map;primarySimId=null;pendingCommands=new Map;cliBySentId=new Map;cliSimBySocket=new Map;cliLastCommandAt=new Map;cliIdentityKeyBySocket=new Map;cliLabelBySocket=new Map;restorableSims=new Map;nextCliFallbackId=1;cliIdleTimer=null;agentHost;static CLI_IDLE_TIMEOUT_MS=6e4;static CLI_LEASE_TTL_MS=6e5;static USER_ACTIVE_LEASE_TTL_MS=8e3;static USER_BOOT_LEASE_TTL_MS=6e4;static SIM_RECONNECT_TTL_MS=3e4;static SIM_IDLE_REAP_TTL_MS=30*6e4;static AUTOMATION_SIM_IDLE_REAP_TTL_MS=10*6e4;static MAX_CONCURRENT_AUTOMATION_SIMS=6;static AUTOMATION_SIM_ACTIVE_GRACE_MS=6e4;preferredPort;portFallbackCount;simIdleReapTtlMs;automationSimIdleReapTtlMs;maxConcurrentAutomationSims;automationSimActiveGraceMs;shouldWriteLockfile;shouldWriteDevLockfile;getShellPort;contrastOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=null;devHeartbeatTimer=null;wsHeartbeatTimer=null;wsIsAlive=new WeakMap;static WS_HEARTBEAT_INTERVAL_MS=3e4;runtimeUpdateTimer=null;runtimeUpdateInFlight=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;scanCache=null;scanCacheAt=0;inflightScan=null;static SCAN_FRESH_MS=2e3;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0,this.shouldWriteDevLockfile=e.writeDevLockfile===!0,this.getShellPort=e.getShellPort??null,this.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new D({getExcludePorts:e.agentScanExcludes,resolveCliLease:t=>{let i=this.sims.get(t),s=i?this.getActiveLease(i):null;return s?{kind:s.kind,cliIdentityKey:s.cliIdentityKey,expiresAt:s.expiresAt}:null}}),this.contrastOrigin=e.contrastOrigin?.replace(/\/$/,"")||null,this.simIdleReapTtlMs=e.simIdleReapTtlMs??o.SIM_IDLE_REAP_TTL_MS,this.automationSimIdleReapTtlMs=e.automationSimIdleReapTtlMs??o.AUTOMATION_SIM_IDLE_REAP_TTL_MS,this.maxConcurrentAutomationSims=e.maxConcurrentAutomationSims??o.MAX_CONCURRENT_AUTOMATION_SIMS,this.automationSimActiveGraceMs=e.automationSimActiveGraceMs??o.AUTOMATION_SIM_ACTIVE_GRACE_MS}getAgentHost(){return this.agentHost}reapIdleSimsForTest(e=Date.now()){this.reapIdleSims(e)}start(e){this.startAsync(e)}async startAsync(e){if(this.httpServer||this.wss)return this.effectivePort;this.refreshActiveRuntime();for(let t=0;t<this.portFallbackCount;t++){let i=this.preferredPort+t;try{return await this.bindOnce(i,e?.silent===!0),this.effectivePort=i,this.port=i,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${i} (preferred ${this.preferredPort} was taken)
13
+ `),this.afterBind(),i}catch(s){if(s?.code!=="EADDRINUSE")throw s;e?.silent||process.stderr.write(`ws bridge port ${i} already in use, trying ${i+1}
14
+ `)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,s)=>{let n=vt((a,d)=>this.handleHttpRequest(a,d)),c=!1,r=a=>{if(!c){c=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(a)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{c||(c=!0,n.removeListener("error",r),n.on("error",a=>{process.stderr.write(`ws bridge http error: ${String(a)}
15
+ `)}),this.httpServer=n,this.wss=new bt({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(a,d,l)=>{Fe(a,d,l)||this.wss?.handleUpgrade(a,d,l,u=>{this.wss?.emit("connection",u,a)})}),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,s=i?"sim":"cli",n=null;if(e.on("error",()=>{}),this.wsIsAlive.set(e,!0),e.on("pong",()=>{this.wsIsAlive.set(e,!0)}),this.agentHost.registerSocket(e),s==="sim")n={id:this.allocateSimId(),ws:e,origin:i,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.sims.set(n.id,n),this.writeConnectedRuntimeSnapshot(),this.shouldPromoteSim(n)&&(this.primarySimId=n.id),this.broadcastSimAssignments(),this.broadcastSimClientStates();else{let c=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,c)}e.on("message",c=>{let r;try{r=JSON.parse(c.toString())}catch{return}if(!(!r||typeof r!="object")){if(typeof r.type=="string"&&r.type.startsWith("agent:")){this.agentHost.handleMessage(e,r);return}if(r.type==="runtime:list"){let a=O.listInstalled(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:a,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let a=typeof r.version=="string"?r.version:"";if(!O.listInstalled().includes(a)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${a||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(a);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let a=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:a.version,activeRuntimeDir:a.runtimeDir}))}catch{}return}if(s==="sim"&&r.type==="bridge:hello"&&n&&!n.url){let a=n.id;this.sims.delete(a),this.primarySimId===a&&(this.primarySimId=this.getOpenSim()?.id??null),n=null,s="cli",this.cliIdentityKeyBySocket.set(e,`ws-${this.nextCliFallbackId++}`),this.writeConnectedRuntimeSnapshot(),this.broadcastSimAssignments(),this.broadcastSimClientStates()}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,this.writeConnectedRuntimeSnapshot(),typeof l.kind=="string"&&l.kind.trim()&&(n.kind=l.kind.trim()),l.meta&&typeof l.meta=="object"&&(n.meta=l.meta);let p=this.primarySimId!==n.id&&this.shouldPromoteSim(n);p&&(this.primarySimId=n.id),(u||p)&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){if(!r.patch||typeof r.patch!="object"||Array.isArray(r.patch))return;let l=Object.fromEntries(Object.entries(r.patch));try{this.writeAndBroadcastSharedConfig(l)}catch(u){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${u instanceof Error?u.message:String(u)}
16
+ `);return}return}if(r.type==="bridge:open-path"){let l=typeof r.path=="string"?r.path:"",u=typeof r.line=="number"&&Number.isFinite(r.line)?r.line:void 0,p=typeof r.column=="number"&&Number.isFinite(r.column)?r.column:void 0;l&&this.openPathInEditor(l,u,p);return}if(r.type==="bridge:boot-clients"&&n){let l=[];for(let[p,m]of this.cliSimBySocket)m===n.id&&l.push(p);for(let p of l){this.cliSimBySocket.delete(p);try{p.close(1e3,"booted by sim")}catch{}}let u=!!n.cliLease;n.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+o.USER_BOOT_LEASE_TTL_MS},process.stderr.write(`rnx booted ${l.length} cli client(s)${u?" (overrode prior lease)":""}; held sim for user [${n.id}]
17
+ `),this.recordSimAction(n.id,"sim booted cli clients"),this.broadcastSimClientStates();return}let a=this.pendingCommands.get(r.id);if(a){this.pendingCommands.delete(r.id),r.error?a.reject(new Error(r.error)):a.resolve(r.result);return}let d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===g.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,_otherCliCount:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[m,y]of this.cliBySentId)y.ws===e&&this.cliBySentId.delete(m);p&&this.broadcastSimClientStates();return}if(r.type==="bridge:hello"){let p=typeof r.cliIdentityKey=="string"&&r.cliIdentityKey.trim()?r.cliIdentityKey.trim():this.cliIdentityKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,p),typeof r.cliLabel=="string"&&r.cliLabel.trim()&&this.cliLabelBySocket.set(e,r.cliLabel.trim()),e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,result:{cliIdentityKey:p,leaseTtlMs:o.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(r.type==="bridge:list-sims"){e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,result:this.listSims()}));return}if(r.type==="bridge:claim"){let p=await this.waitForSim(r.simId),m=this.tryAcquireLease(e,p,{force:r.force===!0});if(!m.granted){e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,_locked:m.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,m.bootedCount>0?`cli force-claimed sim (booted ${m.bootedCount})`:"cli claimed sim"),e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:m.lease.cliIdentityKey,lockExpiresAt:m.lease.expiresAt,bootedCount:m.bootedCount}}));return}let a=await this.waitForSim(r.simId);if(Ct(r)){let p=this.tryAcquireLease(e,a);if(!p.granted){e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${a.id} is locked by another cli \u2014 use \`rnxsim claim ${a.id} --force\` or \`rnxsim open --new\``,_locked:p.lock}));return}}else this.ensureCliIdentityKey(e);this.setCliSimTarget(e,a.id),this.recordSimAction(a.id,this.describeForwardedCommand(r));let d=this.nextCommandId++;this.cliBySentId.set(d,{simId:a.id,ws:e,originalId:r.id});let{simId:l,...u}=r;if(a.ws.send(JSON.stringify({...u,id:d})),u.type==="close"){this.cliBySentId.delete(d),e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,result:{requested:!0,simId:a.id}}));let p=a.ws,m=setTimeout(()=>{this.closeSimSocketFromHost(p)},kt);$e(m)}}catch(a){e.readyState===g.OPEN&&e.send(JSON.stringify({id:r.id,error:a instanceof Error?a.message:String(a)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),s==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[c,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(c));for(let[c,r]of this.cliBySentId)r.simId===n.id&&(r.ws.readyState===g.OPEN&&r.ws.send(JSON.stringify({id:r.originalId,error:"sim disconnected before responding"})),this.cliBySentId.delete(c));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let c=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[r,a]of this.cliBySentId)a.ws===e&&this.cliBySentId.delete(r);c&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
18
+ `),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),o.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(x(),!ne(this.buildLockfileSnapshot()))throw new Error("another rnx daemon wrote the lockfile during startup \u2014 aborting")}catch(e){throw process.stderr.write(`ws bridge failed to claim daemon lockfile: ${String(e)}
19
+ `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},We),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}if(this.shouldWriteDevLockfile){try{this.writeDevLockfileSnapshot()}catch(e){process.stderr.write(`ws bridge failed to write dev bridge lockfile: ${String(e)}
20
+ `)}this.devHeartbeatTimer=setInterval(()=>{try{this.writeDevLockfileSnapshot()}catch{}},We),this.devHeartbeatTimer.unref()}this.agentHost.seedOnBoot()}bootstrapping=!0;connectedRuntimeVersions(){let e=new Set;for(let t of this.sims.values())try{let i=new URL(t.url||t.origin||"http://localhost"),s=L(i.hostname);s&&e.add(s)}catch{}return[...e].sort()}buildLockfileSnapshot(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,activeRuntimeDir:this.activeRuntimeDirPath,servedRuntimes:this.connectedRuntimeVersions(),startedAt:this.startedAt,heartbeatAt:Date.now(),bootstrapping:this.bootstrapping}}buildDevLockfileSnapshot(){let e=this.getShellPort?.()??null;return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,...e&&e>0?{shellPort:e}:{},cwd:process.cwd(),startedAt:this.startedAt,heartbeatAt:Date.now(),source:"vite-dev",servedRuntimes:this.connectedRuntimeVersions()}}writeLockfileSnapshot(){ie(this.buildLockfileSnapshot())}writeDevLockfileSnapshot(){re(this.buildDevLockfileSnapshot())}writeConnectedRuntimeSnapshot(){if(this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}if(this.shouldWriteDevLockfile&&this.httpServer)try{this.writeDevLockfileSnapshot()}catch{}}refreshActiveRuntime(){this.activeRuntimeVersion=j(),this.activeRuntimeDirPath=pe()??Q()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=_({excludePorts:e,buildIconProxyUrl:t=>`/__bundle-proxy?url=${encodeURIComponent(t)}`}).then(t=>(this.scanCache=t,this.scanCacheAt=Date.now(),t)).catch(t=>{let i=t instanceof Error?t.message:String(t);return console.error("[rnx] /__server-scan failed:",i),this.scanCache??[]}).finally(()=>{this.inflightScan=null}),this.inflightScan}handleServerScan(e){let t=s=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(s))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<o.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(s=>t(s))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[Et]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):It}startRuntimeUpdater(){if(!this.shouldWriteLockfile||this.runtimeUpdateTimer||C.existsSync(b.join(q(),"runtime-update-disabled"))||process.env.SOOTSIM_HOME&&z()&&!j())return;this.runRuntimeUpdate("startup");let e=this.resolveRuntimeUpdateIntervalMs();this.runtimeUpdateTimer=setInterval(()=>{this.runRuntimeUpdate("periodic")},e),this.runtimeUpdateTimer.unref()}runRuntimeUpdate(e){return this.runtimeUpdateInFlight?this.runtimeUpdateInFlight:(this.runtimeUpdateInFlight=(async()=>{try{e==="startup"&&process.stderr.write(`rnx: checking for runtime updates\u2026
21
+ `);let t=await O.updateToLatest({protectVersions:this.connectedRuntimeVersions()});if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`rnx: runtime ${this.activeRuntimeVersion??"(none)"} is current
22
+ `);return}let i=this.activeRuntimeVersion,s=this.setActiveRuntime(t.latestVersion);process.stderr.write(`rnx runtime updated to ${s.version} (${e})
23
+ `);try{Y({from:i,to:s.version,at:Date.now()})}catch{}}catch(t){process.stderr.write(`rnx runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
24
+ `)}finally{if(this.runtimeUpdateInFlight=null,e==="startup"&&this.bootstrapping){if(this.bootstrapping=!1,this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}process.stderr.write(`rnx: ready
25
+ `)}}})(),this.runtimeUpdateInFlight)}setActiveRuntime(e){if(Z(e),this.refreshActiveRuntime(),this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}let t=JSON.stringify({type:"runtime:changed",version:e,runtimeDir:this.activeRuntimeDirPath});for(let i of this.sims.values()){try{let s=new URL(i.url||i.origin||"http://localhost");if(L(s.hostname))continue}catch{}if(i.ws.readyState===g.OPEN)try{i.ws.send(t)}catch{}}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{$()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy",wt),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),De(e.url)){He(e,t);return}if(Ne(e.url)&&Ue(e,t))return;let i=(e.method||"GET").toUpperCase(),s;try{s=new URL(e.url||"/",`http://${e.headers.host||"localhost"}`)}catch{t.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}),t.end("invalid request URL or host");return}if(s.pathname==="/__sootsim/shared-config"){if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Allow-Headers","Content-Type"),t.setHeader("Cache-Control","no-store"),i==="OPTIONS"){t.writeHead(204,{Allow:"GET, HEAD, POST, OPTIONS"}),t.end();return}if(i==="GET"||i==="HEAD"){let u="{}";try{u=JSON.stringify(W())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(u);return}if(i==="POST"){(async()=>{try{let u=[],p=0;for await(let h of e){let v=Buffer.isBuffer(h)?h:Buffer.from(h);if(p+=v.byteLength,p>8*1024*1024){t.writeHead(413,{"Content-Type":"text/plain; charset=utf-8"}),t.end("shared config patch is too large");return}u.push(v)}let m=JSON.parse(Buffer.concat(u).toString("utf8"));if(!m||typeof m!="object"||Array.isArray(m))throw new Error("shared config patch must be an object");let y=Object.fromEntries(Object.entries(m)),f=this.writeAndBroadcastSharedConfig(y);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(f))}catch(u){t.writeHead(400,{"Content-Type":"text/plain; charset=utf-8"}),t.end(`invalid shared config patch: ${u instanceof Error?u.message:String(u)}`)}})();return}t.writeHead(405,{Allow:"GET, HEAD, POST, OPTIONS"}),t.end("method not allowed");return}if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}if(s.pathname==="/__bundle-proxy"){let u=s.searchParams.get("url");if(!u){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let p;try{p=new URL(u)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let m=p.hostname;if(!(m==="localhost"||m==="127.0.0.1"||m==="::1"||m.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let f=await fetch(p.toString(),{redirect:"follow"}),h={},v=f.headers.get("content-type");if(v&&(h["Content-Type"]=v),h["Cache-Control"]="no-store",t.writeHead(f.status,h),!f.body){t.end();return}let w=f.body.getReader();for(;;){let{done:A,value:S}=await w.read();if(A)break;t.write(Buffer.from(S))}t.end()}catch(f){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${f instanceof Error?f.message:String(f)}`)}})();return}if(s.pathname==="/__server-scan"){this.handleServerScan(t);return}if(s.pathname==="/healthz"){t.writeHead(200,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify({ok:!0,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,bridgeSource:this.shouldWriteDevLockfile?"vite-dev":this.shouldWriteLockfile?"daemon":"embedded",startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}let n=me(s.hostname),c=L(s.hostname);n||this.refreshActiveRuntime();let r=n?he(s.hostname):this.activeRuntimeDirPath;if(!r){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end(n?`rnx: runtime ${c??"(invalid version origin)"} is not installed. run \`rnxsim open\` from that app again.`:"rnx: no active runtime installed. run `rnxsim runtime install` to fetch one.");return}let a=s.pathname;if(a==="/runtime"||a==="/runtime/"?a="/":a.startsWith("/runtime/")?a=a.slice(8):a==="/sootsim"||a==="/sootsim/"?a="/":a.startsWith("/sootsim/")&&(a=a.slice(8)),(a===""||a==="/")&&(a="/index.html"),a.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&a.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let u of a.split("/"))if(u===".."){t.writeHead(403),t.end("forbidden");return}let d=b.resolve(r,"."+a),l=r.endsWith(b.sep)?r:r+b.sep;if(!d.startsWith(l)&&d!==r){t.writeHead(403),t.end("forbidden");return}C.realpath(d,(u,p)=>{let m=u?d:p,y=m.endsWith(b.sep)?m:m+b.sep;if(!u){let f=(()=>{try{let h=C.realpathSync(r);return h.endsWith(b.sep)?h:h+b.sep}catch{return l}})();if(!y.startsWith(f)&&m+b.sep!==f){t.writeHead(403),t.end("forbidden");return}}C.stat(m,(f,h)=>{if(f||!h?.isFile()){let S=b.extname(a).toLowerCase();if(S&&S!==".html"){t.writeHead(404),t.end("not found");return}if(a.startsWith("/__")||a.startsWith("/api/")||a==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let I=b.join(r,"index.html");C.readFile(I,(Je,Ve)=>{if(Je){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),i==="HEAD"){t.end();return}t.end(je(Ve,this.effectivePort,this.contrastOrigin))});return}let v=b.extname(m).toLowerCase(),w=Pt[v]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":w,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(v===".html"){C.readFile(m,(S,I)=>{if(S){try{t.end()}catch{}return}t.end(je(I,this.effectivePort,this.contrastOrigin))});return}let A=C.createReadStream(m);A.pipe(t),A.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,s]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(e-n<o.CLI_IDLE_TIMEOUT_MS)continue;let c=!1;for(let r of this.cliBySentId.values())if(r.ws===i){c=!0;break}if(!c){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[r,a]of this.cliBySentId)a.ws===i&&this.cliBySentId.delete(r);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e),this.reapIdleSims(e)}isAutomationSim(e){return e.meta?.sootsimHostDriver==="playwright"}automationSimOwnerAlive(e){let t=Number(e.meta?.sootsimHostPid);if(!Number.isInteger(t)||t<=1||t===process.pid)return!1;try{return process.kill(t,0),!0}catch(i){return i.code==="EPERM"}}reapIdleSims(e=Date.now()){let t=new Set(this.cliSimBySocket.values()),i=[];for(let n of this.sims.values()){if(n.id===this.primarySimId||t.has(n.id)||this.getActiveLease(n))continue;let c=Math.max(n.lastActiveAt,n.connectedAt),r=e-c,a=this.isAutomationSim(n);if(a&&this.automationSimOwnerAlive(n))continue;let d=a?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=d){this.closeSimSocketFromHost(n.ws);continue}a&&i.push({sim:n,idleMs:r})}let s=this.maxConcurrentAutomationSims;if(i.length>s){i.sort((n,c)=>c.idleMs-n.idleMs);for(let{sim:n,idleMs:c}of i.slice(0,i.length-s))c<this.automationSimActiveGraceMs||this.closeSimSocketFromHost(n.ws)}}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==g.OPEN)continue;if(this.wsIsAlive.get(e)===!1){try{e.terminate()}catch{}continue}this.wsIsAlive.set(e,!1);try{e.ping()}catch{try{e.terminate()}catch{}}}}closeSimSocketFromHost(e){if(e.readyState!==g.OPEN)return;try{e.close(de,le)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==g.CLOSED)try{e.terminate()}catch{}},Tt);$e(t)}listSims(){return Array.from(this.sims.values()).sort((e,t)=>e.id===this.primarySimId?-1:t.id===this.primarySimId?1:e.connectedAt-t.connectedAt).map(e=>this.describeSim(e))}async sendCommand(e){let t=await this.waitForSim(e.simId),i=this.nextCommandId++;return new Promise((s,n)=>{let c=setTimeout(()=>{this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(i,{simId:t.id,resolve:d=>{clearTimeout(c),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(c),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...a}=e;t.ws.send(JSON.stringify({...a,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,c=(a,d)=>new Promise(l=>{try{let u=yt(a,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let a=r.split(" ").filter(Boolean);if(a.length&&await c(a[0],[...a.slice(1),"-g",n]))return}await c("cursor",["-g",n])||await c("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await fe(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.devHeartbeatTimer&&(clearInterval(this.devHeartbeatTimer),this.devHeartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{$()}catch{}if(this.shouldWriteDevLockfile)try{se()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,s]of this.pendingCommands)s.reject(new Error("server closing")),this.pendingCommands.delete(i);for(let i of this.sims.values())i.ws.close();this.sims.clear(),this.primarySimId=null;let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}describeSim(e){let t;try{t=e.ws.readyState}catch{t=g.CLOSED}let i=this.getActiveLease(e);return{id:e.id,origin:e.origin,url:e.url,title:e.title,userAgent:e.userAgent,connectedAt:e.connectedAt,lastSeenAt:e.lastSeenAt,lastActiveAt:e.lastActiveAt||void 0,isPrimary:e.id===this.primarySimId,readyState:t===g.OPEN?"open":t===g.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:i?i.cliLabel||i.cliIdentityKey:void 0,lockedByKind:i?i.kind:void 0,lockExpiresAt:i?i.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused,kind:e.kind,meta:e.meta}}getActiveLease(e){let t=e.cliLease;return t?Date.now()>=t.expiresAt?(e.cliLease=void 0,null):t:null}tryAcquireLease(e,t,i={}){let s=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),c=Date.now(),r=this.getActiveLease(t),a=r&&r.cliIdentityKey===s,d=0;if(r&&!a&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-c)},bootedCount:0};if(r&&!a&&i.force)for(let[u,p]of this.cliSimBySocket){if(p!==t.id)continue;let m=this.cliIdentityKeyBySocket.get(u);if(m&&m!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:c+o.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}updateUserFocusLease(e,t){let i=t.focused===!0,s=typeof t.visible=="boolean"?t.visible:void 0,n=typeof t.visibilityState=="string"?t.visibilityState:void 0,c=typeof t.documentFocused=="boolean"?t.documentFocused:void 0;e.userFocused===i&&e.userVisible===s&&e.visibilityState===n&&e.documentFocused===c||(e.userFocused=i,e.userVisible=s,e.visibilityState=n,e.documentFocused=c,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+o.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,s):s;e.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:n},this.broadcastSimClientStates()}ensureCliIdentityKey(e){let t=this.cliIdentityKeyBySocket.get(e);if(t)return t;let i=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,i),i}getOpenSim(e){if(e){let i=this.sims.get(e);return i?.ws.readyState===g.OPEN?i:null}let t=this.getDefaultSimCandidates();return t.find(i=>i.id===this.primarySimId)??t[0]??null}getDefaultSimCandidates(){let e=Array.from(this.sims.values()).filter(i=>i.ws.readyState===g.OPEN),t=e.filter(i=>i.url);return t.length>0?t:e}async waitForSim(e,t={}){let i=t.attempts??10,s=t.intervalMs??200;for(let c=0;c<i;c++){if(e){let r=this.getOpenSim(e);if(r)return r}else{let r=this.getDefaultSimCandidates();if(r.length>1)throw new Error(`multiple sims are connected: ${r.map(d=>d.id).join(", ")}; run \`rnxsim use <sim>\` or pass \`--sim <sim>\``);let a=r[0];if(a)return a}await new Promise(r=>setTimeout(r,s))}if(!e)throw new Error("no sim connected");let n=this.getDefaultSimCandidates().map(c=>c.id);throw new Error(`no sim connected with id ${e}`+(n.length>0?`; connected sims: ${n.join(", ")}`:""))}shouldPromoteSim(e){let t=this.primarySimId?this.sims.get(this.primarySimId):null;if(!e.url)return!t;let i=t?.ws.readyState===g.OPEN;if(!t||!i||!t.url)return!0;let s=e.origin?.includes(":5173"),n=t.origin?.includes(":5173");return!!s||!n}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===g.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",simId:e.id,isPrimary:e.id===this.primarySimId}))}writeAndBroadcastSharedConfig(e){let t=X(e),i=JSON.stringify({type:"bridge:shared-config-changed",config:t});for(let s of this.sims.values())if(s.ws.readyState===g.OPEN)try{s.ws.send(i)}catch{}return t}broadcastSimClientStates(){for(let e of this.sims.values()){if(e.ws.readyState!==g.OPEN)continue;let t=this.getActiveLease(e),i={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliIdentityKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused};e.ws.send(JSON.stringify(i))}}setCliSimTarget(e,t){let i=this.cliSimBySocket.get(e);i!==t&&(this.cliSimBySocket.set(e,t),this.recordSimAction(t,i?"cli switched sims":"cli connected",!1),this.broadcastSimClientStates())}recordSimAction(e,t,i=!0){let s=t?.trim();if(!s)return;let n=this.sims.get(e);if(!n)return;let c=Date.now();n.lastActiveAt=c,n.recentActions=[{label:s,at:c},...n.recentActions.filter(r=>r.label!==s)].slice(0,4),i&&this.broadcastSimClientStates()}describeForwardedCommand(e){switch(e?.type){case"evaluate":return"evaluated page state";case"screenshot":return"captured screenshot";case"tap":return"sent tap event";case"keyboard":return e?.action==="type"?"typed text":"used keyboard";case"tree":return"dumped tree";case"focus":return"focused sim";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[i,s]of this.cliSimBySocket){if(s!==e||i.readyState!==g.OPEN)continue;let n=this.cliIdentityKeyBySocket.get(i);t.add(n??`ws-unknown-${t.size}`)}return t.size}getOtherCliIdentityCount(e,t){let i=this.cliIdentityKeyBySocket.get(e),s=new Set;for(let[n,c]of this.cliSimBySocket){if(c!==t||n.readyState!==g.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||s.add(r??`ws-unknown-${s.size}`)}return s.size}getActiveAgentCommandCount(e){let t=0;for(let i of this.pendingCommands.values())i.simId===e&&t++;return t}allocateSimId(){for(;;){let e=this.nextSimNumber.toString(16);if(this.nextSimNumber++,!this.sims.has(e)&&!this.restorableSims.has(e))return e}}tryRestoreSimId(e,t){let i=t?.trim();if(!i||i===e.id)return!1;let s=this.sims.get(i);if(s&&s!==e&&s.ws.readyState===g.OPEN)return!1;let n=this.getRestorableSimState(i),c=e.id;this.sims.delete(c),e.id=i,n&&(e.recentActions=n.recentActions.map(r=>({...r})),e.lastActiveAt=n.lastActiveAt,e.cliLease=n.cliLease?{...n.cliLease}:void 0,this.restorableSims.delete(i)),this.sims.set(e.id,e),this.primarySimId===c&&(this.primarySimId=e.id);for(let[r,a]of this.cliSimBySocket)a===c&&this.cliSimBySocket.set(r,e.id);return!0}rememberDisconnectedSim(e){let t=this.getActiveLease(e);this.restorableSims.set(e.id,{recentActions:e.recentActions.map(i=>({...i})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+o.SIM_RECONNECT_TTL_MS}),this.sims.delete(e.id),this.writeConnectedRuntimeSnapshot()}getRestorableSimState(e){let t=this.restorableSims.get(e);return t?t.expiresAt<=Date.now()?(this.restorableSims.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableSims(e=Date.now()){for(let[t,i]of this.restorableSims)if(!(i.expiresAt>e)){this.restorableSims.delete(t);for(let[s,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(s)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null);let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}};function Rt(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function yi(o,e={}){(o.includes("--help")||o.includes("-h"))&&(console.log(`
26
+ rnxsim serve \u2014 run the rnx bridge in the foreground
27
+
28
+ hosts the WS bridge that CLI commands talk to. once running, any rnx
29
+ renderer (browser, electron, headless playwright) that connects to port 7668
30
+ becomes drivable from 'rnxsim describe', 'rnxsim do tap', etc.
31
+
32
+ usage:
33
+ rnxsim serve [options]
34
+
35
+ options:
36
+ --port <n> bridge port (defaults to ${7668})
37
+ --quiet suppress per-connection logging
38
+
39
+ examples:
40
+ rnxsim serve
41
+ rnxsim serve --port 7668 --quiet
42
+ `),process.exit(0));let t=o.indexOf("--port"),i=t>=0&&o[t+1]?Number(o[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${o[t+1]}`),process.exit(1));let s=o.includes("--quiet")||o.includes("-q"),n=ee();n&&te(n)&&(console.error(` an rnx bridge is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'rnxsim daemon stop' first"),process.exit(1)),x();let c=await ge(),r=new H({port:i,writeLockfile:!0,contrastOrigin:c}),a=await r.startAsync({silent:s}),d=Date.now(),l=y=>{s||process.stdout.write(`${y}
43
+ `)},u=new Set,p=setInterval(()=>{let y=r.listSims(),f=new Set(y.map(h=>h.id));for(let h of y)if(!u.has(h.id)){let v=h.title||h.url||h.origin||"(unknown)";l(` + ${h.id} ${v}`)}for(let h of u)f.has(h)||l(` - ${h}`);u.clear();for(let h of f)u.add(h)},500);oe({event:"daemon_heartbeat",properties:{bridge_port:a,under_daemon:Rt(),platform:process.platform,subsource:"daemon"}}),ae(),l(`rnx bridge listening on ws://localhost:${a} (runtime http on same port)`),a!==i&&l(` (preferred port ${i} was taken \u2014 fell back to ${a})`),l(" ready for browser, electron, or headless playwright sims to connect"),l(" (ctrl-c to stop)");let m=async y=>{clearInterval(p),l(`
44
+ ${y} received \u2014 shutting down after ${Math.round((Date.now()-d)/1e3)}s`);try{await r.close()}catch{}process.exit(0)};process.on("SIGINT",()=>m("SIGINT")),process.on("SIGTERM",()=>m("SIGTERM")),process.on("SIGHUP",()=>m("SIGHUP")),process.on("exit",()=>{try{r.removeLockfile()}catch{}}),await new Promise(()=>{})}export{yi as runServe};
@@ -0,0 +1,32 @@
1
+ /*! rnx v0.1.312 | (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 d}from"./chunk-VUFRB347.js";import{d as V,f as q,g as J,i as F,j as B}from"./chunk-JG6S4RSH.js";import{b as x,c as L}from"./chunk-YRV7HR3P.js";import{c as k}from"./chunk-N6A3SXMR.js";import"./chunk-TCWQJILS.js";import{f as y}from"./chunk-U4PN6JOT.js";import"./chunk-VZBLFMYC.js";import"./chunk-KR5BGMBZ.js";import"./chunk-HG7ORJMT.js";import"./chunk-TYE3WBSR.js";import"./chunk-5OX7ANRA.js";import"./chunk-33FKQH54.js";import"./chunk-7VWOSTD5.js";import"./chunk-6UKJB2VC.js";import{A as R,B as C,H as w,K as N,M as I,l as v}from"./chunk-66NF2KNG.js";import{a as T}from"./chunk-EUAVBTKU.js";import{a as s}from"./chunk-ZMZTHU7V.js";import"./chunk-FTC4M26Q.js";import"./chunk-MENV7VLD.js";import $ from"node:fs";import z from"node:os";import P from"node:path";import{spawn as re}from"node:child_process";import l from"node:fs";import a from"node:path";function Y(e){let n=a.resolve(e);for(;;){if(l.existsSync(a.join(n,"package.json")))return n;let r=a.dirname(n);if(r===n)return null;n=r}}function j(e){let n=a.resolve(e);for(;;){if(l.existsSync(a.join(n,"bun.lock"))||l.existsSync(a.join(n,"bun.lockb")))return"bun";if(l.existsSync(a.join(n,"pnpm-lock.yaml")))return"pnpm";if(l.existsSync(a.join(n,"package-lock.json")))return"npm";let r=a.dirname(n);if(r===n)return"npm";n=r}}function H(e){let n=a.resolve(e.appDir),r=te(a.join(n,"package.json")),t=`${s.commandName} open`,o=r.scripts?.[s.commandName];if(o&&o!==t)throw new Error(`package.json already defines scripts.${s.commandName} as ${JSON.stringify(o)}; resolve that conflict before setup`);let i=j(n),c=[];return r.devDependencies?.[s.packageName]!==e.cliVersion&&c.push(oe(i,e.cliVersion)),o!==t&&c.push(ae(i)),{appDir:n,packageManager:i,operations:c}}async function U(e,n){for(let r of e.operations)n.dryRun||await se(r,e.appDir,n.json)}function O(e){return e.operations.map(n=>`${n.command} ${n.args.map(ie).join(" ")}`)}function te(e){let n;try{n=JSON.parse(l.readFileSync(e,"utf8"))}catch(o){let i=o instanceof Error?o.message:String(o);throw new Error(`could not read ${e}: ${i}`)}if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`${e} must contain a JSON object`);let r=W(Reflect.get(n,"scripts")),t=W(Reflect.get(n,"devDependencies"));return{...r?{scripts:r}:{},...t?{devDependencies:t}:{}}}function W(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=Object.entries(e).filter(r=>typeof r[1]=="string");return Object.fromEntries(n)}function oe(e,n){let r=`${s.packageName}@${n}`;switch(e){case"bun":return{command:"bun",args:["add","--dev","--exact",r],description:`install ${r} as an exact dev dependency`};case"pnpm":return{command:"pnpm",args:["add","--save-dev","--save-exact",r],description:`install ${r} as an exact dev dependency`};case"npm":return{command:"npm",args:["install","--save-dev","--save-exact",r],description:`install ${r} as an exact dev dependency`}}}function ie(e){return/^[a-zA-Z0-9_./@=-]+$/.test(e)?e:JSON.stringify(e)}function se(e,n,r){return new Promise((t,o)=>{let i=re(e.command,e.args,{cwd:n,stdio:r?["ignore",2,"inherit"]:"inherit"});i.once("error",o),i.once("exit",c=>{c===0?t():o(new Error(`${e.command} exited with code ${c??"unknown"}`))})})}function ae(e){return{command:e,args:e==="bun"?["pm","pkg","set",`scripts.${s.commandName}=${s.commandName} open`]:["pkg","set",`scripts.${s.commandName}=${s.commandName} open`],description:`add the \`${s.commandName}\` package script`}}async function Ye(e){if(e.includes("--help")||e.includes("-h")){je();return}let n=ue(e),r="decisions";try{let t=Y(n.appDir),o=x(),i=R(),c=await le(n,o),X=await de(n,t),g=await K(n,"productAnalytics",i.productAnalytics,i.configured),S=await K(n,"crashReports",i.crashReports,i.configured),ee=await y.fetchManifest(),f=y.resolveVersion(ee,{channel:"stable"}).version,A=T();if(A==="0.0.0")throw new Error("could not resolve the installed rnxsim CLI version");let p=null;X&&t&&(p=H({appDir:t,cliVersion:A})),he(n),be(n,o,c,f),ve(n,t,p),Re(n,g,S),r="runtime";let M=!1;if(!n.dryRun){let E=w();M=(await y.install({version:f,channel:"stable",setActive:!0,protectVersions:E?[E]:[]})).installed}r="repository",p&&await U(p,{dryRun:n.dryRun,json:n.json}),r="service";let h=o.installed;c&&!o.installed&&!n.dryRun&&(await L({port:7668,force:!1}),h=!0),r="privacy",n.dryRun||C({productAnalytics:g,crashReports:S}),r="compatibility";let u=t?me(t):null,b=await fe(n,u);b&&u&&t&&!n.dryRun&&await ye(t,u),we(n,u,b);let _={runtimeVersion:f,serviceInstalled:h,repositoryPrepared:p!==null,compatibilityShared:b&&!n.dryRun},ne=Se(f);n.json?console.log(JSON.stringify({..._,runtimeInstalled:n.dryRun?!1:M,dryRun:n.dryRun,cache:ne,repositoryOperations:p?O(p):[]},null,2)):ke(p);let m=u?q(u):null;return k({event:"cli_setup_completed",properties:{service_installed:h,repository_prepared:p!==null,product_analytics:g,crash_reports:S,compat_supported:m?.supported??0,compat_partial:m?.partial??0,compat_unsupported:m?.unsupported??0,compat_not_yet_verified:m?.notYetVerified??0,from_welcome:n.fromWelcome,ci:n.ci,dry_run:n.dryRun}}),_}catch(t){let o=xe(t);throw k({event:"cli_setup_failed",properties:{stage:r,message:o}}),t}}function pe(){let e=x(),n=N(),r=w();return{daemonSupported:e.supported,daemonInstalled:e.installed,daemonRunning:!!(n&&I(n)),runtimeInstalled:!!(r&&$.existsSync(v(r))),privacyConfigured:R().configured}}function He(e=pe()){return!e.runtimeInstalled||!e.privacyConfigured}function ue(e){let n=e.indexOf("--app"),r=n>=0?e[n+1]:void 0;if(n>=0&&(!r||r.startsWith("-")))throw new Error("--app requires a directory");let t=G(e,"--service","--no-service"),o=G(e,"--repo","--no-repo");return{appDir:P.resolve(r??process.cwd()),ci:e.includes("--ci"),dryRun:e.includes("--dry-run"),fromWelcome:e.includes("--from-welcome"),json:e.includes("--json"),yes:e.includes("--yes")||e.includes("-y"),service:t,repository:o,productAnalytics:Z(e,"--analytics"),crashReports:Z(e,"--crash-reports"),shareCompatibility:e.includes("--share-compat")}}function G(e,n,r){if(e.includes(n)&&e.includes(r))throw new Error(`${n} and ${r} cannot be used together`);if(e.includes(n))return!0;if(e.includes(r))return!1}function Z(e,n){let r=e.find(i=>i.startsWith(`${n}=`)),t=e.indexOf(n),o=r?.slice(n.length+1)??(t>=0?e[t+1]:void 0);if(o!==void 0){if(o==="on"||o==="yes"||o==="true")return!0;if(o==="off"||o==="no"||o==="false")return!1;throw new Error(`${n} must be on or off`)}}async function le(e,n){if(e.ci){if(e.service===!0)throw new Error("--ci cannot install a machine service");return!1}return n.supported?n.installed&&e.service===void 0?!0:e.service!==void 0?e.service:e.yes?!0:(D(e,"--service or --no-service"),d("Install the background service and shared managed runtime?",!0)):!1}async function de(e,n){if(!n){if(e.repository===!0)throw new Error("--repo requires a package.json");return!1}return e.repository!==void 0?e.repository:e.yes?!0:(D(e,"--repo or --no-repo"),d(`Prepare ${n} for reproducible rnx runs?`,!0))}async function K(e,n,r,t){let o=n==="productAnalytics"?e.productAnalytics:e.crashReports;return o!==void 0?o:t?r:e.yes?!0:(D(e,n==="productAnalytics"?"--analytics on|off":"--crash-reports on|off"),d(n==="productAnalytics"?"Share bounded product analytics?":"Send bounded crash reports?",!0))}async function fe(e,n){return n?e.shareCompatibility?!0:e.yes||!process.stdin.isTTY?!1:d("Share dependency names, requested versions, framework, and this compatibility result?",!1):!1}function D(e,n){if(!(process.stdin.isTTY&&!e.ci))throw new Error(`non-interactive setup requires ${n}, or --yes to accept defaults`)}function me(e){let n=JSON.parse($.readFileSync(P.join(e,"package.json"),"utf8"));if(!n||typeof n!="object")throw new Error("package.json must contain an object");return V(n)}async function ye(e,n){let r=JSON.parse($.readFileSync(P.join(e,"package.json"),"utf8"));if(!r||typeof r!="object")throw new Error("package.json must be an object");let t=await fetch("https://contrast.dev/api/scan",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(ge(r,n)),signal:AbortSignal.timeout(1e4)});if(!t.ok)throw new Error(`compatibility sharing failed with HTTP ${t.status}`)}function ge(e,n){return{dependencies:Q(Reflect.get(e,"dependencies")),devDependencies:Q(Reflect.get(e,"devDependencies")),framework:n.framework,result:{framework:n.framework,rnVersion:n.rnVersion,packages:n.packages.slice(0,200)},source:"desktop",shared:!0}}function Q(e){if(!e||typeof e!="object")return{};let n={};for(let[r,t]of Object.entries(e).slice(0,200))typeof t=="string"&&(n[r.slice(0,160)]=t.slice(0,80));return n}function Se(e){let n=z.platform(),r=z.arch();return{path:v(e),key:`sootsim-runtime-${n}-${r}-${e}`,inputs:{platform:n,arch:r,runtimeVersion:e}}}function he(e){e.json||console.log(`
5
+ ${e.fromWelcome?"welcome to rnx":"rnxsim setup"}`)}function be(e,n,r,t){e.json||(console.log(`
6
+ 1. machine`),console.log(` stable runtime: ${t}`),console.log(` background service: ${n.supported?r?"install":"skip":"unsupported on this platform"}`))}function ve(e,n,r){if(!e.json){if(console.log(`
7
+ 2. repository`),!n){console.log(" no package.json found; repository preparation skipped");return}if(!r){console.log(` skipped for ${n}`);return}console.log(` package manager: ${j(n)}`);for(let t of O(r))console.log(` ${e.dryRun?"would run":"run"}: ${t}`)}}function Re(e,n,r){e.json||(console.log(`
8
+ 3. privacy`),console.log(` product analytics: ${n?"on":"off"}`),console.log(" command, feature, version, platform, and bounded performance events"),console.log(` crash reports: ${r?"on":"off"}`),console.log(" error type, message, stack, runtime version, platform, and bounded dependency summary"),console.log(" source files, environment values, terminal output, app data, screenshots, and recordings are not included"))}function we(e,n,r){if(!e.json){if(console.log(`
9
+ 4. compatibility`),!n){console.log(" no package.json found; run `rnxsim compat` inside an app later");return}console.log(` ${J(n)}`);for(let t of F(n))console.log(` ${t}`);console.log(` ${B}`),console.log(` dependency sharing: ${r?"yes":"no"}`)}}function ke(e){if(console.log(`
10
+ 5. ready`),e){let n=e.packageManager==="bun"?"bun run sootsim":`${e.packageManager} run rnxsim`;console.log(` start your app normally, then ${n} -- <port>`)}else console.log(" start your app normally, then rnxsim open <port>");console.log(" useful next commands: rnxsim describe; rnxsim get errors; rnxsim compat"),console.log(" install agent skills with `rnxsim skill install`, then start a new session"),console.log(" if a concrete rnx seam is missing or broken, preview `rnxsim report-issue` and confirm separately")}function xe(e){return(e instanceof Error?e.message:String(e)).replace(/(?:\/?[\w.-]+)+/g,"<path>").slice(0,240)}function je(){console.log(`
11
+ rnxsim setup \u2014 configure a machine and optionally prepare the current repository
12
+
13
+ usage:
14
+ rnxsim setup
15
+ rnxsim setup --yes
16
+ rnxsim setup --ci --yes --json
17
+ rnxsim setup --dry-run --yes
18
+
19
+ decisions:
20
+ --service | --no-service
21
+ --repo | --no-repo
22
+ --analytics on|off
23
+ --crash-reports on|off
24
+ --share-compat
25
+
26
+ automation:
27
+ --yes accept defaults; compatibility sharing still defaults off
28
+ --ci never prompt or install a background service
29
+ --json emit runtime/cache metadata as JSON
30
+ --dry-run print exact repository operations without changing the machine
31
+ --app DIR use DIR as the repository search start
32
+ `)}export{ge as buildCompatibilitySharePayload,pe as readMachineSetupStatus,Ye as runSetup,He as shouldRunSetupForBareCommand};