@c9up/helix 0.1.3 → 0.1.5

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 (235) hide show
  1. package/dist/cli/coverage/aggregate.d.ts +24 -0
  2. package/dist/cli/coverage/aggregate.d.ts.map +1 -0
  3. package/dist/cli/coverage/aggregate.js +215 -0
  4. package/dist/cli/coverage/aggregate.js.map +1 -0
  5. package/dist/cli/coverage/collect.d.ts +13 -0
  6. package/dist/cli/coverage/collect.d.ts.map +1 -0
  7. package/dist/cli/coverage/collect.js +66 -0
  8. package/dist/cli/coverage/collect.js.map +1 -0
  9. package/dist/cli/coverage/diff/base.d.ts +17 -0
  10. package/dist/cli/coverage/diff/base.d.ts.map +1 -0
  11. package/dist/cli/coverage/diff/base.js +44 -0
  12. package/dist/cli/coverage/diff/base.js.map +1 -0
  13. package/dist/cli/coverage/diff/index.d.ts +25 -0
  14. package/dist/cli/coverage/diff/index.d.ts.map +1 -0
  15. package/dist/cli/coverage/diff/index.js +119 -0
  16. package/dist/cli/coverage/diff/index.js.map +1 -0
  17. package/dist/cli/coverage/diff/overlay.d.ts +19 -0
  18. package/dist/cli/coverage/diff/overlay.d.ts.map +1 -0
  19. package/dist/cli/coverage/diff/overlay.js +58 -0
  20. package/dist/cli/coverage/diff/overlay.js.map +1 -0
  21. package/dist/cli/coverage/diff/parse.d.ts +27 -0
  22. package/dist/cli/coverage/diff/parse.d.ts.map +1 -0
  23. package/dist/cli/coverage/diff/parse.js +105 -0
  24. package/dist/cli/coverage/diff/parse.js.map +1 -0
  25. package/dist/cli/coverage/diff/reporters.d.ts +12 -0
  26. package/dist/cli/coverage/diff/reporters.d.ts.map +1 -0
  27. package/dist/cli/coverage/diff/reporters.js +59 -0
  28. package/dist/cli/coverage/diff/reporters.js.map +1 -0
  29. package/dist/cli/coverage/diff/types.d.ts +46 -0
  30. package/dist/cli/coverage/diff/types.d.ts.map +1 -0
  31. package/dist/cli/coverage/diff/types.js +15 -0
  32. package/dist/cli/coverage/diff/types.js.map +1 -0
  33. package/dist/cli/coverage/filter.d.ts +13 -0
  34. package/dist/cli/coverage/filter.d.ts.map +1 -0
  35. package/dist/cli/coverage/filter.js +60 -0
  36. package/dist/cli/coverage/filter.js.map +1 -0
  37. package/dist/cli/coverage/glob.d.ts +4 -0
  38. package/dist/cli/coverage/glob.d.ts.map +1 -0
  39. package/dist/cli/coverage/glob.js +0 -0
  40. package/dist/cli/coverage/glob.js.map +1 -0
  41. package/dist/cli/coverage/index.d.ts +40 -0
  42. package/dist/cli/coverage/index.d.ts.map +1 -0
  43. package/dist/cli/coverage/index.js +85 -0
  44. package/dist/cli/coverage/index.js.map +1 -0
  45. package/dist/cli/coverage/reporters/json.d.ts +13 -0
  46. package/dist/cli/coverage/reporters/json.d.ts.map +1 -0
  47. package/dist/cli/coverage/reporters/json.js +37 -0
  48. package/dist/cli/coverage/reporters/json.js.map +1 -0
  49. package/dist/cli/coverage/reporters/lcov.d.ts +13 -0
  50. package/dist/cli/coverage/reporters/lcov.d.ts.map +1 -0
  51. package/dist/cli/coverage/reporters/lcov.js +51 -0
  52. package/dist/cli/coverage/reporters/lcov.js.map +1 -0
  53. package/dist/cli/coverage/reporters/text.d.ts +8 -0
  54. package/dist/cli/coverage/reporters/text.d.ts.map +1 -0
  55. package/dist/cli/coverage/reporters/text.js +39 -0
  56. package/dist/cli/coverage/reporters/text.js.map +1 -0
  57. package/dist/cli/coverage/thresholds.d.ts +14 -0
  58. package/dist/cli/coverage/thresholds.d.ts.map +1 -0
  59. package/dist/cli/coverage/thresholds.js +58 -0
  60. package/dist/cli/coverage/thresholds.js.map +1 -0
  61. package/dist/cli/coverage/types.d.ts +118 -0
  62. package/dist/cli/coverage/types.d.ts.map +1 -0
  63. package/dist/cli/coverage/types.js +8 -0
  64. package/dist/cli/coverage/types.js.map +1 -0
  65. package/dist/cli/discover.d.ts +27 -0
  66. package/dist/cli/discover.d.ts.map +1 -0
  67. package/dist/cli/discover.js +142 -0
  68. package/dist/cli/discover.js.map +1 -0
  69. package/dist/cli/native.d.ts +43 -0
  70. package/dist/cli/native.d.ts.map +1 -0
  71. package/dist/cli/native.js +64 -0
  72. package/dist/cli/native.js.map +1 -0
  73. package/dist/cli/pool.d.ts +55 -0
  74. package/dist/cli/pool.d.ts.map +1 -0
  75. package/dist/cli/pool.js +404 -0
  76. package/dist/cli/pool.js.map +1 -0
  77. package/dist/cli/reporter.d.ts +51 -0
  78. package/dist/cli/reporter.d.ts.map +1 -0
  79. package/dist/cli/reporter.js +124 -0
  80. package/dist/cli/reporter.js.map +1 -0
  81. package/dist/cli/run.d.ts +61 -0
  82. package/dist/cli/run.d.ts.map +1 -0
  83. package/dist/cli/run.js +302 -0
  84. package/dist/cli/run.js.map +1 -0
  85. package/dist/cli/summary.d.ts +18 -0
  86. package/dist/cli/summary.d.ts.map +1 -0
  87. package/dist/cli/summary.js +20 -0
  88. package/dist/cli/summary.js.map +1 -0
  89. package/dist/cli/watch/loop.d.ts +26 -0
  90. package/dist/cli/watch/loop.d.ts.map +1 -0
  91. package/dist/cli/watch/loop.js +133 -0
  92. package/dist/cli/watch/loop.js.map +1 -0
  93. package/dist/cli/watch/types.d.ts +22 -0
  94. package/dist/cli/watch/types.d.ts.map +1 -0
  95. package/dist/cli/watch/types.js +6 -0
  96. package/dist/cli/watch/types.js.map +1 -0
  97. package/dist/cli/watch/watcher.d.ts +25 -0
  98. package/dist/cli/watch/watcher.d.ts.map +1 -0
  99. package/dist/cli/watch/watcher.js +122 -0
  100. package/dist/cli/watch/watcher.js.map +1 -0
  101. package/dist/container/index.d.ts +7 -0
  102. package/dist/container/index.d.ts.map +1 -0
  103. package/dist/container/index.js +6 -0
  104. package/dist/container/index.js.map +1 -0
  105. package/{src/container/override.ts → dist/container/override.d.ts} +6 -46
  106. package/dist/container/override.d.ts.map +1 -0
  107. package/dist/container/override.js +67 -0
  108. package/dist/container/override.js.map +1 -0
  109. package/{src/container/spy.ts → dist/container/spy.d.ts} +2 -6
  110. package/dist/container/spy.d.ts.map +1 -0
  111. package/dist/container/spy.js +23 -0
  112. package/dist/container/spy.js.map +1 -0
  113. package/dist/index.d.ts +20 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/{src/index.ts → dist/index.js} +2 -25
  116. package/dist/index.js.map +1 -0
  117. package/dist/runtime/assertion-error.d.ts +20 -0
  118. package/dist/runtime/assertion-error.d.ts.map +1 -0
  119. package/dist/runtime/assertion-error.js +23 -0
  120. package/dist/runtime/assertion-error.js.map +1 -0
  121. package/dist/runtime/cli-worker.d.ts +25 -0
  122. package/dist/runtime/cli-worker.d.ts.map +1 -0
  123. package/dist/runtime/cli-worker.js +128 -0
  124. package/dist/runtime/cli-worker.js.map +1 -0
  125. package/dist/runtime/equals.d.ts +25 -0
  126. package/dist/runtime/equals.d.ts.map +1 -0
  127. package/dist/runtime/equals.js +343 -0
  128. package/dist/runtime/equals.js.map +1 -0
  129. package/dist/runtime/expect.d.ts +32 -0
  130. package/dist/runtime/expect.d.ts.map +1 -0
  131. package/dist/runtime/expect.js +121 -0
  132. package/dist/runtime/expect.js.map +1 -0
  133. package/{src/runtime/index.ts → dist/runtime/index.d.ts} +5 -27
  134. package/dist/runtime/index.d.ts.map +1 -0
  135. package/dist/runtime/index.js +17 -0
  136. package/dist/runtime/index.js.map +1 -0
  137. package/{src/runtime/lifecycle.ts → dist/runtime/lifecycle.d.ts} +2 -8
  138. package/dist/runtime/lifecycle.d.ts.map +1 -0
  139. package/dist/runtime/lifecycle.js +10 -0
  140. package/dist/runtime/lifecycle.js.map +1 -0
  141. package/dist/runtime/matchers.d.ts +42 -0
  142. package/dist/runtime/matchers.d.ts.map +1 -0
  143. package/dist/runtime/matchers.js +375 -0
  144. package/dist/runtime/matchers.js.map +1 -0
  145. package/dist/runtime/run.d.ts +55 -0
  146. package/dist/runtime/run.d.ts.map +1 -0
  147. package/dist/runtime/run.js +456 -0
  148. package/dist/runtime/run.js.map +1 -0
  149. package/dist/runtime/suite.d.ts +91 -0
  150. package/dist/runtime/suite.d.ts.map +1 -0
  151. package/dist/runtime/suite.js +206 -0
  152. package/dist/runtime/suite.js.map +1 -0
  153. package/dist/runtime/test-context.d.ts +25 -0
  154. package/dist/runtime/test-context.d.ts.map +1 -0
  155. package/dist/runtime/test-context.js +52 -0
  156. package/dist/runtime/test-context.js.map +1 -0
  157. package/dist/runtime/vi/fake-timers.d.ts +48 -0
  158. package/dist/runtime/vi/fake-timers.d.ts.map +1 -0
  159. package/dist/runtime/vi/fake-timers.js +317 -0
  160. package/dist/runtime/vi/fake-timers.js.map +1 -0
  161. package/dist/runtime/vi/index.d.ts +70 -0
  162. package/dist/runtime/vi/index.d.ts.map +1 -0
  163. package/dist/runtime/vi/index.js +209 -0
  164. package/dist/runtime/vi/index.js.map +1 -0
  165. package/dist/runtime/vi/spy.d.ts +54 -0
  166. package/dist/runtime/vi/spy.d.ts.map +1 -0
  167. package/dist/runtime/vi/spy.js +159 -0
  168. package/dist/runtime/vi/spy.js.map +1 -0
  169. package/dist/runtime/vi/spyOn.d.ts +28 -0
  170. package/dist/runtime/vi/spyOn.d.ts.map +1 -0
  171. package/dist/runtime/vi/spyOn.js +121 -0
  172. package/dist/runtime/vi/spyOn.js.map +1 -0
  173. package/dist/runtime/vi/system-time.d.ts +30 -0
  174. package/dist/runtime/vi/system-time.d.ts.map +1 -0
  175. package/dist/runtime/vi/system-time.js +100 -0
  176. package/dist/runtime/vi/system-time.js.map +1 -0
  177. package/dist/runtime/worker.d.ts +26 -0
  178. package/dist/runtime/worker.d.ts.map +1 -0
  179. package/dist/runtime/worker.js +195 -0
  180. package/dist/runtime/worker.js.map +1 -0
  181. package/dist/time/freeze.d.ts +80 -0
  182. package/dist/time/freeze.d.ts.map +1 -0
  183. package/dist/time/freeze.js +184 -0
  184. package/dist/time/freeze.js.map +1 -0
  185. package/{src/time/index.ts → dist/time/index.d.ts} +1 -1
  186. package/dist/time/index.d.ts.map +1 -0
  187. package/dist/time/index.js +15 -0
  188. package/dist/time/index.js.map +1 -0
  189. package/index.darwin-arm64.node +0 -0
  190. package/index.darwin-x64.node +0 -0
  191. package/index.linux-arm64-gnu.node +0 -0
  192. package/index.linux-x64-gnu.node +0 -0
  193. package/index.win32-x64-msvc.node +0 -0
  194. package/package.json +2 -2
  195. package/src/cli/coverage/aggregate.ts +0 -231
  196. package/src/cli/coverage/collect.ts +0 -63
  197. package/src/cli/coverage/diff/base.ts +0 -46
  198. package/src/cli/coverage/diff/index.ts +0 -160
  199. package/src/cli/coverage/diff/overlay.ts +0 -62
  200. package/src/cli/coverage/diff/parse.ts +0 -121
  201. package/src/cli/coverage/diff/reporters.ts +0 -82
  202. package/src/cli/coverage/diff/types.ts +0 -46
  203. package/src/cli/coverage/filter.ts +0 -71
  204. package/src/cli/coverage/glob.ts +0 -0
  205. package/src/cli/coverage/index.ts +0 -126
  206. package/src/cli/coverage/reporters/json.ts +0 -40
  207. package/src/cli/coverage/reporters/lcov.ts +0 -54
  208. package/src/cli/coverage/reporters/text.ts +0 -48
  209. package/src/cli/coverage/thresholds.ts +0 -73
  210. package/src/cli/coverage/types.ts +0 -93
  211. package/src/cli/discover.ts +0 -174
  212. package/src/cli/native.ts +0 -104
  213. package/src/cli/pool.ts +0 -486
  214. package/src/cli/reporter.ts +0 -155
  215. package/src/cli/run.ts +0 -440
  216. package/src/cli/summary.ts +0 -42
  217. package/src/cli/watch/loop.ts +0 -159
  218. package/src/cli/watch/types.ts +0 -22
  219. package/src/cli/watch/watcher.ts +0 -145
  220. package/src/container/index.ts +0 -16
  221. package/src/runtime/assertion-error.ts +0 -38
  222. package/src/runtime/cli-worker.ts +0 -140
  223. package/src/runtime/equals.ts +0 -400
  224. package/src/runtime/expect.ts +0 -173
  225. package/src/runtime/matchers.ts +0 -452
  226. package/src/runtime/run.ts +0 -573
  227. package/src/runtime/suite.ts +0 -310
  228. package/src/runtime/test-context.ts +0 -59
  229. package/src/runtime/vi/fake-timers.ts +0 -410
  230. package/src/runtime/vi/index.ts +0 -254
  231. package/src/runtime/vi/spy.ts +0 -224
  232. package/src/runtime/vi/spyOn.ts +0 -155
  233. package/src/runtime/vi/system-time.ts +0 -121
  234. package/src/runtime/worker.ts +0 -239
  235. package/src/time/freeze.ts +0 -229
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Loads the native `ream-test-napi` binary built by `scripts/copy-napi.mjs`
3
+ * and exposes the Rust orchestrator `run(config)` to the TS CLI.
4
+ *
5
+ * Per the orchestrator design (42-N-orchestrator), the Rust NAPI engine is the
6
+ * canonical discovery + worker-pool + reporter + summary path; the TS `runOnce`
7
+ * delegates to it whenever no TS-only layer (coverage / diff-cov / watch / a
8
+ * pluggable reporter instance) is in play. There is NO JS fallback for a failed
9
+ * load — the caller gets a typed error pointing at `build:napi`.
10
+ *
11
+ * Field names are camelCase: napi-rs converts the Rust struct's snake_case
12
+ * fields automatically (`timeout_ms` → `timeoutMs`, etc.).
13
+ */
14
+ import { createRequire } from "node:module";
15
+ import { arch, platform } from "node:process";
16
+ import { fileURLToPath } from "node:url";
17
+ const SUFFIX_MAP = {
18
+ "linux-x64": "linux-x64-gnu",
19
+ "linux-arm64": "linux-arm64-gnu",
20
+ "darwin-x64": "darwin-x64",
21
+ "darwin-arm64": "darwin-arm64",
22
+ "win32-x64": "win32-x64-msvc",
23
+ };
24
+ function platformSuffix() {
25
+ const key = `${platform}-${arch}`;
26
+ const suffix = SUFFIX_MAP[key];
27
+ if (typeof suffix !== "string") {
28
+ throw new Error(`Unsupported platform/arch '${key}' for @c9up/helix native binary. Supported: ${Object.keys(SUFFIX_MAP).join(", ")}.`);
29
+ }
30
+ return suffix;
31
+ }
32
+ function isNativeExports(value) {
33
+ if (value === null || typeof value !== "object")
34
+ return false;
35
+ return typeof Reflect.get(value, "run") === "function";
36
+ }
37
+ let cachedNative;
38
+ export function getNative() {
39
+ if (cachedNative !== undefined)
40
+ return cachedNative;
41
+ const require = createRequire(import.meta.url);
42
+ const here = fileURLToPath(import.meta.url);
43
+ // `here` is `…/packages/helix/{src,dist}/cli/native.ts|js`. The `.node` lives
44
+ // two levels up at `…/packages/helix/index.<suffix>.node`.
45
+ const suffix = platformSuffix();
46
+ const candidate = `../../index.${suffix}.node`;
47
+ let loaded;
48
+ try {
49
+ loaded = require(candidate);
50
+ }
51
+ catch (err) {
52
+ const cause = err instanceof Error ? err.message : String(err);
53
+ const muslHint = suffix.endsWith("-gnu")
54
+ ? " If you are on Alpine/musl, note the prebuilt binaries target glibc (musl is not a supported target)."
55
+ : "";
56
+ throw new Error(`@c9up/helix native binary 'index.${suffix}.node' not found or failed to load near ${here} — run 'pnpm --filter @c9up/helix build:napi' to build it.${muslHint} Cause: ${cause}`, { cause: err });
57
+ }
58
+ if (!isNativeExports(loaded)) {
59
+ throw new Error("@c9up/helix native binary loaded but missing the expected 'run' export. Rebuild with 'pnpm --filter @c9up/helix build:napi'.");
60
+ }
61
+ cachedNative = loaded;
62
+ return cachedNative;
63
+ }
64
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/cli/native.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAqC;IACpD,WAAW,EAAE,eAAe;IAC5B,aAAa,EAAE,iBAAiB;IAChC,YAAY,EAAE,YAAY;IAC1B,cAAc,EAAE,cAAc;IAC9B,WAAW,EAAE,gBAAgB;CAC7B,CAAC;AAEF,SAAS,cAAc;IACtB,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACd,8BAA8B,GAAG,+CAA+C,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACrH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAgCD,SAAS,eAAe,CAAC,KAAc;IACtC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,OAAO,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,UAAU,CAAC;AACxD,CAAC;AAED,IAAI,YAAuC,CAAC;AAE5C,MAAM,UAAU,SAAS;IACxB,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IAEpD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,8EAA8E;IAC9E,2DAA2D;IAC3D,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,eAAe,MAAM,OAAO,CAAC;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvC,CAAC,CAAC,uGAAuG;YACzG,CAAC,CAAC,EAAE,CAAC;QACN,MAAM,IAAI,KAAK,CACd,oCAAoC,MAAM,2CAA2C,IAAI,6DAA6D,QAAQ,WAAW,KAAK,EAAE,EAChL,EAAE,KAAK,EAAE,GAAG,EAAE,CACd,CAAC;IACH,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACd,8HAA8H,CAC9H,CAAC;IACH,CAAC;IACD,YAAY,GAAG,MAAM,CAAC;IACtB,OAAO,YAAY,CAAC;AACrB,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Worker pool — spawns a Node child process per file and collects the
3
+ * framed result from the worker's stderr.
4
+ *
5
+ * Robustness features (2026-04-24 review pass):
6
+ * - UTF-8 safe chunking via `node:string_decoder`
7
+ * - Drains stdout so chatty `console.log` can't fill the pipe buffer
8
+ * - SIGTERM → SIGKILL escalation after a grace window
9
+ * - Process groups (`detached: true`) so grand-children die with the parent
10
+ * - SIGINT handler that kills every in-flight worker cleanly
11
+ * - Nonce in the frame instruction prevents a test file from spoofing results
12
+ * - Reporter callbacks wrapped in try/catch so a buggy reporter can't crash the run
13
+ * - Argv / config validation (threads, timeout) happens upstream; pool normalises
14
+ */
15
+ import type { FileResult } from "../runtime/run.js";
16
+ import type { Reporter } from "./reporter.js";
17
+ export interface PoolConfig {
18
+ /** Absolute path to the CLI worker entry (cli-worker.ts). */
19
+ workerEntry: string;
20
+ /** Node executable to spawn. Default: `process.execPath`. */
21
+ nodeBin?: string;
22
+ /** Extra args before the worker entry, e.g. `["--import", "<tsx-loader>"]`. */
23
+ nodeArgs?: string[];
24
+ /** Concurrent workers. Default: `os.cpus().length`. */
25
+ threads?: number;
26
+ /** Per-file timeout (ms). Default 60 000. */
27
+ timeoutMs?: number;
28
+ /**
29
+ * Grace period (ms) between SIGTERM and SIGKILL when killing a hanging
30
+ * worker. Default 2 000.
31
+ */
32
+ killGraceMs?: number;
33
+ /**
34
+ * Extra environment variables merged into every spawned worker's env.
35
+ * Used by coverage to forward `NODE_V8_COVERAGE=<tmp-dir>`.
36
+ */
37
+ extraEnv?: NodeJS.ProcessEnv;
38
+ }
39
+ export interface WorkerErrorMessage {
40
+ file: string | undefined;
41
+ message: string;
42
+ stack?: string;
43
+ }
44
+ export type FileOutcome = {
45
+ kind: "result";
46
+ result: FileResult;
47
+ } | {
48
+ kind: "error";
49
+ error: WorkerErrorMessage;
50
+ };
51
+ export declare function runPool(files: string[], cfg: PoolConfig, reporter: Reporter): Promise<{
52
+ results: FileResult[];
53
+ errors: WorkerErrorMessage[];
54
+ }>;
55
+ //# sourceMappingURL=pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/cli/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,UAAU;IAC1B,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,WAAW,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAwHhD,wBAAsB,OAAO,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAAC,CAmClE"}
@@ -0,0 +1,404 @@
1
+ /**
2
+ * Worker pool — spawns a Node child process per file and collects the
3
+ * framed result from the worker's stderr.
4
+ *
5
+ * Robustness features (2026-04-24 review pass):
6
+ * - UTF-8 safe chunking via `node:string_decoder`
7
+ * - Drains stdout so chatty `console.log` can't fill the pipe buffer
8
+ * - SIGTERM → SIGKILL escalation after a grace window
9
+ * - Process groups (`detached: true`) so grand-children die with the parent
10
+ * - SIGINT handler that kills every in-flight worker cleanly
11
+ * - Nonce in the frame instruction prevents a test file from spoofing results
12
+ * - Reporter callbacks wrapped in try/catch so a buggy reporter can't crash the run
13
+ * - Argv / config validation (threads, timeout) happens upstream; pool normalises
14
+ */
15
+ import { spawn } from "node:child_process";
16
+ import os from "node:os";
17
+ import path from "node:path";
18
+ import process from "node:process";
19
+ import { StringDecoder } from "node:string_decoder";
20
+ const FRAME_PREFIX = "__HELIX_RESULT__";
21
+ /** Maximum stderr buffering before we give up and mark the file errored. */
22
+ const MAX_STDERR_BUFFER_BYTES = 4 * 1024 * 1024; // 4 MiB
23
+ /**
24
+ * Magic nonce the worker uses for errors it emits BEFORE receiving the
25
+ * instruction (so before it knows the real nonce). Accepted by the parent
26
+ * only for `type === "error"` frames so a fixture can't spoof results.
27
+ */
28
+ const PRE_HANDSHAKE_NONCE = "__helix_pre_handshake__";
29
+ /** Tracks every spawned worker so SIGINT can tear them all down. */
30
+ const activeChildren = new Set();
31
+ let sigintInstalled = false;
32
+ function installSigintHandlerOnce() {
33
+ if (sigintInstalled)
34
+ return;
35
+ sigintInstalled = true;
36
+ const tearDown = (signal) => {
37
+ for (const child of activeChildren) {
38
+ try {
39
+ child.kill();
40
+ }
41
+ catch {
42
+ /* ignore */
43
+ }
44
+ }
45
+ process.off(signal, tearDown);
46
+ process.kill(process.pid, signal);
47
+ };
48
+ process.once("SIGINT", tearDown);
49
+ process.once("SIGTERM", tearDown);
50
+ }
51
+ /**
52
+ * FIFO counting semaphore. Waiters resolve in the order they called
53
+ * `acquire()` when a permit is released.
54
+ */
55
+ class Semaphore {
56
+ #permits;
57
+ #waiters = [];
58
+ constructor(initial) {
59
+ if (!Number.isFinite(initial) || initial < 1) {
60
+ throw new Error(`Semaphore: initial permits must be a finite number >= 1, got ${initial}`);
61
+ }
62
+ this.#permits = Math.floor(initial);
63
+ }
64
+ async acquire() {
65
+ if (this.#permits > 0) {
66
+ this.#permits -= 1;
67
+ return this.#makeRelease();
68
+ }
69
+ return new Promise((resolve) => {
70
+ this.#waiters.push(() => resolve(this.#makeRelease()));
71
+ });
72
+ }
73
+ #makeRelease() {
74
+ let released = false;
75
+ return () => {
76
+ if (released)
77
+ return;
78
+ released = true;
79
+ const next = this.#waiters.shift();
80
+ if (next) {
81
+ next();
82
+ }
83
+ else {
84
+ this.#permits += 1;
85
+ }
86
+ };
87
+ }
88
+ }
89
+ function safeCall(fn, context) {
90
+ try {
91
+ return fn();
92
+ }
93
+ catch (err) {
94
+ process.stderr.write(`helix: reporter.${context} threw — ${err instanceof Error ? err.message : String(err)}\n`);
95
+ return undefined;
96
+ }
97
+ }
98
+ const LOADER_FLAG_PREFIXES = [
99
+ "--import",
100
+ "--loader",
101
+ "--experimental-loader",
102
+ "--experimental-vm-modules",
103
+ "--experimental-specifier-resolution",
104
+ "--conditions",
105
+ ];
106
+ function inheritedLoaderArgs() {
107
+ const out = [];
108
+ const argv = process.execArgv;
109
+ for (let i = 0; i < argv.length; i += 1) {
110
+ const arg = argv[i];
111
+ if (arg === undefined)
112
+ continue;
113
+ const prefix = LOADER_FLAG_PREFIXES.find((p) => arg === p || arg.startsWith(`${p}=`));
114
+ if (prefix === undefined)
115
+ continue;
116
+ out.push(arg);
117
+ // Flags written as `--import tsx` (space-separated) consume the next argv entry.
118
+ if (arg === prefix) {
119
+ const next = argv[i + 1];
120
+ if (next !== undefined) {
121
+ out.push(next);
122
+ i += 1;
123
+ }
124
+ }
125
+ }
126
+ return out;
127
+ }
128
+ export async function runPool(files, cfg, reporter) {
129
+ installSigintHandlerOnce();
130
+ const effectiveThreads = Math.max(1, Math.min(cfg.threads ?? os.cpus().length, files.length > 0 ? files.length : 1));
131
+ const sem = new Semaphore(effectiveThreads);
132
+ const results = [];
133
+ const errors = [];
134
+ await Promise.all(files.map(async (file) => {
135
+ const absFile = path.isAbsolute(file) ? file : path.resolve(file);
136
+ const release = await sem.acquire();
137
+ try {
138
+ safeCall(() => reporter.onFileStart(absFile), "onFileStart");
139
+ const outcome = await runOne(absFile, cfg);
140
+ if (outcome.kind === "result") {
141
+ safeCall(() => reporter.onFileResult(outcome.result), "onFileResult");
142
+ results.push(outcome.result);
143
+ }
144
+ else {
145
+ safeCall(() => reporter.onFileError(outcome.error), "onFileError");
146
+ errors.push(outcome.error);
147
+ }
148
+ }
149
+ finally {
150
+ release();
151
+ }
152
+ }));
153
+ return { results, errors };
154
+ }
155
+ function runOne(file, cfg) {
156
+ return new Promise((resolve) => {
157
+ const nodeBin = cfg.nodeBin ?? process.execPath;
158
+ // Inherit the parent process's --import / --loader / --experimental-*
159
+ // flags by default. This is what keeps the spawned worker able to
160
+ // execute the .ts worker entry when the parent runs under a TS loader
161
+ // (@swc-node/register, tsx, ts-node/esm, …). Callers that want the
162
+ // child to run with a clean argv pass `nodeArgs: []` explicitly.
163
+ const nodeArgs = cfg.nodeArgs ?? inheritedLoaderArgs();
164
+ const timeoutMs = Number.isFinite(cfg.timeoutMs) && (cfg.timeoutMs ?? 0) > 0
165
+ ? Math.floor(cfg.timeoutMs)
166
+ : 60_000;
167
+ const killGraceMs = Number.isFinite(cfg.killGraceMs) && (cfg.killGraceMs ?? 0) > 0
168
+ ? Math.floor(cfg.killGraceMs)
169
+ : 2_000;
170
+ // Per-invocation nonce — the worker echoes it inside every frame so
171
+ // malicious or confused test code can't spoof a `__HELIX_RESULT__` line.
172
+ const nonce = `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
173
+ const child = spawn(nodeBin, [...nodeArgs, cfg.workerEntry], {
174
+ stdio: ["pipe", "pipe", "pipe"],
175
+ // `detached: true` on POSIX creates a new process group. On
176
+ // termination we kill the whole group so grand-children die too.
177
+ detached: process.platform !== "win32",
178
+ env: cfg.extraEnv ? { ...process.env, ...cfg.extraEnv } : process.env,
179
+ });
180
+ const registration = {
181
+ kill: () => killChild(child, killGraceMs),
182
+ };
183
+ activeChildren.add(registration);
184
+ let settled = false;
185
+ let pendingOutcome;
186
+ const settle = (outcome) => {
187
+ if (settled)
188
+ return;
189
+ settled = true;
190
+ clearTimeout(watchdog);
191
+ activeChildren.delete(registration);
192
+ resolve(outcome);
193
+ };
194
+ /**
195
+ * Schedule resolution. On a `result` or `error` frame from the
196
+ * worker (`forceKill = false`) we wait for `child.on("exit")` so
197
+ * `atExit` hooks (e.g. V8 coverage writer) finish flushing before
198
+ * we let downstream code read the coverage dir. On a timeout or
199
+ * spawn error (`forceKill = true`) we kill it now and resolve
200
+ * immediately — there's no useful flush to wait for.
201
+ */
202
+ const finish = (outcome, forceKill = false) => {
203
+ if (settled)
204
+ return;
205
+ if (forceKill) {
206
+ killChild(child, killGraceMs);
207
+ settle(outcome);
208
+ return;
209
+ }
210
+ // Defer resolution until exit — but if the child has already
211
+ // exited (race), settle now.
212
+ if (child.exitCode !== null || child.signalCode !== null) {
213
+ settle(outcome);
214
+ return;
215
+ }
216
+ pendingOutcome = outcome;
217
+ };
218
+ const watchdog = setTimeout(() => {
219
+ finish({
220
+ kind: "error",
221
+ error: {
222
+ file,
223
+ message: `worker timed out after ${timeoutMs}ms`,
224
+ },
225
+ }, true);
226
+ }, timeoutMs + killGraceMs);
227
+ watchdog.unref?.();
228
+ // UTF-8-safe accumulator for stderr frame parsing.
229
+ const decoder = new StringDecoder("utf8");
230
+ let stderrBuffer = "";
231
+ const processLine = (line) => {
232
+ if (!line.startsWith(FRAME_PREFIX)) {
233
+ if (process.env.HELIX_DEBUG_POOL) {
234
+ process.stderr.write(`[helix-debug] worker stderr: ${line}\n`);
235
+ }
236
+ return;
237
+ }
238
+ const payload = line.slice(FRAME_PREFIX.length);
239
+ let msg;
240
+ try {
241
+ msg = JSON.parse(payload);
242
+ }
243
+ catch {
244
+ return;
245
+ }
246
+ if (!msg || typeof msg !== "object")
247
+ return;
248
+ const m = msg;
249
+ // Reject frames without the matching nonce — prevents a fixture
250
+ // that writes `__HELIX_RESULT__...` on stderr from spoofing.
251
+ // Exception: pre-handshake error frames (worker couldn't parse
252
+ // its own instruction and doesn't know the real nonce yet) are
253
+ // accepted only for `type === "error"` so a fixture still can't
254
+ // claim a fake success.
255
+ const nonceOk = m.nonce === nonce ||
256
+ (m.nonce === PRE_HANDSHAKE_NONCE && m.type === "error");
257
+ if (!nonceOk)
258
+ return;
259
+ if (m.type === "result" && m.result) {
260
+ finish({ kind: "result", result: m.result });
261
+ }
262
+ else if (m.type === "error") {
263
+ finish({
264
+ kind: "error",
265
+ error: {
266
+ file: m.file ?? file,
267
+ message: m.message ?? "unknown worker error",
268
+ stack: m.stack,
269
+ },
270
+ });
271
+ }
272
+ };
273
+ child.stderr?.on("data", (chunk) => {
274
+ const text = decoder.write(chunk);
275
+ stderrBuffer += text;
276
+ if (stderrBuffer.length > MAX_STDERR_BUFFER_BYTES) {
277
+ finish({
278
+ kind: "error",
279
+ error: {
280
+ file,
281
+ message: `worker stderr exceeded ${MAX_STDERR_BUFFER_BYTES} bytes without emitting a frame`,
282
+ },
283
+ }, true);
284
+ return;
285
+ }
286
+ let nl = stderrBuffer.indexOf("\n");
287
+ while (nl >= 0 && !settled) {
288
+ const line = stderrBuffer.slice(0, nl);
289
+ stderrBuffer = stderrBuffer.slice(nl + 1);
290
+ processLine(line);
291
+ nl = stderrBuffer.indexOf("\n");
292
+ }
293
+ });
294
+ // Drain stdout so a chatty `console.log` can't fill the 64 KB pipe
295
+ // buffer and deadlock the worker. We don't currently surface it to
296
+ // the reporter (Phase 2 feature).
297
+ child.stdout?.on("data", () => { });
298
+ child.on("error", (err) => {
299
+ finish({
300
+ kind: "error",
301
+ error: { file, message: `spawn failed: ${err.message}` },
302
+ }, true);
303
+ });
304
+ child.on("exit", () => {
305
+ // If we already have an outcome waiting on the natural exit,
306
+ // resolve it now — coverage hooks have flushed.
307
+ if (pendingOutcome) {
308
+ settle(pendingOutcome);
309
+ return;
310
+ }
311
+ if (settled)
312
+ return;
313
+ // Flush any partial trailing line from the decoder before giving up.
314
+ const trailing = decoder.end();
315
+ if (trailing) {
316
+ stderrBuffer += trailing;
317
+ const nl = stderrBuffer.indexOf("\n");
318
+ if (nl >= 0)
319
+ processLine(stderrBuffer.slice(0, nl));
320
+ }
321
+ if (pendingOutcome) {
322
+ settle(pendingOutcome);
323
+ return;
324
+ }
325
+ if (settled)
326
+ return;
327
+ settle({
328
+ kind: "error",
329
+ error: {
330
+ file,
331
+ message: "worker exited without emitting a framed result",
332
+ },
333
+ });
334
+ });
335
+ // Instruction line.
336
+ const instr = JSON.stringify({
337
+ type: "run",
338
+ file,
339
+ timeoutMs,
340
+ nonce,
341
+ });
342
+ // `child.stdin` may be closed by the time we get here (rare spawn race).
343
+ // Attach an error listener so an EPIPE doesn't crash the parent.
344
+ child.stdin?.on("error", (err) => {
345
+ finish({
346
+ kind: "error",
347
+ error: { file, message: `stdin write failed: ${err.message}` },
348
+ }, true);
349
+ });
350
+ child.stdin?.write(`${instr}\n`, () => {
351
+ child.stdin?.end();
352
+ });
353
+ });
354
+ }
355
+ /**
356
+ * Kill `child` with SIGTERM, escalate to SIGKILL after `graceMs`. On POSIX
357
+ * we target the process group (negative pid) so grand-children die too.
358
+ *
359
+ * Idempotent: further calls after the first are no-ops. If the child has
360
+ * already exited (cleanly or via an earlier kill), no signals are sent and
361
+ * no escalation timer is armed — which matters for large suites where a
362
+ * per-file 2s timer retains the `child` closure and creates GC pressure,
363
+ * and for Linux systems where pid reuse could deliver SIGKILL to the wrong
364
+ * process.
365
+ */
366
+ const killedChildren = new WeakSet();
367
+ function killChild(child, graceMs) {
368
+ if (killedChildren.has(child))
369
+ return;
370
+ killedChildren.add(child);
371
+ // If the child already exited on its own, nothing to do — no SIGTERM,
372
+ // no escalation timer.
373
+ if (child.killed || child.exitCode !== null || child.signalCode !== null) {
374
+ return;
375
+ }
376
+ const pid = child.pid;
377
+ const posix = process.platform !== "win32";
378
+ const trySignal = (signal) => {
379
+ // Re-check exit status on each signal to avoid pid-reuse races: the
380
+ // child may have exited between our initial check and this send.
381
+ if (child.exitCode !== null || child.signalCode !== null)
382
+ return;
383
+ try {
384
+ if (posix && typeof pid === "number") {
385
+ process.kill(-pid, signal);
386
+ }
387
+ else {
388
+ child.kill(signal);
389
+ }
390
+ }
391
+ catch {
392
+ /* already dead, permission denied, or process-group invalid */
393
+ }
394
+ };
395
+ trySignal("SIGTERM");
396
+ // Escalate after the grace window if the child is still alive. Cleared
397
+ // by `child.on("exit")` so a clean exit drops the timer immediately.
398
+ const escalation = setTimeout(() => {
399
+ trySignal("SIGKILL");
400
+ }, graceMs);
401
+ escalation.unref?.();
402
+ child.once("exit", () => clearTimeout(escalation));
403
+ }
404
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/cli/pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Reporters — receive lifecycle callbacks as each file completes, write
3
+ * incremental output to the given sink. Three built-ins matching the
4
+ * Rust-side reporter trait:
5
+ * - Dot: one char per test
6
+ * - Spec: nested tree with colours + diff lines on failure
7
+ * - Json: NDJSON to stdout, machine-readable
8
+ */
9
+ import type { FileResult } from "../runtime/run.js";
10
+ import type { WorkerErrorMessage } from "./pool.js";
11
+ import type { Summary } from "./summary.js";
12
+ export interface Reporter {
13
+ onFileStart(file: string): void;
14
+ onFileResult(result: FileResult): void;
15
+ onFileError(error: WorkerErrorMessage): void;
16
+ onSummary(summary: Summary): void;
17
+ }
18
+ type Sink = {
19
+ write(chunk: string): void;
20
+ writeLine(chunk: string): void;
21
+ };
22
+ export declare function stdoutSink(): Sink;
23
+ export declare class DotReporter implements Reporter {
24
+ private readonly sink;
25
+ constructor(sink?: Sink);
26
+ onFileStart(_file: string): void;
27
+ onFileResult(result: FileResult): void;
28
+ onFileError(_error: WorkerErrorMessage): void;
29
+ onSummary(summary: Summary): void;
30
+ }
31
+ export declare class SpecReporter implements Reporter {
32
+ private readonly sink;
33
+ private readonly useColors;
34
+ constructor(sink?: Sink, useColors?: boolean);
35
+ onFileStart(file: string): void;
36
+ onFileResult(result: FileResult): void;
37
+ onFileError(error: WorkerErrorMessage): void;
38
+ onSummary(summary: Summary): void;
39
+ }
40
+ export declare class JsonReporter implements Reporter {
41
+ private readonly sink;
42
+ constructor(sink?: Sink);
43
+ onFileStart(file: string): void;
44
+ onFileResult(result: FileResult): void;
45
+ onFileError(error: WorkerErrorMessage): void;
46
+ onSummary(summary: Summary): void;
47
+ }
48
+ /** Factory from a CLI-style name. */
49
+ export declare function makeReporter(name: string | undefined, useColors: boolean): Reporter;
50
+ export {};
51
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/cli/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,QAAQ;IACxB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IACvC,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC7C,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAClC;AAED,KAAK,IAAI,GAAG;IACX,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF,wBAAgB,UAAU,IAAI,IAAI,CASjC;AASD,qBAAa,WAAY,YAAW,QAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,IAAmB;IACtD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAChC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAatC,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAG7C,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAIjC;AAED,qBAAa,YAAa,YAAW,QAAQ;IAE3C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,IAAI,GAAE,IAAmB,EACzB,SAAS,UAAO;IAElC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK/B,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IA0BtC,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAM5C,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAIjC;AAED,qBAAa,YAAa,YAAW,QAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,GAAE,IAAmB;IACtD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAG/B,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAGtC,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAG5C,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAGjC;AAWD,qCAAqC;AACrC,wBAAgB,YAAY,CAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,OAAO,GAChB,QAAQ,CASV"}