@systemfsoftware/stryker-js 12.0.0 → 12.1.1

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.
@@ -1,4 +1,4 @@
1
- import { A as Plugin_exports, D as VerdictReached, E as SkippedReported, F as ErrorText_exports, I as Format_exports, L as Instrument_exports, M as Reporter_exports, N as TestRunner_exports, O as Checker_exports, P as Trace_exports$1, R as Mutant_exports, _ as PluginsReported, b as RunFailed$1, c as Heartbeat, f as OutputMode, i as FormatRegistryResolved, j as Report_exports, k as Options_exports, l as HelpRendered, m as PlanKnown, n as StageError, p as PhaseEntered, t as PrepareError, u as ModeSignal, w as RunStarted, x as RunMutantTested, y as RunEvent } from "./Run.schema-BxsyHwHr.mjs";
1
+ import { A as Plugin_exports, D as VerdictReached, E as SkippedReported, F as ErrorText_exports, I as Format_exports, L as Instrument_exports, M as Reporter_exports, N as TestRunner_exports, O as Checker_exports, P as Trace_exports$1, R as Mutant_exports, _ as PluginsReported, b as RunFailed$1, c as Heartbeat, f as OutputMode, i as FormatRegistryResolved, j as Report_exports, k as Options_exports, l as HelpRendered, m as PlanKnown, n as StageError, p as PhaseEntered, t as PrepareError, u as ModeSignal, w as RunStarted, x as RunMutantTested, y as RunEvent } from "./Run.schema-BaK_pxuK.mjs";
2
2
  import { t as mergeConfig } from "./merge-config-ByZJPeQZ.mjs";
