sootsim 0.1.251 → 0.1.253

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 (150) hide show
  1. package/README.md +8 -5
  2. package/dist-cli/bin.js +4 -4
  3. package/dist-cli/chunks/{agent-OS5AFMNY.js → agent-VULBDRQX.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-JXCJFH4J.js → agent-wrapper-NIKM5YH7.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-KM5VGTPQ.js → app-fonts-H6Q7KUPX.js} +2 -2
  6. package/dist-cli/chunks/{assert-IWDBWZA3.js → assert-KG4DXXXU.js} +2 -2
  7. package/dist-cli/chunks/{auth-GGWN2KHL.js → auth-YFAM5XCG.js} +2 -2
  8. package/dist-cli/chunks/beta-X7YVGAZ7.js +2 -0
  9. package/dist-cli/chunks/{camera-W5JQ5P6L.js → camera-LDDRWGWU.js} +2 -2
  10. package/dist-cli/chunks/chunk-36BZF4FN.js +29 -0
  11. package/dist-cli/chunks/{chunk-CQKALFGJ.js → chunk-3UCSOXI3.js} +1 -1
  12. package/dist-cli/chunks/{chunk-XJYAJ5C3.js → chunk-45WNNP6S.js} +2 -2
  13. package/dist-cli/chunks/{chunk-UTNAJIRM.js → chunk-46TTKKZH.js} +2 -2
  14. package/dist-cli/chunks/chunk-57Y54BSR.js +1 -0
  15. package/dist-cli/chunks/{chunk-LJKL5JQ7.js → chunk-5FUEGJVZ.js} +2 -2
  16. package/dist-cli/chunks/{chunk-CDZTB6JX.js → chunk-5KIOJ7EY.js} +2 -2
  17. package/dist-cli/chunks/{chunk-IC4GREHT.js → chunk-5LRIUIDH.js} +1 -1
  18. package/dist-cli/chunks/{chunk-KEBLYJBJ.js → chunk-7X342NBJ.js} +2 -2
  19. package/dist-cli/chunks/chunk-AVDM5PJT.js +7 -0
  20. package/dist-cli/chunks/{chunk-7HCKUJ5R.js → chunk-BMDLK4TN.js} +1 -1
  21. package/dist-cli/chunks/{chunk-VO5UXLRE.js → chunk-C5WLLPSP.js} +2 -2
  22. package/dist-cli/chunks/chunk-DCSZ4W7L.js +4 -0
  23. package/dist-cli/chunks/{chunk-55GPRX3M.js → chunk-DEPT2HN2.js} +2 -2
  24. package/dist-cli/chunks/{chunk-KD347J3Y.js → chunk-DVL3QEUF.js} +2 -2
  25. package/dist-cli/chunks/{chunk-LETXRLKY.js → chunk-GQEV66R5.js} +1 -1
  26. package/dist-cli/chunks/{chunk-Z7IG2OVW.js → chunk-HWJY7OMU.js} +1 -1
  27. package/dist-cli/chunks/chunk-HWUTV647.js +1 -0
  28. package/dist-cli/chunks/{chunk-MK5FIMS5.js → chunk-I2SPWGIX.js} +2 -2
  29. package/dist-cli/chunks/{chunk-7MEV3VTL.js → chunk-IRKSPKGN.js} +1 -1
  30. package/dist-cli/chunks/{chunk-PM3MMXYH.js → chunk-L2MLV2CS.js} +2 -2
  31. package/dist-cli/chunks/{chunk-FBAFTRKJ.js → chunk-L6CZJTQL.js} +2 -2
  32. package/dist-cli/chunks/{chunk-KEJB5OS5.js → chunk-LQGKEJEY.js} +2 -2
  33. package/dist-cli/chunks/{chunk-WD4B3KV6.js → chunk-MJVYTFNP.js} +3 -3
  34. package/dist-cli/chunks/{chunk-YJEU2B3D.js → chunk-MWMCDY2F.js} +1 -1
  35. package/dist-cli/chunks/{chunk-RBHEKEEX.js → chunk-NGPLOHLX.js} +2 -2
  36. package/dist-cli/chunks/{chunk-63FDEQKS.js → chunk-NKBPE462.js} +1 -1
  37. package/dist-cli/chunks/{chunk-OOLWKYWS.js → chunk-NTITLMC6.js} +1 -1
  38. package/dist-cli/chunks/{chunk-TQJZ2AP4.js → chunk-NUEXSE26.js} +2 -2
  39. package/dist-cli/chunks/{chunk-DVLNBQO6.js → chunk-NUPOCIXQ.js} +2 -2
  40. package/dist-cli/chunks/{chunk-GMJ3ROI3.js → chunk-PDGZJCKZ.js} +2 -2
  41. package/dist-cli/chunks/{chunk-ULYIJUKO.js → chunk-PPEVHLXX.js} +2 -2
  42. package/dist-cli/chunks/{chunk-EY5V6OC5.js → chunk-Q5HUMK3X.js} +2 -2
  43. package/dist-cli/chunks/{chunk-NQCAEFUQ.js → chunk-QLD2JSAY.js} +1 -1
  44. package/dist-cli/chunks/{chunk-H3YZXLYR.js → chunk-RKLOJJIQ.js} +1 -1
  45. package/dist-cli/chunks/{chunk-IYPXOVE4.js → chunk-ROP4FQW2.js} +1 -1
  46. package/dist-cli/chunks/{chunk-ZL3QAP5O.js → chunk-SM36BLYO.js} +3 -3
  47. package/dist-cli/chunks/{chunk-37PWKV2H.js → chunk-UTHHCEOE.js} +1 -1
  48. package/dist-cli/chunks/{chunk-X4HNMVAY.js → chunk-VUUVN4CA.js} +2 -2
  49. package/dist-cli/chunks/{chunk-PZZPL7XB.js → chunk-WLTTYQFC.js} +1 -1
  50. package/dist-cli/chunks/{chunk-5T62AM5W.js → chunk-WXXCER5Y.js} +3 -3
  51. package/dist-cli/chunks/{chunk-7JTW5KO4.js → chunk-XRDM6KN6.js} +1 -1
  52. package/dist-cli/chunks/{chunk-HLD3JMUC.js → chunk-Y66ZEDLD.js} +2 -2
  53. package/dist-cli/chunks/{chunk-Z6ZYU2VN.js → chunk-YQDI7PAU.js} +1 -1
  54. package/dist-cli/chunks/cli-version-YK3KEAWE.js +2 -0
  55. package/dist-cli/chunks/{compat-Q7NF5FGR.js → compat-5MLHRLL7.js} +3 -3
  56. package/dist-cli/chunks/{config-CHFGC57H.js → config-XQU7NIBN.js} +2 -2
  57. package/dist-cli/chunks/{control-GMXYQHOC.js → control-CP27GWY2.js} +2 -2
  58. package/dist-cli/chunks/daemon-SZ5235QJ.js +2 -0
  59. package/dist-cli/chunks/{debug-JVFKA6ZJ.js → debug-XAS5RRTR.js} +3 -3
  60. package/dist-cli/chunks/{desktop-DT6WBVHN.js → desktop-DMRDH54D.js} +3 -3
  61. package/dist-cli/chunks/{detox-OQ3DVIZB.js → detox-5RWKQ4FY.js} +2 -2
  62. package/dist-cli/chunks/{device-XBBNWO67.js → device-K4QUDQJW.js} +2 -2
  63. package/dist-cli/chunks/{diagnose-JFWKSZI6.js → diagnose-XQ3UCGAC.js} +2 -2
  64. package/dist-cli/chunks/drivers-4XIRJTRV.js +2 -0
  65. package/dist-cli/chunks/{film-3BI63O2P.js → film-NBO7R7YE.js} +3 -3
  66. package/dist-cli/chunks/flow-IPFJBZ2T.js +2 -0
  67. package/dist-cli/chunks/help-OVFNRXKE.js +2 -0
  68. package/dist-cli/chunks/{hidden-runtime-alias-JGY2SN3U.js → hidden-runtime-alias-HMRDTRPL.js} +2 -2
  69. package/dist-cli/chunks/home-paths-IHLLHTH3.js +2 -0
  70. package/dist-cli/chunks/inspect-OLDRJZFR.js +2 -0
  71. package/dist-cli/chunks/install-desktop-4LN5U3GV.js +2 -0
  72. package/dist-cli/chunks/{login-QT6OUDLD.js → login-JJ26E3ZL.js} +4 -4
  73. package/dist-cli/chunks/{logout-QM7I6EYI.js → logout-Z4T2ZUMV.js} +2 -2
  74. package/dist-cli/chunks/{maestro-YU5YDZ44.js → maestro-27CX2MYE.js} +3 -3
  75. package/dist-cli/chunks/{maestro-generate-YQ5GE6LW.js → maestro-generate-S2HMOTKV.js} +3 -3
  76. package/dist-cli/chunks/{mode-MHOIKOWG.js → mode-MUI6VEX5.js} +2 -2
  77. package/dist-cli/chunks/optional-demo-registry-B5KGRDC7.js +2 -0
  78. package/dist-cli/chunks/{perf-UDWM5CLN.js → perf-XLL4NAW4.js} +2 -2
  79. package/dist-cli/chunks/{record-EEYIMPNW.js → record-CO6ZZXOF.js} +3 -3
  80. package/dist-cli/chunks/runtime-3BT5LEI2.js +2 -0
  81. package/dist-cli/chunks/{screenshot-command-MDOO4W2M.js → screenshot-command-7TLIPP6M.js} +3 -3
  82. package/dist-cli/chunks/{screenshots-capture-MYFBKRYI.js → screenshots-capture-W47CLDWK.js} +2 -2
  83. package/dist-cli/chunks/{serve-TFGKULND.js → serve-JFWQW3PY.js} +15 -15
  84. package/dist-cli/chunks/{setup-WOB5DERX.js → setup-64WP25N3.js} +3 -3
  85. package/dist-cli/chunks/{skills-MFFPTR5A.js → skills-FEOY5MFR.js} +2 -2
  86. package/dist-cli/chunks/{storage-6IZXGU2O.js → storage-DVJEOSE5.js} +2 -2
  87. package/dist-cli/chunks/store-VWZLLKMA.js +2 -0
  88. package/dist-cli/chunks/telemetry-RRR64APJ.js +2 -0
  89. package/dist-cli/chunks/{timeline-BRXK7M5J.js → timeline-BN4FOIE5.js} +2 -2
  90. package/dist-cli/chunks/{upgrade-K6A4PITT.js → upgrade-R6FMWF53.js} +4 -4
  91. package/dist-cli/chunks/upload-VV6ASI6M.js +2 -0
  92. package/dist-cli/chunks/version-5GYDQEIP.js +4 -0
  93. package/dist-cli/chunks/{web-P3ANEMOL.js → web-SZQMAIF5.js} +2 -2
  94. package/dist-cli/chunks/{what-happened-OFMSOZZB.js → what-happened-2KMAVPKZ.js} +2 -2
  95. package/dist-lib/agent-daemon-client.cjs +1 -1
  96. package/dist-lib/agent-events.cjs +1 -1
  97. package/dist-lib/agent-identity.cjs +1 -1
  98. package/dist-lib/agent-sessions.cjs +1 -1
  99. package/dist-lib/attached-projects.cjs +1 -1
  100. package/dist-lib/auth/shared-session.cjs +1 -1
  101. package/dist-lib/backend-origin.cjs +1 -1
  102. package/dist-lib/beta.cjs +1 -1
  103. package/dist-lib/beta.mjs +1 -1
  104. package/dist-lib/bridge-constants.cjs +1 -1
  105. package/dist-lib/cli-constants.cjs +1 -1
  106. package/dist-lib/config.cjs +1 -1
  107. package/dist-lib/detox/index.cjs +1 -1
  108. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  109. package/dist-lib/home-paths.cjs +1 -33
  110. package/dist-lib/host/bridge-host.cjs +404 -329
  111. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  112. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  113. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  114. package/dist-lib/host/websocket-proxy.cjs +1 -1
  115. package/dist-lib/index.cjs +1 -1
  116. package/dist-lib/jump-to-source-babel.cjs +1 -1
  117. package/dist-lib/menu.cjs +1 -1
  118. package/dist-lib/menu.mjs +1 -1
  119. package/dist-lib/metro.cjs +1 -1
  120. package/dist-lib/profiles.cjs +1 -1
  121. package/dist-lib/render-mode.cjs +1 -1
  122. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  123. package/dist-lib/sdk.cjs +1 -1
  124. package/dist-lib/sdk.mjs +1 -1
  125. package/dist-lib/skills.cjs +523 -435
  126. package/dist-lib/vite.cjs +1 -1
  127. package/package.json +2 -1
  128. package/src/home-paths.ts +5 -40
  129. package/src/host/bridge-host.ts +4 -5
  130. package/src/runtime-delivery.ts +36 -377
  131. package/dist-cli/chunks/beta-LVHWRJCU.js +0 -2
  132. package/dist-cli/chunks/chunk-2273TU3I.js +0 -1
  133. package/dist-cli/chunks/chunk-6ACR2P3U.js +0 -1
  134. package/dist-cli/chunks/chunk-HMOZ6UBM.js +0 -29
  135. package/dist-cli/chunks/chunk-JFXVQVXW.js +0 -4
  136. package/dist-cli/chunks/chunk-OLCSJXAQ.js +0 -7
  137. package/dist-cli/chunks/cli-version-Z2MVFJOA.js +0 -2
  138. package/dist-cli/chunks/daemon-NM537LET.js +0 -2
  139. package/dist-cli/chunks/drivers-NOJ7CRI4.js +0 -2
  140. package/dist-cli/chunks/flow-7ETXJJ6C.js +0 -2
  141. package/dist-cli/chunks/help-FE5IIJIM.js +0 -2
  142. package/dist-cli/chunks/home-paths-BLOAGTA2.js +0 -2
  143. package/dist-cli/chunks/inspect-UA376AF4.js +0 -2
  144. package/dist-cli/chunks/install-desktop-KBXAATJW.js +0 -2
  145. package/dist-cli/chunks/optional-demo-registry-RF4SZYRO.js +0 -2
  146. package/dist-cli/chunks/runtime-UJOIMMBS.js +0 -2
  147. package/dist-cli/chunks/store-JG2JCUFN.js +0 -2
  148. package/dist-cli/chunks/telemetry-HI4GNTOS.js +0 -2
  149. package/dist-cli/chunks/upload-ZNSE6XIN.js +0 -2
  150. package/dist-cli/chunks/version-4HZWAXW3.js +0 -4
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.251 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.253 | (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;
@@ -10528,10 +10528,10 @@ function tcpPing(port, timeout = TCP_GATE_MS) {
10528
10528
  sock.connect(port, "localhost");
10529
10529
  });
