rnxsim 0.1.376 → 0.1.378

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +28 -25
  2. package/cli/app-config.ts +9 -12
  3. package/cli/app-fonts.ts +3 -3
  4. package/cli/app-project.ts +8 -8
  5. package/cli/auth.ts +7 -9
  6. package/cli/bin.ts +16 -31
  7. package/cli/bridge-flow-runner.ts +3 -3
  8. package/cli/browser-backend.ts +44 -0
  9. package/cli/command-contract.ts +221 -0
  10. package/cli/command-registry.ts +291 -0
  11. package/cli/commands/agent-wrapper.ts +2 -2
  12. package/cli/commands/app-fonts.ts +2 -2
  13. package/cli/commands/assert.ts +3 -3
  14. package/cli/commands/auth.ts +1 -1
  15. package/cli/commands/box/cloud-box.ts +1 -1
  16. package/cli/commands/box/plane-share.ts +2 -2
  17. package/cli/commands/box.ts +4 -6
  18. package/cli/commands/compat.ts +1 -1
  19. package/cli/commands/config.ts +2 -2
  20. package/cli/commands/control.ts +29 -29
  21. package/cli/commands/cpu-profile.ts +7 -7
  22. package/cli/commands/daemon-mac-app.ts +7 -7
  23. package/cli/commands/daemon.ts +10 -10
  24. package/cli/commands/debug.ts +11 -11
  25. package/cli/commands/detox.ts +13 -13
  26. package/cli/commands/diagnose.ts +6 -6
  27. package/cli/commands/do-chain.ts +1 -2
  28. package/cli/commands/electron.ts +1 -3
  29. package/cli/commands/film.ts +3 -3
  30. package/cli/commands/flow.ts +43 -43
  31. package/cli/commands/inspect/count.ts +1 -1
  32. package/cli/commands/inspect/describe.ts +1 -1
  33. package/cli/commands/inspect/env.ts +2 -2
  34. package/cli/commands/inspect/get-layout.ts +1 -1
  35. package/cli/commands/inspect/keyboard.ts +1 -1
  36. package/cli/commands/inspect/list.ts +1 -1
  37. package/cli/commands/inspect/memory.ts +1 -1
  38. package/cli/commands/inspect/resolve-target.ts +1 -1
  39. package/cli/commands/inspect/screens.ts +1 -1
  40. package/cli/commands/inspect/tree.ts +1 -1
  41. package/cli/commands/inspect/url.ts +1 -1
  42. package/cli/commands/inspect/wait-event.ts +5 -5
  43. package/cli/commands/inspect.ts +34 -34
  44. package/cli/commands/install-desktop.ts +3 -3
  45. package/cli/commands/login.ts +6 -6
  46. package/cli/commands/maestro-generate.ts +5 -5
  47. package/cli/commands/maestro.ts +5 -5
  48. package/cli/commands/profile.ts +1 -1
  49. package/cli/commands/record.ts +9 -9
  50. package/cli/commands/runtime.ts +18 -18
  51. package/cli/commands/screenshot-command.ts +1 -1
  52. package/cli/commands/screenshot-layers.ts +5 -5
  53. package/cli/commands/screenshot-mode.ts +1 -1
  54. package/cli/commands/screenshot.ts +8 -8
  55. package/cli/commands/screenshots-capture.ts +5 -5
  56. package/cli/commands/serve.ts +3 -3
  57. package/cli/commands/setup.ts +20 -12
  58. package/cli/commands/skills.ts +5 -5
  59. package/cli/commands/slides.ts +1 -1
  60. package/cli/commands/telemetry.ts +1 -1
  61. package/cli/commands/three-mode.ts +1 -1
  62. package/cli/commands/timeline.ts +8 -8
  63. package/cli/commands/upgrade.ts +116 -131
  64. package/cli/commands/upload.ts +12 -12
  65. package/cli/commands/version.ts +7 -7
  66. package/cli/commands/what-happened.ts +9 -9
  67. package/cli/current-sim.ts +3 -3
  68. package/cli/desktop-companion.ts +1 -1
  69. package/cli/drivers/playwright.ts +9 -9
  70. package/cli/drivers/registry.ts +1 -1
  71. package/cli/drivers/types.ts +1 -1
  72. package/cli/flow-file.ts +2 -2
  73. package/cli/flow-session.ts +1 -1
  74. package/cli/help-core.ts +136 -0
  75. package/cli/help.ts +17 -53
  76. package/cli/hints.ts +5 -5
  77. package/cli/inspect-notice-state.ts +1 -1
  78. package/cli/maestro-js.ts +1 -1
  79. package/cli/outbound-endpoints.ts +23 -5
  80. package/cli/parse-args.ts +19 -66
  81. package/cli/recording-access.ts +1 -1
  82. package/cli/registry.ts +1 -0
  83. package/cli/run-registry.ts +1 -1
  84. package/cli/run-rnx-core.ts +148 -0
  85. package/cli/run-rnx.ts +6 -9
  86. package/cli/runtime-notes.ts +3 -3
  87. package/cli/standalone.ts +4 -0
  88. package/cli/ws-bridge.ts +8 -8
  89. package/detox/config-loader.ts +2 -2
  90. package/detox/index.ts +8 -8
  91. package/detox/jest-preset.cjs +1 -1
  92. package/detox/navigation.ts +2 -2
  93. package/dist-lib/agent-daemon-client.cjs +5 -5
  94. package/dist-lib/agent-events.cjs +1 -1
  95. package/dist-lib/agent-identity.cjs +2 -2
  96. package/dist-lib/agent-sessions.cjs +10 -10
  97. package/dist-lib/attached-projects.cjs +6 -6
  98. package/dist-lib/auth/shared-session.cjs +6 -6
  99. package/dist-lib/backend-origin.cjs +1 -1
  100. package/dist-lib/beta.cjs +1 -1
  101. package/dist-lib/beta.mjs +1 -1
  102. package/dist-lib/bridge-constants.cjs +1 -1
  103. package/dist-lib/bridge-contract-input.cjs +1 -1
  104. package/dist-lib/bridge-contract-input.mjs +1 -1
  105. package/dist-lib/bridge-contract.cjs +1 -1
  106. package/dist-lib/bridge-contract.mjs +1 -1
  107. package/dist-lib/cli-constants.cjs +1 -1
  108. package/dist-lib/config.cjs +25 -25
  109. package/dist-lib/detox/index.cjs +73 -31
  110. package/dist-lib/detox/jest-preset.cjs +1 -1
  111. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  112. package/dist-lib/home-paths.cjs +29 -29
  113. package/dist-lib/host/bridge-host.cjs +128 -49
  114. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  115. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  116. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  117. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  118. package/dist-lib/host/websocket-proxy.cjs +1 -1
  119. package/dist-lib/index.cjs +14 -14
  120. package/dist-lib/jump-to-source-babel.cjs +1 -1
  121. package/dist-lib/menu.cjs +1 -1
  122. package/dist-lib/menu.mjs +1 -1
  123. package/dist-lib/metro-production-bundle.cjs +1 -1
  124. package/dist-lib/metro-production-bundle.mjs +1 -1
  125. package/dist-lib/metro.cjs +8 -8
  126. package/dist-lib/profiles.cjs +12 -12
  127. package/dist-lib/public-brand.cjs +1 -1
  128. package/dist-lib/react-native-host-modules.cjs +1 -1
  129. package/dist-lib/react-native-host-modules.mjs +1 -1
  130. package/dist-lib/render-mode.cjs +1 -1
  131. package/dist-lib/scripts/dev-server-scanner.cjs +8 -8
  132. package/dist-lib/sdk.cjs +1 -1
  133. package/dist-lib/sdk.mjs +1 -1
  134. package/dist-lib/skills.cjs +329 -160
  135. package/dist-lib/vite.cjs +9 -9
  136. package/package.json +4 -11
  137. package/scripts/dev-server-scanner.ts +2 -2
  138. package/scripts/optional-demo-registry.ts +1 -1
  139. package/skills/contrast/SKILL.md +3 -3
  140. package/skills/rnx-debug/SKILL.md +1 -1
  141. package/skills/rnx-test/SKILL.md +2 -2
  142. package/src/agent-identity.ts +1 -1
  143. package/src/agent-sessions.ts +7 -5
  144. package/src/cli-version.ts +12 -4
  145. package/src/config.ts +26 -28
  146. package/src/disk-cleanup.ts +11 -11
  147. package/src/home-paths.ts +28 -28
  148. package/src/host/bridge-host.ts +16 -16
  149. package/src/metro-plugin.ts +2 -2
  150. package/src/profiles.ts +2 -2
  151. package/src/runtime-assets.ts +7 -7
  152. package/src/runtime-delivery.ts +13 -13
  153. package/src/screenshots/orchestrate.ts +1 -1
  154. package/src/screenshots/schema.ts +2 -2
  155. package/src/skills/builtin/a11y-review.ts +2 -2
  156. package/src/skills/builtin/compat-check.ts +2 -2
  157. package/src/skills/builtin/maestro-test.ts +2 -2
  158. package/src/skills/builtin/perf-profile.ts +2 -2
  159. package/src/skills/builtin/screenshot-all.ts +2 -2
  160. package/src/skills/builtin/visual-diff.ts +2 -2
  161. package/src/skills/registry.ts +8 -8
  162. package/src/skills/types.ts +1 -1
  163. package/src/vite-plugin-one.ts +3 -3
  164. package/src/vite-plugin.ts +15 -2
  165. package/dist-cli/bin.js +0 -15
  166. package/dist-cli/chunks/agent-H42FCKFF.js +0 -48
  167. package/dist-cli/chunks/agent-wrapper-BBZKTZS6.js +0 -17
  168. package/dist-cli/chunks/app-fonts-43VXIKF4.js +0 -4
  169. package/dist-cli/chunks/assert-IXOLVO5Z.js +0 -49
  170. package/dist-cli/chunks/auth-KFMFB6FU.js +0 -12
  171. package/dist-cli/chunks/beta-5AO3SJB7.js +0 -4
  172. package/dist-cli/chunks/box-ZHM66L6K.js +0 -1730
  173. package/dist-cli/chunks/camera-FNJVFCDQ.js +0 -33
  174. package/dist-cli/chunks/chunk-37MCSPTE.js +0 -71
  175. package/dist-cli/chunks/chunk-3PEMSUAQ.js +0 -30
  176. package/dist-cli/chunks/chunk-4TQ5HOK3.js +0 -7
  177. package/dist-cli/chunks/chunk-5YZYDEMI.js +0 -4
  178. package/dist-cli/chunks/chunk-6CV3R3XD.js +0 -15
  179. package/dist-cli/chunks/chunk-7LGK5XU6.js +0 -4
  180. package/dist-cli/chunks/chunk-7R2TK2NY.js +0 -4
  181. package/dist-cli/chunks/chunk-7VZZQQEE.js +0 -497
  182. package/dist-cli/chunks/chunk-AFOVILIL.js +0 -130
  183. package/dist-cli/chunks/chunk-BEU7CD7E.js +0 -9
  184. package/dist-cli/chunks/chunk-CE4JQJ6Y.js +0 -6
  185. package/dist-cli/chunks/chunk-CIE6CZXL.js +0 -142
  186. package/dist-cli/chunks/chunk-CSJ7L7ZL.js +0 -312
  187. package/dist-cli/chunks/chunk-CWCQP53A.js +0 -27
  188. package/dist-cli/chunks/chunk-DCS5FK5N.js +0 -7
  189. package/dist-cli/chunks/chunk-DEV3E3MV.js +0 -4
  190. package/dist-cli/chunks/chunk-DGJMIVZM.js +0 -5
  191. package/dist-cli/chunks/chunk-DGX3MN65.js +0 -5
  192. package/dist-cli/chunks/chunk-DNPQMTW5.js +0 -4
  193. package/dist-cli/chunks/chunk-DOVBJBVD.js +0 -5
  194. package/dist-cli/chunks/chunk-DPBJ3S3J.js +0 -3
  195. package/dist-cli/chunks/chunk-FVZBGPCU.js +0 -4
  196. package/dist-cli/chunks/chunk-GDKMOIUT.js +0 -4
  197. package/dist-cli/chunks/chunk-GIF2NJCS.js +0 -32
  198. package/dist-cli/chunks/chunk-GZE57ORL.js +0 -4
  199. package/dist-cli/chunks/chunk-H3U56DKI.js +0 -24
  200. package/dist-cli/chunks/chunk-HZLOYAPH.js +0 -4
  201. package/dist-cli/chunks/chunk-J2IKAEU2.js +0 -4
  202. package/dist-cli/chunks/chunk-JXAXYK7W.js +0 -11
  203. package/dist-cli/chunks/chunk-KJE2O2GK.js +0 -4
  204. package/dist-cli/chunks/chunk-KMNVDZZI.js +0 -423
  205. package/dist-cli/chunks/chunk-LC3QRIRB.js +0 -10
  206. package/dist-cli/chunks/chunk-LGFTAQYC.js +0 -4
  207. package/dist-cli/chunks/chunk-LQMUA5IY.js +0 -4
  208. package/dist-cli/chunks/chunk-MFIQTWC5.js +0 -4
  209. package/dist-cli/chunks/chunk-MGALNF2F.js +0 -7
  210. package/dist-cli/chunks/chunk-MLBZZHOY.js +0 -4
  211. package/dist-cli/chunks/chunk-NNRF7GIB.js +0 -107
  212. package/dist-cli/chunks/chunk-NORLYTTO.js +0 -7
  213. package/dist-cli/chunks/chunk-P6KVGV3H.js +0 -14
  214. package/dist-cli/chunks/chunk-PAJTUK33.js +0 -4
  215. package/dist-cli/chunks/chunk-QELIC5XP.js +0 -4
  216. package/dist-cli/chunks/chunk-QRDF33WD.js +0 -11
  217. package/dist-cli/chunks/chunk-R76BA7C7.js +0 -535
  218. package/dist-cli/chunks/chunk-RVEB4CZ2.js +0 -4
  219. package/dist-cli/chunks/chunk-SK4M7NXT.js +0 -5
  220. package/dist-cli/chunks/chunk-SKMG5DD7.js +0 -5
  221. package/dist-cli/chunks/chunk-TEESPOYR.js +0 -4
  222. package/dist-cli/chunks/chunk-TH2UFGVP.js +0 -4
  223. package/dist-cli/chunks/chunk-TLP3T3VO.js +0 -4
  224. package/dist-cli/chunks/chunk-TZUABDIJ.js +0 -38
  225. package/dist-cli/chunks/chunk-UB2W6OQM.js +0 -99
  226. package/dist-cli/chunks/chunk-UYVXALPB.js +0 -506
  227. package/dist-cli/chunks/chunk-VQDYFFIG.js +0 -5
  228. package/dist-cli/chunks/chunk-VWCNJPCJ.js +0 -5
  229. package/dist-cli/chunks/chunk-VZIK4WIS.js +0 -74
  230. package/dist-cli/chunks/chunk-W3FNXAQP.js +0 -4
  231. package/dist-cli/chunks/chunk-XCDNVNP3.js +0 -4
  232. package/dist-cli/chunks/chunk-XSVILA4Z.js +0 -4
  233. package/dist-cli/chunks/chunk-XUTJ7ZWD.js +0 -4
  234. package/dist-cli/chunks/chunk-YTXY3MHW.js +0 -4
  235. package/dist-cli/chunks/chunk-ZF7PVX44.js +0 -28
  236. package/dist-cli/chunks/chunk-ZSSG7OR7.js +0 -4
  237. package/dist-cli/chunks/cleanup-MLOK2OZA.js +0 -25
  238. package/dist-cli/chunks/cli-version-OBNR366V.js +0 -4
  239. package/dist-cli/chunks/compat-SHMFSKU7.js +0 -23
  240. package/dist-cli/chunks/config-TPEAEUJ2.js +0 -13
  241. package/dist-cli/chunks/connect-3LEXWTE5.js +0 -4
  242. package/dist-cli/chunks/control-Z3FWA6BO.js +0 -4
  243. package/dist-cli/chunks/daemon-RSVYSC65.js +0 -4
  244. package/dist-cli/chunks/debug-GUVAK2KR.js +0 -200
  245. package/dist-cli/chunks/desktop-OOP2PTKP.js +0 -31
  246. package/dist-cli/chunks/detox-C2ILVBEC.js +0 -52
  247. package/dist-cli/chunks/device-NXIQQJWR.js +0 -18
  248. package/dist-cli/chunks/diagnose-2JBGYE5L.js +0 -43
  249. package/dist-cli/chunks/disk-cleanup-VURWJYQV.js +0 -4
  250. package/dist-cli/chunks/do-chain-DJ4UQC7A.js +0 -5
  251. package/dist-cli/chunks/drivers-JMA2OIKU.js +0 -4
  252. package/dist-cli/chunks/env-KTNPKEZR.js +0 -4
  253. package/dist-cli/chunks/film-DCPS7EID.js +0 -74
  254. package/dist-cli/chunks/flow-4DZ7B2OA.js +0 -4
  255. package/dist-cli/chunks/help-34CJMQY2.js +0 -4
  256. package/dist-cli/chunks/hidden-runtime-alias-HHT2C7WE.js +0 -4
  257. package/dist-cli/chunks/home-paths-KTPGCPMS.js +0 -4
  258. package/dist-cli/chunks/inspect-JF5WYJRD.js +0 -4
  259. package/dist-cli/chunks/install-desktop-ZIC4CDXI.js +0 -4
  260. package/dist-cli/chunks/login-TTJAOI2Q.js +0 -26
  261. package/dist-cli/chunks/logout-ERAQ6SKW.js +0 -4
  262. package/dist-cli/chunks/maestro-W46QCF77.js +0 -108
  263. package/dist-cli/chunks/maestro-generate-VBLM3MTU.js +0 -36
  264. package/dist-cli/chunks/mode-ZEDZK7R7.js +0 -26
  265. package/dist-cli/chunks/optional-demo-registry-ZUTPSVYQ.js +0 -4
  266. package/dist-cli/chunks/perf-YVT2WXT4.js +0 -48
  267. package/dist-cli/chunks/permissions-L7VVDHFP.js +0 -13
  268. package/dist-cli/chunks/platform-7TJOU2FB.js +0 -6
  269. package/dist-cli/chunks/privacy-57UOTB5J.js +0 -4
  270. package/dist-cli/chunks/record-VXG37P7U.js +0 -72
  271. package/dist-cli/chunks/report-issue-WNNOBZHC.js +0 -29
  272. package/dist-cli/chunks/reset-H5NBFE5U.js +0 -4
  273. package/dist-cli/chunks/resolve-target-57TK5WLE.js +0 -4
  274. package/dist-cli/chunks/runtime-QU2NIF2K.js +0 -4
  275. package/dist-cli/chunks/screenshot-command-AN56TTG7.js +0 -159
  276. package/dist-cli/chunks/screenshot-layers-3W5R7DB2.js +0 -20
  277. package/dist-cli/chunks/screenshots-capture-6AWJY7XZ.js +0 -42
  278. package/dist-cli/chunks/serve-GLYO5Q7J.js +0 -56
  279. package/dist-cli/chunks/setup-UA2HLD7S.js +0 -4
  280. package/dist-cli/chunks/sim-client-5C2RDQQO.js +0 -4
  281. package/dist-cli/chunks/skills-EYXWBRNQ.js +0 -50
  282. package/dist-cli/chunks/state-REJ7W6K3.js +0 -14
  283. package/dist-cli/chunks/storage-CFMDHI3V.js +0 -37
  284. package/dist-cli/chunks/store-XMCUA45G.js +0 -4
  285. package/dist-cli/chunks/telemetry-FBL3NAKB.js +0 -4
  286. package/dist-cli/chunks/timeline-HMCHN5FO.js +0 -24
  287. package/dist-cli/chunks/upgrade-2QSPAA3P.js +0 -7
  288. package/dist-cli/chunks/upload-DUQBKZYV.js +0 -4
  289. package/dist-cli/chunks/version-IOA6QFGB.js +0 -6
  290. package/dist-cli/chunks/web-NCGUYVCJ.js +0 -4
  291. package/dist-cli/chunks/welcome-QYGSQCWQ.js +0 -5
  292. package/dist-cli/chunks/what-happened-YTOUK4LO.js +0 -25
  293. package/dist-cli/chunks/ws-bridge-OF4OZARG.js +0 -4
  294. package/scripts/postinstall.cjs +0 -3
  295. package/scripts/preuninstall.cjs +0 -118
