sootsim 0.1.185 → 0.1.187

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 (157) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-VF756RZU.js → agent-LRKJIWBT.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-IAFL7ROV.js → agent-wrapper-7366QMW3.js} +2 -2
  4. package/dist-cli/chunks/{app-fonts-VWLEC7ZA.js → app-fonts-WIJGM2Q3.js} +2 -2
  5. package/dist-cli/chunks/{assert-I55QVGG7.js → assert-XH4UWOXZ.js} +2 -2
  6. package/dist-cli/chunks/beta-HKL7ZI2G.js +2 -0
  7. package/dist-cli/chunks/{camera-CYYBJH7W.js → camera-RKBTE4X7.js} +2 -2
  8. package/dist-cli/chunks/{chunk-4OUQAR34.js → chunk-2YX77KNA.js} +1 -1
  9. package/dist-cli/chunks/{chunk-TNHF6BON.js → chunk-4MSD5YEY.js} +1 -1
  10. package/dist-cli/chunks/{chunk-PKZNXDUJ.js → chunk-5MHGK7K5.js} +2 -2
  11. package/dist-cli/chunks/chunk-6DUOFTWZ.js +118 -0
  12. package/dist-cli/chunks/chunk-7OSC6Q5I.js +1 -0
  13. package/dist-cli/chunks/{chunk-TUF6EPCQ.js → chunk-7PXPUUCL.js} +2 -2
  14. package/dist-cli/chunks/{chunk-FY6DJGOS.js → chunk-7ZCLPWN7.js} +39 -15
  15. package/dist-cli/chunks/{chunk-LI4RLX6B.js → chunk-A6YGOAVQ.js} +1 -1
  16. package/dist-cli/chunks/{chunk-LJ3SOZBF.js → chunk-C3TVJ3MM.js} +2 -2
  17. package/dist-cli/chunks/{chunk-ARNLQPMQ.js → chunk-DVMV4JPO.js} +2 -2
  18. package/dist-cli/chunks/{chunk-M3P67TBN.js → chunk-ECNEUGXI.js} +1 -1
  19. package/dist-cli/chunks/{chunk-X4KS33ZC.js → chunk-ED7KWTZI.js} +2 -2
  20. package/dist-cli/chunks/{chunk-TFZO277G.js → chunk-EUJGZMDY.js} +1 -1
  21. package/dist-cli/chunks/{chunk-K2THZIVC.js → chunk-EXXEJKHE.js} +1 -1
  22. package/dist-cli/chunks/{chunk-HQG4DRQ3.js → chunk-FCEZIUSK.js} +1 -1
  23. package/dist-cli/chunks/{chunk-DZLBZGHN.js → chunk-FCYL4LNR.js} +2 -2
  24. package/dist-cli/chunks/chunk-FHK4ZNGV.js +5 -0
  25. package/dist-cli/chunks/{chunk-C3UEINOZ.js → chunk-FN7PINUE.js} +2 -2
  26. package/dist-cli/chunks/{chunk-NL5IFN4T.js → chunk-FTWRQ4GJ.js} +2 -2
  27. package/dist-cli/chunks/{chunk-BI56RR3G.js → chunk-FUA7CGJ3.js} +4 -4
  28. package/dist-cli/chunks/{chunk-EXFB33AZ.js → chunk-FUYTE2KH.js} +2 -2
  29. package/dist-cli/chunks/{chunk-R4KLD4P4.js → chunk-HCPE77ID.js} +2 -2
  30. package/dist-cli/chunks/{chunk-2T73IGB2.js → chunk-ILF5TI6Y.js} +2 -2
  31. package/dist-cli/chunks/{chunk-E5DE33BU.js → chunk-JCVOSH3U.js} +1 -1
  32. package/dist-cli/chunks/{chunk-WBY4JJ2K.js → chunk-JUAUV4UZ.js} +2 -2
  33. package/dist-cli/chunks/chunk-L4Z2UJX5.js +2 -0
  34. package/dist-cli/chunks/{chunk-FUHXL6BW.js → chunk-N64V23HY.js} +1 -1
  35. package/dist-cli/chunks/{chunk-QQ4NSPAD.js → chunk-NXBBBNH5.js} +2 -2
  36. package/dist-cli/chunks/{chunk-FHJTTB3W.js → chunk-O67BWHYY.js} +2 -2
  37. package/dist-cli/chunks/{chunk-C63EVPDN.js → chunk-OXS4KYCN.js} +2 -2
  38. package/dist-cli/chunks/{chunk-WEJKLJ4B.js → chunk-RFIK5SZF.js} +2 -2
  39. package/dist-cli/chunks/{chunk-GX6MKIFC.js → chunk-TF6TFVED.js} +1 -1
  40. package/dist-cli/chunks/chunk-TJMPYMXV.js +382 -0
  41. package/dist-cli/chunks/{chunk-QTFCJYBF.js → chunk-TXSPFIUO.js} +3 -3
  42. package/dist-cli/chunks/chunk-UBOHWJ5L.js +987 -0
  43. package/dist-cli/chunks/chunk-VZ4HTOAC.js +24 -0
  44. package/dist-cli/chunks/{chunk-BMCBPMTC.js → chunk-WDFDPB4M.js} +1 -1
  45. package/dist-cli/chunks/{chunk-MADEJDFD.js → chunk-WKGGTXDO.js} +1 -1
  46. package/dist-cli/chunks/chunk-XFDPG5AN.js +1 -0
  47. package/dist-cli/chunks/chunk-XJ3ANS4C.js +13 -0
  48. package/dist-cli/chunks/{chunk-4NUQVW5P.js → chunk-XLAWETKN.js} +17 -6
  49. package/dist-cli/chunks/{chunk-CYBRFHPU.js → chunk-XVI2A5KE.js} +2 -2
  50. package/dist-cli/chunks/{chunk-IJP257WP.js → chunk-Y77CNEAC.js} +1 -1
  51. package/dist-cli/chunks/{chunk-PIUKLO3W.js → chunk-ZR6PIQPZ.js} +1 -1
  52. package/dist-cli/chunks/cli-version-XGZD3TZF.js +2 -0
  53. package/dist-cli/chunks/{compat-ZJA3N4ZT.js → compat-XGX4RAXQ.js} +3 -3
  54. package/dist-cli/chunks/control-M76KO3SL.js +2 -0
  55. package/dist-cli/chunks/{cpu-profile-ACSQMVXY.js → cpu-profile-YJRYOP7N.js} +2 -2
  56. package/dist-cli/chunks/daemon-XRE3ZJ3A.js +2 -0
  57. package/dist-cli/chunks/{debug-W2ZOVTQO.js → debug-W4VWXPA4.js} +9 -6
  58. package/dist-cli/chunks/{detox-ANJO6T27.js → detox-EGVU4YL6.js} +2 -2
  59. package/dist-cli/chunks/{device-KPPN4KYD.js → device-XGK2VNF5.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-5PEJYGES.js → diagnose-DI4BFQBP.js} +2 -2
  61. package/dist-cli/chunks/drivers-O6BFN76G.js +2 -0
  62. package/dist-cli/chunks/{electron-U456QLSQ.js → electron-3BE5EPSM.js} +3 -3
  63. package/dist-cli/chunks/flow-6WB3FX4N.js +2 -0
  64. package/dist-cli/chunks/help-BXNU6OAS.js +2 -0
  65. package/dist-cli/chunks/{hints-MBBQLMQU.js → hints-E7NSLFDT.js} +2 -2
  66. package/dist-cli/chunks/{home-paths-KQKYP2SE.js → home-paths-UASDA6NF.js} +2 -2
  67. package/dist-cli/chunks/inspect-Z33SVDQJ.js +2 -0
  68. package/dist-cli/chunks/{install-desktop-OR6ZJ43X.js → install-desktop-KFWZQGHM.js} +3 -3
  69. package/dist-cli/chunks/{keys-JSQMBUE7.js → keys-C5T4EK3E.js} +2 -2
  70. package/dist-cli/chunks/{login-DVMWAI3G.js → login-IB6EEROJ.js} +4 -4
  71. package/dist-cli/chunks/{logout-RIVPFE5N.js → logout-UPNDZL6K.js} +2 -2
  72. package/dist-cli/chunks/{maestro-TX6FPTVH.js → maestro-IU2V4VZI.js} +2 -2
  73. package/dist-cli/chunks/optional-demo-registry-P67F7BGJ.js +2 -0
  74. package/dist-cli/chunks/{preview-3AD7WNA6.js → preview-JBLUMPDD.js} +2 -2
  75. package/dist-cli/chunks/{profile-HY55VFNR.js → profile-SNBM3CDF.js} +2 -2
  76. package/dist-cli/chunks/{react-HDRCKCKV.js → react-SDFO4G5R.js} +2 -2
  77. package/dist-cli/chunks/{record-HW4C7QYN.js → record-ZWXDWCCP.js} +2 -2
  78. package/dist-cli/chunks/runtime-KQQS4SNR.js +2 -0
  79. package/dist-cli/chunks/{screenshot-XFR3QN5T.js → screenshot-CVHGCLGS.js} +2 -2
  80. package/dist-cli/chunks/{screenshot-mode-Y5CVO267.js → screenshot-mode-NDTW64AM.js} +2 -2
  81. package/dist-cli/chunks/{screenshots-RKUL2ZZT.js → screenshots-V6STBJXN.js} +2 -2
  82. package/dist-cli/chunks/{screenshots-capture-RVNF75ZD.js → screenshots-capture-6WYQMQ2U.js} +2 -2
  83. package/dist-cli/chunks/{serve-QMRYLWL5.js → serve-PW4LITPE.js} +16 -16
  84. package/dist-cli/chunks/{setup-ELNJS7AI.js → setup-CGNDZVXB.js} +3 -3
  85. package/dist-cli/chunks/{skills-GPSJYS4W.js → skills-KOK2FNL2.js} +2 -2
  86. package/dist-cli/chunks/{slides-OCFNPIFG.js → slides-3PLFSQMQ.js} +2 -2
  87. package/dist-cli/chunks/store-FSEOWL7R.js +2 -0
  88. package/dist-cli/chunks/{telemetry-KFZQUFG5.js → telemetry-B7LYDPT5.js} +2 -2
  89. package/dist-cli/chunks/telemetry-XACCAQXE.js +2 -0
  90. package/dist-cli/chunks/{test-Z2HZXCZM.js → test-RE7DJ2VV.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-NKJFCDYS.js → three-mode-3IDJZUWE.js} +2 -2
  92. package/dist-cli/chunks/{timeline-PRGQMQRR.js → timeline-VSAVV7SE.js} +2 -2
  93. package/dist-cli/chunks/{upgrade-3NW7JRRX.js → upgrade-N7F4A22A.js} +2 -2
  94. package/dist-cli/chunks/upload-5YUE5AXH.js +2 -0
  95. package/dist-cli/chunks/{version-FDTZRIYT.js → version-NI3AUFKF.js} +2 -2
  96. package/dist-cli/chunks/{web-4N5QQEQJ.js → web-B4BOB3BY.js} +2 -2
  97. package/dist-cli/chunks/{what-happened-IX2RRCOS.js → what-happened-J6KHS3NN.js} +2 -2
  98. package/dist-cli/chunks/{whoami-QZ42FYYF.js → whoami-JX2QC2MC.js} +2 -2
  99. package/dist-lib/agent-daemon-client.cjs +1 -1
  100. package/dist-lib/agent-events.cjs +1 -1
  101. package/dist-lib/agent-sessions.cjs +1 -1
  102. package/dist-lib/attached-projects.cjs +1 -1
  103. package/dist-lib/auth/shared-session.cjs +1 -1
  104. package/dist-lib/backend-origin.cjs +1 -1
  105. package/dist-lib/beta.cjs +1 -1
  106. package/dist-lib/beta.mjs +1 -1
  107. package/dist-lib/bridge-constants.cjs +1 -1
  108. package/dist-lib/cli-constants.cjs +1 -1
  109. package/dist-lib/config.cjs +1 -1
  110. package/dist-lib/detox/index.cjs +1 -1
  111. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  112. package/dist-lib/home-paths.cjs +2 -2
  113. package/dist-lib/host/bridge-host.cjs +77 -44
  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/websocket-proxy.cjs +1 -1
  118. package/dist-lib/index.cjs +28 -1
  119. package/dist-lib/jump-to-source-babel.cjs +1 -1
  120. package/dist-lib/menu.cjs +1 -1
  121. package/dist-lib/menu.mjs +1 -1
  122. package/dist-lib/metro.cjs +28 -1
  123. package/dist-lib/profiles.cjs +1 -1
  124. package/dist-lib/render-mode.cjs +1 -1
  125. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  126. package/dist-lib/sdk.cjs +39 -12
  127. package/dist-lib/sdk.mjs +39 -12
  128. package/dist-lib/skills.cjs +283 -254
  129. package/dist-lib/vite.cjs +28 -1
  130. package/package.json +1 -1
  131. package/src/home-paths.ts +8 -1
  132. package/src/host/bridge-host.ts +15 -1
  133. package/src/runtime-assets.ts +70 -0
  134. package/src/vite-plugin.ts +9 -0
  135. package/dist-cli/chunks/beta-X6YPQVZH.js +0 -2
  136. package/dist-cli/chunks/chunk-7OAUPGLN.js +0 -23
  137. package/dist-cli/chunks/chunk-IGJHME3T.js +0 -1
  138. package/dist-cli/chunks/chunk-JRL7PFNZ.js +0 -463
  139. package/dist-cli/chunks/chunk-KOKIECMB.js +0 -118
  140. package/dist-cli/chunks/chunk-OAHGYDJR.js +0 -13
  141. package/dist-cli/chunks/chunk-PDLQWZN4.js +0 -2
  142. package/dist-cli/chunks/chunk-SL6565MR.js +0 -1
  143. package/dist-cli/chunks/chunk-V4M2R6FZ.js +0 -2
  144. package/dist-cli/chunks/chunk-V5JEPE3P.js +0 -5
  145. package/dist-cli/chunks/chunk-XU5EMZ4B.js +0 -264
  146. package/dist-cli/chunks/cli-version-ICHQMND6.js +0 -2
  147. package/dist-cli/chunks/control-CZFSYSYG.js +0 -2
  148. package/dist-cli/chunks/daemon-337B4P3B.js +0 -2
  149. package/dist-cli/chunks/drivers-MSDIFHBD.js +0 -2
  150. package/dist-cli/chunks/flow-JL3SC6HC.js +0 -2
  151. package/dist-cli/chunks/help-PA4RTR5X.js +0 -2
  152. package/dist-cli/chunks/inspect-ZP5SM4EW.js +0 -987
  153. package/dist-cli/chunks/optional-demo-registry-ONYG6DUI.js +0 -2
  154. package/dist-cli/chunks/runtime-RHHPW5WO.js +0 -2
  155. package/dist-cli/chunks/store-MBKDUQEQ.js +0 -2
  156. package/dist-cli/chunks/telemetry-46XXIUEE.js +0 -2
  157. package/dist-cli/chunks/upload-QVDVJ6ZK.js +0 -2
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.185 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.187 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
3
3
  "use strict";
