headlamp 0.1.5 → 0.1.8

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.
package/dist/cli.cjs CHANGED
@@ -93,7 +93,7 @@ var init_TimeoutError = __esm({
93
93
 
94
94
  // node_modules/es-toolkit/dist/promise/delay.mjs
95
95
  function delay(ms, { signal } = {}) {
96
- return new Promise((resolve8, reject) => {
96
+ return new Promise((resolve9, reject) => {
97
97
  const abortError = () => {
98
98
  reject(new AbortError());
99
99
  };
@@ -106,7 +106,7 @@ function delay(ms, { signal } = {}) {
106
106
  }
107
107
  const timeoutId = setTimeout(() => {
108
108
  signal?.removeEventListener("abort", abortHandler);
109
- resolve8();
109
+ resolve9();
110
110
  }, ms);
111
111
  signal?.addEventListener("abort", abortHandler, { once: true });
112
112
  });
@@ -171,11 +171,11 @@ var init_exec = __esm({
171
171
  child.stderr?.on("data", (chunk) => {
172
172
  stderr += String(chunk);
173
173
  });
174
- const exec = new Promise((resolve8, reject) => {
174
+ const exec = new Promise((resolve9, reject) => {
175
175
  child.on("error", reject);
176
176
  child.on(
177
177
  "close",
178
- (code) => Number(code) === 0 ? resolve8(stdout) : reject(new Error(stderr || `exit ${code}`))
178
+ (code) => Number(code) === 0 ? resolve9(stdout) : reject(new Error(stderr || `exit ${code}`))
179
179
  );
180
180
  });
181
181
  try {
@@ -195,7 +195,7 @@ var init_exec = __esm({
195
195
  throw caughtError;
196
196
  }
197
197
  };
198
- runExitCode = async (cmd, args, opts = {}) => new Promise((resolve8, reject) => {
198
+ runExitCode = async (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
199
199
  const child = (0, import_node_child_process.spawn)(cmd, [...args], {
200
200
  cwd: opts.cwd,
201
201
  env: opts.env,
@@ -204,9 +204,9 @@ var init_exec = __esm({
204
204
  windowsHide: true
205
205
  });
206
206
  child.on("error", reject);
207
- child.on("close", (code) => resolve8(Number(code)));
207
+ child.on("close", (code) => resolve9(Number(code)));
208
208
  });
209
- runWithCapture = async (cmd, args, opts) => new Promise((resolve8, reject) => {
209
+ runWithCapture = async (cmd, args, opts) => new Promise((resolve9, reject) => {
210
210
  const child = (0, import_node_child_process.spawn)(cmd, [...args], {
211
211
  cwd: opts.cwd,
212
212
  env: opts.env,
@@ -222,7 +222,7 @@ var init_exec = __esm({
222
222
  buf += String(chunk);
223
223
  });
224
224
  child.on("error", reject);
225
- child.on("close", (code) => resolve8({ code: Number(code), output: buf }));
225
+ child.on("close", (code) => resolve9({ code: Number(code), output: buf }));
226
226
  });
227
227
  }
228
228
  });
@@ -263,7 +263,8 @@ var init_args = __esm({
263
263
  coverageMode: (value) => ({ type: "coverageMode", value }),
264
264
  coverageMaxFiles: (value) => ({ type: "coverageMaxFiles", value }),
265
265
  coverageMaxHotspots: (value) => ({ type: "coverageMaxHotspots", value }),
266
- coveragePageFit: (value) => ({ type: "coveragePageFit", value })
266
+ coveragePageFit: (value) => ({ type: "coveragePageFit", value }),
267
+ changed: (value) => ({ type: "changed", value })
267
268
  };
268
269
  Some = (value) => ({ _tag: "some", value });
269
270
  None = { _tag: "none" };
@@ -460,6 +461,18 @@ var init_args = __esm({
460
461
  "--coverage.root=",
461
462
  (value) => step([ActionBuilders.coverageRoot((value.split("=")[1] ?? "").trim())])
462
463
  ),
464
+ // --changed flag: selects changed files via git (all|staged|unstaged)
465
+ rule.eq("--changed", () => step([ActionBuilders.changed("all")])),
466
+ rule.startsWith("--changed=", (value) => {
467
+ const raw = (value.split("=")[1] ?? "").trim().toLowerCase();
468
+ const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
469
+ return step([ActionBuilders.changed(mode)]);
470
+ }),
471
+ rule.withLookahead("--changed", (_flag, lookahead) => {
472
+ const raw = String(lookahead).trim().toLowerCase();
473
+ const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
474
+ return step([ActionBuilders.changed(mode)], true);
475
+ }),
463
476
  rule.withLookahead(
464
477
  "-t",
465
478
  (flag, lookahead) => step(
@@ -562,6 +575,8 @@ var init_args = __esm({
562
575
  return { vitest: [], jest: [], coverage: false, coverageMaxHotspots: action.value };
563
576
  case "coveragePageFit":
564
577
  return { vitest: [], jest: [], coverage: false, coveragePageFit: action.value };
578
+ case "changed":
579
+ return { vitest: [], jest: [], coverage: false, changed: action.value };
565
580
  case "jestArg":
566
581
  return { vitest: [], jest: [action.value], coverage: false };
567
582
  case "vitestArg":
@@ -601,6 +616,7 @@ var init_args = __esm({
601
616
  }
602
617
  return {
603
618
  ...next,
619
+ ...right.changed !== void 0 || left.changed !== void 0 ? { changed: right.changed ?? left.changed } : {},
604
620
  ...right.coverageAbortOnFailure !== void 0 || left.coverageAbortOnFailure !== void 0 ? { coverageAbortOnFailure: right.coverageAbortOnFailure ?? left.coverageAbortOnFailure } : {},
605
621
  ...right.coverageDetail !== void 0 || left.coverageDetail !== void 0 ? { coverageDetail: right.coverageDetail ?? left.coverageDetail } : {},
606
622
  ...right.coverageShowCode !== void 0 || left.coverageShowCode !== void 0 ? { coverageShowCode: right.coverageShowCode ?? left.coverageShowCode } : {},
@@ -686,7 +702,8 @@ var init_args = __esm({
686
702
  ...coverageMaxHotspotsLocal !== void 0 ? { coverageMaxHotspots: coverageMaxHotspotsLocal } : {},
687
703
  coveragePageFit,
688
704
  ...contrib.editorCmd !== void 0 ? { editorCmd: contrib.editorCmd } : {},
689
- ...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {}
705
+ ...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {},
706
+ ...contrib.changed !== void 0 ? { changed: contrib.changed } : {}
690
707
  };
691
708
  return out;
692
709
  };
@@ -1960,14 +1977,13 @@ var require_lib = __commonJS({
1960
1977
  });
1961
1978
 
1962
1979
  // src/lib/program.ts
1963
- var path9 = __toESM(require("node:path"), 1);
1980
+ var path10 = __toESM(require("node:path"), 1);
1964
1981
  var os2 = __toESM(require("node:os"), 1);
1965
1982
  var fsSync3 = __toESM(require("node:fs"), 1);
1966
- var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
1967
1983
  var fs5 = __toESM(require("node:fs/promises"), 1);
1968
1984
  var LibReport = __toESM(require("istanbul-lib-report"), 1);
1969
- var import_text = __toESM(require("istanbul-reports/lib/text"), 1);
1970
- var import_text_summary = __toESM(require("istanbul-reports/lib/text-summary"), 1);
1985
+ var Reports = __toESM(require("istanbul-reports"), 1);
1986
+ var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
1971
1987
  init_env_utils();
1972
1988
  init_exec();
1973
1989
  init_args();
@@ -2922,7 +2938,7 @@ var compositeBarPct = (summary, hotspots) => {
2922
2938
  };
2923
2939
 
2924
2940
  // src/lib/coverage-print.ts
2925
- var path7 = __toESM(require("node:path"), 1);
2941
+ var path8 = __toESM(require("node:path"), 1);
2926
2942
  var fsSync2 = __toESM(require("node:fs"), 1);
2927
2943
  init_env_utils();
2928
2944
  init_exec();
@@ -3092,6 +3108,71 @@ var renderTable = (columns, rows) => {
3092
3108
  };
3093
3109
  var barCell = (pct) => (padded) => bar(pct, padded.length);
3094
3110
 
3111
+ // src/lib/relevance.ts
3112
+ var path7 = __toESM(require("node:path"), 1);
3113
+ init_args();
3114
+ init_fast_related();
3115
+ var normalizeAbs = (inputPath) => path7.resolve(inputPath).replace(/\\/g, "/");
3116
+ var compareBooleanDesc = (left, right) => {
3117
+ if (left === right) {
3118
+ return 0;
3119
+ }
3120
+ return right ? 1 : -1;
3121
+ };
3122
+ var compareNumberAsc = (left, right) => left - right;
3123
+ var compareStringAsc = (left, right) => left.localeCompare(right);
3124
+ var fileFailed = (file) => Boolean(
3125
+ (file.status ?? "") === "failed" || (file.testResults ?? []).some((assertion) => (assertion.status ?? "") === "failed")
3126
+ );
3127
+ var composeComparators = (...comparators) => (left, right) => {
3128
+ for (const cmp of comparators) {
3129
+ const result = cmp(left, right);
3130
+ if (result !== 0) {
3131
+ return result;
3132
+ }
3133
+ }
3134
+ return 0;
3135
+ };
3136
+ var comparatorForRank = (rankByPath) => {
3137
+ const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
3138
+ return composeComparators(
3139
+ (left, right) => compareBooleanDesc(fileFailed(left), fileFailed(right)),
3140
+ (left, right) => compareNumberAsc(
3141
+ rankOrInf(normalizeAbs(left.testFilePath)),
3142
+ rankOrInf(normalizeAbs(right.testFilePath))
3143
+ ),
3144
+ (left, right) => compareStringAsc(normalizeAbs(left.testFilePath), normalizeAbs(right.testFilePath))
3145
+ );
3146
+ };
3147
+ var computeDirectnessRank = async (opts) => {
3148
+ const selectionKey = opts.productionSeeds.map((abs) => path7.relative(opts.repoRoot, abs).replace(/\\/g, "/")).sort((left, right) => left.localeCompare(right)).join("|");
3149
+ const related = await cachedRelated({
3150
+ repoRoot: opts.repoRoot,
3151
+ selectionKey,
3152
+ compute: () => findRelatedTestsFast({
3153
+ repoRoot: opts.repoRoot,
3154
+ productionPaths: opts.productionSeeds,
3155
+ testGlobs: DEFAULT_TEST_GLOBS,
3156
+ excludeGlobs: opts.excludeGlobs ?? DEFAULT_EXCLUDE,
3157
+ timeoutMs: 1500
3158
+ })
3159
+ });
3160
+ const out = /* @__PURE__ */ new Map();
3161
+ related.forEach((abs, index) => {
3162
+ out.set(normalizeAbs(abs), index);
3163
+ });
3164
+ return out;
3165
+ };
3166
+ var sortTestResultsWithRank = (rankByPath, results) => results.slice().sort(comparatorForRank(rankByPath));
3167
+ var comparatorForPathRank = (rankByPath) => {
3168
+ const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
3169
+ return composeComparators(
3170
+ (left, right) => compareNumberAsc(rankOrInf(normalizeAbs(left)), rankOrInf(normalizeAbs(right))),
3171
+ (left, right) => compareStringAsc(normalizeAbs(left), normalizeAbs(right))
3172
+ );
3173
+ };
3174
+ var sortPathsWithRank = (rankByPath, paths) => paths.slice().sort(comparatorForPathRank(rankByPath));
3175
+
3095
3176
  // src/lib/coverage-print.ts
3096
3177
  var printDetailedCoverage = async (opts) => {
3097
3178
  const files = opts.map.files().sort((fileA, fileB) => {
@@ -3102,7 +3183,7 @@ var printDetailedCoverage = async (opts) => {
3102
3183
  for (const abs of files) {
3103
3184
  const fc = opts.map.fileCoverageFor(abs);
3104
3185
  const sum = fc.toSummary();
3105
- const rel = path7.relative(opts.root, abs).replace(/\\/g, "/");
3186
+ const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
3106
3187
  const blocks = computeUncoveredBlocks(fc);
3107
3188
  const misses = missedBranches(fc);
3108
3189
  const missFns = missedFunctions(fc);
@@ -3111,9 +3192,9 @@ var printDetailedCoverage = async (opts) => {
3111
3192
  const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
3112
3193
  const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
3113
3194
  linesPctText
3114
- )} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
3115
- sum.functions.pct
3116
- )(funcsPctText)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
3195
+ )} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
3196
+ funcsPctText
3197
+ )} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
3117
3198
  console.info(header);
3118
3199
  const max = opts.limitPerFile === "all" ? Number.POSITIVE_INFINITY : opts.limitPerFile ?? 5;
3119
3200
  const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
@@ -3140,10 +3221,8 @@ var printDetailedCoverage = async (opts) => {
3140
3221
  abs,
3141
3222
  block.start,
3142
3223
  opts.editorCmd
3143
- )}\x07${path7.basename(abs)}:${block.start}\x1B]8;;\x07`;
3144
- const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(
3145
- `L${block.end}`
3146
- )} ${link}`;
3224
+ )}\x07${path8.basename(abs)}:${block.start}\x1B]8;;\x07`;
3225
+ const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(`L${block.end}`)} ${link}`;
3147
3226
  console.info(label);
3148
3227
  if (opts.showCode && src.length) {
3149
3228
  const lines = src.split(/\r?\n/);
@@ -3163,7 +3242,7 @@ var printDetailedCoverage = async (opts) => {
3163
3242
  abs,
3164
3243
  fn.line,
3165
3244
  opts.editorCmd
3166
- )}\x07${path7.basename(abs)}:${fn.line}\x1B]8;;\x07`;
3245
+ )}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`;
3167
3246
  console.info(` - ${fn.name} @ ${link}`);
3168
3247
  }
3169
3248
  }
@@ -3174,12 +3253,8 @@ var printDetailedCoverage = async (opts) => {
3174
3253
  abs,
3175
3254
  br.line,
3176
3255
  opts.editorCmd
3177
- )}\x07${path7.basename(abs)}:${br.line}\x1B]8;;\x07`;
3178
- console.info(
3179
- ` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(
3180
- ", "
3181
- )}]`
3182
- );
3256
+ )}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`;
3257
+ console.info(` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(", ")}]`);
3183
3258
  }
3184
3259
  }
3185
3260
  console.info("");
@@ -3199,7 +3274,7 @@ var printCompactCoverage = async (opts) => {
3199
3274
  for (const abs of files.slice(0, fileCap)) {
3200
3275
  const fc = opts.map.fileCoverageFor(abs);
3201
3276
  const sum = fc.toSummary();
3202
- const rel = path7.relative(opts.root, abs).replace(/\\/g, "/");
3277
+ const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
3203
3278
  const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
3204
3279
  const secondLength = secondRange.end - secondRange.start;
3205
3280
  const firstLength = firstRange.end - firstRange.start;
@@ -3213,9 +3288,9 @@ var printCompactCoverage = async (opts) => {
3213
3288
  const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
3214
3289
  const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
3215
3290
  linesPctText
3216
- )} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
3217
- sum.functions.pct
3218
- )(funcsPctText)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
3291
+ )} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
3292
+ funcsPctText
3293
+ )} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
3219
3294
  console.info(header);
3220
3295
  const hotspots = blocks.slice(0, maxHotspotsDerived);
3221
3296
  if (hotspots.length) {
@@ -3226,10 +3301,8 @@ var printCompactCoverage = async (opts) => {
3226
3301
  abs,
3227
3302
  hotspot.start,
3228
3303
  opts.editorCmd
3229
- )}\x07${path7.basename(abs)}:${hotspot.start}\x1B]8;;\x07`;
3230
- console.info(
3231
- ` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`
3232
- );
3304
+ )}\x07${path8.basename(abs)}:${hotspot.start}\x1B]8;;\x07`;
3305
+ console.info(` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`);
3233
3306
  }
3234
3307
  }