@@ -1,506 +0,0 @@
1
- /*! rnx v0.1.376 | (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 y,c as P}from"./chunk-VWCNJPCJ.js";import{a as f,b as S}from"./chunk-DCS5FK5N.js";import{b}from"./chunk-DGX3MN65.js";import{a as v}from"./chunk-7R2TK2NY.js";function M(){let e=f();return e?{available:!0,reason:null,detail:`${e.kind} @ ${e.path}`}:{available:!1,reason:"rnx desktop app not installed (run `rnx desktop install`)"}}async function A(e){let o=f();if(!o)return{launched:!1,message:"rnx desktop app not installed"};try{let r=await S(e.url,o,{device:e.device,profileId:e.profileId,ephemeralProfile:e.ephemeralProfile,ownerPid:e.ownerPid});return r.launched?{launched:!0,message:e.url?`electron launched via ${r.via} \u2192 ${e.url}`:`electron launched via ${r.via}`,target:r.target,attachUrl:e.url}:{launched:!1,message:"desktop companion failed to start"}}catch(r){return{launched:!1,message:`electron launch failed: ${r instanceof Error?r.message:String(r)}`}}}var k={id:"electron",name:"electron",description:"rnx desktop companion app (native window, menu bar)",kind:"native",availability:M,launch:A};import{spawn as B}from"child_process";import{closeSync as F,mkdtempSync as G,openSync as U,readFileSync as q}from"fs";import{tmpdir as T}from"os";import{join as I}from"path";import{spawnSync as O}from"node:child_process";import{existsSync as _,readFileSync as R}from"node:fs";import{createRequire as L}from"node:module";import{dirname as W,join as N}from"node:path";var $=`
5
- const { existsSync } = require('node:fs');
6
- const modulePath = process.env.SOOTSIM_PW_MODULE;
7
- try {
8
- const playwright = require(modulePath);
9
- const browser = playwright && playwright.chromium;
10
- if (!browser || typeof browser.executablePath !== 'function') {
11
- throw new Error('resolved package does not expose browser "chromium"');
12
- }
13
- const executablePath = browser.executablePath();
14
- process.stdout.write(JSON.stringify({ executablePath, exists: existsSync(executablePath) }));
15
- } catch (error) {
16
- process.stderr.write(String((error && error.stack) || error));
17
- process.exit(1);
18
- }
19
- `;function w(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function g(){let e=[`${process.cwd()}/`];process.argv[1]&&e.push(process.argv[1]);for(let o of e)try{let r=L(o);for(let t of["playwright","playwright-chromium","playwright-core"])try{let n=r.resolve(t),i=r.resolve(`${t}/package.json`),a=JSON.parse(R(i,"utf8"));if(!w(a)||typeof a.version!="string")continue;let l=a.bin,s=null;if(typeof l=="string")s=l;else if(w(l)){let d=l.playwright??l["playwright-core"],p=Object.values(l).find(c=>typeof c=="string");s=typeof d=="string"?d:typeof p=="string"?p:null}if(!s)continue;let u=N(W(i),s);if(!_(u))continue;return{spec:t,modulePath:n,cliPath:u,version:a.version}}catch{}}catch{}return null}function x(e,o){let r=O(process.execPath,["-e",$],{env:{...o,SOOTSIM_PW_MODULE:e.modulePath},encoding:"utf8",timeout:3e4});if(r.status!==0){let t=(r.stderr||r.error?.message||"browser probe failed").trim();return{ok:!1,message:`could not inspect ${e.spec}@${e.version} chromium: ${t}`}}try{let t=JSON.parse(r.stdout);if(!w(t)||typeof t.executablePath!="string"||typeof t.exists!="boolean")throw new Error("probe returned an invalid result");return{ok:!0,executablePath:t.executablePath,exists:t.exists&&_(t.executablePath)}}catch(t){return{ok:!1,message:`could not inspect ${e.spec}@${e.version} chromium: ${t instanceof Error?t.message:String(t)}`}}}function D(e,o=process.env){let r=x(e,o);if(!r.ok)return r;if(r.exists)return{ok:!0,executablePath:r.executablePath,installed:!1};let t=O(process.execPath,[e.cliPath,"install","chromium"],{env:o,encoding:"utf8",timeout:10*6e4});if(t.status!==0){let i=(t.stderr||t.stdout||t.error?.message||"browser install failed").trim(),a=i.length<=4e3?i:i.slice(-4e3);return{ok:!1,message:`${e.spec}@${e.version} requires chromium at ${r.executablePath}, but its browser install failed${a?`:
20
- ${a}`:""}`}}let n=x(e,o);return n.ok?n.exists?{ok:!0,executablePath:n.executablePath,installed:!0}:{ok:!1,message:`${e.spec}@${e.version} browser install completed, but its required chromium executable is still missing at ${n.executablePath}`}:n}var j=`
21
- const modulePath = process.env.SOOTSIM_PW_MODULE;
22
- const url = process.env.SOOTSIM_PW_URL;
23
- // the WS bridge port the sim page must register with, injected below as
24
- // window.__sootsimBridgePort so the page skips its shell-port heuristic (which
25
- // assumes the default offset and breaks when the dev bridge drifted).
26
- const bridgePort = process.env.SOOTSIM_PW_BRIDGE_PORT || '';
27
- const headless = process.env.SOOTSIM_PW_HEADLESS === '1';
28
- const callerUserDataDir = process.env.SOOTSIM_PW_USERDATADIR || '';
29
- // pid of the session that launched us (its topmost non-init ancestor). when
30
- // that process exits we tear Chrome down \u2014 see startOwnerWatch below. it is a
31
- // required lifetime bound: an invalid value aborts before Chrome launches.
32
- // SOOTSIM_PW_OWNER_POLL_MS is a test-only override of the 5s poll interval;
33
- // production never sets it.
34
- const ownerPid = Number(process.env.SOOTSIM_PW_OWNER_PID || 0);
35
- const ownerPollMs = Number(process.env.SOOTSIM_PW_OWNER_POLL_MS || 5000);
36
- // optional CDP port \u2014 exposes Chrome's remote-debugging endpoint so a
37
- // bridge-driven sim can also be cpu-profiled (sootsim perf cpu --cdp-port).
38
- // playwright keeps its own pipe connection; the port is an additional endpoint.
39
- const cdpPort = process.env.SOOTSIM_PW_CDP_PORT || '';
40
- // extra chromium launch args, space-separated. a linux GPU runner injects
41
- // '--use-angle=vulkan --enable-features=Vulkan' here so chrome binds the
42
- // real GPU instead of silently falling back to swiftshader software
43
- // rendering (which pegs cores and produces ~1fps canvas capture).
44
- const extraChromeArgs = (process.env.SOOTSIM_PW_CHROME_ARGS || '')
45
- .split(' ')
46
- .filter(Boolean);
47
- // Local CanvasKit work must never fall back to Playwright's software
48
- // renderer. CI may use the bundled browser for non-interactive coverage, but
49
- // local test drives fail closed unless the hardware-backed test browser is
50
- // proven after launch.
51
- const hardwareGpuRequired = process.env.CI !== '1' && process.env.CI !== 'true';
52
- const softwareRendererPattern = /swiftshader|software(?: rasterizer)?|llvmpipe|lavapipe|softpipe/i;
53
- // page viewport as '<w>x<h>'. the caller sizes it from the device profile;
54
- // the fallback is phone-shaped because the page hosts a phone sim \u2014 the
55
- // playwright default (1280x720 desktop) letterboxes the device frame.
56
- const viewportSpec = /^(\\d+)x(\\d+)$/.exec(process.env.SOOTSIM_PW_VIEWPORT || '');
57
- const viewport = viewportSpec
58
- ? { width: Number(viewportSpec[1]), height: Number(viewportSpec[2]) }
59
- : { width: 600, height: 900 };
60
- // device pixels per css pixel. playwright's default is 1, which makes the
61
- // engine allocate its canvas backing store at HALF the resolution a normal
62
- // retina-mac chrome would (dpr 2) \u2014 the sim looks visibly soft. default to 2
63
- // so a driver-launched sim matches what the user sees in their own browser.
64
- const deviceScaleFactor = Number(process.env.SOOTSIM_PW_DSF || 2);
65
- const closeTimeoutMs = Number(process.env.SOOTSIM_PW_CLOSE_TIMEOUT_MS || 2500);
66
- const connectAckFile = process.env.SOOTSIM_PW_CONNECTED_ACK_FILE || '';
67
- const disposableBrowserCacheDirs = new Set(${JSON.stringify(v)});
68
- const { existsSync, mkdtempSync, readdirSync, rmSync, unlinkSync } = require('fs');
69
- const { execSync } = require('child_process');
70
- const { tmpdir } = require('os');
71
- const { join } = require('path');
72
- // chrome tree reaper \u2014 playwright's browser.close() and even SIGKILLing the
73
- // root chrome process do NOT reliably take down the helper tree (gpu, renderer,
74
- // network/storage utilities). they reparent to launchd/init and survive, each
75
- // one busy enough to peg CPU at 100%+. close() only reaches the root.
76
- //
77
- // the prior approach was \`pgrep -f ms-playwright/[c]hromium\`. it never matched
78
- // system Chrome, so the reaper was a no-op in the common case and every
79
- // aborted/closed \`sootsim open\` leaked a renderer + gpu helper burning 100%+
80
- // CPU until manually killed (multiple incidents 2026-06).
81
- //
82
- // fix: identify our chrome tree by its UNIQUE user-data-dir. every helper a
83
- // chrome root spawns inherits \`--user-data-dir=<dir>\` in its cmdline, so
84
- // \`pgrep -f <profileDir>\` finds exactly the tree we launched and nothing else
85
- // \u2014 Chrome for Testing and bundled playwright chromium alike. as a side benefit we
86
- // no longer need the launch / launchPersistentContext fork: we ALWAYS use a
87
- // profile dir (mkdtemp'd if the caller didn't pass one, then removed at exit).
88
- const reapEnabled = process.platform !== 'win32';
89
- let profileDir = callerUserDataDir;
90
- let ephemeralProfile = false;
91
- if (!profileDir) {
92
- profileDir = mkdtempSync(join(tmpdir(), 'sootsim-playwright-host-'));
93
- ephemeralProfile = true;
94
- }
95
- // browser HTTP caches are acceleration data, not profile identity. give each
96
- // host a bounded temporary cache so persistent named profiles retain cookies
97
- // and storage without multiplying a private cache for every profile.
98
- const diskCacheDir = mkdtempSync(join(tmpdir(), 'sootsim-playwright-cache-'));
99
- const chromePidsByProfile = () => {
100
- if (!reapEnabled) return [];
101
- try {
102
- return execSync('pgrep -f ' + profileDir + ' || true', { stdio: ['ignore', 'pipe', 'ignore'] })
103
- .toString().split('\\n').filter(Boolean).map((p) => Number(p))
104
- .filter((p) => p && p !== process.pid);
105
- } catch { return []; }
106
- };
107
- const chromeCommandsByProfile = () => {
108
- if (!reapEnabled) return [];
109
- const pids = chromePidsByProfile();
110
- if (pids.length === 0) return [];
111
- try {
112
- return execSync('ps -p ' + pids.join(',') + ' -o command=', {
113
- stdio: ['ignore', 'pipe', 'ignore'],
114
- }).toString().split('\\n').filter(Boolean);
115
- } catch { return []; }
116
- };
117
- const assertNoUnsafeSwiftShaderFlag = () => {
118
- if (!hardwareGpuRequired) return;
119
- const unsafe = chromeCommandsByProfile().find((command) =>
120
- command.includes('--enable-unsafe-swiftshader') ||
121
- /--use-angle=(?:swiftshader|swiftshader-webgl)(?:\\s|$)/i.test(command)
122
- );
123
- if (unsafe) {
124
- throw new Error(
125
- '[playwright-driver] refused software-rendering Chrome: launched process contains a SwiftShader flag'
126
- );
127
- }
128
- };
129
- const killTree = (pid) => {
130
- let kids = [];
131
- try {
132
- kids = execSync('pgrep -P ' + pid + ' || true', { stdio: ['ignore', 'pipe', 'ignore'] })
133
- .toString().split('\\n').filter(Boolean);
134
- } catch {}
135
- for (const k of kids) killTree(Number(k));
136
- try { process.kill(pid, 'SIGKILL'); } catch {}
137
- };
138
- const reapChrome = () => { for (const pid of chromePidsByProfile()) killTree(pid); };
139
- const removeDisposableCaches = (root) => {
140
- let children = [];
141
- try { children = readdirSync(root, { withFileTypes: true }); } catch { return; }
142
- for (const child of children) {
143
- if (!child.isDirectory() || child.isSymbolicLink()) continue;
144
- const childPath = join(root, child.name);
145
- if (disposableBrowserCacheDirs.has(child.name)) {
146
- try { rmSync(childPath, { recursive: true, force: true }); } catch {}
147
- continue;
148
- }
149
- removeDisposableCaches(childPath);
150
- }
151
- };
152
- const cleanupProfile = () => {
153
- try { rmSync(diskCacheDir, { recursive: true, force: true }); } catch {}
154
- if (ephemeralProfile) {
155
- try { rmSync(profileDir, { recursive: true, force: true }); } catch {}
156
- return;
157
- }
158
- removeDisposableCaches(profileDir);
159
- };
160
- (async () => {
161
- const pw = require(modulePath);
162
- let context;
163
- let keepAlive = null;
164
- let connectTimer = null;
165
- let connectAckPoll = null;
166
- let ownerWatch = null;
167
- let connected = false;
168
- let shuttingDown = false;
169
- const clearConnectTimer = () => {
170
- if (connectTimer) {
171
- clearTimeout(connectTimer);
172
- connectTimer = null;
173
- }
174
- if (connectAckPoll) {
175
- clearInterval(connectAckPoll);
176
- connectAckPoll = null;
177
- }
178
- };
179
- const markConnected = () => {
180
- connected = true;
181
- clearConnectTimer();
182
- };
183
- const ackFileExists = () => {
184
- if (!connectAckFile) return false;
185
- try { return existsSync(connectAckFile); } catch { return false; }
186
- };
187
- const bounded = async (label, work, timeoutMs) => {
188
- let timer = null;
189
- try {
190
- const timeout = new Promise((resolve) => {
191
- timer = setTimeout(() => resolve({ timedOut: true }), timeoutMs);
192
- });
193
- if (typeof timer.unref === 'function') timer.unref();
194
- const result = await Promise.race([
195
- Promise.resolve().then(work).then(
196
- () => ({ timedOut: false }),
197
- (error) => ({ timedOut: false, error }),
198
- ),
199
- timeout,
200
- ]);
201
- if (result && result.timedOut) {
202
- process.stderr.write('[shutdown-timeout] ' + label + ' exceeded ' + timeoutMs + 'ms\\n');
203
- return false;
204
- }
205
- if (result && result.error) {
206
- process.stderr.write('[shutdown-error] ' + label + ': ' + String((result.error && result.error.message) || result.error) + '\\n');
207
- return false;
208
- }
209
- return true;
210
- } finally {
211
- if (timer) clearTimeout(timer);
212
- }
213
- };
214
- const browserProcess = () => {
215
- if (context && typeof context.browser === 'function') {
216
- try {
217
- const b = context.browser();
218
- if (b && typeof b.process === 'function') return b.process();
219
- } catch {}
220
- }
221
- return null;
222
- };
223
- const processIsAlive = (proc) => {
224
- if (!proc || !proc.pid) return false;
225
- try {
226
- process.kill(proc.pid, 0);
227
- return true;
228
- } catch (err) {
229
- return err && err.code === 'EPERM';
230
- }
231
- };
232
- const terminateBrowserProcess = async () => {
233
- const proc = browserProcess();
234
- if (!proc || !proc.pid || !processIsAlive(proc)) return;
235
- try { proc.kill('SIGTERM'); } catch {}
236
- await bounded('browser process exit after SIGTERM', async () => {
237
- while (processIsAlive(proc)) {
238
- await new Promise((resolve) => setTimeout(resolve, 50));
239
- }
240
- }, 600);
241
- if (!processIsAlive(proc)) return;
242
- try { proc.kill('SIGKILL'); } catch {}
243
- };
244
- const shutdown = async (code = 0) => {
245
- if (shuttingDown) return;
246
- shuttingDown = true;
247
- clearConnectTimer();
248
- if (keepAlive) clearInterval(keepAlive);
249
- if (ownerWatch) clearInterval(ownerWatch);
250
- const timeoutMs = Number.isFinite(closeTimeoutMs) && closeTimeoutMs > 0 ? closeTimeoutMs : 2500;
251
- if (context) await bounded('context.close', () => context.close(), timeoutMs);
252
- await terminateBrowserProcess();
253
- // close() + root-SIGKILL above handle the graceful case; the helper tree
254
- // (gpu/renderer/utilities) reparents and survives every one of those, so
255
- // we always sweep by our unique profile dir as the load-bearing teardown.
256
- reapChrome();
257
- cleanupProfile();
258
- if (connectAckFile) {
259
- try { unlinkSync(connectAckFile); } catch {}
260
- }
261
- process.exit(code);
262
- };
263
- process.once('SIGTERM', () => { void shutdown(0); });
264
- process.once('SIGINT', () => { void shutdown(0); });
265
- // the launch-failure path at the bottom of this script exits without going
266
- // through shutdown(); the exit hook (sync sweep) still reaps the tree.
267
- process.on('exit', () => { reapChrome(); cleanupProfile(); });
268
- // owner-liveness watchdog \u2014 the load-bearing fix for leaked Chrome hosts.
269
- // we are spawned detached + unref'd so \`sootsim open\` returns immediately,
270
- // which means nothing in the OS process tree ties Chrome's lifetime to the
271
- // session that asked for it. once the sim connects, the connect-timeout
272
- // safety net is cleared, so absent an explicit \`sootsim close\` (or the
273
- // daemon's idle reaper closing the sim socket) the host would hold Chrome
274
- // open forever after its owner exits. poll the owning session's pid and tear
275
- // down when it's gone. ESRCH (kill throws) = owner exited; EPERM = alive but
276
- // not signalable by us, which still counts as alive.
277
- const startOwnerWatch = () => {
278
- if (!Number.isInteger(ownerPid) || ownerPid <= 1) {
279
- throw new Error('[playwright-driver] missing valid owning process; refusing unsupervised browser host');
280
- }
281
- const intervalMs = Number.isFinite(ownerPollMs) && ownerPollMs > 0 ? ownerPollMs : 5000;
282
- ownerWatch = setInterval(() => {
283
- try {
284
- process.kill(ownerPid, 0);
285
- } catch (err) {
286
- if (err && err.code === 'EPERM') return;
287
- process.stderr.write('[owner-gone] owning process ' + ownerPid + ' exited; closing playwright host\\n');
288
- void shutdown(0);
289
- }
290
- }, intervalMs);
291
- if (typeof ownerWatch.unref === 'function') ownerWatch.unref();
292
- };
293
- startOwnerWatch();
294
- // Local rendering uses Playwright's full Chrome for Testing app. On macOS its
295
- // com.google.chrome.for.testing identity cannot intercept open/quit events for
296
- // the user's com.google.Chrome browser. CI may use chromium_headless_shell;
297
- // local rendering fails closed because that shell has no GPU and silently
298
- // chooses SwiftShader. NOTE: this is NOT enough to make \`sootsim perf cpu\`
299
- // work \u2014 that profiles the tenant *worker*, and the JS Self-Profiler API
300
- // cannot be constructed in a dedicated worker (see
301
- // worker-handlers/cpu-profile.ts). cpu-profile needs a CDP-based profiler
302
- // instead.
303
- if (
304
- hardwareGpuRequired &&
305
- extraChromeArgs.some((arg) =>
306
- arg === '--enable-unsafe-swiftshader' ||
307
- /^--use-angle=(?:swiftshader|swiftshader-webgl)$/i.test(arg)
308
- )
309
- ) {
310
- throw new Error('[playwright-driver] refused SwiftShader launch arguments');
311
- }
312
- // one browser path per environment: the full, separately identified test app
313
- // locally; chromium_headless_shell on CI. never launch a branded user browser.
314
- const channelsToTry = hardwareGpuRequired ? ['chromium'] : [null];
315
- const launchWith = async (channel) => {
316
- const opts = channel
317
- ? { headless, channel, viewport, deviceScaleFactor }
318
- : { headless, viewport, deviceScaleFactor };
319
- // playwright injects --force-color-profile=srgb by default, which reads
320
- // visibly washed-out next to a normal chrome window on a wide-gamut mac
321
- // display. strip it so driver-launched sims color-match the user's own
322
- // browser (real incident 2026-07-09: "low res and whitewashed" sim).
323
- opts.ignoreDefaultArgs = ['--force-color-profile=srgb'];
324
- // headless chromium backgrounds/occludes the renderer and throttles rAF +
325
- // timers to ~1fps, which silently starves combined/video frame capture
326
- // (was 47 frames over 63s -> frozen-looking mp4). keep the render loop at
327
- // full rate so the recorder captures real motion. document.hidden stays
328
- // false in headless, so assertTabVisibleForCapture never caught this \u2014 it
329
- // has to be fixed at the launch flags.
330
- opts.args = [
331
- // the compositor renders through skia graphite on webgpu, so a launch
332
- // without navigator.gpu boots to a fatal instead of a sim.
333
- '--enable-unsafe-webgpu',
334
- '--disk-cache-dir=' + diskCacheDir,
335
- '--disk-cache-size=67108864',
336
- '--disable-background-timer-throttling',
337
- '--disable-backgrounding-occluded-windows',
338
- '--disable-renderer-backgrounding',
339
- ];
340
- if (channel) {
341
- // the full test browser can bind the real platform GPU \u2014 force the native
342
- // ANGLE backend and strip playwright's --enable-unsafe-swiftshader
343
- // default arg. without both, headless chrome silently falls back to
344
- // swiftshader software rendering for the CanvasKit/WebGL canvas and
345
- // pegs every core. SOOTSIM_PW_CHROME_ARGS is appended later, so an
346
- // env-injected --use-angle=... still overrides (last flag wins).
347
- const angle = process.platform === 'darwin' ? 'metal'
348
- : process.platform === 'linux' ? 'vulkan' : 'default';
349
- opts.args.unshift(
350
- '--use-angle=' + angle,
351
- '--enable-gpu',
352
- '--enable-gpu-rasterization',
353
- '--enable-zero-copy',
354
- '--ignore-gpu-blocklist',
355
- );
356
- opts.ignoreDefaultArgs.push('--enable-unsafe-swiftshader');
357
- } else {
358
- // playwright's bundled software chromium exposes no navigator.gpu until
359
- // Vulkan is named explicitly, and webgpu is the only backend there is.
360
- opts.args.push('--enable-features=Vulkan');
361
- }
362
- if (cdpPort) opts.args.push('--remote-debugging-port=' + cdpPort);
363
- if (extraChromeArgs.length) opts.args.push(...extraChromeArgs);
364
- // headed: size the OS window to the (phone-shaped) viewport too, plus
365
- // room for chrome's own toolbar, so the window isn't desktop-shaped
366
- // around a letterboxed page.
367
- if (!headless) opts.args.push('--window-size=' + viewport.width + ',' + (viewport.height + 88));
368
- // ALWAYS persistent: every chrome process inherits --user-data-dir=<dir>
369
- // in its cmdline, which is how reapChrome() finds the whole tree (root +
370
- // helpers) on shutdown. without a unique dir there is no way to attribute
371
- // an orphaned helper back to us, which is the leak we just fixed.
372
- return await pw.chromium.launchPersistentContext(profileDir, opts);
373
- };
374
- let launchErr = null;
375
- let launchedChannel = null;
376
- for (const channel of channelsToTry) {
377
- try {
378
- context = await launchWith(channel);
379
- launchedChannel = channel || 'chromium';
380
- launchErr = null;
381
- break;
382
- } catch (err) {
383
- launchErr = err;
384
- const msg = err && err.message ? String(err.message) : '';
385
- const isMissingChannel =
386
- /not found at/i.test(msg) ||
387
- /not installed/i.test(msg) ||
388
- /Chromium distribution/i.test(msg);
389
- if (!isMissingChannel) throw err; // unexpected failure: bubble up
390
- if (channel) {
391
- const next = hardwareGpuRequired
392
- ? '; bundled Chromium is disabled for local GPU work\\n'
393
- : ', falling back to bundled chromium\\n';
394
- process.stderr.write('[playwright-driver] channel "' + channel + '" not available' + next);
395
- }
396
- }
397
- }
398
- if (launchErr) throw launchErr;
399
- if (launchedChannel) {
400
- process.stderr.write('[playwright-driver] launched ' + launchedChannel + '\\n');
401
- }
402
- // grant camera up front so the sim's Camera app reaches the host webcam
403
- // through getUserMedia, mirroring a real iOS simulator where the camera just
404
- // works. without this the unhandled chrome permission prompt auto-denies and
405
- // CameraApp renders its "Camera Access Required" placeholder.
406
- await context.grantPermissions(['camera']);
407
- const hostMeta = {
408
- sootsimHostDriver: 'playwright',
409
- sootsimHostPid: process.pid,
410
- sootsimHostOwnerPid: ownerPid,
411
- sootsimHostStartedAt: Date.now(),
412
- };
413
- // inject the resolved bridge port (numeric literal) BEFORE the page runs, so
414
- // the shell/engine talk to the daemon this driver owns. addInitScript runs
415
- // ahead of every page script, and the vite dev plugin only fills the value in
416
- // when it is still unset, so this one wins. plain assignment, NOT
417
- // defineProperty: other injectors also assign to it, and a non-writable
418
- // property would throw at that assignment and crash boot.
419
- const bridgePortInject = bridgePort
420
- ? 'window.__sootsimBridgePort = ' + Number(bridgePort) + ';'
421
- : '';
422
- await context.addInitScript({
423
- content: 'Object.defineProperty(window, "__sootsimHostMeta", { value: ' + JSON.stringify(hostMeta) + ', configurable: true });' + bridgePortInject,
424
- });
425
- await context.exposeBinding('__sootsimHostClose', async () => {
426
- await shutdown(0);
427
- });
428
- const connectTimeoutMs = Number(process.env.SOOTSIM_PW_CONNECT_TIMEOUT_MS || 120000);
429
- if (connectAckFile) {
430
- connectAckPoll = setInterval(() => {
431
- if (ackFileExists()) markConnected();
432
- }, 500);
433
- if (typeof connectAckPoll.unref === 'function') connectAckPoll.unref();
434
- }
435
- connectTimer = setTimeout(() => {
436
- if (ackFileExists()) {
437
- markConnected();
438
- return;
439
- }
440
- if (connected) return;
441
- process.stderr.write('[connect-timeout] sim did not register with the bridge within ' + connectTimeoutMs + 'ms; closing playwright host\\n');
442
- void shutdown(2);
443
- }, Number.isFinite(connectTimeoutMs) && connectTimeoutMs > 0 ? connectTimeoutMs : 120000);
444
- if (typeof connectTimer.unref === 'function') connectTimer.unref();
445
- const page = await context.newPage();
446
- if (hardwareGpuRequired) {
447
- assertNoUnsafeSwiftShaderFlag();
448
- const gpu = await page.evaluate(() => {
449
- const canvas = document.createElement('canvas');
450
- const gl =
451
- canvas.getContext('webgl2', { powerPreference: 'high-performance' }) ||
452
- canvas.getContext('webgl', { powerPreference: 'high-performance' });
453
- if (!gl) return { renderer: null, vendor: null };
454
- const info = gl.getExtension('WEBGL_debug_renderer_info');
455
- return {
456
- renderer: info ? String(gl.getParameter(info.UNMASKED_RENDERER_WEBGL)) : null,
457
- vendor: info ? String(gl.getParameter(info.UNMASKED_VENDOR_WEBGL)) : null,
458
- };
459
- });
460
- if (!gpu.renderer) {
461
- throw new Error(
462
- '[playwright-driver] could not prove a hardware WebGL renderer; refusing local render-heavy launch'
463
- );
464
- }
465
- if (softwareRendererPattern.test(gpu.renderer)) {
466
- throw new Error('[playwright-driver] refused software WebGL renderer: ' + gpu.renderer);
467
- }
468
- assertNoUnsafeSwiftShaderFlag();
469
- process.stderr.write(
470
- '[playwright-driver] hardware WebGL renderer: ' + gpu.renderer +
471
- (gpu.vendor ? ' (' + gpu.vendor + ')' : '') + '\\n'
472
- );
473
- }
474
- // surface page-side failures (engine boot crash, failed WS registration)
475
- // to stderr so a sim that never connects produces a real diagnostic
476
- // instead of a silent "timed out waiting for opened sim to connect".
477
- page.on('pageerror', (e) => {
478
- process.stderr.write('[pageerror] ' + ((e && e.stack) || e) + '\\n');
479
- });
480
- page.on('console', (m) => {
481
- if (m.type() === 'error') {
482
- process.stderr.write('[console.error] ' + m.text() + '\\n');
483
- }
484
- });
485
- page.on('crash', () => process.stderr.write('[page] renderer crashed\\n'));
486
- try {
487
- await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
488
- } catch (err) {
489
- process.stderr.write('[goto] ' + String((err && err.message) || err) + '\\n');
490
- }
491
- keepAlive = setInterval(() => {}, 1 << 30);
492
- // browser disconnect (e.g. user killed chrome from outside) \u2192 tear down.
493
- // we are persistent-only now, so .browser() is the only handle to it.
494
- try {
495
- const b = context.browser && context.browser();
496
- if (b && typeof b.on === 'function') b.on('disconnected', () => { void shutdown(0); });
497
- } catch {}
498
- context.on('close', () => { void shutdown(0); });
499
- page.on('close', () => { void shutdown(0); });
500
- })().catch((err) => {
501
- process.stderr.write(String((err && err.stack) || err) + '\\n');
502
- process.exit(1);
503
- });
504
- `;function H(){let e=g();return e?{available:!0,reason:null,detail:`resolved via ${e.spec}@${e.version}`}:{available:!1,reason:"playwright not installed in the current workspace"}}function K(e,o){return process.platform!=="linux"||e.headless||process.env.DISPLAY||process.env.WAYLAND_DISPLAY||!/missing x server|cannot open display|x server|x11/i.test(o)?null:" hint: linux without DISPLAY/WAYLAND_DISPLAY \u2014 rerun without --headed (or add --headless) to run playwright headless."}function Y(e){return e.profileId?y(P(e.profileId).id):e.ephemeralProfile?G(I(T(),"sootsim-playwright-profile-")):""}async function J(e){let o=g();if(!o)return{launched:!1,message:"playwright not installed \u2014 run `bun add -D playwright` first"};if(!e.url)return{launched:!1,message:"playwright driver requires a target url"};let r=e.ownerPid;if(r===void 0||!Number.isInteger(r)||r<=1)return{launched:!1,message:"playwright driver requires a valid owning session process"};let t={...process.env},n=D(o,t);if(!n.ok)return{launched:!1,message:`playwright browser provisioning failed: ${n.message}`};let i=I(T(),`sootsim-playwright-host-${Date.now().toString(36)}-${process.pid}.log`),a=`${i}.connected`,l=U(i,"a");try{let s=B(process.execPath,["-e",j],{detached:!0,stdio:["ignore","ignore",l],env:{...t,SOOTSIM_PW_MODULE:o.modulePath,SOOTSIM_PW_URL:e.url,SOOTSIM_PW_BRIDGE_PORT:e.bridgePort?String(e.bridgePort):"",SOOTSIM_PW_HEADLESS:e.headless??!0?"1":"0",SOOTSIM_PW_USERDATADIR:Y(e),SOOTSIM_PW_CDP_PORT:e.cdpPort?String(e.cdpPort):"",...e.viewport?{SOOTSIM_PW_VIEWPORT:`${e.viewport.width}x${e.viewport.height}`}:{},SOOTSIM_PW_CONNECTED_ACK_FILE:a,SOOTSIM_PW_CONNECT_TIMEOUT_MS:String(e.connectTimeoutMs??12e4),SOOTSIM_PW_OWNER_PID:String(r)}});s.unref();let u=await new Promise(c=>{let m=setTimeout(()=>c(null),4e3);s.once("exit",C=>{clearTimeout(m),c(C??0)})});if(u!==null){let c=q(i,"utf8").trim(),m=K(e,c);return{launched:!1,message:`playwright host exited early (code ${u}) \u2014 host log ${i}${c?`:
505
- ${c}`:""}${m?`
506
- ${m}`:""}`}}let d=b(r),p=` \u2014 browser closes when pid ${r}${d?` (${d})`:""} exits`;return{launched:!0,message:`playwright chrome launched \u2192 ${e.url}${p}`,pid:s.pid,target:o.spec,attachUrl:e.url,connectAckFile:a,diagnosticLogPath:i}}catch(s){return{launched:!1,message:`playwright launch failed: ${s instanceof Error?s.message:String(s)}`}}finally{F(l)}}var E={id:"playwright",name:"playwright",description:"programmatic chromium via the playwright package \u2014 headless default",kind:"automation",availability:H,launch:J};var h=[k,E];function pe(){return h}function me(e){return h.find(o=>o.id===e)??null}function fe(e,o){if(e)return h.find(t=>t.id===e)??null;for(let r of o){let t=h.find(n=>n.id===r);if(t&&t.availability().available)return t}return null}function we(){return h.map(e=>{let o=e.availability();return{id:e.id,name:e.name,kind:e.kind,description:e.description,available:o.available,reason:o.reason,detail:o.detail??null}})}export{k as a,E as b,h as c,pe as d,me as e,fe as f,we as g};
@@ -1,5 +0,0 @@
1
- /*! rnx v0.1.376 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{e as f}from"./chunk-CWCQP53A.js";import{existsSync as m,mkdirSync as g,readFileSync as h,writeFileSync as S,rmSync as F}from"fs";import{tmpdir as y}from"os";import{dirname as b,join as p}from"path";var w=new Map;function o(e,n){w.set(e,n)}var s=1;function a(){return p(y(),`sootsim-cli-hints-${f()}.json`)}function d(){return p(y(),"sootsim-cli-hints-global.json")}function u(e){if(!m(e))return{version:s,shown:{}};try{let n=JSON.parse(h(e,"utf8"));return n?.version!==s||!n?.shown?{version:s,shown:{}}:n}catch{return{version:s,shown:{}}}}function l(e,n){try{g(b(e),{recursive:!0}),S(e,JSON.stringify(n)+`
5
- `)}catch{}}function v(){let e=(process.env.SOOTSIM_HINTS||"").toLowerCase();return e==="off"||e==="0"||e==="false"?"off":e==="always"||e==="verbose"?"always":"normal"}function x(e,n){let i=v();if(i==="off")return!1;if(i==="always"||n==="always")return!0;let t=Date.now();if(n==="once-per-identity"){let r=u(a());return r.shown[e]?!1:(r.shown[e]=t,l(a(),r),!0)}if(n==="once-ever"){let r=u(d());return r.shown[e]?!1:(r.shown[e]=t,l(d(),r),!0)}if(typeof n=="object"&&"cooldownMs"in n){let r=u(a()),c=r.shown[e]??0;return t-c<n.cooldownMs?!1:(r.shown[e]=t,l(a(),r),!0)}return!0}function A(e,...n){let i=w.get(e);if(!i)return process.env.SOOTSIM_HINTS_DEBUG&&console.error(` [hints] no hint registered for id "${e}"`),!1;if(!x(e,i.frequency))return!1;let t=i.render(...n);if(t==null)return!1;let r=Array.isArray(t)?t:[t];for(let c of r)console.error(` hint: ${c}`);return!0}o("app-still-loading",{frequency:{cooldownMs:6e4},render:e=>`app may still be loading (${e} nodes). run \`rnx wait ready\` first.`});o("wait-selector-for-missing-testid",{frequency:"once-per-identity",render:e=>`rnx wait selector ${e}`});o("prefer-cli-over-eval",{frequency:"once-per-identity",render:e=>e.length?["try the CLI shortcut instead:",...e.map(n=>` ${n}`)]:null});o("describe-use-filters",{frequency:"once-per-identity",render:()=>["describe output is long. narrow it with:"," rnx describe --only '*Bottom Sheet*'"," rnx describe --testid-like 'swap-*'"," rnx describe --subtree <testID>"]});o("describe-filter-context",{frequency:"once-per-identity",render:()=>["filtered describe is search output, not current-route proof.","run `rnx describe` without filters after navigation; clipped nodes are marked `(clipped:...)`."]});o("subtree-root-not-found",{frequency:"always",render:e=>`no node with testID/id "${e}" \u2014 try \`rnx find --testid ${e}\` to discover available ids.`});o("clean-uninstall",{frequency:"once-ever",render:()=>["to remove the background daemon and all ~/.sootsim data, run `rnx daemon uninstall`.","the optional desktop app and its macOS preference plist are separate from the daemon."]});export{A as a};
@@ -1,5 +0,0 @@
1
- /*! rnx v0.1.376 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{L as m,o as P,q as a}from"./chunk-QRDF33WD.js";import l from"fs";import c from"path";var s="default",S="profiles.json",i=1;function o(e){let r=e.trim();if(!r)throw new Error("profile id is required");if(!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(r))throw new Error("profile ids must start with a letter or number and contain only letters, numbers, dot, dash, or underscore");if(r==="."||r==="..")throw new Error(`invalid profile id: ${r}`);return r}function d(){return c.join(a(),S)}function I(e){return`sootsim-profile-${o(e)}`}function h(e){return c.join(P(),"Partitions",I(e))}function A(e){return c.join(a(),"playwright",o(e))}function u(){try{let e=JSON.parse(l.readFileSync(d(),"utf8"));if(!e||e.version!==i)return{version:i,profiles:[]};let r=Array.isArray(e.profiles)?e.profiles.filter(t=>!!t&&typeof t.id=="string"&&typeof t.createdAt=="string"&&typeof t.updatedAt=="string").map(t=>({id:o(t.id),createdAt:t.createdAt,updatedAt:t.updatedAt})):[];return{version:i,profiles:r}}catch{return{version:i,profiles:[]}}}function x(e){return[...e].sort((r,t)=>r.id===s?-1:t.id===s?1:r.id.localeCompare(t.id))}function p(e){if(e.profiles.some(t=>t.id===s))return{...e,profiles:x(e.profiles)};let r=new Date().toISOString();return{version:i,profiles:x([{id:s,createdAt:r,updatedAt:r},...e.profiles])}}function g(e){m();let r=p(e),t=`${d()}.tmp`;return l.writeFileSync(t,`${JSON.stringify(r,null,2)}
5
- `,"utf8"),l.renameSync(t,d()),r}function y(){return g(u()).profiles}function E(e){let r=o(e);return y().find(t=>t.id===r)??null}function _(e=s){let r=o(e),t=E(r);return t||D(r)}function D(e){let r=o(e),t=p(u());if(t.profiles.some(w=>w.id===r))throw new Error(`profile already exists: ${r}`);let f=new Date().toISOString(),n={id:r,createdAt:f,updatedAt:f};return g({version:i,profiles:[...t.profiles,n]}),n}function F(e){let r=o(e);if(r===s)throw new Error("the default profile cannot be deleted; clear it instead");let t=p(u()),f=t.profiles.find(n=>n.id===r);if(!f)throw new Error(`profile not found: ${r}`);return g({version:i,profiles:t.profiles.filter(n=>n.id!==r)}),v(r),f}function v(e){let r=o(e);for(let t of[h(r),A(r)])try{l.rmSync(t,{recursive:!0,force:!0})}catch{}}export{A as a,y as b,_ as c,D as d,F as e,v as f};
@@ -1,74 +0,0 @@
1
- /*! rnx v0.1.376 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- import{c as Y}from"./chunk-LC3QRIRB.js";import{c as u}from"./chunk-TH2UFGVP.js";import{P as M,R as H,g as U,j as A,s as O,t as L,u as j}from"./chunk-QRDF33WD.js";import{a as V}from"./chunk-XSVILA4Z.js";import{a as S}from"./chunk-5YZYDEMI.js";import{execFileSync as Z,spawnSync as a}from"child_process";import{existsSync as s,mkdirSync as E,readFileSync as le,realpathSync as ue,rmSync as y,writeFileSync as Q}from"fs";import{homedir as w}from"os";import{basename as de,dirname as B,resolve as d,sep as W}from"path";import{execFileSync as re}from"child_process";import{chmodSync as ne,mkdirSync as T,rmSync as oe,writeFileSync as _}from"fs";import{dirname as N}from"path";var se="dev.sootsim.daemon",G="SootSim Daemon",q="0.1.36";function X(e,t,r){let o=L(),n=j(),c=N(N(n)),l=N(n),p=`${c}/Resources`;oe(o,{recursive:!0,force:!0}),T(O(),{recursive:!0}),T(l,{recursive:!0}),T(p,{recursive:!0}),_(`${c}/Info.plist`,ie()),_(`${c}/PkgInfo`,"APPL????"),_(n,ae(e,t,r)),ne(n,493);try{re("codesign",["--force","--sign","-","--deep",o],{stdio:"pipe"})}catch(i){let h=i instanceof Error?i.message:String(i);console.warn(` warning: ad-hoc codesign of ${o} failed: ${h}
5
- the daemon will still run, but Login Items may show a generic name.`)}return{bundlePath:o,launcherPath:n}}function ie(){return`<?xml version="1.0" encoding="UTF-8"?>
6
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
7
- <plist version="1.0">
8
- <dict>
9
- <key>CFBundleDevelopmentRegion</key><string>en</string>
10
- <key>CFBundleDisplayName</key><string>${G}</string>
11
- <key>CFBundleExecutable</key><string>sootsim-daemon</string>
12
- <key>CFBundleIdentifier</key><string>${se}</string>
13
- <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
14
- <key>CFBundleName</key><string>${G}</string>
15
- <key>CFBundlePackageType</key><string>APPL</string>
16
- <key>CFBundleShortVersionString</key><string>${q}</string>
17
- <key>CFBundleSignature</key><string>????</string>
18
- <key>CFBundleVersion</key><string>${q}</string>
19
- <key>LSBackgroundOnly</key><true/>
20
- <key>LSUIElement</key><true/>
21
- <key>LSMinimumSystemVersion</key><string>13.0</string>
22
- <key>NSHumanReadableCopyright</key><string>Tamagui LLC</string>
23
- </dict>
24
- </plist>
25
- `}function ae(e,t,r){let n=[e.executable,...e.prefixArgs,"serve","--quiet","--port",String(t)].map(C).join(" "),c=C(r.stdout),l=C(r.stderr);return`#!/bin/sh
26
- # sootsim daemon launcher generated by 'rnx daemon install'.
27
- # launchd spawns this; we exec the real rnx invocation in place so
28
- # launchd tracks the daemon process, not the shell wrapper.
29
- #
30
- # stdout: ${r.stdout}
31
- # stderr: ${r.stderr}
32
- # a missing or broken executable can make launchd retry forever. truncate a
33
- # retry log before it passes 10 MiB so that failure stays bounded on disk.
34
- for log_path in ${c} ${l}; do
35
- if [ -f "$log_path" ]; then
36
- log_bytes=$(wc -c < "$log_path" 2>/dev/null || echo 0)
37
- if [ "$log_bytes" -gt 10485760 ]; then
38
- : > "$log_path"
39
- fi
40
- fi
41
- done
42
- exec ${n}
43
- `}function C(e){return`'${e.replace(/'/g,"'\\''")}'`}var ee=60,$="dev.sootsim.daemon",R="dev.sootsim.server",m="sootsim-daemon",f=d(w(),"Library/Logs/sootsim"),P=d(w(),".local/state/sootsim");async function Qe(e,t={}){let[r,...o]=e,n=t.port??7668;if(!r||r==="--help"||r==="-h"){K();return}switch(r){case"install":return Se({port:n,force:o.includes("--force")});case"uninstall":return De();case"status":return Le();case"restart":return Pe();case"start":return Ee();case"stop":return Ie();case"logs":return Ae(o);default:console.error(` unknown daemon subcommand: ${r}`),K(),u(1)}}function K(){Y("daemon")}function pe(){let e=ge();if(e)return e;let t=he();return{executable:process.execPath,prefixArgs:[t]}}function ge(){if(!me())return null;let e=fe();if(!e)return null;let t=V(),r=t==="0.0.0"?S.packageName:`${S.packageName}@${t}`;return{executable:process.execPath,prefixArgs:[e,"exec","--yes","--package",r,"--",S.commandName]}}function me(){let e=process.argv[1];return process.env.npm_command==="exec"?!0:e?I(e).includes(`${W}_npx${W}`):!1}function fe(){try{let t=Z("which",["npm"],{encoding:"utf8"}).trim();if(t&&s(t))return z(t)}catch{}let e=process.env.npm_execpath;return e&&s(e)?z(e):null}function z(e){let t=I(e);if(de(t)==="npx-cli.js"){let r=d(B(t),"npm-cli.js");if(s(r))return r}return t}function he(){try{let t=Z("which",[S.commandName],{encoding:"utf8"}).trim();if(t&&s(t))return I(t)}catch{}let e=process.argv[1];if(e&&s(e))return I(e);throw new Error(`could not locate the ${S.commandName} binary`)}function I(e){try{return ue(e)}catch{return e}}function ye(e,t){E(f,{recursive:!0});let r=d(f,"bridge.out.log"),o=d(f,"bridge.err.log"),{launcherPath:n}=X(e,t,{stdout:r,stderr:o}),c=` <string>${be(n)}</string>`;return`<?xml version="1.0" encoding="UTF-8"?>
44
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
45
- <plist version="1.0">
46
- <dict>
47
- <key>Label</key><string>${$}</string>
48
- <key>ProgramArguments</key>
49
- <array>
50
- ${c}
51
- </array>
52
- <key>RunAtLoad</key><true/>
53
- <key>KeepAlive</key><true/>
54
- <key>ThrottleInterval</key><integer>${ee}</integer>
55
- <key>ProcessType</key><string>Background</string>
56
- <key>StandardOutPath</key><string>${r}</string>
57
- <key>StandardErrorPath</key><string>${o}</string>
58
- </dict>
59
- </plist>
60
- `}function $e(e,t){return E(P,{recursive:!0}),`[Unit]
61
- Description=rnx bridge daemon
62
- After=default.target
63
-
64
- [Service]
65
- Type=simple
66
- ExecStart=${[e.executable,...e.prefixArgs].map(ke).join(" ")} serve --quiet --port ${t}
67
- Restart=always
68
- RestartSec=${ee}
69
-
70
- [Install]
71
- WantedBy=default.target
72
- `}function be(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function ke(e){return/[^\w@%+=:,./-]/.test(e)?`'${e.replace(/'/g,"'\\''")}'`:e}function b(){return d(w(),"Library/LaunchAgents",`${$}.plist`)}function ve(e=w()){return d(e,"Library/LaunchAgents",`${R}.plist`)}function k(){return d(w(),".config/systemd/user",`${m}.service`)}function We(){if(A())return{supported:!1,installed:!1};if(process.platform==="darwin"){let e=b();return{supported:!0,installed:s(e),path:e}}if(process.platform==="linux"){let e=k();return{supported:!0,installed:s(e),path:e}}return{supported:!1,installed:!1}}async function Se({port:e,force:t}){if(A())throw new Error("background daemon setup is unavailable in this environment");let r=pe();if(console.log(` binary: ${[r.executable,...r.prefixArgs].join(" ")}`),console.log(` port: ${e}`),process.platform==="darwin"){te().missing||console.log(` removed legacy ${R} service`);let n=b();if(s(n)&&!t){console.log(` already installed at ${n}`),console.log(" pass --force to overwrite, or use 'rnx daemon restart' to reload");return}E(B(n),{recursive:!0}),Q(n,ye(r,e)),console.log(` wrote ${n}`);let c=`gui/${process.getuid()}`,l=`${c}/${$}`,p=()=>{let g=a("launchctl",["bootstrap",c,n],{stdio:"pipe",encoding:"utf8"}),D=(g.stderr||g.stdout||"").trim();if(g.status!==0)return{ok:!1,reason:`bootstrap exit ${g.status}${D?`: ${D}`:""}`};let F=a("launchctl",["print",l],{encoding:"utf8"});return F.status!==0?{ok:!1,reason:`bootstrap returned 0 but service not registered (print exit ${F.status})`}:{ok:!0}},i=p();if(!i.ok){let g=i.reason;if(a("launchctl",["bootout",l],{stdio:"ignore"}),i=p(),!i.ok)throw new Error(`launchctl bootstrap failed: ${i.reason}`+(g!==i.reason?` (initial: ${g})`:"")+" \u2014 try `rnx daemon uninstall` then retry, or reboot if launchd state is stuck.")}let h=Date.now()+4e3,v,x;for(;Date.now()<h;){let g=a("launchctl",["print",l],{encoding:"utf8"});if(g.status===0&&(v=g.stdout?.match(/state\s*=\s*(\w+)/)?.[1],x=g.stdout?.match(/pid\s*=\s*(\d+)/)?.[1],v==="running"||x))break;await new Promise(D=>setTimeout(D,150))}if(v!=="running"&&!x)throw new Error(`daemon registered but did not reach running state within 4s (last state: ${v||"unknown"}). check ${d(f,"bridge.err.log")} \u2014 typically a stale runtime or a port already bound by another process.`);console.log(` registered (state: ${v||"unknown"}${x?`, pid ${x}`:""}, log: ${d(f,"bridge.err.log")})`);return}if(process.platform==="linux"){let o=k();if(s(o)&&!t){console.log(` already installed at ${o}`),console.log(" pass --force to overwrite, or use 'rnx daemon restart' to reload");return}E(B(o),{recursive:!0}),Q(o,$e(r,e)),console.log(` wrote ${o}`);let n=a("systemctl",["--user","daemon-reload"],{stdio:"pipe",encoding:"utf8"});if(n.status!==0){let i=(n.stderr||n.stdout||"").trim();throw new Error(`systemctl daemon-reload failed${i?`: ${i}`:""}`)}let c=a("systemctl",["--user","enable","--now",m],{stdio:"pipe",encoding:"utf8"});if(c.status!==0){let i=(c.stderr||c.stdout||"").trim();throw new Error(`systemctl enable --now failed${i?`: ${i}`:""} \u2014 try \`rnx daemon uninstall\` then retry.`)}let p=(a("systemctl",["--user","is-active",m],{encoding:"utf8"}).stdout||"").trim()||"unknown";console.log(` registered (state: ${p}, journalctl --user -u ${m} to tail logs)`);try{let i=process.env.USER||process.env.LOGNAME||"";if(i){let h=a("loginctl",["show-user",i,"--property=Linger","--value"],{encoding:"utf8"});!((h.stdout||"").trim().toLowerCase()==="yes")&&h.status===0&&console.log(` note: linger is not enabled for "${i}". the daemon will exit at logout.
73
- enable persistence with: sudo loginctl enable-linger ${i}`)}}catch{}return}console.error(` background daemon is not supported on ${process.platform}`),console.error(" run 'rnx serve' in a persistent shell instead"),u(1)}function te(e={}){let t=e.userHome??w(),r=ve(t),o=d(t,"Library/Logs/sootsim"),n=[];if(s(r)){let c=`${e.launchTarget??`gui/${process.getuid?.()??0}`}/${R}`;(e.bootout??(p=>{a("launchctl",["bootout",p],{stdio:"ignore"})}))(c),y(r,{force:!0}),n.push(r)}for(let c of["server.err.log","server.out.log"]){let l=d(o,c);s(l)&&(y(l,{force:!0}),n.push(l))}return{removed:n,missing:n.length===0}}function we(){let e=[];if(process.platform==="darwin"){let t=te();e.push(...t.removed);let r=b();s(r)&&(a("launchctl",["bootout",`gui/${process.getuid()}/${$}`],{stdio:"ignore"}),y(r,{force:!0}),e.push(r));let o=L();return s(o)&&(y(o,{recursive:!0,force:!0}),e.push(o)),s(f)&&(y(f,{recursive:!0,force:!0}),e.push(f)),{removed:e,missing:e.length===0}}if(process.platform==="linux"){let t=k();return s(t)&&(a("systemctl",["--user","disable","--now",m],{stdio:"ignore"}),y(t,{force:!0}),a("systemctl",["--user","daemon-reload"],{stdio:"ignore"}),a("systemctl",["--user","reset-failed",m],{stdio:"ignore"}),e.push(t)),s(P)&&(y(P,{recursive:!0,force:!0}),e.push(P)),{removed:e,missing:e.length===0}}return{removed:e,missing:!0}}function xe(){let e=[],t=U();return s(t)&&(y(t,{recursive:!0,force:!0}),e.push(t)),{removed:e,missing:e.length===0}}async function De(){let e=we();for(let r of e.removed)console.log(` removed ${r}`);let t=xe();for(let r of t.removed)console.log(` removed ${r}`);e.missing&&t.missing&&console.log(" not installed")}function J(){let e=M();if(H(e)){console.log(` bridge: responding on port ${e.bridgePort} (pid ${e.pid})`);return}console.log(e?" bridge: NOT responding \u2014 stale lockfile; check `rnx daemon logs`":" bridge: NOT responding \u2014 no lockfile; check `rnx daemon logs`")}async function Le(){if(process.platform==="darwin"){let e=b();if(!s(e)){console.log(" installed: no");return}console.log(` installed: yes (${e})`);let t=Te(e);t&&console.log(` binary: ${t}`);let r=a("launchctl",["print",`gui/${process.getuid()}/${$}`],{encoding:"utf8"});if(r.status===0){let o=r.stdout.match(/state\s*=\s*(\w+)/)?.[1],n=r.stdout.match(/pid\s*=\s*(\d+)/)?.[1];console.log(` state: ${o||"unknown"}${n?` (pid ${n})`:""}`)}else console.log(" state: not running");J();return}if(process.platform==="linux"){let e=k();if(!s(e)){console.log(" installed: no");return}console.log(` installed: yes (${e})`);let t=a("systemctl",["--user","is-active",m],{encoding:"utf8"});console.log(` state: ${t.stdout.trim()||"unknown"}`),J();return}console.error(` unsupported platform: ${process.platform}`),u(1)}async function Pe(){if(process.platform==="darwin"){let e=b();s(e)||(console.error(" daemon not registered. run `rnx daemon install`"),u(1));let t=a("launchctl",["kickstart","-k",`gui/${process.getuid()}/${$}`],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` kickstart failed: ${t.stderr?.trim()}`),u(1)),console.log(" restarted");return}if(process.platform==="linux"){let e=k();s(e)||(console.error(" daemon not registered. run `rnx daemon install`"),u(1));let t=a("systemctl",["--user","restart",m],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` restart failed: ${t.stderr?.trim()}`),u(1)),console.log(" restarted");return}console.error(` unsupported platform: ${process.platform}`),u(1)}async function Ee(){if(process.platform==="darwin"){let e=b();s(e)||(console.error(" daemon not registered. run `rnx daemon install`"),u(1));let t=a("launchctl",["kickstart",`gui/${process.getuid()}/${$}`],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` start failed: ${t.stderr?.trim()}`),u(1)),console.log(" started");return}if(process.platform==="linux"){let e=k();s(e)||(console.error(" daemon not registered. run `rnx daemon install`"),u(1));let t=a("systemctl",["--user","start",m],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` start failed: ${t.stderr?.trim()}`),u(1)),console.log(" started");return}console.error(` unsupported platform: ${process.platform}`),u(1)}async function Ie(){if(process.platform==="darwin"){let e=b();s(e)||(console.error(" daemon not registered \u2014 nothing to stop"),u(1));let t=a("launchctl",["bootout",`gui/${process.getuid()}/${$}`],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` stop failed: ${t.stderr?.trim()}`),u(1)),console.log(" stopped");return}if(process.platform==="linux"){let e=k();s(e)||(console.error(" daemon not registered \u2014 nothing to stop"),u(1));let t=a("systemctl",["--user","stop",m],{stdio:"pipe",encoding:"utf8"});t.status!==0&&(console.error(` stop failed: ${t.stderr?.trim()}`),u(1)),console.log(" stopped");return}console.error(` unsupported platform: ${process.platform}`),u(1)}async function Ae(e){let t=e.find(n=>/^-n\d+$|^--lines=\d+$|^\d+$/.test(n)),r=t?Number(t.replace(/\D/g,"")):200,o=e.includes("-f")||e.includes("--follow");if(process.platform==="darwin"){let n=d(f,"bridge.out.log"),c=d(f,"bridge.err.log"),l=[n,c].filter(i=>s(i));l.length===0&&(console.error(` no daemon logs yet at ${f}. run \`rnx daemon install\``),u(1));let p=o?["-n",String(r),"-F",...l]:["-n",String(r),...l];a("tail",p,{stdio:"inherit"});return}if(process.platform==="linux"){let n=`${m}.service`,c=["--user","-u",n,"-n",String(r),"--no-pager"],l=a("journalctl",o?[...c,"-f"]:c,{encoding:"utf8",stdio:o?"inherit":"pipe"});if(o)return;let p=`${l.stdout||""}${l.stderr||""}`,i=/insufficient permissions|No journal files were opened/i.test(p);if(l.status===0&&!i){process.stdout.write(l.stdout||"");return}let h=a("journalctl",[`_SYSTEMD_USER_UNIT=${n}`,"-n",String(r),"--no-pager"],{encoding:"utf8"});if(h.status===0&&(h.stdout||"").trim()){process.stdout.write(h.stdout);return}console.error(` could not read --user journal for ${n} (this user isn't in the systemd-journal group yet).
74
- run: sudo journalctl _SYSTEMD_USER_UNIT=${n} -n ${r} --no-pager`),u(1)}console.error(` unsupported platform: ${process.platform}`),u(1)}function Te(e){try{return le(e,"utf8").match(/<array>\s*<string>([^<]+)<\/string>/)?.[1]||null}catch{return null}}export{Qe as a,We as b,Se as c,te as d,we as e,xe as f};
@@ -1,4 +0,0 @@
1
- /*! rnx v0.1.376 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import { createRequire as __sootsimCreateRequire } from 'node:module'
3
- var require = __sootsimCreateRequire(import.meta.url)
4
- var e=["SOOTSIM_AGENT","TM_SESSION","CLAUDECODE","CLAUDE_CODE_ENTRYPOINT","CLAUDE_CODE_SESSION_ID","CODEX_THREAD_ID","CURSOR_TRACE_ID","AIDER_MODEL"];function n(){if(process.env.SOOTSIM_AGENT==="0")return!1;for(let _ of e){let E=process.env[_];if(E&&E.trim()&&E!=="0")return!0}return!1}export{n as a};