4
4
  var __create = Object.create;
@@ -10119,10 +10119,10 @@ function tcpPing(port, timeout = TCP_GATE_MS) {
10119
10119
  sock.connect(port, "localhost");
10120
10120
  });
10121
10121
  }
10122
- function httpGet(port, path10, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
10122
+ function httpGet(port, path11, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
10123
10123
  return new Promise((resolve6) => {
10124
10124
  const req = import_http.default.request(
10125
- { hostname: "localhost", port, path: path10, method, timeout, headers },
10125
+ { hostname: "localhost", port, path: path11, method, timeout, headers },
10126
10126
  (res) => {
10127
10127
  let body = "";
10128
10128
  res.on("data", (c) => body += c.toString());
@@ -10580,27 +10580,6 @@ function sootsimHomeDir() {
10580
10580
  if (override && override.length > 0) return import_node_path.default.resolve(override);
10581
10581
  return import_node_path.default.join((0, import_node_os.homedir)(), ".sootsim");
10582
10582
  }
10583
- function isSootsimDevCheckout() {
10584
- if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
10585
- const env = process.env.SOOTSIM_DEV;
10586
- if (env === "1" || env === "true") return true;
10587
- if (env === "0" || env === "false") return false;
10588
- const argv1 = process.argv[1];
10589
- if (!argv1) return false;
10590
- try {
10591
- const real = import_node_fs2.default.realpathSync(argv1);
10592
- return real.includes(`${import_node_path.default.sep}packages${import_node_path.default.sep}sootsim${import_node_path.default.sep}`);
10593
- } catch {
10594
- return false;
10595
- }
10596
- }
10597
- function isDevWorkstation() {
10598
- if (process.env.SOOTSIM_FORCE_DAEMON_INSTALL === "1") return false;
10599
- return process.env.IS_TAMAGUI_DEV === "1";
10600
- }
10601
- function shouldSkipPersistentDaemon() {
10602
- return isSootsimDevCheckout() || isDevWorkstation();
10603
- }
10604
10583
  function runtimesDir() {
10605
10584
  return import_node_path.default.join(sootsimHomeDir(), "runtimes");
10606
10585
  }
@@ -10741,7 +10720,7 @@ function readDevBridgeLockfile() {
10741
10720
  const bytesRead = import_node_fs2.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
10742
10721
  const raw = buf.subarray(0, bytesRead).toString("utf8");
10743
10722
  const parsed = JSON.parse(raw);
10744
- if (parsed && parsed.schema === 1 && parsed.source === "vite-dev" && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.cwd === "string" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number") {
10723
+ if (parsed && parsed.schema === 1 && parsed.source === "vite-dev" && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.cwd === "string" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.shellPort === void 0 || typeof parsed.shellPort === "number")) {
10745
10724
  return parsed;
10746
10725
  }
10747
10726
  return null;
@@ -10824,10 +10803,45 @@ var init_home_paths = __esm({
10824
10803
  }
10825
10804
  });
10826
10805
 
10806
+ // src/runtime-assets.ts
10807
+ function findMonorepoRoot() {
10808
+ if (_monorepoRootCache !== void 0) return _monorepoRootCache;
10809
+ let dir = import_path.default.dirname((0, import_url.fileURLToPath)(__sootsim_import_meta_url));
10810
+ for (let i = 0; i < 12 && dir !== import_path.default.dirname(dir); i++) {
10811
+ if (import_fs.default.existsSync(import_path.default.join(dir, "packages/sootsim-engine/package.json")) && import_fs.default.existsSync(import_path.default.join(dir, "public/sootsim"))) {
10812
+ _monorepoRootCache = dir;
10813
+ return dir;
10814
+ }
10815
+ dir = import_path.default.dirname(dir);
10816
+ }
10817
+ _monorepoRootCache = null;
10818
+ return null;
10819
+ }
10820
+ function resolveDevCheckoutRuntimeRoot() {
10821
+ if (process.env.SOOTSIM_HOME && readActiveRuntime()) return null;
10822
+ const root = findMonorepoRoot();
10823
+ if (!root) return null;
10824
+ const devBuild = import_path.default.join(root, "public/sootsim");
10825
+ if (import_fs.default.existsSync(import_path.default.join(devBuild, "index.html")) && import_fs.default.existsSync(import_path.default.join(devBuild, "engine/index.html")) && import_fs.default.existsSync(import_path.default.join(devBuild, "engine-tenant/worker.js"))) {
10826
+ return devBuild;
10827
+ }
10828
+ return null;
10829
+ }
10830
+ var import_fs, import_path, import_url, _monorepoRootCache;
10831
+ var init_runtime_assets = __esm({
10832
+ "src/runtime-assets.ts"() {
10833
+ "use strict";
10834
+ import_fs = __toESM(require("fs"), 1);
10835
+ import_path = __toESM(require("path"), 1);
10836
+ import_url = require("url");
10837
+ init_home_paths();
10838
+ }
10839
+ });
10840
+
10827
10841
  // src/runtime-delivery.ts
10828
10842
  function readConfig() {
10829
10843
  try {
10830
- const parsed = JSON.parse(import_fs.default.readFileSync(configFilePath(), "utf8"));
10844
+ const parsed = JSON.parse(import_fs2.default.readFileSync(configFilePath(), "utf8"));
10831
10845
  return parsed && typeof parsed === "object" ? parsed : {};
10832
10846
  } catch {
10833
10847
  return {};
@@ -10881,7 +10895,7 @@ async function installRuntime(opts = {}) {
10881
10895
  const { version, channel, entry } = resolveRuntimeVersion(manifest, opts);
10882
10896
  const destDir = runtimeDir(version);
10883
10897
  const setActive = opts.setActive !== false;
10884
- if (!opts.force && import_fs.default.existsSync(import_path.default.join(destDir, "index.html"))) {
10898
+ if (!opts.force && import_fs2.default.existsSync(import_path2.default.join(destDir, "index.html"))) {
10885
10899
  if (setActive) writeActiveRuntime(version);
10886
10900
  return {
10887
10901
  version,
@@ -10894,7 +10908,7 @@ async function installRuntime(opts = {}) {
10894
10908
  };
10895
10909
  }
10896
10910
  const tarUrl = entry.tarball || runtimeTarballUrl(version, cdnOrigin);
10897
- const tarCachePath = import_path.default.join(cacheDir(), `sootsim-runtime-${version}.tar.gz`);
10911
+ const tarCachePath = import_path2.default.join(cacheDir(), `sootsim-runtime-${version}.tar.gz`);
10898
10912
  process.stderr.write(`sootsim: downloading runtime ${version}\u2026
10899
10913
  `);
10900
10914
  await downloadToFile(tarUrl, tarCachePath);
@@ -10902,23 +10916,23 @@ async function installRuntime(opts = {}) {
10902
10916
  `);
10903
10917
  const actualSha = await sha256File(tarCachePath);
10904
10918
  if (actualSha !== entry.sha256) {
10905
- import_fs.default.rmSync(tarCachePath, { force: true });
10919
+ import_fs2.default.rmSync(tarCachePath, { force: true });
10906
10920
  throw new Error(
10907
10921
  `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
10908
10922
  );
10909
10923
  }
10910
- const tmpDir = import_path.default.join(import_path.default.dirname(destDir), `.installing-${version}-${process.pid}`);
10911
- import_fs.default.rmSync(tmpDir, { recursive: true, force: true });
10912
- import_fs.default.mkdirSync(tmpDir, { recursive: true });
10924
+ const tmpDir = import_path2.default.join(import_path2.default.dirname(destDir), `.installing-${version}-${process.pid}`);
10925
+ import_fs2.default.rmSync(tmpDir, { recursive: true, force: true });
10926
+ import_fs2.default.mkdirSync(tmpDir, { recursive: true });
10913
10927
  try {
10914
10928
  await extractTarball(tarCachePath, tmpDir);
10915
- if (!import_fs.default.existsSync(import_path.default.join(tmpDir, "index.html"))) {
10929
+ if (!import_fs2.default.existsSync(import_path2.default.join(tmpDir, "index.html"))) {
10916
10930
  throw new Error(`extracted tarball for runtime ${version} is missing index.html`);
10917
10931
  }
10918
- import_fs.default.rmSync(destDir, { recursive: true, force: true });
10919
- import_fs.default.renameSync(tmpDir, destDir);
10932
+ import_fs2.default.rmSync(destDir, { recursive: true, force: true });
10933
+ import_fs2.default.renameSync(tmpDir, destDir);
10920
10934
  } catch (err) {
10921
- import_fs.default.rmSync(tmpDir, { recursive: true, force: true });
10935
+ import_fs2.default.rmSync(tmpDir, { recursive: true, force: true });
10922
10936
  throw err;
10923
10937
  }
10924
10938
  if (setActive) writeActiveRuntime(version);
@@ -10958,7 +10972,7 @@ async function updateRuntimeToLatest(opts = {}) {
10958
10972
  }
10959
10973
  const activeVersion = readActiveRuntime();
10960
10974
  const activeDir = activeVersion ? runtimeDir(activeVersion) : null;
10961
- const activeInstalled = activeDir ? import_fs.default.existsSync(import_path.default.join(activeDir, "index.html")) : false;
10975
+ const activeInstalled = activeDir ? import_fs2.default.existsSync(import_path2.default.join(activeDir, "index.html")) : false;
10962
10976
  const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
10963
10977
  if (!shouldInstall) {
10964
10978
  return {
@@ -10988,17 +11002,17 @@ async function downloadToFile(url, destPath) {
10988
11002
  if (!res.ok || !res.body) {
10989
11003
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
10990
11004
  }
10991
- import_fs.default.mkdirSync(import_path.default.dirname(destPath), { recursive: true });
11005
+ import_fs2.default.mkdirSync(import_path2.default.dirname(destPath), { recursive: true });
10992
11006
  const tmp = `${destPath}.partial`;
10993
11007
  try {
10994
11008
  await (0, import_promises.pipeline)(
10995
11009
  import_stream.Readable.fromWeb(res.body),
10996
- import_fs.default.createWriteStream(tmp)
11010
+ import_fs2.default.createWriteStream(tmp)
10997
11011
  );
10998
- import_fs.default.renameSync(tmp, destPath);
11012
+ import_fs2.default.renameSync(tmp, destPath);
10999
11013
  } catch (err) {
11000
11014
  try {
11001
- import_fs.default.unlinkSync(tmp);
11015
+ import_fs2.default.unlinkSync(tmp);
11002
11016
  } catch {
11003
11017
  }
11004
11018
  throw err;
@@ -11007,7 +11021,7 @@ async function downloadToFile(url, destPath) {
11007
11021
  function sha256File(filePath) {
11008
11022
  return new Promise((resolve6, reject) => {
11009
11023
  const hash = import_crypto.default.createHash("sha256");
11010
- const stream = import_fs.default.createReadStream(filePath);
11024
+ const stream = import_fs2.default.createReadStream(filePath);
11011
11025
  stream.on("data", (chunk) => hash.update(chunk));
11012
11026
  stream.on("error", reject);
11013
11027
  stream.on("end", () => resolve6(hash.digest("hex")));
@@ -11025,14 +11039,14 @@ function extractTarball(tarPath, destDir) {
11025
11039
  });
11026
11040
  });
11027
11041
  }
11028
- var import_child_process2, import_crypto, import_fs, import_path, import_stream, import_promises, DEFAULT_RUNTIME_CDN_ORIGIN, RUNTIME_CDN_ORIGIN_ENV, RUNTIME_CHANNEL_ENV;
11042
+ var import_child_process2, import_crypto, import_fs2, import_path2, import_stream, import_promises, DEFAULT_RUNTIME_CDN_ORIGIN, RUNTIME_CDN_ORIGIN_ENV, RUNTIME_CHANNEL_ENV;
11029
11043
  var init_runtime_delivery = __esm({
11030
11044
  "src/runtime-delivery.ts"() {
11031
11045
  "use strict";
11032
11046
  import_child_process2 = require("child_process");
11033
11047
  import_crypto = __toESM(require("crypto"), 1);
11034
- import_fs = __toESM(require("fs"), 1);
11035
- import_path = __toESM(require("path"), 1);
11048
+ import_fs2 = __toESM(require("fs"), 1);
11049
+ import_path2 = __toESM(require("path"), 1);
11036
11050
  import_stream = require("stream");
11037
11051
  import_promises = require("stream/promises");
11038
11052
  init_home_paths();
@@ -12647,12 +12661,12 @@ var init_fetch_proxy_handler = __esm({
12647
12661
 
12648
12662
  // src/host/open-url.ts
12649
12663
  function expandHome(candidate) {
12650
- return candidate.startsWith("~/") ? (0, import_path2.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
12664
+ return candidate.startsWith("~/") ? (0, import_path3.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
12651
12665
  }
12652
12666
  function firstExisting(candidates) {
12653
12667
  for (const candidate of candidates) {
12654
12668
  const expanded = expandHome(candidate);
12655
- if ((0, import_fs2.existsSync)(expanded)) return expanded;
12669
+ if ((0, import_fs3.existsSync)(expanded)) return expanded;
12656
12670
  }
12657
12671
  return null;
12658
12672
  }
@@ -12671,7 +12685,7 @@ function lookupExecutable(command, platform) {
12671
12685
  }
12672
12686
  function resolveChromiumBinary(platform = process.platform) {
12673
12687
  const envCandidate = process.env.CHROME_PATH || process.env.CHROMIUM_PATH;
12674
- if (envCandidate && (0, import_fs2.existsSync)(envCandidate)) return envCandidate;
12688
+ if (envCandidate && (0, import_fs3.existsSync)(envCandidate)) return envCandidate;
12675
12689
  const direct = platform === "darwin" ? firstExisting(MAC_CHROMIUM_CANDIDATES) : platform === "win32" ? firstExisting(WINDOWS_CHROMIUM_CANDIDATES) : firstExisting(LINUX_CHROMIUM_CANDIDATES);
12676
12690
  if (direct) return direct;
12677
12691
  const commands = platform === "win32" ? WINDOWS_CHROMIUM_COMMANDS : UNIX_CHROMIUM_COMMANDS;
@@ -12751,14 +12765,14 @@ async function launchUrl(url, options = {}) {
12751
12765
  async function openUrl(url, options = {}) {
12752
12766
  await launchUrl(url, options);
12753
12767
  }
12754
- var import_child_process3, import_fs2, import_os, import_path2, MAC_CHROMIUM_CANDIDATES, LINUX_CHROMIUM_CANDIDATES, WINDOWS_CHROMIUM_CANDIDATES, UNIX_CHROMIUM_COMMANDS, WINDOWS_CHROMIUM_COMMANDS;
12768
+ var import_child_process3, import_fs3, import_os, import_path3, MAC_CHROMIUM_CANDIDATES, LINUX_CHROMIUM_CANDIDATES, WINDOWS_CHROMIUM_CANDIDATES, UNIX_CHROMIUM_COMMANDS, WINDOWS_CHROMIUM_COMMANDS;
12755
12769
  var init_open_url = __esm({
12756
12770
  "src/host/open-url.ts"() {
12757
12771
  "use strict";
12758
12772
  import_child_process3 = require("child_process");
12759
- import_fs2 = require("fs");
12773
+ import_fs3 = require("fs");
12760
12774
  import_os = require("os");
12761
- import_path2 = require("path");
12775
+ import_path3 = require("path");
12762
12776
  MAC_CHROMIUM_CANDIDATES = [
12763
12777
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
12764
12778
  "~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -13013,19 +13027,20 @@ function unrefTimer(timer) {
13013
13027
  timer.unref();
13014
13028
  }
13015
13029
  }
13016
- var import_child_process4, import_fs3, import_http3, import_path3, import_ws2, SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, SootSimBridgeHost;
13030
+ var import_child_process4, import_fs4, import_http3, import_path4, import_ws2, SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, SootSimBridgeHost;
13017
13031
  var init_bridge_host = __esm({
13018
13032
  "src/host/bridge-host.ts"() {
13019
13033
  "use strict";
13020
13034
  import_child_process4 = require("child_process");
13021
- import_fs3 = __toESM(require("fs"), 1);
13035
+ import_fs4 = __toESM(require("fs"), 1);
13022
13036
  import_http3 = require("http");
13023
- import_path3 = __toESM(require("path"), 1);
13037
+ import_path4 = __toESM(require("path"), 1);
13024
13038
  import_ws2 = require("ws");
13025
13039
  init_dev_server_scanner();
13026
13040
  init_bridge_constants();
13027
13041
  init_cli_version();
13028
13042
  init_home_paths();
13043
+ init_runtime_assets();
13029
13044
  init_runtime_delivery();
13030
13045
  init_agent_host();
13031
13046
  init_fetch_proxy_handler();
@@ -13118,6 +13133,7 @@ var init_bridge_host = __esm({
13118
13133
  automationSimActiveGraceMs;
13119
13134
  shouldWriteLockfile;
13120
13135
  shouldWriteDevLockfile;
13136
+ getShellPort;
13121
13137
  sootbeanOrigin = null;
13122
13138
  effectivePort = 0;
13123
13139
  startedAt = 0;
@@ -13150,6 +13166,7 @@ var init_bridge_host = __esm({
13150
13166
  this.port = this.preferredPort;
13151
13167
  this.shouldWriteLockfile = opts.writeLockfile === true;
13152
13168
  this.shouldWriteDevLockfile = opts.writeDevLockfile === true;
13169
+ this.getShellPort = opts.getShellPort ?? null;
13153
13170
  this.portFallbackCount = Math.max(1, opts.portFallbackCount ?? 10);
13154
13171
  this.openUrlHandler = opts.openUrl;
13155
13172
  this.agentHost = new AgentHost({
@@ -13755,12 +13772,14 @@ var init_bridge_host = __esm({
13755
13772
  };
13756
13773
  }
13757
13774
  buildDevLockfileSnapshot() {
13775
+ const shellPort = this.getShellPort?.() ?? null;
13758
13776
  return {
13759
13777
  schema: 1,
13760
13778
  pid: process.pid,
13761
13779
  platform: process.platform,
13762
13780
  bridgePort: this.effectivePort,
13763
13781
  runtimePort: this.effectivePort,
13782
+ ...shellPort && shellPort > 0 ? { shellPort } : {},
13764
13783
  cwd: process.cwd(),
13765
13784
  startedAt: this.startedAt,
13766
13785
  heartbeatAt: Date.now(),
@@ -13775,7 +13794,7 @@ var init_bridge_host = __esm({
13775
13794
  }
13776
13795
  refreshActiveRuntime() {
13777
13796
  this.activeRuntimeVersion = readActiveRuntime();
13778
- this.activeRuntimeDirPath = activeRuntimeDir();
13797
+ this.activeRuntimeDirPath = resolveDevCheckoutRuntimeRoot() ?? activeRuntimeDir();
13779
13798
  }
13780
13799
  runServerScan() {
13781
13800
  if (this.inflightScan) return this.inflightScan;
@@ -14065,34 +14084,34 @@ var init_bridge_host = __esm({
14065
14084
  return;
14066
14085
  }
14067
14086
  }
14068
- const resolved = import_path3.default.resolve(baseDir, "." + rel);
14069
- const baseWithSep = baseDir.endsWith(import_path3.default.sep) ? baseDir : baseDir + import_path3.default.sep;
14087
+ const resolved = import_path4.default.resolve(baseDir, "." + rel);
14088
+ const baseWithSep = baseDir.endsWith(import_path4.default.sep) ? baseDir : baseDir + import_path4.default.sep;
14070
14089
  if (!resolved.startsWith(baseWithSep) && resolved !== baseDir) {
14071
14090
  res.writeHead(403);
14072
14091
  res.end("forbidden");
14073
14092
  return;
14074
14093
  }
14075
- import_fs3.default.realpath(resolved, (realErr, realResolved) => {
14094
+ import_fs4.default.realpath(resolved, (realErr, realResolved) => {
14076
14095
  const servePath = realErr ? resolved : realResolved;
14077
- const servePathWithSep = servePath.endsWith(import_path3.default.sep) ? servePath : servePath + import_path3.default.sep;
14096
+ const servePathWithSep = servePath.endsWith(import_path4.default.sep) ? servePath : servePath + import_path4.default.sep;
14078
14097
  if (!realErr) {
14079
14098
  const realBaseWithSep = (() => {
14080
14099
  try {
14081
- const rb = import_fs3.default.realpathSync(baseDir);
14082
- return rb.endsWith(import_path3.default.sep) ? rb : rb + import_path3.default.sep;
14100
+ const rb = import_fs4.default.realpathSync(baseDir);
14101
+ return rb.endsWith(import_path4.default.sep) ? rb : rb + import_path4.default.sep;
14083
14102
  } catch {
14084
14103
  return baseWithSep;
14085
14104
  }
14086
14105
  })();
14087
- if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path3.default.sep !== realBaseWithSep) {
14106
+ if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path4.default.sep !== realBaseWithSep) {
14088
14107
  res.writeHead(403);
14089
14108
  res.end("forbidden");
14090
14109
  return;
14091
14110
  }
14092
14111
  }
14093
- import_fs3.default.stat(servePath, (err, stats) => {
14112
+ import_fs4.default.stat(servePath, (err, stats) => {
14094
14113
  if (err || !stats?.isFile()) {
14095
- const ext2 = import_path3.default.extname(rel).toLowerCase();
14114
+ const ext2 = import_path4.default.extname(rel).toLowerCase();
14096
14115
  if (ext2 && ext2 !== ".html") {
14097
14116
  res.writeHead(404);
14098
14117
  res.end("not found");
@@ -14103,8 +14122,8 @@ var init_bridge_host = __esm({
14103
14122
  res.end("not found");
14104
14123
  return;
14105
14124
  }
14106
- const indexPath = import_path3.default.join(baseDir, "index.html");
14107
- import_fs3.default.readFile(indexPath, (err2, data) => {
14125
+ const indexPath = import_path4.default.join(baseDir, "index.html");
14126
+ import_fs4.default.readFile(indexPath, (err2, data) => {
14108
14127
  if (err2) {
14109
14128
  res.writeHead(404);
14110
14129
  res.end("not found");
@@ -14124,7 +14143,7 @@ var init_bridge_host = __esm({
14124
14143
  });
14125
14144
  return;
14126
14145
  }
14127
- const ext = import_path3.default.extname(servePath).toLowerCase();
14146
+ const ext = import_path4.default.extname(servePath).toLowerCase();
14128
14147
  const contentType = HTTP_MIME_TYPES[ext] || "application/octet-stream";
14129
14148
  res.writeHead(200, {
14130
14149
  "Content-Type": contentType,
@@ -14135,7 +14154,7 @@ var init_bridge_host = __esm({
14135
14154
  return;
14136
14155
  }
14137
14156
  if (ext === ".html") {
14138
- import_fs3.default.readFile(servePath, (readErr, data) => {
14157
+ import_fs4.default.readFile(servePath, (readErr, data) => {
14139
14158
  if (readErr) {
14140
14159
  try {
14141
14160
  res.end();
@@ -14149,7 +14168,7 @@ var init_bridge_host = __esm({
14149
14168
  });
14150
14169
  return;
14151
14170
  }
14152
- const stream = import_fs3.default.createReadStream(servePath);
14171
+ const stream = import_fs4.default.createReadStream(servePath);
14153
14172
  stream.pipe(res);
14154
14173
  stream.on("error", () => {
14155
14174
  try {
@@ -14819,6 +14838,15 @@ var init_bridge_host = __esm({
14819
14838
  }
14820
14839
  });
14821
14840
 
14841
+ // src/cli-constants.ts
14842
+ var DEFAULT_SOOTSIM_SHELL_URL;
14843
+ var init_cli_constants = __esm({
14844
+ "src/cli-constants.ts"() {
14845
+ "use strict";
14846
+ DEFAULT_SOOTSIM_SHELL_URL = "http://localhost:5173/";
14847
+ }
14848
+ });
14849
+
14822
14850
  // cli/parent-pid.ts
14823
14851
  function getParentPid(pid) {
14824
14852
  if (!cached3) cached3 = build();
@@ -14844,7 +14872,7 @@ function build() {
14844
14872
  function buildLinux() {
14845
14873
  return (pid) => {
14846
14874
  try {
14847
- const raw = (0, import_fs4.readFileSync)(`/proc/${pid}/stat`, "utf8");
14875
+ const raw = (0, import_fs5.readFileSync)(`/proc/${pid}/stat`, "utf8");
14848
14876
  const end = raw.lastIndexOf(")");
14849
14877
  if (end < 0) return null;
14850
14878
  const rest = raw.slice(end + 1).trim().split(/\s+/);
@@ -14897,12 +14925,12 @@ function buildDarwinLsof() {
14897
14925
  }
14898
14926
  };
14899
14927
  }
14900
- var import_child_process5, import_fs4, import_module, cached3, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET;
14928
+ var import_child_process5, import_fs5, import_module, cached3, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET;
14901
14929
  var init_parent_pid = __esm({
14902
14930
  "cli/parent-pid.ts"() {
14903
14931
  "use strict";
14904
14932
  import_child_process5 = require("child_process");
14905
- import_fs4 = require("fs");
14933
+ import_fs5 = require("fs");
14906
14934
  import_module = require("module");
14907
14935
  cached3 = null;
14908
14936
  PROC_PIDTBSDINFO = 3;
@@ -14940,18 +14968,18 @@ function getCliIdentityKey() {
14940
14968
  }
14941
14969
  function getCurrentSimPath() {
14942
14970
  if (process.env[CURRENT_SIM_PATH_ENV]) {
14943
- return (0, import_path4.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
14971
+ return (0, import_path5.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
14944
14972
  }
14945
14973
  const key = getCliIdentityKey();
14946
- return (0, import_path4.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
14974
+ return (0, import_path5.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
14947
14975
  }
14948
14976
  function readCurrentSim() {
14949
14977
  const filepath = getCurrentSimPath();
14950
- if (!(0, import_fs5.existsSync)(filepath)) return null;
14978
+ if (!(0, import_fs6.existsSync)(filepath)) return null;
14951
14979
  try {
14952
- const parsed = JSON.parse((0, import_fs5.readFileSync)(filepath, "utf8"));
14980
+ const parsed = JSON.parse((0, import_fs6.readFileSync)(filepath, "utf8"));
14953
14981
  if (parsed.version !== CURRENT_SIM_VERSION || typeof parsed.simId !== "string" || !parsed.simId.trim() || typeof parsed.updatedAt !== "string") {
14954
- (0, import_fs5.rmSync)(filepath, { force: true });
14982
+ (0, import_fs6.rmSync)(filepath, { force: true });
14955
14983
  return null;
14956
14984
  }
14957
14985
  return {
@@ -14960,7 +14988,7 @@ function readCurrentSim() {
14960
14988
  updatedAt: parsed.updatedAt
14961
14989
  };
14962
14990
  } catch {
14963
- (0, import_fs5.rmSync)(filepath, { force: true });
14991
+ (0, import_fs6.rmSync)(filepath, { force: true });
14964
14992
  return null;
14965
14993
  }
14966
14994
  }
@@ -14968,15 +14996,15 @@ function readCurrentSimId() {
14968
14996
  return readCurrentSim()?.simId || null;
14969
14997
  }
14970
14998
  function clearCurrentSimId() {
14971
- (0, import_fs5.rmSync)(getCurrentSimPath(), { force: true });
14999
+ (0, import_fs6.rmSync)(getCurrentSimPath(), { force: true });
14972
15000
  }
14973
- var import_fs5, import_os2, import_path4, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS;
15001
+ var import_fs6, import_os2, import_path5, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS;
14974
15002
  var init_current_sim = __esm({
14975
15003
  "cli/current-sim.ts"() {
14976
15004
  "use strict";
14977
- import_fs5 = require("fs");
15005
+ import_fs6 = require("fs");
14978
15006
  import_os2 = require("os");
14979
- import_path4 = require("path");
15007
+ import_path5 = require("path");
14980
15008
  init_parent_pid();
14981
15009
  CURRENT_SIM_VERSION = 1;
14982
15010
  CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
@@ -15015,6 +15043,7 @@ var init_current_sim = __esm({
15015
15043
  var ws_bridge_exports = {};
15016
15044
  __export(ws_bridge_exports, {
15017
15045
  BridgeSimLockedError: () => BridgeSimLockedError,
15046
+ bridgePortForShellBaseUrl: () => bridgePortForShellBaseUrl,
15018
15047
  callInBridge: () => callInBridge,
15019
15048
  callInBridgeWrite: () => callInBridgeWrite,
15020
15049
  checkSimHealth: () => checkSimHealth,
@@ -15022,16 +15051,84 @@ __export(ws_bridge_exports, {
15022
15051
  createBridgeFromParsed: () => createBridgeFromParsed,
15023
15052
  evalInBridge: () => evalInBridge,
15024
15053
  parseBridgeCliArgs: () => parseBridgeCliArgs,
15025
- resolveDefaultBridgePort: () => resolveDefaultBridgePort
15054
+ printBridgeWorldNotice: () => printBridgeWorldNotice,
15055
+ resolveBridgeWorld: () => resolveBridgeWorld,
15056
+ resolveDefaultBridgePort: () => resolveDefaultBridgePort,
15057
+ worldForBridgePort: () => worldForBridgePort
15026
15058
  });
15027
- function resolveDefaultBridgePort() {
15028
- if (shouldSkipPersistentDaemon()) {
15029
- const dev = readDevBridgeLockfile();
15030
- if (dev && isDevBridgeLockfileFresh(dev)) return dev.bridgePort;
15059
+ function resolveBridgeWorld() {
15060
+ const dev = readDevBridgeLockfile();
15061
+ if (dev && isDevBridgeLockfileFresh(dev)) {
15062
+ return {
15063
+ source: "dev-bridge",
15064
+ bridgePort: dev.bridgePort,
15065
+ // older lockfile writers don't record the vite http port; the default
15066
+ // shell URL is the dev shell anyway, so the fallback stays coherent.
15067
+ shellBaseUrl: dev.shellPort ? `http://localhost:${dev.shellPort}/` : DEFAULT_SOOTSIM_SHELL_URL
15068
+ };
15031
15069
  }
15032
15070
  const lock = readDaemonLockfile();
15033
- if (lock && isDaemonLockfileFresh(lock)) return lock.bridgePort;
15034
- return DEFAULT_SOOTSIM_BRIDGE_PORT;
15071
+ if (lock && isDaemonLockfileFresh(lock)) {
15072
+ return {
15073
+ source: "daemon",
15074
+ bridgePort: lock.bridgePort,
15075
+ shellBaseUrl: lock.runtimePort > 0 ? `http://localhost:${lock.runtimePort}/` : DEFAULT_SOOTSIM_SHELL_URL
15076
+ };
15077
+ }
15078
+ return {
15079
+ source: "default",
15080
+ bridgePort: DEFAULT_SOOTSIM_BRIDGE_PORT,
15081
+ shellBaseUrl: DEFAULT_SOOTSIM_SHELL_URL
15082
+ };
15083
+ }
15084
+ function worldForBridgePort(port) {
15085
+ const dev = readDevBridgeLockfile();
15086
+ if (dev && isDevBridgeLockfileFresh(dev) && dev.bridgePort === port) {
15087
+ return {
15088
+ source: "dev-bridge",
15089
+ shellBaseUrl: dev.shellPort ? `http://localhost:${dev.shellPort}/` : DEFAULT_SOOTSIM_SHELL_URL
15090
+ };
15091
+ }
15092
+ const lock = readDaemonLockfile();
15093
+ if (lock && isDaemonLockfileFresh(lock) && lock.bridgePort === port) {
15094
+ return {
15095
+ source: "daemon",
15096
+ shellBaseUrl: lock.runtimePort > 0 ? `http://localhost:${lock.runtimePort}/` : DEFAULT_SOOTSIM_SHELL_URL
15097
+ };
15098
+ }
15099
+ return null;
15100
+ }
15101
+ function bridgePortForShellBaseUrl(baseUrl) {
15102
+ let port;
15103
+ try {
15104
+ const url = new URL(baseUrl);
15105
+ port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80;
15106
+ } catch {
15107
+ return null;
15108
+ }
15109
+ if (!Number.isFinite(port) || port <= 0) return null;
15110
+ const dev = readDevBridgeLockfile();
15111
+ if (dev && isDevBridgeLockfileFresh(dev) && (dev.shellPort === port || dev.runtimePort === port || dev.bridgePort === port)) {
15112
+ return dev.bridgePort;
15113
+ }
15114
+ const lock = readDaemonLockfile();
15115
+ if (lock && isDaemonLockfileFresh(lock) && (lock.runtimePort === port || lock.bridgePort === port)) {
15116
+ return lock.bridgePort;
15117
+ }
15118
+ return null;
15119
+ }
15120
+ function resolveDefaultBridgePort() {
15121
+ return resolveBridgeWorld().bridgePort;
15122
+ }
15123
+ function printBridgeWorldNotice(bridgePort, shellBaseUrl) {
15124
+ const world = worldForBridgePort(bridgePort);
15125
+ const kind = world?.source === "dev-bridge" ? "dev bridge" : world?.source === "daemon" ? "daemon bridge" : "bridge";
15126
+ const origin = world ? `${world.source}.json` : "no lockfile";
15127
+ const shell = shellBaseUrl ?? world?.shellBaseUrl;
15128
+ process.stderr.write(
15129
+ ` \u2192 ${kind} :${bridgePort} (${shell ? `shell ${shell}, ` : ""}${origin})
15130
+ `
15131
+ );
15035
15132
  }
15036
15133
  function describeSimIdSource(source) {
15037
15134
  if (source === "flag") return "via --sim";
@@ -15339,11 +15436,11 @@ async function evalInBridge(bridge, code, opts = {}) {
15339
15436
  if (opts.acquireLock) payload.acquireLock = true;
15340
15437
  return bridge.send(payload);
15341
15438
  }
15342
- async function callInBridge(bridge, path10, ...args) {
15343
- return bridge.send({ type: "call", path: path10, args });
15439
+ async function callInBridge(bridge, path11, ...args) {
15440
+ return bridge.send({ type: "call", path: path11, args });
15344
15441
  }
15345
- async function callInBridgeWrite(bridge, path10, ...args) {
15346
- return bridge.send({ type: "call", path: path10, args, acquireLock: true });
15442
+ async function callInBridgeWrite(bridge, path11, ...args) {
15443
+ return bridge.send({ type: "call", path: path11, args, acquireLock: true });
15347
15444
  }
15348
15445
  var import_ws3, BridgeSimLockedError;
15349
15446
  var init_ws_bridge = __esm({
@@ -15351,6 +15448,7 @@ var init_ws_bridge = __esm({
15351
15448
  "use strict";
15352
15449
  import_ws3 = require("ws");
15353
15450
  init_bridge_constants();
15451
+ init_cli_constants();
15354
15452
  init_home_paths();
15355
15453
  init_current_sim();
15356
15454
  BridgeSimLockedError = class extends Error {
@@ -15925,6 +16023,7 @@ var init_core = __esm({
15925
16023
  let externalReady = null
15926
16024
  let externalStatus = ''
15927
16025
  let externalError = ''
16026
+ let suppressedEntryError = ''
15928
16027
  try {
15929
16028
  const getExternalAppState = t?.getExternalAppState
15930
16029
  const external = typeof getExternalAppState === 'function'
@@ -15949,10 +16048,16 @@ var init_core = __esm({
15949
16048
  if (typeof state.error === 'string') externalError = state.error
15950
16049
  }
15951
16050
  if (!externalError && Array.isArray(external?.entryErrors)) {
15952
- const entry = external.entryErrors.find((item) => {
15953
- return item && typeof item.message === 'string' && item.message.trim()
15954
- })
15955
- if (entry) externalError = entry.message
16051
+ // suppressed-and-continued entry errors (bundle-loader's patched __r
16052
+ // swallows entry throws and moves on) must NOT gate readiness \u2014 the
16053
+ // app frequently runs fine after one (e.g. metro's "Unknown named
16054
+ // module" probing noise). they surface separately as a diagnostic
16055
+ // for the timeout path.
16056
+ const isReal = (item) => item && typeof item.message === 'string' && item.message.trim()
16057
+ const fatal = external.entryErrors.find((item) => isReal(item) && item.suppressed !== true)
16058
+ if (fatal) externalError = fatal.message
16059
+ const suppressed = external.entryErrors.find((item) => isReal(item) && item.suppressed === true)
16060
+ if (suppressed) suppressedEntryError = suppressed.message
15956
16061
  }
15957
16062
  if (externalReady === false && externalStatus) loadingText = externalStatus
15958
16063
  } catch {}
@@ -15968,6 +16073,7 @@ var init_core = __esm({
15968
16073
  externalReady,
15969
16074
  externalStatus,
15970
16075
  externalError,
16076
+ suppressedEntryError,
15971
16077
  }
15972
16078
  })()`;
15973
16079
  READY_CONTENT_NODE_FLOOR = 100;
@@ -16754,16 +16860,16 @@ function resolveFlowScreenshotPath(screenshotDir, name) {
16754
16860
  }
16755
16861
  function resolveProjectRelativeFlowBase(flowDir) {
16756
16862
  if (!flowDir) return process.cwd();
16757
- return path8.basename(flowDir) === ".maestro" ? path8.dirname(flowDir) : flowDir;
16863
+ return path9.basename(flowDir) === ".maestro" ? path9.dirname(flowDir) : flowDir;
16758
16864
  }
16759
16865
  function resolveFlowScreenshotPathWithMode(screenshotDir, name, opts) {
16760
16866
  const normalizedName = name.endsWith(".png") ? name : `${name}.png`;
16761
- if (path8.isAbsolute(normalizedName)) return normalizedName;
16867
+ if (path9.isAbsolute(normalizedName)) return normalizedName;
16762
16868
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
16763
16869
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
16764
- return path8.resolve(baseDir, normalizedName);
16870
+ return path9.resolve(baseDir, normalizedName);
16765
16871
  }
16766
- return path8.join(screenshotDir, normalizedName);
16872
+ return path9.join(screenshotDir, normalizedName);
16767
16873
  }
16768
16874
  function normalizeFlowScreenshotSpec(step) {
16769
16875
  if (typeof step === "string") {
@@ -16818,12 +16924,12 @@ function parseFlowSteps(content) {
16818
16924
  const parsed = import_yaml.default.parse(candidate);
16819
16925
  return Array.isArray(parsed) ? parsed : [];
16820
16926
  }
16821
- var fs8, path8, import_settings2, import_yaml, DEFAULT_TIMEOUT, SCREEN_W, SCREEN_H, CLI_PERF_SESSION_GLOBAL, SootSimBridgeFlowRunner;
16927
+ var fs9, path9, import_settings2, import_yaml, DEFAULT_TIMEOUT, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
16822
16928
  var init_bridge_flow_runner = __esm({
16823
16929
  "cli/bridge-flow-runner.ts"() {
16824
16930
  "use strict";
16825
- fs8 = __toESM(require("fs"), 1);
16826
- path8 = __toESM(require("path"), 1);
16931
+ fs9 = __toESM(require("fs"), 1);
16932
+ path9 = __toESM(require("path"), 1);
16827
16933
  import_settings2 = require("sootsim-engine/settings");
16828
16934
  import_yaml = __toESM(require("yaml"), 1);
16829
16935
  init_frame_compose();
@@ -16836,7 +16942,6 @@ var init_bridge_flow_runner = __esm({
16836
16942
  DEFAULT_TIMEOUT = 1e4;
16837
16943
  SCREEN_W = 393;
16838
16944
  SCREEN_H = 852;
16839
- CLI_PERF_SESSION_GLOBAL = "__sootsimCliPerf";
16840
16945
  SootSimBridgeFlowRunner = class {
16841
16946
  constructor(bridge, opts) {
16842
16947
  this.bridge = bridge;
@@ -17047,14 +17152,14 @@ var init_bridge_flow_runner = __esm({
17047
17152
  if (chunks.length === 0) {
17048
17153
  throw new Error("recording requested but no video buffer was produced");
17049
17154
  }
17050
- fs8.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
17155
+ fs9.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
17051
17156
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
17052
17157
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
17053
- const outputPath = path8.join(
17158
+ const outputPath = path9.join(
17054
17159
  this.opts.recordingOutputDir,
17055
17160
  `sootsim-${Date.now()}.${extension}`
17056
17161
  );
17057
- fs8.writeFileSync(outputPath, Buffer.concat(chunks));
17162
+ fs9.writeFileSync(outputPath, Buffer.concat(chunks));
17058
17163
  return outputPath;
17059
17164
  }
17060
17165
  async waitForRecordingTail(opts) {
@@ -17493,7 +17598,7 @@ var init_bridge_flow_runner = __esm({
17493
17598
  flowDir: this.opts.flowDir
17494
17599
  }
17495
17600
  );
17496
- fs8.mkdirSync(path8.dirname(outputPath), { recursive: true });
17601
+ fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
17497
17602
  const layers = spec.layers ?? this.opts.screenshotLayers;
17498
17603
  const screenshotRequest = {
17499
17604
  type: "screenshot",
@@ -17509,11 +17614,11 @@ var init_bridge_flow_runner = __esm({
17509
17614
  throw new Error("could not read current device model for framed screenshot");
17510
17615
  }
17511
17616
  const framed = await composeFramedScreenshot(rawBuffer, model);
17512
- fs8.writeFileSync(outputPath, framed);
17617
+ fs9.writeFileSync(outputPath, framed);
17513
17618
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
17514
17619
  return;
17515
17620
  }
17516
- fs8.writeFileSync(outputPath, rawBuffer);
17621
+ fs9.writeFileSync(outputPath, rawBuffer);
17517
17622
  console.log(`[flow] screenshot: ${outputPath}`);
17518
17623
  }
17519
17624
  async readCurrentDeviceModel() {
@@ -17528,22 +17633,22 @@ var init_bridge_flow_runner = __esm({
17528
17633
  return model;
17529
17634
  }
17530
17635
  async captureFailureScreenshot(outputPath) {
17531
- fs8.mkdirSync(path8.dirname(outputPath), { recursive: true });
17636
+ fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
17532
17637
  const dataUrl = await this.bridge.send({
17533
17638
  type: "screenshot",
17534
17639
  simId: this.opts.simId
17535
17640
  });
17536
17641
  const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
17537
- fs8.writeFileSync(outputPath, Buffer.from(base64, "base64"));
17642
+ fs9.writeFileSync(outputPath, Buffer.from(base64, "base64"));
17538
17643
  }
17539
17644
  // writes a per-failure debug bundle: screenshot + structured describe
17540
17645
  // + a11y tree + console errors/warnings + failed network requests +
17541
17646
  // shell state, all under one directory so post-mortem is one grep away.
17542
17647
  async captureFailureBundle(outputDir, context) {
17543
- fs8.mkdirSync(outputDir, { recursive: true });
17648
+ fs9.mkdirSync(outputDir, { recursive: true });
17544
17649
  const write = (name, content) => {
17545
17650
  try {
17546
- fs8.writeFileSync(path8.join(outputDir, name), content);
17651
+ fs9.writeFileSync(path9.join(outputDir, name), content);
17547
17652
  } catch {
17548
17653
  }
17549
17654
  };
@@ -17983,101 +18088,25 @@ var init_bridge_flow_runner = __esm({
17983
18088
  return true;
17984
18089
  }
17985
18090
  async startProfile() {
17986
- await this.evaluate(`((sessionKey) => {
17987
- const perf = window.__sootsimPerf
17988
- const a11y = window.__sootsimA11y
17989
- perf?.enableFrameStats?.(true)
17990
- perf?.resetFrameStats?.()
17991
- a11y?.resetProfile?.()
17992
- window[sessionKey] = {
17993
- active: true,
17994
- mode: window.__sootsimRenderHost ? 'render-worker' : 'main-thread',
17995
- lastSamples: [],
17996
- startedAt: performance.now(),
18091
+ const result = await this.evaluate(`(() => {
18092
+ if (!window.__sootsimShellPerf) {
18093
+ return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
17997
18094
  }
17998
- })(${JSON.stringify(CLI_PERF_SESSION_GLOBAL)})`);
18095
+ window.__sootsimShellPerf.start()
18096
+ return { started: true }
18097
+ })()`);
18098
+ if (result?.error) {
18099
+ throw new Error(result.error);
18100
+ }
17999
18101
  this.profilingEnabled = true;
18000
18102
  }
18001
18103
  async stopProfile() {
18002
- const result = await this.evaluate(`(async (sessionKey) => {
18003
- const host = window.__sootsimRenderHost
18004
- if (host?.flushSamples) {
18005
- const perf = window.__sootsimPerf
18006
- const session = window[sessionKey] || {}
18007
- const priorSamples = session.active && Array.isArray(session.lastSamples)
18008
- ? session.lastSamples
18009
- : []
18010
- const flushedSamples = await host.flushSamples()
18011
- await perf?.disableFrameStats?.()
18012
- const samples = priorSamples.concat(flushedSamples)
18013
- window[sessionKey] = {
18014
- ...session,
18015
- active: false,
18016
- mode: 'render-worker',
18017
- lastSamples: samples,
18018
- stoppedAt: performance.now(),
18019
- }
18020
-
18021
- const frameTimes = samples.map((sample) => Number(sample?.[1]) || 0)
18022
- const sorted = [...frameTimes].sort((a, b) => a - b)
18023
- const worstFrames = samples
18024
- .slice()
18025
- .sort((a, b) => (Number(b?.[1]) || 0) - (Number(a?.[1]) || 0))
18026
- .slice(0, 10)
18027
- .map((sample) => [
18028
- Number(sample?.[0]) || 0,
18029
- Number(sample?.[1]) || 0,
18030
- Number(sample?.[2]) || 0,
18031
- Number(sample?.[3]) || 0,
18032
- Number(sample?.[4]) || 0,
18033
- ])
18034
-
18035
- return {
18036
- mode: 'render-worker',
18037
- frames: frameTimes.length,
18038
- totalMs: frameTimes.reduce((sum, value) => sum + value, 0),
18039
- avgMs: frameTimes.length ? frameTimes.reduce((sum, value) => sum + value, 0) / frameTimes.length : 0,
18040
- maxMs: sorted[sorted.length - 1] || 0,
18041
- layoutTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[2]) || 0), 0),
18042
- renderTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[3]) || 0), 0),
18043
- copyTotalMs: samples.reduce((sum, sample) => sum + (Number(sample?.[4]) || 0), 0),
18044
- layoutAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[2]) || 0), 0) / frameTimes.length : 0,
18045
- renderAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[3]) || 0), 0) / frameTimes.length : 0,
18046
- copyAvgMs: frameTimes.length ? samples.reduce((sum, sample) => sum + (Number(sample?.[4]) || 0), 0) / frameTimes.length : 0,
18047
- p50: sorted[Math.floor(sorted.length * 0.5)] || 0,
18048
- p95: sorted[Math.floor(sorted.length * 0.95)] || 0,
18049
- p99: sorted[Math.floor(sorted.length * 0.99)] || 0,
18050
- jankFrames: frameTimes.filter((value) => value > 16.67).length,
18051
- sampleCount: frameTimes.length,
18052
- worstFrames,
18053
- }
18054
- }
18055
-
18056
- const perf = window.__sootsimPerf
18057
- const a11y = window.__sootsimA11y
18058
- if (!perf && !a11y) return { error: 'no perf globals available' }
18059
-
18060
- const stoppedStats = await perf?.disableFrameStats?.()
18061
- const frameStats = stoppedStats || await perf?.getFrameStats?.() || {}
18062
- const profile = a11y?.profile?.() || {}
18063
- const recent = Array.isArray(frameStats.recentFrames) ? frameStats.recentFrames : []
18064
- const sorted = [...recent].sort((a, b) => a - b)
18065
-
18066
- return {
18067
- mode: 'main-thread',
18068
- frames: frameStats.frames || profile.syncCount || 0,
18069
- totalMs: frameStats.totalMs || 0,
18070
- avgMs: frameStats.totalMs && frameStats.frames ? frameStats.totalMs / frameStats.frames : profile.avgSyncMs || 0,
18071
- maxMs: frameStats.maxMs || profile.maxSyncMs || 0,
18072
- layoutTotalMs: frameStats.layoutTotalMs || 0,
18073
- p50: sorted[Math.floor(sorted.length * 0.5)] || 0,
18074
- p95: sorted[Math.floor(sorted.length * 0.95)] || 0,
18075
- p99: sorted[Math.floor(sorted.length * 0.99)] || 0,
18076
- jankFrames: recent.filter((value) => value > 16.67).length,
18077
- sampleCount: recent.length,
18078
- worstFrames: recent.slice().sort((a, b) => b - a).slice(0, 10),
18104
+ const result = await this.evaluate(`(async () => {
18105
+ if (!window.__sootsimShellPerf) {
18106
+ return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
18079
18107
  }
18080
- })(${JSON.stringify(CLI_PERF_SESSION_GLOBAL)})`);
18108
+ return await window.__sootsimShellPerf.stop()
18109
+ })()`);
18081
18110
  this.profilingEnabled = false;
18082
18111
  if (result?.error) {
18083
18112
  throw new Error(result.error);
@@ -18139,8 +18168,8 @@ var init_bridge_flow_runner = __esm({
18139
18168
  runScript(target) {
18140
18169
  const spec = typeof target === "string" ? { file: target } : target;
18141
18170
  if (!spec.file) throw new Error("runScript requires a file");
18142
- const scriptPath = path8.resolve(this.opts.flowDir, spec.file);
18143
- const source = fs8.readFileSync(scriptPath, "utf8");
18171
+ const scriptPath = path9.resolve(this.opts.flowDir, spec.file);
18172
+ const source = fs9.readFileSync(scriptPath, "utf8");
18144
18173
  this.js.evaluate(source, { env: spec.env });
18145
18174
  console.log(`[flow] runScript: ${spec.file} done`);
18146
18175
  }
@@ -18380,10 +18409,10 @@ var init_bridge_flow_runner = __esm({
18380
18409
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
18381
18410
  }
18382
18411
  if (file) {
18383
- const flowPath = path8.resolve(this.opts.flowDir, file);
18384
- const flowContent = fs8.readFileSync(flowPath, "utf8");
18412
+ const flowPath = path9.resolve(this.opts.flowDir, file);
18413
+ const flowContent = fs9.readFileSync(flowPath, "utf8");
18385
18414
  const previousDir = this.opts.flowDir;
18386
- this.opts.flowDir = path8.dirname(flowPath);
18415
+ this.opts.flowDir = path9.dirname(flowPath);
18387
18416
  try {
18388
18417
  await this.runFlow(parseFlowSteps(flowContent));
18389
18418
  } finally {
@@ -18479,8 +18508,8 @@ __export(registry_exports, {
18479
18508
  skillRegistry: () => skillRegistry
18480
18509
  });
18481
18510
  module.exports = __toCommonJS(registry_exports);
18482
- var fs9 = __toESM(require("fs"), 1);
18483
- var path9 = __toESM(require("path"), 1);
18511
+ var fs10 = __toESM(require("fs"), 1);
18512
+ var path10 = __toESM(require("path"), 1);
18484
18513
 
18485
18514
  // src/skills/builtin/a11y-review.ts
18486
18515
  var skill = {
@@ -18498,8 +18527,8 @@ var skill = {
18498
18527
  },
18499
18528
  async execute(params, context) {
18500
18529
  const { chromium } = await import("playwright");
18501
- const path10 = await import("path");
18502
- const fs10 = await import("fs");
18530
+ const path11 = await import("path");
18531
+ const fs11 = await import("fs");
18503
18532
  const browser = await chromium.launch({ channel: "chrome", headless: true });
18504
18533
  const page = await browser.newPage({ viewport: { width: 500, height: 900 } });
18505
18534
  try {
@@ -18552,9 +18581,9 @@ var skill = {
18552
18581
  warnings: issues.filter((i) => i.severity === "warning").length,
18553
18582
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
18554
18583
  };
18555
- const reportPath = path10.join(context.outputDir, "a11y-report.json");
18556
- fs10.mkdirSync(path10.dirname(reportPath), { recursive: true });
18557
- fs10.writeFileSync(reportPath, JSON.stringify(report, null, 2));
18584
+ const reportPath = path11.join(context.outputDir, "a11y-report.json");
18585
+ fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
18586
+ fs11.writeFileSync(reportPath, JSON.stringify(report, null, 2));
18558
18587
  return {
18559
18588
  success: issues.filter((i) => i.severity === "error").length === 0,
18560
18589
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -18592,8 +18621,8 @@ var skill2 = {
18592
18621
  }
18593
18622
  },
18594
18623
  async execute(params, context) {
18595
- const fs10 = await import("fs");
18596
- const path10 = await import("path");
18624
+ const fs11 = await import("fs");
18625
+ const path11 = await import("path");
18597
18626
  const { POLYFILL_REGISTRY: POLYFILL_REGISTRY2 } = await Promise.resolve().then(() => (init_web(), web_exports));
18598
18627
  if (params.packageName) {
18599
18628
  const entry = POLYFILL_REGISTRY2[params.packageName];
@@ -18611,11 +18640,11 @@ var skill2 = {
18611
18640
  data: { package: params.packageName, status, ...entry }
18612
18641
  };
18613
18642
  }
18614
- const pkgPath = path10.join(context.projectDir, "package.json");
18615
- if (!fs10.existsSync(pkgPath)) {
18643
+ const pkgPath = path11.join(context.projectDir, "package.json");
18644
+ if (!fs11.existsSync(pkgPath)) {
18616
18645
  return { success: false, message: "No package.json found" };
18617
18646
  }
18618
- const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf8"));
18647
+ const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
18619
18648
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
18620
18649
  const results = {
18621
18650
  full: [],
@@ -18633,9 +18662,9 @@ var skill2 = {
18633
18662
  results.unknown.push(dep);
18634
18663
  }
18635
18664
  }
18636
- const reportPath = path10.join(context.outputDir, "compat-report.json");
18637
- fs10.mkdirSync(path10.dirname(reportPath), { recursive: true });
18638
- fs10.writeFileSync(reportPath, JSON.stringify(results, null, 2));
18665
+ const reportPath = path11.join(context.outputDir, "compat-report.json");
18666
+ fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
18667
+ fs11.writeFileSync(reportPath, JSON.stringify(results, null, 2));
18639
18668
  return {
18640
18669
  success: results.unsupported.length === 0,
18641
18670
  message: `${results.full.length} full, ${results.partial.length} partial, ${results.unsupported.length} unsupported, ${results.unknown.length} unknown`,
@@ -18673,8 +18702,8 @@ var skill3 = {
18673
18702
  },
18674
18703
  async execute(params, context) {
18675
18704
  const { chromium } = await import("playwright");
18676
- const path10 = await import("path");
18677
- const fs10 = await import("fs");
18705
+ const path11 = await import("path");
18706
+ const fs11 = await import("fs");
18678
18707
  const browser = await chromium.launch({ channel: "chrome", headless: true });
18679
18708
  const page = await browser.newPage({ viewport: { width: 500, height: 900 } });
18680
18709
  try {
@@ -18698,9 +18727,9 @@ var skill3 = {
18698
18727
  ...profile,
18699
18728
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
18700
18729
  };
18701
- const reportPath = path10.join(context.outputDir, "perf-report.json");
18702
- fs10.mkdirSync(path10.dirname(reportPath), { recursive: true });
18703
- fs10.writeFileSync(reportPath, JSON.stringify(report, null, 2));
18730
+ const reportPath = path11.join(context.outputDir, "perf-report.json");
18731
+ fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
18732
+ fs11.writeFileSync(reportPath, JSON.stringify(report, null, 2));
18704
18733
  return {
18705
18734
  success: true,
18706
18735
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -18732,15 +18761,15 @@ var skill4 = {
18732
18761
  },
18733
18762
  async execute(params, context) {
18734
18763
  const { chromium } = await import("playwright");
18735
- const path10 = await import("path");
18736
- const fs10 = await import("fs");
18764
+ const path11 = await import("path");
18765
+ const fs11 = await import("fs");
18737
18766
  const browser = await chromium.launch({ channel: "chrome", headless: true });
18738
18767
  const page = await browser.newPage({ viewport: { width: 500, height: 900 } });
18739
18768
  try {
18740
18769
  await page.goto(context.url, { waitUntil: "networkidle" });
18741
18770
  await page.waitForTimeout(2e3);
18742
- const outputPath = path10.join(context.outputDir, `${params.name}.png`);
18743
- fs10.mkdirSync(path10.dirname(outputPath), { recursive: true });
18771
+ const outputPath = path11.join(context.outputDir, `${params.name}.png`);
18772
+ fs11.mkdirSync(path11.dirname(outputPath), { recursive: true });
18744
18773
  await page.screenshot({ path: outputPath });
18745
18774
  return {
18746
18775
  success: true,
@@ -18778,8 +18807,8 @@ var skill5 = {
18778
18807
  record: { type: "boolean", description: "Record video of the flow" }
18779
18808
  },
18780
18809
  async execute(params, context) {
18781
- const fs10 = await import("fs");
18782
- const path10 = await import("path");
18810
+ const fs11 = await import("fs");
18811
+ const path11 = await import("path");
18783
18812
  const yaml2 = await import("yaml");
18784
18813
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
18785
18814
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -18788,7 +18817,7 @@ var skill5 = {
18788
18817
  const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
18789
18818
  host.start({ silent: true });
18790
18819
  try {
18791
- const flowContent = fs10.readFileSync(params.flowPath, "utf8");
18820
+ const flowContent = fs11.readFileSync(params.flowPath, "utf8");
18792
18821
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
18793
18822
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
18794
18823
  const steps = yaml2.parse(stepsBody);
@@ -18813,7 +18842,7 @@ var skill5 = {
18813
18842
  });
18814
18843
  const driver = new SootSimBridgeFlowRunner2(bridge, {
18815
18844
  screenshotDir: context.outputDir,
18816
- flowDir: path10.dirname(path10.resolve(params.flowPath)),
18845
+ flowDir: path11.dirname(path11.resolve(params.flowPath)),
18817
18846
  simId,
18818
18847
  recordingOutputDir: params.record ? context.outputDir : void 0
18819
18848
  });
@@ -18835,7 +18864,7 @@ var skill5 = {
18835
18864
  simId,
18836
18865
  videoPath: videoPath || void 0
18837
18866
  },
18838
- artifacts: videoPath ? [{ type: "video", name: path10.basename(videoPath), path: videoPath }] : void 0
18867
+ artifacts: videoPath ? [{ type: "video", name: path11.basename(videoPath), path: videoPath }] : void 0
18839
18868
  };
18840
18869
  } finally {
18841
18870
  try {
@@ -18883,21 +18912,21 @@ var skill6 = {
18883
18912
  },
18884
18913
  async execute(params, context) {
18885
18914
  const { chromium } = await import("playwright");
18886
- const path10 = await import("path");
18887
- const fs10 = await import("fs");
18915
+ const path11 = await import("path");
18916
+ const fs11 = await import("fs");
18888
18917
  const browser = await chromium.launch({ channel: "chrome", headless: true });
18889
18918
  const page = await browser.newPage({ viewport: { width: 500, height: 900 } });
18890
18919
  try {
18891
18920
  await page.goto(context.url, { waitUntil: "networkidle" });
18892
18921
  await page.waitForTimeout(2e3);
18893
- const currentPath = path10.join(context.outputDir, `${params.name}-current.png`);
18894
- fs10.mkdirSync(path10.dirname(currentPath), { recursive: true });
18922
+ const currentPath = path11.join(context.outputDir, `${params.name}-current.png`);
18923
+ fs11.mkdirSync(path11.dirname(currentPath), { recursive: true });
18895
18924
  await page.screenshot({ path: currentPath });
18896
18925
  try {
18897
18926
  const { PNG } = await import("pngjs");
18898
18927
  const pixelmatch = (await import("pixelmatch")).default;
18899
- const baseline = PNG.sync.read(fs10.readFileSync(params.baseline));
18900
- const current = PNG.sync.read(fs10.readFileSync(currentPath));
18928
+ const baseline = PNG.sync.read(fs11.readFileSync(params.baseline));
18929
+ const current = PNG.sync.read(fs11.readFileSync(currentPath));
18901
18930
  const { width, height } = baseline;
18902
18931
  const diff = new PNG({ width, height });
18903
18932
  const numDiffPixels = pixelmatch(
@@ -18908,8 +18937,8 @@ var skill6 = {
18908
18937
  height,
18909
18938
  { threshold: params.threshold || 0.1 }
18910
18939
  );
18911
- const diffPath = path10.join(context.outputDir, `${params.name}-diff.png`);
18912
- fs10.writeFileSync(diffPath, PNG.sync.write(diff));
18940
+ const diffPath = path11.join(context.outputDir, `${params.name}-diff.png`);
18941
+ fs11.writeFileSync(diffPath, PNG.sync.write(diff));
18913
18942
  const totalPixels = width * height;
18914
18943
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
18915
18944
  return {
@@ -18973,10 +19002,10 @@ var skillRegistry = {
18973
19002
  },
18974
19003
  // load skills from a project manifest (sootsim-skills.json)
18975
19004
  async loadFromManifest(projectDir) {
18976
- const manifestPath = path9.join(projectDir, "sootsim-skills.json");
18977
- if (!fs9.existsSync(manifestPath)) return;
19005
+ const manifestPath = path10.join(projectDir, "sootsim-skills.json");
19006
+ if (!fs10.existsSync(manifestPath)) return;
18978
19007
  try {
18979
- const manifest = JSON.parse(fs9.readFileSync(manifestPath, "utf8"));
19008
+ const manifest = JSON.parse(fs10.readFileSync(manifestPath, "utf8"));
18980
19009
  if (Array.isArray(manifest.skills)) {
18981
19010
  for (const entry of manifest.skills) {
18982
19011
  if (typeof entry === "string") {
@@ -18987,7 +19016,7 @@ var skillRegistry = {
18987
19016
  }
18988
19017
  } else if (entry.file) {
18989
19018
  try {
18990
- const mod = await import(path9.resolve(projectDir, entry.file));
19019
+ const mod = await import(path10.resolve(projectDir, entry.file));
18991
19020
  if (mod.skill) this.register(mod.skill);
18992
19021
  } catch {
18993
19022
  }
@@ -19000,10 +19029,10 @@ var skillRegistry = {
19000
19029
  // auto-discover skills based on project dependencies
19001
19030
  suggestSkills(projectDir) {
19002
19031
  const suggestions = [];
19003
- const pkgPath = path9.join(projectDir, "package.json");
19004
- if (!fs9.existsSync(pkgPath)) return suggestions;
19032
+ const pkgPath = path10.join(projectDir, "package.json");
19033
+ if (!fs10.existsSync(pkgPath)) return suggestions;
19005
19034
  try {
19006
- const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf8"));
19035
+ const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf8"));
19007
19036
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
19008
19037
  if (deps["detox"] || deps["maestro"]) {
19009
19038
  suggestions.push("test-flow");