sootsim 0.1.250 → 0.1.252

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 (151) hide show
  1. package/README.md +8 -5
  2. package/dist-cli/bin.js +4 -4
  3. package/dist-cli/chunks/{agent-JPKDUK4P.js → agent-JRN5KS75.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-Z64YICSQ.js → agent-wrapper-2ZH2WQ2L.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-524IXHZF.js → app-fonts-LBQ7A7LL.js} +2 -2
  6. package/dist-cli/chunks/{assert-WZRU7L2S.js → assert-XFQCRREO.js} +2 -2
  7. package/dist-cli/chunks/{auth-3ZPMASCJ.js → auth-DAMRQQ53.js} +2 -2
  8. package/dist-cli/chunks/beta-JJ4YSCOE.js +2 -0
  9. package/dist-cli/chunks/{camera-FPGFHVAE.js → camera-NQWFOHXI.js} +2 -2
  10. package/dist-cli/chunks/chunk-25FMG2DR.js +1 -0
  11. package/dist-cli/chunks/{chunk-ZFJZLRAG.js → chunk-4P7EXY3Q.js} +2 -2
  12. package/dist-cli/chunks/{chunk-JMJJJQ3N.js → chunk-54RVP6DQ.js} +1 -1
  13. package/dist-cli/chunks/{chunk-ODXX3PDC.js → chunk-56CSO42W.js} +2 -2
  14. package/dist-cli/chunks/{chunk-7SDQP3K6.js → chunk-5PVVFMLA.js} +2 -2
  15. package/dist-cli/chunks/{chunk-LFRFK56L.js → chunk-677KF26C.js} +1 -1
  16. package/dist-cli/chunks/{chunk-ZBAOOQ7L.js → chunk-AJVA4XFD.js} +2 -2
  17. package/dist-cli/chunks/{chunk-OOYVCERU.js → chunk-BU4QJGYM.js} +2 -2
  18. package/dist-cli/chunks/{chunk-LCEWHXGT.js → chunk-F2DZ3EHN.js} +2 -2
  19. package/dist-cli/chunks/chunk-F7NVK7U5.js +29 -0
  20. package/dist-cli/chunks/{chunk-GVEBFN3A.js → chunk-FCNI6ZWQ.js} +2 -2
  21. package/dist-cli/chunks/{chunk-7CESRUUF.js → chunk-GBJS3QVL.js} +2 -2
  22. package/dist-cli/chunks/{chunk-RDQ4RP2I.js → chunk-GPECMCCD.js} +2 -2
  23. package/dist-cli/chunks/{chunk-HQVZVJWB.js → chunk-GRPNPAFQ.js} +1 -1
  24. package/dist-cli/chunks/{chunk-EJQGI6U6.js → chunk-HERRSHL3.js} +2 -2
  25. package/dist-cli/chunks/{chunk-QQDVBF5C.js → chunk-HNYCB3ZY.js} +1 -1
  26. package/dist-cli/chunks/chunk-HV773SED.js +4 -0
  27. package/dist-cli/chunks/{chunk-DOOM7A5G.js → chunk-J4XJHPJV.js} +2 -2
  28. package/dist-cli/chunks/{chunk-TIWQBBA6.js → chunk-JYJ37QKN.js} +2 -2
  29. package/dist-cli/chunks/chunk-K5UURTEB.js +1 -0
  30. package/dist-cli/chunks/{chunk-AV734IPM.js → chunk-LHAUZJH5.js} +1 -1
  31. package/dist-cli/chunks/{chunk-XBWJ7DPK.js → chunk-LL7KIGNG.js} +2 -2
  32. package/dist-cli/chunks/{chunk-HTGCR74O.js → chunk-LXRPMNYD.js} +2 -2
  33. package/dist-cli/chunks/{chunk-2FGQSNTC.js → chunk-LYIN47A5.js} +2 -2
  34. package/dist-cli/chunks/{chunk-Q72PZST6.js → chunk-MJU6KNLI.js} +3 -3
  35. package/dist-cli/chunks/{chunk-23DV2XSE.js → chunk-MMCNYDBD.js} +1 -1
  36. package/dist-cli/chunks/{chunk-G2QKQWCY.js → chunk-NADQK2CU.js} +1 -1
  37. package/dist-cli/chunks/{chunk-N52AECUU.js → chunk-NB6RTLLI.js} +3 -3
  38. package/dist-cli/chunks/{chunk-S5ILN4OM.js → chunk-NNEUAQME.js} +3 -3
  39. package/dist-cli/chunks/{chunk-RMP6YTMJ.js → chunk-NTZYSZ3Q.js} +2 -2
  40. package/dist-cli/chunks/{chunk-AWT2ISDX.js → chunk-NYKHYDBN.js} +1 -1
  41. package/dist-cli/chunks/{chunk-7WCUYHR3.js → chunk-OSPFE643.js} +1 -1
  42. package/dist-cli/chunks/{chunk-DX6CUGUF.js → chunk-PLK4SCBY.js} +2 -2
  43. package/dist-cli/chunks/{chunk-HLDQHWK5.js → chunk-PVDPE5BH.js} +1 -1
  44. package/dist-cli/chunks/{chunk-L5VG4RQT.js → chunk-QHNYUT7D.js} +1 -1
  45. package/dist-cli/chunks/{chunk-ZA4K47LA.js → chunk-S6DIPG7L.js} +2 -2
  46. package/dist-cli/chunks/{chunk-YACJ3KQ4.js → chunk-T2BJFGBC.js} +1 -1
  47. package/dist-cli/chunks/{chunk-CJMASJXU.js → chunk-TDWFR6H5.js} +2 -2
  48. package/dist-cli/chunks/{chunk-COON6LFC.js → chunk-U5JMZPBD.js} +1 -1
  49. package/dist-cli/chunks/{chunk-N6WXF6OS.js → chunk-UA5FVOEO.js} +1 -1
  50. package/dist-cli/chunks/chunk-UVE2LY6V.js +7 -0
  51. package/dist-cli/chunks/{chunk-GHJRRNR3.js → chunk-WS3DDBN3.js} +1 -1
  52. package/dist-cli/chunks/{chunk-KZZFQRPX.js → chunk-X2IKDV5A.js} +1 -1
  53. package/dist-cli/chunks/{chunk-GXNJSLZM.js → chunk-ZKN7GCX4.js} +2 -2
  54. package/dist-cli/chunks/cli-version-OZF5OMW4.js +2 -0
  55. package/dist-cli/chunks/{compat-C3N6PFK5.js → compat-ME4QWRZ6.js} +3 -3
  56. package/dist-cli/chunks/{config-UVEGEV7N.js → config-TMMSBXDV.js} +2 -2
  57. package/dist-cli/chunks/{control-ROSEFQH3.js → control-QGYYWKJP.js} +2 -2
  58. package/dist-cli/chunks/daemon-6NBHEVXS.js +2 -0
  59. package/dist-cli/chunks/{debug-VLB6FCUL.js → debug-LFJ46Q45.js} +3 -3
  60. package/dist-cli/chunks/{desktop-LAPJ2XXG.js → desktop-W5GPU7JA.js} +3 -3
  61. package/dist-cli/chunks/{detox-UKRIYJBM.js → detox-U3B3N3K7.js} +2 -2
  62. package/dist-cli/chunks/{device-HABOB4FC.js → device-I2WVQFXL.js} +2 -2
  63. package/dist-cli/chunks/{diagnose-TPTVALBD.js → diagnose-6TQOA4QJ.js} +2 -2
  64. package/dist-cli/chunks/drivers-5J25VDIG.js +2 -0
  65. package/dist-cli/chunks/{film-RZABTGXV.js → film-P5E64XQH.js} +3 -3
  66. package/dist-cli/chunks/flow-LD6MOZQC.js +2 -0
  67. package/dist-cli/chunks/help-VCWJZBQU.js +2 -0
  68. package/dist-cli/chunks/{hidden-runtime-alias-AITHRBI5.js → hidden-runtime-alias-ICP5W4W5.js} +2 -2
  69. package/dist-cli/chunks/home-paths-MCD3DISJ.js +2 -0
  70. package/dist-cli/chunks/inspect-VF575AD3.js +2 -0
  71. package/dist-cli/chunks/install-desktop-Q4Y6FTSA.js +2 -0
  72. package/dist-cli/chunks/{login-LIPDXOLT.js → login-A5LRYTNO.js} +4 -4
  73. package/dist-cli/chunks/{logout-7TCXGQM4.js → logout-M3HFZGFU.js} +2 -2
  74. package/dist-cli/chunks/{maestro-CQRCUEZJ.js → maestro-HNREOYXF.js} +3 -3
  75. package/dist-cli/chunks/{maestro-generate-TBBDRYEU.js → maestro-generate-BEEDUOOJ.js} +3 -3
  76. package/dist-cli/chunks/{mode-Z7E6YZTJ.js → mode-IBFHS3G2.js} +2 -2
  77. package/dist-cli/chunks/optional-demo-registry-6XYQJXI5.js +2 -0
  78. package/dist-cli/chunks/{perf-OS7TTPQ2.js → perf-62BD5VIU.js} +2 -2
  79. package/dist-cli/chunks/{record-YH22UVU2.js → record-2ILPO4XB.js} +3 -3
  80. package/dist-cli/chunks/runtime-WCDQFR7G.js +2 -0
  81. package/dist-cli/chunks/{screenshot-command-DV35HE24.js → screenshot-command-YZR5KVV2.js} +3 -3
  82. package/dist-cli/chunks/{screenshots-capture-OV6RMSA2.js → screenshots-capture-QHQ43OBD.js} +2 -2
  83. package/dist-cli/chunks/{serve-WTZRYS6X.js → serve-GQ4PUD5P.js} +15 -15
  84. package/dist-cli/chunks/{setup-AQ46RLHL.js → setup-C74I2RO3.js} +3 -3
  85. package/dist-cli/chunks/{skills-P6P5L7CV.js → skills-I7EVR3MU.js} +2 -2
  86. package/dist-cli/chunks/{storage-PIHIVEBL.js → storage-CH6BAYB4.js} +2 -2
  87. package/dist-cli/chunks/store-PTQ4QMFA.js +2 -0
  88. package/dist-cli/chunks/telemetry-AJDAGOFX.js +2 -0
  89. package/dist-cli/chunks/{timeline-334MEYTC.js → timeline-FUS7F5LI.js} +2 -2
  90. package/dist-cli/chunks/{upgrade-UVEGTAME.js → upgrade-DHMZFD5R.js} +4 -4
  91. package/dist-cli/chunks/upload-XJXPQMKX.js +2 -0
  92. package/dist-cli/chunks/version-M2GSAVKM.js +4 -0
  93. package/dist-cli/chunks/web-NV7UM2T7.js +2 -0
  94. package/dist-cli/chunks/{what-happened-3UH7ZQW6.js → what-happened-VRDDXQWR.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 +396 -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 +517 -437
  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 +32 -377
  131. package/dist-cli/chunks/beta-BBI3GYZ6.js +0 -2
  132. package/dist-cli/chunks/chunk-2UGQF7XX.js +0 -4
  133. package/dist-cli/chunks/chunk-J3XNJTO5.js +0 -1
  134. package/dist-cli/chunks/chunk-M7NRJV7O.js +0 -1
  135. package/dist-cli/chunks/chunk-PZR5U4RD.js +0 -29
  136. package/dist-cli/chunks/chunk-TJBXFUCI.js +0 -7
  137. package/dist-cli/chunks/cli-version-GWSUBSWJ.js +0 -2
  138. package/dist-cli/chunks/daemon-NVFYFCWX.js +0 -2
  139. package/dist-cli/chunks/drivers-ZUD4PX2W.js +0 -2
  140. package/dist-cli/chunks/flow-NHVT35XI.js +0 -2
  141. package/dist-cli/chunks/help-CM77GYXU.js +0 -2
  142. package/dist-cli/chunks/home-paths-XIHGBDLL.js +0 -2
  143. package/dist-cli/chunks/inspect-2WK43KRH.js +0 -2
  144. package/dist-cli/chunks/install-desktop-TS2RBWU5.js +0 -2
  145. package/dist-cli/chunks/optional-demo-registry-ANMKFJWS.js +0 -2
  146. package/dist-cli/chunks/runtime-WYDPR5RI.js +0 -2
  147. package/dist-cli/chunks/store-SVTB7QDS.js +0 -2
  148. package/dist-cli/chunks/telemetry-HM3ULN5U.js +0 -2
  149. package/dist-cli/chunks/upload-BIEPTIMK.js +0 -2
  150. package/dist-cli/chunks/version-VITMYQHS.js +0 -4
  151. package/dist-cli/chunks/web-G5IDDAAI.js +0 -2
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.250 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.252 | (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;
@@ -2896,8 +2896,8 @@ var init_registry = __esm({
2896
2896
  range: ">=0.1.0",
2897
2897
  coverage: 0.92,
2898
2898
  note: "real canvaskit-wasm backing via the engine instance (`globalThis.__sootsimCanvasKit`); declarative <Canvas> snapshots each commit through an offscreen SkSurface and mounts the encoded PNG as a host image. zero second canvaskit bundle.",
2899
- working: "<Canvas> with offscreen SkSurface paint\u2192PNG\u2192host <Image>, <Path>/<Rect>/<RoundedRect>/<Circle>/<Oval>/<Line>/<Fill>/<Image>/<Text>/<Group> primitives, <LinearGradient>/<RadialGradient>/<SweepGradient>/<ColorShader> paint shaders, <BlurMask>/<Blur>/<Mask>/<Shadow> mask + image filters, <BackdropFilter>/<BackdropBlur>, <DashPathEffect>/<DiscretePathEffect>/<CornerPathEffect>, Skia.Path/Paint/Color/Shader/MaskFilter/ImageFilter/ColorFilter/Font/Typeface/FontMgr factories, Skia.MakeImageFromEncoded, Skia.XYWHRect/LTRBRect/RRectXY/Point/Matrix, useImage (fetches+decodes through canvaskit), useFont (loads typeface from ArrayBuffer / URL), useFonts (matchFamilyStyle), useCanvasRef + ref.makeImageSnapshot, useValue/useDerivedValue/useComputedValue/useValueEffect/useClockValue listener model, BlendMode/StrokeCap/StrokeJoin/FillType/PaintStyle/TileMode/BlurStyle/FontWeight/FontStyle/FontSlant/FontWidth/ClipOp/PathVerb/PathOp/TextAlign/TextDirection enums.",
2900
- missing: "<RuntimeShader> SkSL compilation+uniform-binding pipeline, <Points>/<TextPath>/<Glyphs>/<ImageSVG>/<Vertices>/<Patch>/<Atlas>/<Picture>/<FitBox>/<Box>/<BoxShadow> (each logs a one-time hint and renders null), <Paint> as a declarative component, useTouchHandler full gesture state machine (we forward a minimal touch handler shape; consumers should use Pressable wrappers for hit-testing), reanimated worklet-driven canvas redraws (`useSharedValueEffect` subscribes only to the local SkiaValue listener shape; Canvas display-list encoding and setTick/setDataUrl updates remain owned by React useLayoutEffect, so redraws still reconcile through React), Skia.ParagraphBuilder full layout (we keep measurement-only semantics matching the previous stub; for pixel-perfect skia paragraphs apps should wait on the upstream JsiSkParagraphBuilder adapter), Skia.SVG.MakeFromString (canvaskit-wasm omits svg parsing in the size-tuned builds we ship), GPU SkSurface backing on offscreen paints (we use software MakeSurface so each Canvas paint runs on cpu; deferred until a real engine host element owns its own GrDirectContext for paint-only animation)."
2899
+ working: "<Canvas> with offscreen SkSurface paint\u2192PNG\u2192host <Image>, <Path>/<Rect>/<RoundedRect>/<Circle>/<Oval>/<Line>/<Fill>/<Image>/<Text>/<Picture>/<Group> primitives, shared-value group transforms, rect/rrect group clipping, <LinearGradient>/<RadialGradient>/<SweepGradient>/<ColorShader> paint shaders, <BlurMask>/<Blur>/<Mask>/<Shadow> mask + image filters, <BackdropFilter>/<BackdropBlur>, <DashPathEffect>/<DiscretePathEffect>/<CornerPathEffect>, Skia.Path/Paint/Color/Shader/MaskFilter/ImageFilter/ColorFilter/Font/Typeface/FontMgr factories, Skia.MakeImageFromEncoded, Skia.XYWHRect/LTRBRect/RRectXY/Point/Matrix, useImage (fetches+decodes through canvaskit), useFont (loads typeface from ArrayBuffer / URL), useFonts (URL, module, and Metro asset-id sources with matchFamilyStyle), useCanvasRef + ref.makeImageSnapshot, useValue/useDerivedValue/useComputedValue/useValueEffect/useClockValue listener model, BlendMode/StrokeCap/StrokeJoin/FillType/PaintStyle/TileMode/BlurStyle/FontWeight/FontStyle/FontSlant/FontWidth/ClipOp/PathVerb/PathOp/TextAlign/TextDirection enums.",
2900
+ missing: "<RuntimeShader> SkSL compilation+uniform-binding pipeline, <Points>/<TextPath>/<Glyphs>/<ImageSVG>/<Vertices>/<Patch>/<Atlas>/<FitBox>/<Box>/<BoxShadow> (each logs a one-time hint and renders null), path-shaped group clipping, <Paint> as a declarative component, useTouchHandler full gesture state machine (we forward a minimal touch handler shape; consumers should use Pressable wrappers for hit-testing), reanimated worklet-driven canvas redraws (`useSharedValueEffect` subscribes only to the local SkiaValue listener shape; Canvas display-list encoding and setTick/setDataUrl updates remain owned by React useLayoutEffect, so redraws still reconcile through React), Skia.ParagraphBuilder full layout (we keep measurement-only semantics matching the previous stub; for pixel-perfect skia paragraphs apps should wait on the upstream JsiSkParagraphBuilder adapter), Skia.SVG.MakeFromString (canvaskit-wasm omits svg parsing in the size-tuned builds we ship), GPU SkSurface backing on offscreen paints (we use software MakeSurface so each Canvas paint runs on cpu; deferred until a real engine host element owns its own GrDirectContext for paint-only animation)."
2901
2901
  }
2902
2902
  ]
2903
2903
  },
@@ -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,237 @@ 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();
11254
+ function runtimeTarballCacheName(product, version) {
11255
+ return import_node_path2.default.posix.basename(product.tarballPath(version));
11302
11256
  }
11303
- function runtimeTarballUrl(version, cdnOrigin) {
11304
- return `${resolveRuntimeCdnOrigin(cdnOrigin)}/runtimes/sootsim-runtime-${version}.tar.gz`;
11305
- }
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, "index.html"))) {
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, "index.html"))) {
11391
+ throw new Error(`extracted tarball for runtime ${version} is missing index.html`);
11392
+ }
11393
+ import_node_fs4.default.rmSync(destDir, { recursive: true, force: true });
11394
+ import_node_fs4.default.renameSync(tmpDir, destDir);
11395
+ } catch (err) {
11396
+ import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
11397
+ throw err;
11398
+ }
11399
+ if (setActive) product.writeActiveRuntime(version);
11339
11400
  return {
11340
11401
  version,
11341
11402
  channel,
11342
11403
  cdnOrigin,
11343
11404
  runtimeDir: destDir,
11344
- installed: false,
11405
+ installed: true,
11345
11406
  activated: setActive,
11346
11407
  manifest
11347
11408
  };