3235
3308
  const functionsList = missFns.slice(0, maxFunctionsDerived);
@@ -3241,7 +3314,7 @@ var printCompactCoverage = async (opts) => {
3241
3314
  abs,
3242
3315
  fn.line,
3243
3316
  opts.editorCmd
3244
- )}\x07${path7.basename(abs)}:${fn.line}\x1B]8;;\x07`
3317
+ )}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`
3245
3318
  );
3246
3319
  }
3247
3320
  }
@@ -3256,7 +3329,7 @@ var printCompactCoverage = async (opts) => {
3256
3329
  abs,
3257
3330
  br.line,
3258
3331
  opts.editorCmd
3259
- )}\x07${path7.basename(abs)}:${br.line}\x1B]8;;\x07`
3332
+ )}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`
3260
3333
  );
3261
3334
  }
3262
3335
  }
@@ -3265,9 +3338,7 @@ var printCompactCoverage = async (opts) => {
3265
3338
  const restBrs = Math.max(0, misses.length - branchesList.length);
3266
3339
  if (restHs + restFns + restBrs > 0) {
3267
3340
  console.info(
3268
- ansi.dim(
3269
- ` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`
3270
- )
3341
+ ansi.dim(` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`)
3271
3342
  );
3272
3343
  }
3273
3344
  console.info("");
@@ -3304,7 +3375,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3304
3375
  return { stem: base.slice(0, -ending.length), ext: ending };
3305
3376
  }