3
3
  import { Blueprint, Cell, Handle, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
4
4
  import * as Boolean$1 from "effect/Boolean";
@@ -61,13 +61,13 @@ import * as NodeFileSystem$1 from "@effect/platform-node-shared/NodeFileSystem";
61
61
  import * as NodePath$1 from "@effect/platform-node-shared/NodePath";
62
62
  import { badArgument } from "effect/PlatformError";
63
63
  import * as Equivalence from "effect/Equivalence";
64
- import { Session } from "@systemfsoftware/stryker-vm-harness";
65
64
  import * as Console from "effect/Console";
66
65
  import * as Formatter from "effect/Formatter";
67
66
  import * as Runtime from "effect/Runtime";
68
67
  import * as Order from "effect/Order";
69
68
  import * as CliError from "effect/unstable/cli/CliError";
70
69
  import { sha256 } from "@noble/hashes/sha2.js";
70
+ import "effect/Deferred";
71
71
  import * as Pool from "effect/Pool";
72
72
  import * as Semaphore from "effect/Semaphore";
73
73
  //#region src/admit-checker-answer.workflow.ts
@@ -178,14 +178,14 @@ var WorkerBootTimeoutError = class extends Schema.TaggedError()("WorkerBootTimeo
178
178
  };
179
179
  //#endregion
180
180
  //#region src/Checker/Checker.handle.ts
181
- const TypeId$11 = Symbol.for("~systemfsoftware/stryker-js/Checker");
181
+ const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/Checker");
182
182
  const checkerDuration = Metric.timer("stryker.checker.duration", { description: "Checker worker RPC duration in milliseconds" });
183
183
  const checkerMutantsChecked = Metric.counter("stryker.checker.mutants.checked", { description: "Total number of mutants a checker worker answered for" });
184
184
  const checkerRpcFailures = Metric.counter("stryker.checker.rpc_failures", {
185
185
  description: "Checker worker RPC calls that did not complete, excluding interruptions",
186
186
  incremental: true
187
187
  });
188
- const CheckerHandle = Handle.make()(TypeId$11);
188
+ const CheckerHandle = Handle.make()(TypeId$10);
189
189
  const isCheckerHandle = CheckerHandle.is;
190
190
  const connectionCrashed = (cause) => ChildProcessCrashedError.make({
191
191
  pid: 0,
@@ -418,7 +418,7 @@ const checkCell = Sandwich.named("stryker.checker.check_plans")(readCheckCommand
418
418
  CheckerSkippedRequested: (breach) => Effect$1.fail(CheckerSkippedRequested.make(breach)),
419
419
  CommandRejected: ({ issue }, raw) => Effect$1.fail(commandFailed(issue, raw))
420
420
  });
421
- const checkGroupedCell = Sandwich.named("stryker.checker.group_plans")(readGroupCommand).decide(admitCheckerAnswer).write({
421
+ const groupCell = Sandwich.named("stryker.checker.group_plans")(readGroupCommand).decide(admitCheckerAnswer).write({
422
422
  CheckGroupDecision: ({ groups }, raw) => writeDecidedGroups({
423
423
  plans: raw.plans,
424
424
  checkerName: raw.checkerName,
@@ -432,16 +432,20 @@ const checkGroupedCell = Sandwich.named("stryker.checker.group_plans")(readGroup
432
432
  CheckerAnsweredUnrequested: (breach) => Effect$1.fail(CheckerAnsweredUnrequested.make(breach)),
433
433
  CheckerSkippedRequested: (breach) => Effect$1.fail(CheckerSkippedRequested.make(breach)),
434
434
  CommandRejected: ({ issue }, raw) => Effect$1.fail(commandFailed(issue, raw))
435
- }).pipe(Cell.flatMap((groups) => Cell.mapInput(Cell.collect(checkCell, (perGroup) => perGroup.flat()), (input) => groups.map((group) => ({
435
+ });
436
+ const checkGroupedCell = groupCell.pipe(Cell.flatMap((groups) => Cell.mapInput(Cell.collect(checkCell, (perGroup) => perGroup.flat()), (input) => groups.map((group) => ({
436
437
  ...input,
437
438
  plans: group
438
439
  })))));
439
- const checkGroupedPlans = dual(3, (checker, checkerName, plans) => checkGroupedCell.run({
440
+ const checkRequestOf = (checker, checkerName, plans) => ({
440
441
  checker,
441
442
  checkerName,
442
443
  plans,
443
444
  lookup: lookupOf(partitionMutantsForWire(plans))
444
- }));
445
+ });
446
+ const groupPlans = dual(3, (checker, checkerName, plans) => groupCell.run(checkRequestOf(checker, checkerName, plans)));
447
+ const checkPlans = dual(3, (checker, checkerName, plans) => checkCell.run(checkRequestOf(checker, checkerName, plans)));
448
+ const checkGroupedPlans = dual(3, (checker, checkerName, plans) => checkGroupedCell.run(checkRequestOf(checker, checkerName, plans)));
445
449
  //#endregion
446
450
  //#region src/Config.schema.ts
447
451
  const ConfigDocumentSchema = S.Record(S.String, S.Unknown);
@@ -718,8 +722,8 @@ const interpretDryRunResult = Workflow.make({
718
722
  });
719
723
  //#endregion
720
724
  //#region src/pooled-test-runner.handle.ts
721
- const TypeId$10 = Symbol.for("~systemfsoftware/stryker-js/PooledTestRunner");
722
- const PooledTestRunner = Handle.make()(TypeId$10);
725
+ const TypeId$9 = Symbol.for("~systemfsoftware/stryker-js/PooledTestRunner");
726
+ const PooledTestRunner = Handle.make()(TypeId$9);
723
727
  PooledTestRunner.is;
724
728
  const make$3 = (runner) => PooledTestRunner.make({
725
729
  capabilities: runner.capabilities,
@@ -820,7 +824,7 @@ const withEnvironmentReload = dual(2, (inner, retire) => Effect$1.gen(function*
820
824
  }));
821
825
  //#endregion
822
826
  //#region src/command-runner.blueprint.ts
823
- const TypeId$9 = Symbol.for("~systemfsoftware/stryker-js/CommandRunner");
827
+ const TypeId$8 = Symbol.for("~systemfsoftware/stryker-js/CommandRunner");
824
828
  const ALL_TESTS_NAME = "All tests";
825
829
  const isCommandRunner = (name) => typeof name === "string" && name.toLowerCase() === "command";
826
830
  const commandRunnerCapabilities = { reloadEnvironment: true };
@@ -881,7 +885,7 @@ const pooledRunnerOf = (config, spawner) => {
881
885
  mutantRun: (options) => commandRunnerMutantRun(config, options).pipe(provided)
882
886
  });
883
887
  };
884
- const CommandRunners = Blueprint.make()(TypeId$9).steps({
888
+ const CommandRunners = Blueprint.make()(TypeId$8).steps({
885
889
  steps: {},
886
890
  targets: { runner: (spec) => (spawner) => pooledRunnerOf({
887
891
  workingDir: spec.workingDir,
@@ -1036,7 +1040,7 @@ const resolveConfig = Workflow.make({
1036
1040
  const ExitDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/ExitDecision");
1037
1041
  var ClassifyExitCommand = class extends S.TaggedClass()("ClassifyExitCommand", {
1038
1042
  pending: S.Array(Plugin_exports.ExitClass),
1039
- score: S.NullOr(S.Finite),
1043
+ score: Report_exports.MutationScore,
1040
1044
  breakingThreshold: S.NullOr(S.Finite)
1041
1045
  }) {
1042
1046
  static [Workflow.InstrumentationBrand] = {};
@@ -1071,9 +1075,12 @@ const PRECEDENCE = [
1071
1075
  ];
1072
1076
  const precedenceOf = (pending) => Arr.findFirst(PRECEDENCE, (candidate) => pending.includes(candidate));
1073
1077
  const decisionOf$1 = (exitClass) => Match.value(exitClass).pipe(Match.when("VerdictFail", () => ExitVerdictFailed.make({})), Match.when("ConfigError", () => ExitConfigErrored.make({})), Match.when("RuntimeError", () => ExitRuntimeErrored.make({})), Match.when("InternalError", () => ExitInternalErrored.make({})), Match.exhaustive);
1074
- const verdictExitClass = (score, breakingThreshold) => Option$1.match(Option$1.all([Option$1.fromNullishOr(score), Option$1.fromNullishOr(breakingThreshold)]), {
1075
- onNone: () => null,
1076
- onSome: ([actual, threshold]) => Match.value(actual < threshold).pipe(Match.when(true, () => "VerdictFail"), Match.when(false, () => null), Match.exhaustive)
1078
+ const verdictExitClass = (score, breakingThreshold) => Match.valueTags(score, {
1079
+ Unscored: () => null,
1080
+ Scored: ({ percentage }) => Option$1.match(Option$1.fromNullishOr(breakingThreshold), {
1081
+ onNone: () => null,
1082
+ onSome: (threshold) => Match.value(percentage < threshold).pipe(Match.when(true, () => "VerdictFail"), Match.when(false, () => null), Match.exhaustive)
1083
+ })
1077
1084
  });
1078
1085
  const decide$9 = (command) => Option$1.match(Option$1.fromNullishOr(verdictExitClass(command.score, command.breakingThreshold)), {
1079
1086
  onNone: () => Option$1.match(precedenceOf(command.pending), {
@@ -1266,13 +1273,13 @@ const restrictSocket = (address) => Match.value(address).pipe(Match.tag("UnixPat
1266
1273
  onTrue: () => Effect$1.void,
1267
1274
  onFalse: () => Effect$1.flatMap(FileSystem.FileSystem, (fs) => fs.chmod(path, 384))
1268
1275
  })), Match.orElse(() => Effect$1.void));
1269
- const TypeId$8 = Symbol.for("~systemfsoftware/stryker-js-plugin-runtime/WorkerServer");
1276
+ const TypeId$7 = Symbol.for("~systemfsoftware/stryker-js-plugin-runtime/WorkerServer");
1270
1277
  const workerServerLayerOf = (params) => Layer.unwrap(Effect$1.gen(function* () {
1271
1278
  const socket = yield* SocketServer.SocketServer;
1272
1279
  yield* restrictSocket(socket.address);
1273
1280
  return RpcServer.layer(params.rpcs).pipe(Layer.provide(params.handlers), Layer.provide(params.schemaServices), Layer.provide(RpcServer.layerProtocolSocketServer), Layer.provide(RpcSerialization.layerNdjson), Layer.provide(traceContextServer));
1274
1281
  }));
1275
- Blueprint.make()(TypeId$8).steps({
1282
+ Blueprint.make()(TypeId$7).steps({
1276
1283
  steps: {},
1277
1284
  targets: { layer: workerServerLayerOf }
1278
1285
  }).is;
@@ -1320,8 +1327,8 @@ var Worker_exports = /* @__PURE__ */ __exportAll$1({
1320
1327
  });
1321
1328
  //#endregion
1322
1329
  //#region src/spawned-socket-worker.handle.ts
1323
- const TypeId$7 = Symbol.for("~systemfsoftware/stryker-js/SpawnedSocketWorker");
1324
- const SpawnedSocketWorker = Handle.make()(TypeId$7);
1330
+ const TypeId$6 = Symbol.for("~systemfsoftware/stryker-js/SpawnedSocketWorker");
1331
+ const SpawnedSocketWorker = Handle.make()(TypeId$6);
1325
1332
  SpawnedSocketWorker.is;
1326
1333
  const make$2 = (worker) => SpawnedSocketWorker.make({
1327
1334
  pid: worker.pid,
@@ -1333,9 +1340,9 @@ const clientLayer = (self) => SpawnedSocketWorker.slot(self).clientLayer;
1333
1340
  var WorkerLauncher = class extends Context.Service()("@systemfsoftware/stryker-js/WorkerLauncher.service/WorkerLauncher") {};
1334
1341
  //#endregion
1335
1342
  //#region src/worker-client.blueprint.ts
1336
- const TypeId$6 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
1343
+ const TypeId$5 = Symbol.for("~systemfsoftware/stryker-js/WorkerClient");
1337
1344
  const connectRetry = Schedule.max([Schedule.spaced(50), Schedule.recurs(100)]);
1338
- const scopedOf$2 = (params) => Effect$1.gen(function* () {
1345
+ const scopedOf$1 = (params) => Effect$1.gen(function* () {
1339
1346
  const launcher = yield* WorkerLauncher;
1340
1347
  const optionsJson = yield* S.encodeEffect(Worker_exports.WorkerOptionsWire)(params.options).pipe(Effect$1.orDie);
1341
1348
  const worker = yield* launcher.spawn({
@@ -1350,9 +1357,9 @@ const scopedOf$2 = (params) => Effect$1.gen(function* () {
1350
1357
  const traceContext = yield* Layer.build(Trace_exports.layerTraceContextClient);
1351
1358
  return yield* RpcClient.make(params.rpcs).pipe(Effect$1.provideContext(Context.merge(protocol, traceContext)));
1352
1359
  });
1353
- const WorkerClients = () => Blueprint.make()(TypeId$6).steps({
1360
+ const WorkerClients = () => Blueprint.make()(TypeId$5).steps({
1354
1361
  steps: {},
1355
- targets: { scoped: scopedOf$2 }
1362
+ targets: { scoped: scopedOf$1 }
1356
1363
  });
1357
1364
  const makeWorkerClient = (params) => WorkerClients().of(params).scoped;
1358
1365
  const ReporterStageTypeId = Symbol.for("@systemfsoftware/stryker-js/ReporterStage");
@@ -1702,7 +1709,10 @@ var VerdictEnvelope = class VerdictEnvelope extends S.Class("VerdictEnvelope")({
1702
1709
  runId,
1703
1710
  mode,
1704
1711
  signal,
1705
- score: Option$1.getOrNull(Option$1.filter(Option$1.some(metrics.mutationScore), (score) => metrics.totalMutants > 0 && Number.isFinite(score))),
1712
+ score: Report_exports.MutationScore.match(metrics.mutationScore, {
1713
+ Scored: ({ percentage }) => percentage,
1714
+ Unscored: () => null
1715
+ }),
1706
1716
  thresholds: {
1707
1717
  high: report.thresholds.high,
1708
1718
  low: report.thresholds.low,
@@ -1740,7 +1750,7 @@ var RunEvents = class extends Context.Service()("@systemfsoftware/stryker-js/run
1740
1750
  var RunIdentity = class extends Context.Service()("@systemfsoftware/stryker-js/run-events.service/RunIdentity") {};
1741
1751
  //#endregion
1742
1752
  //#region package.json
1743
- var version = "12.0.0";
1753
+ var version = "12.1.1";
1744
1754
  //#endregion
1745
1755
  //#region src/stryker-package.schema.ts
1746
1756
  var StrykerPackage = class extends S.Class("StrykerPackage")({
@@ -2032,22 +2042,28 @@ const mutationTestReport = (deps, input) => (results) => Effect$1.gen(function*
2032
2042
  identities
2033
2043
  };
2034
2044
  });
2035
- const determineExitCode = (input) => (metrics) => Effect$1.gen(function* () {
2036
- const { mutationScore } = metrics.metrics;
2045
+ const determineExitCode = (input) => (metrics) => {
2037
2046
  const breaking = input.options.thresholds.break;
2038
- const formattedScore = mutationScore.toFixed(2);
2039
- return yield* Option$1.match(Option$1.fromNullishOr(Result.match(classifyExit(ClassifyExitCommand.make({
2047
+ const score = metrics.metrics.mutationScore;
2048
+ const failure = Option$1.fromNullishOr(Result.match(classifyExit(ClassifyExitCommand.make({
2040
2049
  pending: [],
2041
- score: mutationScore,
2050
+ score,
2042
2051
  breakingThreshold: breaking
2043
2052
  })), {
2044
2053
  onFailure: (refused) => refused,
2045
2054
  onSuccess: (decision) => Match.value(decision).pipe(Match.tag("ExitVerdictFailed", () => "VerdictFail"), Match.orElse(() => null))
2046
- })), {
2047
- onNone: () => Effect$1.map(Match.value(breaking).pipe(Match.when(null, () => Effect$1.logDebug("No breaking threshold configured. Won't fail the build no matter how low your mutation score is. Set `thresholds.break` to change this behavior.")), Match.orElse((threshold) => Effect$1.logInfo(`Final mutation score of ${formattedScore} is greater than or equal to break threshold ${String(threshold)}`))), () => null),
2048
- onSome: (failure) => Effect$1.map(Effect$1.andThen(Effect$1.logError(`Final mutation score ${formattedScore} under breaking threshold ${String(breaking)}, setting exit code to 1 (failure).`), Effect$1.logInfo("(improve mutation score or set `thresholds.break = null` to prevent this error in the future)")), () => failure)
2055
+ }));
2056
+ return Report_exports.MutationScore.match(score, {
2057
+ Scored: ({ percentage }) => Option$1.match(failure, {
2058
+ onNone: () => Effect$1.as(logScoredPass(breaking, percentage), null),
2059
+ onSome: (exitClass) => Effect$1.as(logBroken(breaking, percentage), exitClass)
2060
+ }),
2061
+ Unscored: () => Effect$1.as(logUnscored(breaking), Option$1.getOrNull(failure))
2049
2062
  });
2050
- });
2063
+ };
2064
+ const logScoredPass = (breaking, percentage) => Match.value(breaking).pipe(Match.when(null, () => Effect$1.logDebug("No breaking threshold configured. Won't fail the build no matter how low your mutation score is. Set `thresholds.break` to change this behavior.")), Match.orElse((threshold) => Effect$1.logInfo(`Final mutation score of ${percentage.toFixed(2)} is greater than or equal to break threshold ${String(threshold)}`)));
2065
+ const logUnscored = (breaking) => Match.value(breaking).pipe(Match.when(null, () => Effect$1.void), Match.orElse((threshold) => Effect$1.logInfo(`No valid mutant was tested, so there is no mutation score to hold against break threshold ${String(threshold)}`)));
2066
+ const logBroken = (breaking, percentage) => Effect$1.andThen(Effect$1.logError(`Final mutation score ${percentage.toFixed(2)} under breaking threshold ${String(breaking)}, setting exit code to 1 (failure).`), Effect$1.logInfo("(improve mutation score or set `thresholds.break = null` to prevent this error in the future)"));
2051
2067
  const emitVerdict = (deps, input) => (report) => Effect$1.gen(function* () {
2052
2068
  const envelope = VerdictEnvelope.build(report, input.resolvedMode.mode, input.resolvedMode.signal, input.runId, input.basePath, deps.path);
2053
2069
  yield* Queue.offer(deps.events, VerdictReached.make({
@@ -2079,7 +2095,7 @@ const reportAll = (deps, input) => Effect$1.gen(function* () {
2079
2095
  const verdict = yield* determineExitCode(input)(metrics);
2080
2096
  const finalVerdict = Result.match(classifyExit(ClassifyExitCommand.make({
2081
2097
  pending: [verdict, terminalDrain].filter((candidate) => candidate !== null),
2082
- score: null,
2098
+ score: Report_exports.MutationScore.cases.Unscored.make({}),
2083
2099
  breakingThreshold: null
2084
2100
  })), {
2085
2101
  onFailure: (refused) => refused,
@@ -2431,8 +2447,12 @@ const mutantReportSection = (report, metrics, render) => Boolean$1.match(render.
2431
2447
  },
2432
2448
  onFalse: () => EMPTY_SECTIONS
2433
2449
  });
2450
+ const hasFullScore = (metrics) => Match.valueTags(metrics.mutationScore, {
2451
+ Scored: ({ percentage }) => percentage === 100,
2452
+ Unscored: () => false
2453
+ });
2434
2454
  const partialScoresVisible = (metrics, render) => Boolean$1.match(render.skipFull, {
2435
- onTrue: () => metrics.childResults.some((child) => child.metrics.mutationScore !== 100),
2455
+ onTrue: () => metrics.childResults.some((child) => !hasFullScore(child.metrics)),
2436
2456
  onFalse: () => true
2437
2457
  });
2438
2458
  const drawsScoreTable = (metrics, render) => Boolean$1.match(render.reportScoreTable, {
@@ -2440,14 +2460,14 @@ const drawsScoreTable = (metrics, render) => Boolean$1.match(render.reportScoreT
2440
2460
  onFalse: () => false
2441
2461
  });
2442
2462
  const mutationScoreOf = (scoreType, metrics) => Match.value(scoreType).pipe(Match.when("total", () => metrics.mutationScore), Match.when("covered", () => metrics.mutationScoreBasedOnCoveredCode), Match.exhaustive);
2443
- const scoreText = (scoreType, row) => {
2444
- const score = mutationScoreOf(scoreType, row.metrics);
2445
- return Boolean$1.match(Number.isNaN(score), {
2446
- onTrue: () => "n/a",
2447
- onFalse: () => score.toFixed(2)
2448
- });
2449
- };
2450
- const thresholdTone = (thresholds, score) => Match.value(score).pipe(Match.when((present) => Number.isNaN(present), () => "muted"), Match.when((present) => present >= thresholds.high, () => "positive"), Match.when((present) => present >= thresholds.low, () => "warning"), Match.orElse(() => "negative"));
2463
+ const scoreText = (scoreType, row) => Match.valueTags(mutationScoreOf(scoreType, row.metrics), {
2464
+ Scored: ({ percentage }) => percentage.toFixed(2),
2465
+ Unscored: () => "n/a"
2466
+ });
2467
+ const thresholdTone = (thresholds, score) => Match.valueTags(score, {
2468
+ Scored: ({ percentage }) => Match.value(percentage).pipe(Match.when((value) => value >= thresholds.high, () => "positive"), Match.when((value) => value >= thresholds.low, () => "warning"), Match.orElse(() => "negative")),
2469
+ Unscored: () => "muted"
2470
+ });
2451
2471
  const scoreTone = (thresholds, scoreType, allowColor) => Boolean$1.match(allowColor, {
2452
2472
  onTrue: () => (row) => thresholdTone(thresholds, mutationScoreOf(scoreType, row.metrics)),
2453
2473
  onFalse: () => () => "plain"
@@ -2544,7 +2564,7 @@ const createColumns = (metricsResult, render) => [
2544
2564
  const leafRules = (columns) => columns.flatMap((column) => column.leaves.map((leaf) => [rule("-", slotWidthOf(leaf))]));
2545
2565
  const leafHeaders = (columns) => columns.flatMap((column) => column.leaves.map((leaf) => placedLine(leaf.header, leaf.style, leaf.netWidth)));
2546
2566
  const fullRowVisible = (render, row) => Boolean$1.match(render.skipFull, {
2547
- onTrue: () => row.metrics.mutationScore !== 100,
2567
+ onTrue: () => !hasFullScore(row.metrics),
2548
2568
  onFalse: () => true
2549
2569
  });
2550
2570
  const bodyRow = (columns, row, ancestorCount) => rowOfLines(columns.flatMap((column) => column.leaves.map((leaf) => [placedCell(leaf.cell(row, ancestorCount), leaf.style, leaf.netWidth, leaf.tone(row))])));
@@ -2650,41 +2670,33 @@ const readClearTextReport = (input) => Effect$1.map(Stream.fromAsyncIterable(inp
2650
2670
  }));
2651
2671
  const tint = (color, text) => `${AnsiCode.fields[color].literal}${text}${AnsiCode.fields.reset.literal}`;
2652
2672
  const TINT_BY_TONE = {
2653
- "plain": (text) => text,
2654
- "identifier": (text) => tint("cyan", text),
2655
- "emphasis": (text) => tint("yellow", text),
2656
- "positive": (text) => tint("green", text),
2657
- "warning": (text) => tint("yellow", text),
2658
- "negative": (text) => tint("red", text),
2659
- "muted": (text) => tint("grey", text)
2660
- };
2661
- const runsMergeable = (left, right) => Arr.every([
2662
- left.tone === right.tone,
2663
- left.leftPad === right.leftPad,
2664
- left.rightPad === right.rightPad,
2665
- left.repeat === 1,
2666
- right.repeat === 1
2667
- ], (holds) => holds);
2668
- const mergeInto = (runs, span) => Option$1.match(Arr.last(runs), {
2669
- onNone: () => [span],
2670
- onSome: (last) => Boolean$1.match(runsMergeable(last, span), {
2671
- onTrue: () => [...runs.slice(0, -1), {
2672
- ...last,
2673
- text: `${last.text}${span.text}`
2674
- }],
2675
- onFalse: () => [...runs, span]
2676
- })
2673
+ plain: (text) => text,
2674
+ identifier: (text) => tint("cyan", text),
2675
+ emphasis: (text) => tint("yellow", text),
2676
+ positive: (text) => tint("green", text),
2677
+ warning: (text) => tint("yellow", text),
2678
+ negative: (text) => tint("red", text),
2679
+ muted: (text) => tint("grey", text)
2680
+ };
2681
+ const bytesOf = (span) => `${" ".repeat(span.leftPad)}${span.text.repeat(span.repeat)}${" ".repeat(span.rightPad)}`;
2682
+ const appendSpan = (runs, span) => Option$1.match(Option$1.filter(Arr.last(runs), (last) => last.tone === span.tone), {
2683
+ onNone: () => [...runs, {
2684
+ tone: span.tone,
2685
+ bytes: bytesOf(span)
2686
+ }],
2687
+ onSome: (last) => [...runs.slice(0, -1), {
2688
+ tone: last.tone,
2689
+ bytes: `${last.bytes}${bytesOf(span)}`
2690
+ }]
2677
2691
  });
2678
- const runsOf = (line) => Arr.reduce(line, [], mergeInto);
2679
- const renderSpan = (span) => TINT_BY_TONE[span.tone](`${" ".repeat(span.leftPad)}${span.text.repeat(span.repeat)}${" ".repeat(span.rightPad)}`);
2680
- const renderLine = (line) => runsOf(line).map(renderSpan).join("");
2681
- const renderChunk = (chunk) => chunk.map(renderLine).join("\n");
2682
- const writeChunks = (output, channel, chunks) => output.write(channel, chunks.map((chunk) => `${renderChunk(chunk)}\n`)).pipe(Effect$1.mapError(failAsClearText), Effect$1.asVoid);
2692
+ const renderLine = (line) => Arr.reduce(line, Arr.empty(), appendSpan).map((run) => TINT_BY_TONE[run.tone](run.bytes)).join("");
2693
+ const renderChunk = (chunk) => `${chunk.map(renderLine).join("\n")}\n`;
2694
+ const writeChunks = (output, channel, chunks) => Effect$1.mapError(output.write(channel, chunks.map(renderChunk)), failAsClearText);
2683
2695
  const clearTextReportCell = Sandwich.named("stryker.report.clearText")(readClearTextReport).decide(renderClearTextReport).write({
2684
- ClearTextReportRendered: (rendered, _raw) => Effect$1.gen(function* () {
2696
+ ClearTextReportRendered: (rendered) => Effect$1.gen(function* () {
2685
2697
  const output = yield* ReporterOutput;
2686
2698
  yield* writeChunks(output, "stdout", rendered.stdout);
2687
- yield* Effect$1.forEach(rendered.stderr, (chunk) => writeChunks(output, "stderr", [chunk]), { discard: true });
2699
+ yield* writeChunks(output, "stderr", rendered.stderr);
2688
2700
  }),
2689
2701
  ClearTextReportSuppressed: () => Effect$1.void,
2690
2702
  CommandRejected: ({ issue }) => Effect$1.fail(failAsClearText(issue))
@@ -3697,7 +3709,7 @@ const classifyWorkerExit = Workflow.make({
3697
3709
  });
3698
3710
  //#endregion
3699
3711
  //#region src/worker-protocol.blueprint.ts
3700
- const TypeId$5 = Symbol.for("~systemfsoftware/stryker-js/WorkerProtocol");
3712
+ const TypeId$4 = Symbol.for("~systemfsoftware/stryker-js/WorkerProtocol");
3701
3713
  const droppedConnection = RpcClientError.make({ reason: Socket.SocketReadError.make({ cause: /* @__PURE__ */ new Error("worker connection dropped with the request in flight") }) });
3702
3714
  const layerOf = (socket) => Layer.effect(RpcClient.Protocol, Effect$1.gen(function* () {
3703
3715
  const handlers = MutableHashMap.empty();
@@ -3738,7 +3750,7 @@ const layerOf = (socket) => Layer.effect(RpcClient.Protocol, Effect$1.gen(functi
3738
3750
  send: (clientId, request, transferables) => track(clientId, request).pipe(Effect$1.andThen(inner.send(clientId, request, transferables)))
3739
3751
  });
3740
3752
  }));
3741
- const WorkerProtocol = Blueprint.make()(TypeId$5).steps({
3753
+ const WorkerProtocol = Blueprint.make()(TypeId$4).steps({
3742
3754
  steps: {},
3743
3755
  targets: { layer: (spec) => layerOf(spec.socket) }
3744
3756
  });
@@ -3746,7 +3758,7 @@ const layerWorkerProtocol = (socket) => WorkerProtocol.of({ socket }).layer;
3746
3758
  //#endregion
3747
3759
  //#region src/drivers/node.ts
3748
3760
  const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.tapError((cause) => Effect$1.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect$1.annotateLogs("cause", cause))), Effect$1.catchTag("PlatformError", () => Effect$1.void));
3749
- const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
3761
+ const nodeWorkerLauncherLayer = (childEnv) => Layer.effect(WorkerLauncher, Effect$1.gen(function* () {
3750
3762
  const crypto = yield* Crypto.Crypto;
3751
3763
  const fs = yield* FileSystem.FileSystem;
3752
3764
  const path = yield* Path.Path;
@@ -3765,6 +3777,7 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
3765
3777
  env: {
3766
3778
  STRYKER_WORKER_DIR: workerDir,
3767
3779
  STRYKER_SOCKET: socketPath,
3780
+ ...childEnv,
3768
3781
  ...params.env
3769
3782
  },
3770
3783
  stderr: "inherit"
@@ -3804,7 +3817,8 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
3804
3817
  const nodeFsPathLayer$1 = Layer.mergeAll(NodeFileSystem.layer, NodePath.layer);
3805
3818
  const nodeSpawnerLayer = NodeChildProcessSpawner.layer.pipe(Layer.provide(nodeFsPathLayer$1));
3806
3819
  const nodeBase = Layer.mergeAll(nodeFsPathLayer$1, nodeSpawnerLayer, NodeStdio.layer);
3807
- const nodePlatformLayer = Layer.mergeAll(nodeWorkerLauncherLayer.pipe(Layer.provide(Layer.merge(nodeBase, NodeCrypto.layer))), nodeBase);
3820
+ const makeNodePlatformLayer = (options) => Layer.mergeAll(nodeWorkerLauncherLayer(options.childEnv).pipe(Layer.provide(Layer.merge(nodeBase, NodeCrypto.layer))), nodeBase);
3821
+ const nodePlatformLayer = makeNodePlatformLayer({ childEnv: {} });
3808
3822
  //#endregion
3809
3823
  //#region src/IncrementalDiff.schema.ts
3810
3824
  const PositionSchema$1 = S.Struct({
@@ -4146,138 +4160,6 @@ const admitIncrementalReport = Workflow.make({
4146
4160
  decide: (command) => Result.succeed(decide$6(command))
4147
4161
  });
4148
4162
  //#endregion
4149
- //#region src/VmRunner.blueprint.ts
4150
- const TypeId$4 = Symbol.for("~systemfsoftware/stryker-js/VmTestRunner");
4151
- const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
4152
- const vmRunnerCapabilities = { reloadEnvironment: true };
4153
- const HOST_TIMEOUT_SLACK_MS = 1e3;
4154
- const messageOf$1 = (cause) => cause instanceof Error ? cause.message : new Error("the vm test runner failed", { cause }).message;
4155
- const testResultOf = (test) => {
4156
- const base = {
4157
- id: test.id,
4158
- name: test.name,
4159
- timeSpentMs: test.timeSpentMs
4160
- };
4161
- return Match.value(test.status).pipe(Match.when("failed", () => ({
4162
- ...base,
4163
- status: "failed",
4164
- failureMessage: test.failureMessage ?? ""
4165
- })), Match.when("skipped", () => ({
4166
- ...base,
4167
- status: "skipped"
4168
- })), Match.orElse(() => ({
4169
- ...base,
4170
- status: "success"
4171
- })));
4172
- };
4173
- const dryRunResultOf = (response) => {
4174
- const tests = response.tests.map(testResultOf);
4175
- return Option$1.match(Option$1.fromUndefinedOr(response.mutantCoverage), {
4176
- onNone: () => ({
4177
- status: "complete",
4178
- tests
4179
- }),
4180
- onSome: (mutantCoverage) => ({
4181
- status: "complete",
4182
- tests,
4183
- mutantCoverage
4184
- })
4185
- });
4186
- };
4187
- const respond = (response) => Match.value(response).pipe(Match.discriminator("status")("init-failed", (failed) => Effect$1.fail(TestRunner_exports.TestRunnerFailed.make({
4188
- runnerName: "vm",
4189
- phase: "init",
4190
- cause: failed.message
4191
- }))), Match.discriminator("status")("timeout", () => Effect$1.succeed({ status: "timeout" })), Match.discriminator("status")("error", (errored) => Effect$1.succeed({
4192
- status: "error",
4193
- errorMessage: errored.errorMessage
4194
- })), Match.discriminator("status")("complete", (complete) => Effect$1.succeed(dryRunResultOf(complete))), Match.exhaustive);
4195
- const pooledVmRunner = (config, scope) => {
4196
- let client;
4197
- let sessionTestFiles = config.testFiles;
4198
- const sessionOptions = () => ({
4199
- sandboxWorkingDirectory: config.sandboxWorkingDirectory,
4200
- testFiles: sessionTestFiles
4201
- });
4202
- const spawnClient = Effect$1.try({
4203
- try: () => {
4204
- const spawned = Session.createVmWorkerClient(sessionOptions(), { onExit: () => {
4205
- if (client === spawned) client = void 0;
4206
- } });
4207
- return spawned;
4208
- },
4209
- catch: (cause) => TestRunner_exports.TestRunnerFailed.make({
4210
- runnerName: "vm",
4211
- phase: "init",
4212
- cause: `the vm test runner could not start its worker: ${messageOf$1(cause)}`
4213
- })
4214
- });
4215
- const dropClient = Effect$1.suspend(() => {
4216
- const current = client;
4217
- client = void 0;
4218
- return current === void 0 ? Effect$1.void : Effect$1.promise(() => current.terminate());
4219
- });
4220
- const run = (request) => Effect$1.gen(function* () {
4221
- if (client === void 0) {
4222
- const spawned = yield* spawnClient;
4223
- yield* Scope.addFinalizer(scope, Effect$1.promise(() => spawned.terminate()));
4224
- client = spawned;
4225
- }
4226
- const current = client;
4227
- const answer = yield* Effect$1.tryPromise({
4228
- try: () => current.run(request),
4229
- catch: (cause) => ({
4230
- status: "error",
4231
- errorMessage: messageOf$1(cause)
4232
- })
4233
- }).pipe(Effect$1.catch((failed) => Effect$1.succeed(failed)), Effect$1.timeoutOrElse({
4234
- duration: request.timeoutMs + HOST_TIMEOUT_SLACK_MS,
4235
- orElse: () => dropClient.pipe(Effect$1.as({ status: "timeout" }))
4236
- }));
4237
- return yield* respond(answer);
4238
- }).pipe(Effect$1.onInterrupt(() => dropClient));
4239
- const shouldAdoptTestFiles = () => config.testFiles.length === 0 && client === void 0;
4240
- const adoptedTestFiles = (testFiles) => testFiles ?? [];
4241
- const testFilterFieldOf = (testFilter) => testFilter === void 0 ? {} : { testFilter: [...testFilter] };
4242
- const hitLimitFieldOf = (hitLimit) => hitLimit === void 0 ? {} : { hitLimit };
4243
- const mutantRequestOf = (options) => ({
4244
- kind: "mutant",
4245
- timeoutMs: options.timeout,
4246
- activeMutantId: String(options.activeMutant.id),
4247
- ...testFilterFieldOf(options.testFilter),
4248
- ...hitLimitFieldOf(options.hitLimit),
4249
- reloadEnvironment: options.reloadEnvironment
4250
- });
4251
- return make$3({
4252
- capabilities: Effect$1.succeed(vmRunnerCapabilities),
4253
- init: Effect$1.void,
4254
- dryRun: (options) => {
4255
- if (shouldAdoptTestFiles()) sessionTestFiles = adoptedTestFiles(options.testFiles);
4256
- return run({
4257
- kind: "dry",
4258
- timeoutMs: options.timeout,
4259
- reloadEnvironment: true
4260
- });
4261
- },
4262
- mutantRun: (options) => run(mutantRequestOf(options)).pipe(Effect$1.map((dryRunResult) => interpretDryRunResult(InterpretDryRunResultCommand.make({ dryRunResult }))), Effect$1.flatMap((decided) => Result.match(decided, {
4263
- onFailure: (failure) => Effect$1.fail(failure),
4264
- onSuccess: (decision) => Effect$1.succeed(decision.asResult)
4265
- })), Effect$1.catchTag("TestRunnerFailed", (failure) => Effect$1.succeed({
4266
- status: "error",
4267
- errorMessage: failure.cause
4268
- })))
4269
- });
4270
- };
4271
- const scopedOf$1 = (config) => Effect$1.gen(function* () {
4272
- const scope = yield* Effect$1.scope;
4273
- return pooledVmRunner(config, scope);
4274
- });
4275
- const VmRunners = Blueprint.make()(TypeId$4).steps({
4276
- steps: {},
4277
- targets: { scoped: scopedOf$1 }
4278
- });
4279
- const vmTestRunner = (config) => VmRunners.of(config).scoped;
4280
- //#endregion
4281
4163
  //#region src/read-project.parts.ts
4282
4164
  const ALWAYS_IGNORE = Object.freeze([
4283
4165
  "node_modules",
@@ -4290,23 +4172,9 @@ const ALWAYS_IGNORE = Object.freeze([
4290
4172
  ]);
4291
4173
  const IGNORE_PATTERN_CHARACTER = "!";
4292
4174
  const DEFAULT_GLOB = "**/*.{js,ts,jsx,tsx,html,vue,mjs,mts,cts,cjs}";
4293
- const VITEST_DEFAULT_TEST_FILE_PATTERNS = ["**/*.{test,spec}.{js,jsx,ts,tsx,cjs,cjsx,cts,ctsx,mjs,mjsx,mts,mtsx}"];
4294
- const defaultTestFileIgnores = (tempDirName) => [
4295
- "**/node_modules/**",
4296
- "**/dist/**",
4297
- "**/.{idea,git,cache,output,temp}/**",
4298
- `**/${tempDirName}/**`
4299
- ];
4300
- const shouldDiscoverTestFiles = (options) => options.testFiles.length === 0 && isVmRunner(options.testRunner);
4301
- const testFileSelectionOf = (options) => Boolean.match(shouldDiscoverTestFiles(options), {
4302
- onTrue: () => ({
4303
- testFilePatterns: VITEST_DEFAULT_TEST_FILE_PATTERNS,
4304
- testFileIgnores: defaultTestFileIgnores(options.tempDirName)
4305
- }),
4306
- onFalse: () => ({
4307
- testFilePatterns: options.testFiles,
4308
- testFileIgnores: []
4309
- })
4175
+ const testFileSelectionOf = (options) => ({
4176
+ testFilePatterns: options.testFiles,
4177
+ testFileIgnores: []
4310
4178
  });
4311
4179
  const normalizeFileName = (value) => value.replace(/\\/g, "/");
4312
4180
  const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -4818,8 +4686,11 @@ const formatTotal = (total) => Option$1.match(Option$1.fromNullishOr(total), {
4818
4686
  onSome: (val) => String(val)
4819
4687
  });
4820
4688
  const formatStderrEvent = (event) => Match.value(event).pipe(Match.tag("plan", (e) => `plan ${e.total} mutants`), Match.tag("phase", (e) => `phase ${e.phase}`), Match.tag("tick", (e) => `${e.completed}/${formatTotal(e.total)} elapsed ${e.elapsedMs}ms`), Match.tag("verdict", (e) => `score ${formatScore(e.score)} killed ${e.counts.killed} survived ${e.counts.survived}`), Match.tag("error", (e) => `error ${e.error}`), Match.tag("stream", () => null), Match.tag("mutant", () => null), Match.tag("help", () => null), Match.tag("plugins", () => null), Match.tag("formats", () => null), Match.tag("skipped", () => null), Match.exhaustive);
4821
- const stderrLineFor = (state, event) => Match.value(state.terminalSeen).pipe(Match.when(true, () => null), Match.when(false, () => formatStderrEvent(event)), Match.exhaustive);
4822
- const shouldFrame = (state) => Match.value(state.mode).pipe(Match.when("machine", () => !state.terminalSeen), Match.when("human", () => false), Match.exhaustive);
4689
+ const stderrLineFor = (state, event) => Boolean$1.match(Boolean$1.and(state.mode === "human", !state.terminalSeen), {
4690
+ onTrue: () => formatStderrEvent(event),
4691
+ onFalse: () => null
4692
+ });
4693
+ const shouldFrame = (state) => !state.terminalSeen;
4823
4694
  const decideFrame = (command) => {
4824
4695
  const nextState = noteState(command.state, command.event);
4825
4696
  const stderrLine = stderrLineFor(command.state, command.event);
@@ -4878,7 +4749,10 @@ const formatTemplate = (template, args) => {
4878
4749
  };
4879
4750
  const headOf = (args) => Option$1.fromNullishOr(args[0]);
4880
4751
  const formatArgs = (args) => Option$1.match(Option$1.filter(headOf(args), Predicate$1.isString), {
4881
- onSome: (first) => formatTemplate(first, args.slice(1)),
4752
+ onSome: (first) => Boolean$1.match(args.length === 1, {
4753
+ onTrue: () => first,
4754
+ onFalse: () => formatTemplate(first, args.slice(1))
4755
+ }),
4882
4756
  onNone: () => args.map(inspectValue).join(" ")
4883
4757
  });
4884
4758
  const DEFAULT_CONSOLE_LABEL = "default";
@@ -5530,7 +5404,7 @@ var RunEventDrain = class RunEventDrain extends Context.Service()("@systemfsoftw
5530
5404
  static layer = Layer.effect(RunEventDrain, Effect$1.gen(function* () {
5531
5405
  const stdio = yield* Stdio.Stdio;
5532
5406
  return RunEventDrain.of({
5533
- drainFramed: (framed) => drainOf(stdio, framed),
5407
+ drainFramed: (framed, toStdout) => drainOf(stdio, framed, toStdout),
5534
5408
  setProgressStreamFile: () => Effect$1.void
5535
5409
  });
5536
5410
  }));
@@ -5543,25 +5417,29 @@ var RunEventDrain = class RunEventDrain extends Context.Service()("@systemfsoftw
5543
5417
  };
5544
5418
  const RunEventDrainLive = RunEventDrain.layer;
5545
5419
  const encodeUtf8 = (line) => new TextEncoder().encode(line);
5546
- const drainStdoutAndFile = (fs, path, stdio, fileName, framed) => Effect$1.gen(function* () {
5420
+ const runToSink = (stdio, lines, toStdout) => Boolean$1.match(toStdout, {
5421
+ onTrue: () => Stream.run(lines, stdio.stdout({ endOnDone: true })),
5422
+ onFalse: () => Stream.runDrain(lines)
5423
+ });
5424
+ const drainToSinks = (fs, path, stdio, fileName, toStdout, framed) => Effect$1.gen(function* () {
5547
5425
  yield* fs.makeDirectory(path.dirname(fileName), { recursive: true });
5548
5426
  yield* Effect$1.scoped(Effect$1.gen(function* () {
5549
5427
  const handle = yield* fs.open(fileName, { flag: "w" });
5550
5428
  const withFile = framed.pipe(Stream.tap((line) => handle.writeAll(encodeUtf8(line)).pipe(Effect$1.flatMap(() => handle.sync))));
5551
- yield* Stream.run(withFile, stdio.stdout({ endOnDone: true })).pipe(Effect$1.ignore);
5429
+ yield* runToSink(stdio, withFile, toStdout).pipe(Effect$1.ignore);
5552
5430
  }));
5553
5431
  }).pipe(Effect$1.orDie);
5554
5432
  const drainFileOf = (stdio, fs, path) => Effect$1.gen(function* () {
5555
5433
  const fileNameRef = yield* Ref.make(DEFAULT_PROGRESS_STREAM_FILE);
5556
5434
  return RunEventDrain.of({
5557
- drainFramed: (framed) => Effect$1.gen(function* () {
5435
+ drainFramed: (framed, toStdout) => Effect$1.gen(function* () {
5558
5436
  const fileName = yield* Ref.get(fileNameRef);
5559
- yield* drainStdoutAndFile(fs, path, stdio, fileName, framed);
5437
+ yield* drainToSinks(fs, path, stdio, fileName, toStdout, framed);
5560
5438
  }).pipe(Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_file_failed", cause)), Effect$1.ignoreCause),
5561
5439
  setProgressStreamFile: (fileName) => Ref.set(fileNameRef, fileName)
5562
5440
  });
5563
5441
  });
5564
- const drainOf = (stdio, framed) => Stream.run(framed, stdio.stdout({ endOnDone: true })).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_failed", cause)), Effect$1.ignoreCause);
5442
+ const drainOf = (stdio, framed, toStdout) => runToSink(stdio, framed, toStdout).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_failed", cause)), Effect$1.ignoreCause);
5565
5443
  const writeStderr = (stdio, line) => Stream.run(Stream.succeed(`${line}\n`), stdio.stderr({ endOnDone: false })).pipe(Effect$1.ignore);
5566
5444
  const emitNullScoreVerdict = (params) => {
5567
5445
  const { stream, mode, thresholds, basePath, pathService } = params;
@@ -5708,7 +5586,8 @@ const makeRunEventStream = (resolved) => Effect$1.gen(function* () {
5708
5586
  open: Effect$1.gen(function* () {
5709
5587
  yield* Option$1.match(yield* Ref.get(drainFiberRef), {
5710
5588
  onNone: () => Effect$1.gen(function* () {
5711
- const drainFiber = yield* drain.drainFramed(framed).pipe(Effect$1.forkDetach);
5589
+ const mode = (yield* Ref.get(stateRef)).mode;
5590
+ const drainFiber = yield* drain.drainFramed(framed, mode === "machine").pipe(Effect$1.forkDetach);
5712
5591
  yield* Ref.set(drainFiberRef, Option$1.some(drainFiber));
5713
5592
  }),
5714
5593
  onSome: () => Effect$1.void
@@ -5730,7 +5609,11 @@ const makeRunEventStream = (resolved) => Effect$1.gen(function* () {
5730
5609
  var DryRunError = class extends S.TaggedError()("DryRunError", {
5731
5610
  stage: S.Literals(["dryRun", "dryRunNoTests"]),
5732
5611
  reason: S.String
5733
- }) {};
5612
+ }) {
5613
+ get message() {
5614
+ return this.reason;
5615
+ }
5616
+ };
5734
5617
  var FailedTestSummary = class extends S.Class("FailedTestSummary")({
5735
5618
  name: S.String,
5736
5619
  failureMessage: S.String
@@ -5865,6 +5748,15 @@ const originalFileFor = dual(2, (self, sandboxFileName) => {
5865
5748
  const slot = SandboxHandle.slot(self);
5866
5749
  return originalFileNameOf(sandboxFileName, self.workingDirectory, slot.basePath, slot.pathService);
5867
5750
  });
5751
+ const VM_RUNNER_SPECIFIER = "@systemfsoftware/stryker-js-vm-runner";
5752
+ const vmRunnerOptions = { pool: "threads" };
5753
+ const vmRunnerPluginUrl = () => import.meta.resolve(VM_RUNNER_SPECIFIER);
5754
+ const isVmRunner = (name) => typeof name === "string" && name.toLowerCase() === "vm";
5755
+ const vmTestRunnerConfig = () => ({
5756
+ plugin: vmRunnerPluginUrl(),
5757
+ options: { ...vmRunnerOptions }
5758
+ });
5759
+ const testRunnerConfigOf = (configured) => Match.value(configured).pipe(Match.when(isVmRunner, vmTestRunnerConfig), Match.orElse((unchanged) => unchanged));
5868
5760
  //#endregion
5869
5761
  //#region src/TestRunner.blueprint.ts
5870
5762
  const TypeId$2 = Symbol.for("~systemfsoftware/stryker-js/TestRunner");
@@ -5891,11 +5783,15 @@ const toRunnerFailure = (runnerName, phase) => (error) => Match.value(error).pip
5891
5783
  * can see.
5892
5784
  */
5893
5785
  const scopedOf = (params) => Effect$1.gen(function* () {
5894
- const runnerName = Match.value(params.options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
5895
- const execArgv = Match.value(params.options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => Match.value(runner.nodeArgs).pipe(Match.when(Match.undefined, () => params.options.testRunnerNodeArgs), Match.orElse((args) => args))), Match.orElse(() => params.options.testRunnerNodeArgs));
5786
+ const options = {
5787
+ ...params.options,
5788
+ testRunner: testRunnerConfigOf(params.options.testRunner)
5789
+ };
5790
+ const runnerName = Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
5791
+ const execArgv = Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => Match.value(runner.nodeArgs).pipe(Match.when(Match.undefined, () => options.testRunnerNodeArgs), Match.orElse((args) => args))), Match.orElse(() => options.testRunnerNodeArgs));
5896
5792
  const client = yield* makeWorkerClient({
5897
5793
  rpcs: Plugin_exports.TestRunnerRpcs,
5898
- options: params.options,
5794
+ options,
5899
5795
  entrypoint: params.workerEntrypoint,
5900
5796
  workingDirectory: params.sandboxWorkingDirectory,
5901
5797
  execArgv: [...execArgv],
@@ -5919,10 +5815,7 @@ const TestRunners = Blueprint.make()(TypeId$2).steps({
5919
5815
  });
5920
5816
  const makeChildProcessTestRunner = (params) => TestRunners.of(params).scoped;
5921
5817
  const commandRunnerEffect = (context) => ChildProcessSpawner.ChildProcessSpawner.pipe(Effect$1.map((spawner) => commandRunner(context, spawner).pipe(withTimeout, withRetry)));
5922
- const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option$1.some(commandRunnerEffect(context))), Match.when(isVmRunner, () => Option$1.some(vmTestRunner({
5923
- testFiles: context.testFiles,
5924
- sandboxWorkingDirectory: context.sandboxWorkingDirectory
5925
- }))), Match.orElse(() => Option$1.none()));
5818
+ const inProcessRunner = (context) => Match.value(context.options.testRunner).pipe(Match.when(isCommandRunner, () => Option$1.some(commandRunnerEffect(context))), Match.orElse(() => Option$1.none()));
5926
5819
  const buildTestRunner = dual(2, (context, childProcessRunner) => Option$1.match(inProcessRunner(context), {
5927
5820
  onSome: (inProcess) => inProcess,
5928
5821
  onNone: () => Effect$1.gen(function* () {
@@ -6081,7 +5974,7 @@ const resolveConfiguredPlugin = Workflow.make({
6081
5974
  //#endregion
6082
5975
  //#region src/run/dry-run.parts.ts
6083
5976
  const sandboxPathsOf = (sandbox, fileNames) => Result.all(fileNames.map((fileName) => sandboxFileFor(sandbox, fileName)));
6084
- const configuredPluginOf$1 = (configured) => Match.value(configured).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
5977
+ const configuredPluginOf$1 = (configured) => Match.value(testRunnerConfigOf(configured)).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
6085
5978
  const workerSpawnOf$1 = (stage, loaded, kind, configured) => Effect$1.mapError(Effect$1.fromResult(resolveConfiguredPlugin(WorkerSpawnCommand.make({
6086
5979
  sources: loaded.pluginSources,
6087
5980
  kind,
@@ -6095,7 +5988,11 @@ const optionalSandboxPathsOf = (command) => Boolean$1.match(command.options.test
6095
5988
  onTrue: () => Result.succeed(void 0),
6096
5989
  onFalse: () => sandboxPathsOf(command.sandbox, command.project.testFiles)
6097
5990
  });
6098
- const buildDryRunFiles = (command) => Result.flatMap(sandboxPathsOf(command.sandbox, [...MutableHashMap.keys(command.project.filesToMutate)]), (files) => Result.map(optionalSandboxPathsOf(command), (testFiles) => ({
5991
+ const mutatedFileNamesOf = (command) => {
5992
+ const mutated = MutableHashSet.fromIterable(command.mutants.map((mutant) => mutant.fileName));
5993
+ return [...MutableHashMap.keys(command.project.filesToMutate)].filter((name) => MutableHashSet.has(mutated, name));
5994
+ };
5995
+ const buildDryRunFiles = (command) => Result.flatMap(sandboxPathsOf(command.sandbox, mutatedFileNamesOf(command)), (files) => Result.map(optionalSandboxPathsOf(command), (testFiles) => ({
6099
5996
  files,
6100
5997
  testFiles
6101
5998
  })));
@@ -6326,14 +6223,11 @@ const dryRunCell = Sandwich.named("stryker.dry_run")(readDryRun).decide(dryRun).
6326
6223
  });
6327
6224
  //#endregion
6328
6225
  //#region src/plan-instrumentation.workflow.ts
6329
- var InstrumentError = class extends S.TaggedError()("InstrumentError", {
6330
- stage: S.Literal("instrument"),
6331
- reason: S.String
6332
- }) {};
6226
+ const Count = S.Int.check(S.isGreaterThanOrEqualTo(0));
6333
6227
  var InstrumentCommand = class extends S.TaggedClass()("InstrumentCommand", {
6334
- fileCount: S.Finite,
6228
+ fileCount: Count,
6335
6229
  inPlace: S.Boolean,
6336
- pluginCount: S.Finite
6230
+ pluginCount: Count
6337
6231
  }) {
6338
6232
  static [Workflow.InstrumentationBrand] = {
6339
6233
  fileCount: "stryker.instrument.file_count",
@@ -6344,32 +6238,28 @@ const InstrumentDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/Instrum
6344
6238
  var InPlaceInstrument = class extends S.TaggedClass()("InPlaceInstrument", {
6345
6239
  workingDirectoryHint: S.String,
6346
6240
  backupDirectoryHint: S.String,
6347
- fileCount: S.Finite
6241
+ fileCount: Count
6348
6242
  }) {
6349
6243
  [InstrumentDecisionTypeId] = InstrumentDecisionTypeId;
6350
6244
  };
6351
6245
  var EphemeralInstrument = class extends S.TaggedClass()("EphemeralInstrument", {
6352
6246
  workingDirectoryHint: S.String,
6353
- fileCount: S.Finite
6247
+ fileCount: Count
6354
6248
  }) {
6355
6249
  [InstrumentDecisionTypeId] = InstrumentDecisionTypeId;
6356
6250
  };
6357
- const commandShape = (command) => Match.value(command.fileCount === 0).pipe(Match.when(true, () => "empty"), Match.when(false, () => Match.value(command.inPlace).pipe(Match.when(true, () => "inPlace"), Match.when(false, () => "ephemeral"), Match.exhaustive)), Match.exhaustive);
6358
- const decide$3 = (command) => Match.value(commandShape(command)).pipe(Match.when("empty", () => Result.fail(InstrumentError.make({
6359
- stage: "instrument",
6360
- reason: "No files to instrument."
6361
- }))), Match.when("inPlace", () => Result.succeed(InPlaceInstrument.make({
6251
+ const decide$3 = (command) => Match.value(command.inPlace).pipe(Match.when(true, () => Result.succeed(InPlaceInstrument.make({
6362
6252
  workingDirectoryHint: "inPlace",
6363
6253
  backupDirectoryHint: "backup",
6364
6254
  fileCount: command.fileCount
6365
- }))), Match.when("ephemeral", () => Result.succeed(EphemeralInstrument.make({
6255
+ }))), Match.when(false, () => Result.succeed(EphemeralInstrument.make({
6366
6256
  workingDirectoryHint: "temp",
6367
6257
  fileCount: command.fileCount
6368
6258
  }))), Match.exhaustive);
6369
6259
  const planInstrumentation = Workflow.make({
6370
6260
  command: InstrumentCommand,
6371
6261
  decision: S.Union([InPlaceInstrument, EphemeralInstrument]),
6372
- error: InstrumentError,
6262
+ error: S.Never,
6373
6263
  decide: decide$3
6374
6264
  });
6375
6265
  //#endregion
@@ -7117,14 +7007,6 @@ const instrumentCell = Sandwich.named("stryker.instrument")((command) => Effect$
7117
7007
  })).decide(planInstrumentation).write({
7118
7008
  InPlaceInstrument: (_decision, raw) => writeInstrument(raw),
7119
7009
  EphemeralInstrument: (_decision, raw) => writeInstrument(raw),
7120
- InstrumentError: ({ stage, reason }, raw) => enteringInstrumentPhase(raw, Effect$1.fail(StageError.make({
7121
- stage,
7122
- reason,
7123
- cause: InstrumentError.make({
7124
- stage,
7125
- reason
7126
- })
7127
- }))),
7128
7010
  CommandRejected: ({ issue }) => Effect$1.fail(StageError.make({
7129
7011
  stage: "instrument",
7130
7012
  reason: issue
@@ -7149,7 +7031,11 @@ var MutationTestCommand = class extends S.TaggedClass()("MutationTestCommand", {
7149
7031
  var MutationTestError = class extends S.TaggedError()("MutationTestError", {
7150
7032
  stage: S.Literal("mutationTest"),
7151
7033
  reason: S.String
7152
- }) {};
7034
+ }) {
7035
+ get message() {
7036
+ return this.reason;
7037
+ }
7038
+ };
7153
7039
  const MutationTestDecisionTypeId = Symbol.for("@systemfsoftware/stryker-js/MutationTestDecision");
7154
7040
  var MutationTestProceed = class extends S.TaggedClass()("MutationTestProceed", {}) {
7155
7041
  [MutationTestDecisionTypeId] = MutationTestDecisionTypeId;
@@ -7586,8 +7472,9 @@ const toReportedMutant = (mutant) => Object.assign(mutant, {
7586
7472
  static: mutant.static
7587
7473
  });
7588
7474
  const CHECKER_ACQUIRE_RETRIES = 2;
7475
+ const TEST_RUNNER_POOL_IDLE_TIME_TO_LIVE = Duration.minutes(1);
7589
7476
  const isCheckerCrash = (error) => Match.value(error).pipe(Match.tag("ChildProcessCrashedError", "OutOfMemoryError", () => true), Match.orElse(() => false));
7590
- const configuredPluginOf = (configured) => Match.value(configured).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
7477
+ const configuredPluginOf = (configured) => Match.value(testRunnerConfigOf(configured)).pipe(Match.when(Options_exports.isCustomTestRunner, (custom) => ConfiguredPluginModulePath.make({ modulePath: custom.plugin })), Match.orElse((name) => ConfiguredPluginName.make({ name })));
7591
7478
  const workerSpawnOf = (stage, loaded, kind, configured) => Effect$1.mapError(Effect$1.fromResult(resolveConfiguredPlugin(WorkerSpawnCommand.make({
7592
7479
  sources: loaded.pluginSources,
7593
7480
  kind,
@@ -7781,13 +7668,17 @@ const checkerBreachToStageError = (error) => Match.value(error).pipe(Match.tag("
7781
7668
  cause: breach
7782
7669
  })), Match.exhaustive);
7783
7670
  const invalidateSlot = (pool, slot, error) => Effect$1.flatMap(Pool.invalidate(pool, slot), () => Effect$1.fail(error));
7784
- const checkSlotPlans = (pool, slot, checker, checkerName, currentPlans) => checkGroupedPlans(checker, checkerName, currentPlans).pipe(Effect$1.catchTags({
7785
- OutOfMemoryError: (error) => invalidateSlot(pool, slot, error),
7786
- ChildProcessCrashedError: (error) => invalidateSlot(pool, slot, error),
7787
- CheckerFailed: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
7788
- CheckerAnsweredUnrequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
7789
- CheckerSkippedRequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail)
7671
+ const onCheckerSlot = (pool, checkerIndex, run) => Pool.use(pool, (slot) => Option$1.match(Option$1.fromUndefinedOr(slot[checkerIndex]), {
7672
+ onNone: () => Effect$1.die(/* @__PURE__ */ new Error(`checker slot has no entry at index ${checkerIndex}`)),
7673
+ onSome: ({ checker }) => run(checker).pipe(Effect$1.catchTags({
7674
+ OutOfMemoryError: (error) => invalidateSlot(pool, slot, error),
7675
+ ChildProcessCrashedError: (error) => invalidateSlot(pool, slot, error),
7676
+ CheckerFailed: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
7677
+ CheckerAnsweredUnrequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail),
7678
+ CheckerSkippedRequested: (error) => error.pipe(checkerBreachToStageError, Effect$1.fail)
7679
+ }))
7790
7680
  }));
7681
+ const checkGroupsConcurrently = (pool, checkerIndex, checkerName, currentPlans) => Effect$1.flatMap(onCheckerSlot(pool, checkerIndex, (checker) => groupPlans(checker, checkerName, currentPlans)), (groups) => Effect$1.map(Effect$1.forEach(groups, (group) => onCheckerSlot(pool, checkerIndex, (checker) => checkPlans(checker, checkerName, group)), { concurrency: "unbounded" }), (perGroup) => perGroup.flat()));
7791
7682
  const isFailedCheck = (check) => check[1].status !== "passed";
7792
7683
  const splitCheckedPlans = (checked, reporting) => {
7793
7684
  const failures = checked.filter(isFailedCheck);
@@ -7797,18 +7688,15 @@ const splitCheckedPlans = (checked, reporting) => {
7797
7688
  results
7798
7689
  }));
7799
7690
  };
7800
- const stepOneChecker = (pool, slot, checker, checkerName, currentPlans, reporting) => checkSlotPlans(pool, slot, checker, checkerName, currentPlans).pipe(Effect$1.flatMap((checked) => splitCheckedPlans(checked, reporting)));
7691
+ const stepOneChecker = (pool, checkerIndex, checkerName, currentPlans, reporting) => checkGroupsConcurrently(pool, checkerIndex, checkerName, currentPlans).pipe(Effect$1.flatMap((checked) => splitCheckedPlans(checked, reporting)));
7801
7692
  const emptyRunResults = [];
7802
- const runConfiguredCheckers = (pool, plans, reporting) => Effect$1.scoped(Effect$1.gen(function* () {
7803
- const slot = yield* Pool.get(pool);
7804
- return yield* Effect$1.reduce(slot, () => ({
7805
- passedPlans: plans,
7806
- checkerResults: emptyRunResults
7807
- }), (acc, { checkerName, checker }) => Effect$1.map(stepOneChecker(pool, slot, checker, checkerName, acc.passedPlans, reporting), (split) => ({
7808
- passedPlans: split.passed,
7809
- checkerResults: [...acc.checkerResults, ...split.results]
7810
- })));
7811
- }));
7693
+ const runConfiguredCheckers = (pool, plans, reporting) => Effect$1.flatMap(Pool.use(pool, (slot) => Effect$1.succeed(slot.map(({ checkerName }) => checkerName))), (checkerNames) => Effect$1.reduce(checkerNames, () => ({
7694
+ passedPlans: plans,
7695
+ checkerResults: emptyRunResults
7696
+ }), (acc, checkerName, checkerIndex) => Effect$1.map(stepOneChecker(pool, checkerIndex, checkerName, acc.passedPlans, reporting), (split) => ({
7697
+ passedPlans: split.passed,
7698
+ checkerResults: [...acc.checkerResults, ...split.results]
7699
+ }))));
7812
7700
  const checkPlansWithConfiguredCheckers = (checkerPool, plans, reporting) => Option$1.match(Option$1.fromNullishOr(checkerPool), {
7813
7701
  onNone: () => Effect$1.succeed({
7814
7702
  passedPlans: plans,
@@ -7816,6 +7704,14 @@ const checkPlansWithConfiguredCheckers = (checkerPool, plans, reporting) => Opti
7816
7704
  }),
7817
7705
  onSome: (pool) => runConfiguredCheckers(pool, plans, reporting)
7818
7706
  });
7707
+ const checkerResourcesInOwnScope = (acquire) => Effect$1.gen(function* () {
7708
+ const checkerScope = yield* Scope.make();
7709
+ yield* Effect$1.addFinalizer(() => Scope.close(checkerScope, Exit.void));
7710
+ return {
7711
+ resources: yield* acquire.pipe(Scope.provide(checkerScope)),
7712
+ releaseInBackground: Scope.close(checkerScope, Exit.void).pipe(Effect$1.forkScoped({ uninterruptible: true }))
7713
+ };
7714
+ });
7819
7715
  const isPlannable = (mutant) => Result.isSuccess(S.decodeResult(CheckerMutantFromMutant)(mutant));
7820
7716
  const DROPPED_IDS_IN_WARNING = 5;
7821
7717
  const configuredTestFilesOf = (run) => run.options.testFiles.length === 0 ? [] : run.project.testFiles;
@@ -7861,14 +7757,15 @@ const writeMutationTestDryRunOnly = Effect$1.gen(function* () {
7861
7757
  });
7862
7758
  const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
7863
7759
  const prev = raw.prev;
7760
+ const testRunnerCapacity = prev.concurrency.testRunners + prev.concurrency.checkers;
7864
7761
  const { dropped, plannable: plannableMutants } = partitionPlannable(prev.mutants);
7865
7762
  yield* reportDroppedMutants(dropped);
7866
7763
  yield* phaseEntered("mutation-test");
7867
7764
  const idGenerator = yield* IdGenerator;
7868
7765
  const env = yield* RunEnvironment;
7869
- const checkerPool = yield* makeCheckerPool(prev, env.basePath);
7766
+ const scopedCheckers = yield* checkerResourcesInOwnScope(makeCheckerPool(prev, env.basePath));
7870
7767
  const testFiles = yield* Effect$1.map(sandboxFilesOf(prev.sandbox, configuredTestFilesOf(prev)), (pairs) => pairs.map(([, sandboxFileName]) => sandboxFileName));
7871
- const testRunnerPool = yield* Pool.make({
7768
+ const testRunnerPool = yield* Pool.makeWithTTL({
7872
7769
  acquire: buildTestRunner({
7873
7770
  options: prev.options,
7874
7771
  fileDescriptions: prev.project.fileDescriptions,
@@ -7886,7 +7783,9 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
7886
7783
  idGenerator
7887
7784
  })));
7888
7785
  })),
7889
- size: prev.concurrency.testRunners
7786
+ min: prev.concurrency.testRunners,
7787
+ max: testRunnerCapacity,
7788
+ timeToLive: TEST_RUNNER_POOL_IDLE_TIME_TO_LIVE
7890
7789
  });
7891
7790
  const reporting = yield* MutationReporting;
7892
7791
  const sandboxFileByName = Object.fromEntries(yield* sandboxFilesOf(prev.sandbox, [...MutableHashMap.keys(prev.project.filesToMutate)]));
@@ -7929,7 +7828,8 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
7929
7828
  })).pipe(Effect$1.ignoreCause);
7930
7829
  const progressQueue = yield* RunEvents;
7931
7830
  yield* Queue.offer(progressQueue, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
7932
- const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(checkerPool, sortedPlans, reporting);
7831
+ const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(scopedCheckers.resources, sortedPlans, reporting);
7832
+ const checkerRelease = yield* scopedCheckers.releaseInBackground;
7933
7833
  const testRunnerStream = Stream.fromIterable(passedPlans);
7934
7834
  const plannedTotal = sortedPlans.length + noCoverageResults.length + rememberedResults.length;
7935
7835
  const completedRef = yield* Ref.make(0);
@@ -8030,7 +7930,7 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
8030
7930
  yield* offerStreamTested(reported, finished, prepared);
8031
7931
  yield* persist(reported);
8032
7932
  return reported;
8033
- })), { concurrency: Math.max(1, prev.concurrency.testRunners) }).pipe(Stream.runCollect, Effect$1.map((chunk) => [...chunk])));
7933
+ })), { concurrency: Math.max(1, testRunnerCapacity) }).pipe(Stream.runCollect, Effect$1.map((chunk) => [...chunk])));
8034
7934
  const allResults = [
8035
7935
  ...rememberedResults,
8036
7936
  ...noCoverageResults,
@@ -8038,6 +7938,7 @@ const writeMutationTestProceed = (raw) => Effect$1.gen(function* () {
8038
7938
  ...runResults
8039
7939
  ];
8040
7940
  const outcomeResult = yield* reporting.reportAll(reportingInputOf(prev, env, allResults));
7941
+ yield* Fiber.await(checkerRelease);
8041
7942
  const doneNow = yield* Clock.currentTimeMillis;
8042
7943
  const elapsed = Duration.millis(doneNow - env.runStartedAt);
8043
7944
  yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
@@ -8517,7 +8418,7 @@ const pluginUrlsFromOptions = (options) => [
8517
8418
  ...options.plugins,
8518
8419
  ...options.appendPlugins,
8519
8420
  ...options.ignorers,
8520
- ...Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => [runner.plugin]), Match.orElse(() => [])),
8421
+ ...Match.value(options.testRunner).pipe(Match.when(Options_exports.isCustomTestRunner, (runner) => [runner.plugin]), Match.when(isVmRunner, () => [vmRunnerPluginUrl()]), Match.orElse(() => [])),
8521
8422
  ...options.checkers.map((checker) => checker.plugin)
8522
8423
  ];
8523
8424
  //#endregion
@@ -8817,4 +8718,4 @@ const strykerCell = dual((args) => Predicate$1.isObject(args[0]), (options, targ
8817
8718
  })
8818
8719
  })), Effect$1.scoped));
8819
8720
  //#endregion
8820
- export { ExtendsStepResolve as $, VerdictMutant as A, FileMatcher as B, mergeConfigs as C, RunEvents as D, IdGenerator as E, makeWorkerClient as F, ConfigFileUnsupportedError as G, ConfigFileInvalidError as H, WorkerLauncher as I, ConfigDocumentSchema as J, createDefaultOptions as K, make$2 as L, MetricsResultFromReport as M, reporterWorkerFactory as N, RunIdentity as O, spawnReporterWorker as P, ExtendsStepRefused as Q, StrykerError as R, initialExtendsStepState as S, RunEnvironment as T, ConfigFileNotFoundError as U, ConfigError as V, ConfigFileUnreadableError as W, ExtendsStepDone as X, ExtendsStepDocumentSchema as Y, ExtendsStepRead as Z, readConfig as _, RunEventDrainLive as a, extendsPropertySchema as at, forkCoreSchema as b, isVmRunner as c, checkGroupedPlans as ct, nodePlatformLayer as d, WorkerBootTimeoutError as dt, ExtendsStepStateSchema as et, layerWorkerProtocol as f, CheckerAnsweredUnrequested as ft, loadConfigCell as g, classifyWorkerExit as h, RunEventDrain as i, ReadConfigCommand as it, VerdictThresholds as j, VerdictEnvelope as k, vmTestRunner as l, ChildProcessCrashedError as lt, ClassifyWorkerExitDecision as m, strykerCell as n, MergeCommand as nt, makeRunEventStream as o, forkOptionsSchema as ot, ClassifyWorkerExitCommand as p, CheckerSkippedRequested as pt, defaultOptions as q, buildTestRunner as r, MergeResult as rt, RunEventWireLine as s, survivorsPriorReport as st, mutationTestCell as t, ImportedModuleSchema as tt, IncrementalReportSchema as u, OutOfMemoryError as ut, decideExtendsStep as v, validateOptions as w, importModule as x, describeErrors as y, isCommandRunner as z };
8721
+ export { ExtendsStepDone as $, RunEvents as A, make$2 as B, forkCoreSchema as C, validateOptions as D, mergeConfigs as E, MetricsResultFromReport as F, ConfigFileInvalidError as G, isCommandRunner as H, reporterWorkerFactory as I, ConfigFileUnsupportedError as J, ConfigFileNotFoundError as K, spawnReporterWorker as L, VerdictEnvelope as M, VerdictMutant as N, RunEnvironment as O, VerdictThresholds as P, ExtendsStepDocumentSchema as Q, makeWorkerClient as R, describeErrors as S, initialExtendsStepState as T, FileMatcher as U, StrykerError as V, ConfigError as W, defaultOptions as X, createDefaultOptions as Y, ConfigDocumentSchema as Z, ClassifyWorkerExitDecision as _, isVmRunner as a, MergeCommand as at, readConfig as b, vmTestRunnerConfig as c, extendsPropertySchema as ct, makeRunEventStream as d, checkGroupedPlans as dt, ExtendsStepRead as et, RunEventWireLine as f, ChildProcessCrashedError as ft, ClassifyWorkerExitCommand as g, CheckerSkippedRequested as gt, layerWorkerProtocol as h, CheckerAnsweredUnrequested as ht, makeChildProcessTestRunner as i, ImportedModuleSchema as it, RunIdentity as j, IdGenerator as k, RunEventDrain as l, forkOptionsSchema as lt, nodePlatformLayer as m, WorkerBootTimeoutError as mt, strykerCell as n, ExtendsStepResolve as nt, testRunnerConfigOf as o, MergeResult as ot, IncrementalReportSchema as p, OutOfMemoryError as pt, ConfigFileUnreadableError as q, buildTestRunner as r, ExtendsStepStateSchema as rt, vmRunnerPluginUrl as s, ReadConfigCommand as st, mutationTestCell as t, ExtendsStepRefused as tt, RunEventDrainLive as u, survivorsPriorReport as ut, classifyWorkerExit as v, importModule as w, decideExtendsStep as x, loadConfigCell as y, WorkerLauncher as z };