11348
11409
  }
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`);
11410
+ async function updateToLatest(opts = {}) {
11411
+ product.ensureHome();
11412
+ const cdnOrigin = resolveCdnOrigin(opts.cdnOrigin);
11413
+ const channel = resolveChannel(opts.channel);
11414
+ const pin = resolvePin();
11415
+ if (pin) {
11416
+ const activeVersion2 = product.readActiveRuntime();
11417
+ const pinInstalled = import_node_fs4.default.existsSync(import_node_path3.default.join(product.runtimeDir(pin), "index.html"));
11418
+ if (activeVersion2 === pin && pinInstalled) {
11419
+ return {
11420
+ checked: true,
11421
+ updated: false,
11422
+ reason: `runtime is pinned to ${pin}`,
11423
+ activeVersion: activeVersion2,
11424
+ latestVersion: pin
11425
+ };
11426
+ }
11427
+ const installed3 = await install({
11428
+ version: pin,
11429
+ channel,
11430
+ cdnOrigin,
11431
+ setActive: false
11432
+ });
11433
+ return {
11434
+ checked: true,
11435
+ updated: true,
11436
+ reason: `runtime is pinned to ${pin}`,
11437
+ activeVersion: pin,
11438
+ latestVersion: pin,
11439
+ install: installed3
11440
+ };
11370
11441
  }
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) {
11442
+ const manifest = await fetchManifest(cdnOrigin);
11443
+ const latestVersion = manifest.channels[channel]?.latest;
11444
+ if (!latestVersion) {
11397
11445
  return {
11398
11446
  checked: true,
11399
11447
  updated: false,
11400
- reason: `runtime is pinned to ${pin}`,
11401
- activeVersion: activeVersion2,
11402
- latestVersion: pin
11448
+ reason: `channel '${channel}' has no latest runtime`,
11449
+ activeVersion: product.readActiveRuntime()
11450
+ };
11451
+ }
11452
+ const entry = manifest.versions[latestVersion];
11453
+ if (!entry) {
11454
+ return {
11455
+ checked: true,
11456
+ updated: false,
11457
+ reason: `manifest is missing version ${latestVersion}`,
11458
+ activeVersion: product.readActiveRuntime(),
11459
+ latestVersion
11460
+ };
11461
+ }
11462
+ const activeVersion = product.readActiveRuntime();
11463
+ const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
11464
+ const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path3.default.join(activeDir, "index.html")) : false;
11465
+ const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
11466
+ if (!shouldInstall) {
11467
+ return {
11468
+ checked: true,
11469
+ updated: false,
11470
+ reason: "active runtime is current",
11471
+ activeVersion,
11472
+ latestVersion
11403
11473
  };
11404
11474
  }
11405
- const install2 = await installRuntime({
11406
- version: pin,
11475
+ const installed2 = await install({
11476
+ version: latestVersion,
11407
11477
  channel,
11408
11478
  cdnOrigin,
11409
11479
  setActive: false
@@ -11411,57 +11481,40 @@ async function updateRuntimeToLatest(opts = {}) {
11411
11481
  return {
11412
11482
  checked: true,
11413
11483
  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()
11484
+ activeVersion: latestVersion,
11485
+ latestVersion,
11486
+ install: installed2
11428
11487
  };
11429
11488
  }
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
- };
11489
+ async function checkUpToDate(opts = {}) {
11490
+ const active = product.readActiveRuntime();
11491
+ const pinned = resolvePin();
11492
+ if (pinned) {
11493
+ return { active, latest: pinned, pinned, outdated: active !== pinned };
11494
+ }
11495
+ try {
11496
+ const manifest = await fetchManifest(resolveCdnOrigin(opts.cdnOrigin));
11497
+ const channel = resolveChannel(opts.channel);
11498
+ const latest = manifest.channels[channel]?.latest ?? null;
11499
+ const outdated = !!(latest && (!active || compareSemver(latest, active) > 0));
11500
+ return { active, latest, pinned: null, outdated };
11501
+ } catch {
11502
+ return { active, latest: null, pinned: null, outdated: false };
11503
+ }
11452
11504
  }
11453
- const install = await installRuntime({
11454
- version: latestVersion,
11455
- channel,
11456
- cdnOrigin,
11457
- setActive: false
11458
- });
11459
11505
  return {
11460
- checked: true,
11461
- updated: true,
11462
- activeVersion: latestVersion,
11463
- latestVersion,
11464
- install
11506
+ product,
11507
+ resolveCdnOrigin,
11508
+ resolveChannel,
11509
+ resolvePin,
11510
+ manifestUrl,
11511
+ tarballUrl,
11512
+ fetchManifest,
11513
+ resolveVersion,
11514
+ install,
11515
+ updateToLatest,
11516
+ checkUpToDate,
11517
+ listInstalled: () => listInstalledRuntimes(product)
11465
11518
  };
11466
11519
  }
11467
11520
  async function downloadToFile(url, destPath) {
@@ -11469,17 +11522,17 @@ async function downloadToFile(url, destPath) {
11469
11522
  if (!res.ok || !res.body) {
11470
11523
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
11471
11524
  }
11472
- import_fs2.default.mkdirSync(import_path2.default.dirname(destPath), { recursive: true });
11525
+ import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(destPath), { recursive: true });
11473
11526
  const tmp = `${destPath}.partial`;
11474
11527
  try {
11475
11528
  await (0, import_promises.pipeline)(
11476
- import_stream.Readable.fromWeb(res.body),
11477
- import_fs2.default.createWriteStream(tmp)
11529
+ import_node_stream.Readable.fromWeb(res.body),
11530
+ import_node_fs4.default.createWriteStream(tmp)
11478
11531
  );
11479
- import_fs2.default.renameSync(tmp, destPath);
11532
+ import_node_fs4.default.renameSync(tmp, destPath);
11480
11533
  } catch (err) {
11481
11534
  try {
11482
- import_fs2.default.unlinkSync(tmp);
11535
+ import_node_fs4.default.unlinkSync(tmp);
11483
11536
  } catch {
11484
11537
  }
11485
11538
  throw err;
@@ -11487,8 +11540,8 @@ async function downloadToFile(url, destPath) {
11487
11540
  }
11488
11541
  function sha256File(filePath) {
11489
11542
  return new Promise((resolve5, reject) => {
11490
- const hash = import_crypto.default.createHash("sha256");
11491
- const stream = import_fs2.default.createReadStream(filePath);
11543
+ const hash = import_node_crypto.default.createHash("sha256");
11544
+ const stream = import_node_fs4.default.createReadStream(filePath);
11492
11545
  stream.on("data", (chunk) => hash.update(chunk));
11493
11546
  stream.on("error", reject);
11494
11547
  stream.on("end", () => resolve5(hash.digest("hex")));
@@ -11496,7 +11549,7 @@ function sha256File(filePath) {
11496
11549
  }
11497
11550
  function extractTarball(tarPath, destDir) {
11498
11551
  return new Promise((resolve5, reject) => {
11499
- const child = (0, import_child_process2.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
11552
+ const child = (0, import_node_child_process2.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
11500
11553
  stdio: ["ignore", "inherit", "inherit"]
11501
11554
  });
11502
11555
  child.on("error", reject);
@@ -11506,21 +11559,48 @@ function extractTarball(tarPath, destDir) {
11506
11559
  });
11507
11560
  });
11508
11561
  }
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;
11562
+ var import_node_child_process2, import_node_crypto, import_node_fs4, import_node_path3, import_node_stream, import_promises;
11563
+ var init_src = __esm({
11564
+ "../contrast-runtime-delivery/src/index.ts"() {
11565
+ "use strict";
11566
+ import_node_child_process2 = require("node:child_process");
11567
+ import_node_crypto = __toESM(require("node:crypto"), 1);
11568
+ import_node_fs4 = __toESM(require("node:fs"), 1);
11569
+ import_node_path3 = __toESM(require("node:path"), 1);
11570
+ import_node_stream = require("node:stream");
11571
+ import_promises = require("node:stream/promises");
11572
+ init_product();
11573
+ init_product();
11574
+ }
11575
+ });
11576
+
11577
+ // src/runtime-delivery.ts
11578
+ var DEFAULT_RUNTIME_CDN_ORIGIN, SOOTSIM_RUNTIME_PRODUCT, sootsimRuntime;
11510
11579
  var init_runtime_delivery = __esm({
11511
11580
  "src/runtime-delivery.ts"() {
11512
11581
  "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");
11582
+ init_src();
11519
11583
  init_home_paths();
11520
11584
  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";
11585
+ SOOTSIM_RUNTIME_PRODUCT = {
11586
+ id: "sootsim",
11587
+ defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
11588
+ manifestPath: "/runtimes/manifest.json",
11589
+ tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
11590
+ env: {
11591
+ cdnOrigin: "SOOTSIM_CDN_ORIGIN",
11592
+ channel: "SOOTSIM_RUNTIME_CHANNEL",
11593
+ pin: "SOOTSIM_RUNTIME_VERSION"
11594
+ },
11595
+ ensureHome: ensureSootsimHome,
11596
+ configFile: configFilePath,
11597
+ runtimesDir,
11598
+ runtimeDir,
11599
+ cacheDir,
11600
+ readActiveRuntime,
11601
+ writeActiveRuntime
11602
+ };
11603
+ sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT);
11524
11604
  }
11525
11605
  });
11526
11606
 
@@ -11585,7 +11665,7 @@ function getUserDataDir() {
11585
11665
  return userDataDir();
11586
11666
  }
11587
11667
  function storeFile() {
11588
- return import_node_path2.default.join(userDataDir(), "attached-projects.json");
11668
+ return import_node_path4.default.join(userDataDir(), "attached-projects.json");
11589
11669
  }
11590
11670
  function cloneEmpty() {
11591
11671
  return {
@@ -11599,7 +11679,7 @@ function loadStore() {
11599
11679
  const file = storeFile();
11600
11680
  let raw;
11601
11681
  try {
11602
- raw = import_node_fs3.default.readFileSync(file, "utf8");
11682
+ raw = import_node_fs5.default.readFileSync(file, "utf8");
11603
11683
  } catch (err) {
11604
11684
  if (err.code === "ENOENT") return cloneEmpty();
11605
11685
  throw err;
@@ -11616,7 +11696,7 @@ function loadStore() {
11616
11696
  } catch (err) {
11617
11697
  const quarantine = `${file}.corrupt-${Date.now()}`;
11618
11698
  try {
11619
- import_node_fs3.default.renameSync(file, quarantine);
11699
+ import_node_fs5.default.renameSync(file, quarantine);
11620
11700
  console.warn(
11621
11701
  `[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
11622
11702
  );