10530
10530
  }
10531
- function httpGet(port, path11, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
10531
+ function httpGet(port, path12, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
10532
10532
  return new Promise((resolve5) => {
10533
10533
  const req = import_http.default.request(
10534
- { hostname: "localhost", port, path: path11, method, timeout, headers },
10534
+ { hostname: "localhost", port, path: path12, method, timeout, headers },
10535
10535
  (res) => {
10536
10536
  let body = "";
10537
10537
  res.on("data", (c) => body += c.toString());
@@ -11088,34 +11088,6 @@ function writeActiveRuntime(version) {
11088
11088
  import_node_fs2.default.writeFileSync(activeRuntimeFile(), `${version}
11089
11089
  `, "utf8");
11090
11090
  }
11091
- function listInstalledRuntimes() {
11092
- try {
11093
- return import_node_fs2.default.readdirSync(runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
11094
- } catch {
11095
- return [];
11096
- }
11097
- }
11098
- function compareSemver(a, b) {
11099
- const parse = (v) => {
11100
- const hyphen = v.indexOf("-");
11101
- const core = hyphen >= 0 ? v.slice(0, hyphen) : v;
11102
- const pre = hyphen >= 0 ? v.slice(hyphen + 1) : "";
11103
- const parts = core.split(".").map((n) => Number.parseInt(n, 10));
11104
- if (parts.some((n) => !Number.isFinite(n))) return [[Number.POSITIVE_INFINITY], v];
11105
- return [parts, pre];
11106
- };
11107
- const [an, ap] = parse(a);
11108
- const [bn, bp] = parse(b);
11109
- for (let i = 0; i < Math.max(an.length, bn.length); i++) {
11110
- const av = an[i] ?? 0;
11111
- const bv = bn[i] ?? 0;
11112
- if (av !== bv) return av - bv;
11113
- }
11114
- if (ap === bp) return 0;
11115
- if (!ap) return 1;
11116
- if (!bp) return -1;
11117
- return ap < bp ? -1 : 1;
11118
- }
11119
11091
  function activeRuntimeDir() {
11120
11092
  const version = readActiveRuntime();
11121
11093
  if (!version) return null;
@@ -11271,139 +11243,241 @@ var init_runtime_assets = __esm({
11271
11243
  }
11272
11244
  });
11273
11245
 
11274
- // src/runtime-delivery.ts
11275
- function readConfig() {
11246
+ // ../contrast-runtime-delivery/src/product.ts
11247
+ function listInstalledRuntimes(product) {
11276
11248
  try {
11277
- const parsed = JSON.parse(import_fs2.default.readFileSync(configFilePath(), "utf8"));
11278
- return parsed && typeof parsed === "object" ? parsed : {};
11249
+ return import_node_fs3.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
11279
11250
  } catch {
11280
- return {};
11251
+ return [];
11281
11252
  }
11282
11253
  }
11283
- function resolveRuntimeCdnOrigin(input) {
11284
- const config = readConfig();
11285
- const value = input || process.env[RUNTIME_CDN_ORIGIN_ENV] || config.cdnOrigin || DEFAULT_RUNTIME_CDN_ORIGIN;
11286
- return value.replace(/\/+$/, "");
11287
- }
11288
- function resolveRuntimeChannel(input) {
11289
- const config = readConfig();
11290
- return input || process.env[RUNTIME_CHANNEL_ENV] || config.runtimeChannel || "stable";
11291
- }
11292
- function resolveRuntimePin() {
11293
- const env = process.env[RUNTIME_PIN_ENV];
11294
- if (env && env.trim()) return env.trim();
11295
- const config = readConfig();
11296
- return typeof config.runtimeVersion === "string" && config.runtimeVersion.trim() ? config.runtimeVersion.trim() : null;
11297
- }
11298
- function runtimeManifestUrl(cdnOrigin) {
11299
- const url = new URL(`${resolveRuntimeCdnOrigin(cdnOrigin)}/runtimes/manifest.json`);
11300
- url.searchParams.set("t", String(Date.now()));
11301
- return url.toString();
11302
- }
11303
- function runtimeTarballUrl(version, cdnOrigin) {
11304
- return `${resolveRuntimeCdnOrigin(cdnOrigin)}/runtimes/sootsim-runtime-${version}.tar.gz`;
11254
+ function runtimeTarballCacheName(product, version) {
11255
+ return import_node_path2.default.posix.basename(product.tarballPath(version));
11305
11256
  }
11306
- async function fetchRuntimeManifest(cdnOrigin) {
11307
- const url = runtimeManifestUrl(cdnOrigin);
11308
- const res = await fetch(url, { headers: { Accept: "application/json" } });
11309
- if (!res.ok) {
11310
- throw new Error(`manifest fetch failed: ${res.status} ${res.statusText} (${url})`);
11257
+ function compareSemver(a, b) {
11258
+ const parse = (v) => {
11259
+ const hyphen = v.indexOf("-");
11260
+ const core = hyphen >= 0 ? v.slice(0, hyphen) : v;
11261
+ const pre = hyphen >= 0 ? v.slice(hyphen + 1) : "";
11262
+ const parts = core.split(".").map((n) => Number.parseInt(n, 10));
11263
+ if (parts.some((n) => !Number.isFinite(n))) return [[Number.POSITIVE_INFINITY], v];
11264
+ return [parts, pre];
11265
+ };
11266
+ const [an, ap] = parse(a);
11267
+ const [bn, bp] = parse(b);
11268
+ for (let i = 0; i < Math.max(an.length, bn.length); i++) {
11269
+ const av = an[i] ?? 0;
11270
+ const bv = bn[i] ?? 0;
11271
+ if (av !== bv) return av - bv;
11311
11272
  }
11312
- return await res.json();
11273
+ if (ap === bp) return 0;
11274
+ if (!ap) return 1;
11275
+ if (!bp) return -1;
11276
+ return ap < bp ? -1 : 1;
11313
11277
  }
11314
- function resolveRuntimeVersion(manifest, opts = {}) {
11315
- const channel = resolveRuntimeChannel(opts.channel);
11316
- const version = opts.version || resolveRuntimePin() || manifest.channels[channel]?.latest;
11317
- if (!version) {
11318
- throw new Error(
11319
- `no version specified and channel '${channel}' has no latest entry in the manifest`
11320
- );
11278
+ var import_node_fs3, import_node_path2;
11279
+ var init_product = __esm({
11280
+ "../contrast-runtime-delivery/src/product.ts"() {
11281
+ "use strict";
11282
+ import_node_fs3 = __toESM(require("node:fs"), 1);
11283
+ import_node_path2 = __toESM(require("node:path"), 1);
11321
11284
  }
11322
- const entry = manifest.versions[version];
11323
- if (!entry) {
11324
- throw new Error(
11325
- `version ${version} not found in manifest; available: ${Object.keys(manifest.versions).slice(-10).join(", ") || "(none)"}`
11326
- );
11285
+ });
11286
+
11287
+ // ../contrast-runtime-delivery/src/index.ts
11288
+ function createRuntimeDelivery(product) {
11289
+ function readConfig() {
11290
+ try {
11291
+ const parsed = JSON.parse(
11292
+ import_node_fs4.default.readFileSync(product.configFile(), "utf8")
11293
+ );
11294
+ return parsed && typeof parsed === "object" ? parsed : {};
11295
+ } catch {
11296
+ return {};
11297
+ }
11327
11298
  }
11328
- return { version, channel, entry };
11329
- }
11330
- async function installRuntime(opts = {}) {
11331
- ensureSootsimHome();
11332
- const cdnOrigin = resolveRuntimeCdnOrigin(opts.cdnOrigin);
11333
- const manifest = await fetchRuntimeManifest(cdnOrigin);
11334
- const { version, channel, entry } = resolveRuntimeVersion(manifest, opts);
11335
- const destDir = runtimeDir(version);
11336
- const setActive = opts.setActive !== false;
11337
- if (!opts.force && import_fs2.default.existsSync(import_path2.default.join(destDir, "index.html"))) {
11338
- if (setActive) writeActiveRuntime(version);
11299
+ function resolveCdnOrigin(input) {
11300
+ const config = readConfig();
11301
+ const value = input || process.env[product.env.cdnOrigin] || config.cdnOrigin || product.defaultCdnOrigin;
11302
+ return value.replace(/\/+$/, "");
11303
+ }
11304
+ function resolveChannel(input) {
11305
+ const config = readConfig();
11306
+ return input || process.env[product.env.channel] || config.runtimeChannel || "stable";
11307
+ }
11308
+ function resolvePin() {
11309
+ const env = process.env[product.env.pin];
11310
+ if (env && env.trim()) return env.trim();
11311
+ const config = readConfig();
11312
+ return typeof config.runtimeVersion === "string" && config.runtimeVersion.trim() ? config.runtimeVersion.trim() : null;
11313
+ }
11314
+ function manifestUrl(cdnOrigin) {
11315
+ const url = new URL(`${resolveCdnOrigin(cdnOrigin)}${product.manifestPath}`);
11316
+ url.searchParams.set("t", String(Date.now()));
11317
+ return url.toString();
11318
+ }
11319
+ function tarballUrl(version, cdnOrigin) {
11320
+ return `${resolveCdnOrigin(cdnOrigin)}${product.tarballPath(version)}`;
11321
+ }
11322
+ async function fetchManifest(cdnOrigin) {
11323
+ const url = manifestUrl(cdnOrigin);
11324
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
11325
+ if (!res.ok) {
11326
+ throw new Error(`manifest fetch failed: ${res.status} ${res.statusText} (${url})`);
11327
+ }
11328
+ return await res.json();
11329
+ }
11330
+ function resolveVersion(manifest, opts = {}) {
11331
+ const channel = resolveChannel(opts.channel);
11332
+ const version = opts.version || resolvePin() || manifest.channels[channel]?.latest;
11333
+ if (!version) {
11334
+ throw new Error(
11335
+ `no version specified and channel '${channel}' has no latest entry in the manifest`
11336
+ );
11337
+ }
11338
+ const entry = manifest.versions[version];
11339
+ if (!entry) {
11340
+ throw new Error(
11341
+ `version ${version} not found in manifest; available: ${Object.keys(manifest.versions).slice(-10).join(", ") || "(none)"}`
11342
+ );
11343
+ }
11344
+ return { version, channel, entry };
11345
+ }
11346
+ async function install(opts = {}) {
11347
+ product.ensureHome();
11348
+ const cdnOrigin = resolveCdnOrigin(opts.cdnOrigin);
11349
+ const manifest = await fetchManifest(cdnOrigin);
11350
+ const { version, channel, entry } = resolveVersion(manifest, opts);
11351
+ const destDir = product.runtimeDir(version);
11352
+ const setActive = opts.setActive !== false;
11353
+ if (!opts.force && import_node_fs4.default.existsSync(import_node_path3.default.join(destDir, product.installedMarker))) {
11354
+ if (setActive) product.writeActiveRuntime(version);
11355
+ return {
11356
+ version,
11357
+ channel,
11358
+ cdnOrigin,
11359
+ runtimeDir: destDir,
11360
+ installed: false,
11361
+ activated: setActive,
11362
+ manifest
11363
+ };
11364
+ }
11365
+ const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
11366
+ const tarCachePath = import_node_path3.default.join(
11367
+ product.cacheDir(),
11368
+ runtimeTarballCacheName(product, version)
11369
+ );
11370
+ process.stderr.write(`${product.id}: downloading runtime ${version}\u2026
11371
+ `);
11372
+ await downloadToFile(tarUrl, tarCachePath);
11373
+ process.stderr.write(`${product.id}: extracting runtime ${version}\u2026
11374
+ `);
11375
+ const actualSha = await sha256File(tarCachePath);
11376
+ if (actualSha !== entry.sha256) {
11377
+ import_node_fs4.default.rmSync(tarCachePath, { force: true });
11378
+ throw new Error(
11379
+ `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
11380
+ );
11381
+ }
11382
+ const tmpDir = import_node_path3.default.join(
11383
+ import_node_path3.default.dirname(destDir),
11384
+ `.installing-${version}-${process.pid}`
11385
+ );
11386
+ import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
11387
+ import_node_fs4.default.mkdirSync(tmpDir, { recursive: true });
11388
+ try {
11389
+ await extractTarball(tarCachePath, tmpDir);
11390
+ if (!import_node_fs4.default.existsSync(import_node_path3.default.join(tmpDir, product.installedMarker))) {
11391
+ throw new Error(
11392
+ `extracted tarball for runtime ${version} is missing ${product.installedMarker}`
11393
+ );
11394
+ }
11395
+ import_node_fs4.default.rmSync(destDir, { recursive: true, force: true });
11396
+ import_node_fs4.default.renameSync(tmpDir, destDir);
11397
+ } catch (err) {
11398
+ import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
11399
+ throw err;
11400
+ }
11401
+ if (setActive) product.writeActiveRuntime(version);
11339
11402
  return {
11340
11403
  version,
11341
11404
  channel,
11342
11405
  cdnOrigin,
11343
11406
  runtimeDir: destDir,
11344
- installed: false,
11407
+ installed: true,
11345
11408
  activated: setActive,
11346
11409
  manifest
11347
11410
  };
11348
11411
  }
11349
- const tarUrl = entry.tarball || runtimeTarballUrl(version, cdnOrigin);
11350
- const tarCachePath = import_path2.default.join(cacheDir(), `sootsim-runtime-${version}.tar.gz`);
11351
- process.stderr.write(`sootsim: downloading runtime ${version}\u2026
11352
- `);
11353
- await downloadToFile(tarUrl, tarCachePath);
11354
- process.stderr.write(`sootsim: extracting runtime ${version}\u2026
11355
- `);
11356
- const actualSha = await sha256File(tarCachePath);
11357
- if (actualSha !== entry.sha256) {
11358
- import_fs2.default.rmSync(tarCachePath, { force: true });
11359
- throw new Error(
11360
- `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
11361
- );
11362
- }
11363
- const tmpDir = import_path2.default.join(import_path2.default.dirname(destDir), `.installing-${version}-${process.pid}`);
11364
- import_fs2.default.rmSync(tmpDir, { recursive: true, force: true });
11365
- import_fs2.default.mkdirSync(tmpDir, { recursive: true });
11366
- try {
11367
- await extractTarball(tarCachePath, tmpDir);
11368
- if (!import_fs2.default.existsSync(import_path2.default.join(tmpDir, "index.html"))) {
11369
- throw new Error(`extracted tarball for runtime ${version} is missing index.html`);
11412
+ async function updateToLatest(opts = {}) {
11413
+ product.ensureHome();
11414
+ const cdnOrigin = resolveCdnOrigin(opts.cdnOrigin);
11415
+ const channel = resolveChannel(opts.channel);
11416
+ const pin = resolvePin();
11417
+ if (pin) {
11418
+ const activeVersion2 = product.readActiveRuntime();
11419
+ const pinInstalled = import_node_fs4.default.existsSync(
11420
+ import_node_path3.default.join(product.runtimeDir(pin), product.installedMarker)
11421
+ );
11422
+ if (activeVersion2 === pin && pinInstalled) {
11423
+ return {
11424
+ checked: true,
11425
+ updated: false,
11426
+ reason: `runtime is pinned to ${pin}`,
11427
+ activeVersion: activeVersion2,
11428
+ latestVersion: pin
11429
+ };
11430
+ }
11431
+ const installed3 = await install({
11432
+ version: pin,
11433
+ channel,
11434
+ cdnOrigin,
11435
+ setActive: false
11436
+ });
11437
+ return {
11438
+ checked: true,
11439
+ updated: true,
11440
+ reason: `runtime is pinned to ${pin}`,
11441
+ activeVersion: pin,
11442
+ latestVersion: pin,
11443
+ install: installed3
11444
+ };
11370
11445
  }
11371
- import_fs2.default.rmSync(destDir, { recursive: true, force: true });
11372
- import_fs2.default.renameSync(tmpDir, destDir);
11373
- } catch (err) {
11374
- import_fs2.default.rmSync(tmpDir, { recursive: true, force: true });
11375
- throw err;
11376
- }
11377
- if (setActive) writeActiveRuntime(version);
11378
- return {
11379
- version,
11380
- channel,
11381
- cdnOrigin,
11382
- runtimeDir: destDir,
11383
- installed: true,
11384
- activated: setActive,
11385
- manifest
11386
- };
11387
- }
11388
- async function updateRuntimeToLatest(opts = {}) {
11389
- ensureSootsimHome();
11390
- const cdnOrigin = resolveRuntimeCdnOrigin(opts.cdnOrigin);
11391
- const channel = resolveRuntimeChannel(opts.channel);
11392
- const pin = resolveRuntimePin();
11393
- if (pin) {
11394
- const activeVersion2 = readActiveRuntime();
11395
- const pinInstalled = import_fs2.default.existsSync(import_path2.default.join(runtimeDir(pin), "index.html"));
11396
- if (activeVersion2 === pin && pinInstalled) {
11446
+ const manifest = await fetchManifest(cdnOrigin);
11447
+ const latestVersion = manifest.channels[channel]?.latest;
11448
+ if (!latestVersion) {
11397
11449
  return {
11398
11450
  checked: true,
11399
11451
  updated: false,
11400
- reason: `runtime is pinned to ${pin}`,
11401
- activeVersion: activeVersion2,
11402
- latestVersion: pin
11452
+ reason: `channel '${channel}' has no latest runtime`,
11453
+ activeVersion: product.readActiveRuntime()
11454
+ };
11455
+ }
11456
+ const entry = manifest.versions[latestVersion];
11457
+ if (!entry) {
11458
+ return {
11459
+ checked: true,
11460
+ updated: false,
11461
+ reason: `manifest is missing version ${latestVersion}`,
11462
+ activeVersion: product.readActiveRuntime(),
11463
+ latestVersion
11464
+ };
11465
+ }
11466
+ const activeVersion = product.readActiveRuntime();
11467
+ const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
11468
+ const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path3.default.join(activeDir, product.installedMarker)) : false;
11469
+ const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
11470
+ if (!shouldInstall) {
11471
+ return {
11472
+ checked: true,
11473
+ updated: false,
11474
+ reason: "active runtime is current",
11475
+ activeVersion,
11476
+ latestVersion
11403
11477
  };
11404
11478
  }
11405
- const install2 = await installRuntime({
11406
- version: pin,
11479
+ const installed2 = await install({
11480
+ version: latestVersion,
11407
11481
  channel,
11408
11482
  cdnOrigin,
11409
11483
  setActive: false
@@ -11411,57 +11485,40 @@ async function updateRuntimeToLatest(opts = {}) {
11411
11485
  return {
11412
11486
  checked: true,
11413
11487
  updated: true,
11414
- reason: `runtime is pinned to ${pin}`,
11415
- activeVersion: pin,
11416
- latestVersion: pin,
11417
- install: install2
11418
- };
11419
- }
11420
- const manifest = await fetchRuntimeManifest(cdnOrigin);
11421
- const latestVersion = manifest.channels[channel]?.latest;
11422
- if (!latestVersion) {
11423
- return {
11424
- checked: true,
11425
- updated: false,
11426
- reason: `channel '${channel}' has no latest runtime`,
11427
- activeVersion: readActiveRuntime()
11488
+ activeVersion: latestVersion,
11489
+ latestVersion,
11490
+ install: installed2
11428
11491
  };
11429
11492
  }
11430
- const entry = manifest.versions[latestVersion];
11431
- if (!entry) {
11432
- return {
11433
- checked: true,
11434
- updated: false,
11435
- reason: `manifest is missing version ${latestVersion}`,
11436
- activeVersion: readActiveRuntime(),
11437
- latestVersion
11438
- };
11439
- }
11440
- const activeVersion = readActiveRuntime();
11441
- const activeDir = activeVersion ? runtimeDir(activeVersion) : null;
11442
- const activeInstalled = activeDir ? import_fs2.default.existsSync(import_path2.default.join(activeDir, "index.html")) : false;
11443
- const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
11444
- if (!shouldInstall) {
11445
- return {
11446
- checked: true,
11447
- updated: false,
11448
- reason: "active runtime is current",
11449
- activeVersion,
11450
- latestVersion
11451
- };
11493
+ async function checkUpToDate(opts = {}) {
11494
+ const active = product.readActiveRuntime();
11495
+ const pinned = resolvePin();
11496
+ if (pinned) {
11497
+ return { active, latest: pinned, pinned, outdated: active !== pinned };
11498
+ }
11499
+ try {
11500
+ const manifest = await fetchManifest(resolveCdnOrigin(opts.cdnOrigin));
11501
+ const channel = resolveChannel(opts.channel);
11502
+ const latest = manifest.channels[channel]?.latest ?? null;
11503
+ const outdated = !!(latest && (!active || compareSemver(latest, active) > 0));
11504
+ return { active, latest, pinned: null, outdated };
11505
+ } catch {
11506
+ return { active, latest: null, pinned: null, outdated: false };
11507
+ }
11452
11508
  }
11453
- const install = await installRuntime({
11454
- version: latestVersion,
11455
- channel,
11456
- cdnOrigin,
11457
- setActive: false
11458
- });
11459
11509
  return {
11460
- checked: true,
11461
- updated: true,
11462
- activeVersion: latestVersion,
11463
- latestVersion,
11464
- install
11510
+ product,
11511
+ resolveCdnOrigin,
11512
+ resolveChannel,
11513
+ resolvePin,
11514
+ manifestUrl,
11515
+ tarballUrl,
11516
+ fetchManifest,
11517
+ resolveVersion,
11518
+ install,
11519
+ updateToLatest,
11520
+ checkUpToDate,
11521
+ listInstalled: () => listInstalledRuntimes(product)
11465
11522
  };
11466
11523
  }
11467
11524
  async function downloadToFile(url, destPath) {
@@ -11469,17 +11526,17 @@ async function downloadToFile(url, destPath) {
11469
11526
  if (!res.ok || !res.body) {
11470
11527
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
11471
11528
  }
11472
- import_fs2.default.mkdirSync(import_path2.default.dirname(destPath), { recursive: true });
11529
+ import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(destPath), { recursive: true });
11473
11530
  const tmp = `${destPath}.partial`;
11474
11531
  try {
11475
11532
  await (0, import_promises.pipeline)(
11476
- import_stream.Readable.fromWeb(res.body),
11477
- import_fs2.default.createWriteStream(tmp)
11533
+ import_node_stream.Readable.fromWeb(res.body),
11534
+ import_node_fs4.default.createWriteStream(tmp)
11478
11535
  );
11479
- import_fs2.default.renameSync(tmp, destPath);
11536
+ import_node_fs4.default.renameSync(tmp, destPath);
11480
11537
  } catch (err) {
11481
11538
  try {
11482
- import_fs2.default.unlinkSync(tmp);
11539
+ import_node_fs4.default.unlinkSync(tmp);
11483
11540
  } catch {
11484
11541
  }
11485
11542
  throw err;
@@ -11487,8 +11544,8 @@ async function downloadToFile(url, destPath) {
11487
11544
  }
11488
11545
  function sha256File(filePath) {
11489
11546
  return new Promise((resolve5, reject) => {
11490
- const hash = import_crypto.default.createHash("sha256");
11491
- const stream = import_fs2.default.createReadStream(filePath);
11547
+ const hash = import_node_crypto.default.createHash("sha256");
11548
+ const stream = import_node_fs4.default.createReadStream(filePath);
11492
11549
  stream.on("data", (chunk) => hash.update(chunk));
11493
11550
  stream.on("error", reject);
11494
11551
  stream.on("end", () => resolve5(hash.digest("hex")));
@@ -11496,7 +11553,7 @@ function sha256File(filePath) {
11496
11553
  }
11497
11554
  function extractTarball(tarPath, destDir) {
11498
11555
  return new Promise((resolve5, reject) => {
11499
- const child = (0, import_child_process2.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
11556
+ const child = (0, import_node_child_process2.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
11500
11557
  stdio: ["ignore", "inherit", "inherit"]
11501
11558
  });
11502
11559
  child.on("error", reject);
@@ -11506,21 +11563,52 @@ function extractTarball(tarPath, destDir) {
11506
11563
  });
11507
11564
  });
11508
11565
  }
11509
- 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, RUNTIME_PIN_ENV;
11566
+ var import_node_child_process2, import_node_crypto, import_node_fs4, import_node_path3, import_node_stream, import_promises;
11567
+ var init_src = __esm({
11568
+ "../contrast-runtime-delivery/src/index.ts"() {
11569
+ "use strict";
11570
+ import_node_child_process2 = require("node:child_process");
11571
+ import_node_crypto = __toESM(require("node:crypto"), 1);
11572
+ import_node_fs4 = __toESM(require("node:fs"), 1);
11573
+ import_node_path3 = __toESM(require("node:path"), 1);
11574
+ import_node_stream = require("node:stream");
11575
+ import_promises = require("node:stream/promises");
11576
+ init_product();
11577
+ init_product();
11578
+ }
11579
+ });
11580
+
11581
+ // src/runtime-delivery.ts
11582
+ var DEFAULT_RUNTIME_CDN_ORIGIN, SOOTSIM_RUNTIME_PRODUCT, sootsimRuntime;
11510
11583
  var init_runtime_delivery = __esm({
11511
11584
  "src/runtime-delivery.ts"() {
11512
11585
  "use strict";
11513
- import_child_process2 = require("child_process");
11514
- import_crypto = __toESM(require("crypto"), 1);
11515
- import_fs2 = __toESM(require("fs"), 1);
11516
- import_path2 = __toESM(require("path"), 1);
11517
- import_stream = require("stream");
11518
- import_promises = require("stream/promises");
11586
+ init_src();
11519
11587
  init_home_paths();
11520
11588
  DEFAULT_RUNTIME_CDN_ORIGIN = "https://contrast.dev";
11521
- RUNTIME_CDN_ORIGIN_ENV = "SOOTSIM_CDN_ORIGIN";
11522
- RUNTIME_CHANNEL_ENV = "SOOTSIM_RUNTIME_CHANNEL";
11523
- RUNTIME_PIN_ENV = "SOOTSIM_RUNTIME_VERSION";
11589
+ SOOTSIM_RUNTIME_PRODUCT = {
11590
+ id: "sootsim",
11591
+ defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
11592
+ manifestPath: "/runtimes/manifest.json",
11593
+ tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
11594
+ // the engine runtime is a static SPA: shell at the root, engine/ and
11595
+ // engine-tenant/ beneath it. index.html is what the daemon and the
11596
+ // vite/metro plugins serve, so its absence means the tarball is not one.
11597
+ installedMarker: "index.html",
11598
+ env: {
11599
+ cdnOrigin: "SOOTSIM_CDN_ORIGIN",
11600
+ channel: "SOOTSIM_RUNTIME_CHANNEL",
11601
+ pin: "SOOTSIM_RUNTIME_VERSION"
11602
+ },
11603
+ ensureHome: ensureSootsimHome,
11604
+ configFile: configFilePath,
11605
+ runtimesDir,
11606
+ runtimeDir,
11607
+ cacheDir,
11608
+ readActiveRuntime,
11609
+ writeActiveRuntime
11610
+ };
11611
+ sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT);
11524
11612
  }
11525
11613
  });
11526
11614
 
@@ -11585,7 +11673,7 @@ function getUserDataDir() {
11585
11673
  return userDataDir();
11586
11674
  }
11587
11675
  function storeFile() {
11588
- return import_node_path2.default.join(userDataDir(), "attached-projects.json");
11676
+ return import_node_path4.default.join(userDataDir(), "attached-projects.json");
11589
11677
  }
11590
11678
  function cloneEmpty() {
11591
11679
  return {
@@ -11599,7 +11687,7 @@ function loadStore() {
11599
11687
  const file = storeFile();
11600
11688
  let raw;
11601
11689
  try {
11602
- raw = import_node_fs3.default.readFileSync(file, "utf8");
11690
+ raw = import_node_fs5.default.readFileSync(file, "utf8");
11603
11691
  } catch (err) {
11604
11692
  if (err.code === "ENOENT") return cloneEmpty();
11605
11693
  throw err;
@@ -11616,7 +11704,7 @@ function loadStore() {
11616
11704
  } catch (err) {
11617
11705
  const quarantine = `${file}.corrupt-${Date.now()}`;
11618
11706
  try {
11619
- import_node_fs3.default.renameSync(file, quarantine);
11707
+ import_node_fs5.default.renameSync(file, quarantine);
11620
11708
  console.warn(
11621
11709
  `[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
11622
11710
  );
@@ -11627,16 +11715,16 @@ function loadStore() {
11627
11715
  }
11628
11716
  function writeStore(store) {
11629
11717
  const file = storeFile();
11630
- import_node_fs3.default.mkdirSync(import_node_path2.default.dirname(file), { recursive: true });
11718
+ import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
11631
11719
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
11632
- const fd = import_node_fs3.default.openSync(tmp, "w", 384);
11720
+ const fd = import_node_fs5.default.openSync(tmp, "w", 384);
11633
11721
  try {
11634
- import_node_fs3.default.writeFileSync(fd, JSON.stringify(store, null, 2));
11635
- import_node_fs3.default.fsyncSync(fd);
11722
+ import_node_fs5.default.writeFileSync(fd, JSON.stringify(store, null, 2));
11723
+ import_node_fs5.default.fsyncSync(fd);
11636
11724
  } finally {
11637
- import_node_fs3.default.closeSync(fd);
11725
+ import_node_fs5.default.closeSync(fd);
11638
11726
  }
11639
- import_node_fs3.default.renameSync(tmp, file);
11727
+ import_node_fs5.default.renameSync(tmp, file);
11640
11728
  }
11641
11729
  function mutateStore(fn) {
11642
11730
  const store = loadStore();
@@ -11645,13 +11733,13 @@ function mutateStore(fn) {
11645
11733
  return store;
11646
11734
  }
11647
11735
  function projectIdForCwd(cwd) {
11648
- return (0, import_node_crypto.createHash)("sha256").update(import_node_path2.default.resolve(cwd)).digest("hex").slice(0, 16);
11736
+ return (0, import_node_crypto2.createHash)("sha256").update(import_node_path4.default.resolve(cwd)).digest("hex").slice(0, 16);
11649
11737
  }
11650
11738
  function newSessionId() {
11651
- return `s_${(0, import_node_crypto.randomBytes)(10).toString("hex")}`;
11739
+ return `s_${(0, import_node_crypto2.randomBytes)(10).toString("hex")}`;
11652
11740
  }
11653
11741
  function upsertProject(input) {
11654
- const cwd = import_node_path2.default.resolve(input.cwd);
11742
+ const cwd = import_node_path4.default.resolve(input.cwd);
11655
11743
  const id = projectIdForCwd(cwd);
11656
11744
  let result;
11657
11745
  mutateStore((store) => {
@@ -11677,7 +11765,7 @@ function upsertProject(input) {
11677
11765
  const now = Date.now();
11678
11766
  const created = {
11679
11767
  id,
11680
- name: input.name ?? import_node_path2.default.basename(cwd),
11768
+ name: input.name ?? import_node_path4.default.basename(cwd),
11681
11769
  cwd,
11682
11770
  repoRoot: input.repoRoot,
11683
11771
  sourceRoots: input.sourceRoots ?? [cwd],
@@ -11806,8 +11894,8 @@ async function seedFromDemoAppRegistry() {
11806
11894
  if (apps.length === 0) return;
11807
11895
  mutateStore((store) => {
11808
11896
  for (const app of apps) {
11809
- if (!import_node_fs3.default.existsSync(app.dir)) continue;
11810
- const cwd = import_node_path2.default.resolve(app.dir);
11897
+ if (!import_node_fs5.default.existsSync(app.dir)) continue;
11898
+ const cwd = import_node_path4.default.resolve(app.dir);
11811
11899
  const id = projectIdForCwd(cwd);
11812
11900
  if (store.attachedProjects.some((p) => p.id === id)) continue;
11813
11901
  const now = Date.now();
@@ -11828,13 +11916,13 @@ async function seedFromDemoAppRegistry() {
11828
11916
  }
11829
11917
  });
11830
11918
  }
11831
- var import_node_crypto, import_node_fs3, import_node_path2, overrideDir, COST_HISTORY_MAX_AGE_MS;
11919
+ var import_node_crypto2, import_node_fs5, import_node_path4, overrideDir, COST_HISTORY_MAX_AGE_MS;
11832
11920
  var init_attached_projects = __esm({
11833
11921
  "src/attached-projects.ts"() {
11834
11922
  "use strict";
11835
- import_node_crypto = require("node:crypto");
11836
- import_node_fs3 = __toESM(require("node:fs"), 1);
11837
- import_node_path2 = __toESM(require("node:path"), 1);
11923
+ import_node_crypto2 = require("node:crypto");
11924
+ import_node_fs5 = __toESM(require("node:fs"), 1);
11925
+ import_node_path4 = __toESM(require("node:path"), 1);
11838
11926
  init_home_paths();
11839
11927
  overrideDir = null;
11840
11928
  COST_HISTORY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -11843,16 +11931,16 @@ var init_attached_projects = __esm({
11843
11931
 
11844
11932
  // src/agent-sessions.ts
11845
11933
  function sessionDir(sessionId) {
11846
- return import_node_path3.default.join(getUserDataDir(), "sessions", sessionId);
11934
+ return import_node_path5.default.join(getUserDataDir(), "sessions", sessionId);
11847
11935
  }
11848
11936
  function promptFifoPath(sessionId) {
11849
- return import_node_path3.default.join(sessionDir(sessionId), "prompt.in");
11937
+ return import_node_path5.default.join(sessionDir(sessionId), "prompt.in");
11850
11938
  }
11851
11939
  function eventsFifoPath(sessionId) {
11852
- return import_node_path3.default.join(sessionDir(sessionId), "events.out");
11940
+ return import_node_path5.default.join(sessionDir(sessionId), "events.out");
11853
11941
  }
11854
11942
  function transcriptPath(sessionId) {
11855
- return import_node_path3.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
11943
+ return import_node_path5.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
11856
11944
  }
11857
11945
  function pidIsAlive(pid, sessionId) {
11858
11946
  if (!pid) return false;
@@ -11862,7 +11950,7 @@ function pidIsAlive(pid, sessionId) {
11862
11950
  return false;
11863
11951
  }
11864
11952
  if (sessionId) {
11865
- if (!import_node_fs4.default.existsSync(sessionDir(sessionId))) return false;
11953
+ if (!import_node_fs6.default.existsSync(sessionDir(sessionId))) return false;
11866
11954
  }
11867
11955
  return true;
11868
11956
  }
@@ -11874,11 +11962,11 @@ function resolveSootsimInvocation() {
11874
11962
  const resourcesPath = process.resourcesPath;
11875
11963
  if (resourcesPath) {
11876
11964
  const candidates = [
11877
- import_node_path3.default.join(resourcesPath, "bin", "sootsim"),
11878
- import_node_path3.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
11965
+ import_node_path5.default.join(resourcesPath, "bin", "sootsim"),
11966
+ import_node_path5.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
11879
11967
  ];
11880
11968
  for (const c of candidates) {
11881
- if (import_node_fs4.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
11969
+ if (import_node_fs6.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
11882
11970
  }
11883
11971
  }
11884
11972
  }
@@ -11901,15 +11989,15 @@ function tryWorkspaceSootsim() {
11901
11989
  const sootsimDir = resolveSootsimPackageDir();
11902
11990
  if (!sootsimDir) return null;
11903
11991
  const binaryName = `sootsim-${process.platform}-${process.arch}`;
11904
- const distBinary = import_node_path3.default.join(sootsimDir, "dist-bin", binaryName);
11905
- if (import_node_fs4.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
11906
- const distBin = import_node_path3.default.join(sootsimDir, "dist-cli", "bin.js");
11907
- if (import_node_fs4.default.existsSync(distBin)) {
11992
+ const distBinary = import_node_path5.default.join(sootsimDir, "dist-bin", binaryName);
11993
+ if (import_node_fs6.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
11994
+ const distBin = import_node_path5.default.join(sootsimDir, "dist-cli", "bin.js");
11995
+ if (import_node_fs6.default.existsSync(distBin)) {
11908
11996
  try {
11909
- const src = import_node_path3.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
11910
- if (import_node_fs4.default.existsSync(src)) {
11911
- const srcMtime = import_node_fs4.default.statSync(src).mtimeMs;
11912
- const buildMtime = import_node_fs4.default.statSync(distBin).mtimeMs;
11997
+ const src = import_node_path5.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
11998
+ if (import_node_fs6.default.existsSync(src)) {
11999
+ const srcMtime = import_node_fs6.default.statSync(src).mtimeMs;
12000
+ const buildMtime = import_node_fs6.default.statSync(distBin).mtimeMs;
11913
12001
  if (buildMtime < srcMtime) {
11914
12002
  console.warn(
11915
12003
  `[sootsim] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/sootsim build:cli\`.`
@@ -11928,22 +12016,22 @@ function tryWorkspaceSootsim() {
11928
12016
  function resolveSootsimPackageDir() {
11929
12017
  try {
11930
12018
  const resolved = require.resolve("sootsim/package.json");
11931
- return import_node_path3.default.dirname(resolved);
12019
+ return import_node_path5.default.dirname(resolved);
11932
12020
  } catch {
11933
12021
  }
11934
12022
  const here = fileFromImportMeta();
11935
12023
  if (!here) return null;
11936
- let cur = import_node_path3.default.dirname(here);
12024
+ let cur = import_node_path5.default.dirname(here);
11937
12025
  for (let i = 0; i < 8; i++) {
11938
- const pkg = import_node_path3.default.join(cur, "package.json");
12026
+ const pkg = import_node_path5.default.join(cur, "package.json");
11939
12027
  try {
11940
- if (import_node_fs4.default.existsSync(pkg)) {
11941
- const parsed = JSON.parse(import_node_fs4.default.readFileSync(pkg, "utf8"));
12028
+ if (import_node_fs6.default.existsSync(pkg)) {
12029
+ const parsed = JSON.parse(import_node_fs6.default.readFileSync(pkg, "utf8"));
11942
12030
  if (parsed.name === "sootsim") return cur;
11943
12031
  }
11944
12032
  } catch {
11945
12033
  }
11946
- const parent = import_node_path3.default.dirname(cur);
12034
+ const parent = import_node_path5.default.dirname(cur);
11947
12035
  if (parent === cur) break;
11948
12036
  cur = parent;
11949
12037
  }
@@ -11959,28 +12047,28 @@ function fileFromImportMeta() {
11959
12047
  }
11960
12048
  }
11961
12049
  async function withStartLock(projectId, provider, fn) {
11962
- const lockDir = import_node_path3.default.join(getUserDataDir(), "locks");
11963
- import_node_fs4.default.mkdirSync(lockDir, { recursive: true });
12050
+ const lockDir = import_node_path5.default.join(getUserDataDir(), "locks");
12051
+ import_node_fs6.default.mkdirSync(lockDir, { recursive: true });
11964
12052
  try {
11965
- import_node_fs4.default.chmodSync(lockDir, 448);
12053
+ import_node_fs6.default.chmodSync(lockDir, 448);
11966
12054
  } catch {
11967
12055
  }
11968
- const lockPath = import_node_path3.default.join(lockDir, `start-${projectId}-${provider}.lock`);
12056
+ const lockPath = import_node_path5.default.join(lockDir, `start-${projectId}-${provider}.lock`);
11969
12057
  const deadline = Date.now() + 4e3;
11970
12058
  let fd = null;
11971
12059
  while (fd === null) {
11972
12060
  try {
11973
- fd = import_node_fs4.default.openSync(
12061
+ fd = import_node_fs6.default.openSync(
11974
12062
  lockPath,
11975
- import_node_fs4.constants.O_WRONLY | import_node_fs4.constants.O_CREAT | import_node_fs4.constants.O_EXCL,
12063
+ import_node_fs6.constants.O_WRONLY | import_node_fs6.constants.O_CREAT | import_node_fs6.constants.O_EXCL,
11976
12064
  384
11977
12065
  );
11978
12066
  } catch (err) {
11979
12067
  if (err.code !== "EEXIST") throw err;
11980
12068
  try {
11981
- const stale = Number(import_node_fs4.default.readFileSync(lockPath, "utf8").trim());
12069
+ const stale = Number(import_node_fs6.default.readFileSync(lockPath, "utf8").trim());
11982
12070
  if (stale && !isProcessAlive(stale)) {
11983
- import_node_fs4.default.unlinkSync(lockPath);
12071
+ import_node_fs6.default.unlinkSync(lockPath);
11984
12072
  continue;
11985
12073
  }
11986
12074
  } catch {
@@ -11994,15 +12082,15 @@ async function withStartLock(projectId, provider, fn) {
11994
12082
  }
11995
12083
  }
11996
12084
  try {
11997
- import_node_fs4.default.writeFileSync(fd, String(process.pid));
12085
+ import_node_fs6.default.writeFileSync(fd, String(process.pid));
11998
12086
  return await fn();
11999
12087
  } finally {
12000
12088
  try {
12001
- import_node_fs4.default.closeSync(fd);
12089
+ import_node_fs6.default.closeSync(fd);
12002
12090
  } catch {
12003
12091
  }
12004
12092
  try {
12005
- import_node_fs4.default.unlinkSync(lockPath);
12093
+ import_node_fs6.default.unlinkSync(lockPath);
12006
12094
  } catch {
12007
12095
  }
12008
12096
  }
@@ -12016,28 +12104,28 @@ function isProcessAlive(pid) {
12016
12104
  }
12017
12105
  }
12018
12106
  function mkfifoSync(p) {
12019
- const parent = import_node_path3.default.dirname(p);
12020
- import_node_fs4.default.mkdirSync(parent, { recursive: true });
12107
+ const parent = import_node_path5.default.dirname(p);
12108
+ import_node_fs6.default.mkdirSync(parent, { recursive: true });
12021
12109
  try {
12022
- import_node_fs4.default.chmodSync(parent, 448);
12110
+ import_node_fs6.default.chmodSync(parent, 448);
12023
12111
  } catch {
12024
12112
  }
12025
- if (import_node_fs4.default.existsSync(p)) {
12113
+ if (import_node_fs6.default.existsSync(p)) {
12026
12114
  try {
12027
- const stat = import_node_fs4.default.statSync(p);
12115
+ const stat = import_node_fs6.default.statSync(p);
12028
12116
  if (stat.isFIFO()) {
12029
12117
  try {
12030
- import_node_fs4.default.chmodSync(p, 384);
12118
+ import_node_fs6.default.chmodSync(p, 384);
12031
12119
  } catch {
12032
12120
  }
12033
12121
  return;
12034
12122
  }
12035
- import_node_fs4.default.unlinkSync(p);
12123
+ import_node_fs6.default.unlinkSync(p);
12036
12124
  } catch {
12037
- import_node_fs4.default.unlinkSync(p);
12125
+ import_node_fs6.default.unlinkSync(p);
12038
12126
  }
12039
12127
  }
12040
- const result = (0, import_node_child_process2.spawnSync)("mkfifo", ["-m", "600", p]);
12128
+ const result = (0, import_node_child_process3.spawnSync)("mkfifo", ["-m", "600", p]);
12041
12129
  if (result.status !== 0) {
12042
12130
  throw new Error(
12043
12131
  `mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
@@ -12060,7 +12148,7 @@ async function startSession(opts) {
12060
12148
  `session already running for project=${project.id} provider=${provider} (session ${existingLive.id}, pid ${existingLive.wrapperPid}). end it first with \`sootsim agent end <sessionId>\`.`
12061
12149
  );
12062
12150
  }
12063
- const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto2.randomUUID)() : void 0;
12151
+ const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto3.randomUUID)() : void 0;
12064
12152
  const session = upsertSession({
12065
12153
  projectId: project.id,
12066
12154
  provider,
@@ -12074,10 +12162,10 @@ async function startSession(opts) {
12074
12162
  const transcript = transcriptPath(session.id);
12075
12163
  mkfifoSync(promptIn);
12076
12164
  mkfifoSync(eventsOut);
12077
- const transcriptDir = import_node_path3.default.dirname(transcript);
12078
- import_node_fs4.default.mkdirSync(transcriptDir, { recursive: true });
12165
+ const transcriptDir = import_node_path5.default.dirname(transcript);
12166
+ import_node_fs6.default.mkdirSync(transcriptDir, { recursive: true });
12079
12167
  try {
12080
- import_node_fs4.default.chmodSync(transcriptDir, 448);
12168
+ import_node_fs6.default.chmodSync(transcriptDir, 448);
12081
12169
  } catch {
12082
12170
  }
12083
12171
  const { cmd, prefixArgs } = resolveSootsimInvocation();
@@ -12105,7 +12193,7 @@ async function startSession(opts) {
12105
12193
  if (claudeSessionUuid) {
12106
12194
  wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
12107
12195
  }
12108
- const child = (0, import_node_child_process2.spawn)(cmd, wrapperArgs, {
12196
+ const child = (0, import_node_child_process3.spawn)(cmd, wrapperArgs, {
12109
12197
  detached: true,
12110
12198
  stdio: "ignore",
12111
12199
  env: {
@@ -12128,7 +12216,7 @@ async function startSession(opts) {
12128
12216
  }
12129
12217
  }
12130
12218
  try {
12131
- import_node_fs4.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
12219
+ import_node_fs6.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
12132
12220
  } catch {
12133
12221
  }
12134
12222
  updateSessionStatus(session.id, { status: "ended" });
@@ -12156,18 +12244,18 @@ async function sendPrompt(sessionId, prompt) {
12156
12244
  );
12157
12245
  }
12158
12246
  const fifo = promptFifoPath(sessionId);
12159
- if (!import_node_fs4.default.existsSync(fifo)) {
12247
+ if (!import_node_fs6.default.existsSync(fifo)) {
12160
12248
  throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
12161
12249
  }
12162
- const fd = import_node_fs4.default.openSync(fifo, import_node_fs4.constants.O_WRONLY);
12250
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_WRONLY);
12163
12251
  try {
12164
12252
  const wireText = encodeAgentPromptEnvelope(prompt);
12165
12253
  if (!wireText) {
12166
12254
  throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
12167
12255
  }
12168
- import_node_fs4.default.writeSync(fd, wireText + "\n");
12256
+ import_node_fs6.default.writeSync(fd, wireText + "\n");
12169
12257
  } finally {
12170
- import_node_fs4.default.closeSync(fd);
12258
+ import_node_fs6.default.closeSync(fd);
12171
12259
  }
12172
12260
  updateSessionStatus(sessionId, {
12173
12261
  lastPrompt: prompt.displayText ?? prompt.text,
@@ -12189,7 +12277,7 @@ async function endSession(sessionId) {
12189
12277
  const base = getUserDataDir();
12190
12278
  if (dir.startsWith(base)) {
12191
12279
  try {
12192
- import_node_fs4.default.rmSync(dir, { recursive: true, force: true });
12280
+ import_node_fs6.default.rmSync(dir, { recursive: true, force: true });
12193
12281
  } catch {
12194
12282
  }
12195
12283
  }
@@ -12197,11 +12285,11 @@ async function endSession(sessionId) {
12197
12285
  }
12198
12286
  function subscribeEvents(sessionId, onEvent) {
12199
12287
  const fifo = eventsFifoPath(sessionId);
12200
- if (!import_node_fs4.default.existsSync(fifo)) {
12288
+ if (!import_node_fs6.default.existsSync(fifo)) {
12201
12289
  throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
12202
12290
  }
12203
- const fd = import_node_fs4.default.openSync(fifo, import_node_fs4.constants.O_RDWR);
12204
- const stream = import_node_fs4.default.createReadStream("", { fd, autoClose: true });
12291
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR);
12292
+ const stream = import_node_fs6.default.createReadStream("", { fd, autoClose: true });
12205
12293
  const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
12206
12294
  rl.on("line", (line) => {
12207
12295
  const event = parseAgentEventLine(line);
@@ -12222,7 +12310,7 @@ function subscribeEvents(sessionId, onEvent) {
12222
12310
  };
12223
12311
  }
12224
12312
  async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12225
- const fd = import_node_fs4.default.openSync(fifo, import_node_fs4.constants.O_RDWR | import_node_fs4.constants.O_NONBLOCK);
12313
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR | import_node_fs6.constants.O_NONBLOCK);
12226
12314
  const buf = Buffer.alloc(8192);
12227
12315
  let leftover = "";
12228
12316
  const deadline = Date.now() + timeoutMs;
@@ -12230,7 +12318,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12230
12318
  while (Date.now() < deadline) {
12231
12319
  let n = 0;
12232
12320
  try {
12233
- n = import_node_fs4.default.readSync(fd, buf, 0, buf.length, null);
12321
+ n = import_node_fs6.default.readSync(fd, buf, 0, buf.length, null);
12234
12322
  } catch (err) {
12235
12323
  if (err.code !== "EAGAIN") throw err;
12236
12324
  n = 0;
@@ -12250,17 +12338,17 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12250
12338
  }
12251
12339
  return null;
12252
12340
  } finally {
12253
- import_node_fs4.default.closeSync(fd);
12341
+ import_node_fs6.default.closeSync(fd);
12254
12342
  }
12255
12343
  }
12256
- var import_node_child_process2, import_node_crypto2, import_node_fs4, import_node_path3, import_node_readline, AgentSessionError;
12344
+ var import_node_child_process3, import_node_crypto3, import_node_fs6, import_node_path5, import_node_readline, AgentSessionError;
12257
12345
  var init_agent_sessions = __esm({
12258
12346
  "src/agent-sessions.ts"() {
12259
12347
  "use strict";
12260
- import_node_child_process2 = require("node:child_process");
12261
- import_node_crypto2 = require("node:crypto");
12262
- import_node_fs4 = __toESM(require("node:fs"), 1);
12263
- import_node_path3 = __toESM(require("node:path"), 1);
12348
+ import_node_child_process3 = require("node:child_process");
12349
+ import_node_crypto3 = require("node:crypto");
12350
+ import_node_fs6 = __toESM(require("node:fs"), 1);
12351
+ import_node_path5 = __toESM(require("node:path"), 1);
12264
12352
  import_node_readline = __toESM(require("node:readline"), 1);
12265
12353
  init_agent_events();
12266
12354
  init_agent_prompt();
@@ -12302,8 +12390,8 @@ function resolveAgentbusCommand(explicit) {
12302
12390
  if (fromArg) return fromArg;
12303
12391
  const fromEnv = process.env.AGENTBUS_COMMAND?.trim();
12304
12392
  if (fromEnv) return fromEnv;
12305
- const localBin = import_node_path4.default.join(import_node_os2.default.homedir(), ".local", "bin", "agentbus");
12306
- if (import_node_fs5.default.existsSync(localBin)) return localBin;
12393
+ const localBin = import_node_path6.default.join(import_node_os2.default.homedir(), ".local", "bin", "agentbus");
12394
+ if (import_node_fs7.default.existsSync(localBin)) return localBin;
12307
12395
  return "agentbus";
12308
12396
  }
12309
12397
  async function sendPromptToAgentbusSession(input) {
@@ -12318,7 +12406,7 @@ async function sendPromptToAgentbusSession(input) {
12318
12406
  const command = resolveAgentbusCommand(input.command);
12319
12407
  const timeoutMs = input.timeoutMs ?? 15e3;
12320
12408
  await new Promise((resolve5, reject) => {
12321
- const child = (0, import_node_child_process3.spawn)(command, ["send", sessionId, text], {
12409
+ const child = (0, import_node_child_process4.spawn)(command, ["send", sessionId, text], {
12322
12410
  stdio: ["ignore", "ignore", "pipe"],
12323
12411
  env: process.env
12324
12412
  });
@@ -12353,14 +12441,14 @@ async function sendPromptToAgentbusSession(input) {
12353
12441
  });
12354
12442
  });
12355
12443
  }
12356
- var import_node_child_process3, import_node_fs5, import_node_os2, import_node_path4;
12444
+ var import_node_child_process4, import_node_fs7, import_node_os2, import_node_path6;
12357
12445
  var init_agentbus_prompt = __esm({
12358
12446
  "src/agentbus-prompt.ts"() {
12359
12447
  "use strict";
12360
- import_node_child_process3 = require("node:child_process");
12361
- import_node_fs5 = __toESM(require("node:fs"), 1);
12448
+ import_node_child_process4 = require("node:child_process");
12449
+ import_node_fs7 = __toESM(require("node:fs"), 1);
12362
12450
  import_node_os2 = __toESM(require("node:os"), 1);
12363
- import_node_path4 = __toESM(require("node:path"), 1);
12451
+ import_node_path6 = __toESM(require("node:path"), 1);
12364
12452
  init_agent_identity();
12365
12453
  init_agent_identity();
12366
12454
  }
@@ -12379,12 +12467,12 @@ function mapFrameworkToProjectFramework(fw) {
12379
12467
  if (fw === "one" || fw === "vxrn") return "one";
12380
12468
  return "unknown";
12381
12469
  }
12382
- var import_node_fs6, import_node_path5, WS_OPEN, AgentHost;
12470
+ var import_node_fs8, import_node_path7, WS_OPEN, AgentHost;
12383
12471
  var init_agent_host = __esm({
12384
12472
  "src/host/agent-host.ts"() {
12385
12473
  "use strict";
12386
- import_node_fs6 = __toESM(require("node:fs"), 1);
12387
- import_node_path5 = __toESM(require("node:path"), 1);
12474
+ import_node_fs8 = __toESM(require("node:fs"), 1);
12475
+ import_node_path7 = __toESM(require("node:path"), 1);
12388
12476
  init_dev_server_scanner();
12389
12477
  init_agent_sessions();
12390
12478
  init_agentbus_prompt();
@@ -12571,7 +12659,7 @@ var init_agent_host = __esm({
12571
12659
  );
12572
12660
  const project = upsertProject({
12573
12661
  cwd: match.cwd,
12574
- name: match.projectName ?? import_node_path5.default.basename(match.cwd),
12662
+ name: match.projectName ?? import_node_path7.default.basename(match.cwd),
12575
12663
  preferredProvider: input.provider ?? existing?.preferredProvider,
12576
12664
  sourceRoots: existing?.sourceRoots ?? [match.cwd],
12577
12665
  knownBundleUrls,
@@ -12582,18 +12670,18 @@ var init_agent_host = __esm({
12582
12670
  }
12583
12671
  getTranscript(sessionId) {
12584
12672
  const p = transcriptPath(sessionId);
12585
- if (!import_node_fs6.default.existsSync(p)) {
12673
+ if (!import_node_fs8.default.existsSync(p)) {
12586
12674
  return { error: "transcript not found", code: "NO_TRANSCRIPT" };
12587
12675
  }
12588
- return import_node_fs6.default.readFileSync(p, "utf8");
12676
+ return import_node_fs8.default.readFileSync(p, "utf8");
12589
12677
  }
12590
12678
  getPaths() {
12591
12679
  const dir = getUserDataDir();
12592
12680
  return {
12593
12681
  userDataDir: dir,
12594
- storeFile: import_node_path5.default.join(dir, "attached-projects.json"),
12595
- sessionsDir: import_node_path5.default.join(dir, "sessions"),
12596
- transcriptsDir: import_node_path5.default.join(dir, "transcripts")
12682
+ storeFile: import_node_path7.default.join(dir, "attached-projects.json"),
12683
+ sessionsDir: import_node_path7.default.join(dir, "sessions"),
12684
+ transcriptsDir: import_node_path7.default.join(dir, "transcripts")
12597
12685
  };
12598
12686
  }
12599
12687
  // --- subscription management ---
@@ -13193,19 +13281,19 @@ var init_fetch_proxy_handler = __esm({
13193
13281
 
13194
13282
  // src/host/open-url.ts
13195
13283
  function expandHome(candidate) {
13196
- return candidate.startsWith("~/") ? (0, import_path3.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
13284
+ return candidate.startsWith("~/") ? (0, import_path2.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
13197
13285
  }
13198
13286
  function firstExisting(candidates) {
13199
13287
  for (const candidate of candidates) {
13200
13288
  const expanded = expandHome(candidate);
13201
- if ((0, import_fs3.existsSync)(expanded)) return expanded;
13289
+ if ((0, import_fs2.existsSync)(expanded)) return expanded;
13202
13290
  }
13203
13291
  return null;
13204
13292
  }
13205
13293
  function lookupExecutable(command, platform) {
13206
13294
  try {
13207
13295
  const tool = platform === "win32" ? "where" : "which";
13208
- const out = (0, import_child_process3.execFileSync)(tool, [command], {
13296
+ const out = (0, import_child_process2.execFileSync)(tool, [command], {
13209
13297
  encoding: "utf8",
13210
13298
  timeout: 1500,
13211
13299
  stdio: ["ignore", "pipe", "ignore"]
@@ -13217,7 +13305,7 @@ function lookupExecutable(command, platform) {
13217
13305
  }
13218
13306
  function resolveChromiumBinary(platform = process.platform) {
13219
13307
  const envCandidate = process.env.CHROME_PATH || process.env.CHROMIUM_PATH;
13220
- if (envCandidate && (0, import_fs3.existsSync)(envCandidate)) return envCandidate;
13308
+ if (envCandidate && (0, import_fs2.existsSync)(envCandidate)) return envCandidate;
13221
13309
  const direct = platform === "darwin" ? firstExisting(MAC_CHROMIUM_CANDIDATES) : platform === "win32" ? firstExisting(WINDOWS_CHROMIUM_CANDIDATES) : firstExisting(LINUX_CHROMIUM_CANDIDATES);
13222
13310
  if (direct) return direct;
13223
13311
  const commands = platform === "win32" ? WINDOWS_CHROMIUM_COMMANDS : UNIX_CHROMIUM_COMMANDS;
@@ -13274,7 +13362,7 @@ function buildChromiumUrlCommand(url, options = {}) {
13274
13362
  }
13275
13363
  async function spawnLaunch(command, args, detached) {
13276
13364
  return new Promise((resolve5, reject) => {
13277
- const child = (0, import_child_process3.spawn)(command, args, {
13365
+ const child = (0, import_child_process2.spawn)(command, args, {
13278
13366
  detached,
13279
13367
  stdio: "ignore"
13280
13368
  });
@@ -13297,14 +13385,14 @@ async function launchUrl(url, options = {}) {
13297
13385
  async function openUrl(url, options = {}) {
13298
13386
  await launchUrl(url, options);
13299
13387
  }
13300
- 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;
13388
+ var import_child_process2, import_fs2, import_os, import_path2, MAC_CHROMIUM_CANDIDATES, LINUX_CHROMIUM_CANDIDATES, WINDOWS_CHROMIUM_CANDIDATES, UNIX_CHROMIUM_COMMANDS, WINDOWS_CHROMIUM_COMMANDS;
13301
13389
  var init_open_url = __esm({
13302
13390
  "src/host/open-url.ts"() {
13303
13391
  "use strict";
13304
- import_child_process3 = require("child_process");
13305
- import_fs3 = require("fs");
13392
+ import_child_process2 = require("child_process");
13393
+ import_fs2 = require("fs");
13306
13394
  import_os = require("os");
13307
- import_path3 = require("path");
13395
+ import_path2 = require("path");
13308
13396
  MAC_CHROMIUM_CANDIDATES = [
13309
13397
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
13310
13398
  "~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -13566,14 +13654,14 @@ function unrefTimer(timer) {
13566
13654
  timer.unref();
13567
13655
  }
13568
13656
  }
13569
- 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;
13657
+ var import_child_process3, 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;
13570
13658
  var init_bridge_host = __esm({
13571
13659
  "src/host/bridge-host.ts"() {
13572
13660
  "use strict";
13573
- import_child_process4 = require("child_process");
13574
- import_fs4 = __toESM(require("fs"), 1);
13661
+ import_child_process3 = require("child_process");
13662
+ import_fs3 = __toESM(require("fs"), 1);
13575
13663
  import_http3 = require("http");
13576
- import_path4 = __toESM(require("path"), 1);
13664
+ import_path3 = __toESM(require("path"), 1);
13577
13665
  import_ws2 = require("ws");
13578
13666
  init_dev_server_scanner();
13579
13667
  init_bridge_constants();
@@ -13865,7 +13953,7 @@ var init_bridge_host = __esm({
13865
13953
  return;
13866
13954
  }
13867
13955
  if (msg.type === "runtime:list") {
13868
- const versions = listInstalledRuntimes();
13956
+ const versions = sootsimRuntime.listInstalled();
13869
13957
  const active = this.getActiveRuntime();
13870
13958
  const reply = {
13871
13959
  type: "runtime:list:ok",
@@ -13882,7 +13970,7 @@ var init_bridge_host = __esm({
13882
13970
  }
13883
13971
  if (msg.type === "runtime:use") {
13884
13972
  const version = typeof msg.version === "string" ? msg.version : "";
13885
- const installed2 = listInstalledRuntimes();
13973
+ const installed2 = sootsimRuntime.listInstalled();
13886
13974
  if (!installed2.includes(version)) {
13887
13975
  try {
13888
13976
  ws.send(
@@ -14411,7 +14499,7 @@ var init_bridge_host = __esm({
14411
14499
  if (reason === "startup") {
14412
14500
  process.stderr.write("sootsim: checking for runtime updates\u2026\n");
14413
14501
  }
14414
- const result = await updateRuntimeToLatest();
14502
+ const result = await sootsimRuntime.updateToLatest();
14415
14503
  if (!result.updated || !result.latestVersion) {
14416
14504
  if (reason === "startup") {
14417
14505
  process.stderr.write(
@@ -14647,34 +14735,34 @@ var init_bridge_host = __esm({
14647
14735
  return;
14648
14736
  }
14649
14737
  }
14650
- const resolved = import_path4.default.resolve(baseDir, "." + rel);
14651
- const baseWithSep = baseDir.endsWith(import_path4.default.sep) ? baseDir : baseDir + import_path4.default.sep;
14738
+ const resolved = import_path3.default.resolve(baseDir, "." + rel);
14739
+ const baseWithSep = baseDir.endsWith(import_path3.default.sep) ? baseDir : baseDir + import_path3.default.sep;
14652
14740
  if (!resolved.startsWith(baseWithSep) && resolved !== baseDir) {
14653
14741
  res.writeHead(403);
14654
14742
  res.end("forbidden");
14655
14743
  return;
14656
14744
  }
14657
- import_fs4.default.realpath(resolved, (realErr, realResolved) => {
14745
+ import_fs3.default.realpath(resolved, (realErr, realResolved) => {
14658
14746
  const servePath = realErr ? resolved : realResolved;
14659
- const servePathWithSep = servePath.endsWith(import_path4.default.sep) ? servePath : servePath + import_path4.default.sep;
14747
+ const servePathWithSep = servePath.endsWith(import_path3.default.sep) ? servePath : servePath + import_path3.default.sep;
14660
14748
  if (!realErr) {
14661
14749
  const realBaseWithSep = (() => {
14662
14750
  try {
14663
- const rb = import_fs4.default.realpathSync(baseDir);
14664
- return rb.endsWith(import_path4.default.sep) ? rb : rb + import_path4.default.sep;
14751
+ const rb = import_fs3.default.realpathSync(baseDir);
14752
+ return rb.endsWith(import_path3.default.sep) ? rb : rb + import_path3.default.sep;
14665
14753
  } catch {
14666
14754
  return baseWithSep;
14667
14755
  }
14668
14756
  })();
14669
- if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path4.default.sep !== realBaseWithSep) {
14757
+ if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path3.default.sep !== realBaseWithSep) {
14670
14758
  res.writeHead(403);
14671
14759
  res.end("forbidden");
14672
14760
  return;
14673
14761
  }
14674
14762
  }
14675
- import_fs4.default.stat(servePath, (err, stats) => {
14763
+ import_fs3.default.stat(servePath, (err, stats) => {
14676
14764
  if (err || !stats?.isFile()) {
14677
- const ext2 = import_path4.default.extname(rel).toLowerCase();
14765
+ const ext2 = import_path3.default.extname(rel).toLowerCase();
14678
14766
  if (ext2 && ext2 !== ".html") {
14679
14767
  res.writeHead(404);
14680
14768
  res.end("not found");
@@ -14685,8 +14773,8 @@ var init_bridge_host = __esm({
14685
14773
  res.end("not found");
14686
14774
  return;
14687
14775
  }
14688
- const indexPath = import_path4.default.join(baseDir, "index.html");
14689
- import_fs4.default.readFile(indexPath, (err2, data) => {
14776
+ const indexPath = import_path3.default.join(baseDir, "index.html");
14777
+ import_fs3.default.readFile(indexPath, (err2, data) => {
14690
14778
  if (err2) {
14691
14779
  res.writeHead(404);
14692
14780
  res.end("not found");
@@ -14706,7 +14794,7 @@ var init_bridge_host = __esm({
14706
14794
  });
14707
14795
  return;
14708
14796
  }
14709
- const ext = import_path4.default.extname(servePath).toLowerCase();
14797
+ const ext = import_path3.default.extname(servePath).toLowerCase();
14710
14798
  const contentType = HTTP_MIME_TYPES[ext] || "application/octet-stream";
14711
14799
  res.writeHead(200, {
14712
14800
  "Content-Type": contentType,
@@ -14717,7 +14805,7 @@ var init_bridge_host = __esm({
14717
14805
  return;
14718
14806
  }
14719
14807
  if (ext === ".html") {
14720
- import_fs4.default.readFile(servePath, (readErr, data) => {
14808
+ import_fs3.default.readFile(servePath, (readErr, data) => {
14721
14809
  if (readErr) {
14722
14810
  try {
14723
14811
  res.end();
@@ -14731,7 +14819,7 @@ var init_bridge_host = __esm({
14731
14819
  });
14732
14820
  return;
14733
14821
  }
14734
- const stream = import_fs4.default.createReadStream(servePath);
14822
+ const stream = import_fs3.default.createReadStream(servePath);
14735
14823
  stream.pipe(res);
14736
14824
  stream.on("error", () => {
14737
14825
  try {
@@ -14937,7 +15025,7 @@ var init_bridge_host = __esm({
14937
15025
  const target = `${filePath}${loc}`;
14938
15026
  const trySpawn = (cmd, args) => new Promise((resolve5) => {
14939
15027
  try {
14940
- const child = (0, import_child_process4.spawn)(cmd, args, { detached: true, stdio: "ignore" });
15028
+ const child = (0, import_child_process3.spawn)(cmd, args, { detached: true, stdio: "ignore" });
14941
15029
  let settled = false;
14942
15030
  child.on("error", () => {
14943
15031
  if (settled) return;
@@ -15439,7 +15527,7 @@ function buildComm() {
15439
15527
  if (process.platform === "linux") {
15440
15528
  return (pid) => {
15441
15529
  try {
15442
- return (0, import_fs5.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
15530
+ return (0, import_fs4.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
15443
15531
  } catch {
15444
15532
  return null;
15445
15533
  }
@@ -15468,7 +15556,7 @@ function build() {
15468
15556
  function buildLinux() {
15469
15557
  return (pid) => {
15470
15558
  try {
15471
- const raw = (0, import_fs5.readFileSync)(`/proc/${pid}/stat`, "utf8");
15559
+ const raw = (0, import_fs4.readFileSync)(`/proc/${pid}/stat`, "utf8");
15472
15560
  const end = raw.lastIndexOf(")");
15473
15561
  if (end < 0) return null;
15474
15562
  const rest = raw.slice(end + 1).trim().split(/\s+/);
@@ -15532,7 +15620,7 @@ function tryBuildDarwinCommFfi() {
15532
15620
  function buildDarwinLsofComm() {
15533
15621
  return (pid) => {
15534
15622
  try {
15535
- const out = (0, import_child_process5.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15623
+ const out = (0, import_child_process4.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15536
15624
  encoding: "utf8",
15537
15625
  timeout: 2e3,
15538
15626
  stdio: ["ignore", "pipe", "ignore"]
@@ -15549,7 +15637,7 @@ function buildDarwinLsofComm() {
15549
15637
  function buildDarwinLsof() {
15550
15638
  return (pid) => {
15551
15639
  try {
15552
- const out = (0, import_child_process5.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15640
+ const out = (0, import_child_process4.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15553
15641
  encoding: "utf8",
15554
15642
  timeout: 2e3,
15555
15643
  stdio: ["ignore", "pipe", "ignore"]
@@ -15564,12 +15652,12 @@ function buildDarwinLsof() {
15564
15652
  }
15565
15653
  };
15566
15654
  }
15567
- var import_child_process5, import_fs5, import_module, cached3, cachedComm, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET, PBI_COMM_OFFSET, PBI_COMM_LEN;
15655
+ var import_child_process4, import_fs4, import_module, cached3, cachedComm, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET, PBI_COMM_OFFSET, PBI_COMM_LEN;
15568
15656
  var init_parent_pid = __esm({
15569
15657
  "cli/parent-pid.ts"() {
15570
15658
  "use strict";
15571
- import_child_process5 = require("child_process");
15572
- import_fs5 = require("fs");
15659
+ import_child_process4 = require("child_process");
15660
+ import_fs4 = require("fs");
15573
15661
  import_module = require("module");
15574
15662
  cached3 = null;
15575
15663
  cachedComm = null;
@@ -15614,18 +15702,18 @@ function getCliIdentityKey() {
15614
15702
  }
15615
15703
  function getCurrentSimPath() {
15616
15704
  if (process.env[CURRENT_SIM_PATH_ENV]) {
15617
- return (0, import_path5.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
15705
+ return (0, import_path4.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
15618
15706
  }
15619
15707
  const key = getCliIdentityKey();
15620
- return (0, import_path5.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
15708
+ return (0, import_path4.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
15621
15709
  }
15622
15710
  function readCurrentSim() {
15623
15711
  const filepath = getCurrentSimPath();
15624
- if (!(0, import_fs6.existsSync)(filepath)) return null;
15712
+ if (!(0, import_fs5.existsSync)(filepath)) return null;
15625
15713
  try {
15626
- const parsed = JSON.parse((0, import_fs6.readFileSync)(filepath, "utf8"));
15714
+ const parsed = JSON.parse((0, import_fs5.readFileSync)(filepath, "utf8"));
15627
15715
  if (parsed.version !== CURRENT_SIM_VERSION || typeof parsed.simId !== "string" || !parsed.simId.trim() || typeof parsed.updatedAt !== "string") {
15628
- (0, import_fs6.rmSync)(filepath, { force: true });
15716
+ (0, import_fs5.rmSync)(filepath, { force: true });
15629
15717
  return null;
15630
15718
  }
15631
15719
  return {
@@ -15634,7 +15722,7 @@ function readCurrentSim() {
15634
15722
  updatedAt: parsed.updatedAt
15635
15723
  };
15636
15724
  } catch {
15637
- (0, import_fs6.rmSync)(filepath, { force: true });
15725
+ (0, import_fs5.rmSync)(filepath, { force: true });
15638
15726
  return null;
15639
15727
  }
15640
15728
  }
@@ -15642,15 +15730,15 @@ function readCurrentSimId() {
15642
15730
  return readCurrentSim()?.simId || null;
15643
15731
  }
15644
15732
  function clearCurrentSimId() {
15645
- (0, import_fs6.rmSync)(getCurrentSimPath(), { force: true });
15733
+ (0, import_fs5.rmSync)(getCurrentSimPath(), { force: true });
15646
15734
  }
15647
- var import_fs6, import_os2, import_path5, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE;
15735
+ var import_fs5, import_os2, import_path4, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE;
15648
15736
  var init_current_sim = __esm({
15649
15737
  "cli/current-sim.ts"() {
15650
15738
  "use strict";
15651
- import_fs6 = require("fs");
15739
+ import_fs5 = require("fs");
15652
15740
  import_os2 = require("os");
15653
- import_path5 = require("path");
15741
+ import_path4 = require("path");
15654
15742
  init_parent_pid();
15655
15743
  CURRENT_SIM_VERSION = 1;
15656
15744
  CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
@@ -16091,11 +16179,11 @@ async function evalInBridge(bridge, code, opts = {}) {
16091
16179
  if (opts.acquireLock) payload.acquireLock = true;
16092
16180
  return bridge.send(payload);
16093
16181
  }
16094
- async function callInBridge(bridge, path11, ...args) {
16095
- return bridge.send({ type: "call", path: path11, args });
16182
+ async function callInBridge(bridge, path12, ...args) {
16183
+ return bridge.send({ type: "call", path: path12, args });
16096
16184
  }
16097
- async function callInBridgeWrite(bridge, path11, ...args) {
16098
- return bridge.send({ type: "call", path: path11, args, acquireLock: true });
16185
+ async function callInBridgeWrite(bridge, path12, ...args) {
16186
+ return bridge.send({ type: "call", path: path12, args, acquireLock: true });
16099
16187
  }
16100
16188
  var import_ws3, resolvedWorld, BridgeSimLockedError;
16101
16189
  var init_ws_bridge = __esm({
@@ -17091,7 +17179,7 @@ function executeSyncHttp(url, method, params) {
17091
17179
  delete childEnv[key];
17092
17180
  }
17093
17181
  }
17094
- const child = (0, import_child_process6.spawnSync)(process.execPath, ["-e", HTTP_CHILD_SRC], {
17182
+ const child = (0, import_child_process5.spawnSync)(process.execPath, ["-e", HTTP_CHILD_SRC], {
17095
17183
  input: JSON.stringify({ url, method, headers: params?.headers, body: params?.body }),
17096
17184
  encoding: "utf8",
17097
17185
  timeout: HTTP_TIMEOUT_MS,
@@ -17138,11 +17226,11 @@ function scriptConditionIsTruthy(value) {
17138
17226
  if (!Number.isNaN(num) && num === 0) return false;
17139
17227
  return true;
17140
17228
  }
17141
- var import_child_process6, vm, HTTP_TIMEOUT_MS, HTTP_CHILD_SRC, TEMPLATE_RE, ESCAPED_TEMPLATE_RE, BARE_IDENTIFIER_RE, MaestroJsContext;
17229
+ var import_child_process5, vm, HTTP_TIMEOUT_MS, HTTP_CHILD_SRC, TEMPLATE_RE, ESCAPED_TEMPLATE_RE, BARE_IDENTIFIER_RE, MaestroJsContext;
17142
17230
  var init_maestro_js = __esm({
17143
17231
  "cli/maestro-js.ts"() {
17144
17232
  "use strict";
17145
- import_child_process6 = require("child_process");
17233
+ import_child_process5 = require("child_process");
17146
17234
  vm = __toESM(require("vm"), 1);
17147
17235
  HTTP_TIMEOUT_MS = 3e5;
17148
17236
  HTTP_CHILD_SRC = `
@@ -17322,14 +17410,14 @@ process.stdin.on('end', async () => {
17322
17410
  function getBaseDir() {
17323
17411
  const explicit = process.env[SESSION_FILE_ENV];
17324
17412
  if (explicit?.trim()) {
17325
- return (0, import_node_path6.dirname)((0, import_node_path6.resolve)(explicit));
17413
+ return (0, import_node_path8.dirname)((0, import_node_path8.resolve)(explicit));
17326
17414
  }
17327
17415
  return electronUserDataDir();
17328
17416
  }
17329
17417
  function getSharedDesktopAuthFilePath() {
17330
17418
  const explicit = process.env[SESSION_FILE_ENV];
17331
- if (explicit?.trim()) return (0, import_node_path6.resolve)(explicit);
17332
- return (0, import_node_path6.join)(getBaseDir(), "desktop-auth.json");
17419
+ if (explicit?.trim()) return (0, import_node_path8.resolve)(explicit);
17420
+ return (0, import_node_path8.join)(getBaseDir(), "desktop-auth.json");
17333
17421
  }
17334
17422
  function normalizeUser(input) {
17335
17423
  if (!input || typeof input !== "object") return null;
@@ -17375,26 +17463,26 @@ function normalizeSession(input) {
17375
17463
  }
17376
17464
  function readSharedDesktopAuthSession() {
17377
17465
  const filepath = getSharedDesktopAuthFilePath();
17378
- if (!(0, import_node_fs7.existsSync)(filepath)) return null;
17466
+ if (!(0, import_node_fs9.existsSync)(filepath)) return null;
17379
17467
  try {
17380
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(filepath, "utf8"));
17468
+ const parsed = JSON.parse((0, import_node_fs9.readFileSync)(filepath, "utf8"));
17381
17469
  const normalized = normalizeSession(parsed);
17382
17470
  if (!normalized) {
17383
- (0, import_node_fs7.rmSync)(filepath, { force: true });
17471
+ (0, import_node_fs9.rmSync)(filepath, { force: true });
17384
17472
  return null;
17385
17473
  }
17386
17474
  return normalized;
17387
17475
  } catch {
17388
- (0, import_node_fs7.rmSync)(filepath, { force: true });
17476
+ (0, import_node_fs9.rmSync)(filepath, { force: true });
17389
17477
  return null;
17390
17478
  }
17391
17479
  }
17392
- var import_node_fs7, import_node_path6, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
17480
+ var import_node_fs9, import_node_path8, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
17393
17481
  var init_shared_session = __esm({
17394
17482
  "src/auth/shared-session.ts"() {
17395
17483
  "use strict";
17396
- import_node_fs7 = require("node:fs");
17397
- import_node_path6 = require("node:path");
17484
+ import_node_fs9 = require("node:fs");
17485
+ import_node_path8 = require("node:path");
17398
17486
  init_home_paths();
17399
17487
  SESSION_VERSION = 1;
17400
17488
  SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
@@ -17670,16 +17758,16 @@ function resolveFlowScreenshotPath(screenshotDir, name) {
17670
17758
  }
17671
17759
  function resolveProjectRelativeFlowBase(flowDir) {
17672
17760
  if (!flowDir) return process.cwd();
17673
- return path9.basename(flowDir) === ".maestro" ? path9.dirname(flowDir) : flowDir;
17761
+ return path10.basename(flowDir) === ".maestro" ? path10.dirname(flowDir) : flowDir;
17674
17762
  }
17675
17763
  function resolveFlowScreenshotPathWithMode(screenshotDir, name, opts) {
17676
17764
  const normalizedName = name.endsWith(".png") ? name : `${name}.png`;
17677
- if (path9.isAbsolute(normalizedName)) return normalizedName;
17765
+ if (path10.isAbsolute(normalizedName)) return normalizedName;
17678
17766
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
17679
17767
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
17680
- return path9.resolve(baseDir, normalizedName);
17768
+ return path10.resolve(baseDir, normalizedName);
17681
17769
  }
17682
- return path9.join(screenshotDir, normalizedName);
17770
+ return path10.join(screenshotDir, normalizedName);
17683
17771
  }
17684
17772
  function normalizeFlowScreenshotSpec(step) {
17685
17773
  if (typeof step === "string") {
@@ -17736,12 +17824,12 @@ function parseFlowSteps(content) {
17736
17824
  const parsed = import_yaml.default.parse(candidate);
17737
17825
  return Array.isArray(parsed) ? parsed : [];
17738
17826
  }
17739
- var fs9, path9, import_settings2, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
17827
+ var fs10, path10, import_settings2, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
17740
17828
  var init_bridge_flow_runner = __esm({
17741
17829
  "cli/bridge-flow-runner.ts"() {
17742
17830
  "use strict";
17743
- fs9 = __toESM(require("fs"), 1);
17744
- path9 = __toESM(require("path"), 1);
17831
+ fs10 = __toESM(require("fs"), 1);
17832
+ path10 = __toESM(require("path"), 1);
17745
17833
  import_settings2 = require("sootsim-engine/settings");
17746
17834
  import_yaml = __toESM(require("yaml"), 1);
17747
17835
  init_frame_compose();
@@ -18029,14 +18117,14 @@ var init_bridge_flow_runner = __esm({
18029
18117
  if (chunks.length === 0) {
18030
18118
  throw new Error("recording requested but no video buffer was produced");
18031
18119
  }
18032
- fs9.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
18120
+ fs10.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
18033
18121
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
18034
18122
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
18035
- const outputPath = path9.join(
18123
+ const outputPath = path10.join(
18036
18124
  this.opts.recordingOutputDir,
18037
18125
  `sootsim-${Date.now()}.${extension}`
18038
18126
  );
18039
- fs9.writeFileSync(outputPath, Buffer.concat(chunks));
18127
+ fs10.writeFileSync(outputPath, Buffer.concat(chunks));
18040
18128
  return outputPath;
18041
18129
  }
18042
18130
  async waitForRecordingTail(opts) {
@@ -18545,7 +18633,7 @@ var init_bridge_flow_runner = __esm({
18545
18633
  flowDir: this.opts.flowDir
18546
18634
  }
18547
18635
  );
18548
- fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
18636
+ fs10.mkdirSync(path10.dirname(outputPath), { recursive: true });
18549
18637
  const layers = spec.layers ?? this.opts.screenshotLayers;
18550
18638
  const screenshotRequest = {
18551
18639
  type: "screenshot",
@@ -18561,11 +18649,11 @@ var init_bridge_flow_runner = __esm({
18561
18649
  throw new Error("could not read current device model for framed screenshot");
18562
18650
  }
18563
18651
  const framed = await composeFramedScreenshot(rawBuffer, model);
18564
- fs9.writeFileSync(outputPath, framed);
18652
+ fs10.writeFileSync(outputPath, framed);
18565
18653
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
18566
18654
  return outputPath;
18567
18655
  }
18568
- fs9.writeFileSync(outputPath, rawBuffer);
18656
+ fs10.writeFileSync(outputPath, rawBuffer);
18569
18657
  console.log(`[flow] screenshot: ${outputPath}`);
18570
18658
  return outputPath;
18571
18659
  }
@@ -18581,22 +18669,22 @@ var init_bridge_flow_runner = __esm({
18581
18669
  return model;
18582
18670
  }
18583
18671
  async captureScreenshot(outputPath) {
18584
- fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
18672
+ fs10.mkdirSync(path10.dirname(outputPath), { recursive: true });
18585
18673
  const dataUrl = await this.bridge.send({
18586
18674
  type: "screenshot",
18587
18675
  simId: this.opts.simId
18588
18676
  });
18589
18677
  const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
18590
- fs9.writeFileSync(outputPath, Buffer.from(base64, "base64"));
18678
+ fs10.writeFileSync(outputPath, Buffer.from(base64, "base64"));
18591
18679
  }
18592
18680
  // writes a per-failure debug bundle: screenshot + structured describe
18593
18681
  // + a11y tree + console errors/warnings + failed network requests +
18594
18682
  // shell state, all under one directory so post-mortem is one grep away.
18595
18683
  async captureFailureBundle(outputDir, context) {
18596
- fs9.mkdirSync(outputDir, { recursive: true });
18684
+ fs10.mkdirSync(outputDir, { recursive: true });
18597
18685
  const write = (name, content) => {
18598
18686
  try {
18599
- fs9.writeFileSync(path9.join(outputDir, name), content);
18687
+ fs10.writeFileSync(path10.join(outputDir, name), content);
18600
18688
  } catch {
18601
18689
  }
18602
18690
  };
@@ -19138,8 +19226,8 @@ var init_bridge_flow_runner = __esm({
19138
19226
  runScript(target) {
19139
19227
  const spec = typeof target === "string" ? { file: target } : target;
19140
19228
  if (!spec.file) throw new Error("runScript requires a file");
19141
- const scriptPath = path9.resolve(this.opts.flowDir, spec.file);
19142
- const source = fs9.readFileSync(scriptPath, "utf8");
19229
+ const scriptPath = path10.resolve(this.opts.flowDir, spec.file);
19230
+ const source = fs10.readFileSync(scriptPath, "utf8");
19143
19231
  this.js.evaluate(source, { env: spec.env });
19144
19232
  console.log(`[flow] runScript: ${spec.file} done`);
19145
19233
  }
@@ -19433,10 +19521,10 @@ var init_bridge_flow_runner = __esm({
19433
19521
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
19434
19522
  }
19435
19523
  if (file) {
19436
- const flowPath = path9.resolve(this.opts.flowDir, file);
19437
- const flowContent = fs9.readFileSync(flowPath, "utf8");
19524
+ const flowPath = path10.resolve(this.opts.flowDir, file);
19525
+ const flowContent = fs10.readFileSync(flowPath, "utf8");
19438
19526
  const previousDir = this.opts.flowDir;
19439
- this.opts.flowDir = path9.dirname(flowPath);
19527
+ this.opts.flowDir = path10.dirname(flowPath);
19440
19528
  try {
19441
19529
  await this.runFlow(parseFlowSteps(flowContent));
19442
19530
  } finally {
@@ -19591,8 +19679,8 @@ __export(registry_exports, {
19591
19679
  skillRegistry: () => skillRegistry
19592
19680
  });
19593
19681
  module.exports = __toCommonJS(registry_exports);
19594
- var fs10 = __toESM(require("fs"), 1);
19595
- var path10 = __toESM(require("path"), 1);
19682
+ var fs11 = __toESM(require("fs"), 1);
19683
+ var path11 = __toESM(require("path"), 1);
19596
19684
 
19597
19685
  // src/skills/builtin/a11y-review.ts
19598
19686
  init_reap_browser();
@@ -19611,8 +19699,8 @@ var skill = {
19611
19699
  },
19612
19700
  async execute(params, context) {
19613
19701
  const { chromium } = await import("playwright");
19614
- const path11 = await import("path");
19615
- const fs11 = await import("fs");
19702
+ const path12 = await import("path");
19703
+ const fs12 = await import("fs");
19616
19704
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19617
19705
  headless: true
19618
19706
  });
@@ -19667,9 +19755,9 @@ var skill = {
19667
19755
  warnings: issues.filter((i) => i.severity === "warning").length,
19668
19756
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
19669
19757
  };
19670
- const reportPath = path11.join(context.outputDir, "a11y-report.json");
19671
- fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
19672
- fs11.writeFileSync(reportPath, JSON.stringify(report, null, 2));
19758
+ const reportPath = path12.join(context.outputDir, "a11y-report.json");
19759
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
19760
+ fs12.writeFileSync(reportPath, JSON.stringify(report, null, 2));
19673
19761
  return {
19674
19762
  success: issues.filter((i) => i.severity === "error").length === 0,
19675
19763
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -19707,8 +19795,8 @@ var skill2 = {
19707
19795
  }
19708
19796
  },
19709
19797
  async execute(params, context) {
19710
- const fs11 = await import("fs");
19711
- const path11 = await import("path");
19798
+ const fs12 = await import("fs");
19799
+ const path12 = await import("path");
19712
19800
  const { POLYFILL_REGISTRY: POLYFILL_REGISTRY2 } = await Promise.resolve().then(() => (init_web(), web_exports));
19713
19801
  if (params.packageName) {
19714
19802
  const entry = POLYFILL_REGISTRY2[params.packageName];
@@ -19726,11 +19814,11 @@ var skill2 = {
19726
19814
  data: { package: params.packageName, status, ...entry }
19727
19815
  };
19728
19816
  }
19729
- const pkgPath = path11.join(context.projectDir, "package.json");
19730
- if (!fs11.existsSync(pkgPath)) {
19817
+ const pkgPath = path12.join(context.projectDir, "package.json");
19818
+ if (!fs12.existsSync(pkgPath)) {
19731
19819
  return { success: false, message: "No package.json found" };
19732
19820
  }
19733
- const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
19821
+ const pkg = JSON.parse(fs12.readFileSync(pkgPath, "utf8"));
19734
19822
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
19735
19823
  const results = {
19736
19824
  full: [],
@@ -19748,9 +19836,9 @@ var skill2 = {
19748
19836
  results.unknown.push(dep);
19749
19837
  }
19750
19838
  }
19751
- const reportPath = path11.join(context.outputDir, "compat-report.json");
19752
- fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
19753
- fs11.writeFileSync(reportPath, JSON.stringify(results, null, 2));
19839
+ const reportPath = path12.join(context.outputDir, "compat-report.json");
19840
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
19841
+ fs12.writeFileSync(reportPath, JSON.stringify(results, null, 2));
19754
19842
  return {
19755
19843
  success: results.unsupported.length === 0,
19756
19844
  message: `${results.full.length} full, ${results.partial.length} partial, ${results.unsupported.length} unsupported, ${results.unknown.length} unknown`,
@@ -19788,8 +19876,8 @@ var skill3 = {
19788
19876
  record: { type: "boolean", description: "Record video of the flow" }
19789
19877
  },
19790
19878
  async execute(params, context) {
19791
- const fs11 = await import("fs");
19792
- const path11 = await import("path");
19879
+ const fs12 = await import("fs");
19880
+ const path12 = await import("path");
19793
19881
  const yaml2 = await import("yaml");
19794
19882
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
19795
19883
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -19798,7 +19886,7 @@ var skill3 = {
19798
19886
  const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
19799
19887
  host.start({ silent: true });
19800
19888
  try {
19801
- const flowContent = fs11.readFileSync(params.flowPath, "utf8");
19889
+ const flowContent = fs12.readFileSync(params.flowPath, "utf8");
19802
19890
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
19803
19891
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
19804
19892
  const steps = yaml2.parse(stepsBody);
@@ -19823,7 +19911,7 @@ var skill3 = {
19823
19911
  });
19824
19912
  const driver = new SootSimBridgeFlowRunner2(bridge, {
19825
19913
  screenshotDir: context.outputDir,
19826
- flowDir: path11.dirname(path11.resolve(params.flowPath)),
19914
+ flowDir: path12.dirname(path12.resolve(params.flowPath)),
19827
19915
  simId,
19828
19916
  recordingOutputDir: params.record ? context.outputDir : void 0
19829
19917
  });
@@ -19845,7 +19933,7 @@ var skill3 = {
19845
19933
  simId,
19846
19934
  videoPath: videoPath || void 0
19847
19935
  },
19848
- artifacts: videoPath ? [{ type: "video", name: path11.basename(videoPath), path: videoPath }] : void 0
19936
+ artifacts: videoPath ? [{ type: "video", name: path12.basename(videoPath), path: videoPath }] : void 0
19849
19937
  };
19850
19938
  } finally {
19851
19939
  try {
@@ -19892,8 +19980,8 @@ var skill4 = {
19892
19980
  },
19893
19981
  async execute(params, context) {
19894
19982
  const { chromium } = await import("playwright");
19895
- const path11 = await import("path");
19896
- const fs11 = await import("fs");
19983
+ const path12 = await import("path");
19984
+ const fs12 = await import("fs");
19897
19985
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19898
19986
  headless: true
19899
19987
  });
@@ -19919,9 +20007,9 @@ var skill4 = {
19919
20007
  ...profile,
19920
20008
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
19921
20009
  };
19922
- const reportPath = path11.join(context.outputDir, "perf-report.json");
19923
- fs11.mkdirSync(path11.dirname(reportPath), { recursive: true });
19924
- fs11.writeFileSync(reportPath, JSON.stringify(report, null, 2));
20010
+ const reportPath = path12.join(context.outputDir, "perf-report.json");
20011
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
20012
+ fs12.writeFileSync(reportPath, JSON.stringify(report, null, 2));
19925
20013
  return {
19926
20014
  success: true,
19927
20015
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -19954,8 +20042,8 @@ var skill5 = {
19954
20042
  },
19955
20043
  async execute(params, context) {
19956
20044
  const { chromium } = await import("playwright");
19957
- const path11 = await import("path");
19958
- const fs11 = await import("fs");
20045
+ const path12 = await import("path");
20046
+ const fs12 = await import("fs");
19959
20047
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19960
20048
  headless: true
19961
20049
  });
@@ -19963,8 +20051,8 @@ var skill5 = {
19963
20051
  try {
19964
20052
  await page.goto(context.url, { waitUntil: "networkidle" });
19965
20053
  await page.waitForTimeout(2e3);
19966
- const outputPath = path11.join(context.outputDir, `${params.name}.png`);
19967
- fs11.mkdirSync(path11.dirname(outputPath), { recursive: true });
20054
+ const outputPath = path12.join(context.outputDir, `${params.name}.png`);
20055
+ fs12.mkdirSync(path12.dirname(outputPath), { recursive: true });
19968
20056
  await page.screenshot({ path: outputPath });
19969
20057
  return {
19970
20058
  success: true,
@@ -20005,8 +20093,8 @@ var skill6 = {
20005
20093
  },
20006
20094
  async execute(params, context) {
20007
20095
  const { chromium } = await import("playwright");
20008
- const path11 = await import("path");
20009
- const fs11 = await import("fs");
20096
+ const path12 = await import("path");
20097
+ const fs12 = await import("fs");
20010
20098
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
20011
20099
  headless: true
20012
20100
  });
@@ -20014,14 +20102,14 @@ var skill6 = {
20014
20102
  try {
20015
20103
  await page.goto(context.url, { waitUntil: "networkidle" });
20016
20104
  await page.waitForTimeout(2e3);
20017
- const currentPath = path11.join(context.outputDir, `${params.name}-current.png`);
20018
- fs11.mkdirSync(path11.dirname(currentPath), { recursive: true });
20105
+ const currentPath = path12.join(context.outputDir, `${params.name}-current.png`);
20106
+ fs12.mkdirSync(path12.dirname(currentPath), { recursive: true });
20019
20107
  await page.screenshot({ path: currentPath });
20020
20108
  try {
20021
20109
  const { PNG } = await import("pngjs");
20022
20110
  const pixelmatch = (await import("pixelmatch")).default;
20023
- const baseline = PNG.sync.read(fs11.readFileSync(params.baseline));
20024
- const current = PNG.sync.read(fs11.readFileSync(currentPath));
20111
+ const baseline = PNG.sync.read(fs12.readFileSync(params.baseline));
20112
+ const current = PNG.sync.read(fs12.readFileSync(currentPath));
20025
20113
  const { width, height } = baseline;
20026
20114
  const diff = new PNG({ width, height });
20027
20115
  const numDiffPixels = pixelmatch(
@@ -20032,8 +20120,8 @@ var skill6 = {
20032
20120
  height,
20033
20121
  { threshold: params.threshold || 0.1 }
20034
20122
  );
20035
- const diffPath = path11.join(context.outputDir, `${params.name}-diff.png`);
20036
- fs11.writeFileSync(diffPath, PNG.sync.write(diff));
20123
+ const diffPath = path12.join(context.outputDir, `${params.name}-diff.png`);
20124
+ fs12.writeFileSync(diffPath, PNG.sync.write(diff));
20037
20125
  const totalPixels = width * height;
20038
20126
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
20039
20127
  return {
@@ -20097,10 +20185,10 @@ var skillRegistry = {
20097
20185
  },
20098
20186
  // load skills from a project manifest (sootsim-skills.json)
20099
20187
  async loadFromManifest(projectDir) {
20100
- const manifestPath = path10.join(projectDir, "sootsim-skills.json");
20101
- if (!fs10.existsSync(manifestPath)) return;
20188
+ const manifestPath = path11.join(projectDir, "sootsim-skills.json");
20189
+ if (!fs11.existsSync(manifestPath)) return;
20102
20190
  try {
20103
- const manifest = JSON.parse(fs10.readFileSync(manifestPath, "utf8"));
20191
+ const manifest = JSON.parse(fs11.readFileSync(manifestPath, "utf8"));
20104
20192
  if (Array.isArray(manifest.skills)) {
20105
20193
  for (const entry of manifest.skills) {
20106
20194
  if (typeof entry === "string") {
@@ -20111,7 +20199,7 @@ var skillRegistry = {
20111
20199
  }
20112
20200
  } else if (entry.file) {
20113
20201
  try {
20114
- const mod = await import(path10.resolve(projectDir, entry.file));
20202
+ const mod = await import(path11.resolve(projectDir, entry.file));
20115
20203
  if (mod.skill) this.register(mod.skill);
20116
20204
  } catch {
20117
20205
  }
@@ -20124,10 +20212,10 @@ var skillRegistry = {
20124
20212
  // auto-discover skills based on project dependencies
20125
20213
  suggestSkills(projectDir) {
20126
20214
  const suggestions = [];
20127
- const pkgPath = path10.join(projectDir, "package.json");
20128
- if (!fs10.existsSync(pkgPath)) return suggestions;
20215
+ const pkgPath = path11.join(projectDir, "package.json");
20216
+ if (!fs11.existsSync(pkgPath)) return suggestions;
20129
20217
  try {
20130
- const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf8"));
20218
+ const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
20131
20219
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
20132
20220
  if (deps["detox"] || deps["maestro"]) {
20133
20221
  suggestions.push("maestro-test");