@halecraft/verify 1.2.0 → 1.3.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.
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ var VerificationNodeSchema = z.lazy(
25
25
  }),
26
26
  name: z.string().optional(),
27
27
  run: z.union([z.string(), VerificationCommandSchema]).optional(),
28
+ fix: z.union([z.string(), VerificationCommandSchema]).optional(),
28
29
  children: z.array(VerificationNodeSchema).optional(),
29
30
  strategy: z.enum(["parallel", "sequential", "fail-fast"]).optional(),
30
31
  parser: z.string().optional(),
@@ -43,7 +44,9 @@ var VerifyOptionsSchema = z.object({
43
44
  noColor: z.boolean().optional(),
44
45
  topLevelOnly: z.boolean().optional(),
45
46
  noTty: z.boolean().optional(),
46
- passthrough: z.array(z.string()).optional()
47
+ quiet: z.boolean().optional(),
48
+ passthrough: z.array(z.string()).optional(),
49
+ fix: z.boolean().optional()
47
50
  });
48
51
  var PackageDiscoveryOptionsSchema = z.object({
49
52
  patterns: z.array(z.string()).optional(),
@@ -123,7 +126,9 @@ function mergeOptions(configOptions, cliOptions) {
123
126
  noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,
124
127
  topLevelOnly: cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,
125
128
  noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,
126
- passthrough: cliOptions?.passthrough ?? configOptions?.passthrough
129
+ quiet: cliOptions?.quiet ?? configOptions?.quiet ?? false,
130
+ passthrough: cliOptions?.passthrough ?? configOptions?.passthrough,
131
+ fix: cliOptions?.fix ?? configOptions?.fix ?? false
127
132
  };
128
133
  }
129
134
 
@@ -238,6 +243,33 @@ function collectPaths(nodes) {
238
243
  });
239
244
  return paths;
240
245
  }
246
+ function flattenResults(results) {
247
+ const flat = [];
248
+ for (const r of results) {
249
+ flat.push(r);
250
+ if (r.children) {
251
+ flat.push(...flattenResults(r.children));
252
+ }
253
+ }
254
+ return flat;
255
+ }
256
+ function hasFixAvailable(tasks, results) {
257
+ const failedPaths = /* @__PURE__ */ new Set();
258
+ for (const r of flattenResults(results)) {
259
+ if (!r.ok && !r.blocked) {
260
+ failedPaths.add(r.path);
261
+ }
262
+ }
263
+ if (failedPaths.size === 0) return false;
264
+ let found = false;
265
+ walkNodes(tasks, (node, path) => {
266
+ if (found) return;
267
+ if (node.fix && !node.children && failedPaths.has(path)) {
268
+ found = true;
269
+ }
270
+ });
271
+ return found;
272
+ }
241
273
 
242
274
  // src/filter.ts
243
275
  var TaskNotFoundError = class extends Error {
@@ -351,6 +383,12 @@ var TOOL_PATTERNS = [
351
383
  const biomeMatch = content.match(/biome\s+([^&|;]+)/);
352
384
  return biomeMatch ? biomeMatch[1].trim() : "check .";
353
385
  },
386
+ getFixArgs: (match, content) => {
387
+ const biomeMatch = content.match(/biome\s+([^&|;]+)/);
388
+ const args = biomeMatch ? biomeMatch[1].trim() : "check .";
389
+ if (args.includes("--write")) return null;
390
+ return args.replace(/^(check|lint|format)/, "$1 --write");
391
+ },
354
392
  parser: "biome"
355
393
  },
356
394
  // ESLint
@@ -360,6 +398,12 @@ var TOOL_PATTERNS = [
360
398
  getArgs: (_, content) => {
361
399
  const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
362
400
  return eslintMatch ? eslintMatch[1].trim() : ".";
401
+ },
402
+ getFixArgs: (_, content) => {
403
+ const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
404
+ const args = eslintMatch ? eslintMatch[1].trim() : ".";
405
+ if (args.includes("--fix")) return null;
406
+ return `${args} --fix`;
363
407
  }
364
408
  },
365
409
  // Prettier