@@ -11627,16 +11707,16 @@ function loadStore() {
11627
11707
  }
11628
11708
  function writeStore(store) {
11629
11709
  const file = storeFile();
11630
- import_node_fs3.default.mkdirSync(import_node_path2.default.dirname(file), { recursive: true });
11710
+ import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
11631
11711
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
11632
- const fd = import_node_fs3.default.openSync(tmp, "w", 384);
11712
+ const fd = import_node_fs5.default.openSync(tmp, "w", 384);
11633
11713
  try {
11634
- import_node_fs3.default.writeFileSync(fd, JSON.stringify(store, null, 2));
11635
- import_node_fs3.default.fsyncSync(fd);
11714
+ import_node_fs5.default.writeFileSync(fd, JSON.stringify(store, null, 2));
11715
+ import_node_fs5.default.fsyncSync(fd);
11636
11716
  } finally {
11637
- import_node_fs3.default.closeSync(fd);
11717
+ import_node_fs5.default.closeSync(fd);
11638
11718
  }
11639
- import_node_fs3.default.renameSync(tmp, file);
11719
+ import_node_fs5.default.renameSync(tmp, file);
11640
11720
  }
11641
11721
  function mutateStore(fn) {
11642
11722
  const store = loadStore();
@@ -11645,13 +11725,13 @@ function mutateStore(fn) {
11645
11725
  return store;
11646
11726
  }
11647
11727
  function projectIdForCwd(cwd) {
11648
- return (0, import_node_crypto.createHash)("sha256").update(import_node_path2.default.resolve(cwd)).digest("hex").slice(0, 16);
11728
+ return (0, import_node_crypto2.createHash)("sha256").update(import_node_path4.default.resolve(cwd)).digest("hex").slice(0, 16);
11649
11729
  }
11650
11730
  function newSessionId() {
11651
- return `s_${(0, import_node_crypto.randomBytes)(10).toString("hex")}`;
11731
+ return `s_${(0, import_node_crypto2.randomBytes)(10).toString("hex")}`;
11652
11732
  }
11653
11733
  function upsertProject(input) {
11654
- const cwd = import_node_path2.default.resolve(input.cwd);
11734
+ const cwd = import_node_path4.default.resolve(input.cwd);
11655
11735
  const id = projectIdForCwd(cwd);
11656
11736
  let result;
11657
11737
  mutateStore((store) => {
@@ -11677,7 +11757,7 @@ function upsertProject(input) {
11677
11757
  const now = Date.now();
11678
11758
  const created = {
11679
11759
  id,
11680
- name: input.name ?? import_node_path2.default.basename(cwd),
11760
+ name: input.name ?? import_node_path4.default.basename(cwd),
11681
11761
  cwd,
11682
11762
  repoRoot: input.repoRoot,
11683
11763
  sourceRoots: input.sourceRoots ?? [cwd],
@@ -11806,8 +11886,8 @@ async function seedFromDemoAppRegistry() {
11806
11886
  if (apps.length === 0) return;
11807
11887
  mutateStore((store) => {
11808
11888
  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);
11889
+ if (!import_node_fs5.default.existsSync(app.dir)) continue;
11890
+ const cwd = import_node_path4.default.resolve(app.dir);
11811
11891
  const id = projectIdForCwd(cwd);
11812
11892
  if (store.attachedProjects.some((p) => p.id === id)) continue;
11813
11893
  const now = Date.now();
@@ -11828,13 +11908,13 @@ async function seedFromDemoAppRegistry() {
11828
11908
  }
11829
11909
  });
11830
11910
  }
11831
- var import_node_crypto, import_node_fs3, import_node_path2, overrideDir, COST_HISTORY_MAX_AGE_MS;
11911
+ var import_node_crypto2, import_node_fs5, import_node_path4, overrideDir, COST_HISTORY_MAX_AGE_MS;
11832
11912
  var init_attached_projects = __esm({
11833
11913
  "src/attached-projects.ts"() {
11834
11914
  "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);
11915
+ import_node_crypto2 = require("node:crypto");
11916
+ import_node_fs5 = __toESM(require("node:fs"), 1);
11917
+ import_node_path4 = __toESM(require("node:path"), 1);
11838
11918
  init_home_paths();
11839
11919
  overrideDir = null;
11840
11920
  COST_HISTORY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -11843,16 +11923,16 @@ var init_attached_projects = __esm({
11843
11923
 
11844
11924
  // src/agent-sessions.ts
11845
11925
  function sessionDir(sessionId) {
11846
- return import_node_path3.default.join(getUserDataDir(), "sessions", sessionId);
11926
+ return import_node_path5.default.join(getUserDataDir(), "sessions", sessionId);
11847
11927
  }
11848
11928
  function promptFifoPath(sessionId) {
11849
- return import_node_path3.default.join(sessionDir(sessionId), "prompt.in");
11929
+ return import_node_path5.default.join(sessionDir(sessionId), "prompt.in");
11850
11930
  }
11851
11931
  function eventsFifoPath(sessionId) {
11852
- return import_node_path3.default.join(sessionDir(sessionId), "events.out");
11932
+ return import_node_path5.default.join(sessionDir(sessionId), "events.out");
11853
11933
  }
11854
11934
  function transcriptPath(sessionId) {
11855
- return import_node_path3.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
11935
+ return import_node_path5.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
11856
11936
  }
11857
11937
  function pidIsAlive(pid, sessionId) {
11858
11938
  if (!pid) return false;
@@ -11862,7 +11942,7 @@ function pidIsAlive(pid, sessionId) {
11862
11942
  return false;
11863
11943
  }
11864
11944
  if (sessionId) {
11865
- if (!import_node_fs4.default.existsSync(sessionDir(sessionId))) return false;
11945
+ if (!import_node_fs6.default.existsSync(sessionDir(sessionId))) return false;
11866
11946
  }
11867
11947
  return true;
11868
11948
  }
@@ -11874,11 +11954,11 @@ function resolveSootsimInvocation() {
11874
11954
  const resourcesPath = process.resourcesPath;
11875
11955
  if (resourcesPath) {
11876
11956
  const candidates = [
11877
- import_node_path3.default.join(resourcesPath, "bin", "sootsim"),
11878
- import_node_path3.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
11957
+ import_node_path5.default.join(resourcesPath, "bin", "sootsim"),
11958
+ import_node_path5.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
11879
11959
  ];
11880
11960
  for (const c of candidates) {
11881
- if (import_node_fs4.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
11961
+ if (import_node_fs6.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
11882
11962
  }
11883
11963
  }
11884
11964
  }
@@ -11901,15 +11981,15 @@ function tryWorkspaceSootsim() {
11901
11981
  const sootsimDir = resolveSootsimPackageDir();
11902
11982
  if (!sootsimDir) return null;
11903
11983
  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)) {
11984
+ const distBinary = import_node_path5.default.join(sootsimDir, "dist-bin", binaryName);
11985
+ if (import_node_fs6.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
11986
+ const distBin = import_node_path5.default.join(sootsimDir, "dist-cli", "bin.js");
11987
+ if (import_node_fs6.default.existsSync(distBin)) {
11908
11988
  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;
11989
+ const src = import_node_path5.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
11990
+ if (import_node_fs6.default.existsSync(src)) {
11991
+ const srcMtime = import_node_fs6.default.statSync(src).mtimeMs;
11992
+ const buildMtime = import_node_fs6.default.statSync(distBin).mtimeMs;
11913
11993
  if (buildMtime < srcMtime) {
11914
11994
  console.warn(
11915
11995
  `[sootsim] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/sootsim build:cli\`.`
@@ -11928,22 +12008,22 @@ function tryWorkspaceSootsim() {
11928
12008
  function resolveSootsimPackageDir() {
11929
12009
  try {
11930
12010
  const resolved = require.resolve("sootsim/package.json");
11931
- return import_node_path3.default.dirname(resolved);
12011
+ return import_node_path5.default.dirname(resolved);
11932
12012
  } catch {
11933
12013
  }
11934
12014
  const here = fileFromImportMeta();
11935
12015
  if (!here) return null;
11936
- let cur = import_node_path3.default.dirname(here);
12016
+ let cur = import_node_path5.default.dirname(here);
11937
12017
  for (let i = 0; i < 8; i++) {
11938
- const pkg = import_node_path3.default.join(cur, "package.json");
12018
+ const pkg = import_node_path5.default.join(cur, "package.json");
11939
12019
  try {
11940
- if (import_node_fs4.default.existsSync(pkg)) {
11941
- const parsed = JSON.parse(import_node_fs4.default.readFileSync(pkg, "utf8"));
12020
+ if (import_node_fs6.default.existsSync(pkg)) {
12021
+ const parsed = JSON.parse(import_node_fs6.default.readFileSync(pkg, "utf8"));
11942
12022
  if (parsed.name === "sootsim") return cur;
11943
12023
  }
11944
12024
  } catch {
11945
12025
  }
11946
- const parent = import_node_path3.default.dirname(cur);
12026
+ const parent = import_node_path5.default.dirname(cur);
11947
12027
  if (parent === cur) break;
11948
12028
  cur = parent;
11949
12029
  }
@@ -11959,28 +12039,28 @@ function fileFromImportMeta() {
11959
12039
  }
11960
12040
  }
11961
12041
  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 });
12042
+ const lockDir = import_node_path5.default.join(getUserDataDir(), "locks");
12043
+ import_node_fs6.default.mkdirSync(lockDir, { recursive: true });
11964
12044
  try {
11965
- import_node_fs4.default.chmodSync(lockDir, 448);
12045
+ import_node_fs6.default.chmodSync(lockDir, 448);
11966
12046
  } catch {
11967
12047
  }
11968
- const lockPath = import_node_path3.default.join(lockDir, `start-${projectId}-${provider}.lock`);
12048
+ const lockPath = import_node_path5.default.join(lockDir, `start-${projectId}-${provider}.lock`);
11969
12049
  const deadline = Date.now() + 4e3;
11970
12050
  let fd = null;
11971
12051
  while (fd === null) {
11972
12052
  try {
11973
- fd = import_node_fs4.default.openSync(
12053
+ fd = import_node_fs6.default.openSync(
11974
12054
  lockPath,
11975
- import_node_fs4.constants.O_WRONLY | import_node_fs4.constants.O_CREAT | import_node_fs4.constants.O_EXCL,
12055
+ import_node_fs6.constants.O_WRONLY | import_node_fs6.constants.O_CREAT | import_node_fs6.constants.O_EXCL,
11976
12056
  384
11977
12057
  );
11978
12058
  } catch (err) {
11979
12059
  if (err.code !== "EEXIST") throw err;
11980
12060
  try {
11981
- const stale = Number(import_node_fs4.default.readFileSync(lockPath, "utf8").trim());
12061
+ const stale = Number(import_node_fs6.default.readFileSync(lockPath, "utf8").trim());
11982
12062
  if (stale && !isProcessAlive(stale)) {
11983
- import_node_fs4.default.unlinkSync(lockPath);
12063
+ import_node_fs6.default.unlinkSync(lockPath);
11984
12064
  continue;
11985
12065
  }
11986
12066
  } catch {
@@ -11994,15 +12074,15 @@ async function withStartLock(projectId, provider, fn) {
11994
12074
  }
11995
12075
  }
11996
12076
  try {
11997
- import_node_fs4.default.writeFileSync(fd, String(process.pid));
12077
+ import_node_fs6.default.writeFileSync(fd, String(process.pid));
11998
12078
  return await fn();
11999
12079
  } finally {
12000
12080
  try {
12001
- import_node_fs4.default.closeSync(fd);
12081
+ import_node_fs6.default.closeSync(fd);
12002
12082
  } catch {
12003
12083
  }
12004
12084
  try {
12005
- import_node_fs4.default.unlinkSync(lockPath);
12085
+ import_node_fs6.default.unlinkSync(lockPath);
12006
12086
  } catch {
12007
12087
  }
12008
12088
  }
@@ -12016,28 +12096,28 @@ function isProcessAlive(pid) {
12016
12096
  }
12017
12097
  }
12018
12098
  function mkfifoSync(p) {
12019
- const parent = import_node_path3.default.dirname(p);
12020
- import_node_fs4.default.mkdirSync(parent, { recursive: true });
12099
+ const parent = import_node_path5.default.dirname(p);
12100
+ import_node_fs6.default.mkdirSync(parent, { recursive: true });
12021
12101
  try {
12022
- import_node_fs4.default.chmodSync(parent, 448);
12102
+ import_node_fs6.default.chmodSync(parent, 448);
12023
12103
  } catch {
12024
12104
  }
12025
- if (import_node_fs4.default.existsSync(p)) {
12105
+ if (import_node_fs6.default.existsSync(p)) {
12026
12106
  try {
12027
- const stat = import_node_fs4.default.statSync(p);
12107
+ const stat = import_node_fs6.default.statSync(p);
12028
12108
  if (stat.isFIFO()) {
12029
12109
  try {
12030
- import_node_fs4.default.chmodSync(p, 384);
12110
+ import_node_fs6.default.chmodSync(p, 384);
12031
12111
  } catch {
12032
12112
  }
12033
12113
  return;
12034
12114
  }
12035
- import_node_fs4.default.unlinkSync(p);
12115
+ import_node_fs6.default.unlinkSync(p);
12036
12116
  } catch {
12037
- import_node_fs4.default.unlinkSync(p);
12117
+ import_node_fs6.default.unlinkSync(p);
12038
12118
  }
12039
12119
  }
12040
- const result = (0, import_node_child_process2.spawnSync)("mkfifo", ["-m", "600", p]);
12120
+ const result = (0, import_node_child_process3.spawnSync)("mkfifo", ["-m", "600", p]);
12041
12121
  if (result.status !== 0) {
12042
12122
  throw new Error(
12043
12123
  `mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
@@ -12060,7 +12140,7 @@ async function startSession(opts) {
12060
12140
  `session already running for project=${project.id} provider=${provider} (session ${existingLive.id}, pid ${existingLive.wrapperPid}). end it first with \`sootsim agent end <sessionId>\`.`
12061
12141
  );
12062
12142
  }
12063
- const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto2.randomUUID)() : void 0;
12143
+ const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto3.randomUUID)() : void 0;
12064
12144
  const session = upsertSession({
12065
12145
  projectId: project.id,
12066
12146
  provider,
@@ -12074,10 +12154,10 @@ async function startSession(opts) {
12074
12154
  const transcript = transcriptPath(session.id);
12075
12155
  mkfifoSync(promptIn);
12076
12156
  mkfifoSync(eventsOut);
12077
- const transcriptDir = import_node_path3.default.dirname(transcript);
12078
- import_node_fs4.default.mkdirSync(transcriptDir, { recursive: true });
12157
+ const transcriptDir = import_node_path5.default.dirname(transcript);
12158
+ import_node_fs6.default.mkdirSync(transcriptDir, { recursive: true });
12079
12159
  try {
12080
- import_node_fs4.default.chmodSync(transcriptDir, 448);
12160
+ import_node_fs6.default.chmodSync(transcriptDir, 448);
12081
12161
  } catch {
12082
12162
  }
12083
12163
  const { cmd, prefixArgs } = resolveSootsimInvocation();
@@ -12105,7 +12185,7 @@ async function startSession(opts) {
12105
12185
  if (claudeSessionUuid) {
12106
12186
  wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
12107
12187
  }
12108
- const child = (0, import_node_child_process2.spawn)(cmd, wrapperArgs, {
12188
+ const child = (0, import_node_child_process3.spawn)(cmd, wrapperArgs, {
12109
12189
  detached: true,
12110
12190
  stdio: "ignore",
12111
12191
  env: {
@@ -12128,7 +12208,7 @@ async function startSession(opts) {
12128
12208
  }
12129
12209
  }
12130
12210
  try {
12131
- import_node_fs4.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
12211
+ import_node_fs6.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
12132
12212
  } catch {
12133
12213
  }
12134
12214
  updateSessionStatus(session.id, { status: "ended" });
@@ -12156,18 +12236,18 @@ async function sendPrompt(sessionId, prompt) {
12156
12236
  );
12157
12237
  }
12158
12238
  const fifo = promptFifoPath(sessionId);
12159
- if (!import_node_fs4.default.existsSync(fifo)) {
12239
+ if (!import_node_fs6.default.existsSync(fifo)) {
12160
12240
  throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
12161
12241
  }
12162
- const fd = import_node_fs4.default.openSync(fifo, import_node_fs4.constants.O_WRONLY);
12242
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_WRONLY);
12163
12243
  try {
12164
12244
  const wireText = encodeAgentPromptEnvelope(prompt);
12165
12245
  if (!wireText) {
12166
12246
  throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
12167
12247
  }
12168
- import_node_fs4.default.writeSync(fd, wireText + "\n");
12248
+ import_node_fs6.default.writeSync(fd, wireText + "\n");
12169
12249
  } finally {
12170
- import_node_fs4.default.closeSync(fd);
12250
+ import_node_fs6.default.closeSync(fd);
12171
12251
  }
12172
12252
  updateSessionStatus(sessionId, {
12173
12253
  lastPrompt: prompt.displayText ?? prompt.text,
@@ -12189,7 +12269,7 @@ async function endSession(sessionId) {
12189
12269
  const base = getUserDataDir();
12190
12270
  if (dir.startsWith(base)) {
12191
12271
  try {
12192
- import_node_fs4.default.rmSync(dir, { recursive: true, force: true });
12272
+ import_node_fs6.default.rmSync(dir, { recursive: true, force: true });
12193
12273
  } catch {
12194
12274
  }
12195
12275
  }
@@ -12197,11 +12277,11 @@ async function endSession(sessionId) {
12197
12277
  }
12198
12278
  function subscribeEvents(sessionId, onEvent) {
12199
12279
  const fifo = eventsFifoPath(sessionId);
12200
- if (!import_node_fs4.default.existsSync(fifo)) {
12280
+ if (!import_node_fs6.default.existsSync(fifo)) {
12201
12281
  throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
12202
12282
  }
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 });
12283
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR);
12284
+ const stream = import_node_fs6.default.createReadStream("", { fd, autoClose: true });
12205
12285
  const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
12206
12286
  rl.on("line", (line) => {
12207
12287
  const event = parseAgentEventLine(line);
@@ -12222,7 +12302,7 @@ function subscribeEvents(sessionId, onEvent) {
12222
12302
  };
12223
12303
  }
12224
12304
  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);
12305
+ const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR | import_node_fs6.constants.O_NONBLOCK);
12226
12306
  const buf = Buffer.alloc(8192);
12227
12307
  let leftover = "";
12228
12308
  const deadline = Date.now() + timeoutMs;
@@ -12230,7 +12310,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12230
12310
  while (Date.now() < deadline) {
12231
12311
  let n = 0;
12232
12312
  try {
12233
- n = import_node_fs4.default.readSync(fd, buf, 0, buf.length, null);
12313
+ n = import_node_fs6.default.readSync(fd, buf, 0, buf.length, null);
12234
12314
  } catch (err) {
12235
12315
  if (err.code !== "EAGAIN") throw err;
12236
12316
  n = 0;
@@ -12250,17 +12330,17 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
12250
12330
  }
12251
12331
  return null;
12252
12332
  } finally {
12253
- import_node_fs4.default.closeSync(fd);
12333
+ import_node_fs6.default.closeSync(fd);
12254
12334
  }
12255
12335
  }
12256
- var import_node_child_process2, import_node_crypto2, import_node_fs4, import_node_path3, import_node_readline, AgentSessionError;
12336
+ var import_node_child_process3, import_node_crypto3, import_node_fs6, import_node_path5, import_node_readline, AgentSessionError;
12257
12337
  var init_agent_sessions = __esm({
12258
12338
  "src/agent-sessions.ts"() {
12259
12339
  "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);
12340
+ import_node_child_process3 = require("node:child_process");
12341
+ import_node_crypto3 = require("node:crypto");
12342
+ import_node_fs6 = __toESM(require("node:fs"), 1);
12343
+ import_node_path5 = __toESM(require("node:path"), 1);
12264
12344
  import_node_readline = __toESM(require("node:readline"), 1);
12265
12345
  init_agent_events();
12266
12346
  init_agent_prompt();
@@ -12302,8 +12382,8 @@ function resolveAgentbusCommand(explicit) {
12302
12382
  if (fromArg) return fromArg;
12303
12383
  const fromEnv = process.env.AGENTBUS_COMMAND?.trim();
12304
12384
  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;
12385
+ const localBin = import_node_path6.default.join(import_node_os2.default.homedir(), ".local", "bin", "agentbus");
12386
+ if (import_node_fs7.default.existsSync(localBin)) return localBin;
12307
12387
  return "agentbus";
12308
12388
  }
12309
12389
  async function sendPromptToAgentbusSession(input) {
@@ -12318,7 +12398,7 @@ async function sendPromptToAgentbusSession(input) {
12318
12398
  const command = resolveAgentbusCommand(input.command);
12319
12399
  const timeoutMs = input.timeoutMs ?? 15e3;
12320
12400
  await new Promise((resolve5, reject) => {
12321
- const child = (0, import_node_child_process3.spawn)(command, ["send", sessionId, text], {
12401
+ const child = (0, import_node_child_process4.spawn)(command, ["send", sessionId, text], {
12322
12402
  stdio: ["ignore", "ignore", "pipe"],
12323
12403
  env: process.env
12324
12404
  });
@@ -12353,14 +12433,14 @@ async function sendPromptToAgentbusSession(input) {
12353
12433
  });
12354
12434
  });
12355
12435
  }
12356
- var import_node_child_process3, import_node_fs5, import_node_os2, import_node_path4;
12436
+ var import_node_child_process4, import_node_fs7, import_node_os2, import_node_path6;
12357
12437
  var init_agentbus_prompt = __esm({
12358
12438
  "src/agentbus-prompt.ts"() {
12359
12439
  "use strict";
12360
- import_node_child_process3 = require("node:child_process");
12361
- import_node_fs5 = __toESM(require("node:fs"), 1);
12440
+ import_node_child_process4 = require("node:child_process");
12441
+ import_node_fs7 = __toESM(require("node:fs"), 1);
12362
12442
  import_node_os2 = __toESM(require("node:os"), 1);
12363
- import_node_path4 = __toESM(require("node:path"), 1);
12443
+ import_node_path6 = __toESM(require("node:path"), 1);
12364
12444
  init_agent_identity();
12365
12445
  init_agent_identity();
12366
12446
  }
@@ -12379,12 +12459,12 @@ function mapFrameworkToProjectFramework(fw) {
12379
12459
  if (fw === "one" || fw === "vxrn") return "one";
12380
12460
  return "unknown";
12381
12461
  }
12382
- var import_node_fs6, import_node_path5, WS_OPEN, AgentHost;
12462
+ var import_node_fs8, import_node_path7, WS_OPEN, AgentHost;
12383
12463
  var init_agent_host = __esm({
12384
12464
  "src/host/agent-host.ts"() {
12385
12465
  "use strict";
12386
- import_node_fs6 = __toESM(require("node:fs"), 1);
12387
- import_node_path5 = __toESM(require("node:path"), 1);
12466
+ import_node_fs8 = __toESM(require("node:fs"), 1);
12467
+ import_node_path7 = __toESM(require("node:path"), 1);
12388
12468
  init_dev_server_scanner();
12389
12469
  init_agent_sessions();
12390
12470
  init_agentbus_prompt();
@@ -12571,7 +12651,7 @@ var init_agent_host = __esm({
12571
12651
  );
12572
12652
  const project = upsertProject({
12573
12653
  cwd: match.cwd,
12574
- name: match.projectName ?? import_node_path5.default.basename(match.cwd),
12654
+ name: match.projectName ?? import_node_path7.default.basename(match.cwd),
12575
12655
  preferredProvider: input.provider ?? existing?.preferredProvider,
12576
12656
  sourceRoots: existing?.sourceRoots ?? [match.cwd],
12577
12657
  knownBundleUrls,
@@ -12582,18 +12662,18 @@ var init_agent_host = __esm({
12582
12662
  }
12583
12663
  getTranscript(sessionId) {
12584
12664
  const p = transcriptPath(sessionId);
12585
- if (!import_node_fs6.default.existsSync(p)) {
12665
+ if (!import_node_fs8.default.existsSync(p)) {
12586
12666
  return { error: "transcript not found", code: "NO_TRANSCRIPT" };
12587
12667
  }
12588
- return import_node_fs6.default.readFileSync(p, "utf8");
12668
+ return import_node_fs8.default.readFileSync(p, "utf8");
12589
12669
  }
12590
12670
  getPaths() {
12591
12671
  const dir = getUserDataDir();
12592
12672
  return {
12593
12673
  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")
12674
+ storeFile: import_node_path7.default.join(dir, "attached-projects.json"),
12675
+ sessionsDir: import_node_path7.default.join(dir, "sessions"),
12676
+ transcriptsDir: import_node_path7.default.join(dir, "transcripts")
12597
12677
  };
12598
12678
  }
12599
12679
  // --- subscription management ---
@@ -13193,19 +13273,19 @@ var init_fetch_proxy_handler = __esm({
13193
13273
 
13194
13274
  // src/host/open-url.ts
13195
13275
  function expandHome(candidate) {
13196
- return candidate.startsWith("~/") ? (0, import_path3.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
13276
+ return candidate.startsWith("~/") ? (0, import_path2.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
13197
13277
  }
13198
13278
  function firstExisting(candidates) {
13199
13279
  for (const candidate of candidates) {
13200
13280
  const expanded = expandHome(candidate);
13201
- if ((0, import_fs3.existsSync)(expanded)) return expanded;
13281
+ if ((0, import_fs2.existsSync)(expanded)) return expanded;
13202
13282
  }
13203
13283
  return null;
13204
13284
  }
13205
13285
  function lookupExecutable(command, platform) {
13206
13286
  try {
13207
13287
  const tool = platform === "win32" ? "where" : "which";
13208
- const out = (0, import_child_process3.execFileSync)(tool, [command], {
13288
+ const out = (0, import_child_process2.execFileSync)(tool, [command], {
13209
13289
  encoding: "utf8",
13210
13290
  timeout: 1500,
13211
13291
  stdio: ["ignore", "pipe", "ignore"]
@@ -13217,7 +13297,7 @@ function lookupExecutable(command, platform) {
13217
13297
  }
13218
13298
  function resolveChromiumBinary(platform = process.platform) {
13219
13299
  const envCandidate = process.env.CHROME_PATH || process.env.CHROMIUM_PATH;
13220
- if (envCandidate && (0, import_fs3.existsSync)(envCandidate)) return envCandidate;
13300
+ if (envCandidate && (0, import_fs2.existsSync)(envCandidate)) return envCandidate;
13221
13301
  const direct = platform === "darwin" ? firstExisting(MAC_CHROMIUM_CANDIDATES) : platform === "win32" ? firstExisting(WINDOWS_CHROMIUM_CANDIDATES) : firstExisting(LINUX_CHROMIUM_CANDIDATES);
13222
13302
  if (direct) return direct;
13223
13303
  const commands = platform === "win32" ? WINDOWS_CHROMIUM_COMMANDS : UNIX_CHROMIUM_COMMANDS;
@@ -13274,7 +13354,7 @@ function buildChromiumUrlCommand(url, options = {}) {
13274
13354
  }
13275
13355
  async function spawnLaunch(command, args, detached) {
13276
13356
  return new Promise((resolve5, reject) => {
13277
- const child = (0, import_child_process3.spawn)(command, args, {
13357
+ const child = (0, import_child_process2.spawn)(command, args, {
13278
13358
  detached,
13279
13359
  stdio: "ignore"
13280
13360
  });
@@ -13297,14 +13377,14 @@ async function launchUrl(url, options = {}) {
13297
13377
  async function openUrl(url, options = {}) {
13298
13378
  await launchUrl(url, options);
13299
13379
  }
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;
13380
+ 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
13381
  var init_open_url = __esm({
13302
13382
  "src/host/open-url.ts"() {
13303
13383
  "use strict";
13304
- import_child_process3 = require("child_process");
13305
- import_fs3 = require("fs");
13384
+ import_child_process2 = require("child_process");
13385
+ import_fs2 = require("fs");
13306
13386
  import_os = require("os");
13307
- import_path3 = require("path");
13387
+ import_path2 = require("path");
13308
13388
  MAC_CHROMIUM_CANDIDATES = [
13309
13389
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
13310
13390
  "~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -13566,14 +13646,14 @@ function unrefTimer(timer) {
13566
13646
  timer.unref();
13567
13647
  }
13568
13648
  }
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;
13649
+ 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
13650
  var init_bridge_host = __esm({
13571
13651
  "src/host/bridge-host.ts"() {
13572
13652
  "use strict";
13573
- import_child_process4 = require("child_process");
13574
- import_fs4 = __toESM(require("fs"), 1);
13653
+ import_child_process3 = require("child_process");
13654
+ import_fs3 = __toESM(require("fs"), 1);
13575
13655
  import_http3 = require("http");
13576
- import_path4 = __toESM(require("path"), 1);
13656
+ import_path3 = __toESM(require("path"), 1);
13577
13657
  import_ws2 = require("ws");
13578
13658
  init_dev_server_scanner();
13579
13659
  init_bridge_constants();
@@ -13865,7 +13945,7 @@ var init_bridge_host = __esm({
13865
13945
  return;
13866
13946
  }
13867
13947
  if (msg.type === "runtime:list") {
13868
- const versions = listInstalledRuntimes();
13948
+ const versions = sootsimRuntime.listInstalled();
13869
13949
  const active = this.getActiveRuntime();
13870
13950
  const reply = {
13871
13951
  type: "runtime:list:ok",
@@ -13882,7 +13962,7 @@ var init_bridge_host = __esm({
13882
13962
  }
13883
13963
  if (msg.type === "runtime:use") {
13884
13964
  const version = typeof msg.version === "string" ? msg.version : "";
13885
- const installed2 = listInstalledRuntimes();
13965
+ const installed2 = sootsimRuntime.listInstalled();
13886
13966
  if (!installed2.includes(version)) {
13887
13967
  try {
13888
13968
  ws.send(
@@ -14411,7 +14491,7 @@ var init_bridge_host = __esm({
14411
14491
  if (reason === "startup") {
14412
14492
  process.stderr.write("sootsim: checking for runtime updates\u2026\n");
14413
14493
  }
14414
- const result = await updateRuntimeToLatest();
14494
+ const result = await sootsimRuntime.updateToLatest();
14415
14495
  if (!result.updated || !result.latestVersion) {
14416
14496
  if (reason === "startup") {
14417
14497
  process.stderr.write(
@@ -14647,34 +14727,34 @@ var init_bridge_host = __esm({
14647
14727
  return;
14648
14728
  }
14649
14729
  }
14650
- const resolved = import_path4.default.resolve(baseDir, "." + rel);
14651
- const baseWithSep = baseDir.endsWith(import_path4.default.sep) ? baseDir : baseDir + import_path4.default.sep;
14730
+ const resolved = import_path3.default.resolve(baseDir, "." + rel);
14731
+ const baseWithSep = baseDir.endsWith(import_path3.default.sep) ? baseDir : baseDir + import_path3.default.sep;
14652
14732
  if (!resolved.startsWith(baseWithSep) && resolved !== baseDir) {
14653
14733
  res.writeHead(403);
14654
14734
  res.end("forbidden");
14655
14735
  return;
14656
14736
  }
14657
- import_fs4.default.realpath(resolved, (realErr, realResolved) => {
14737
+ import_fs3.default.realpath(resolved, (realErr, realResolved) => {
14658
14738
  const servePath = realErr ? resolved : realResolved;
14659
- const servePathWithSep = servePath.endsWith(import_path4.default.sep) ? servePath : servePath + import_path4.default.sep;
14739
+ const servePathWithSep = servePath.endsWith(import_path3.default.sep) ? servePath : servePath + import_path3.default.sep;
14660
14740
  if (!realErr) {
14661
14741
  const realBaseWithSep = (() => {
14662
14742
  try {
14663
- const rb = import_fs4.default.realpathSync(baseDir);
14664
- return rb.endsWith(import_path4.default.sep) ? rb : rb + import_path4.default.sep;
14743
+ const rb = import_fs3.default.realpathSync(baseDir);
14744
+ return rb.endsWith(import_path3.default.sep) ? rb : rb + import_path3.default.sep;
14665
14745
  } catch {
14666
14746
  return baseWithSep;
14667
14747
  }
14668
14748
  })();
14669
- if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path4.default.sep !== realBaseWithSep) {
14749
+ if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path3.default.sep !== realBaseWithSep) {
14670
14750
  res.writeHead(403);
14671
14751
  res.end("forbidden");
14672
14752
  return;
14673
14753
  }
14674
14754
  }
14675
- import_fs4.default.stat(servePath, (err, stats) => {
14755
+ import_fs3.default.stat(servePath, (err, stats) => {
14676
14756
  if (err || !stats?.isFile()) {
14677
- const ext2 = import_path4.default.extname(rel).toLowerCase();
14757
+ const ext2 = import_path3.default.extname(rel).toLowerCase();
14678
14758
  if (ext2 && ext2 !== ".html") {
14679
14759
  res.writeHead(404);
14680
14760
  res.end("not found");
@@ -14685,8 +14765,8 @@ var init_bridge_host = __esm({
14685
14765
  res.end("not found");
14686
14766
  return;
14687
14767
  }
14688
- const indexPath = import_path4.default.join(baseDir, "index.html");
14689
- import_fs4.default.readFile(indexPath, (err2, data) => {
14768
+ const indexPath = import_path3.default.join(baseDir, "index.html");
14769
+ import_fs3.default.readFile(indexPath, (err2, data) => {
14690
14770
  if (err2) {
14691
14771
  res.writeHead(404);
14692
14772
  res.end("not found");
@@ -14706,7 +14786,7 @@ var init_bridge_host = __esm({
14706
14786
  });
14707
14787
  return;
14708
14788
  }
14709
- const ext = import_path4.default.extname(servePath).toLowerCase();
14789
+ const ext = import_path3.default.extname(servePath).toLowerCase();
14710
14790
  const contentType = HTTP_MIME_TYPES[ext] || "application/octet-stream";
14711
14791
  res.writeHead(200, {
14712
14792
  "Content-Type": contentType,
@@ -14717,7 +14797,7 @@ var init_bridge_host = __esm({
14717
14797
  return;
14718
14798
  }
14719
14799
  if (ext === ".html") {
14720
- import_fs4.default.readFile(servePath, (readErr, data) => {
14800
+ import_fs3.default.readFile(servePath, (readErr, data) => {
14721
14801
  if (readErr) {
14722
14802
  try {
14723
14803
  res.end();
@@ -14731,7 +14811,7 @@ var init_bridge_host = __esm({
14731
14811
  });
14732
14812
  return;
14733
14813
  }
14734
- const stream = import_fs4.default.createReadStream(servePath);
14814
+ const stream = import_fs3.default.createReadStream(servePath);
14735
14815
  stream.pipe(res);
14736
14816
  stream.on("error", () => {
14737
14817
  try {
@@ -14937,7 +15017,7 @@ var init_bridge_host = __esm({
14937
15017
  const target = `${filePath}${loc}`;
14938
15018
  const trySpawn = (cmd, args) => new Promise((resolve5) => {
14939
15019
  try {
14940
- const child = (0, import_child_process4.spawn)(cmd, args, { detached: true, stdio: "ignore" });
15020
+ const child = (0, import_child_process3.spawn)(cmd, args, { detached: true, stdio: "ignore" });
14941
15021
  let settled = false;
14942
15022
  child.on("error", () => {
14943
15023
  if (settled) return;
@@ -15439,7 +15519,7 @@ function buildComm() {
15439
15519
  if (process.platform === "linux") {
15440
15520
  return (pid) => {
15441
15521
  try {
15442
- return (0, import_fs5.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
15522
+ return (0, import_fs4.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
15443
15523
  } catch {
15444
15524
  return null;
15445
15525
  }
@@ -15468,7 +15548,7 @@ function build() {
15468
15548
  function buildLinux() {
15469
15549
  return (pid) => {
15470
15550
  try {
15471
- const raw = (0, import_fs5.readFileSync)(`/proc/${pid}/stat`, "utf8");
15551
+ const raw = (0, import_fs4.readFileSync)(`/proc/${pid}/stat`, "utf8");
15472
15552
  const end = raw.lastIndexOf(")");
15473
15553
  if (end < 0) return null;
15474
15554
  const rest = raw.slice(end + 1).trim().split(/\s+/);
@@ -15532,7 +15612,7 @@ function tryBuildDarwinCommFfi() {
15532
15612
  function buildDarwinLsofComm() {
15533
15613
  return (pid) => {
15534
15614
  try {
15535
- const out = (0, import_child_process5.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15615
+ const out = (0, import_child_process4.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15536
15616
  encoding: "utf8",
15537
15617
  timeout: 2e3,
15538
15618
  stdio: ["ignore", "pipe", "ignore"]
@@ -15549,7 +15629,7 @@ function buildDarwinLsofComm() {
15549
15629
  function buildDarwinLsof() {
15550
15630
  return (pid) => {
15551
15631
  try {
15552
- const out = (0, import_child_process5.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15632
+ const out = (0, import_child_process4.execFileSync)("lsof", ["-R", "-p", String(pid), "-d", "cwd", "-a"], {
15553
15633
  encoding: "utf8",
15554
15634
  timeout: 2e3,
15555
15635
  stdio: ["ignore", "pipe", "ignore"]
@@ -15564,12 +15644,12 @@ function buildDarwinLsof() {
15564
15644
  }
15565
15645
  };
15566
15646
  }
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;
15647
+ 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
15648
  var init_parent_pid = __esm({
15569
15649
  "cli/parent-pid.ts"() {
15570
15650
  "use strict";
15571
- import_child_process5 = require("child_process");
15572
- import_fs5 = require("fs");
15651
+ import_child_process4 = require("child_process");
15652
+ import_fs4 = require("fs");
15573
15653
  import_module = require("module");
15574
15654
  cached3 = null;
15575
15655
  cachedComm = null;
@@ -15614,18 +15694,18 @@ function getCliIdentityKey() {
15614
15694
  }
15615
15695
  function getCurrentSimPath() {
15616
15696
  if (process.env[CURRENT_SIM_PATH_ENV]) {
15617
- return (0, import_path5.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
15697
+ return (0, import_path4.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
15618
15698
  }
15619
15699
  const key = getCliIdentityKey();
15620
- return (0, import_path5.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
15700
+ return (0, import_path4.join)((0, import_os2.tmpdir)(), `sootsim-current-sim-${key}.json`);
15621
15701
  }
15622
15702
  function readCurrentSim() {
15623
15703
  const filepath = getCurrentSimPath();
15624
- if (!(0, import_fs6.existsSync)(filepath)) return null;
15704
+ if (!(0, import_fs5.existsSync)(filepath)) return null;
15625
15705
  try {
15626
- const parsed = JSON.parse((0, import_fs6.readFileSync)(filepath, "utf8"));
15706
+ const parsed = JSON.parse((0, import_fs5.readFileSync)(filepath, "utf8"));
15627
15707
  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 });
15708
+ (0, import_fs5.rmSync)(filepath, { force: true });
15629
15709
  return null;
15630
15710
  }
15631
15711
  return {
@@ -15634,7 +15714,7 @@ function readCurrentSim() {
15634
15714
  updatedAt: parsed.updatedAt
15635
15715
  };
15636
15716
  } catch {
15637
- (0, import_fs6.rmSync)(filepath, { force: true });
15717
+ (0, import_fs5.rmSync)(filepath, { force: true });
15638
15718
  return null;
15639
15719
  }
15640
15720
  }
@@ -15642,15 +15722,15 @@ function readCurrentSimId() {
15642
15722
  return readCurrentSim()?.simId || null;
15643
15723
  }
15644
15724
  function clearCurrentSimId() {
15645
- (0, import_fs6.rmSync)(getCurrentSimPath(), { force: true });
15725
+ (0, import_fs5.rmSync)(getCurrentSimPath(), { force: true });
15646
15726
  }
15647
- var import_fs6, import_os2, import_path5, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE;
15727
+ var import_fs5, import_os2, import_path4, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE;
15648
15728
  var init_current_sim = __esm({
15649
15729
  "cli/current-sim.ts"() {
15650
15730
  "use strict";
15651
- import_fs6 = require("fs");
15731
+ import_fs5 = require("fs");
15652
15732
  import_os2 = require("os");
15653
- import_path5 = require("path");
15733
+ import_path4 = require("path");
15654
15734
  init_parent_pid();
15655
15735
  CURRENT_SIM_VERSION = 1;
15656
15736
  CURRENT_SIM_PATH_ENV = "SOOTSIM_CLI_CURRENT_SIM_PATH";
@@ -16091,11 +16171,11 @@ async function evalInBridge(bridge, code, opts = {}) {
16091
16171
  if (opts.acquireLock) payload.acquireLock = true;
16092
16172
  return bridge.send(payload);
16093
16173
  }
16094
- async function callInBridge(bridge, path11, ...args) {
16095
- return bridge.send({ type: "call", path: path11, args });
16174
+ async function callInBridge(bridge, path12, ...args) {
16175
+ return bridge.send({ type: "call", path: path12, args });
16096
16176
  }
16097
- async function callInBridgeWrite(bridge, path11, ...args) {
16098
- return bridge.send({ type: "call", path: path11, args, acquireLock: true });
16177
+ async function callInBridgeWrite(bridge, path12, ...args) {
16178
+ return bridge.send({ type: "call", path: path12, args, acquireLock: true });
16099
16179
  }
16100
16180
  var import_ws3, resolvedWorld, BridgeSimLockedError;
16101
16181
  var init_ws_bridge = __esm({
@@ -17091,7 +17171,7 @@ function executeSyncHttp(url, method, params) {
17091
17171
  delete childEnv[key];
17092
17172
  }
17093
17173
  }
17094
- const child = (0, import_child_process6.spawnSync)(process.execPath, ["-e", HTTP_CHILD_SRC], {
17174
+ const child = (0, import_child_process5.spawnSync)(process.execPath, ["-e", HTTP_CHILD_SRC], {
17095
17175
  input: JSON.stringify({ url, method, headers: params?.headers, body: params?.body }),
17096
17176
  encoding: "utf8",
17097
17177
  timeout: HTTP_TIMEOUT_MS,
@@ -17138,11 +17218,11 @@ function scriptConditionIsTruthy(value) {
17138
17218
  if (!Number.isNaN(num) && num === 0) return false;
17139
17219
  return true;
17140
17220
  }
17141
- var import_child_process6, vm, HTTP_TIMEOUT_MS, HTTP_CHILD_SRC, TEMPLATE_RE, ESCAPED_TEMPLATE_RE, BARE_IDENTIFIER_RE, MaestroJsContext;
17221
+ var import_child_process5, vm, HTTP_TIMEOUT_MS, HTTP_CHILD_SRC, TEMPLATE_RE, ESCAPED_TEMPLATE_RE, BARE_IDENTIFIER_RE, MaestroJsContext;
17142
17222
  var init_maestro_js = __esm({
17143
17223
  "cli/maestro-js.ts"() {
17144
17224
  "use strict";
17145
- import_child_process6 = require("child_process");
17225
+ import_child_process5 = require("child_process");
17146
17226
  vm = __toESM(require("vm"), 1);
17147
17227
  HTTP_TIMEOUT_MS = 3e5;
17148
17228
  HTTP_CHILD_SRC = `
@@ -17322,14 +17402,14 @@ process.stdin.on('end', async () => {
17322
17402
  function getBaseDir() {
17323
17403
  const explicit = process.env[SESSION_FILE_ENV];
17324
17404
  if (explicit?.trim()) {
17325
- return (0, import_node_path6.dirname)((0, import_node_path6.resolve)(explicit));
17405
+ return (0, import_node_path8.dirname)((0, import_node_path8.resolve)(explicit));
17326
17406
  }
17327
17407
  return electronUserDataDir();
17328
17408
  }
17329
17409
  function getSharedDesktopAuthFilePath() {
17330
17410
  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");
17411
+ if (explicit?.trim()) return (0, import_node_path8.resolve)(explicit);
17412
+ return (0, import_node_path8.join)(getBaseDir(), "desktop-auth.json");
17333
17413
  }
17334
17414
  function normalizeUser(input) {
17335
17415
  if (!input || typeof input !== "object") return null;
@@ -17375,26 +17455,26 @@ function normalizeSession(input) {
17375
17455
  }
17376
17456
  function readSharedDesktopAuthSession() {
17377
17457
  const filepath = getSharedDesktopAuthFilePath();
17378
- if (!(0, import_node_fs7.existsSync)(filepath)) return null;
17458
+ if (!(0, import_node_fs9.existsSync)(filepath)) return null;
17379
17459
  try {
17380
- const parsed = JSON.parse((0, import_node_fs7.readFileSync)(filepath, "utf8"));
17460
+ const parsed = JSON.parse((0, import_node_fs9.readFileSync)(filepath, "utf8"));
17381
17461
  const normalized = normalizeSession(parsed);
17382
17462
  if (!normalized) {
17383
- (0, import_node_fs7.rmSync)(filepath, { force: true });
17463
+ (0, import_node_fs9.rmSync)(filepath, { force: true });
17384
17464
  return null;
17385
17465
  }
17386
17466
  return normalized;
17387
17467
  } catch {
17388
- (0, import_node_fs7.rmSync)(filepath, { force: true });
17468
+ (0, import_node_fs9.rmSync)(filepath, { force: true });
17389
17469
  return null;
17390
17470
  }
17391
17471
  }
17392
- var import_node_fs7, import_node_path6, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
17472
+ var import_node_fs9, import_node_path8, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
17393
17473
  var init_shared_session = __esm({
17394
17474
  "src/auth/shared-session.ts"() {
17395
17475
  "use strict";
17396
- import_node_fs7 = require("node:fs");
17397
- import_node_path6 = require("node:path");
17476
+ import_node_fs9 = require("node:fs");
17477
+ import_node_path8 = require("node:path");
17398
17478
  init_home_paths();
17399
17479
  SESSION_VERSION = 1;
17400
17480
  SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
@@ -17670,16 +17750,16 @@ function resolveFlowScreenshotPath(screenshotDir, name) {
17670
17750
  }
17671
17751
  function resolveProjectRelativeFlowBase(flowDir) {
17672
17752
  if (!flowDir) return process.cwd();
17673
- return path9.basename(flowDir) === ".maestro" ? path9.dirname(flowDir) : flowDir;
17753
+ return path10.basename(flowDir) === ".maestro" ? path10.dirname(flowDir) : flowDir;
17674
17754
  }
17675
17755
  function resolveFlowScreenshotPathWithMode(screenshotDir, name, opts) {
17676
17756
  const normalizedName = name.endsWith(".png") ? name : `${name}.png`;
17677
- if (path9.isAbsolute(normalizedName)) return normalizedName;
17757
+ if (path10.isAbsolute(normalizedName)) return normalizedName;
17678
17758
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
17679
17759
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
17680
- return path9.resolve(baseDir, normalizedName);
17760
+ return path10.resolve(baseDir, normalizedName);
17681
17761
  }
17682
- return path9.join(screenshotDir, normalizedName);
17762
+ return path10.join(screenshotDir, normalizedName);
17683
17763
  }
17684
17764
  function normalizeFlowScreenshotSpec(step) {
17685
17765
  if (typeof step === "string") {
@@ -17736,12 +17816,12 @@ function parseFlowSteps(content) {
17736
17816
  const parsed = import_yaml.default.parse(candidate);
17737
17817
  return Array.isArray(parsed) ? parsed : [];
17738
17818
  }
17739
- var fs9, path9, import_settings2, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
17819
+ var fs10, path10, import_settings2, import_yaml, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
17740
17820
  var init_bridge_flow_runner = __esm({
17741
17821
  "cli/bridge-flow-runner.ts"() {
17742
17822
  "use strict";
17743
- fs9 = __toESM(require("fs"), 1);
17744
- path9 = __toESM(require("path"), 1);
17823
+ fs10 = __toESM(require("fs"), 1);
17824
+ path10 = __toESM(require("path"), 1);
17745
17825
  import_settings2 = require("sootsim-engine/settings");
17746
17826
  import_yaml = __toESM(require("yaml"), 1);
17747
17827
  init_frame_compose();
@@ -18029,14 +18109,14 @@ var init_bridge_flow_runner = __esm({
18029
18109
  if (chunks.length === 0) {
18030
18110
  throw new Error("recording requested but no video buffer was produced");
18031
18111
  }
18032
- fs9.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
18112
+ fs10.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
18033
18113
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
18034
18114
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
18035
- const outputPath = path9.join(
18115
+ const outputPath = path10.join(
18036
18116
  this.opts.recordingOutputDir,
18037
18117
  `sootsim-${Date.now()}.${extension}`
18038
18118
  );
18039
- fs9.writeFileSync(outputPath, Buffer.concat(chunks));
18119
+ fs10.writeFileSync(outputPath, Buffer.concat(chunks));
18040
18120
  return outputPath;
18041
18121
  }
18042
18122
  async waitForRecordingTail(opts) {
@@ -18545,7 +18625,7 @@ var init_bridge_flow_runner = __esm({
18545
18625
  flowDir: this.opts.flowDir
18546
18626
  }
18547
18627
  );
18548
- fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
18628
+ fs10.mkdirSync(path10.dirname(outputPath), { recursive: true });
18549
18629
  const layers = spec.layers ?? this.opts.screenshotLayers;
18550
18630
  const screenshotRequest = {
18551
18631
  type: "screenshot",
@@ -18561,11 +18641,11 @@ var init_bridge_flow_runner = __esm({
18561
18641
  throw new Error("could not read current device model for framed screenshot");
18562
18642
  }
18563
18643
  const framed = await composeFramedScreenshot(rawBuffer, model);
18564
- fs9.writeFileSync(outputPath, framed);
18644
+ fs10.writeFileSync(outputPath, framed);
18565
18645
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
18566
18646
  return outputPath;
18567
18647
  }
18568
- fs9.writeFileSync(outputPath, rawBuffer);
18648
+ fs10.writeFileSync(outputPath, rawBuffer);
18569
18649
  console.log(`[flow] screenshot: ${outputPath}`);
18570
18650
  return outputPath;
18571
18651
  }
@@ -18581,22 +18661,22 @@ var init_bridge_flow_runner = __esm({
18581
18661
  return model;
18582
18662
  }
18583
18663
  async captureScreenshot(outputPath) {
18584
- fs9.mkdirSync(path9.dirname(outputPath), { recursive: true });
18664
+ fs10.mkdirSync(path10.dirname(outputPath), { recursive: true });
18585
18665
  const dataUrl = await this.bridge.send({
18586
18666
  type: "screenshot",
18587
18667
  simId: this.opts.simId
18588
18668
  });
18589
18669
  const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
18590
- fs9.writeFileSync(outputPath, Buffer.from(base64, "base64"));
18670
+ fs10.writeFileSync(outputPath, Buffer.from(base64, "base64"));
18591
18671
  }
18592
18672
  // writes a per-failure debug bundle: screenshot + structured describe
18593
18673
  // + a11y tree + console errors/warnings + failed network requests +
18594
18674
  // shell state, all under one directory so post-mortem is one grep away.
18595
18675
  async captureFailureBundle(outputDir, context) {
18596
- fs9.mkdirSync(outputDir, { recursive: true });
18676
+ fs10.mkdirSync(outputDir, { recursive: true });
18597
18677
  const write = (name, content) => {
18598
18678
  try {
18599
- fs9.writeFileSync(path9.join(outputDir, name), content);
18679
+ fs10.writeFileSync(path10.join(outputDir, name), content);
18600
18680
  } catch {
18601
18681
  }
18602
18682
  };
@@ -19138,8 +19218,8 @@ var init_bridge_flow_runner = __esm({
19138
19218
  runScript(target) {
19139
19219
  const spec = typeof target === "string" ? { file: target } : target;
19140
19220
  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");
19221
+ const scriptPath = path10.resolve(this.opts.flowDir, spec.file);
19222
+ const source = fs10.readFileSync(scriptPath, "utf8");
19143
19223
  this.js.evaluate(source, { env: spec.env });
19144
19224
  console.log(`[flow] runScript: ${spec.file} done`);
19145
19225
  }
@@ -19433,10 +19513,10 @@ var init_bridge_flow_runner = __esm({
19433
19513
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
19434
19514
  }
19435
19515
  if (file) {
19436
- const flowPath = path9.resolve(this.opts.flowDir, file);
19437
- const flowContent = fs9.readFileSync(flowPath, "utf8");
19516
+ const flowPath = path10.resolve(this.opts.flowDir, file);
19517
+ const flowContent = fs10.readFileSync(flowPath, "utf8");
19438
19518
  const previousDir = this.opts.flowDir;
19439
- this.opts.flowDir = path9.dirname(flowPath);
19519
+ this.opts.flowDir = path10.dirname(flowPath);
19440
19520
  try {
19441
19521
  await this.runFlow(parseFlowSteps(flowContent));
19442
19522
  } finally {
@@ -19591,8 +19671,8 @@ __export(registry_exports, {
19591
19671
  skillRegistry: () => skillRegistry
19592
19672
  });
19593
19673
  module.exports = __toCommonJS(registry_exports);
19594
- var fs10 = __toESM(require("fs"), 1);
19595
- var path10 = __toESM(require("path"), 1);
19674
+ var fs11 = __toESM(require("fs"), 1);
19675
+ var path11 = __toESM(require("path"), 1);
19596
19676
 
19597
19677
  // src/skills/builtin/a11y-review.ts
19598
19678
  init_reap_browser();
@@ -19611,8 +19691,8 @@ var skill = {
19611
19691
  },
19612
19692
  async execute(params, context) {
19613
19693
  const { chromium } = await import("playwright");
19614
- const path11 = await import("path");
19615
- const fs11 = await import("fs");
19694
+ const path12 = await import("path");
19695
+ const fs12 = await import("fs");
19616
19696
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19617
19697
  headless: true
19618
19698
  });
@@ -19667,9 +19747,9 @@ var skill = {
19667
19747
  warnings: issues.filter((i) => i.severity === "warning").length,
19668
19748
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
19669
19749
  };
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));
19750
+ const reportPath = path12.join(context.outputDir, "a11y-report.json");
19751
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
19752
+ fs12.writeFileSync(reportPath, JSON.stringify(report, null, 2));
19673
19753
  return {
19674
19754
  success: issues.filter((i) => i.severity === "error").length === 0,
19675
19755
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -19707,8 +19787,8 @@ var skill2 = {
19707
19787
  }
19708
19788
  },
19709
19789
  async execute(params, context) {
19710
- const fs11 = await import("fs");
19711
- const path11 = await import("path");
19790
+ const fs12 = await import("fs");
19791
+ const path12 = await import("path");
19712
19792
  const { POLYFILL_REGISTRY: POLYFILL_REGISTRY2 } = await Promise.resolve().then(() => (init_web(), web_exports));
19713
19793
  if (params.packageName) {
19714
19794
  const entry = POLYFILL_REGISTRY2[params.packageName];
@@ -19726,11 +19806,11 @@ var skill2 = {
19726
19806
  data: { package: params.packageName, status, ...entry }
19727
19807
  };
19728
19808
  }
19729
- const pkgPath = path11.join(context.projectDir, "package.json");
19730
- if (!fs11.existsSync(pkgPath)) {
19809
+ const pkgPath = path12.join(context.projectDir, "package.json");
19810
+ if (!fs12.existsSync(pkgPath)) {
19731
19811
  return { success: false, message: "No package.json found" };
19732
19812
  }
19733
- const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
19813
+ const pkg = JSON.parse(fs12.readFileSync(pkgPath, "utf8"));
19734
19814
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
19735
19815
  const results = {
19736
19816
  full: [],
@@ -19748,9 +19828,9 @@ var skill2 = {
19748
19828
  results.unknown.push(dep);
19749
19829
  }
19750
19830
  }
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));
19831
+ const reportPath = path12.join(context.outputDir, "compat-report.json");
19832
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
19833
+ fs12.writeFileSync(reportPath, JSON.stringify(results, null, 2));
19754
19834
  return {
19755
19835
  success: results.unsupported.length === 0,
19756
19836
  message: `${results.full.length} full, ${results.partial.length} partial, ${results.unsupported.length} unsupported, ${results.unknown.length} unknown`,
@@ -19788,8 +19868,8 @@ var skill3 = {
19788
19868
  record: { type: "boolean", description: "Record video of the flow" }
19789
19869
  },
19790
19870
  async execute(params, context) {
19791
- const fs11 = await import("fs");
19792
- const path11 = await import("path");
19871
+ const fs12 = await import("fs");
19872
+ const path12 = await import("path");
19793
19873
  const yaml2 = await import("yaml");
19794
19874
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
19795
19875
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -19798,7 +19878,7 @@ var skill3 = {
19798
19878
  const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
19799
19879
  host.start({ silent: true });
19800
19880
  try {
19801
- const flowContent = fs11.readFileSync(params.flowPath, "utf8");
19881
+ const flowContent = fs12.readFileSync(params.flowPath, "utf8");
19802
19882
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
19803
19883
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
19804
19884
  const steps = yaml2.parse(stepsBody);
@@ -19823,7 +19903,7 @@ var skill3 = {
19823
19903
  });
19824
19904
  const driver = new SootSimBridgeFlowRunner2(bridge, {
19825
19905
  screenshotDir: context.outputDir,
19826
- flowDir: path11.dirname(path11.resolve(params.flowPath)),
19906
+ flowDir: path12.dirname(path12.resolve(params.flowPath)),
19827
19907
  simId,
19828
19908
  recordingOutputDir: params.record ? context.outputDir : void 0
19829
19909
  });
@@ -19845,7 +19925,7 @@ var skill3 = {
19845
19925
  simId,
19846
19926
  videoPath: videoPath || void 0
19847
19927
  },
19848
- artifacts: videoPath ? [{ type: "video", name: path11.basename(videoPath), path: videoPath }] : void 0
19928
+ artifacts: videoPath ? [{ type: "video", name: path12.basename(videoPath), path: videoPath }] : void 0
19849
19929
  };
19850
19930
  } finally {
19851
19931
  try {
@@ -19892,8 +19972,8 @@ var skill4 = {
19892
19972
  },
19893
19973
  async execute(params, context) {
19894
19974
  const { chromium } = await import("playwright");
19895
- const path11 = await import("path");
19896
- const fs11 = await import("fs");
19975
+ const path12 = await import("path");
19976
+ const fs12 = await import("fs");
19897
19977
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19898
19978
  headless: true
19899
19979
  });
@@ -19919,9 +19999,9 @@ var skill4 = {
19919
19999
  ...profile,
19920
20000
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
19921
20001
  };
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));
20002
+ const reportPath = path12.join(context.outputDir, "perf-report.json");
20003
+ fs12.mkdirSync(path12.dirname(reportPath), { recursive: true });
20004
+ fs12.writeFileSync(reportPath, JSON.stringify(report, null, 2));
19925
20005
  return {
19926
20006
  success: true,
19927
20007
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -19954,8 +20034,8 @@ var skill5 = {
19954
20034
  },
19955
20035
  async execute(params, context) {
19956
20036
  const { chromium } = await import("playwright");
19957
- const path11 = await import("path");
19958
- const fs11 = await import("fs");
20037
+ const path12 = await import("path");
20038
+ const fs12 = await import("fs");
19959
20039
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
19960
20040
  headless: true
19961
20041
  });
@@ -19963,8 +20043,8 @@ var skill5 = {
19963
20043
  try {
19964
20044
  await page.goto(context.url, { waitUntil: "networkidle" });
19965
20045
  await page.waitForTimeout(2e3);
19966
- const outputPath = path11.join(context.outputDir, `${params.name}.png`);
19967
- fs11.mkdirSync(path11.dirname(outputPath), { recursive: true });
20046
+ const outputPath = path12.join(context.outputDir, `${params.name}.png`);
20047
+ fs12.mkdirSync(path12.dirname(outputPath), { recursive: true });
19968
20048
  await page.screenshot({ path: outputPath });
19969
20049
  return {
19970
20050
  success: true,
@@ -20005,8 +20085,8 @@ var skill6 = {
20005
20085
  },
20006
20086
  async execute(params, context) {
20007
20087
  const { chromium } = await import("playwright");
20008
- const path11 = await import("path");
20009
- const fs11 = await import("fs");
20088
+ const path12 = await import("path");
20089
+ const fs12 = await import("fs");
20010
20090
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
20011
20091
  headless: true
20012
20092
  });
@@ -20014,14 +20094,14 @@ var skill6 = {
20014
20094
  try {
20015
20095
  await page.goto(context.url, { waitUntil: "networkidle" });
20016
20096
  await page.waitForTimeout(2e3);
20017
- const currentPath = path11.join(context.outputDir, `${params.name}-current.png`);
20018
- fs11.mkdirSync(path11.dirname(currentPath), { recursive: true });
20097
+ const currentPath = path12.join(context.outputDir, `${params.name}-current.png`);
20098
+ fs12.mkdirSync(path12.dirname(currentPath), { recursive: true });
20019
20099
  await page.screenshot({ path: currentPath });
20020
20100
  try {
20021
20101
  const { PNG } = await import("pngjs");
20022
20102
  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));
20103
+ const baseline = PNG.sync.read(fs12.readFileSync(params.baseline));
20104
+ const current = PNG.sync.read(fs12.readFileSync(currentPath));
20025
20105
  const { width, height } = baseline;
20026
20106
  const diff = new PNG({ width, height });
20027
20107
  const numDiffPixels = pixelmatch(
@@ -20032,8 +20112,8 @@ var skill6 = {
20032
20112
  height,
20033
20113
  { threshold: params.threshold || 0.1 }
20034
20114
  );
20035
- const diffPath = path11.join(context.outputDir, `${params.name}-diff.png`);
20036
- fs11.writeFileSync(diffPath, PNG.sync.write(diff));
20115
+ const diffPath = path12.join(context.outputDir, `${params.name}-diff.png`);
20116
+ fs12.writeFileSync(diffPath, PNG.sync.write(diff));
20037
20117
  const totalPixels = width * height;
20038
20118
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
20039
20119
  return {
@@ -20097,10 +20177,10 @@ var skillRegistry = {
20097
20177
  },
20098
20178
  // load skills from a project manifest (sootsim-skills.json)
20099
20179
  async loadFromManifest(projectDir) {
20100
- const manifestPath = path10.join(projectDir, "sootsim-skills.json");
20101
- if (!fs10.existsSync(manifestPath)) return;
20180
+ const manifestPath = path11.join(projectDir, "sootsim-skills.json");
20181
+ if (!fs11.existsSync(manifestPath)) return;
20102
20182
  try {
20103
- const manifest = JSON.parse(fs10.readFileSync(manifestPath, "utf8"));
20183
+ const manifest = JSON.parse(fs11.readFileSync(manifestPath, "utf8"));
20104
20184
  if (Array.isArray(manifest.skills)) {
20105
20185
  for (const entry of manifest.skills) {
20106
20186
  if (typeof entry === "string") {
@@ -20111,7 +20191,7 @@ var skillRegistry = {
20111
20191
  }
20112
20192
  } else if (entry.file) {
20113
20193
  try {
20114
- const mod = await import(path10.resolve(projectDir, entry.file));
20194
+ const mod = await import(path11.resolve(projectDir, entry.file));
20115
20195
  if (mod.skill) this.register(mod.skill);
20116
20196
  } catch {
20117
20197
  }
@@ -20124,10 +20204,10 @@ var skillRegistry = {
20124
20204
  // auto-discover skills based on project dependencies
20125
20205
  suggestSkills(projectDir) {
20126
20206
  const suggestions = [];
20127
- const pkgPath = path10.join(projectDir, "package.json");
20128
- if (!fs10.existsSync(pkgPath)) return suggestions;
20207
+ const pkgPath = path11.join(projectDir, "package.json");
20208
+ if (!fs11.existsSync(pkgPath)) return suggestions;
20129
20209
  try {
20130
- const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf8"));
20210
+ const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf8"));
20131
20211
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
20132
20212
  if (deps["detox"] || deps["maestro"]) {
20133
20213
  suggestions.push("maestro-test");