3306
3377
  }
3307
- const ext2 = path7.extname(base);
3378
+ const ext2 = path8.extname(base);
3308
3379
  return { stem: base.slice(0, -ext2.length), ext: ext2 };
3309
3380
  };
3310
3381
  const sliceBalanced = (input, width) => {
@@ -3387,12 +3458,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3387
3458
  const tailParts = tailSrc.map((segment) => segment);
3388
3459
  let hidAny = false;
3389
3460
  const build = () => {
3390
- const label2 = joinParts(
3391
- headParts,
3392
- tailParts,
3393
- hideMiddle2 || hidAny,
3394
- baseLabel
3395
- );
3461
+ const label2 = joinParts(headParts, tailParts, hideMiddle2 || hidAny, baseLabel);
3396
3462
  return { label: label2, width: visibleWidth(label2) };
3397
3463
  };
3398
3464
  let { label, width } = build();
@@ -3485,13 +3551,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3485
3551
  return { headRaw: headRaw2, tailRaw: tailRaw2, hideMiddle: hideMiddle2 };
3486
3552
  };
3487
3553
  let { headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tailCount);
3488
- let candidate = tryTrimDirsToFit(
3489
- headRaw,
3490
- tailRaw,
3491
- hideMiddle,
3492
- baseFull,
3493
- maxWidth
3494
- );
3554
+ let candidate = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
3495
3555
  if (!candidate) {
3496
3556
  return baseFull;
3497
3557
  }