@@ -369,6 +413,13 @@ var TOOL_PATTERNS = [
369
413
  getArgs: (_, content) => {
370
414
  const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
371
415
  return prettierMatch ? prettierMatch[1].trim() : "--check .";
416
+ },
417
+ getFixArgs: (_, content) => {
418
+ const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
419
+ const args = prettierMatch ? prettierMatch[1].trim() : "--check .";
420
+ if (args.includes("--write")) return null;
421
+ if (args.includes("--check")) return args.replace("--check", "--write");
422
+ return `--write ${args}`;
372
423
  }
373
424
  },
374
425
  // TypeScript
@@ -514,7 +565,14 @@ function extractOptimizedCommand(cwd, scriptContent) {
514
565
  if (match && binaryExists(cwd, tool.binary)) {
515
566
  const args = tool.getArgs(match, scriptContent);
516
567
  const command = args ? `${tool.binary} ${args}` : tool.binary;
517
- return { command, parser: tool.parser };
568
+ let fixCommand;
569
+ if (tool.getFixArgs) {
570
+ const fixArgs = tool.getFixArgs(match, scriptContent);
571
+ if (fixArgs) {
572
+ fixCommand = `${tool.binary} ${fixArgs}`;
573
+ }
574
+ }
575
+ return { command, parser: tool.parser, fixCommand };
518
576
  }
519
577
  }
520
578
  return null;
@@ -542,7 +600,8 @@ function detectFromPackageJson(cwd) {
542
600
  scriptName,
543
601
  command: optimized?.command ?? `npm run ${scriptName}`,
544
602
  category,
545
- parser: optimized?.parser
603
+ parser: optimized?.parser,
604
+ fixCommand: optimized?.fixCommand
546
605
  });
547
606
  }
548
607
  break;
@@ -612,6 +671,9 @@ function generateImport(format) {
612
671
  }