@@ -3500,13 +3560,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3500
3560
  if (headCount + tailCount < total) {
3501
3561
  const tryTail = Math.min(tailCount + 1, total - headCount);
3502
3562
  ({ headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tryTail));
3503
- const candTail = tryTrimDirsToFit(
3504
- headRaw,
3505
- tailRaw,
3506
- hideMiddle,
3507
- baseFull,
3508
- maxWidth
3509
- );
3563
+ const candTail = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
3510
3564
  if (candTail) {
3511
3565
  tailCount = tryTail;
3512
3566
  candidate = candTail;
@@ -3516,13 +3570,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3516
3570
  if (!advanced && headCount + tailCount < total) {
3517
3571
  const tryHead = Math.min(headCount + 1, total - tailCount);
3518
3572
  ({ headRaw, tailRaw, hideMiddle } = buildRaw(tryHead, tailCount));
3519
- const candHead = tryTrimDirsToFit(
3520
- headRaw,
3521
- tailRaw,
3522
- hideMiddle,
3523
- baseFull,
3524
- maxWidth
3525
- );
3573
+ const candHead = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
3526
3574
  if (candHead) {
3527
3575
  headCount = tryHead;
3528
3576
  candidate = candHead;
@@ -3584,7 +3632,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
3584
3632
  const queue = [];
3585
3633
  const seen = /* @__PURE__ */ new Set();
3586
3634
  for (const testAbs of executedTestsAbs) {
3587
- const testPathNormalized = path7.resolve(testAbs).replace(/\\/g, "/");
3635
+ const testPathNormalized = path8.resolve(testAbs).replace(/\\/g, "/");
3588
3636
  dist.set(testPathNormalized, 0);
3589
3637
  queue.push([testPathNormalized, 0]);
3590
3638
  }
@@ -3603,12 +3651,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
3603
3651
  const specs = await extractImportSpecs2(currentFile, specsCache);
3604
3652
  const nextDistance = currentDistance + 1;
3605
3653
  for (const spec of specs) {
3606
- const resolved = resolveImportWithRoot(
3607
- currentFile,
3608
- spec,
3609
- rootDir,
3610
- resolutionCache
3611
- );
3654
+ const resolved = resolveImportWithRoot(currentFile, spec, rootDir, resolutionCache);
3612
3655
  const usable = resolved && !resolved.includes("/node_modules/");
3613
3656
  if (usable) {
3614
3657
  const existing = dist.get(resolved);
@@ -3623,13 +3666,10 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
3623
3666
  return dist;
3624
3667
  };
3625
3668
  var renderPerFileCompositeTable = async (opts) => {
3626
- const rel = path7.relative(opts.root, opts.absPath).replace(/\\/g, "/");
3669
+ const rel = path8.relative(opts.root, opts.absPath).replace(/\\/g, "/");
3627
3670
  const sum = opts.file.toSummary();
3628
3671
  const rowsAvail = typeof process.stdout.rows === "number" && process.stdout.rows > 10 ? process.stdout.rows : 40;
3629
- const tableBudget = Math.max(
3630
- 14,
3631
- Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8)
3632
- );
3672
+ const tableBudget = Math.max(14, Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8));
3633
3673
  const rowBudget = Math.max(6, tableBudget - 6);
3634
3674
  const blocks = computeUncoveredBlocks(opts.file).slice().sort((firstRange, secondRange) => {
3635
3675
  const firstLength = firstRange.end - firstRange.start;
@@ -3673,9 +3713,7 @@ var renderPerFileCompositeTable = async (opts) => {
3673
3713
  rows.push([
3674
3714
  cell(
3675
3715
  rel,
3676
- (padded) => ansi.dim(
3677
- shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length)
3678
- )
3716
+ (padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
3679
3717
  ),
3680
3718
  cell("Totals", ansi.dim),
3681
3719
  cell("\u2014", ansi.dim),
@@ -3694,11 +3732,7 @@ var renderPerFileCompositeTable = async (opts) => {
3694
3732
  rows.push([
3695
3733
  cell(
3696
3734
  rel,
3697
- (padded) => ansi.dim(
3698
- shortenPathPreservingFilename(rel, padded.length).padEnd(
3699
- padded.length
3700
- )
3701
- )
3735
+ (padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
3702
3736
  ),
3703
3737
  cell("Hotspots", ansi.dim),
3704
3738
  cell("", ansi.dim),
@@ -3712,14 +3746,8 @@ var renderPerFileCompositeTable = async (opts) => {
3712
3746
  rows.push([
3713
3747
  cell(rel, (padded) => {
3714
3748
  const width = padded.length;
3715
- const display = shortenPathPreservingFilename(rel, width).padEnd(
3716
- width
3717
- );
3718
- return linkifyPadded(
3719
- opts.absPath,
3720
- hotspotRange.start,
3721
- opts.editorCmd
3722
- )(display);
3749
+ const display = shortenPathPreservingFilename(rel, width).padEnd(width);
3750
+ return linkifyPadded(opts.absPath, hotspotRange.start, opts.editorCmd)(display);
3723
3751
  }),
3724
3752
  cell("Hotspot"),
3725
3753
  cell(`L${hotspotRange.start}\u2013L${hotspotRange.end}`),
@@ -3736,11 +3764,7 @@ var renderPerFileCompositeTable = async (opts) => {
3736
3764
  rows.push([
3737
3765
  cell(
3738
3766
  rel,
3739
- (padded) => ansi.dim(
3740
- shortenPathPreservingFilename(rel, padded.length).padEnd(
3741
- padded.length
3742
- )
3743
- )
3767
+ (padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
3744
3768
  ),
3745
3769
  cell("Functions", ansi.dim),
3746
3770
  cell("", ansi.dim),
@@ -3754,14 +3778,8 @@ var renderPerFileCompositeTable = async (opts) => {
3754
3778
  rows.push([
3755
3779
  cell(rel, (padded) => {
3756
3780
  const width = padded.length;
3757
- const display = shortenPathPreservingFilename(rel, width).padEnd(
3758
- width
3759
- );
3760
- return linkifyPadded(
3761
- opts.absPath,
3762
- missedFunction.line,
3763
- opts.editorCmd
3764
- )(display);
3781
+ const display = shortenPathPreservingFilename(rel, width).padEnd(width);
3782
+ return linkifyPadded(opts.absPath, missedFunction.line, opts.editorCmd)(display);
3765
3783
  }),
3766
3784
  cell("Func"),
3767
3785
  cell(`L${missedFunction.line}`),
@@ -3778,11 +3796,7 @@ var renderPerFileCompositeTable = async (opts) => {
3778
3796
  rows.push([
3779
3797
  cell(
3780
3798
  rel,
3781
- (padded) => ansi.dim(
3782
- shortenPathPreservingFilename(rel, padded.length).padEnd(
3783
- padded.length
3784
- )
3785
- )
3799
+ (padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
3786
3800
  ),
3787
3801
  cell("Branches", ansi.dim),
3788
3802
  cell("", ansi.dim),
@@ -3796,14 +3810,8 @@ var renderPerFileCompositeTable = async (opts) => {
3796
3810
  rows.push([
3797
3811
  cell(rel, (padded) => {
3798
3812
  const width = padded.length;
3799
- const display = shortenPathPreservingFilename(rel, width).padEnd(
3800
- width
3801
- );
3802
- return linkifyPadded(
3803
- opts.absPath,
3804
- missedBranch.line,
3805
- opts.editorCmd
3806
- )(display);
3813
+ const display = shortenPathPreservingFilename(rel, width).padEnd(width);
3814
+ return linkifyPadded(opts.absPath, missedBranch.line, opts.editorCmd)(display);
3807
3815
  }),
3808
3816
  cell("Branch"),
3809
3817
  cell(`L${missedBranch.line}`),
@@ -3811,9 +3819,7 @@ var renderPerFileCompositeTable = async (opts) => {
3811
3819
  cell(""),
3812
3820
  cell(""),
3813
3821
  cell(""),
3814
- cell(
3815
- `#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`
3816
- )
3822
+ cell(`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`)
3817
3823
  ]);
3818
3824
  }
3819
3825
  }
@@ -3833,9 +3839,7 @@ var renderPerFileCompositeTable = async (opts) => {
3833
3839
  rows.push([
3834
3840
  cell(rel, (padded) => {
3835
3841
  const width = padded.length;
3836
- const display = shortenPathPreservingFilename(rel, width).padEnd(
3837
- width
3838
- );
3842
+ const display = shortenPathPreservingFilename(rel, width).padEnd(width);
3839
3843
  return linkifyPadded(opts.absPath, ln, opts.editorCmd)(display);
3840
3844
  }),
3841
3845
  cell("Line"),
@@ -3848,16 +3852,7 @@ var renderPerFileCompositeTable = async (opts) => {
3848
3852
  ]);
3849
3853
  }
3850
3854
  while (rows.length < target) {
3851
- rows.push([
3852
- cell(""),
3853
- cell(""),
3854
- cell(""),
3855
- cell(""),
3856
- cell(""),
3857
- cell(""),
3858
- cell(""),
3859
- cell("")
3860
- ]);
3855
+ rows.push([cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell("")]);
3861
3856
  }
3862
3857
  }
3863
3858
  }
@@ -3865,20 +3860,17 @@ var renderPerFileCompositeTable = async (opts) => {
3865
3860
  console.info(table);
3866
3861
  const sep = ansi.gray(
3867
3862
  "\u2500".repeat(
3868
- Math.max(
3869
- 20,
3870
- typeof process.stdout.columns === "number" ? process.stdout.columns : 100
3871
- )
3863
+ Math.max(20, typeof process.stdout.columns === "number" ? process.stdout.columns : 100)
3872
3864
  )
3873
3865
  );
3874
3866
  console.info(sep);
3875
3867
  };
3876
3868
  var printPerFileCompositeTables = async (opts) => {
3877
3869
  const selectionAbs = (opts.selectionPaths ?? []).map(
3878
- (selPath) => path7.resolve(selPath).replace(/\\/g, "/")
3870
+ (selPath) => path8.resolve(selPath).replace(/\\/g, "/")
3879
3871
  );
3880
3872
  const changedAbs = (opts.changedFiles ?? []).map(
3881
- (chgPath) => path7.resolve(chgPath).replace(/\\/g, "/")
3873
+ (chgPath) => path8.resolve(chgPath).replace(/\\/g, "/")
3882
3874
  );
3883
3875
  const tokenizeForSimilarity = (filePathForTokens) => new Set(
3884
3876
  filePathForTokens.toLowerCase().replace(/[^a-z0-9/_\-.]/g, " ").split(/[/_.-]+/).filter(Boolean)
@@ -3894,15 +3886,15 @@ var printPerFileCompositeTables = async (opts) => {
3894
3886
  return intersectionCount / unionSize;
3895
3887
  };
3896
3888
  const isSameDirOrChild = (firstAbs, secondAbs) => {
3897
- const dirA = path7.dirname(firstAbs).replace(/\\/g, "/");
3898
- const dirB = path7.dirname(secondAbs).replace(/\\/g, "/");
3889
+ const dirA = path8.dirname(firstAbs).replace(/\\/g, "/");
3890
+ const dirB = path8.dirname(secondAbs).replace(/\\/g, "/");
3899
3891
  return dirA === dirB || dirB.startsWith(`${dirA}/`) || dirA.startsWith(`${dirB}/`);
3900
3892
  };
3901
3893
  const selectionTokens = selectionAbs.map(tokenizeForSimilarity);
3902
3894
  const changedTokens = changedAbs.map(tokenizeForSimilarity);
3903
- const executedTestsAbs = (opts.executedTests ?? []).map((testPath) => path7.resolve(testPath).replace(/\\/g, "/")).filter((absPath) => absPath.length > 0);
3895
+ const executedTestsAbs = (opts.executedTests ?? []).map((testPath) => path8.resolve(testPath).replace(/\\/g, "/")).filter((absPath) => absPath.length > 0);
3904
3896
  const testTokens = executedTestsAbs.map(tokenizeForSimilarity);
3905
- const allMapFilesAbs = opts.map.files().map((absPath) => path7.resolve(absPath).replace(/\\/g, "/"));
3897
+ const allMapFilesAbs = opts.map.files().map((absPath) => path8.resolve(absPath).replace(/\\/g, "/"));
3906
3898
  const uncoveredCandidates = allMapFilesAbs.filter((absPath) => {
3907
3899
  const sum = opts.map.fileCoverageFor(absPath).toSummary();
3908
3900
  return !(sum.lines.pct >= 100 && sum.functions.pct >= 100 && sum.branches.pct >= 100);
@@ -3919,33 +3911,24 @@ var printPerFileCompositeTables = async (opts) => {
3919
3911
  const selectionSetAbs = new Set(selectionAbs);
3920
3912
  const scored = await Promise.all(
3921
3913
  candidates.map(async (abs) => {
3922
- const rel = path7.relative(opts.root, abs).replace(/\\/g, "/");
3914
+ const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
3923
3915
  const sum = opts.map.fileCoverageFor(abs).toSummary();
3924
3916
  const pct = Number.isFinite(sum.lines.pct) ? sum.lines.pct : 0;
3925
- const absNorm = path7.resolve(abs).replace(/\\/g, "/");
3917
+ const absNorm = path8.resolve(abs).replace(/\\/g, "/");
3926
3918
  const selfTokens = tokenizeForSimilarity(absNorm);
3927
3919
  const selSim = Math.max(
3928
3920
  0,
3929
- ...selectionTokens.map(
3930
- (selectionTokenSet) => jaccard(selfTokens, selectionTokenSet)
3931
- )
3921
+ ...selectionTokens.map((selectionTokenSet) => jaccard(selfTokens, selectionTokenSet))
3932
3922
  );
3933
3923
  const chgSim = Math.max(
3934
3924
  0,
3935
- ...changedTokens.map(
3936
- (changedTokenSet) => jaccard(selfTokens, changedTokenSet)
3937
- )
3938
- );
3939
- const tstSim = Math.max(
3940
- 0,
3941
- ...testTokens.map((tset) => jaccard(selfTokens, tset))
3925
+ ...changedTokens.map((changedTokenSet) => jaccard(selfTokens, changedTokenSet))
3942
3926
  );
3927
+ const tstSim = Math.max(0, ...testTokens.map((tset) => jaccard(selfTokens, tset)));
3943
3928
  const nearSelection = selectionAbs.some(
3944
3929
  (selectionPath) => isSameDirOrChild(absNorm, selectionPath)
3945
3930
  );
3946
- const nearChanged = changedAbs.some(
3947
- (changedPath) => isSameDirOrChild(absNorm, changedPath)
3948
- );
3931
+ const nearChanged = changedAbs.some((changedPath) => isSameDirOrChild(absNorm, changedPath));
3949
3932
  const related = selSim > 0 || chgSim > 0 || nearSelection || nearChanged;
3950
3933
  const distance = selectionSetAbs.has(absNorm) ? 0 : distFromTests.get(absNorm) ?? INF;
3951
3934
  let group = 6;
@@ -3969,9 +3952,12 @@ var printPerFileCompositeTables = async (opts) => {
3969
3952
  return { abs: absNorm, rel, linesPct: pct, group, score, distance };
3970
3953
  })
3971
3954
  );
3972
- let files = scored.sort(
3973
- (left, right) => left.group - right.group || left.distance - right.distance || right.score - left.score || right.linesPct - left.linesPct || left.rel.localeCompare(right.rel)
3974
- ).map((scoredItem) => scoredItem.abs);
3955
+ const prodSeeds = selectionAbs.length > 0 ? selectionAbs : changedAbs;
3956
+ const rank = await computeDirectnessRank({ repoRoot: opts.root, productionSeeds: prodSeeds });
3957
+ let files = sortPathsWithRank(
3958
+ rank,
3959
+ scored.map((s) => s.abs)
3960
+ );
3975
3961
  if (selectionAbs.length > 0) {
3976
3962
  const selectionSet = new Set(selectionAbs);
3977
3963
  const selectedHead = files.filter((filePath) => selectionSet.has(filePath));
@@ -3994,7 +3980,7 @@ var printPerFileCompositeTables = async (opts) => {
3994
3980
  };
3995
3981
 
3996
3982
  // src/lib/jest-bridge.ts
3997
- var path8 = __toESM(require("node:path"), 1);
3983
+ var path9 = __toESM(require("node:path"), 1);
3998
3984
  var fs4 = __toESM(require("node:fs"), 1);
3999
3985
  var util = __toESM(require("node:util"), 1);
4000
3986
  var import_json5 = __toESM(require_lib(), 1);
@@ -4069,7 +4055,7 @@ var extractBridgePath = (raw, cwd) => {
4069
4055
  return null;
4070
4056
  }
4071
4057
  const jsonPath = matches[matches.length - 1][1].trim().replace(/^["'`]|["'`]$/g, "");
4072
- return path8.isAbsolute(jsonPath) ? jsonPath : path8.resolve(cwd, jsonPath);
4058
+ return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
4073
4059
  };
4074
4060
  var drawRule = (label) => {
4075
4061
  const width = Math.max(
@@ -4668,7 +4654,7 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
4668
4654
  const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
4669
4655
  if (loc) {
4670
4656
  const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
4671
- out.push(` ${ansi.dim("at")} ${osc8(`${path8.basename(loc.file)}:${loc.line}`, href)}`);
4657
+ out.push(` ${ansi.dim("at")} ${osc8(`${path9.basename(loc.file)}:${loc.line}`, href)}`);
4672
4658
  }
4673
4659
  out.push("");
4674
4660
  return out;
@@ -4947,7 +4933,7 @@ function renderVitestFromJestJSON(data, opts) {
4947
4933
  const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
4948
4934
  const locLink = deepestLoc && (() => {
4949
4935
  const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, opts?.editorCmd);
4950
- const base = `${path8.basename(deepestLoc.file)}:${deepestLoc.line}`;
4936
+ const base = `${path9.basename(deepestLoc.file)}:${deepestLoc.line}`;
4951
4937
  return osc8(base, href);
4952
4938
  })();
4953
4939
  const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
@@ -4992,13 +4978,8 @@ ${footer}`;
4992
4978
  }
4993
4979
 
4994
4980
  // src/lib/program.ts
4995
- var import_meta = {};
4996
4981
  var jestBin = "./node_modules/.bin/jest";
4997
4982
  var babelNodeBin = "./node_modules/.bin/babel-node";
4998
- var moduleSpecifierForRequire = (
4999
- // @ts-ignore
5000
- typeof __filename !== "undefined" ? __filename : import_meta.url
5001
- );
5002
4983
  var registerSignalHandlersOnce = () => {
5003
4984
  let handled = false;
5004
4985
  const on = (sig) => {
@@ -5016,7 +4997,6 @@ Received ${sig}, exiting...
5016
4997
  };
5017
4998
  var isDebug = () => Boolean(process.env.TEST_CLI_DEBUG);
5018
4999
  var mergeLcov = async () => {
5019
- const jestLcovPath = "coverage/jest/lcov.info";
5020
5000
  const vitestLcovPath = "coverage/vitest/lcov.info";
5021
5001
  const mergedOutPath = "coverage/lcov.info";
5022
5002
  const readOrEmpty = async (filePath) => {
@@ -5027,7 +5007,7 @@ var mergeLcov = async () => {
5027
5007
  }
5028
5008
  };
5029
5009
  let vitestContent = "";
5030
- let jestContent = "";
5010
+ const jestParts = [];
5031
5011
  try {
5032
5012
  vitestContent = await readOrEmpty(vitestLcovPath);
5033
5013
  } catch (readVitestError) {
@@ -5035,20 +5015,46 @@ var mergeLcov = async () => {
5035
5015
  console.info(`read vitest lcov failed: ${String(readVitestError)}`);
5036
5016
  }
5037
5017
  }
5018
+ const collectLcovs = (dir) => {
5019
+ const out = [];
5020
+ try {
5021
+ const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
5022
+ for (const entry of entries) {
5023
+ const full = path10.join(dir, entry.name);
5024
+ if (entry.isDirectory()) {
5025
+ out.push(...collectLcovs(full));
5026
+ } else if (entry.isFile() && entry.name === "lcov.info") {
5027
+ out.push(full);
5028
+ }
5029
+ }
5030
+ } catch {
5031
+ }
5032
+ return out;
5033
+ };
5038
5034
  try {
5039
- jestContent = await readOrEmpty(jestLcovPath);
5035
+ const jestRoot = path10.join("coverage", "jest");
5036
+ const candidates = [path10.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
5037
+ for (const filePath of candidates) {
5038
+ try {
5039
+ const content = await readOrEmpty(filePath);
5040
+ if (content.trim()) {
5041
+ jestParts.push(content.trim());
5042
+ }
5043
+ } catch {
5044
+ }
5045
+ }
5040
5046
  } catch (readJestError) {
5041
5047
  if (isDebug()) {
5042
- console.info(`read jest lcov failed: ${String(readJestError)}`);
5048
+ console.info(`scan jest lcov failed: ${String(readJestError)}`);
5043
5049
  }
5044
5050
  }
5045
- if (!vitestContent && !jestContent) {
5051
+ if (!vitestContent && jestParts.length === 0) {
5046
5052
  if (isDebug()) {
5047
5053
  console.info("No coverage outputs found to merge.");
5048
5054
  }
5049
5055
  return;
5050
5056
  }
5051
- const merged = [vitestContent.trim(), jestContent.trim()].filter(Boolean).join("\n");
5057
+ const merged = [vitestContent.trim(), ...jestParts].filter(Boolean).join("\n");
5052
5058
  if (merged.length > 0) {
5053
5059
  await (await import("node:fs/promises")).mkdir("coverage", { recursive: true });
5054
5060
  await (await import("node:fs/promises")).writeFile(mergedOutPath, `${merged}
@@ -5061,23 +5067,40 @@ var mergeLcov = async () => {
5061
5067
  }
5062
5068
  };
5063
5069
  var emitMergedCoverage = async (ui, opts) => {
5064
- const jestJson = path9.join("coverage", "jest", "coverage-final.json");
5065
- const jSize = fsSync3.existsSync(jestJson) ? fsSync3.statSync(jestJson).size : -1;
5066
- const jestSizeLabel = jSize >= 0 ? `${jSize} bytes` : "missing";
5067
- if (isDebug()) {
5068
- console.info(`Coverage JSON probe \u2192 jest: ${jestSizeLabel}`);
5069
- }
5070
- const jestData = await readCoverageJson(jestJson);
5071
- const jestFilesCount = Object.keys(jestData).length;
5072
- if (isDebug()) {
5073
- console.info(`Decoded coverage entries \u2192 jest: ${jestFilesCount}`);
5074
- }
5075
5070
  const map = (0, import_istanbul_lib_coverage2.createCoverageMap)({});
5076
- if (jestFilesCount > 0) {
5071
+ const listJsons = (dir) => {
5072
+ const out = [];
5073
+ try {
5074
+ const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
5075
+ for (const entry of entries) {
5076
+ const full = path10.join(dir, entry.name);
5077
+ if (entry.isDirectory()) {
5078
+ out.push(...listJsons(full));
5079
+ } else if (entry.isFile() && entry.name === "coverage-final.json") {
5080
+ out.push(full);
5081
+ }
5082
+ }
5083
+ } catch {
5084
+ }
5085
+ return out;
5086
+ };
5087
+ const coverageRoot = path10.join("coverage", "jest");
5088
+ const jsonCandidates = [
5089
+ path10.join(coverageRoot, "coverage-final.json"),
5090
+ ...listJsons(coverageRoot)
5091
+ ].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => {
5092
+ const isFirst = arr.indexOf(absolutePath) === index;
5093
+ const exists = fsSync3.existsSync(absolutePath);
5094
+ return isFirst && exists;
5095
+ });
5096
+ for (const jsonPath of jsonCandidates) {
5077
5097
  try {
5078
- map.merge(jestData);
5098
+ const data = await readCoverageJson(jsonPath);
5099
+ if (Object.keys(data).length) {
5100
+ map.merge(data);
5101
+ }
5079
5102
  } catch (mergeJestError) {
5080
- console.warn(`Failed merging jest coverage JSON: ${String(mergeJestError)}`);
5103
+ console.warn(`Failed merging jest coverage JSON @ ${jsonPath}: ${String(mergeJestError)}`);
5081
5104
  }
5082
5105
  }
5083
5106
  if (map.files().length === 0) {
@@ -5127,11 +5150,14 @@ var emitMergedCoverage = async (ui, opts) => {
5127
5150
  executedTests: opts.executedTests ?? []
5128
5151
  });
5129
5152
  const context = LibReport.createContext({
5130
- dir: path9.resolve("coverage", "merged"),
5153
+ dir: path10.resolve("coverage", "merged"),
5131
5154
  coverageMap: filteredMap,
5132
5155
  defaultSummarizer: "nested"
5133
5156
  });
5134
- const reporters = ui === "jest" ? [(0, import_text.default)({ file: "coverage.txt" })] : [(0, import_text.default)({ file: "coverage.txt" }), (0, import_text_summary.default)({ file: "coverage-summary.txt" })];
5157
+ const reporters = ui === "jest" ? [Reports.create("text", { file: "coverage.txt" })] : [
5158
+ Reports.create("text", { file: "coverage.txt" }),
5159
+ Reports.create("text-summary", { file: "coverage-summary.txt" })
5160
+ ];
5135
5161
  const colorizeIstanbulLine = (lineText) => {
5136
5162
  const separator = /^[-=\s]+$/;
5137
5163
  if (separator.test(lineText.trim())) {
@@ -5192,8 +5218,8 @@ var emitMergedCoverage = async (ui, opts) => {
5192
5218
  for (const reporter of reporters) {
5193
5219
  reporter.execute(context);
5194
5220
  }
5195
- const textPath = path9.resolve("coverage", "merged", "coverage.txt");
5196
- const summaryPath = path9.resolve("coverage", "merged", "coverage-summary.txt");
5221
+ const textPath = path10.resolve("coverage", "merged", "coverage.txt");
5222
+ const summaryPath = path10.resolve("coverage", "merged", "coverage-summary.txt");
5197
5223
  const filesToPrint = [];
5198
5224
  if (fsSync3.existsSync(textPath)) {
5199
5225
  filesToPrint.push(textPath);
@@ -5218,7 +5244,7 @@ var emitMergedCoverage = async (ui, opts) => {
5218
5244
  }
5219
5245
  }
5220
5246
  } else {
5221
- const stdoutReporters = ui === "jest" ? [(0, import_text.default)({})] : [(0, import_text.default)({}), (0, import_text_summary.default)({})];
5247
+ const stdoutReporters = ui === "jest" ? [Reports.create("text", {})] : [Reports.create("text", {}), Reports.create("text-summary", {})];
5222
5248
  for (const reporter of stdoutReporters) {
5223
5249
  reporter.execute(context);
5224
5250
  }
@@ -5275,17 +5301,43 @@ var program = async () => {
5275
5301
  coverageMode,
5276
5302
  coverageMaxFiles: coverageMaxFilesArg,
5277
5303
  coverageMaxHotspots: coverageMaxHotspotsArg,
5278
- coveragePageFit
5304
+ coveragePageFit,
5305
+ changed
5279
5306
  } = deriveArgs(argv);
5280
- console.info(`Selection \u2192 specified=${selectionSpecified} paths=${selectionPaths.length}`);
5307
+ const getChangedFiles = async (mode, cwd) => {
5308
+ const collect = async (cmd, args) => {
5309
+ try {
5310
+ const out = await runText(cmd, args, {
5311
+ cwd,
5312
+ env: safeEnv(process.env, {}),
5313
+ timeoutMs: 4e3
5314
+ });
5315
+ return out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
5316
+ } catch {
5317
+ return [];
5318
+ }
5319
+ };
5320
+ const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
5321
+ const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
5322
+ const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
5323
+ const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
5324
+ return rels.map((rel) => path10.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
5325
+ };
5326
+ const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
5327
+ const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
5328
+ const selectionPathsAugmented = changedSelectionAbs.length ? Array.from(/* @__PURE__ */ new Set([...selectionPaths, ...changedSelectionAbs])) : selectionPaths;
5329
+ const selectionSpecifiedAugmented = Boolean(selectionSpecified || changedSelectionAbs.length > 0);
5330
+ console.info(
5331
+ `Selection \u2192 specified=${selectionSpecifiedAugmented} paths=${selectionPathsAugmented.length}`
5332
+ );
5281
5333
  const { jest } = argsForDiscovery(["run"], jestArgs);
5282
- const selectionLooksLikeTest = selectionPaths.some(
5334
+ const selectionLooksLikeTest = selectionPathsAugmented.some(
5283
5335
  (pathText) => /\.(test|spec)\.[tj]sx?$/i.test(pathText) || /(^|\/)tests?\//i.test(pathText)
5284
5336
  );
5285
- const selectionLooksLikePath = selectionPaths.some(
5337
+ const selectionLooksLikePath = selectionPathsAugmented.some(
5286
5338
  (pathText) => /[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)
5287
5339
  );
5288
- const selectionHasPaths = selectionPaths.length > 0;
5340
+ const selectionHasPaths = selectionPathsAugmented.length > 0;
5289
5341
  const repoRootForDiscovery = workspaceRoot ?? await findRepoRoot();
5290
5342
  const expandProductionSelections = async (tokens, repoRoot) => {
5291
5343
  const results = /* @__PURE__ */ new Set();
@@ -5294,18 +5346,18 @@ var program = async () => {
5294
5346
  if (!token) {
5295
5347
  continue;
5296
5348
  }
5297
- const isAbs = path9.isAbsolute(token);
5349
+ const isAbs = path10.isAbsolute(token);
5298
5350
  const looksLikeRelPath = /[\\/]/.test(token);
5299
5351
  let candidateFromRoot;
5300
5352
  if (token.startsWith("/")) {
5301
- candidateFromRoot = path9.join(repoRoot, token.slice(1));
5353
+ candidateFromRoot = path10.join(repoRoot, token.slice(1));
5302
5354
  } else if (looksLikeRelPath) {
5303
- candidateFromRoot = path9.join(repoRoot, token);
5355
+ candidateFromRoot = path10.join(repoRoot, token);
5304
5356
  } else {
5305
5357
  candidateFromRoot = void 0;
5306
5358
  }
5307
5359
  const tryPushIfProd = (absPath) => {
5308
- const norm = path9.resolve(absPath).replace(/\\/g, "/");
5360
+ const norm = path10.resolve(absPath).replace(/\\/g, "/");
5309
5361
  const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
5310
5362
  if (!isTest && fsSync3.existsSync(norm)) {
5311
5363
  results.add(norm);
@@ -5327,7 +5379,7 @@ var program = async () => {
5327
5379
  }),
5328
5380
  timeoutMs: 4e3
5329
5381
  });
5330
- const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path9.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
5382
+ const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path10.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
5331
5383
  (abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
5332
5384
  );
5333
5385
  matches.forEach((abs) => results.add(abs));
@@ -5336,20 +5388,20 @@ var program = async () => {
5336
5388
  }
5337
5389
  return Array.from(results);
5338
5390
  };
5339
- const initialProdSelections = selectionPaths.filter(
5391
+ const initialProdSelections = selectionPathsAugmented.filter(
5340
5392
  (pathText) => (/[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)) && !/(^|\/)tests?\//i.test(pathText) && !/\.(test|spec)\.[tj]sx?$/i.test(pathText)
5341
5393
  );
5342
- const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(selectionPaths, repoRootForDiscovery);
5394
+ const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(selectionPathsAugmented, repoRootForDiscovery);
5343
5395
  const selectionIncludesProdPaths = expandedProdSelections.length > 0;
5344
5396
  console.info(
5345
5397
  `Selection classify \u2192 looksLikePath=${selectionLooksLikePath} looksLikeTest=${selectionLooksLikeTest} prodPaths=${selectionIncludesProdPaths}`
5346
5398
  );
5347
- const stripPathTokens = (args) => args.filter((token) => !selectionPaths.includes(token));
5399
+ const stripPathTokens = (args) => args.filter((token) => !selectionPathsAugmented.includes(token));
5348
5400
  const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
5349
5401
  const projectConfigs = [];
5350
5402
  try {
5351
- const baseCfg = path9.resolve("jest.config.js");
5352
- const tsCfg = path9.resolve("jest.ts.config.js");
5403
+ const baseCfg = path10.resolve("jest.config.js");
5404
+ const tsCfg = path10.resolve("jest.ts.config.js");
5353
5405
  if (fsSync3.existsSync(baseCfg)) {
5354
5406
  projectConfigs.push(baseCfg);
5355
5407
  }
@@ -5366,7 +5418,7 @@ var program = async () => {
5366
5418
  );
5367
5419
  const prodSelections2 = expandedProdSelections;
5368
5420
  for (const cfg of projectConfigs) {
5369
- const cfgCwd = path9.dirname(cfg);
5421
+ const cfgCwd = path10.dirname(cfg);
5370
5422
  const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5371
5423
  cwd: cfgCwd
5372
5424
  });
@@ -5379,7 +5431,7 @@ var program = async () => {
5379
5431
  });
5380
5432
  } catch (err) {
5381
5433
  if (isDebug()) {
5382
- console.warn(`direct selection failed for project ${path9.basename(cfg)}: ${String(err)}`);
5434
+ console.warn(`direct selection failed for project ${path10.basename(cfg)}: ${String(err)}`);
5383
5435
  }
5384
5436
  }
5385
5437
  perProjectFiles.set(cfg, directPerProject);
@@ -5391,7 +5443,7 @@ var program = async () => {
5391
5443
  )} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
5392
5444
  );
5393
5445
  for (const cfg of projectConfigs) {
5394
- const cfgCwd = path9.dirname(cfg);
5446
+ const cfgCwd = path10.dirname(cfg);
5395
5447
  const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5396
5448
  cwd: cfgCwd
5397
5449
  });
@@ -5401,18 +5453,18 @@ var program = async () => {
5401
5453
  const perProjectFiltered = /* @__PURE__ */ new Map();
5402
5454
  for (const cfg of projectConfigs) {
5403
5455
  const files = perProjectFiles.get(cfg) ?? [];
5404
- const selectionTestPaths = selectionPaths.filter(
5456
+ const selectionTestPaths = selectionPathsAugmented.filter(
5405
5457
  (pathToken) => /\.(test|spec)\.[tj]sx?$/i.test(pathToken) || /(^|\/)tests?\//i.test(pathToken)
5406
5458
  );
5407
5459
  const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
5408
5460
  const absFiles = candidates.map(
5409
- (candidatePath) => path9.isAbsolute(candidatePath) ? candidatePath : path9.join(repoRootForDiscovery, candidatePath)
5461
+ (candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
5410
5462
  ).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
5411
5463
  const onlyOwned = await filterCandidatesForProject(
5412
5464
  cfg,
5413
5465
  jestDiscoveryArgs,
5414
5466
  absFiles,
5415
- path9.dirname(cfg)
5467
+ path10.dirname(cfg)
5416
5468
  );
5417
5469
  perProjectFiltered.set(cfg, onlyOwned);
5418
5470
  }
@@ -5424,7 +5476,7 @@ var program = async () => {
5424
5476
  if (selectionHasPaths && prodSelections.length > 0) {
5425
5477
  console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
5426
5478
  const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
5427
- const selectionKey = prodSelections.map((absPath) => path9.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((a, b) => a.localeCompare(b)).join("|");
5479
+ const selectionKey = prodSelections.map((absPath) => path10.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
5428
5480
  const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
5429
5481
  const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
5430
5482
  const rgMatches = await cachedRelated2({
@@ -5454,7 +5506,7 @@ var program = async () => {
5454
5506
  cfg,
5455
5507
  jestDiscoveryArgs,
5456
5508
  rgCandidates,
5457
- path9.dirname(cfg)
5509
+ path10.dirname(cfg)
5458
5510
  );
5459
5511
  perProjectFromRg.set(cfg, owned);
5460
5512
  }
@@ -5469,9 +5521,9 @@ var program = async () => {
5469
5521
  } else {
5470
5522
  const repoRootForScan = repoRootForDiscovery;
5471
5523
  const toSeeds = (abs) => {
5472
- const rel = path9.relative(repoRootForScan, abs).replace(/\\/g, "/");
5524
+ const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
5473
5525
  const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
5474
- const base = path9.basename(withoutExt);
5526
+ const base = path10.basename(withoutExt);
5475
5527
  const segs = withoutExt.split("/");
5476
5528
  const tail2 = segs.slice(-2).join("/");
5477
5529
  return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
@@ -5486,8 +5538,8 @@ var program = async () => {
5486
5538
  }
5487
5539
  };
5488
5540
  const resolveLocalImport = (fromFile, spec) => {
5489
- const baseDir = path9.dirname(fromFile);
5490
- const cand = path9.resolve(baseDir, spec);
5541
+ const baseDir = path10.dirname(fromFile);
5542
+ const cand = path10.resolve(baseDir, spec);
5491
5543
  const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
5492
5544
  for (const ext of exts) {
5493
5545
  const full = ext ? `${cand}${ext}` : cand;
@@ -5496,7 +5548,7 @@ var program = async () => {
5496
5548
  }
5497
5549
  }
5498
5550
  for (const ext of exts) {
5499
- const full = path9.join(cand, `index${ext}`);
5551
+ const full = path10.join(cand, `index${ext}`);
5500
5552
  if (fsSync3.existsSync(full)) {
5501
5553
  return full;
5502
5554
  }
@@ -5550,7 +5602,7 @@ var program = async () => {
5550
5602
  cfg,
5551
5603
  jestDiscoveryArgs,
5552
5604
  keptCandidates,
5553
- path9.dirname(cfg)
5605
+ path10.dirname(cfg)
5554
5606
  );
5555
5607
  perProjectFromScan.set(cfg, owned);
5556
5608
  }
@@ -5577,9 +5629,9 @@ var program = async () => {
5577
5629
  if (effectiveJestFiles.length === 0) {
5578
5630
  const repoRoot = repoRootForRefinement;
5579
5631
  const seeds = prodSelections.map(
5580
- (abs) => path9.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
5632
+ (abs) => path10.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
5581
5633
  ).flatMap((rel) => {
5582
- const base = path9.basename(rel);
5634
+ const base = path10.basename(rel);
5583
5635
  const segments = rel.split("/");
5584
5636
  return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
5585
5637
  });
@@ -5592,8 +5644,8 @@ var program = async () => {
5592
5644
  }
5593
5645
  };
5594
5646
  const resolveLocalImport = (fromFile, spec) => {
5595
- const baseDir = path9.dirname(fromFile);
5596
- const candidate = path9.resolve(baseDir, spec);
5647
+ const baseDir = path10.dirname(fromFile);
5648
+ const candidate = path10.resolve(baseDir, spec);
5597
5649
  const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
5598
5650
  for (const ext of extensions) {
5599
5651
  const fullPath = ext ? `${candidate}${ext}` : candidate;
@@ -5602,7 +5654,7 @@ var program = async () => {
5602
5654
  }
5603
5655
  }
5604
5656
  for (const ext of extensions) {
5605
- const fullPath = path9.join(candidate, `index${ext}`);
5657
+ const fullPath = path10.join(candidate, `index${ext}`);
5606
5658
  if (fsSync3.existsSync(fullPath)) {
5607
5659
  return fullPath;
5608
5660
  }
@@ -5721,8 +5773,8 @@ var program = async () => {
5721
5773
  }
5722
5774
  }
5723
5775
  const jestDecision = decideShouldRunJest([], effectiveJestFiles, {
5724
- selectionSpecified,
5725
- selectionPaths
5776
+ selectionSpecified: selectionSpecifiedAugmented,
5777
+ selectionPaths: selectionPathsAugmented
5726
5778
  });
5727
5779
  const { shouldRunJest } = jestDecision;
5728
5780
  const jestCount = effectiveJestFiles.length;
@@ -5740,45 +5792,63 @@ var program = async () => {
5740
5792
  }
5741
5793
  console.info(`Run plan \u2192 Jest maybe=${shouldRunJest} (projects=${projectConfigs.length})`);
5742
5794
  let jestExitCode = 0;
5795
+ const allBridgeJson = [];
5743
5796
  const executedTestFilesSet = /* @__PURE__ */ new Set();
5744
5797
  if (shouldRunJest) {
5745
5798
  console.info("Starting Jest (no Vitest targets)\u2026");
5746
5799
  await runJestBootstrap();
5747
5800
  const jestRunArgs = selectionIncludesProdPaths ? stripPathTokens(jestArgs) : jestArgs;
5801
+ const sanitizedJestRunArgs = jestRunArgs.filter(
5802
+ (arg) => !/^--coverageDirectory(?:=|$)/.test(String(arg))
5803
+ );
5748
5804
  const projectsToRun = projectConfigs.filter(
5749
5805
  (cfg) => (perProjectFiltered.get(cfg) ?? []).length > 0
5750
5806
  );
5751
- const totalProjectsToRun = projectsToRun.length;
5752
5807
  const stripFooter = (text) => {
5753
5808
  const lines = text.split("\n");
5754
5809
  const idx = lines.findIndex((ln) => /^Test Files\s/.test(stripAnsiSimple(ln)));
5755
5810
  return idx >= 0 ? lines.slice(0, idx).join("\n").trimEnd() : text;
5756
5811
  };
5812
+ const prodSeedsForRun = (() => {
5813
+ const changedAbs = (changedSelectionAbs ?? []).map(
5814
+ (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
5815
+ );
5816
+ const selAbs = selectionPathsAugmented.map(
5817
+ (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
5818
+ );
5819
+ return (changedAbs.length ? changedAbs : selAbs).filter(
5820
+ (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
5821
+ );
5822
+ })();
5823
+ const repoRootForRank = repoRootForDiscovery;
5824
+ const fileRank = await computeDirectnessRank({
5825
+ repoRoot: repoRootForRank,
5826
+ productionSeeds: prodSeedsForRun
5827
+ });
5757
5828
  for (let projIndex = 0; projIndex < projectsToRun.length; projIndex += 1) {
5758
5829
  const cfg = projectsToRun[projIndex];
5759
- const isLastProject = projIndex === totalProjectsToRun - 1;
5760
5830
  const files = perProjectFiltered.get(cfg) ?? [];
5761
5831
  if (files.length === 0) {
5762
- console.info(`Project ${path9.basename(cfg)}: 0 matching tests after filter; skipping.`);
5832
+ console.info(`Project ${path10.basename(cfg)}: 0 matching tests after filter; skipping.`);
5763
5833
  continue;
5764
5834
  }
5765
5835
  files.forEach(
5766
- (absTestPath) => executedTestFilesSet.add(path9.resolve(absTestPath).replace(/\\/g, "/"))
5836
+ (absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
5767
5837
  );
5768
- const outJson = path9.join(
5838
+ const outJson = path10.join(
5769
5839
  os2.tmpdir(),
5770
5840
  `jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
5771
5841
  );
5772
- const reporterPath = path9.resolve("scripts/jest-vitest-bridge.cjs");
5842
+ const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
5773
5843
  try {
5774
5844
  if (!fsSync3.existsSync(reporterPath)) {
5775
- fsSync3.mkdirSync(path9.dirname(reporterPath), { recursive: true });
5845
+ fsSync3.mkdirSync(path10.dirname(reporterPath), { recursive: true });
5776
5846
  fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
5777
5847
  }
5778
5848
  } catch (ensureReporterError) {
5779
5849
  console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
5780
5850
  }
5781
- const selectedFilesForCoverage = selectionPaths.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path9.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
5851
+ const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path10.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
5782
5852
  const coverageFromArgs = [];
5783
5853
  for (const relPath of selectedFilesForCoverage) {
5784
5854
  coverageFromArgs.push("--collectCoverageFrom", relPath);
@@ -5792,14 +5862,17 @@ var program = async () => {
5792
5862
  "--config",
5793
5863
  cfg,
5794
5864
  "--runTestsByPath",
5795
- "--reporters",
5796
- reporterPath,
5865
+ `--reporters=${reporterPath}`,
5797
5866
  "--silent",
5798
5867
  "--colors",
5799
5868
  "--json",
5800
5869
  "--outputFile",
5801
5870
  outJson,
5802
- ...jestRunArgs,
5871
+ ...sanitizedJestRunArgs,
5872
+ ...collectCoverage ? [
5873
+ "--coverageDirectory",
5874
+ path10.join("coverage", "jest", path10.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
5875
+ ] : [],
5803
5876
  ...coverageFromArgs,
5804
5877
  "--passWithNoTests",
5805
5878
  ...files
@@ -5825,10 +5898,22 @@ var program = async () => {
5825
5898
  const jsonText = fsSync3.readFileSync(outJson, "utf8");
5826
5899
  const parsed = JSON.parse(jsonText);
5827
5900
  const bridge = coerceJestJsonToBridge(parsed);
5828
- pretty = renderVitestFromJestJSON(bridge, {
5829
- cwd: repoRootForDiscovery,
5830
- ...editorCmd !== void 0 ? { editorCmd } : {}
5831
- });
5901
+ allBridgeJson.push(bridge);
5902
+ try {
5903
+ const reordered = {
5904
+ ...bridge,
5905
+ testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
5906
+ };
5907
+ pretty = renderVitestFromJestJSON(reordered, {
5908
+ cwd: repoRootForDiscovery,
5909
+ ...editorCmd !== void 0 ? { editorCmd } : {}
5910
+ });
5911
+ } catch {
5912
+ pretty = renderVitestFromJestJSON(bridge, {
5913
+ cwd: repoRootForDiscovery,
5914
+ ...editorCmd !== void 0 ? { editorCmd } : {}
5915
+ });
5916
+ }
5832
5917
  if (debug) {
5833
5918
  const preview = pretty.split("\n").slice(0, 3).join("\n");
5834
5919
  console.info(`pretty preview (json):
@@ -5852,9 +5937,7 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5852
5937
  ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5853
5938
  }
5854
5939
  }
5855
- if (!isLastProject) {
5856
- pretty = stripFooter(pretty);
5857
- }
5940
+ pretty = stripFooter(pretty);
5858
5941
  if (pretty.trim().length > 0) {
5859
5942
  process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
5860
5943
  `);
@@ -5866,15 +5949,69 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5866
5949
  } else {
5867
5950
  console.info("Jest run skipped based on selection and thresholds.");
5868
5951
  }
5869
- if (collectCoverage && shouldRunJest && coverageAbortOnFailure && jestExitCode !== 0) {
5870
- process.exit(jestExitCode);
5952
+ if (allBridgeJson.length > 0) {
5953
+ const agg = allBridgeJson.map((bridge) => bridge.aggregated);
5954
+ const sum = (select) => agg.reduce((total, item) => total + (select(item) || 0), 0);
5955
+ const startTime = Math.min(
5956
+ ...allBridgeJson.map((bridge) => Number(bridge.startTime || Date.now()))
5957
+ );
5958
+ const unified = {
5959
+ startTime,
5960
+ testResults: allBridgeJson.flatMap((bridge) => bridge.testResults),
5961
+ aggregated: {
5962
+ numTotalTestSuites: sum((item) => item.numTotalTestSuites),
5963
+ numPassedTestSuites: sum((item) => item.numPassedTestSuites),
5964
+ numFailedTestSuites: sum((item) => item.numFailedTestSuites),
5965
+ numTotalTests: sum((item) => item.numTotalTests),
5966
+ numPassedTests: sum((item) => item.numPassedTests),
5967
+ numFailedTests: sum((item) => item.numFailedTests),
5968
+ numPendingTests: sum((item) => item.numPendingTests),
5969
+ numTodoTests: sum((item) => item.numTodoTests),
5970
+ startTime,
5971
+ success: agg.every((item) => Boolean(item.success)),
5972
+ runTimeMs: sum((item) => Number(item.runTimeMs ?? 0))
5973
+ }
5974
+ };
5975
+ try {
5976
+ const prodSeeds = (() => {
5977
+ const changedAbs = (changedSelectionAbs ?? []).map(
5978
+ (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
5979
+ );
5980
+ const selAbs = selectionPathsAugmented.map(
5981
+ (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
5982
+ );
5983
+ return (changedAbs.length ? changedAbs : selAbs).filter(
5984
+ (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
5985
+ );
5986
+ })();
5987
+ const unifiedRank = await computeDirectnessRank({
5988
+ repoRoot: repoRootForDiscovery,
5989
+ productionSeeds: prodSeeds
5990
+ });
5991
+ const ordered = sortTestResultsWithRank(unifiedRank, unified.testResults).reverse();
5992
+ unified.testResults = ordered;
5993
+ } catch {
5994
+ }
5995
+ const text = renderVitestFromJestJSON(unified, {
5996
+ cwd: repoRootForDiscovery,
5997
+ ...editorCmd !== void 0 ? { editorCmd } : {}
5998
+ });
5999
+ if (text.trim().length > 0) {
6000
+ process.stdout.write(text.endsWith("\n") ? text : `${text}
6001
+ `);
6002
+ }
6003
+ }
6004
+ const finalExitCode = jestExitCode;
6005
+ if (collectCoverage && shouldRunJest && coverageAbortOnFailure && finalExitCode !== 0) {
6006
+ process.exit(finalExitCode);
6007
+ return;
5871
6008
  }
5872
6009
  if (collectCoverage && shouldRunJest) {
5873
6010
  await mergeLcov();
5874
6011
  const repoRoot = workspaceRoot ?? await findRepoRoot();
5875
6012
  const mergedOptsBase = {
5876
- selectionSpecified,
5877
- selectionPaths,
6013
+ selectionSpecified: selectionSpecifiedAugmented,
6014
+ selectionPaths: selectionPathsAugmented,
5878
6015
  includeGlobs,
5879
6016
  excludeGlobs,
5880
6017
  workspaceRoot: repoRoot,
@@ -5889,7 +6026,6 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5889
6026
  };
5890
6027
  await emitMergedCoverage(coverageUi, mergedOptsBase);
5891
6028
  }
5892
- const finalExitCode = jestExitCode;
5893
6029
  process.exit(finalExitCode);
5894
6030
  };
5895
6031