613
672
  function generateTask(task, indent) {
614
673
  const parts = [`key: "${task.key}"`, `run: "${task.command}"`];
674
+ if (task.fixCommand) {
675
+ parts.push(`fix: "${task.fixCommand}"`);
676
+ }
615
677
  if (task.parser) {
616
678
  parts.push(`parser: "${task.parser}"`);
617
679
  }
@@ -956,20 +1018,36 @@ var vitestParser = {
956
1018
  id: "vitest",
957
1019
  parse(output, exitCode) {
958
1020
  const cleanOutput = stripAnsi(output);
959
- const testsMatch = cleanOutput.match(/Tests\s+(\d+)\s+passed\s*\((\d+)\)/m);
1021
+ const testsLineMatch = cleanOutput.match(/Tests\s+(.+?)\s*\((\d+)\)/m);
960
1022
  const durationMatch = cleanOutput.match(/Duration\s+([\d.]+(?:ms|s))\b/m);
961
- if (!testsMatch) {
1023
+ if (!testsLineMatch) {
962
1024
  return null;
963
1025
  }
964
- const passed = Number.parseInt(testsMatch[1], 10);
965
- const total = Number.parseInt(testsMatch[2], 10);
1026
+ const statsStr = testsLineMatch[1];
1027
+ const total = Number.parseInt(testsLineMatch[2], 10);
1028
+ const passedMatch = statsStr.match(/(\d+)\s+passed/);
1029
+ const failedMatch = statsStr.match(/(\d+)\s+failed/);
1030
+ const skippedMatch = statsStr.match(/(\d+)\s+skipped/);
1031
+ const passed = passedMatch ? Number.parseInt(passedMatch[1], 10) : 0;
1032
+ const skipped = skippedMatch ? Number.parseInt(skippedMatch[1], 10) : 0;
966
1033
  const duration = durationMatch ? durationMatch[1] : void 0;
1034
+ const failed = failedMatch ? Number.parseInt(failedMatch[1], 10) : total - passed - skipped;
1035
+ const ran = passed + failed;
1036
+ let summary;
1037
+ if (ran === 0 && skipped > 0) {
1038
+ summary = `${skipped} tests skipped (no matches)`;
1039
+ } else if (skipped > 0) {
1040
+ summary = exitCode === 0 ? `passed ${passed}/${ran} tests (${skipped} skipped)` : `passed ${passed}/${ran} tests (${skipped} skipped, some failed)`;
1041
+ } else {
1042
+ summary = exitCode === 0 ? `passed ${passed}/${total} tests` : `passed ${passed}/${total} tests (some failed)`;
1043
+ }
967
1044
  return {
968
- summary: exitCode === 0 ? `passed ${passed}/${total} tests` : `passed ${passed}/${total} tests (some failed)`,
1045
+ summary,
969
1046
  metrics: {
970
1047
  passed,
971
1048
  total,
972
- failed: total - passed,
1049
+ failed,
1050
+ skipped,
973
1051
  duration
974
1052
  }
975
1053
  };
@@ -1106,20 +1184,31 @@ var cursor = {
1106
1184
  moveToStart: "\x1B[0G",
1107
1185
  clearLine: "\x1B[2K"
1108
1186
  };
1109
- function shouldUseColors(options) {
1187
+ function defaultTerminalContext() {
1188
+ return { isTTY: !!process.stdout.isTTY, env: process.env };
1189
+ }
1190
+ function shouldUseColors(options, ctx) {
1110
1191
  if (options.noColor) return false;
1111
1192
  if (options.format === "json") return false;
1112
- if (!process.stdout.isTTY) return false;
1113
- if ("NO_COLOR" in process.env) return false;
1114
- if (process.env.TERM === "dumb") return false;
1193
+ if (!ctx.isTTY) return false;
1194
+ if ("NO_COLOR" in ctx.env) return false;
1195
+ if (ctx.env.TERM === "dumb") return false;
1196
+ return true;
1197
+ }
1198
+ function shouldUseLiveDashboard(options, ctx) {
1199
+ if (options.noTty) return false;
1200
+ if (ctx.env.TURBO_IS_TUI === "true") return false;
1201
+ if (ctx.isTTY && ctx.env.TURBO_HASH != null) return false;
1202
+ if (!ctx.isTTY) return false;
1115
1203
  return true;
1116
1204
  }
1117
1205
  var BaseReporter = class {
1118
1206
  colorEnabled;
1119
1207
  stream;
1120
1208
  taskDepths = /* @__PURE__ */ new Map();
1121
- constructor(options = {}) {
1122
- this.colorEnabled = shouldUseColors(options);
1209
+ constructor(options = {}, ctx) {
1210
+ const termCtx = ctx ?? defaultTerminalContext();
1211
+ this.colorEnabled = shouldUseColors(options, termCtx);
1123
1212
  this.stream = options.format === "json" ? process.stderr : process.stdout;
1124
1213
  }
1125
1214
  /**
@@ -1141,10 +1230,10 @@ var BaseReporter = class {
1141
1230
  return this.colorEnabled ? this.c(ansi.red, "\u2717") : "FAIL";
1142
1231
  }
1143
1232
  /**
1144
- * Get suppressed mark (⊘ or SUPPRESSED)
1233
+ * Get blocked mark (⊘ or BLOCK)
1145
1234
  */
1146
- suppressedMark() {
1147
- return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "SUPPRESSED";
1235
+ blockedMark() {
1236
+ return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "BLOCK";
1148
1237
  }
1149
1238
  /**
1150
1239
  * Get arrow symbol (→ or ->)
@@ -1172,6 +1261,22 @@ var BaseReporter = class {
1172
1261
  this.taskDepths.set(path, depth);
1173
1262
  });
1174
1263
  }
1264
+ /**
1265
+ * Format a completed task result line in name-first format.
1266
+ * Shared by LiveDashboardReporter and SequentialReporter.
1267
+ */
1268
+ formatResultLine(name, result) {
1269
+ const duration = this.c(ansi.dim, `${result.durationMs}ms`);
1270
+ if (result.blocked) {
1271
+ const reason = result.blockedBy ? `by ${result.blockedBy}` : "by dependency";
1272
+ return `${this.blockedMark()} ${this.c(ansi.bold, name)} blocked ${this.c(ansi.dim, `(${reason}, ${duration})`)}`;
1273
+ }
1274
+ const summary = this.extractSummary(result);
1275
+ if (result.ok) {
1276
+ return `${this.okMark()} ${this.c(ansi.bold, name)} verified ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1277
+ }
1278
+ return `${this.failMark()} ${this.c(ansi.bold, name)} failed ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1279
+ }
1175
1280
  /**
1176
1281
  * Extract summary from task result
1177
1282
  */
@@ -1207,7 +1312,7 @@ var BaseReporter = class {
1207
1312
  for (const r of flatResults) {
1208
1313
  if (r.children) continue;
1209
1314
  if (logsMode === "failed" && r.ok) continue;
1210
- if (r.suppressed) continue;
1315
+ if (r.blocked) continue;
1211
1316
  const status = r.ok ? this.c(ansi.green, "OK") : this.c(ansi.red, "FAIL");
1212
1317
  this.stream.write(
1213
1318
  `
@@ -1225,6 +1330,13 @@ ${this.c(ansi.bold, "====")} ${this.c(ansi.bold, r.path.toUpperCase())} ${status
1225
1330
  this.stream.write(`${finalMessage}
1226
1331
  `);
1227
1332
  }
1333
+ outputFixHint(result) {
1334
+ if (result.fixAvailable && !result.ok) {
1335
+ this.stream.write(`
1336
+ \u{1F4A1} Tip: run "verify --fix" to attempt auto-fixes
1337
+ `);
1338
+ }
1339
+ }
1228
1340
  };
1229
1341
  var LiveDashboardReporter = class extends BaseReporter {
1230
1342
  topLevelOnly;
@@ -1232,8 +1344,8 @@ var LiveDashboardReporter = class extends BaseReporter {
1232
1344
  taskOrder = [];
1233
1345
  spinner;
1234
1346
  lineCount = 0;
1235
- constructor(options = {}) {
1236
- super(options);
1347
+ constructor(options = {}, ctx) {
1348
+ super(options, ctx);
1237
1349
  this.topLevelOnly = options.topLevelOnly ?? false;
1238
1350
  this.spinner = new SpinnerManager();
1239
1351
  const cleanup = () => {
@@ -1294,16 +1406,7 @@ var LiveDashboardReporter = class extends BaseReporter {
1294
1406
  return `${indent}${this.arrow()} verifying ${this.c(ansi.bold, displayKey)} ${spinnerChar}`;
1295
1407
  }
1296
1408
  if (task.status === "completed" && task.result) {
1297
- const duration = this.c(ansi.dim, `${task.result.durationMs}ms`);
1298
- if (task.result.suppressed) {
1299
- const reason = task.result.suppressedBy ? `${task.result.suppressedBy} failed` : "dependency failed";
1300
- return `${indent}${this.suppressedMark()} suppressed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}`;
1301
- }
1302
- const summary = this.extractSummary(task.result);
1303
- if (task.result.ok) {
1304
- return `${indent}${this.okMark()} verified ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1305
- }
1306
- return `${indent}${this.failMark()} failed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1409
+ return `${indent}${this.formatResultLine(displayKey, task.result)}`;
1307
1410
  }
1308
1411
  return "";
1309
1412
  }
@@ -1353,8 +1456,8 @@ var LiveDashboardReporter = class extends BaseReporter {
1353
1456
  };
1354
1457
  var SequentialReporter = class extends BaseReporter {
1355
1458
  topLevelOnly;
1356
- constructor(options = {}) {
1357
- super(options);
1459
+ constructor(options = {}, ctx) {
1460
+ super(options, ctx);
1358
1461
  this.topLevelOnly = options.topLevelOnly ?? false;
1359
1462
  }
1360
1463
  onStart(tasks) {
@@ -1374,27 +1477,8 @@ var SequentialReporter = class extends BaseReporter {
1374
1477
  }
1375
1478
  onTaskComplete(result) {
1376
1479
  if (!this.shouldDisplay(result.path)) return;
1377
- const duration = this.c(ansi.dim, `${result.durationMs}ms`);
1378
- if (result.suppressed) {
1379
- const reason = result.suppressedBy ? `${result.suppressedBy} failed` : "dependency failed";
1380
- this.stream.write(
1381
- `${this.suppressedMark()} suppressed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}
1382
- `
1383
- );
1384
- return;
1385
- }
1386
- const summary = this.extractSummary(result);
1387
- if (result.ok) {
1388
- this.stream.write(
1389
- `${this.okMark()} verified ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}
1390
- `
1391
- );
1392
- } else {
1393
- this.stream.write(
1394
- `${this.failMark()} failed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}
1395
- `
1396
- );
1397
- }
1480
+ this.stream.write(`${this.formatResultLine(result.path, result)}
1481
+ `);
1398
1482
  }
1399
1483
  onFinish() {
1400
1484
  }
@@ -1416,6 +1500,7 @@ var JSONReporter = class {
1416
1500
  startedAt: result.startedAt,
1417
1501
  finishedAt: result.finishedAt,
1418
1502
  durationMs: result.durationMs,
1503
+ ...result.fixAvailable ? { fixAvailable: result.fixAvailable } : {},
1419
1504
  tasks: this.serializeTasks(result.tasks)
1420
1505
  };
1421
1506
  process.stdout.write(`${JSON.stringify(summary)}
@@ -1429,8 +1514,8 @@ var JSONReporter = class {
1429
1514
  code: t.code,
1430
1515
  durationMs: t.durationMs,
1431
1516
  summaryLine: t.summaryLine,
1432
- ...t.suppressed ? { suppressed: t.suppressed } : {},
1433
- ...t.suppressedBy ? { suppressedBy: t.suppressedBy } : {},
1517
+ ...t.blocked ? { blocked: t.blocked } : {},
1518
+ ...t.blockedBy ? { blockedBy: t.blockedBy } : {},
1434
1519
  ...t.children ? { children: this.serializeTasks(t.children) } : {}
1435
1520
  }));
1436
1521
  }
@@ -1451,15 +1536,25 @@ var QuietReporter = class extends BaseReporter {
1451
1536
  process.stdout.write(`${message}
1452
1537
  `);
1453
1538
  }
1539
+ outputFixHint(result) {
1540
+ if (result.fixAvailable && !result.ok) {
1541
+ process.stdout.write(`\u{1F4A1} fix available: verify --fix
1542
+ `);
1543
+ }
1544
+ }
1454
1545
  };
1455
1546
  function createReporter(options) {
1547
+ const ctx = defaultTerminalContext();
1456
1548
  if (options.format === "json") {
1457
1549
  return new JSONReporter();
1458
1550
  }
1459
- if (process.stdout.isTTY && !options.noTty) {
1460
- return new LiveDashboardReporter(options);
1551
+ if (options.quiet) {
1552
+ return new QuietReporter(options, ctx);
1461
1553
  }
1462
- return new SequentialReporter(options);
1554
+ if (shouldUseLiveDashboard(options, ctx)) {
1555
+ return new LiveDashboardReporter(options, ctx);
1556
+ }
1557
+ return new SequentialReporter(options, ctx);
1463
1558
  }
1464
1559
 
1465
1560
  // src/runner.ts
@@ -1716,6 +1811,10 @@ var ReportingDependencyTracker = class {
1716
1811
  };
1717
1812
 
1718
1813
  // src/runner.ts
1814
+ function resolveCommand(node, fix) {
1815
+ if (fix && node.fix) return node.fix;
1816
+ return node.run;
1817
+ }
1719
1818
  function mergeEnv(base, overlay) {
1720
1819
  if (!overlay) return { ...base };
1721
1820
  const result = { ...base };
@@ -1911,12 +2010,14 @@ var VerificationRunner = class {
1911
2010
  const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
1912
2011
  const durationMs = Date.now() - wallStart;
1913
2012
  const allOk = results.every((r) => r.ok);
2013
+ const fixAvailable = hasFixAvailable(tasks, results);
1914
2014
  return {
1915
2015
  ok: allOk,
1916
2016
  startedAt,
1917
2017
  finishedAt,
1918
2018
  durationMs,
1919
- tasks: results
2019
+ tasks: results,
2020
+ ...fixAvailable ? { fixAvailable } : {}
1920
2021
  };
1921
2022
  }
1922
2023
  /**
@@ -1973,9 +2074,9 @@ var VerificationRunner = class {
1973
2074
  nodeEnv
1974
2075
  );
1975
2076
  const durationMs2 = Date.now() - start;
1976
- const allOk = childResults.every((r) => r.ok || r.suppressed);
1977
- const allSuppressed = childResults.length > 0 && childResults.every((r) => r.suppressed);
1978
- const anySuppressed = childResults.some((r) => r.suppressed);
2077
+ const allOk = childResults.every((r) => r.ok || r.blocked);
2078
+ const allBlocked = childResults.length > 0 && childResults.every((r) => r.blocked);
2079
+ const anyBlocked = childResults.some((r) => r.blocked);
1979
2080
  const result2 = {
1980
2081
  key: node.key,
1981
2082
  path,
@@ -1986,16 +2087,17 @@ var VerificationRunner = class {
1986
2087
  summaryLine: allOk ? node.successLabel ?? `${node.key}: all passed` : node.failureLabel ?? `${node.key}: some failed`,
1987
2088
  children: childResults
1988
2089
  };
1989
- if (allSuppressed) {
1990
- result2.suppressed = true;
1991
- result2.suppressedBy = childResults[0].suppressedBy;
1992
- } else if (anySuppressed && !allOk) {
2090
+ if (allBlocked) {
2091
+ result2.blocked = true;
2092
+ result2.blockedBy = childResults[0].blockedBy;
2093
+ } else if (anyBlocked && !allOk) {
1993
2094
  }
1994
2095
  this.dependencyTracker.recordResult(result2);
1995
2096
  this.callbacks.onTaskComplete?.(result2);
1996
2097
  return result2;
1997
2098
  }
1998
- if (!node.run) {
2099
+ const effectiveRun = resolveCommand(node, this.options.fix ?? false);
2100
+ if (!effectiveRun) {
1999
2101
  const result2 = {
2000
2102
  key: node.key,
2001
2103
  path,
@@ -2011,7 +2113,7 @@ var VerificationRunner = class {
2011
2113
  }
2012
2114
  const passthrough = this.options.passthrough;
2013
2115
  const command = normalizeCommand(
2014
- node.run,
2116
+ effectiveRun,
2015
2117
  node.timeout,
2016
2118
  passthrough,
2017
2119
  nodeEnv
@@ -2050,8 +2152,8 @@ var VerificationRunner = class {
2050
2152
  durationMs,
2051
2153
  output,
2052
2154
  summaryLine: `${node.key}: terminated`,
2053
- suppressed: true,
2054
- suppressedBy: failedDep ?? "unknown"
2155
+ blocked: true,
2156
+ blockedBy: failedDep ?? "unknown"
2055
2157
  };
2056
2158
  this.dependencyTracker.recordResult(result2);
2057
2159
  this.callbacks.onTaskComplete?.(result2);
@@ -2087,8 +2189,8 @@ var VerificationRunner = class {
2087
2189
  if (failedDep) {
2088
2190
  result = {
2089
2191
  ...result,
2090
- suppressed: true,
2091
- suppressedBy: failedDep
2192
+ blocked: true,
2193
+ blockedBy: failedDep
2092
2194
  };
2093
2195
  }
2094
2196
  }
@@ -2126,6 +2228,9 @@ async function verify(config, cliOptions) {
2126
2228
  reporter.onFinish?.();
2127
2229
  reporter.outputLogs(result.tasks, options.logs ?? "failed");
2128
2230
  reporter.outputSummary(result);
2231
+ if (!options.fix) {
2232
+ reporter.outputFixHint?.(result);
2233
+ }
2129
2234
  return result;
2130
2235
  }
2131
2236
  async function verifyFromConfig(cwd = process.cwd(), cliOptions) {
@@ -2163,11 +2268,13 @@ export {
2163
2268
  generateConfigContent,
2164
2269
  genericParser,
2165
2270
  gotestParser,
2271
+ hasFixAvailable,
2166
2272
  hasPackageChanged,
2167
2273
  loadConfig,
2168
2274
  loadConfigFromCwd,
2169
2275
  mergeOptions,
2170
2276
  parsers,
2277
+ resolveCommand,
2171
2278
  resolveFilters,
2172
2279
  runInit,
2173
2280
  tscParser,