@halecraft/verify 1.2.0 → 1.3.0

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/README.md CHANGED
@@ -135,9 +135,9 @@ interface VerificationNode {
135
135
  }
136
136
  ```
137
137
 
138
- ### Smart Output Suppression with `reportingDependsOn`
138
+ ### Dependency-Aware Failure Reporting with `reportingDependsOn`
139
139
 
140
- When a syntax error occurs, multiple tools often report the same underlying issue (Biome, tsc, esbuild all complaining about the same missing comma). The `reportingDependsOn` option reduces this noise by suppressing redundant failure output.
140
+ When a syntax error occurs, multiple tools often report the same underlying issue (Biome, tsc, esbuild all complaining about the same missing comma). The `reportingDependsOn` option reduces this noise by marking dependent failures as blocked.
141
141
 
142
142
  ```typescript
143
143
  import { defineConfig } from "@halecraft/verify";
@@ -156,17 +156,17 @@ export default defineConfig({
156
156
 
157
157
  - All tasks still execute in parallel (no speed regression)
158
158
  - When a dependency fails (e.g., `format`), dependent tasks are terminated early for faster feedback
159
- - Dependent tasks that also fail are marked as "suppressed"
159
+ - Dependent tasks that also fail are marked as "blocked"
160
160
  - Only the root cause failure shows detailed logs
161
- - Suppressed tasks show `⊘ suppressed` instead of `✗ failed`
161
+ - Blocked tasks show `⊘ blocked` instead of `✗ failed`
162
162
 
163
163
  **Before (noisy):**
164
164
 
165
165
  ```
166
- ✗ format (syntax error at line 14)
167
- ✗ types (syntax error at line 14)
168
- ✗ logic (syntax error at line 14)
169
- ✗ build (syntax error at line 14)
166
+ ✗ format failed (syntax error at line 14)
167
+ ✗ types failed (syntax error at line 14)
168
+ ✗ logic failed (syntax error at line 14)
169
+ ✗ build failed (syntax error at line 14)
170
170
 
171
171
  ==== FORMAT FAIL ====
172
172
  [50 lines of biome output]
@@ -184,10 +184,10 @@ export default defineConfig({
184
184
  **After (clean):**
185
185
 
186
186
  ```
187
- ✗ format (syntax error at line 14)
188
- ⊘ types (suppressed - format failed)
189
- ⊘ logic (suppressed - format failed)
190
- ⊘ build (suppressed - format failed)
187
+ ✗ format failed (syntax error at line 14)
188
+ ⊘ types blocked (by format, 120ms)
189
+ ⊘ logic blocked (by format, 150ms)
190
+ ⊘ build blocked (by format, 130ms)
191
191
 
192
192
  ==== FORMAT FAIL ====
193
193
  [50 lines of biome output]
@@ -469,8 +469,8 @@ interface TaskResult {
469
469
  durationMs: number; // Duration in milliseconds
470
470
  output: string; // Raw output
471
471
  summaryLine: string; // Parsed summary
472
- suppressed?: boolean; // True if output was suppressed
473
- suppressedBy?: string; // Path of dependency that caused suppression
472
+ blocked?: boolean; // True if blocked by a dependency failure
473
+ blockedBy?: string; // Path of dependency that caused the block
474
474
  timedOut?: boolean; // True if task exceeded its timeout
475
475
  children?: TaskResult[]; // Child results (for group nodes)
476
476
  }
package/bin/verify.mjs CHANGED
@@ -138,6 +138,7 @@ async function main() {
138
138
  cwd: flags.config,
139
139
  topLevelOnly: flags.topLevel,
140
140
  noTty: flags.noTty,
141
+ quiet: flags.quiet,
141
142
  passthrough: passthrough && passthrough.length > 0 ? passthrough : undefined,
142
143
  }
143
144
 
package/dist/index.d.ts CHANGED
@@ -26,6 +26,7 @@ interface ParsedResult {
26
26
  metrics?: {
27
27
  passed?: number;
28
28
  failed?: number;
29
+ skipped?: number;
29
30
  total?: number;
30
31
  duration?: string;
31
32
  errors?: number;
@@ -67,7 +68,7 @@ interface VerificationNode {
67
68
  failureLabel?: string;
68
69
  /**
69
70
  * Tasks that must pass for this task's failure to be reported.
70
- * If any dependency fails, this task's failure output is suppressed.
71
+ * If any dependency fails, this task's failure is marked as blocked.
71
72
  * Can specify task keys (e.g., "format") or full paths (e.g., "types:tsc").
72
73
  */
73
74
  reportingDependsOn?: string[];
@@ -104,6 +105,8 @@ interface VerifyOptions {
104
105
  topLevelOnly?: boolean;
105
106
  /** Force sequential output (disable live dashboard) */
106
107
  noTty?: boolean;
108
+ /** Suppress in-progress output, show only final summary */
109
+ quiet?: boolean;
107
110
  /** Arguments to pass through to the underlying command (requires single task filter) */
108
111
  passthrough?: string[];
109
112
  }
@@ -158,15 +161,15 @@ interface TaskResult {
158
161
  /** Child results (for group nodes) */
159
162
  children?: TaskResult[];
160
163
  /**
161
- * Whether this task's failure output was suppressed due to a dependency failure.
162
- * The task still ran and failed, but its output is hidden to reduce noise.
164
+ * Whether this task's failure was blocked by a dependency failure.
165
+ * The task ran but its failure output is hidden because the root cause is the dependency.
163
166
  */
164
- suppressed?: boolean;
167
+ blocked?: boolean;
165
168
  /**
166
- * The path of the dependency task that caused this task to be suppressed.
167
- * Only set when suppressed is true.
169
+ * The path of the dependency task that caused this task to be blocked.
170
+ * Only set when blocked is true.
168
171
  */
169
- suppressedBy?: string;
172
+ blockedBy?: string;
170
173
  /**
171
174
  * Whether this task was terminated due to timeout.
172
175
  * Only set when the task exceeded its configured timeout.
@@ -469,6 +472,14 @@ interface Reporter {
469
472
  /** Called to output final summary */
470
473
  outputSummary(result: VerifyResult): void;
471
474
  }
475
+ /**
476
+ * Terminal capability context — the single point where globals are read.
477
+ * Passed to pure decision functions for testability.
478
+ */
479
+ interface TerminalContext {
480
+ isTTY: boolean;
481
+ env: Record<string, string | undefined>;
482
+ }
472
483
  /**
473
484
  * Base Reporter - common functionality for all reporters
474
485
  */
@@ -476,7 +487,7 @@ declare abstract class BaseReporter implements Reporter {
476
487
  protected colorEnabled: boolean;
477
488
  protected stream: NodeJS.WriteStream;
478
489
  protected taskDepths: Map<string, number>;
479
- constructor(options?: VerifyOptions);
490
+ constructor(options?: VerifyOptions, ctx?: TerminalContext);
480
491
  /**
481
492
  * Apply ANSI color code to string (if colors enabled)
482
493
  */
@@ -490,9 +501,9 @@ declare abstract class BaseReporter implements Reporter {
490
501
  */
491
502
  protected failMark(): string;
492
503
  /**
493
- * Get suppressed mark (⊘ or SUPPRESSED)
504
+ * Get blocked mark (⊘ or BLOCK)
494
505
  */
495
- protected suppressedMark(): string;
506
+ protected blockedMark(): string;
496
507
  /**
497
508
  * Get arrow symbol (→ or ->)
498
509
  */
@@ -509,6 +520,11 @@ declare abstract class BaseReporter implements Reporter {
509
520
  * Collect task depths from verification tree using walkNodes
510
521
  */
511
522
  protected collectTaskDepths(nodes: VerificationNode[]): void;
523
+ /**
524
+ * Format a completed task result line in name-first format.
525
+ * Shared by LiveDashboardReporter and SequentialReporter.
526
+ */
527
+ protected formatResultLine(name: string, result: TaskResult): string;
512
528
  /**
513
529
  * Extract summary from task result
514
530
  */
@@ -539,7 +555,7 @@ declare class LiveDashboardReporter extends BaseReporter {
539
555
  private taskOrder;
540
556
  private spinner;
541
557
  private lineCount;
542
- constructor(options?: VerifyOptions);
558
+ constructor(options?: VerifyOptions, ctx?: TerminalContext);
543
559
  /**
544
560
  * Initialize task list from verification nodes
545
561
  */
@@ -574,7 +590,7 @@ declare class LiveDashboardReporter extends BaseReporter {
574
590
  */
575
591
  declare class SequentialReporter extends BaseReporter {
576
592
  private topLevelOnly;
577
- constructor(options?: VerifyOptions);
593
+ constructor(options?: VerifyOptions, ctx?: TerminalContext);
578
594
  onStart(tasks: VerificationNode[]): void;
579
595
  /**
580
596
  * Check if task should be displayed based on topLevelOnly flag
@@ -608,7 +624,9 @@ declare class QuietReporter extends BaseReporter {
608
624
  outputSummary(result: VerifyResult): void;
609
625
  }
610
626
  /**
611
- * Create appropriate reporter based on options
627
+ * Create appropriate reporter based on options.
628
+ *
629
+ * Decision tree: JSON → Quiet → LiveDashboard → Sequential
612
630
  */
613
631
  declare function createReporter(options: VerifyOptions): Reporter;
614
632
 
@@ -675,4 +693,4 @@ declare function verify(config: VerifyConfig, cliOptions?: Partial<VerifyOptions
675
693
  */
676
694
  declare function verifyFromConfig(cwd?: string, cliOptions?: Partial<VerifyOptions>): Promise<VerifyResult>;
677
695
 
678
- export { AmbiguousTaskError, ConfigError, type DetectedTask, type DiscoveredPackage, type ExecutionStrategy, type InitOptions, type InitResult, JSONReporter, LiveDashboardReporter, type NodeVisitor, type OutputFormat, type OutputParser, PATH_SEPARATOR, type PackageDiscoveryOptions, type ParsedResult, type ParserId, ParserRegistry, QuietReporter, type Reporter, type ResolvedFilter, type RunnerCallbacks, SequentialReporter, SequentialReporter as TTYReporter, TaskNotFoundError, type TaskResult, type VerificationCommand, type VerificationNode, VerificationRunner, type VerifyConfig, type VerifyOptions, type VerifyResult, biomeParser, buildTaskPath, collectPaths, createReporter, defaultRegistry, defineConfig, defineTask, detectTasks, discoverPackages, findBestSuggestion, findConfigFile, generateConfigContent, genericParser, gotestParser, hasPackageChanged, loadConfig, loadConfigFromCwd, mergeOptions, parsers, resolveFilters, runInit, tscParser, validateConfig, verify, verifyFromConfig, vitestParser, walkNodes };
696
+ export { AmbiguousTaskError, ConfigError, type DetectedTask, type DiscoveredPackage, type ExecutionStrategy, type InitOptions, type InitResult, JSONReporter, LiveDashboardReporter, type NodeVisitor, type OutputFormat, type OutputParser, PATH_SEPARATOR, type PackageDiscoveryOptions, type ParsedResult, type ParserId, ParserRegistry, QuietReporter, type Reporter, type ResolvedFilter, type RunnerCallbacks, SequentialReporter, SequentialReporter as TTYReporter, TaskNotFoundError, type TaskResult, type TerminalContext, type VerificationCommand, type VerificationNode, VerificationRunner, type VerifyConfig, type VerifyOptions, type VerifyResult, biomeParser, buildTaskPath, collectPaths, createReporter, defaultRegistry, defineConfig, defineTask, detectTasks, discoverPackages, findBestSuggestion, findConfigFile, generateConfigContent, genericParser, gotestParser, hasPackageChanged, loadConfig, loadConfigFromCwd, mergeOptions, parsers, resolveFilters, runInit, tscParser, validateConfig, verify, verifyFromConfig, vitestParser, walkNodes };
package/dist/index.js CHANGED
@@ -123,6 +123,7 @@ function mergeOptions(configOptions, cliOptions) {
123
123
  noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,
124
124
  topLevelOnly: cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,
125
125
  noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,
126
+ quiet: cliOptions?.quiet ?? configOptions?.quiet ?? false,
126
127
  passthrough: cliOptions?.passthrough ?? configOptions?.passthrough
127
128
  };
128
129
  }
@@ -956,20 +957,36 @@ var vitestParser = {
956
957
  id: "vitest",
957
958
  parse(output, exitCode) {
958
959
  const cleanOutput = stripAnsi(output);
959
- const testsMatch = cleanOutput.match(/Tests\s+(\d+)\s+passed\s*\((\d+)\)/m);
960
+ const testsLineMatch = cleanOutput.match(/Tests\s+(.+?)\s*\((\d+)\)/m);
960
961
  const durationMatch = cleanOutput.match(/Duration\s+([\d.]+(?:ms|s))\b/m);
961
- if (!testsMatch) {
962
+ if (!testsLineMatch) {
962
963
  return null;
963
964
  }
964
- const passed = Number.parseInt(testsMatch[1], 10);
965
- const total = Number.parseInt(testsMatch[2], 10);
965
+ const statsStr = testsLineMatch[1];
966
+ const total = Number.parseInt(testsLineMatch[2], 10);
967
+ const passedMatch = statsStr.match(/(\d+)\s+passed/);
968
+ const failedMatch = statsStr.match(/(\d+)\s+failed/);
969
+ const skippedMatch = statsStr.match(/(\d+)\s+skipped/);
970
+ const passed = passedMatch ? Number.parseInt(passedMatch[1], 10) : 0;
971
+ const skipped = skippedMatch ? Number.parseInt(skippedMatch[1], 10) : 0;
966
972
  const duration = durationMatch ? durationMatch[1] : void 0;
973
+ const failed = failedMatch ? Number.parseInt(failedMatch[1], 10) : total - passed - skipped;
974
+ const ran = passed + failed;
975
+ let summary;
976
+ if (ran === 0 && skipped > 0) {
977
+ summary = `${skipped} tests skipped (no matches)`;
978
+ } else if (skipped > 0) {
979
+ summary = exitCode === 0 ? `passed ${passed}/${ran} tests (${skipped} skipped)` : `passed ${passed}/${ran} tests (${skipped} skipped, some failed)`;
980
+ } else {
981
+ summary = exitCode === 0 ? `passed ${passed}/${total} tests` : `passed ${passed}/${total} tests (some failed)`;
982
+ }
967
983
  return {
968
- summary: exitCode === 0 ? `passed ${passed}/${total} tests` : `passed ${passed}/${total} tests (some failed)`,
984
+ summary,
969
985
  metrics: {
970
986
  passed,
971
987
  total,
972
- failed: total - passed,
988
+ failed,
989
+ skipped,
973
990
  duration
974
991
  }
975
992
  };
@@ -1106,20 +1123,31 @@ var cursor = {
1106
1123
  moveToStart: "\x1B[0G",
1107
1124
  clearLine: "\x1B[2K"
1108
1125
  };
1109
- function shouldUseColors(options) {
1126
+ function defaultTerminalContext() {
1127
+ return { isTTY: !!process.stdout.isTTY, env: process.env };
1128
+ }
1129
+ function shouldUseColors(options, ctx) {
1110
1130
  if (options.noColor) return false;
1111
1131
  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;
1132
+ if (!ctx.isTTY) return false;
1133
+ if ("NO_COLOR" in ctx.env) return false;
1134
+ if (ctx.env.TERM === "dumb") return false;
1135
+ return true;
1136
+ }
1137
+ function shouldUseLiveDashboard(options, ctx) {
1138
+ if (options.noTty) return false;
1139
+ if (ctx.env.TURBO_IS_TUI === "true") return false;
1140
+ if (ctx.isTTY && ctx.env.TURBO_HASH != null) return false;
1141
+ if (!ctx.isTTY) return false;
1115
1142
  return true;
1116
1143
  }
1117
1144
  var BaseReporter = class {
1118
1145
  colorEnabled;
1119
1146
  stream;
1120
1147
  taskDepths = /* @__PURE__ */ new Map();
1121
- constructor(options = {}) {
1122
- this.colorEnabled = shouldUseColors(options);
1148
+ constructor(options = {}, ctx) {
1149
+ const termCtx = ctx ?? defaultTerminalContext();
1150
+ this.colorEnabled = shouldUseColors(options, termCtx);
1123
1151
  this.stream = options.format === "json" ? process.stderr : process.stdout;
1124
1152
  }
1125
1153
  /**
@@ -1141,10 +1169,10 @@ var BaseReporter = class {
1141
1169
  return this.colorEnabled ? this.c(ansi.red, "\u2717") : "FAIL";
1142
1170
  }
1143
1171
  /**
1144
- * Get suppressed mark (⊘ or SUPPRESSED)
1172
+ * Get blocked mark (⊘ or BLOCK)
1145
1173
  */
1146
- suppressedMark() {
1147
- return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "SUPPRESSED";
1174
+ blockedMark() {
1175
+ return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "BLOCK";
1148
1176
  }
1149
1177
  /**
1150
1178
  * Get arrow symbol (→ or ->)
@@ -1172,6 +1200,22 @@ var BaseReporter = class {
1172
1200
  this.taskDepths.set(path, depth);
1173
1201
  });
1174
1202
  }
1203
+ /**
1204
+ * Format a completed task result line in name-first format.
1205
+ * Shared by LiveDashboardReporter and SequentialReporter.
1206
+ */
1207
+ formatResultLine(name, result) {
1208
+ const duration = this.c(ansi.dim, `${result.durationMs}ms`);
1209
+ if (result.blocked) {
1210
+ const reason = result.blockedBy ? `by ${result.blockedBy}` : "by dependency";
1211
+ return `${this.blockedMark()} ${this.c(ansi.bold, name)} blocked ${this.c(ansi.dim, `(${reason}, ${duration})`)}`;
1212
+ }
1213
+ const summary = this.extractSummary(result);
1214
+ if (result.ok) {
1215
+ return `${this.okMark()} ${this.c(ansi.bold, name)} verified ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1216
+ }
1217
+ return `${this.failMark()} ${this.c(ansi.bold, name)} failed ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
1218
+ }
1175
1219
  /**
1176
1220
  * Extract summary from task result
1177
1221
  */
@@ -1207,7 +1251,7 @@ var BaseReporter = class {
1207
1251
  for (const r of flatResults) {
1208
1252
  if (r.children) continue;
1209
1253
  if (logsMode === "failed" && r.ok) continue;
1210
- if (r.suppressed) continue;
1254
+ if (r.blocked) continue;
1211
1255
  const status = r.ok ? this.c(ansi.green, "OK") : this.c(ansi.red, "FAIL");
1212
1256
  this.stream.write(
1213
1257
  `
@@ -1232,8 +1276,8 @@ var LiveDashboardReporter = class extends BaseReporter {
1232
1276
  taskOrder = [];
1233
1277
  spinner;
1234
1278
  lineCount = 0;
1235
- constructor(options = {}) {
1236
- super(options);
1279
+ constructor(options = {}, ctx) {
1280
+ super(options, ctx);
1237
1281
  this.topLevelOnly = options.topLevelOnly ?? false;
1238
1282
  this.spinner = new SpinnerManager();
1239
1283
  const cleanup = () => {
@@ -1294,16 +1338,7 @@ var LiveDashboardReporter = class extends BaseReporter {
1294
1338
  return `${indent}${this.arrow()} verifying ${this.c(ansi.bold, displayKey)} ${spinnerChar}`;
1295
1339
  }
1296
1340
  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})`)}`;
1341
+ return `${indent}${this.formatResultLine(displayKey, task.result)}`;
1307
1342
  }
1308
1343
  return "";
1309
1344
  }
@@ -1353,8 +1388,8 @@ var LiveDashboardReporter = class extends BaseReporter {
1353
1388
  };
1354
1389
  var SequentialReporter = class extends BaseReporter {
1355
1390
  topLevelOnly;
1356
- constructor(options = {}) {
1357
- super(options);
1391
+ constructor(options = {}, ctx) {
1392
+ super(options, ctx);
1358
1393
  this.topLevelOnly = options.topLevelOnly ?? false;
1359
1394
  }
1360
1395
  onStart(tasks) {
@@ -1374,27 +1409,8 @@ var SequentialReporter = class extends BaseReporter {
1374
1409
  }
1375
1410
  onTaskComplete(result) {
1376
1411
  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
- }
1412
+ this.stream.write(`${this.formatResultLine(result.path, result)}
1413
+ `);
1398
1414
  }
1399
1415
  onFinish() {
1400
1416
  }
@@ -1429,8 +1445,8 @@ var JSONReporter = class {
1429
1445
  code: t.code,
1430
1446
  durationMs: t.durationMs,
1431
1447
  summaryLine: t.summaryLine,
1432
- ...t.suppressed ? { suppressed: t.suppressed } : {},
1433
- ...t.suppressedBy ? { suppressedBy: t.suppressedBy } : {},
1448
+ ...t.blocked ? { blocked: t.blocked } : {},
1449
+ ...t.blockedBy ? { blockedBy: t.blockedBy } : {},
1434
1450
  ...t.children ? { children: this.serializeTasks(t.children) } : {}
1435
1451
  }));
1436
1452
  }
@@ -1453,13 +1469,17 @@ var QuietReporter = class extends BaseReporter {
1453
1469
  }
1454
1470
  };
1455
1471
  function createReporter(options) {
1472
+ const ctx = defaultTerminalContext();
1456
1473
  if (options.format === "json") {
1457
1474
  return new JSONReporter();
1458
1475
  }
1459
- if (process.stdout.isTTY && !options.noTty) {
1460
- return new LiveDashboardReporter(options);
1476
+ if (options.quiet) {
1477
+ return new QuietReporter(options, ctx);
1478
+ }
1479
+ if (shouldUseLiveDashboard(options, ctx)) {
1480
+ return new LiveDashboardReporter(options, ctx);
1461
1481
  }
1462
- return new SequentialReporter(options);
1482
+ return new SequentialReporter(options, ctx);
1463
1483
  }
1464
1484
 
1465
1485
  // src/runner.ts
@@ -1973,9 +1993,9 @@ var VerificationRunner = class {
1973
1993
  nodeEnv
1974
1994
  );
1975
1995
  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);
1996
+ const allOk = childResults.every((r) => r.ok || r.blocked);
1997
+ const allBlocked = childResults.length > 0 && childResults.every((r) => r.blocked);
1998
+ const anyBlocked = childResults.some((r) => r.blocked);
1979
1999
  const result2 = {
1980
2000
  key: node.key,
1981
2001
  path,
@@ -1986,10 +2006,10 @@ var VerificationRunner = class {
1986
2006
  summaryLine: allOk ? node.successLabel ?? `${node.key}: all passed` : node.failureLabel ?? `${node.key}: some failed`,
1987
2007
  children: childResults
1988
2008
  };
1989
- if (allSuppressed) {
1990
- result2.suppressed = true;
1991
- result2.suppressedBy = childResults[0].suppressedBy;
1992
- } else if (anySuppressed && !allOk) {
2009
+ if (allBlocked) {
2010
+ result2.blocked = true;
2011
+ result2.blockedBy = childResults[0].blockedBy;
2012
+ } else if (anyBlocked && !allOk) {
1993
2013
  }
1994
2014
  this.dependencyTracker.recordResult(result2);
1995
2015
  this.callbacks.onTaskComplete?.(result2);
@@ -2050,8 +2070,8 @@ var VerificationRunner = class {
2050
2070
  durationMs,
2051
2071
  output,
2052
2072
  summaryLine: `${node.key}: terminated`,
2053
- suppressed: true,
2054
- suppressedBy: failedDep ?? "unknown"
2073
+ blocked: true,
2074
+ blockedBy: failedDep ?? "unknown"
2055
2075
  };
2056
2076
  this.dependencyTracker.recordResult(result2);
2057
2077
  this.callbacks.onTaskComplete?.(result2);
@@ -2087,8 +2107,8 @@ var VerificationRunner = class {
2087
2107
  if (failedDep) {
2088
2108
  result = {
2089
2109
  ...result,
2090
- suppressed: true,
2091
- suppressedBy: failedDep
2110
+ blocked: true,
2111
+ blockedBy: failedDep
2092
2112
  };
2093
2113
  }
2094
2114
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/discovery.ts","../src/schemas/package-json.ts","../src/filter.ts","../src/tree.ts","../src/init/detect.ts","../src/init/generate.ts","../src/init/prompts.ts","../src/init/write.ts","../src/init/index.ts","../src/parsers/biome.ts","../src/parsers/generic.ts","../src/parsers/gotest.ts","../src/parsers/tsc.ts","../src/parsers/vitest.ts","../src/parsers/index.ts","../src/spinner.ts","../src/reporter.ts","../src/runner.ts","../src/dependency-tracker.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { z } from \"zod\"\nimport type { VerificationNode, VerifyConfig, VerifyOptions } from \"./types.js\"\n\n/**\n * Error thrown when config validation fails\n */\nexport class ConfigError extends Error {\n constructor(\n message: string,\n public readonly configPath?: string,\n ) {\n super(message)\n this.name = \"ConfigError\"\n }\n}\n\n/**\n * Reusable env schema - allows string or null values\n */\nconst EnvSchema = z.record(z.string(), z.string().nullable()).optional()\n\n/**\n * Zod schema for VerificationCommand\n */\nconst VerificationCommandSchema = z.object({\n cmd: z.string(),\n args: z.array(z.string()),\n cwd: z.string().optional(),\n env: EnvSchema,\n timeout: z.number().positive().optional(),\n})\n\n/**\n * Zod schema for VerificationNode (recursive)\n */\nconst VerificationNodeSchema: z.ZodType<VerificationNode> = z.lazy(() =>\n z.object({\n key: z\n .string()\n .min(1, \"Task key cannot be empty\")\n .refine(key => !key.includes(\":\"), {\n message: \"Task key cannot contain ':' (reserved for paths)\",\n }),\n name: z.string().optional(),\n run: z.union([z.string(), VerificationCommandSchema]).optional(),\n children: z.array(VerificationNodeSchema).optional(),\n strategy: z.enum([\"parallel\", \"sequential\", \"fail-fast\"]).optional(),\n parser: z.string().optional(),\n successLabel: z.string().optional(),\n failureLabel: z.string().optional(),\n reportingDependsOn: z.array(z.string()).optional(),\n timeout: z.number().positive().optional(),\n env: EnvSchema,\n }),\n) as z.ZodType<VerificationNode>\n\n/**\n * Zod schema for VerifyOptions\n */\nconst VerifyOptionsSchema = z.object({\n logs: z.enum([\"all\", \"failed\", \"none\"]).optional(),\n format: z.enum([\"human\", \"json\"]).optional(),\n filter: z.array(z.string()).optional(),\n cwd: z.string().optional(),\n noColor: z.boolean().optional(),\n topLevelOnly: z.boolean().optional(),\n noTty: z.boolean().optional(),\n passthrough: z.array(z.string()).optional(),\n})\n\n/**\n * Zod schema for PackageDiscoveryOptions\n */\nconst PackageDiscoveryOptionsSchema = z.object({\n patterns: z.array(z.string()).optional(),\n filter: z.array(z.string()).optional(),\n changed: z.boolean().optional(),\n})\n\n/**\n * Zod schema for VerifyConfig\n */\nconst VerifyConfigSchema = z.object({\n tasks: z.array(VerificationNodeSchema),\n packages: PackageDiscoveryOptionsSchema.optional(),\n options: VerifyOptionsSchema.optional(),\n env: EnvSchema,\n})\n\n/**\n * Validate a config object and return typed result\n */\nexport function validateConfig(\n value: unknown,\n configPath?: string,\n): VerifyConfig {\n const result = VerifyConfigSchema.safeParse(value)\n\n if (!result.success) {\n const errors = result.error.issues.map(issue => {\n const path = issue.path.join(\".\")\n return path ? `${path}: ${issue.message}` : issue.message\n })\n throw new ConfigError(\n `Invalid config:\\n - ${errors.join(\"\\n - \")}`,\n configPath,\n )\n }\n\n return result.data\n}\n\n/**\n * Helper function for defining config with type inference\n */\nexport function defineConfig(config: VerifyConfig): VerifyConfig {\n return config\n}\n\n/**\n * Helper function for defining a single verification task\n */\nexport function defineTask(task: VerificationNode): VerificationNode {\n return task\n}\n\n/**\n * Config file names to search for (in order of priority)\n */\nconst CONFIG_FILES = [\n \"verify.config.ts\",\n \"verify.config.mts\",\n \"verify.config.js\",\n \"verify.config.mjs\",\n]\n\n/**\n * Find config file in directory\n */\nexport function findConfigFile(cwd: string): string | null {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n if (existsSync(filepath)) {\n return filepath\n }\n }\n return null\n}\n\n/**\n * Load config from file\n */\nexport async function loadConfig(\n configPath: string,\n): Promise<VerifyConfig | null> {\n const absolutePath = resolve(configPath)\n\n if (!existsSync(absolutePath)) {\n return null\n }\n\n // Use dynamic import with file URL for cross-platform compatibility\n const fileUrl = pathToFileURL(absolutePath).href\n const module = (await import(fileUrl)) as { default?: unknown }\n\n if (!module.default) {\n throw new ConfigError(`Config file must have a default export`, configPath)\n }\n\n // Validate the config using zod\n return validateConfig(module.default, configPath)\n}\n\n/**\n * Load config from cwd or specified path\n */\nexport async function loadConfigFromCwd(\n cwd: string,\n configPath?: string,\n): Promise<VerifyConfig | null> {\n if (configPath) {\n return loadConfig(configPath)\n }\n\n const foundPath = findConfigFile(cwd)\n if (!foundPath) {\n return null\n }\n\n return loadConfig(foundPath)\n}\n\n/**\n * Helper type that requires all keys to be present but preserves original value types.\n * This is used to ensure mergeOptions handles all VerifyOptions properties.\n */\ntype AllKeys<T> = { [K in keyof Required<T>]: T[K] }\n\n/**\n * Merge options with defaults.\n *\n * NOTE: The `satisfies AllKeys<VerifyOptions>` ensures this function handles\n * all properties of VerifyOptions. If you add a new option to VerifyOptions,\n * TypeScript will error here until you add it to the return object.\n */\nexport function mergeOptions(\n configOptions?: VerifyOptions,\n cliOptions?: Partial<VerifyOptions>,\n): VerifyOptions {\n return {\n logs: cliOptions?.logs ?? configOptions?.logs ?? \"failed\",\n format: cliOptions?.format ?? configOptions?.format ?? \"human\",\n filter: cliOptions?.filter ?? configOptions?.filter,\n cwd: cliOptions?.cwd ?? configOptions?.cwd ?? process.cwd(),\n noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,\n topLevelOnly:\n cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,\n noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,\n passthrough: cliOptions?.passthrough ?? configOptions?.passthrough,\n } satisfies AllKeys<VerifyOptions>\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\"\nimport { join, relative } from \"node:path\"\nimport { findConfigFile, loadConfig } from \"./config.js\"\nimport { parsePackageJson } from \"./schemas/package-json.js\"\nimport type { PackageDiscoveryOptions, VerifyConfig } from \"./types.js\"\n\n/**\n * Discovered package with its config\n */\nexport interface DiscoveredPackage {\n /** Package name from package.json */\n name: string\n /** Relative path from root */\n path: string\n /** Absolute path */\n absolutePath: string\n /** Loaded verify config (if exists) */\n config: VerifyConfig | null\n}\n\n/**\n * Default glob patterns for package discovery\n */\nconst DEFAULT_PATTERNS = [\"packages/*\", \"apps/*\"]\n\n/**\n * Find directories matching patterns\n */\nfunction findMatchingDirs(rootDir: string, patterns: string[]): string[] {\n const results: string[] = []\n\n for (const pattern of patterns) {\n // Handle simple patterns like \"packages/*\"\n if (pattern.endsWith(\"/*\")) {\n const parentDir = pattern.slice(0, -2)\n const parentPath = join(rootDir, parentDir)\n\n if (existsSync(parentPath) && statSync(parentPath).isDirectory()) {\n const entries = readdirSync(parentPath)\n for (const entry of entries) {\n const entryPath = join(parentPath, entry)\n if (statSync(entryPath).isDirectory()) {\n results.push(entryPath)\n }\n }\n }\n } else {\n // Direct path\n const dirPath = join(rootDir, pattern)\n if (existsSync(dirPath) && statSync(dirPath).isDirectory()) {\n results.push(dirPath)\n }\n }\n }\n\n return results\n}\n\n/**\n * Read package name from package.json\n */\nfunction getPackageName(packageDir: string): string | null {\n const packageJsonPath = join(packageDir, \"package.json\")\n if (!existsSync(packageJsonPath)) {\n return null\n }\n\n try {\n const content = readFileSync(packageJsonPath, \"utf-8\")\n const parsed = parsePackageJson(content)\n return parsed?.name ?? null\n } catch {\n // File read error\n return null\n }\n}\n\n/**\n * Discover packages in a monorepo\n */\nexport async function discoverPackages(\n rootDir: string,\n options: PackageDiscoveryOptions = {},\n): Promise<DiscoveredPackage[]> {\n const patterns = options.patterns ?? DEFAULT_PATTERNS\n const matchingDirs = findMatchingDirs(rootDir, patterns)\n\n const packages: DiscoveredPackage[] = []\n\n for (const dir of matchingDirs) {\n const name = getPackageName(dir)\n if (!name) continue // Skip directories without package.json\n\n // Check filter\n if (options.filter && options.filter.length > 0) {\n const matches = options.filter.some(\n f =>\n name === f || name.includes(f) || relative(rootDir, dir).includes(f),\n )\n if (!matches) continue\n }\n\n // Try to load verify config\n const configPath = findConfigFile(dir)\n const config = configPath ? await loadConfig(configPath) : null\n\n packages.push({\n name,\n path: relative(rootDir, dir),\n absolutePath: dir,\n config,\n })\n }\n\n return packages\n}\n\n/**\n * Check if a package has changed (git-aware)\n * This is a placeholder - full implementation would use git diff\n */\nexport async function hasPackageChanged(\n _packagePath: string,\n _baseBranch = \"main\",\n): Promise<boolean> {\n // TODO: Implement git-aware change detection\n // For now, always return true (include all packages)\n return true\n}\n","import { z } from \"zod\"\n\n/**\n * Minimal zod schema for package.json\n * Only validates the fields we actually use\n */\nexport const PackageJsonSchema = z\n .object({\n name: z.string().optional(),\n scripts: z.record(z.string(), z.string()).optional(),\n })\n .passthrough() // Allow other fields we don't care about\n\n/**\n * Typed result from parsing package.json\n */\nexport type PackageJson = z.infer<typeof PackageJsonSchema>\n\n/**\n * Parse package.json content safely\n * Returns null if parsing fails (invalid JSON or schema mismatch)\n */\nexport function parsePackageJson(content: string): PackageJson | null {\n try {\n const parsed: unknown = JSON.parse(content)\n const result = PackageJsonSchema.safeParse(parsed)\n return result.success ? result.data : null\n } catch {\n // JSON parse error\n return null\n }\n}\n","import leven from \"leven\"\nimport { collectPaths, PATH_SEPARATOR } from \"./tree.js\"\nimport type { VerificationNode } from \"./types.js\"\n\n/**\n * Result of resolving a filter to a valid task path\n */\nexport interface ResolvedFilter {\n /** The original filter string provided by the user */\n original: string\n /** The resolved full task path */\n resolved: string\n /** Whether this was resolved via child shortcut (e.g., \"tsc\" → \"types:tsc\") */\n wasShortcut: boolean\n}\n\n/**\n * Error thrown when a task filter doesn't match any existing task\n */\nexport class TaskNotFoundError extends Error {\n readonly exitCode = 2\n\n constructor(\n public readonly filter: string,\n public readonly suggestion: string | undefined,\n public readonly availableTasks: string[],\n ) {\n super(buildErrorMessage(filter, suggestion, availableTasks))\n this.name = \"TaskNotFoundError\"\n }\n}\n\n/**\n * Error thrown when a task filter matches multiple tasks ambiguously\n */\nexport class AmbiguousTaskError extends Error {\n readonly exitCode = 2\n\n constructor(\n public readonly filter: string,\n public readonly matches: string[],\n ) {\n super(buildAmbiguousErrorMessage(filter, matches))\n this.name = \"AmbiguousTaskError\"\n }\n}\n\n/**\n * Build error message for task not found\n */\nfunction buildErrorMessage(\n filter: string,\n suggestion: string | undefined,\n availableTasks: string[],\n): string {\n let message = `Task \"${filter}\" not found.`\n\n if (suggestion) {\n message += `\\n\\nDid you mean \"${suggestion}\"?`\n }\n\n message += \"\\n\\nAvailable tasks:\"\n for (const task of availableTasks) {\n message += `\\n ${task}`\n }\n\n return message\n}\n\n/**\n * Build error message for ambiguous task\n */\nfunction buildAmbiguousErrorMessage(filter: string, matches: string[]): string {\n let message = `Task \"${filter}\" is ambiguous.`\n message += \"\\n\\nMatches multiple tasks:\"\n for (const match of matches) {\n message += `\\n ${match}`\n }\n return message\n}\n\n/**\n * Find the single best suggestion using Levenshtein distance.\n * Returns undefined if no good match (distance > threshold).\n */\nexport function findBestSuggestion(\n availablePaths: string[],\n invalidFilter: string,\n): string | undefined {\n let bestPath: string | undefined\n let bestDistance = Number.POSITIVE_INFINITY\n\n // Threshold: distance <= 2 for short names, or <= length/3 for longer\n const threshold = Math.max(2, Math.floor(invalidFilter.length / 3))\n\n for (const path of availablePaths) {\n // Check against full path\n const distance = leven(invalidFilter, path)\n if (distance < bestDistance && distance <= threshold) {\n bestDistance = distance\n bestPath = path\n }\n\n // Also check against just the last segment (child key)\n const lastSegment = path.split(PATH_SEPARATOR).pop()\n if (lastSegment && lastSegment !== path) {\n const segmentDistance = leven(invalidFilter, lastSegment)\n if (segmentDistance < bestDistance && segmentDistance <= threshold) {\n bestDistance = segmentDistance\n bestPath = path\n }\n }\n }\n\n return bestPath\n}\n\n/**\n * Resolve a single filter to a valid task path.\n * Returns the resolved filter or throws an error.\n */\nfunction resolveFilter(\n filter: string,\n availablePaths: string[],\n): ResolvedFilter {\n // 1. Exact match - filter matches a path exactly\n if (availablePaths.includes(filter)) {\n return { original: filter, resolved: filter, wasShortcut: false }\n }\n\n // 2. Prefix match - filter is a prefix of paths (e.g., \"types\" matches \"types:tsc\")\n const prefixMatches = availablePaths.filter(\n path => path === filter || path.startsWith(`${filter}${PATH_SEPARATOR}`),\n )\n if (prefixMatches.length > 0) {\n // If the filter itself is a valid path (parent node), use it\n // The runner will handle running children\n return { original: filter, resolved: filter, wasShortcut: false }\n }\n\n // 3. Child shortcut - filter matches the last segment of path(s)\n const childMatches = availablePaths.filter(path => {\n const lastSegment = path.split(PATH_SEPARATOR).pop()\n return lastSegment === filter\n })\n\n if (childMatches.length === 1) {\n // Unambiguous child match\n return {\n original: filter,\n resolved: childMatches[0],\n wasShortcut: true,\n }\n }\n\n if (childMatches.length > 1) {\n // Ambiguous - multiple paths end with this key\n throw new AmbiguousTaskError(filter, childMatches)\n }\n\n // 4. No match - find suggestion and throw error\n const suggestion = findBestSuggestion(availablePaths, filter)\n throw new TaskNotFoundError(filter, suggestion, availablePaths)\n}\n\n/**\n * Resolve and validate all filters before running any tasks.\n * Fails fast on first invalid filter.\n *\n * @param nodes - The verification task tree\n * @param filters - User-provided filter strings\n * @returns Array of resolved filters\n * @throws TaskNotFoundError if a filter doesn't match any task\n * @throws AmbiguousTaskError if a filter matches multiple tasks\n */\nexport function resolveFilters(\n nodes: VerificationNode[],\n filters: string[],\n): ResolvedFilter[] {\n const availablePaths = collectPaths(nodes)\n const resolved: ResolvedFilter[] = []\n\n for (const filter of filters) {\n resolved.push(resolveFilter(filter, availablePaths))\n }\n\n return resolved\n}\n","import type { VerificationNode } from \"./types.js\"\n\n/**\n * Path separator used in task paths\n */\nexport const PATH_SEPARATOR = \":\"\n\n/**\n * Build a task path from parent path and key\n */\nexport function buildTaskPath(parentPath: string, key: string): string {\n return parentPath ? `${parentPath}${PATH_SEPARATOR}${key}` : key\n}\n\n/**\n * Visitor function called for each node during tree traversal\n */\nexport type NodeVisitor = (\n node: VerificationNode,\n path: string,\n depth: number,\n) => void\n\n/**\n * Walk all nodes in a verification tree in depth-first order\n *\n * @param nodes - The nodes to walk\n * @param visitor - Function called for each node with (node, path, depth)\n * @param parentPath - Parent path prefix (used for recursion)\n * @param depth - Current depth (used for recursion)\n */\nexport function walkNodes(\n nodes: VerificationNode[],\n visitor: NodeVisitor,\n parentPath = \"\",\n depth = 0,\n): void {\n for (const node of nodes) {\n const path = buildTaskPath(parentPath, node.key)\n visitor(node, path, depth)\n if (node.children) {\n walkNodes(node.children, visitor, path, depth + 1)\n }\n }\n}\n\n/**\n * Collect all task paths from a verification tree\n */\nexport function collectPaths(nodes: VerificationNode[]): string[] {\n const paths: string[] = []\n walkNodes(nodes, (_node, path) => {\n paths.push(path)\n })\n return paths\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { type PackageJson, parsePackageJson } from \"../schemas/package-json.js\"\n\n/**\n * A detected task candidate from package.json\n */\nexport interface DetectedTask {\n /** Suggested key for the task */\n key: string\n /** Human-readable name */\n name: string\n /** The npm script name that was detected */\n scriptName: string\n /** The command to run (optimized direct path when possible) */\n command: string\n /** Category for grouping (format, types, logic, build) */\n category: \"format\" | \"types\" | \"logic\" | \"build\" | \"other\"\n /** Parser to use for this task */\n parser?: string\n /**\n * Tasks that must pass for this task's failure to be reported.\n * Auto-populated based on category (types/logic/build depend on format).\n */\n reportingDependsOn?: string[]\n}\n\n/**\n * Tool detection patterns - maps script content to optimized commands\n */\ninterface ToolPattern {\n /** Regex to match in script content */\n pattern: RegExp\n /** Binary name in node_modules/.bin */\n binary: string\n /** Arguments to append (extracted from script or default) */\n getArgs: (match: RegExpMatchArray, scriptContent: string) => string\n /** Parser to use */\n parser?: string\n}\n\nconst TOOL_PATTERNS: ToolPattern[] = [\n // Biome\n {\n pattern: /\\bbiome\\s+(check|lint|format)/,\n binary: \"biome\",\n getArgs: (match, content) => {\n // Extract the full biome command with args\n const biomeMatch = content.match(/biome\\s+([^&|;]+)/)\n return biomeMatch ? biomeMatch[1].trim() : \"check .\"\n },\n parser: \"biome\",\n },\n // ESLint\n {\n pattern: /\\beslint\\b/,\n binary: \"eslint\",\n getArgs: (_, content) => {\n const eslintMatch = content.match(/eslint\\s+([^&|;]+)/)\n return eslintMatch ? eslintMatch[1].trim() : \".\"\n },\n },\n // Prettier\n {\n pattern: /\\bprettier\\b/,\n binary: \"prettier\",\n getArgs: (_, content) => {\n const prettierMatch = content.match(/prettier\\s+([^&|;]+)/)\n return prettierMatch ? prettierMatch[1].trim() : \"--check .\"\n },\n },\n // TypeScript\n {\n pattern: /\\btsc\\b/,\n binary: \"tsc\",\n getArgs: (_, content) => {\n const tscMatch = content.match(/tsc\\s+([^&|;]+)/)\n return tscMatch ? tscMatch[1].trim() : \"--noEmit\"\n },\n parser: \"tsc\",\n },\n // tsgo\n {\n pattern: /\\btsgo\\b/,\n binary: \"tsgo\",\n getArgs: (_, content) => {\n const tsgoMatch = content.match(/tsgo\\s+([^&|;]+)/)\n return tsgoMatch ? tsgoMatch[1].trim() : \"--noEmit\"\n },\n parser: \"tsc\",\n },\n // Vitest\n {\n pattern: /\\bvitest\\b/,\n binary: \"vitest\",\n getArgs: (_, content) => {\n // Check if it's watch mode or run mode\n if (content.includes(\"vitest run\")) return \"run\"\n if (content.includes(\"vitest watch\")) return \"run\" // Convert watch to run for verify\n return \"run\"\n },\n parser: \"vitest\",\n },\n // Jest\n {\n pattern: /\\bjest\\b/,\n binary: \"jest\",\n getArgs: () => \"\",\n },\n // Mocha\n {\n pattern: /\\bmocha\\b/,\n binary: \"mocha\",\n getArgs: () => \"\",\n },\n // tsup\n {\n pattern: /\\btsup\\b/,\n binary: \"tsup\",\n getArgs: (_, content) => {\n const tsupMatch = content.match(/tsup\\s+([^&|;]+)/)\n return tsupMatch ? tsupMatch[1].trim() : \"\"\n },\n },\n // esbuild\n {\n pattern: /\\besbuild\\b/,\n binary: \"esbuild\",\n getArgs: (_, content) => {\n const esbuildMatch = content.match(/esbuild\\s+([^&|;]+)/)\n return esbuildMatch ? esbuildMatch[1].trim() : \"\"\n },\n },\n]\n\n/**\n * Patterns to detect verification-related scripts by name\n */\nconst SCRIPT_NAME_PATTERNS: Array<{\n pattern: RegExp\n key: string\n name: string\n category: DetectedTask[\"category\"]\n}> = [\n // Format/Lint patterns\n {\n pattern: /^(lint|eslint|biome|prettier|format)$/i,\n key: \"format\",\n name: \"Format & Lint\",\n category: \"format\",\n },\n {\n pattern: /^(lint:fix|format:fix|fix)$/i,\n key: \"format\",\n name: \"Format & Lint\",\n category: \"format\",\n },\n {\n pattern: /^verify:format$/i,\n key: \"format\",\n name: \"Format\",\n category: \"format\",\n },\n\n // Type checking patterns\n {\n pattern: /^(typecheck|type-check|tsc|types|check-types)$/i,\n key: \"types\",\n name: \"Type Check\",\n category: \"types\",\n },\n {\n pattern: /^verify:types$/i,\n key: \"types\",\n name: \"Types\",\n category: \"types\",\n },\n\n // Test patterns\n {\n pattern: /^(test|tests|vitest|jest|mocha|ava)$/i,\n key: \"test\",\n name: \"Tests\",\n category: \"logic\",\n },\n {\n pattern: /^test:(unit|integration|e2e)$/i,\n key: \"test\",\n name: \"Tests\",\n category: \"logic\",\n },\n {\n pattern: /^verify:logic$/i,\n key: \"logic\",\n name: \"Logic Tests\",\n category: \"logic\",\n },\n\n // Build patterns\n {\n pattern: /^(build|compile)$/i,\n key: \"build\",\n name: \"Build\",\n category: \"build\",\n },\n]\n\n/**\n * Read and parse package.json from a directory\n */\nfunction readPackageJson(cwd: string): PackageJson | null {\n const packageJsonPath = join(cwd, \"package.json\")\n\n if (!existsSync(packageJsonPath)) {\n return null\n }\n\n try {\n const content = readFileSync(packageJsonPath, \"utf-8\")\n return parsePackageJson(content)\n } catch {\n return null\n }\n}\n\n/**\n * Check if a binary exists in node_modules/.bin\n */\nfunction binaryExists(cwd: string, binary: string): boolean {\n return existsSync(join(cwd, \"node_modules\", \".bin\", binary))\n}\n\n/**\n * Try to extract an optimized direct command from script content.\n * Returns clean binary names since verify automatically includes\n * node_modules/.bin in PATH.\n */\nfunction extractOptimizedCommand(\n cwd: string,\n scriptContent: string,\n): { command: string; parser?: string } | null {\n for (const tool of TOOL_PATTERNS) {\n const match = scriptContent.match(tool.pattern)\n if (match && binaryExists(cwd, tool.binary)) {\n const args = tool.getArgs(match, scriptContent)\n // Use clean binary name - verify automatically adds node_modules/.bin to PATH\n const command = args ? `${tool.binary} ${args}` : tool.binary\n return { command, parser: tool.parser }\n }\n }\n return null\n}\n\n/**\n * Detect verification tasks from package.json scripts\n */\nexport function detectFromPackageJson(cwd: string): DetectedTask[] {\n const pkg = readPackageJson(cwd)\n\n if (!pkg?.scripts) {\n return []\n }\n\n const detected: DetectedTask[] = []\n const seenKeys = new Set<string>()\n\n for (const [scriptName, scriptContent] of Object.entries(pkg.scripts)) {\n // Skip scripts that are just running other scripts (like \"verify\": \"run-s ...\")\n if (\n scriptContent.includes(\"run-s\") ||\n scriptContent.includes(\"run-p\") ||\n scriptContent.includes(\"npm-run-all\")\n ) {\n continue\n }\n\n // Check against detection patterns\n for (const { pattern, key, name, category } of SCRIPT_NAME_PATTERNS) {\n if (pattern.test(scriptName)) {\n // Avoid duplicates for the same key\n const uniqueKey = seenKeys.has(key) ? `${key}-${scriptName}` : key\n if (!seenKeys.has(uniqueKey)) {\n seenKeys.add(uniqueKey)\n\n // Try to extract optimized command\n const optimized = extractOptimizedCommand(cwd, scriptContent)\n\n detected.push({\n key: uniqueKey,\n name,\n scriptName,\n command: optimized?.command ?? `npm run ${scriptName}`,\n category,\n parser: optimized?.parser,\n })\n }\n break\n }\n }\n }\n\n // Sort by category priority: format -> types -> logic -> build -> other\n const categoryOrder: Record<DetectedTask[\"category\"], number> = {\n format: 0,\n types: 1,\n logic: 2,\n build: 3,\n other: 4,\n }\n\n detected.sort((a, b) => categoryOrder[a.category] - categoryOrder[b.category])\n\n // Add reportingDependsOn for non-format tasks if a format task exists\n // This reduces noise when a syntax error causes multiple tools to fail\n const hasFormatTask = detected.some(t => t.category === \"format\")\n if (hasFormatTask) {\n for (const task of detected) {\n if (task.category !== \"format\" && task.category !== \"other\") {\n task.reportingDependsOn = [\"format\"]\n }\n }\n }\n\n return detected\n}\n\n/**\n * Detect the package manager being used\n */\nexport function detectPackageManager(cwd: string): \"npm\" | \"pnpm\" | \"yarn\" {\n if (existsSync(join(cwd, \"pnpm-lock.yaml\"))) {\n return \"pnpm\"\n }\n if (existsSync(join(cwd, \"yarn.lock\"))) {\n return \"yarn\"\n }\n return \"npm\"\n}\n\n/**\n * Get the run command for a package manager\n */\nexport function getRunCommand(\n packageManager: \"npm\" | \"pnpm\" | \"yarn\",\n scriptName: string,\n): string {\n switch (packageManager) {\n case \"pnpm\":\n return `pnpm ${scriptName}`\n case \"yarn\":\n return `yarn ${scriptName}`\n default:\n return `npm run ${scriptName}`\n }\n}\n\n/**\n * Detect tasks with proper package manager commands\n * Uses optimized direct binary names when possible, falls back to package manager\n */\nexport function detectTasks(cwd: string): DetectedTask[] {\n const packageManager = detectPackageManager(cwd)\n const tasks = detectFromPackageJson(cwd)\n\n // For tasks without optimized commands, use package manager\n return tasks.map(task => {\n // If command is already optimized (doesn't start with npm/pnpm/yarn), keep it\n if (!task.command.startsWith(\"npm run \")) {\n return task\n }\n // Otherwise use package manager command\n return {\n ...task,\n command: getRunCommand(packageManager, task.scriptName),\n }\n })\n}\n","import type { DetectedTask } from \"./detect.js\"\n\n/**\n * Output format for the generated config\n */\nexport type OutputFormat = \"ts\" | \"mts\" | \"js\" | \"mjs\"\n\n/**\n * Determine output format from file path\n */\nexport function getOutputFormat(filePath: string): OutputFormat {\n if (filePath.endsWith(\".mts\")) return \"mts\"\n if (filePath.endsWith(\".mjs\")) return \"mjs\"\n if (filePath.endsWith(\".js\")) return \"js\"\n return \"ts\" // Default to TypeScript\n}\n\n/**\n * Generate the import statement based on format\n */\nfunction generateImport(format: OutputFormat): string {\n // All formats use ESM import syntax\n return `import { defineConfig } from \"@halecraft/verify\"`\n}\n\n/**\n * Generate a task object as a string\n */\nfunction generateTask(task: DetectedTask, indent: string): string {\n const parts = [`key: \"${task.key}\"`, `run: \"${task.command}\"`]\n if (task.parser) {\n parts.push(`parser: \"${task.parser}\"`)\n }\n if (task.reportingDependsOn && task.reportingDependsOn.length > 0) {\n const deps = task.reportingDependsOn.map(d => `\"${d}\"`).join(\", \")\n parts.push(`reportingDependsOn: [${deps}]`)\n }\n return `${indent}{ ${parts.join(\", \")} }`\n}\n\n/**\n * Generate the skeleton config when no tasks are detected\n */\nfunction generateSkeleton(format: OutputFormat): string {\n const importStatement = generateImport(format)\n\n return `${importStatement}\n\nexport default defineConfig({\n env: {\n NO_COLOR: \"1\",\n },\n tasks: [\n // Add your verification tasks here\n // Example:\n // { key: \"format\", run: \"biome check .\" },\n // { key: \"types\", run: \"tsc --noEmit\" },\n // { key: \"test\", run: \"vitest run\" },\n ],\n})\n`\n}\n\n/**\n * Generate config content from selected tasks\n */\nexport function generateConfigContent(\n tasks: DetectedTask[],\n format: OutputFormat,\n): string {\n // If no tasks, generate skeleton\n if (tasks.length === 0) {\n return generateSkeleton(format)\n }\n\n const importStatement = generateImport(format)\n const indent = \" \"\n\n // Group tasks by category for better organization\n const taskLines = tasks.map(task => generateTask(task, indent))\n\n return `${importStatement}\n\nexport default defineConfig({\n env: {\n NO_COLOR: \"1\",\n },\n tasks: [\n${taskLines.join(\",\\n\")},\n ],\n})\n`\n}\n\n/**\n * Get the default config filename\n */\nexport function getDefaultConfigPath(): string {\n return \"verify.config.ts\"\n}\n","import type { DetectedTask } from \"./detect.js\"\n\n/**\n * Options for the prompt flow\n */\nexport interface PromptOptions {\n /** Skip interactive prompts and auto-accept all */\n yes: boolean\n /** Whether we're in a TTY environment */\n isTTY: boolean\n}\n\n/**\n * Result of the prompt flow\n */\nexport interface PromptResult {\n /** Selected tasks */\n tasks: DetectedTask[]\n /** Whether the user cancelled */\n cancelled: boolean\n}\n\n/**\n * Check if we should skip prompts\n */\nexport function shouldSkipPrompts(options: PromptOptions): boolean {\n return options.yes || !options.isTTY\n}\n\n/**\n * Run the interactive task selection prompt\n */\nexport async function promptForTasks(\n detectedTasks: DetectedTask[],\n options: PromptOptions,\n): Promise<PromptResult> {\n // If no tasks detected, return empty (will use skeleton)\n if (detectedTasks.length === 0) {\n if (!shouldSkipPrompts(options)) {\n console.log(\n \"\\n⚠️ No verification scripts detected in package.json.\\n A skeleton config will be created.\\n\",\n )\n }\n return { tasks: [], cancelled: false }\n }\n\n // If skipping prompts, return all detected tasks\n if (shouldSkipPrompts(options)) {\n console.log(`\\n✓ Auto-selecting ${detectedTasks.length} detected task(s)\\n`)\n return { tasks: detectedTasks, cancelled: false }\n }\n\n // Dynamic import of @inquirer/prompts to avoid loading it when not needed\n try {\n const { checkbox } = await import(\"@inquirer/prompts\")\n\n console.log(\"\\n🔍 Detected verification scripts in package.json:\\n\")\n\n const choices = detectedTasks.map(task => ({\n name: `${task.name} (${task.command})`,\n value: task,\n checked: true, // Pre-select all by default\n }))\n\n const selected = await checkbox<DetectedTask>({\n message: \"Select tasks to include in your config:\",\n choices,\n instructions: false,\n })\n\n if (selected.length === 0) {\n console.log(\n \"\\n⚠️ No tasks selected. A skeleton config will be created.\\n\",\n )\n }\n\n return { tasks: selected, cancelled: false }\n } catch (error) {\n // Handle Ctrl+C or other cancellation\n if (\n error instanceof Error &&\n (error.message.includes(\"User force closed\") ||\n error.name === \"ExitPromptError\")\n ) {\n return { tasks: [], cancelled: true }\n }\n throw error\n }\n}\n","import { existsSync, writeFileSync } from \"node:fs\"\nimport { resolve } from \"node:path\"\nimport type { DetectedTask } from \"./detect.js\"\n\n/**\n * Result of checking if a file exists\n */\nexport interface FileCheckResult {\n exists: boolean\n path: string\n}\n\n/**\n * Check if the config file already exists\n */\nexport function checkConfigExists(\n cwd: string,\n configPath: string,\n): FileCheckResult {\n const absolutePath = resolve(cwd, configPath)\n return {\n exists: existsSync(absolutePath),\n path: absolutePath,\n }\n}\n\n/**\n * Write the config file\n */\nexport function writeConfigFile(\n cwd: string,\n configPath: string,\n content: string,\n): void {\n const absolutePath = resolve(cwd, configPath)\n writeFileSync(absolutePath, content, \"utf-8\")\n}\n\n/**\n * Print warning about existing file\n */\nexport function printExistsWarning(path: string): void {\n console.error(`\\n⚠️ Config file already exists: ${path}`)\n console.error(\" Use --force to overwrite.\\n\")\n}\n\n/**\n * Options for success message\n */\nexport interface SuccessOptions {\n /** Path to the created config file */\n configPath: string\n /** Tasks that were configured */\n tasks: DetectedTask[]\n /** Whether optimized commands were used */\n hasOptimizedCommands: boolean\n /** Script names that can potentially be removed */\n removableScripts: string[]\n}\n\n/**\n * Print success message with educational notes\n */\nexport function printSuccess(options: SuccessOptions): void {\n const { configPath, tasks, hasOptimizedCommands, removableScripts } = options\n\n console.log(`\\n✅ Created ${configPath}`)\n console.log(\"\")\n\n // Quick start\n console.log(\" Quick start:\")\n console.log(\" $ verify # Run all verifications\")\n console.log(\" $ verify --top-level # Show only top-level tasks\")\n console.log(\" $ verify format # Run only 'format' task\")\n console.log(\"\")\n\n // Performance note if optimized commands were used\n if (hasOptimizedCommands) {\n console.log(\n \" ⚡ Performance: Using direct tool paths for faster execution\",\n )\n console.log(\n \" (avoids ~250ms overhead per command from package manager)\",\n )\n console.log(\"\")\n }\n\n // Cleanup suggestion if there are removable scripts\n if (removableScripts.length > 0) {\n console.log(\" 💡 Optional cleanup:\")\n console.log(\n \" You can remove these scripts from package.json if you only\",\n )\n console.log(\" run them via 'verify' (keeps package.json cleaner):\")\n for (const script of removableScripts) {\n console.log(` - \"${script}\"`)\n }\n console.log(\"\")\n }\n\n // Parser note if parsers were detected\n const tasksWithParsers = tasks.filter(t => t.parser)\n if (tasksWithParsers.length > 0) {\n console.log(\" 📊 Rich output: Parsers detected for detailed summaries:\")\n for (const task of tasksWithParsers) {\n console.log(` - ${task.key}: ${task.parser}`)\n }\n console.log(\"\")\n }\n\n console.log(\" 📖 Docs: https://github.com/halecraft/verify\")\n console.log(\"\")\n}\n","import { detectTasks } from \"./detect.js\"\nimport {\n generateConfigContent,\n getDefaultConfigPath,\n getOutputFormat,\n} from \"./generate.js\"\nimport { promptForTasks, shouldSkipPrompts } from \"./prompts.js\"\nimport {\n checkConfigExists,\n printExistsWarning,\n printSuccess,\n writeConfigFile,\n} from \"./write.js\"\n\n/**\n * Options for the init command\n */\nexport interface InitOptions {\n /** Custom config output path */\n config?: string\n /** Force overwrite existing file */\n force: boolean\n /** Skip interactive prompts */\n yes: boolean\n /** Working directory */\n cwd: string\n}\n\n/**\n * Result of the init command\n */\nexport interface InitResult {\n /** Whether init succeeded */\n success: boolean\n /** Path to the created config file (if successful) */\n configPath?: string\n /** Error message (if failed) */\n error?: string\n}\n\n/**\n * Run the init command\n */\nexport async function runInit(options: InitOptions): Promise<InitResult> {\n const configPath = options.config ?? getDefaultConfigPath()\n const format = getOutputFormat(configPath)\n\n // Check if file already exists\n const fileCheck = checkConfigExists(options.cwd, configPath)\n if (fileCheck.exists && !options.force) {\n printExistsWarning(fileCheck.path)\n return {\n success: false,\n error: \"Config file already exists. Use --force to overwrite.\",\n }\n }\n\n // Detect tasks from package.json\n const detectedTasks = detectTasks(options.cwd)\n\n // Determine if we should skip prompts\n const isTTY = process.stdout.isTTY ?? false\n const promptOptions = {\n yes: options.yes,\n isTTY,\n }\n\n // If not skipping prompts, show what we're doing\n if (!shouldSkipPrompts(promptOptions)) {\n console.log(\"\\n🚀 Initializing @halecraft/verify config...\\n\")\n }\n\n // Run interactive prompts (or auto-select)\n const promptResult = await promptForTasks(detectedTasks, promptOptions)\n\n if (promptResult.cancelled) {\n console.log(\"\\n❌ Cancelled.\\n\")\n return {\n success: false,\n error: \"User cancelled\",\n }\n }\n\n // Generate config content\n const content = generateConfigContent(promptResult.tasks, format)\n\n // Determine if optimized commands were used\n const hasOptimizedCommands = promptResult.tasks.some(t =>\n t.command.startsWith(\"./node_modules/.bin/\"),\n )\n\n // Determine which scripts could be removed (those that were detected and optimized)\n const removableScripts = promptResult.tasks\n .filter(t => t.command.startsWith(\"./node_modules/.bin/\"))\n .map(t => t.scriptName)\n\n // Write the file\n try {\n writeConfigFile(options.cwd, configPath, content)\n printSuccess({\n configPath,\n tasks: promptResult.tasks,\n hasOptimizedCommands,\n removableScripts,\n })\n return {\n success: true,\n configPath,\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Failed to write config file\"\n console.error(`\\n❌ Error: ${message}\\n`)\n return {\n success: false,\n error: message,\n }\n }\n}\n\n// Re-export types and utilities\nexport type { DetectedTask } from \"./detect.js\"\nexport { detectTasks } from \"./detect.js\"\nexport type { OutputFormat } from \"./generate.js\"\nexport { generateConfigContent, getOutputFormat } from \"./generate.js\"\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for Biome linter/formatter output\n * Extracts issue counts and file counts from biome check output\n */\nexport const biomeParser: OutputParser = {\n id: \"biome\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Extract file count from \"Checked N files in Xms\"\n const filesMatch = output.match(\n /Checked\\s+(\\d+)\\s+files?\\s+in\\s+[\\d.]+(?:ms|s)/i,\n )\n const fileCount = filesMatch\n ? Number.parseInt(filesMatch[1], 10)\n : undefined\n\n // Check for warnings in output like \"Found 1 warning.\"\n const warningMatch = output.match(/Found\\s+(\\d+)\\s+warning/i)\n const warnings = warningMatch ? Number.parseInt(warningMatch[1], 10) : 0\n\n if (exitCode === 0) {\n const filesPart = fileCount ? `passed ${fileCount} files` : \"passed\"\n const warningSuffix =\n warnings > 0 ? `, ${warnings} warning${warnings === 1 ? \"\" : \"s\"}` : \"\"\n return {\n summary: `${filesPart}${warningSuffix}`,\n metrics: { errors: 0, warnings, total: fileCount },\n }\n }\n\n // Biome outputs something like \"Found 5 errors and 2 warnings\"\n // or individual diagnostics\n const summaryMatch = output.match(\n /Found\\s+(\\d+)\\s+error(?:s)?(?:\\s+and\\s+(\\d+)\\s+warning(?:s)?)?/i,\n )\n\n if (summaryMatch) {\n const errors = Number.parseInt(summaryMatch[1], 10)\n const parsedWarnings = summaryMatch[2]\n ? Number.parseInt(summaryMatch[2], 10)\n : warnings\n\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errors} error${errors === 1 ? \"\" : \"s\"}${parsedWarnings > 0 ? `, ${parsedWarnings} warning${parsedWarnings === 1 ? \"\" : \"s\"}` : \"\"}${fileSuffix}`,\n metrics: { errors, warnings: parsedWarnings, total: fileCount },\n }\n }\n\n // Count individual error markers if no summary found\n // Biome uses \"error\" prefix for diagnostics\n const errorLines = output.match(/^\\s*error\\[/gm)\n const warningLines = output.match(/^\\s*warning\\[/gm)\n\n const errors = errorLines ? errorLines.length : 0\n const countedWarnings = warningLines ? warningLines.length : warnings\n\n if (errors > 0 || countedWarnings > 0) {\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errors} error${errors === 1 ? \"\" : \"s\"}${countedWarnings > 0 ? `, ${countedWarnings} warning${countedWarnings === 1 ? \"\" : \"s\"}` : \"\"}${fileSuffix}`,\n metrics: { errors, warnings: countedWarnings, total: fileCount },\n }\n }\n\n // No errors found but still have file count\n if (fileCount) {\n return {\n summary: `passed ${fileCount} files`,\n metrics: { errors: 0, warnings: 0, total: fileCount },\n }\n }\n\n return null\n },\n}\n","import type { ParsedResult } from \"../types.js\"\n\n/**\n * Generic fallback parser - just reports exit code\n * This parser always returns a result (never null)\n */\nexport const genericParser = {\n id: \"generic\",\n parse(_output: string, exitCode: number): ParsedResult {\n return {\n summary: exitCode === 0 ? \"passed\" : `failed (exit code ${exitCode})`,\n }\n },\n} as const\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for Go test output\n * Counts packages passed/failed from go test output\n */\nexport const gotestParser: OutputParser = {\n id: \"gotest\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Match \"ok\" and \"FAIL\" lines for packages\n // ok github.com/user/pkg 0.123s\n // FAIL github.com/user/pkg 0.456s\n const okMatches = output.match(/^ok\\s+\\S+/gm)\n const failMatches = output.match(/^FAIL\\s+\\S+/gm)\n\n const passed = okMatches ? okMatches.length : 0\n const failed = failMatches ? failMatches.length : 0\n const total = passed + failed\n\n if (total === 0) {\n // Try to detect \"no test files\" case\n if (output.includes(\"no test files\")) {\n return {\n summary: \"no test files\",\n metrics: { passed: 0, failed: 0, total: 0 },\n }\n }\n return null\n }\n\n // Extract total duration if present\n // \"PASS\" or \"FAIL\" at the end with duration\n const durationMatch = output.match(/(?:PASS|FAIL)\\s*$[\\s\\S]*?(\\d+\\.?\\d*s)/m)\n const duration = durationMatch ? durationMatch[1] : undefined\n\n if (exitCode === 0) {\n return {\n summary: `${passed} package${passed === 1 ? \"\" : \"s\"} passed${duration ? ` in ${duration}` : \"\"}`,\n metrics: { passed, failed: 0, total: passed, duration },\n }\n }\n\n return {\n summary: `${failed}/${total} package${total === 1 ? \"\" : \"s\"} failed`,\n metrics: { passed, failed, total, duration },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for TypeScript compiler (tsc/tsgo) output\n * Counts type errors and extracts diagnostics info\n */\nexport const tscParser: OutputParser = {\n id: \"tsc\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Extract file count from diagnostics output: \"Files: 277\"\n const filesMatch = output.match(/^Files:\\s+(\\d+)/m)\n const fileCount = filesMatch\n ? Number.parseInt(filesMatch[1], 10)\n : undefined\n\n if (exitCode === 0) {\n const filesPart = fileCount ? `passed ${fileCount} files` : \"passed\"\n return {\n summary: filesPart,\n metrics: { errors: 0, total: fileCount },\n }\n }\n\n // Count error lines: \"src/file.ts(10,5): error TS2345: ...\"\n const errorMatches = output.match(/error TS\\d+:/g)\n const errorCount = errorMatches ? errorMatches.length : 0\n\n if (errorCount === 0) {\n // No recognizable errors but still failed\n return null\n }\n\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errorCount} type error${errorCount === 1 ? \"\" : \"s\"}${fileSuffix}`,\n metrics: { errors: errorCount, total: fileCount },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Strip ANSI escape codes from string\n */\nfunction stripAnsi(str: string): string {\n // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape codes use control characters\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\")\n}\n\n/**\n * Parser for vitest output\n * Extracts test counts from vitest summary\n */\nexport const vitestParser: OutputParser = {\n id: \"vitest\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Strip ANSI codes for reliable parsing\n const cleanOutput = stripAnsi(output)\n\n // Match: \"Tests 26 passed (26)\" with flexible whitespace\n // Vitest v4 format: \" Tests 26 passed (26)\"\n const testsMatch = cleanOutput.match(/Tests\\s+(\\d+)\\s+passed\\s*\\((\\d+)\\)/m)\n\n // Match: \"Duration 192ms\" or \"Duration 1.72s\"\n const durationMatch = cleanOutput.match(/Duration\\s+([\\d.]+(?:ms|s))\\b/m)\n\n if (!testsMatch) {\n return null\n }\n\n const passed = Number.parseInt(testsMatch[1], 10)\n const total = Number.parseInt(testsMatch[2], 10)\n const duration = durationMatch ? durationMatch[1] : undefined\n\n // Don't include duration in summary - the reporter adds wall-clock time\n return {\n summary:\n exitCode === 0\n ? `passed ${passed}/${total} tests`\n : `passed ${passed}/${total} tests (some failed)`,\n metrics: {\n passed,\n total,\n failed: total - passed,\n duration,\n },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\nimport { biomeParser } from \"./biome.js\"\nimport { genericParser } from \"./generic.js\"\nimport { gotestParser } from \"./gotest.js\"\nimport { tscParser } from \"./tsc.js\"\nimport { vitestParser } from \"./vitest.js\"\n\n/**\n * Parser ID constants for type-safe parser references.\n * Use these instead of magic strings when specifying parsers in config.\n *\n * @example\n * ```typescript\n * import { parsers } from \"@halecraft/verify\"\n *\n * export default defineConfig({\n * tasks: [\n * { key: \"test\", run: \"vitest run\", parser: parsers.vitest },\n * ],\n * })\n * ```\n */\nexport const parsers = {\n /** Vitest/Jest test runner output parser */\n vitest: \"vitest\",\n /** TypeScript compiler (tsc/tsgo) output parser */\n tsc: \"tsc\",\n /** Biome/ESLint linter output parser */\n biome: \"biome\",\n /** Go test runner output parser */\n gotest: \"gotest\",\n /** Generic fallback parser */\n generic: \"generic\",\n} as const\n\n/** Type for valid parser IDs */\nexport type ParserId = (typeof parsers)[keyof typeof parsers]\n\n/**\n * Registry for output parsers\n */\nexport class ParserRegistry {\n private parsers = new Map<string, OutputParser>()\n\n constructor() {\n // Register built-in parsers\n this.register(genericParser)\n this.register(vitestParser)\n this.register(tscParser)\n this.register(biomeParser)\n this.register(gotestParser)\n }\n\n /**\n * Register a custom parser\n */\n register(parser: OutputParser): void {\n this.parsers.set(parser.id, parser)\n }\n\n /**\n * Get a parser by ID\n */\n get(id: string): OutputParser | undefined {\n return this.parsers.get(id)\n }\n\n /**\n * Auto-detect parser based on command\n */\n detectParser(cmd: string): ParserId {\n const cmdLower = cmd.toLowerCase()\n\n if (cmdLower.includes(\"vitest\") || cmdLower.includes(\"jest\")) {\n return parsers.vitest\n }\n if (cmdLower.includes(\"tsc\") || cmdLower.includes(\"tsgo\")) {\n return parsers.tsc\n }\n if (cmdLower.includes(\"biome\") || cmdLower.includes(\"eslint\")) {\n return parsers.biome\n }\n if (\n cmdLower.includes(\"go test\") ||\n (cmdLower.includes(\"go\") && cmdLower.includes(\"test\"))\n ) {\n return parsers.gotest\n }\n\n return parsers.generic\n }\n\n /**\n * Parse output using the specified or auto-detected parser\n */\n parse(\n output: string,\n exitCode: number,\n parserId?: string,\n cmd?: string,\n ): ParsedResult {\n const id = parserId ?? (cmd ? this.detectParser(cmd) : parsers.generic)\n const parser = this.parsers.get(id) ?? genericParser\n\n const result = parser.parse(output, exitCode)\n if (result) {\n return result\n }\n\n // Fallback to generic if parser returns null\n // genericParser.parse always returns a result, never null\n const fallback = genericParser.parse(output, exitCode)\n if (!fallback) {\n throw new Error(\"genericParser unexpectedly returned null\")\n }\n return fallback\n }\n}\n\n// Default registry instance\nexport const defaultRegistry = new ParserRegistry()\n\n// Re-export individual parsers\nexport { biomeParser } from \"./biome.js\"\nexport { genericParser } from \"./generic.js\"\nexport { gotestParser } from \"./gotest.js\"\nexport { tscParser } from \"./tsc.js\"\nexport { vitestParser } from \"./vitest.js\"\n","/**\n * Arc spinner frames for terminal animation\n */\nconst SPINNER_FRAMES = [\"◜\", \"◠\", \"◝\", \"◞\", \"◡\", \"◟\"]\n\n/**\n * Spinner animation interval in milliseconds\n */\nconst SPINNER_INTERVAL = 80\n\n/**\n * Manages spinner animation for terminal output\n */\nexport class SpinnerManager {\n private frames = SPINNER_FRAMES\n private frameIndex = 0\n private interval: ReturnType<typeof setInterval> | null = null\n\n /**\n * Start the spinner animation\n * @param onTick - Callback called on each frame update\n */\n start(onTick: () => void): void {\n if (this.interval) return\n\n this.interval = setInterval(() => {\n this.frameIndex = (this.frameIndex + 1) % this.frames.length\n onTick()\n }, SPINNER_INTERVAL)\n }\n\n /**\n * Stop the spinner animation\n */\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval)\n this.interval = null\n }\n }\n\n /**\n * Get the current spinner frame character\n */\n getFrame(): string {\n return this.frames[this.frameIndex]\n }\n\n /**\n * Check if spinner is currently running\n */\n isRunning(): boolean {\n return this.interval !== null\n }\n}\n","import { SpinnerManager } from \"./spinner.js\"\nimport { walkNodes } from \"./tree.js\"\nimport type {\n TaskResult,\n VerificationNode,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\n/**\n * ANSI color codes\n */\nconst ansi = {\n reset: \"\\u001b[0m\",\n dim: \"\\u001b[2m\",\n red: \"\\u001b[31m\",\n green: \"\\u001b[32m\",\n yellow: \"\\u001b[33m\",\n cyan: \"\\u001b[36m\",\n bold: \"\\u001b[1m\",\n}\n\n/**\n * ANSI cursor control codes\n */\nconst cursor = {\n hide: \"\\u001b[?25l\",\n show: \"\\u001b[?25h\",\n moveUp: (n: number) => `\\u001b[${n}A`,\n moveToStart: \"\\u001b[0G\",\n clearLine: \"\\u001b[2K\",\n}\n\n/**\n * Reporter interface\n */\nexport interface Reporter {\n /** Called before any tasks start - initialize display */\n onStart?(tasks: VerificationNode[]): void\n /** Called when a task starts */\n onTaskStart(path: string, key: string): void\n /** Called when a task completes */\n onTaskComplete(result: TaskResult): void\n /** Called when all tasks complete - cleanup display */\n onFinish?(): void\n /** Called to output task logs */\n outputLogs(results: TaskResult[], logsMode: \"all\" | \"failed\" | \"none\"): void\n /** Called to output final summary */\n outputSummary(result: VerifyResult): void\n}\n\n/**\n * Check if colors should be enabled\n */\nfunction shouldUseColors(options: VerifyOptions): boolean {\n if (options.noColor) return false\n if (options.format === \"json\") return false\n if (!process.stdout.isTTY) return false\n if (\"NO_COLOR\" in process.env) return false\n if (process.env.TERM === \"dumb\") return false\n return true\n}\n\n/**\n * Base Reporter - common functionality for all reporters\n */\nexport abstract class BaseReporter implements Reporter {\n protected colorEnabled: boolean\n protected stream: NodeJS.WriteStream\n protected taskDepths: Map<string, number> = new Map()\n\n constructor(options: VerifyOptions = {}) {\n this.colorEnabled = shouldUseColors(options)\n this.stream = options.format === \"json\" ? process.stderr : process.stdout\n }\n\n /**\n * Apply ANSI color code to string (if colors enabled)\n */\n protected c(code: string, s: string): string {\n return this.colorEnabled ? `${code}${s}${ansi.reset}` : s\n }\n\n /**\n * Get success mark (✓ or OK)\n */\n protected okMark(): string {\n return this.colorEnabled ? this.c(ansi.green, \"✓\") : \"OK\"\n }\n\n /**\n * Get failure mark (✗ or FAIL)\n */\n protected failMark(): string {\n return this.colorEnabled ? this.c(ansi.red, \"✗\") : \"FAIL\"\n }\n\n /**\n * Get suppressed mark (⊘ or SUPPRESSED)\n */\n protected suppressedMark(): string {\n return this.colorEnabled ? this.c(ansi.yellow, \"⊘\") : \"SUPPRESSED\"\n }\n\n /**\n * Get arrow symbol (→ or ->)\n */\n protected arrow(): string {\n return this.colorEnabled ? this.c(ansi.cyan, \"→\") : \"->\"\n }\n\n /**\n * Get indentation string for a given depth\n */\n protected getIndent(depth: number): string {\n return \" \".repeat(depth)\n }\n\n /**\n * Get task depth from path\n */\n protected getTaskDepth(path: string): number {\n return this.taskDepths.get(path) ?? 0\n }\n\n /**\n * Collect task depths from verification tree using walkNodes\n */\n protected collectTaskDepths(nodes: VerificationNode[]): void {\n walkNodes(nodes, (_node, path, depth) => {\n this.taskDepths.set(path, depth)\n })\n }\n\n /**\n * Extract summary from task result\n */\n protected extractSummary(result: TaskResult): string {\n // Use the parsed summary from summaryLine (strip the \"key: \" prefix if present)\n // The parsers already format summaries nicely with file counts, test counts, etc.\n if (result.summaryLine) {\n const colonIndex = result.summaryLine.indexOf(\": \")\n if (colonIndex !== -1) {\n return result.summaryLine.slice(colonIndex + 2)\n }\n return result.summaryLine\n }\n\n return result.ok ? \"passed\" : \"failed\"\n }\n\n /**\n * Flatten nested task results into a single array\n */\n protected flattenResults(results: TaskResult[]): TaskResult[] {\n const flat: TaskResult[] = []\n for (const r of results) {\n flat.push(r)\n if (r.children) {\n flat.push(...this.flattenResults(r.children))\n }\n }\n return flat\n }\n\n /**\n * Output task logs\n */\n outputLogs(results: TaskResult[], logsMode: \"all\" | \"failed\" | \"none\"): void {\n if (logsMode === \"none\") return\n\n const flatResults = this.flattenResults(results)\n\n for (const r of flatResults) {\n if (r.children) continue\n if (logsMode === \"failed\" && r.ok) continue\n // Skip suppressed tasks - their output is hidden to reduce noise\n if (r.suppressed) continue\n\n const status = r.ok ? this.c(ansi.green, \"OK\") : this.c(ansi.red, \"FAIL\")\n\n this.stream.write(\n `\\n${this.c(ansi.bold, \"====\")} ${this.c(ansi.bold, r.path.toUpperCase())} ${status} ${this.c(ansi.bold, \"====\")}\\n`,\n )\n this.stream.write(r.output || \"(no output)\\n\")\n }\n }\n\n /**\n * Output final summary\n */\n outputSummary(result: VerifyResult): void {\n const finalMessage = result.ok\n ? this.c(ansi.green, \"\\n== verification: All correct ==\")\n : this.c(ansi.red, \"\\n== verification: Failed ==\")\n this.stream.write(`${finalMessage}\\n`)\n }\n\n // Abstract methods that subclasses must implement\n abstract onStart(tasks: VerificationNode[]): void\n abstract onTaskStart(path: string, key: string): void\n abstract onTaskComplete(result: TaskResult): void\n abstract onFinish(): void\n}\n\n/**\n * Task state for live dashboard\n */\ninterface TaskState {\n key: string\n path: string\n depth: number\n status: \"pending\" | \"running\" | \"completed\"\n result?: TaskResult\n}\n\n/**\n * Live Dashboard Reporter - animated in-place updates for TTY\n */\nexport class LiveDashboardReporter extends BaseReporter {\n private topLevelOnly: boolean\n private tasks: Map<string, TaskState> = new Map()\n private taskOrder: string[] = []\n private spinner: SpinnerManager\n private lineCount = 0\n\n constructor(options: VerifyOptions = {}) {\n super(options)\n this.topLevelOnly = options.topLevelOnly ?? false\n this.spinner = new SpinnerManager()\n\n // Handle Ctrl+C to restore cursor\n const cleanup = () => {\n this.spinner.stop()\n this.stream.write(cursor.show)\n process.exit(130)\n }\n process.on(\"SIGINT\", cleanup)\n process.on(\"SIGTERM\", cleanup)\n }\n\n /**\n * Initialize task list from verification nodes\n */\n onStart(tasks: VerificationNode[]): void {\n this.collectTasks(tasks)\n this.stream.write(cursor.hide)\n this.spinner.start(() => this.redraw())\n }\n\n /**\n * Collect tasks from verification tree using walkNodes\n */\n private collectTasks(nodes: VerificationNode[]): void {\n walkNodes(nodes, (node, path, depth) => {\n this.tasks.set(path, {\n key: node.key,\n path,\n depth,\n status: \"pending\",\n })\n this.taskOrder.push(path)\n // Also store in base class for consistency\n this.taskDepths.set(path, depth)\n })\n }\n\n /**\n * Get display key - shows :key for nested, key for root\n */\n private getDisplayKey(task: TaskState): string {\n if (task.depth === 0) {\n return task.key\n }\n return `:${task.key}`\n }\n\n /**\n * Check if task should be displayed based on topLevelOnly flag\n */\n private shouldDisplay(task: TaskState): boolean {\n if (this.topLevelOnly) return task.depth === 0\n return true\n }\n\n /**\n * Format a single task line\n */\n private formatLine(task: TaskState): string {\n const indent = this.getIndent(task.depth)\n const displayKey = this.getDisplayKey(task)\n\n if (task.status === \"running\") {\n const spinnerChar = this.c(ansi.dim, `(${this.spinner.getFrame()})`)\n return `${indent}${this.arrow()} verifying ${this.c(ansi.bold, displayKey)} ${spinnerChar}`\n }\n\n if (task.status === \"completed\" && task.result) {\n const duration = this.c(ansi.dim, `${task.result.durationMs}ms`)\n\n // Handle suppressed tasks\n if (task.result.suppressed) {\n const reason = task.result.suppressedBy\n ? `${task.result.suppressedBy} failed`\n : \"dependency failed\"\n return `${indent}${this.suppressedMark()} suppressed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}`\n }\n\n const summary = this.extractSummary(task.result)\n\n if (task.result.ok) {\n return `${indent}${this.okMark()} verified ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`\n }\n return `${indent}${this.failMark()} failed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`\n }\n\n // Pending - don't show\n return \"\"\n }\n\n /**\n * Redraw all visible task lines\n */\n private redraw(): void {\n // Move cursor up to overwrite previous lines\n if (this.lineCount > 0) {\n this.stream.write(cursor.moveUp(this.lineCount))\n }\n\n // Build new output\n const lines: string[] = []\n for (const path of this.taskOrder) {\n const task = this.tasks.get(path)\n if (!task) continue\n if (!this.shouldDisplay(task)) continue\n if (task.status === \"pending\") continue\n\n const line = this.formatLine(task)\n if (line) {\n lines.push(line)\n }\n }\n\n // Write lines with clear\n for (const line of lines) {\n this.stream.write(`${cursor.clearLine}${cursor.moveToStart}${line}\\n`)\n }\n\n this.lineCount = lines.length\n }\n\n onTaskStart(path: string, _key: string): void {\n const task = this.tasks.get(path)\n if (task) {\n task.status = \"running\"\n }\n // Redraw happens on spinner tick\n }\n\n onTaskComplete(result: TaskResult): void {\n const task = this.tasks.get(result.path)\n if (task) {\n task.status = \"completed\"\n task.result = result\n }\n // Redraw happens on spinner tick, but do one now for immediate feedback\n this.redraw()\n }\n\n onFinish(): void {\n this.spinner.stop()\n this.redraw() // Final redraw\n this.stream.write(cursor.show)\n }\n}\n\n/**\n * Sequential Reporter - line-by-line output for non-TTY\n * No indentation since parallel execution means output order doesn't reflect hierarchy\n */\nexport class SequentialReporter extends BaseReporter {\n private topLevelOnly: boolean\n\n constructor(options: VerifyOptions = {}) {\n super(options)\n this.topLevelOnly = options.topLevelOnly ?? false\n }\n\n onStart(tasks: VerificationNode[]): void {\n // Collect task depths from the config tree\n this.collectTaskDepths(tasks)\n }\n\n /**\n * Check if task should be displayed based on topLevelOnly flag\n */\n private shouldDisplay(path: string): boolean {\n if (this.topLevelOnly) return this.getTaskDepth(path) === 0\n return true\n }\n\n onTaskStart(path: string, _key: string): void {\n if (!this.shouldDisplay(path)) return\n this.stream.write(`${this.arrow()} verifying ${this.c(ansi.bold, path)}\\n`)\n }\n\n onTaskComplete(result: TaskResult): void {\n if (!this.shouldDisplay(result.path)) return\n const duration = this.c(ansi.dim, `${result.durationMs}ms`)\n\n // Handle suppressed tasks\n if (result.suppressed) {\n const reason = result.suppressedBy\n ? `${result.suppressedBy} failed`\n : \"dependency failed\"\n this.stream.write(\n `${this.suppressedMark()} suppressed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}\\n`,\n )\n return\n }\n\n const summary = this.extractSummary(result)\n // Align output: \"⊘ suppressed\" is the longest at 12 chars\n // \"✓ verified\" = 12 chars (mark + 3 spaces + verified)\n // \"✗ failed\" = 12 chars (mark + 5 spaces + failed)\n if (result.ok) {\n this.stream.write(\n `${this.okMark()} verified ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}\\n`,\n )\n } else {\n this.stream.write(\n `${this.failMark()} failed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}\\n`,\n )\n }\n }\n\n onFinish(): void {\n // No cleanup needed for sequential output\n }\n}\n\n/**\n * JSON Reporter - machine-readable output\n */\nexport class JSONReporter implements Reporter {\n onStart(_tasks: VerificationNode[]): void {\n // No output during execution in JSON mode\n }\n\n onTaskStart(_path: string, _key: string): void {\n // No output during execution in JSON mode\n }\n\n onTaskComplete(_result: TaskResult): void {\n // No output during execution in JSON mode\n }\n\n onFinish(): void {\n // No cleanup needed for JSON output\n }\n\n outputLogs(\n _results: TaskResult[],\n _logsMode: \"all\" | \"failed\" | \"none\",\n ): void {\n // Logs are included in the JSON output\n }\n\n outputSummary(result: VerifyResult): void {\n const summary = {\n ok: result.ok,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n durationMs: result.durationMs,\n tasks: this.serializeTasks(result.tasks),\n }\n\n process.stdout.write(`${JSON.stringify(summary)}\\n`)\n }\n\n private serializeTasks(tasks: TaskResult[]): Array<{\n key: string\n path: string\n ok: boolean\n code: number\n durationMs: number\n summaryLine: string\n suppressed?: boolean\n suppressedBy?: string\n children?: ReturnType<JSONReporter[\"serializeTasks\"]>\n }> {\n return tasks.map(t => ({\n key: t.key,\n path: t.path,\n ok: t.ok,\n code: t.code,\n durationMs: t.durationMs,\n summaryLine: t.summaryLine,\n ...(t.suppressed ? { suppressed: t.suppressed } : {}),\n ...(t.suppressedBy ? { suppressedBy: t.suppressedBy } : {}),\n ...(t.children ? { children: this.serializeTasks(t.children) } : {}),\n }))\n }\n}\n\n/**\n * Quiet Reporter - minimal output (summary only)\n */\nexport class QuietReporter extends BaseReporter {\n onStart(_tasks: VerificationNode[]): void {\n // No output\n }\n\n onTaskStart(_path: string, _key: string): void {\n // No output\n }\n\n onTaskComplete(_result: TaskResult): void {\n // No output\n }\n\n onFinish(): void {\n // No cleanup needed\n }\n\n outputLogs(\n _results: TaskResult[],\n _logsMode: \"all\" | \"failed\" | \"none\",\n ): void {\n // No logs in quiet mode\n }\n\n outputSummary(result: VerifyResult): void {\n const message = result.ok\n ? this.c(ansi.green, \"✓ All verifications passed\")\n : this.c(ansi.red, \"✗ Some verifications failed\")\n process.stdout.write(`${message}\\n`)\n }\n}\n\n/**\n * Create appropriate reporter based on options\n */\nexport function createReporter(options: VerifyOptions): Reporter {\n if (options.format === \"json\") {\n return new JSONReporter()\n }\n\n // Use LiveDashboardReporter for TTY (unless --no-tty is set)\n if (process.stdout.isTTY && !options.noTty) {\n return new LiveDashboardReporter(options)\n }\n\n return new SequentialReporter(options)\n}\n\n// Keep TTYReporter as alias for backwards compatibility\nexport { SequentialReporter as TTYReporter }\n","import { spawn } from \"node:child_process\"\nimport { dirname, join, resolve } from \"node:path\"\nimport treeKill from \"tree-kill\"\nimport { ReportingDependencyTracker } from \"./dependency-tracker.js\"\nimport { defaultRegistry, type ParserRegistry } from \"./parsers/index.js\"\nimport { buildTaskPath } from \"./tree.js\"\nimport type {\n ParsedResult,\n TaskResult,\n VerificationCommand,\n VerificationNode,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\n// Re-export for backwards compatibility\nexport { ReportingDependencyTracker } from \"./dependency-tracker.js\"\n\n/**\n * Internal command representation that supports shell strings\n */\ninterface InternalCommand {\n /** The command/binary to run (or full shell command if shell is true) */\n cmd: string\n /** Arguments to pass to the command (empty if shell is true) */\n args: string[]\n /** Working directory (defaults to cwd) */\n cwd?: string\n /** Environment variables to set (null values will unset from process.env) */\n env?: Record<string, string | null>\n /** Whether to run through shell (true for string commands) */\n shell: boolean\n /** Timeout in milliseconds */\n timeout?: number\n}\n\n/**\n * Merge environment variables, handling null values as \"unset\".\n * Preserves null values in the result so they can unset process.env vars later.\n */\nexport function mergeEnv(\n base: Record<string, string | null>,\n overlay?: Record<string, string | null>,\n): Record<string, string | null> {\n if (!overlay) return { ...base }\n\n const result = { ...base }\n for (const [key, value] of Object.entries(overlay)) {\n if (value === null) {\n result[key] = null // Mark for unsetting (will be applied in executeCommand)\n } else {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Apply environment overlay to process.env, handling null values as \"unset\".\n * Returns a clean Record<string, string> suitable for spawn().\n */\nfunction buildFinalEnv(\n processEnv: NodeJS.ProcessEnv,\n path: string,\n overlay?: Record<string, string | null>,\n): Record<string, string> {\n // Start with process.env (filter out undefined values)\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(processEnv)) {\n if (value !== undefined) {\n result[key] = value\n }\n }\n\n // Set PATH\n result.PATH = path\n\n // Apply overlay, handling nulls as unset\n if (overlay) {\n for (const [key, value] of Object.entries(overlay)) {\n if (value === null) {\n delete result[key] // Unset from process.env\n } else {\n result[key] = value\n }\n }\n }\n\n return result\n}\n\n/**\n * Escape a shell argument if it contains spaces or special characters\n */\nfunction shellEscape(arg: string): string {\n // If arg contains spaces, quotes, or shell metacharacters, wrap in quotes\n if (/[\\s\"'`$\\\\!&|;<>(){}[\\]*?#~]/.test(arg)) {\n // Escape any existing double quotes and wrap in double quotes\n return `\"${arg.replace(/\"/g, '\\\\\"')}\"`\n }\n return arg\n}\n\n/**\n * Build PATH with node_modules/.bin directories prepended.\n * Walks up from cwd to find all node_modules/.bin directories,\n * mimicking npm/pnpm/yarn script behavior.\n */\nexport function buildNodeModulesPath(cwd: string): string {\n const pathSeparator = process.platform === \"win32\" ? \";\" : \":\"\n const existingPath = process.env.PATH ?? \"\"\n const binPaths: string[] = []\n\n let current = resolve(cwd)\n\n while (true) {\n binPaths.push(join(current, \"node_modules\", \".bin\"))\n const parent = dirname(current)\n if (parent === current) break // Reached filesystem root\n current = parent\n }\n\n return [...binPaths, existingPath].join(pathSeparator)\n}\n\n/**\n * Normalize command to internal format\n * String commands use shell: true to properly handle quotes and special characters\n */\nexport function normalizeCommand(\n run: VerificationCommand | string,\n nodeTimeout?: number,\n passthrough?: string[],\n inheritedEnv?: Record<string, string | null>,\n): InternalCommand {\n if (typeof run === \"string\") {\n // Append passthrough args to the shell command string\n let cmd = run\n if (passthrough && passthrough.length > 0) {\n const escapedArgs = passthrough.map(shellEscape).join(\" \")\n cmd = `${run} ${escapedArgs}`\n }\n\n // Use shell to handle the command string - this properly handles quotes,\n // environment variables, pipes, and other shell features\n return {\n cmd,\n args: [],\n shell: true,\n timeout: nodeTimeout,\n env: inheritedEnv,\n }\n }\n\n // For object commands, append passthrough to args array\n const args = passthrough ? [...run.args, ...passthrough] : run.args\n\n // Merge inherited env with command-level env (command takes precedence)\n const env = mergeEnv(inheritedEnv ?? {}, run.env)\n\n return {\n cmd: run.cmd,\n args,\n cwd: run.cwd,\n env: Object.keys(env).length > 0 ? env : undefined,\n shell: false,\n // Command-level timeout takes precedence over node-level timeout\n timeout: run.timeout ?? nodeTimeout,\n }\n}\n\n/**\n * Execute a single command and capture output.\n * Optionally registers the process with a tracker for early termination support.\n */\nasync function executeCommand(\n command: InternalCommand,\n cwd: string,\n tracker?: ReportingDependencyTracker,\n path?: string,\n): Promise<{\n code: number\n output: string\n durationMs: number\n killed: boolean\n timedOut: boolean\n}> {\n const start = Date.now()\n\n return new Promise(resolve => {\n // Use shell: true for string commands (to handle quotes, pipes, etc.)\n // or on Windows for all commands\n const useShell = command.shell || process.platform === \"win32\"\n\n const effectiveCwd = command.cwd ?? cwd\n const finalEnv = buildFinalEnv(\n process.env,\n buildNodeModulesPath(effectiveCwd),\n command.env,\n )\n const proc = spawn(command.cmd, command.args, {\n shell: useShell,\n cwd: effectiveCwd,\n env: finalEnv,\n })\n\n // Register process for early termination\n if (tracker && path) {\n tracker.registerProcess(path, proc)\n }\n\n let output = \"\"\n let timedOut = false\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n // Set up timeout if configured\n if (command.timeout && proc.pid) {\n const pid = proc.pid // Capture pid to avoid non-null assertion in callback\n timeoutId = setTimeout(() => {\n timedOut = true\n // Use tree-kill to kill the process and all its children\n treeKill(pid, \"SIGTERM\", err => {\n if (err) {\n // Process may have already exited, ignore errors\n }\n })\n }, command.timeout)\n }\n\n proc.stdout.on(\"data\", (data: Buffer) => {\n output += data.toString()\n })\n\n proc.stderr.on(\"data\", (data: Buffer) => {\n output += data.toString()\n })\n\n proc.on(\"close\", (code, signal) => {\n // Clear timeout if set\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n\n // Unregister process\n if (tracker && path) {\n tracker.unregisterProcess(path)\n }\n\n const durationMs = Date.now() - start\n // Check if process was killed (SIGTERM = 15, exit code 143 = 128 + 15)\n const killed =\n signal === \"SIGTERM\" ||\n code === 143 ||\n (tracker?.wasKilled(path ?? \"\") ?? false)\n\n resolve({\n code: code ?? 1,\n output,\n durationMs,\n killed: killed && !timedOut, // Don't mark as killed if it was a timeout\n timedOut,\n })\n })\n\n proc.on(\"error\", err => {\n // Clear timeout if set\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n\n // Unregister process\n if (tracker && path) {\n tracker.unregisterProcess(path)\n }\n\n const durationMs = Date.now() - start\n resolve({\n code: 1,\n output: `Failed to execute command: ${err.message}`,\n durationMs,\n killed: false,\n timedOut: false,\n })\n })\n })\n}\n\n/**\n * Check if a path matches the filter\n */\nfunction matchesFilter(path: string, filters?: string[]): boolean {\n if (!filters || filters.length === 0) {\n return true\n }\n\n return filters.some(filter => {\n // Exact match or prefix match\n return path === filter || path.startsWith(`${filter}:`)\n })\n}\n\n/**\n * Check if any descendant matches the filter\n */\nfunction hasMatchingDescendant(\n node: VerificationNode,\n parentPath: string,\n filters?: string[],\n): boolean {\n const path = buildTaskPath(parentPath, node.key)\n\n if (matchesFilter(path, filters)) {\n return true\n }\n\n if (node.children) {\n return node.children.some(child =>\n hasMatchingDescendant(child, path, filters),\n )\n }\n\n return false\n}\n\nexport interface RunnerCallbacks {\n onTaskStart?: (path: string, key: string) => void\n onTaskComplete?: (result: TaskResult) => void\n}\n\n/**\n * Verification runner\n */\nexport class VerificationRunner {\n private registry: ParserRegistry\n private options: VerifyOptions\n private callbacks: RunnerCallbacks\n private dependencyTracker: ReportingDependencyTracker\n private configEnv: Record<string, string | null>\n\n constructor(\n options: VerifyOptions = {},\n registry: ParserRegistry = defaultRegistry,\n callbacks: RunnerCallbacks = {},\n configEnv: Record<string, string | null> = {},\n ) {\n this.options = options\n this.registry = registry\n this.callbacks = callbacks\n this.dependencyTracker = new ReportingDependencyTracker()\n this.configEnv = configEnv\n }\n\n /**\n * Run all verification tasks\n */\n async run(tasks: VerificationNode[]): Promise<VerifyResult> {\n const startedAt = new Date().toISOString()\n const wallStart = Date.now()\n\n // Initialize dependency tracker with all tasks (validates cycles)\n this.dependencyTracker.initialize(tasks)\n\n // Start with config-level env merged into an empty base\n const baseEnv = mergeEnv({}, this.configEnv)\n const results = await this.runNodes(tasks, \"\", \"parallel\", baseEnv)\n\n const finishedAt = new Date().toISOString()\n const durationMs = Date.now() - wallStart\n\n const allOk = results.every(r => r.ok)\n\n return {\n ok: allOk,\n startedAt,\n finishedAt,\n durationMs,\n tasks: results,\n }\n }\n\n /**\n * Run a list of nodes with the appropriate strategy\n */\n private async runNodes(\n nodes: VerificationNode[],\n parentPath: string,\n strategy: \"parallel\" | \"sequential\" | \"fail-fast\" = \"parallel\",\n inheritedEnv: Record<string, string | null> = {},\n ): Promise<TaskResult[]> {\n // Filter nodes based on filter option\n const filteredNodes = nodes.filter(node =>\n hasMatchingDescendant(node, parentPath, this.options.filter),\n )\n\n if (filteredNodes.length === 0) {\n return []\n }\n\n switch (strategy) {\n case \"parallel\":\n return Promise.all(\n filteredNodes.map(node =>\n this.runNode(node, parentPath, inheritedEnv),\n ),\n )\n\n case \"sequential\": {\n const results: TaskResult[] = []\n for (const node of filteredNodes) {\n results.push(await this.runNode(node, parentPath, inheritedEnv))\n }\n return results\n }\n\n case \"fail-fast\": {\n const results: TaskResult[] = []\n for (const node of filteredNodes) {\n const result = await this.runNode(node, parentPath, inheritedEnv)\n results.push(result)\n if (!result.ok) {\n break\n }\n }\n return results\n }\n }\n }\n\n /**\n * Run a single node (leaf or group)\n */\n private async runNode(\n node: VerificationNode,\n parentPath: string,\n inheritedEnv: Record<string, string | null> = {},\n ): Promise<TaskResult> {\n const path = buildTaskPath(parentPath, node.key)\n\n // Merge inherited env with node env (node takes precedence)\n const nodeEnv = mergeEnv(inheritedEnv, node.env)\n\n // Mark this task as active (will run) so dependencies know about it\n this.dependencyTracker.markActive(path)\n\n // Notify start\n this.callbacks.onTaskStart?.(path, node.key)\n\n // If this is a group node (has children), run children\n if (node.children && node.children.length > 0) {\n const start = Date.now()\n const childResults = await this.runNodes(\n node.children,\n path,\n node.strategy ?? \"parallel\",\n nodeEnv,\n )\n const durationMs = Date.now() - start\n\n const allOk = childResults.every(r => r.ok || r.suppressed)\n\n // Propagate suppressed status from children to parent\n const allSuppressed =\n childResults.length > 0 && childResults.every(r => r.suppressed)\n const anySuppressed = childResults.some(r => r.suppressed)\n\n const result: TaskResult = {\n key: node.key,\n path,\n ok: allOk,\n code: allOk ? 0 : 1,\n durationMs,\n output: \"\",\n summaryLine: allOk\n ? (node.successLabel ?? `${node.key}: all passed`)\n : (node.failureLabel ?? `${node.key}: some failed`),\n children: childResults,\n }\n\n // If all children are suppressed, parent is also suppressed\n if (allSuppressed) {\n result.suppressed = true\n result.suppressedBy = childResults[0].suppressedBy\n } else if (anySuppressed && !allOk) {\n // Mixed: some suppressed, some failed - don't suppress parent\n // The parent shows as failed with the actual failures visible\n }\n\n // Record result in tracker before emitting\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Leaf node - execute command\n if (!node.run) {\n const result: TaskResult = {\n key: node.key,\n path,\n ok: true,\n code: 0,\n durationMs: 0,\n output: \"\",\n summaryLine: `${node.key}: no command specified`,\n }\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Pass through args only if this is the filtered task (single task filter required)\n const passthrough = this.options.passthrough\n const command = normalizeCommand(\n node.run,\n node.timeout,\n passthrough,\n nodeEnv,\n )\n const cwd = this.options.cwd ?? process.cwd()\n\n // Pass tracker and path for early termination support\n const { code, output, durationMs, killed, timedOut } = await executeCommand(\n command,\n cwd,\n this.dependencyTracker,\n path,\n )\n\n const ok = code === 0\n\n // If process timed out, mark as failed with timeout info\n if (timedOut) {\n const result: TaskResult = {\n key: node.key,\n path,\n ok: false,\n code,\n durationMs,\n output,\n summaryLine: `${node.key}: timed out after ${command.timeout}ms`,\n timedOut: true,\n }\n\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // If process was killed (by dependency failure), mark as suppressed\n if (killed) {\n // Wait for dependencies to get the failed dependency path\n await this.dependencyTracker.waitForDependencies(path)\n const failedDep = this.dependencyTracker.getFailedDependency(path)\n\n const result: TaskResult = {\n key: node.key,\n path,\n ok: false,\n code,\n durationMs,\n output,\n summaryLine: `${node.key}: terminated`,\n suppressed: true,\n suppressedBy: failedDep ?? \"unknown\",\n }\n\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Parse output - for shell commands, cmd is the full command string\n const cmdString = command.shell\n ? command.cmd\n : `${command.cmd} ${command.args.join(\" \")}`\n const parsed: ParsedResult = this.registry.parse(\n output,\n code,\n node.parser,\n cmdString,\n )\n\n // Build summary line\n let summaryLine: string\n if (ok) {\n summaryLine = node.successLabel\n ? `${node.key}: ${node.successLabel}`\n : `${node.key}: ${parsed.summary}`\n } else {\n summaryLine = node.failureLabel\n ? `${node.key}: ${node.failureLabel}`\n : `${node.key}: ${parsed.summary}`\n }\n\n let result: TaskResult = {\n key: node.key,\n path,\n ok,\n code,\n durationMs,\n output,\n summaryLine,\n metrics: parsed.metrics,\n }\n\n // If this task has reporting dependencies, wait for them and check for suppression\n if (this.dependencyTracker.hasDependencies(path)) {\n await this.dependencyTracker.waitForDependencies(path)\n\n // Check if any dependency failed - if so, suppress this task's failure\n if (!ok) {\n const failedDep = this.dependencyTracker.getFailedDependency(path)\n if (failedDep) {\n result = {\n ...result,\n suppressed: true,\n suppressedBy: failedDep,\n }\n }\n }\n }\n\n // Record result in tracker before emitting\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n}\n","import type { ChildProcess } from \"node:child_process\"\nimport treeKill from \"tree-kill\"\nimport { walkNodes } from \"./tree.js\"\nimport type { TaskResult, VerificationNode } from \"./types.js\"\n\n/**\n * Tracks reporting dependencies between tasks and coordinates result emission.\n * Allows tasks to wait for their dependencies to complete before emitting results,\n * and determines if a task's failure should be suppressed.\n * Also handles early termination by killing dependent processes when a dependency fails.\n */\nexport class ReportingDependencyTracker {\n /** Map of task path/key to their results */\n private results: Map<string, TaskResult> = new Map()\n\n /** Map of task path/key to waiters (callbacks to resolve when result is available) */\n private waiters: Map<string, Array<() => void>> = new Map()\n\n /** Map of task path to its key (for key-based lookups) */\n private pathToKey: Map<string, string> = new Map()\n\n /** Map of task key to its path (for key-based lookups) */\n private keyToPath: Map<string, string> = new Map()\n\n /** Map of task path to its reportingDependsOn array */\n private dependencies: Map<string, string[]> = new Map()\n\n /** Reverse map: task path → list of tasks that depend on it */\n private reverseDeps: Map<string, string[]> = new Map()\n\n /** Map of task path to its running ChildProcess */\n private processes: Map<string, ChildProcess> = new Map()\n\n /** Set of task paths that have been killed */\n private killedPaths: Set<string> = new Set()\n\n /** Set of task paths that will actually run (based on filter) */\n private activePaths: Set<string> = new Set()\n\n /**\n * Initialize the tracker with all tasks from the verification tree.\n * Also validates for circular dependencies and builds reverse dependency map.\n */\n initialize(nodes: VerificationNode[]): void {\n walkNodes(nodes, (node, path) => {\n this.pathToKey.set(path, node.key)\n this.keyToPath.set(node.key, path)\n\n if (node.reportingDependsOn && node.reportingDependsOn.length > 0) {\n this.dependencies.set(path, node.reportingDependsOn)\n }\n })\n\n this.validateNoCycles()\n this.buildReverseDeps()\n }\n\n /**\n * Build reverse dependency map (task → tasks that depend on it)\n */\n private buildReverseDeps(): void {\n for (const [path, deps] of this.dependencies.entries()) {\n for (const dep of deps) {\n const resolvedDep = this.resolveDependency(dep)\n if (resolvedDep) {\n const existing = this.reverseDeps.get(resolvedDep) ?? []\n existing.push(path)\n this.reverseDeps.set(resolvedDep, existing)\n }\n }\n }\n }\n\n /**\n * Validate that there are no circular dependencies using DFS with coloring.\n * Throws an error with the cycle path if a cycle is detected.\n */\n private validateNoCycles(): void {\n const WHITE = 0 // Not visited\n const GRAY = 1 // Currently visiting (in stack)\n const BLACK = 2 // Fully visited\n\n const colors = new Map<string, number>()\n const parent = new Map<string, string>()\n\n // Initialize all nodes as white\n for (const path of this.pathToKey.keys()) {\n colors.set(path, WHITE)\n }\n\n const dfs = (path: string): string | null => {\n colors.set(path, GRAY)\n\n const deps = this.dependencies.get(path) ?? []\n for (const dep of deps) {\n const depPath = this.resolveDependency(dep)\n if (!depPath) continue // Unknown dependency, skip\n\n const color = colors.get(depPath) ?? WHITE\n\n if (color === GRAY) {\n // Found a cycle - reconstruct the path\n const cycle: string[] = [depPath]\n let current = path\n while (current !== depPath) {\n cycle.unshift(current)\n current = parent.get(current) ?? \"\"\n }\n cycle.unshift(depPath)\n return cycle.join(\" → \")\n }\n\n if (color === WHITE) {\n parent.set(depPath, path)\n const cyclePath = dfs(depPath)\n if (cyclePath) return cyclePath\n }\n }\n\n colors.set(path, BLACK)\n return null\n }\n\n for (const path of this.pathToKey.keys()) {\n if (colors.get(path) === WHITE) {\n const cyclePath = dfs(path)\n if (cyclePath) {\n throw new Error(\n `Circular reporting dependency detected: ${cyclePath}`,\n )\n }\n }\n }\n }\n\n /**\n * Resolve a dependency identifier to a task path.\n * Tries exact path match first, then key match.\n */\n private resolveDependency(dep: string): string | null {\n // Try exact path match first\n if (this.pathToKey.has(dep)) {\n return dep\n }\n\n // Try key match\n if (this.keyToPath.has(dep)) {\n return this.keyToPath.get(dep) ?? null\n }\n\n return null\n }\n\n /**\n * Record a task result and notify any waiters.\n * If the task failed, kills all dependent processes for early termination.\n */\n recordResult(result: TaskResult): void {\n // Store by path\n this.results.set(result.path, result)\n\n // If this task failed, kill all dependent processes\n if (!result.ok) {\n this.killDependents(result.path)\n }\n\n // Notify waiters for this path\n const pathWaiters = this.waiters.get(result.path) ?? []\n for (const waiter of pathWaiters) {\n waiter()\n }\n this.waiters.delete(result.path)\n\n // Also notify waiters for the key (if different from path)\n const key = result.key\n if (key !== result.path) {\n const keyWaiters = this.waiters.get(key) ?? []\n for (const waiter of keyWaiters) {\n waiter()\n }\n this.waiters.delete(key)\n }\n }\n\n /**\n * Mark a task as active (will actually run).\n * Called before running each task to track which tasks are in the execution set.\n */\n markActive(path: string): void {\n this.activePaths.add(path)\n }\n\n /**\n * Check if a dependency is active (will run).\n * If not active, we shouldn't wait for it.\n */\n private isDependencyActive(dep: string): boolean {\n const resolvedPath = this.resolveDependency(dep)\n if (!resolvedPath) {\n return false\n }\n return this.activePaths.has(resolvedPath)\n }\n\n /**\n * Wait for all dependencies of a task to complete.\n * Only waits for dependencies that are actually active (will run).\n */\n async waitForDependencies(path: string): Promise<void> {\n const deps = this.dependencies.get(path)\n if (!deps || deps.length === 0) {\n return\n }\n\n // Only wait for dependencies that are active (will run)\n const activeDeps = deps.filter(dep => this.isDependencyActive(dep))\n const waitPromises = activeDeps.map(dep => this.waitForResult(dep))\n await Promise.all(waitPromises)\n }\n\n /**\n * Wait for a specific task result to be available.\n */\n private waitForResult(pathOrKey: string): Promise<void> {\n // Check if result already exists\n const resolvedPath = this.resolveDependency(pathOrKey)\n if (resolvedPath && this.results.has(resolvedPath)) {\n return Promise.resolve()\n }\n\n // Also check by the original identifier\n if (this.results.has(pathOrKey)) {\n return Promise.resolve()\n }\n\n // Register a waiter\n return new Promise<void>(resolve => {\n const waiters = this.waiters.get(pathOrKey) ?? []\n waiters.push(resolve)\n this.waiters.set(pathOrKey, waiters)\n })\n }\n\n /**\n * Check if any dependency of a task has failed.\n * Returns the path of the first failed dependency, or null if all passed.\n */\n getFailedDependency(path: string): string | null {\n const deps = this.dependencies.get(path)\n if (!deps || deps.length === 0) {\n return null\n }\n\n for (const dep of deps) {\n const resolvedPath = this.resolveDependency(dep)\n if (!resolvedPath) continue\n\n const result = this.results.get(resolvedPath)\n if (result && !result.ok) {\n return resolvedPath\n }\n }\n\n return null\n }\n\n /**\n * Check if a task has any reporting dependencies.\n */\n hasDependencies(path: string): boolean {\n const deps = this.dependencies.get(path)\n return deps !== undefined && deps.length > 0\n }\n\n /**\n * Register a running process for a task.\n */\n registerProcess(path: string, proc: ChildProcess): void {\n this.processes.set(path, proc)\n }\n\n /**\n * Unregister a process (called when it completes naturally).\n */\n unregisterProcess(path: string): void {\n this.processes.delete(path)\n }\n\n /**\n * Check if a task was killed.\n */\n wasKilled(path: string): boolean {\n return this.killedPaths.has(path)\n }\n\n /**\n * Kill all processes that depend on the failed task.\n * Called when a task fails to terminate dependent tasks early.\n */\n killDependents(failedPath: string): void {\n const dependents = this.reverseDeps.get(failedPath) ?? []\n\n for (const depPath of dependents) {\n const proc = this.processes.get(depPath)\n if (proc?.pid) {\n this.killedPaths.add(depPath)\n // Use tree-kill to kill the process and all its children\n treeKill(proc.pid, \"SIGTERM\", err => {\n if (err) {\n // Process may have already exited, ignore errors\n }\n })\n }\n }\n }\n}\n","// Types\n\n// Config helpers\nexport {\n ConfigError,\n defineConfig,\n defineTask,\n findConfigFile,\n loadConfig,\n loadConfigFromCwd,\n mergeOptions,\n validateConfig,\n} from \"./config.js\"\n// Discovery\nexport {\n type DiscoveredPackage,\n discoverPackages,\n hasPackageChanged,\n} from \"./discovery.js\"\n// Filter validation\nexport {\n AmbiguousTaskError,\n findBestSuggestion,\n type ResolvedFilter,\n resolveFilters,\n TaskNotFoundError,\n} from \"./filter.js\"\n// Init\nexport {\n type DetectedTask,\n detectTasks,\n generateConfigContent,\n type InitOptions,\n type InitResult,\n type OutputFormat,\n runInit,\n} from \"./init/index.js\"\n// Parsers\nexport {\n biomeParser,\n defaultRegistry,\n genericParser,\n gotestParser,\n type ParserId,\n ParserRegistry,\n parsers,\n tscParser,\n vitestParser,\n} from \"./parsers/index.js\"\n\n// Reporter\nexport {\n createReporter,\n JSONReporter,\n LiveDashboardReporter,\n QuietReporter,\n type Reporter,\n SequentialReporter,\n TTYReporter,\n} from \"./reporter.js\"\n// Runner\nexport { type RunnerCallbacks, VerificationRunner } from \"./runner.js\"\n// Tree utilities\nexport {\n buildTaskPath,\n collectPaths,\n type NodeVisitor,\n PATH_SEPARATOR,\n walkNodes,\n} from \"./tree.js\"\nexport type {\n ExecutionStrategy,\n OutputParser,\n PackageDiscoveryOptions,\n ParsedResult,\n TaskResult,\n VerificationCommand,\n VerificationNode,\n VerifyConfig,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\nimport { loadConfigFromCwd, mergeOptions } from \"./config.js\"\nimport { resolveFilters } from \"./filter.js\"\nimport { createReporter } from \"./reporter.js\"\nimport { VerificationRunner } from \"./runner.js\"\n// Main verify function\nimport type { VerifyConfig, VerifyOptions, VerifyResult } from \"./types.js\"\n\n/**\n * Run verification with the given config and options\n */\nexport async function verify(\n config: VerifyConfig,\n cliOptions?: Partial<VerifyOptions>,\n): Promise<VerifyResult> {\n const options = mergeOptions(config.options, cliOptions)\n\n // VALIDATION PHASE - fail fast before any execution\n if (options.filter && options.filter.length > 0) {\n const resolved = resolveFilters(config.tasks, options.filter)\n\n // Log info messages for any shortcuts used\n for (const r of resolved) {\n if (r.wasShortcut) {\n console.error(`→ Resolving \"${r.original}\" to \"${r.resolved}\"`)\n }\n }\n\n // Update options with resolved filters\n options.filter = resolved.map(r => r.resolved)\n }\n\n // EXECUTION PHASE - only runs if validation passed\n const reporter = createReporter(options)\n\n // Initialize reporter with task list (for live dashboard)\n reporter.onStart?.(config.tasks)\n\n const runner = new VerificationRunner(\n options,\n undefined,\n {\n onTaskStart: (path, key) => reporter.onTaskStart(path, key),\n onTaskComplete: result => reporter.onTaskComplete(result),\n },\n config.env,\n )\n\n const result = await runner.run(config.tasks)\n\n // Cleanup reporter (stop spinner, restore cursor)\n reporter.onFinish?.()\n\n reporter.outputLogs(result.tasks, options.logs ?? \"failed\")\n reporter.outputSummary(result)\n\n return result\n}\n\n/**\n * Run verification from config file in cwd\n */\nexport async function verifyFromConfig(\n cwd: string = process.cwd(),\n cliOptions?: Partial<VerifyOptions>,\n): Promise<VerifyResult> {\n const config = await loadConfigFromCwd(cwd, cliOptions?.cwd)\n\n if (!config) {\n throw new Error(\n `No verify config found in ${cwd}. Create a verify.config.ts file.`,\n )\n }\n\n return verify(config, { ...cliOptions, cwd })\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAMX,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrC,YACE,SACgB,YAChB;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAKA,IAAM,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS;AAKvE,IAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,KAAK,EAAE,OAAO;AAAA,EACd,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA,EACxB,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,KAAK;AAAA,EACL,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC1C,CAAC;AAKD,IAAM,yBAAsD,EAAE;AAAA,EAAK,MACjE,EAAE,OAAO;AAAA,IACP,KAAK,EACF,OAAO,EACP,IAAI,GAAG,0BAA0B,EACjC,OAAO,SAAO,CAAC,IAAI,SAAS,GAAG,GAAG;AAAA,MACjC,SAAS;AAAA,IACX,CAAC;AAAA,IACH,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC,EAAE,SAAS;AAAA,IAC/D,UAAU,EAAE,MAAM,sBAAsB,EAAE,SAAS;AAAA,IACnD,UAAU,EAAE,KAAK,CAAC,YAAY,cAAc,WAAW,CAAC,EAAE,SAAS;AAAA,IACnE,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,IAClC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,IAClC,oBAAoB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACjD,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACxC,KAAK;AAAA,EACP,CAAC;AACH;AAKA,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,MAAM,EAAE,KAAK,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,SAAS;AAAA,EACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,MAAM,CAAC,EAAE,SAAS;AAAA,EAC3C,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACrC,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC9B,cAAc,EAAE,QAAQ,EAAE,SAAS;AAAA,EACnC,OAAO,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC5B,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAC5C,CAAC;AAKD,IAAM,gCAAgC,EAAE,OAAO;AAAA,EAC7C,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACvC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACrC,SAAS,EAAE,QAAQ,EAAE,SAAS;AAChC,CAAC;AAKD,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,OAAO,EAAE,MAAM,sBAAsB;AAAA,EACrC,UAAU,8BAA8B,SAAS;AAAA,EACjD,SAAS,oBAAoB,SAAS;AAAA,EACtC,KAAK;AACP,CAAC;AAKM,SAAS,eACd,OACA,YACc;AACd,QAAM,SAAS,mBAAmB,UAAU,KAAK;AAEjD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OAAO,IAAI,WAAS;AAC9C,YAAM,OAAO,MAAM,KAAK,KAAK,GAAG;AAChC,aAAO,OAAO,GAAG,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM;AAAA,IACpD,CAAC;AACD,UAAM,IAAI;AAAA,MACR;AAAA,MAAwB,OAAO,KAAK,QAAQ,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAKO,SAAS,aAAa,QAAoC;AAC/D,SAAO;AACT;AAKO,SAAS,WAAW,MAA0C;AACnE,SAAO;AACT;AAKA,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,eAAe,KAA4B;AACzD,aAAW,YAAY,cAAc;AACnC,UAAM,WAAW,KAAK,KAAK,QAAQ;AACnC,QAAI,WAAW,QAAQ,GAAG;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAKA,eAAsB,WACpB,YAC8B;AAC9B,QAAM,eAAe,QAAQ,UAAU;AAEvC,MAAI,CAAC,WAAW,YAAY,GAAG;AAC7B,WAAO;AAAA,EACT;AAGA,QAAM,UAAU,cAAc,YAAY,EAAE;AAC5C,QAAM,SAAU,MAAM,OAAO;AAE7B,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,YAAY,0CAA0C,UAAU;AAAA,EAC5E;AAGA,SAAO,eAAe,OAAO,SAAS,UAAU;AAClD;AAKA,eAAsB,kBACpB,KACA,YAC8B;AAC9B,MAAI,YAAY;AACd,WAAO,WAAW,UAAU;AAAA,EAC9B;AAEA,QAAM,YAAY,eAAe,GAAG;AACpC,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,SAAS;AAC7B;AAeO,SAAS,aACd,eACA,YACe;AACf,SAAO;AAAA,IACL,MAAM,YAAY,QAAQ,eAAe,QAAQ;AAAA,IACjD,QAAQ,YAAY,UAAU,eAAe,UAAU;AAAA,IACvD,QAAQ,YAAY,UAAU,eAAe;AAAA,IAC7C,KAAK,YAAY,OAAO,eAAe,OAAO,QAAQ,IAAI;AAAA,IAC1D,SAAS,YAAY,WAAW,eAAe,WAAW;AAAA,IAC1D,cACE,YAAY,gBAAgB,eAAe,gBAAgB;AAAA,IAC7D,OAAO,YAAY,SAAS,eAAe,SAAS;AAAA,IACpD,aAAa,YAAY,eAAe,eAAe;AAAA,EACzD;AACF;;;AC/NA,SAAS,cAAAA,aAAY,aAAa,cAAc,gBAAgB;AAChE,SAAS,QAAAC,OAAM,gBAAgB;;;ACD/B,SAAS,KAAAC,UAAS;AAMX,IAAM,oBAAoBA,GAC9B,OAAO;AAAA,EACN,MAAMA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,SAASA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,OAAO,CAAC,EAAE,SAAS;AACrD,CAAC,EACA,YAAY;AAWR,SAAS,iBAAiB,SAAqC;AACpE,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,OAAO;AAC1C,UAAM,SAAS,kBAAkB,UAAU,MAAM;AACjD,WAAO,OAAO,UAAU,OAAO,OAAO;AAAA,EACxC,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;;;ADRA,IAAM,mBAAmB,CAAC,cAAc,QAAQ;AAKhD,SAAS,iBAAiB,SAAiB,UAA8B;AACvE,QAAM,UAAoB,CAAC;AAE3B,aAAW,WAAW,UAAU;AAE9B,QAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,YAAM,YAAY,QAAQ,MAAM,GAAG,EAAE;AACrC,YAAM,aAAaC,MAAK,SAAS,SAAS;AAE1C,UAAIC,YAAW,UAAU,KAAK,SAAS,UAAU,EAAE,YAAY,GAAG;AAChE,cAAM,UAAU,YAAY,UAAU;AACtC,mBAAW,SAAS,SAAS;AAC3B,gBAAM,YAAYD,MAAK,YAAY,KAAK;AACxC,cAAI,SAAS,SAAS,EAAE,YAAY,GAAG;AACrC,oBAAQ,KAAK,SAAS;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AAEL,YAAM,UAAUA,MAAK,SAAS,OAAO;AACrC,UAAIC,YAAW,OAAO,KAAK,SAAS,OAAO,EAAE,YAAY,GAAG;AAC1D,gBAAQ,KAAK,OAAO;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,eAAe,YAAmC;AACzD,QAAM,kBAAkBD,MAAK,YAAY,cAAc;AACvD,MAAI,CAACC,YAAW,eAAe,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,iBAAiB,OAAO;AACrD,UAAM,SAAS,iBAAiB,OAAO;AACvC,WAAO,QAAQ,QAAQ;AAAA,EACzB,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,iBACpB,SACA,UAAmC,CAAC,GACN;AAC9B,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,eAAe,iBAAiB,SAAS,QAAQ;AAEvD,QAAM,WAAgC,CAAC;AAEvC,aAAW,OAAO,cAAc;AAC9B,UAAM,OAAO,eAAe,GAAG;AAC/B,QAAI,CAAC,KAAM;AAGX,QAAI,QAAQ,UAAU,QAAQ,OAAO,SAAS,GAAG;AAC/C,YAAM,UAAU,QAAQ,OAAO;AAAA,QAC7B,OACE,SAAS,KAAK,KAAK,SAAS,CAAC,KAAK,SAAS,SAAS,GAAG,EAAE,SAAS,CAAC;AAAA,MACvE;AACA,UAAI,CAAC,QAAS;AAAA,IAChB;AAGA,UAAM,aAAa,eAAe,GAAG;AACrC,UAAM,SAAS,aAAa,MAAM,WAAW,UAAU,IAAI;AAE3D,aAAS,KAAK;AAAA,MACZ;AAAA,MACA,MAAM,SAAS,SAAS,GAAG;AAAA,MAC3B,cAAc;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMA,eAAsB,kBACpB,cACA,cAAc,QACI;AAGlB,SAAO;AACT;;;AEhIA,OAAO,WAAW;;;ACKX,IAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,KAAqB;AACrE,SAAO,aAAa,GAAG,UAAU,GAAG,cAAc,GAAG,GAAG,KAAK;AAC/D;AAmBO,SAAS,UACd,OACA,SACA,aAAa,IACb,QAAQ,GACF;AACN,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,cAAc,YAAY,KAAK,GAAG;AAC/C,YAAQ,MAAM,MAAM,KAAK;AACzB,QAAI,KAAK,UAAU;AACjB,gBAAU,KAAK,UAAU,SAAS,MAAM,QAAQ,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAKO,SAAS,aAAa,OAAqC;AAChE,QAAM,QAAkB,CAAC;AACzB,YAAU,OAAO,CAAC,OAAO,SAAS;AAChC,UAAM,KAAK,IAAI;AAAA,EACjB,CAAC;AACD,SAAO;AACT;;;ADpCO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAG3C,YACkB,QACA,YACA,gBAChB;AACA,UAAM,kBAAkB,QAAQ,YAAY,cAAc,CAAC;AAJ3C;AACA;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EATS,WAAW;AAUtB;AAKO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAG5C,YACkB,QACA,SAChB;AACA,UAAM,2BAA2B,QAAQ,OAAO,CAAC;AAHjC;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EARS,WAAW;AAStB;AAKA,SAAS,kBACP,QACA,YACA,gBACQ;AACR,MAAI,UAAU,SAAS,MAAM;AAE7B,MAAI,YAAY;AACd,eAAW;AAAA;AAAA,gBAAqB,UAAU;AAAA,EAC5C;AAEA,aAAW;AACX,aAAW,QAAQ,gBAAgB;AACjC,eAAW;AAAA,IAAO,IAAI;AAAA,EACxB;AAEA,SAAO;AACT;AAKA,SAAS,2BAA2B,QAAgB,SAA2B;AAC7E,MAAI,UAAU,SAAS,MAAM;AAC7B,aAAW;AACX,aAAW,SAAS,SAAS;AAC3B,eAAW;AAAA,IAAO,KAAK;AAAA,EACzB;AACA,SAAO;AACT;AAMO,SAAS,mBACd,gBACA,eACoB;AACpB,MAAI;AACJ,MAAI,eAAe,OAAO;AAG1B,QAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,SAAS,CAAC,CAAC;AAElE,aAAW,QAAQ,gBAAgB;AAEjC,UAAM,WAAW,MAAM,eAAe,IAAI;AAC1C,QAAI,WAAW,gBAAgB,YAAY,WAAW;AACpD,qBAAe;AACf,iBAAW;AAAA,IACb;AAGA,UAAM,cAAc,KAAK,MAAM,cAAc,EAAE,IAAI;AACnD,QAAI,eAAe,gBAAgB,MAAM;AACvC,YAAM,kBAAkB,MAAM,eAAe,WAAW;AACxD,UAAI,kBAAkB,gBAAgB,mBAAmB,WAAW;AAClE,uBAAe;AACf,mBAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,cACP,QACA,gBACgB;AAEhB,MAAI,eAAe,SAAS,MAAM,GAAG;AACnC,WAAO,EAAE,UAAU,QAAQ,UAAU,QAAQ,aAAa,MAAM;AAAA,EAClE;AAGA,QAAM,gBAAgB,eAAe;AAAA,IACnC,UAAQ,SAAS,UAAU,KAAK,WAAW,GAAG,MAAM,GAAG,cAAc,EAAE;AAAA,EACzE;AACA,MAAI,cAAc,SAAS,GAAG;AAG5B,WAAO,EAAE,UAAU,QAAQ,UAAU,QAAQ,aAAa,MAAM;AAAA,EAClE;AAGA,QAAM,eAAe,eAAe,OAAO,UAAQ;AACjD,UAAM,cAAc,KAAK,MAAM,cAAc,EAAE,IAAI;AACnD,WAAO,gBAAgB;AAAA,EACzB,CAAC;AAED,MAAI,aAAa,WAAW,GAAG;AAE7B,WAAO;AAAA,MACL,UAAU;AAAA,MACV,UAAU,aAAa,CAAC;AAAA,MACxB,aAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,aAAa,SAAS,GAAG;AAE3B,UAAM,IAAI,mBAAmB,QAAQ,YAAY;AAAA,EACnD;AAGA,QAAM,aAAa,mBAAmB,gBAAgB,MAAM;AAC5D,QAAM,IAAI,kBAAkB,QAAQ,YAAY,cAAc;AAChE;AAYO,SAAS,eACd,OACA,SACkB;AAClB,QAAM,iBAAiB,aAAa,KAAK;AACzC,QAAM,WAA6B,CAAC;AAEpC,aAAW,UAAU,SAAS;AAC5B,aAAS,KAAK,cAAc,QAAQ,cAAc,CAAC;AAAA,EACrD;AAEA,SAAO;AACT;;;AE3LA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,QAAAC,aAAY;AAwCrB,IAAM,gBAA+B;AAAA;AAAA,EAEnC;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,OAAO,YAAY;AAE3B,YAAM,aAAa,QAAQ,MAAM,mBAAmB;AACpD,aAAO,aAAa,WAAW,CAAC,EAAE,KAAK,IAAI;AAAA,IAC7C;AAAA,IACA,QAAQ;AAAA,EACV;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,cAAc,QAAQ,MAAM,oBAAoB;AACtD,aAAO,cAAc,YAAY,CAAC,EAAE,KAAK,IAAI;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,gBAAgB,QAAQ,MAAM,sBAAsB;AAC1D,aAAO,gBAAgB,cAAc,CAAC,EAAE,KAAK,IAAI;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,WAAW,QAAQ,MAAM,iBAAiB;AAChD,aAAO,WAAW,SAAS,CAAC,EAAE,KAAK,IAAI;AAAA,IACzC;AAAA,IACA,QAAQ;AAAA,EACV;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,YAAY,QAAQ,MAAM,kBAAkB;AAClD,aAAO,YAAY,UAAU,CAAC,EAAE,KAAK,IAAI;AAAA,IAC3C;AAAA,IACA,QAAQ;AAAA,EACV;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AAEvB,UAAI,QAAQ,SAAS,YAAY,EAAG,QAAO;AAC3C,UAAI,QAAQ,SAAS,cAAc,EAAG,QAAO;AAC7C,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,EACV;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,MAAM;AAAA,EACjB;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,MAAM;AAAA,EACjB;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,YAAY,QAAQ,MAAM,kBAAkB;AAClD,aAAO,YAAY,UAAU,CAAC,EAAE,KAAK,IAAI;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,SAAS,CAAC,GAAG,YAAY;AACvB,YAAM,eAAe,QAAQ,MAAM,qBAAqB;AACxD,aAAO,eAAe,aAAa,CAAC,EAAE,KAAK,IAAI;AAAA,IACjD;AAAA,EACF;AACF;AAKA,IAAM,uBAKD;AAAA;AAAA,EAEH;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA;AAAA,EAGA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA;AAAA,EAGA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AAAA;AAAA,EAGA;AAAA,IACE,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,EACZ;AACF;AAKA,SAAS,gBAAgB,KAAiC;AACxD,QAAM,kBAAkBC,MAAK,KAAK,cAAc;AAEhD,MAAI,CAACC,YAAW,eAAe,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAUC,cAAa,iBAAiB,OAAO;AACrD,WAAO,iBAAiB,OAAO;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,SAAS,aAAa,KAAa,QAAyB;AAC1D,SAAOD,YAAWD,MAAK,KAAK,gBAAgB,QAAQ,MAAM,CAAC;AAC7D;AAOA,SAAS,wBACP,KACA,eAC6C;AAC7C,aAAW,QAAQ,eAAe;AAChC,UAAM,QAAQ,cAAc,MAAM,KAAK,OAAO;AAC9C,QAAI,SAAS,aAAa,KAAK,KAAK,MAAM,GAAG;AAC3C,YAAM,OAAO,KAAK,QAAQ,OAAO,aAAa;AAE9C,YAAM,UAAU,OAAO,GAAG,KAAK,MAAM,IAAI,IAAI,KAAK,KAAK;AACvD,aAAO,EAAE,SAAS,QAAQ,KAAK,OAAO;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,sBAAsB,KAA6B;AACjE,QAAM,MAAM,gBAAgB,GAAG;AAE/B,MAAI,CAAC,KAAK,SAAS;AACjB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAA2B,CAAC;AAClC,QAAM,WAAW,oBAAI,IAAY;AAEjC,aAAW,CAAC,YAAY,aAAa,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AAErE,QACE,cAAc,SAAS,OAAO,KAC9B,cAAc,SAAS,OAAO,KAC9B,cAAc,SAAS,aAAa,GACpC;AACA;AAAA,IACF;AAGA,eAAW,EAAE,SAAS,KAAK,MAAM,SAAS,KAAK,sBAAsB;AACnE,UAAI,QAAQ,KAAK,UAAU,GAAG;AAE5B,cAAM,YAAY,SAAS,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI,UAAU,KAAK;AAC/D,YAAI,CAAC,SAAS,IAAI,SAAS,GAAG;AAC5B,mBAAS,IAAI,SAAS;AAGtB,gBAAM,YAAY,wBAAwB,KAAK,aAAa;AAE5D,mBAAS,KAAK;AAAA,YACZ,KAAK;AAAA,YACL;AAAA,YACA;AAAA,YACA,SAAS,WAAW,WAAW,WAAW,UAAU;AAAA,YACpD;AAAA,YACA,QAAQ,WAAW;AAAA,UACrB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAA0D;AAAA,IAC9D,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AAEA,WAAS,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ,CAAC;AAI7E,QAAM,gBAAgB,SAAS,KAAK,OAAK,EAAE,aAAa,QAAQ;AAChE,MAAI,eAAe;AACjB,eAAW,QAAQ,UAAU;AAC3B,UAAI,KAAK,aAAa,YAAY,KAAK,aAAa,SAAS;AAC3D,aAAK,qBAAqB,CAAC,QAAQ;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,qBAAqB,KAAsC;AACzE,MAAIC,YAAWD,MAAK,KAAK,gBAAgB,CAAC,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,MAAIC,YAAWD,MAAK,KAAK,WAAW,CAAC,GAAG;AACtC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAKO,SAAS,cACd,gBACA,YACQ;AACR,UAAQ,gBAAgB;AAAA,IACtB,KAAK;AACH,aAAO,QAAQ,UAAU;AAAA,IAC3B,KAAK;AACH,aAAO,QAAQ,UAAU;AAAA,IAC3B;AACE,aAAO,WAAW,UAAU;AAAA,EAChC;AACF;AAMO,SAAS,YAAY,KAA6B;AACvD,QAAM,iBAAiB,qBAAqB,GAAG;AAC/C,QAAM,QAAQ,sBAAsB,GAAG;AAGvC,SAAO,MAAM,IAAI,UAAQ;AAEvB,QAAI,CAAC,KAAK,QAAQ,WAAW,UAAU,GAAG;AACxC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,SAAS,cAAc,gBAAgB,KAAK,UAAU;AAAA,IACxD;AAAA,EACF,CAAC;AACH;;;AC9WO,SAAS,gBAAgB,UAAgC;AAC9D,MAAI,SAAS,SAAS,MAAM,EAAG,QAAO;AACtC,MAAI,SAAS,SAAS,MAAM,EAAG,QAAO;AACtC,MAAI,SAAS,SAAS,KAAK,EAAG,QAAO;AACrC,SAAO;AACT;AAKA,SAAS,eAAe,QAA8B;AAEpD,SAAO;AACT;AAKA,SAAS,aAAa,MAAoB,QAAwB;AAChE,QAAM,QAAQ,CAAC,SAAS,KAAK,GAAG,KAAK,SAAS,KAAK,OAAO,GAAG;AAC7D,MAAI,KAAK,QAAQ;AACf,UAAM,KAAK,YAAY,KAAK,MAAM,GAAG;AAAA,EACvC;AACA,MAAI,KAAK,sBAAsB,KAAK,mBAAmB,SAAS,GAAG;AACjE,UAAM,OAAO,KAAK,mBAAmB,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI;AACjE,UAAM,KAAK,wBAAwB,IAAI,GAAG;AAAA,EAC5C;AACA,SAAO,GAAG,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC;AACvC;AAKA,SAAS,iBAAiB,QAA8B;AACtD,QAAM,kBAAkB,eAAe,MAAM;AAE7C,SAAO,GAAG,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAe3B;AAKO,SAAS,sBACd,OACA,QACQ;AAER,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,iBAAiB,MAAM;AAAA,EAChC;AAEA,QAAM,kBAAkB,eAAe,MAAM;AAC7C,QAAM,SAAS;AAGf,QAAM,YAAY,MAAM,IAAI,UAAQ,aAAa,MAAM,MAAM,CAAC;AAE9D,SAAO,GAAG,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzB,UAAU,KAAK,KAAK,CAAC;AAAA;AAAA;AAAA;AAIvB;AAKO,SAAS,uBAA+B;AAC7C,SAAO;AACT;;;AC1EO,SAAS,kBAAkB,SAAiC;AACjE,SAAO,QAAQ,OAAO,CAAC,QAAQ;AACjC;AAKA,eAAsB,eACpB,eACA,SACuB;AAEvB,MAAI,cAAc,WAAW,GAAG;AAC9B,QAAI,CAAC,kBAAkB,OAAO,GAAG;AAC/B,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,OAAO,CAAC,GAAG,WAAW,MAAM;AAAA,EACvC;AAGA,MAAI,kBAAkB,OAAO,GAAG;AAC9B,YAAQ,IAAI;AAAA,wBAAsB,cAAc,MAAM;AAAA,CAAqB;AAC3E,WAAO,EAAE,OAAO,eAAe,WAAW,MAAM;AAAA,EAClD;AAGA,MAAI;AACF,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,mBAAmB;AAErD,YAAQ,IAAI,8DAAuD;AAEnE,UAAM,UAAU,cAAc,IAAI,WAAS;AAAA,MACzC,MAAM,GAAG,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,MACnC,OAAO;AAAA,MACP,SAAS;AAAA;AAAA,IACX,EAAE;AAEF,UAAM,WAAW,MAAM,SAAuB;AAAA,MAC5C,SAAS;AAAA,MACT;AAAA,MACA,cAAc;AAAA,IAChB,CAAC;AAED,QAAI,SAAS,WAAW,GAAG;AACzB,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,OAAO,UAAU,WAAW,MAAM;AAAA,EAC7C,SAAS,OAAO;AAEd,QACE,iBAAiB,UAChB,MAAM,QAAQ,SAAS,mBAAmB,KACzC,MAAM,SAAS,oBACjB;AACA,aAAO,EAAE,OAAO,CAAC,GAAG,WAAW,KAAK;AAAA,IACtC;AACA,UAAM;AAAA,EACR;AACF;;;ACxFA,SAAS,cAAAG,aAAY,qBAAqB;AAC1C,SAAS,WAAAC,gBAAe;AAcjB,SAAS,kBACd,KACA,YACiB;AACjB,QAAM,eAAeA,SAAQ,KAAK,UAAU;AAC5C,SAAO;AAAA,IACL,QAAQD,YAAW,YAAY;AAAA,IAC/B,MAAM;AAAA,EACR;AACF;AAKO,SAAS,gBACd,KACA,YACA,SACM;AACN,QAAM,eAAeC,SAAQ,KAAK,UAAU;AAC5C,gBAAc,cAAc,SAAS,OAAO;AAC9C;AAKO,SAAS,mBAAmB,MAAoB;AACrD,UAAQ,MAAM;AAAA,4CAAqC,IAAI,EAAE;AACzD,UAAQ,MAAM,gCAAgC;AAChD;AAmBO,SAAS,aAAa,SAA+B;AAC1D,QAAM,EAAE,YAAY,OAAO,sBAAsB,iBAAiB,IAAI;AAEtE,UAAQ,IAAI;AAAA,iBAAe,UAAU,EAAE;AACvC,UAAQ,IAAI,EAAE;AAGd,UAAQ,IAAI,iBAAiB;AAC7B,UAAQ,IAAI,kDAAkD;AAC9D,UAAQ,IAAI,sDAAsD;AAClE,UAAQ,IAAI,mDAAmD;AAC/D,UAAQ,IAAI,EAAE;AAGd,MAAI,sBAAsB;AACxB,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAGA,MAAI,iBAAiB,SAAS,GAAG;AAC/B,YAAQ,IAAI,gCAAyB;AACrC,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,IAAI,2DAA2D;AACvE,eAAW,UAAU,kBAAkB;AACrC,cAAQ,IAAI,cAAc,MAAM,GAAG;AAAA,IACrC;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAGA,QAAM,mBAAmB,MAAM,OAAO,OAAK,EAAE,MAAM;AACnD,MAAI,iBAAiB,SAAS,GAAG;AAC/B,YAAQ,IAAI,oEAA6D;AACzE,eAAW,QAAQ,kBAAkB;AACnC,cAAQ,IAAI,aAAa,KAAK,GAAG,KAAK,KAAK,MAAM,EAAE;AAAA,IACrD;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAEA,UAAQ,IAAI,wDAAiD;AAC7D,UAAQ,IAAI,EAAE;AAChB;;;ACrEA,eAAsB,QAAQ,SAA2C;AACvE,QAAM,aAAa,QAAQ,UAAU,qBAAqB;AAC1D,QAAM,SAAS,gBAAgB,UAAU;AAGzC,QAAM,YAAY,kBAAkB,QAAQ,KAAK,UAAU;AAC3D,MAAI,UAAU,UAAU,CAAC,QAAQ,OAAO;AACtC,uBAAmB,UAAU,IAAI;AACjC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,gBAAgB,YAAY,QAAQ,GAAG;AAG7C,QAAM,QAAQ,QAAQ,OAAO,SAAS;AACtC,QAAM,gBAAgB;AAAA,IACpB,KAAK,QAAQ;AAAA,IACb;AAAA,EACF;AAGA,MAAI,CAAC,kBAAkB,aAAa,GAAG;AACrC,YAAQ,IAAI,wDAAiD;AAAA,EAC/D;AAGA,QAAM,eAAe,MAAM,eAAe,eAAe,aAAa;AAEtE,MAAI,aAAa,WAAW;AAC1B,YAAQ,IAAI,uBAAkB;AAC9B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,UAAU,sBAAsB,aAAa,OAAO,MAAM;AAGhE,QAAM,uBAAuB,aAAa,MAAM;AAAA,IAAK,OACnD,EAAE,QAAQ,WAAW,sBAAsB;AAAA,EAC7C;AAGA,QAAM,mBAAmB,aAAa,MACnC,OAAO,OAAK,EAAE,QAAQ,WAAW,sBAAsB,CAAC,EACxD,IAAI,OAAK,EAAE,UAAU;AAGxB,MAAI;AACF,oBAAgB,QAAQ,KAAK,YAAY,OAAO;AAChD,iBAAa;AAAA,MACX;AAAA,MACA,OAAO,aAAa;AAAA,MACpB;AAAA,MACA;AAAA,IACF,CAAC;AACD,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,YAAQ,MAAM;AAAA,gBAAc,OAAO;AAAA,CAAI;AACvC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;AChHO,IAAM,cAA4B;AAAA,EACvC,IAAI;AAAA,EACJ,MAAM,QAAgB,UAAuC;AAE3D,UAAM,aAAa,OAAO;AAAA,MACxB;AAAA,IACF;AACA,UAAM,YAAY,aACd,OAAO,SAAS,WAAW,CAAC,GAAG,EAAE,IACjC;AAGJ,UAAM,eAAe,OAAO,MAAM,0BAA0B;AAC5D,UAAM,WAAW,eAAe,OAAO,SAAS,aAAa,CAAC,GAAG,EAAE,IAAI;AAEvE,QAAI,aAAa,GAAG;AAClB,YAAM,YAAY,YAAY,UAAU,SAAS,WAAW;AAC5D,YAAM,gBACJ,WAAW,IAAI,KAAK,QAAQ,WAAW,aAAa,IAAI,KAAK,GAAG,KAAK;AACvE,aAAO;AAAA,QACL,SAAS,GAAG,SAAS,GAAG,aAAa;AAAA,QACrC,SAAS,EAAE,QAAQ,GAAG,UAAU,OAAO,UAAU;AAAA,MACnD;AAAA,IACF;AAIA,UAAM,eAAe,OAAO;AAAA,MAC1B;AAAA,IACF;AAEA,QAAI,cAAc;AAChB,YAAMC,UAAS,OAAO,SAAS,aAAa,CAAC,GAAG,EAAE;AAClD,YAAM,iBAAiB,aAAa,CAAC,IACjC,OAAO,SAAS,aAAa,CAAC,GAAG,EAAE,IACnC;AAEJ,YAAM,aAAa,YAAY,OAAO,SAAS,WAAW;AAC1D,aAAO;AAAA,QACL,SAAS,GAAGA,OAAM,SAASA,YAAW,IAAI,KAAK,GAAG,GAAG,iBAAiB,IAAI,KAAK,cAAc,WAAW,mBAAmB,IAAI,KAAK,GAAG,KAAK,EAAE,GAAG,UAAU;AAAA,QAC3J,SAAS,EAAE,QAAAA,SAAQ,UAAU,gBAAgB,OAAO,UAAU;AAAA,MAChE;AAAA,IACF;AAIA,UAAM,aAAa,OAAO,MAAM,eAAe;AAC/C,UAAM,eAAe,OAAO,MAAM,iBAAiB;AAEnD,UAAM,SAAS,aAAa,WAAW,SAAS;AAChD,UAAM,kBAAkB,eAAe,aAAa,SAAS;AAE7D,QAAI,SAAS,KAAK,kBAAkB,GAAG;AACrC,YAAM,aAAa,YAAY,OAAO,SAAS,WAAW;AAC1D,aAAO;AAAA,QACL,SAAS,GAAG,MAAM,SAAS,WAAW,IAAI,KAAK,GAAG,GAAG,kBAAkB,IAAI,KAAK,eAAe,WAAW,oBAAoB,IAAI,KAAK,GAAG,KAAK,EAAE,GAAG,UAAU;AAAA,QAC9J,SAAS,EAAE,QAAQ,UAAU,iBAAiB,OAAO,UAAU;AAAA,MACjE;AAAA,IACF;AAGA,QAAI,WAAW;AACb,aAAO;AAAA,QACL,SAAS,UAAU,SAAS;AAAA,QAC5B,SAAS,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,UAAU;AAAA,MACtD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACtEO,IAAM,gBAAgB;AAAA,EAC3B,IAAI;AAAA,EACJ,MAAM,SAAiB,UAAgC;AACrD,WAAO;AAAA,MACL,SAAS,aAAa,IAAI,WAAW,qBAAqB,QAAQ;AAAA,IACpE;AAAA,EACF;AACF;;;ACPO,IAAM,eAA6B;AAAA,EACxC,IAAI;AAAA,EACJ,MAAM,QAAgB,UAAuC;AAI3D,UAAM,YAAY,OAAO,MAAM,aAAa;AAC5C,UAAM,cAAc,OAAO,MAAM,eAAe;AAEhD,UAAM,SAAS,YAAY,UAAU,SAAS;AAC9C,UAAM,SAAS,cAAc,YAAY,SAAS;AAClD,UAAM,QAAQ,SAAS;AAEvB,QAAI,UAAU,GAAG;AAEf,UAAI,OAAO,SAAS,eAAe,GAAG;AACpC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,EAAE;AAAA,QAC5C;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAIA,UAAM,gBAAgB,OAAO,MAAM,wCAAwC;AAC3E,UAAM,WAAW,gBAAgB,cAAc,CAAC,IAAI;AAEpD,QAAI,aAAa,GAAG;AAClB,aAAO;AAAA,QACL,SAAS,GAAG,MAAM,WAAW,WAAW,IAAI,KAAK,GAAG,UAAU,WAAW,OAAO,QAAQ,KAAK,EAAE;AAAA,QAC/F,SAAS,EAAE,QAAQ,QAAQ,GAAG,OAAO,QAAQ,SAAS;AAAA,MACxD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,GAAG,MAAM,IAAI,KAAK,WAAW,UAAU,IAAI,KAAK,GAAG;AAAA,MAC5D,SAAS,EAAE,QAAQ,QAAQ,OAAO,SAAS;AAAA,IAC7C;AAAA,EACF;AACF;;;ACzCO,IAAM,YAA0B;AAAA,EACrC,IAAI;AAAA,EACJ,MAAM,QAAgB,UAAuC;AAE3D,UAAM,aAAa,OAAO,MAAM,kBAAkB;AAClD,UAAM,YAAY,aACd,OAAO,SAAS,WAAW,CAAC,GAAG,EAAE,IACjC;AAEJ,QAAI,aAAa,GAAG;AAClB,YAAM,YAAY,YAAY,UAAU,SAAS,WAAW;AAC5D,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,EAAE,QAAQ,GAAG,OAAO,UAAU;AAAA,MACzC;AAAA,IACF;AAGA,UAAM,eAAe,OAAO,MAAM,eAAe;AACjD,UAAM,aAAa,eAAe,aAAa,SAAS;AAExD,QAAI,eAAe,GAAG;AAEpB,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,YAAY,OAAO,SAAS,WAAW;AAC1D,WAAO;AAAA,MACL,SAAS,GAAG,UAAU,cAAc,eAAe,IAAI,KAAK,GAAG,GAAG,UAAU;AAAA,MAC5E,SAAS,EAAE,QAAQ,YAAY,OAAO,UAAU;AAAA,IAClD;AAAA,EACF;AACF;;;ACjCA,SAAS,UAAU,KAAqB;AAEtC,SAAO,IAAI,QAAQ,mBAAmB,EAAE;AAC1C;AAMO,IAAM,eAA6B;AAAA,EACxC,IAAI;AAAA,EACJ,MAAM,QAAgB,UAAuC;AAE3D,UAAM,cAAc,UAAU,MAAM;AAIpC,UAAM,aAAa,YAAY,MAAM,qCAAqC;AAG1E,UAAM,gBAAgB,YAAY,MAAM,gCAAgC;AAExE,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,OAAO,SAAS,WAAW,CAAC,GAAG,EAAE;AAChD,UAAM,QAAQ,OAAO,SAAS,WAAW,CAAC,GAAG,EAAE;AAC/C,UAAM,WAAW,gBAAgB,cAAc,CAAC,IAAI;AAGpD,WAAO;AAAA,MACL,SACE,aAAa,IACT,UAAU,MAAM,IAAI,KAAK,WACzB,UAAU,MAAM,IAAI,KAAK;AAAA,MAC/B,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,QAAQ,QAAQ;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC3BO,IAAM,UAAU;AAAA;AAAA,EAErB,QAAQ;AAAA;AAAA,EAER,KAAK;AAAA;AAAA,EAEL,OAAO;AAAA;AAAA,EAEP,QAAQ;AAAA;AAAA,EAER,SAAS;AACX;AAQO,IAAM,iBAAN,MAAqB;AAAA,EAClB,UAAU,oBAAI,IAA0B;AAAA,EAEhD,cAAc;AAEZ,SAAK,SAAS,aAAa;AAC3B,SAAK,SAAS,YAAY;AAC1B,SAAK,SAAS,SAAS;AACvB,SAAK,SAAS,WAAW;AACzB,SAAK,SAAS,YAAY;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,QAA4B;AACnC,SAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,IAAsC;AACxC,WAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAuB;AAClC,UAAM,WAAW,IAAI,YAAY;AAEjC,QAAI,SAAS,SAAS,QAAQ,KAAK,SAAS,SAAS,MAAM,GAAG;AAC5D,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,MAAM,GAAG;AACzD,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,SAAS,SAAS,OAAO,KAAK,SAAS,SAAS,QAAQ,GAAG;AAC7D,aAAO,QAAQ;AAAA,IACjB;AACA,QACE,SAAS,SAAS,SAAS,KAC1B,SAAS,SAAS,IAAI,KAAK,SAAS,SAAS,MAAM,GACpD;AACA,aAAO,QAAQ;AAAA,IACjB;AAEA,WAAO,QAAQ;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,MACE,QACA,UACA,UACA,KACc;AACd,UAAM,KAAK,aAAa,MAAM,KAAK,aAAa,GAAG,IAAI,QAAQ;AAC/D,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE,KAAK;AAEvC,UAAM,SAAS,OAAO,MAAM,QAAQ,QAAQ;AAC5C,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAIA,UAAM,WAAW,cAAc,MAAM,QAAQ,QAAQ;AACrD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AACF;AAGO,IAAM,kBAAkB,IAAI,eAAe;;;ACrHlD,IAAM,iBAAiB,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AAKpD,IAAM,mBAAmB;AAKlB,IAAM,iBAAN,MAAqB;AAAA,EAClB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,WAAkD;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1D,MAAM,QAA0B;AAC9B,QAAI,KAAK,SAAU;AAEnB,SAAK,WAAW,YAAY,MAAM;AAChC,WAAK,cAAc,KAAK,aAAa,KAAK,KAAK,OAAO;AACtD,aAAO;AAAA,IACT,GAAG,gBAAgB;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,QAAI,KAAK,UAAU;AACjB,oBAAc,KAAK,QAAQ;AAC3B,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAmB;AACjB,WAAO,KAAK,OAAO,KAAK,UAAU;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAqB;AACnB,WAAO,KAAK,aAAa;AAAA,EAC3B;AACF;;;AC1CA,IAAM,OAAO;AAAA,EACX,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AACR;AAKA,IAAM,SAAS;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ,CAAC,MAAc,QAAU,CAAC;AAAA,EAClC,aAAa;AAAA,EACb,WAAW;AACb;AAuBA,SAAS,gBAAgB,SAAiC;AACxD,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,QAAQ,WAAW,OAAQ,QAAO;AACtC,MAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAClC,MAAI,cAAc,QAAQ,IAAK,QAAO;AACtC,MAAI,QAAQ,IAAI,SAAS,OAAQ,QAAO;AACxC,SAAO;AACT;AAKO,IAAe,eAAf,MAAgD;AAAA,EAC3C;AAAA,EACA;AAAA,EACA,aAAkC,oBAAI,IAAI;AAAA,EAEpD,YAAY,UAAyB,CAAC,GAAG;AACvC,SAAK,eAAe,gBAAgB,OAAO;AAC3C,SAAK,SAAS,QAAQ,WAAW,SAAS,QAAQ,SAAS,QAAQ;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKU,EAAE,MAAc,GAAmB;AAC3C,WAAO,KAAK,eAAe,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKU,SAAiB;AACzB,WAAO,KAAK,eAAe,KAAK,EAAE,KAAK,OAAO,QAAG,IAAI;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKU,WAAmB;AAC3B,WAAO,KAAK,eAAe,KAAK,EAAE,KAAK,KAAK,QAAG,IAAI;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAyB;AACjC,WAAO,KAAK,eAAe,KAAK,EAAE,KAAK,QAAQ,QAAG,IAAI;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKU,QAAgB;AACxB,WAAO,KAAK,eAAe,KAAK,EAAE,KAAK,MAAM,QAAG,IAAI;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKU,UAAU,OAAuB;AACzC,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKU,aAAa,MAAsB;AAC3C,WAAO,KAAK,WAAW,IAAI,IAAI,KAAK;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKU,kBAAkB,OAAiC;AAC3D,cAAU,OAAO,CAAC,OAAO,MAAM,UAAU;AACvC,WAAK,WAAW,IAAI,MAAM,KAAK;AAAA,IACjC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKU,eAAe,QAA4B;AAGnD,QAAI,OAAO,aAAa;AACtB,YAAM,aAAa,OAAO,YAAY,QAAQ,IAAI;AAClD,UAAI,eAAe,IAAI;AACrB,eAAO,OAAO,YAAY,MAAM,aAAa,CAAC;AAAA,MAChD;AACA,aAAO,OAAO;AAAA,IAChB;AAEA,WAAO,OAAO,KAAK,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKU,eAAe,SAAqC;AAC5D,UAAM,OAAqB,CAAC;AAC5B,eAAW,KAAK,SAAS;AACvB,WAAK,KAAK,CAAC;AACX,UAAI,EAAE,UAAU;AACd,aAAK,KAAK,GAAG,KAAK,eAAe,EAAE,QAAQ,CAAC;AAAA,MAC9C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAAuB,UAA2C;AAC3E,QAAI,aAAa,OAAQ;AAEzB,UAAM,cAAc,KAAK,eAAe,OAAO;AAE/C,eAAW,KAAK,aAAa;AAC3B,UAAI,EAAE,SAAU;AAChB,UAAI,aAAa,YAAY,EAAE,GAAI;AAEnC,UAAI,EAAE,WAAY;AAElB,YAAM,SAAS,EAAE,KAAK,KAAK,EAAE,KAAK,OAAO,IAAI,IAAI,KAAK,EAAE,KAAK,KAAK,MAAM;AAExE,WAAK,OAAO;AAAA,QACV;AAAA,EAAK,KAAK,EAAE,KAAK,MAAM,MAAM,CAAC,IAAI,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,CAAC,CAAC,IAAI,MAAM,IAAI,KAAK,EAAE,KAAK,MAAM,MAAM,CAAC;AAAA;AAAA,MAClH;AACA,WAAK,OAAO,MAAM,EAAE,UAAU,eAAe;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,QAA4B;AACxC,UAAM,eAAe,OAAO,KACxB,KAAK,EAAE,KAAK,OAAO,mCAAmC,IACtD,KAAK,EAAE,KAAK,KAAK,8BAA8B;AACnD,SAAK,OAAO,MAAM,GAAG,YAAY;AAAA,CAAI;AAAA,EACvC;AAOF;AAgBO,IAAM,wBAAN,cAAoC,aAAa;AAAA,EAC9C;AAAA,EACA,QAAgC,oBAAI,IAAI;AAAA,EACxC,YAAsB,CAAC;AAAA,EACvB;AAAA,EACA,YAAY;AAAA,EAEpB,YAAY,UAAyB,CAAC,GAAG;AACvC,UAAM,OAAO;AACb,SAAK,eAAe,QAAQ,gBAAgB;AAC5C,SAAK,UAAU,IAAI,eAAe;AAGlC,UAAM,UAAU,MAAM;AACpB,WAAK,QAAQ,KAAK;AAClB,WAAK,OAAO,MAAM,OAAO,IAAI;AAC7B,cAAQ,KAAK,GAAG;AAAA,IAClB;AACA,YAAQ,GAAG,UAAU,OAAO;AAC5B,YAAQ,GAAG,WAAW,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAiC;AACvC,SAAK,aAAa,KAAK;AACvB,SAAK,OAAO,MAAM,OAAO,IAAI;AAC7B,SAAK,QAAQ,MAAM,MAAM,KAAK,OAAO,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAiC;AACpD,cAAU,OAAO,CAAC,MAAM,MAAM,UAAU;AACtC,WAAK,MAAM,IAAI,MAAM;AAAA,QACnB,KAAK,KAAK;AAAA,QACV;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AACD,WAAK,UAAU,KAAK,IAAI;AAExB,WAAK,WAAW,IAAI,MAAM,KAAK;AAAA,IACjC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,MAAyB;AAC7C,QAAI,KAAK,UAAU,GAAG;AACpB,aAAO,KAAK;AAAA,IACd;AACA,WAAO,IAAI,KAAK,GAAG;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,MAA0B;AAC9C,QAAI,KAAK,aAAc,QAAO,KAAK,UAAU;AAC7C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,MAAyB;AAC1C,UAAM,SAAS,KAAK,UAAU,KAAK,KAAK;AACxC,UAAM,aAAa,KAAK,cAAc,IAAI;AAE1C,QAAI,KAAK,WAAW,WAAW;AAC7B,YAAM,cAAc,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,QAAQ,SAAS,CAAC,GAAG;AACnE,aAAO,GAAG,MAAM,GAAG,KAAK,MAAM,CAAC,cAAc,KAAK,EAAE,KAAK,MAAM,UAAU,CAAC,IAAI,WAAW;AAAA,IAC3F;AAEA,QAAI,KAAK,WAAW,eAAe,KAAK,QAAQ;AAC9C,YAAM,WAAW,KAAK,EAAE,KAAK,KAAK,GAAG,KAAK,OAAO,UAAU,IAAI;AAG/D,UAAI,KAAK,OAAO,YAAY;AAC1B,cAAM,SAAS,KAAK,OAAO,eACvB,GAAG,KAAK,OAAO,YAAY,YAC3B;AACJ,eAAO,GAAG,MAAM,GAAG,KAAK,eAAe,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,UAAU,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,MAAM,KAAK,QAAQ,GAAG,CAAC;AAAA,MACtI;AAEA,YAAM,UAAU,KAAK,eAAe,KAAK,MAAM;AAE/C,UAAI,KAAK,OAAO,IAAI;AAClB,eAAO,GAAG,MAAM,GAAG,KAAK,OAAO,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,UAAU,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC;AAAA,MAC/H;AACA,aAAO,GAAG,MAAM,GAAG,KAAK,SAAS,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,UAAU,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC;AAAA,IACjI;AAGA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAe;AAErB,QAAI,KAAK,YAAY,GAAG;AACtB,WAAK,OAAO,MAAM,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,IACjD;AAGA,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,KAAK,WAAW;AACjC,YAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,UAAI,CAAC,KAAM;AACX,UAAI,CAAC,KAAK,cAAc,IAAI,EAAG;AAC/B,UAAI,KAAK,WAAW,UAAW;AAE/B,YAAM,OAAO,KAAK,WAAW,IAAI;AACjC,UAAI,MAAM;AACR,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAGA,eAAW,QAAQ,OAAO;AACxB,WAAK,OAAO,MAAM,GAAG,OAAO,SAAS,GAAG,OAAO,WAAW,GAAG,IAAI;AAAA,CAAI;AAAA,IACvE;AAEA,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA,EAEA,YAAY,MAAc,MAAoB;AAC5C,UAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAChC,QAAI,MAAM;AACR,WAAK,SAAS;AAAA,IAChB;AAAA,EAEF;AAAA,EAEA,eAAe,QAA0B;AACvC,UAAM,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI;AACvC,QAAI,MAAM;AACR,WAAK,SAAS;AACd,WAAK,SAAS;AAAA,IAChB;AAEA,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,WAAiB;AACf,SAAK,QAAQ,KAAK;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,MAAM,OAAO,IAAI;AAAA,EAC/B;AACF;AAMO,IAAM,qBAAN,cAAiC,aAAa;AAAA,EAC3C;AAAA,EAER,YAAY,UAAyB,CAAC,GAAG;AACvC,UAAM,OAAO;AACb,SAAK,eAAe,QAAQ,gBAAgB;AAAA,EAC9C;AAAA,EAEA,QAAQ,OAAiC;AAEvC,SAAK,kBAAkB,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,MAAuB;AAC3C,QAAI,KAAK,aAAc,QAAO,KAAK,aAAa,IAAI,MAAM;AAC1D,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,MAAc,MAAoB;AAC5C,QAAI,CAAC,KAAK,cAAc,IAAI,EAAG;AAC/B,SAAK,OAAO,MAAM,GAAG,KAAK,MAAM,CAAC,cAAc,KAAK,EAAE,KAAK,MAAM,IAAI,CAAC;AAAA,CAAI;AAAA,EAC5E;AAAA,EAEA,eAAe,QAA0B;AACvC,QAAI,CAAC,KAAK,cAAc,OAAO,IAAI,EAAG;AACtC,UAAM,WAAW,KAAK,EAAE,KAAK,KAAK,GAAG,OAAO,UAAU,IAAI;AAG1D,QAAI,OAAO,YAAY;AACrB,YAAM,SAAS,OAAO,eAClB,GAAG,OAAO,YAAY,YACtB;AACJ,WAAK,OAAO;AAAA,QACV,GAAG,KAAK,eAAe,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,OAAO,IAAI,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,MAAM,KAAK,QAAQ,GAAG,CAAC;AAAA;AAAA,MACvH;AACA;AAAA,IACF;AAEA,UAAM,UAAU,KAAK,eAAe,MAAM;AAI1C,QAAI,OAAO,IAAI;AACb,WAAK,OAAO;AAAA,QACV,GAAG,KAAK,OAAO,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,OAAO,IAAI,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC;AAAA;AAAA,MAChH;AAAA,IACF,OAAO;AACL,WAAK,OAAO;AAAA,QACV,GAAG,KAAK,SAAS,CAAC,eAAe,KAAK,EAAE,KAAK,MAAM,OAAO,IAAI,CAAC,IAAI,KAAK,EAAE,KAAK,KAAK,IAAI,OAAO,KAAK,QAAQ,GAAG,CAAC;AAAA;AAAA,MAClH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAiB;AAAA,EAEjB;AACF;AAKO,IAAM,eAAN,MAAuC;AAAA,EAC5C,QAAQ,QAAkC;AAAA,EAE1C;AAAA,EAEA,YAAY,OAAe,MAAoB;AAAA,EAE/C;AAAA,EAEA,eAAe,SAA2B;AAAA,EAE1C;AAAA,EAEA,WAAiB;AAAA,EAEjB;AAAA,EAEA,WACE,UACA,WACM;AAAA,EAER;AAAA,EAEA,cAAc,QAA4B;AACxC,UAAM,UAAU;AAAA,MACd,IAAI,OAAO;AAAA,MACX,WAAW,OAAO;AAAA,MAClB,YAAY,OAAO;AAAA,MACnB,YAAY,OAAO;AAAA,MACnB,OAAO,KAAK,eAAe,OAAO,KAAK;AAAA,IACzC;AAEA,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,CAAI;AAAA,EACrD;AAAA,EAEQ,eAAe,OAUpB;AACD,WAAO,MAAM,IAAI,QAAM;AAAA,MACrB,KAAK,EAAE;AAAA,MACP,MAAM,EAAE;AAAA,MACR,IAAI,EAAE;AAAA,MACN,MAAM,EAAE;AAAA,MACR,YAAY,EAAE;AAAA,MACd,aAAa,EAAE;AAAA,MACf,GAAI,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,IAAI,CAAC;AAAA,MACnD,GAAI,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,IAAI,CAAC;AAAA,MACzD,GAAI,EAAE,WAAW,EAAE,UAAU,KAAK,eAAe,EAAE,QAAQ,EAAE,IAAI,CAAC;AAAA,IACpE,EAAE;AAAA,EACJ;AACF;AAKO,IAAM,gBAAN,cAA4B,aAAa;AAAA,EAC9C,QAAQ,QAAkC;AAAA,EAE1C;AAAA,EAEA,YAAY,OAAe,MAAoB;AAAA,EAE/C;AAAA,EAEA,eAAe,SAA2B;AAAA,EAE1C;AAAA,EAEA,WAAiB;AAAA,EAEjB;AAAA,EAEA,WACE,UACA,WACM;AAAA,EAER;AAAA,EAEA,cAAc,QAA4B;AACxC,UAAM,UAAU,OAAO,KACnB,KAAK,EAAE,KAAK,OAAO,iCAA4B,IAC/C,KAAK,EAAE,KAAK,KAAK,kCAA6B;AAClD,YAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EACrC;AACF;AAKO,SAAS,eAAe,SAAkC;AAC/D,MAAI,QAAQ,WAAW,QAAQ;AAC7B,WAAO,IAAI,aAAa;AAAA,EAC1B;AAGA,MAAI,QAAQ,OAAO,SAAS,CAAC,QAAQ,OAAO;AAC1C,WAAO,IAAI,sBAAsB,OAAO;AAAA,EAC1C;AAEA,SAAO,IAAI,mBAAmB,OAAO;AACvC;;;AC1iBA,SAAS,aAAa;AACtB,SAAS,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AACvC,OAAOC,eAAc;;;ACDrB,OAAO,cAAc;AAUd,IAAM,6BAAN,MAAiC;AAAA;AAAA,EAE9B,UAAmC,oBAAI,IAAI;AAAA;AAAA,EAG3C,UAA0C,oBAAI,IAAI;AAAA;AAAA,EAGlD,YAAiC,oBAAI,IAAI;AAAA;AAAA,EAGzC,YAAiC,oBAAI,IAAI;AAAA;AAAA,EAGzC,eAAsC,oBAAI,IAAI;AAAA;AAAA,EAG9C,cAAqC,oBAAI,IAAI;AAAA;AAAA,EAG7C,YAAuC,oBAAI,IAAI;AAAA;AAAA,EAG/C,cAA2B,oBAAI,IAAI;AAAA;AAAA,EAGnC,cAA2B,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3C,WAAW,OAAiC;AAC1C,cAAU,OAAO,CAAC,MAAM,SAAS;AAC/B,WAAK,UAAU,IAAI,MAAM,KAAK,GAAG;AACjC,WAAK,UAAU,IAAI,KAAK,KAAK,IAAI;AAEjC,UAAI,KAAK,sBAAsB,KAAK,mBAAmB,SAAS,GAAG;AACjE,aAAK,aAAa,IAAI,MAAM,KAAK,kBAAkB;AAAA,MACrD;AAAA,IACF,CAAC;AAED,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,eAAW,CAAC,MAAM,IAAI,KAAK,KAAK,aAAa,QAAQ,GAAG;AACtD,iBAAW,OAAO,MAAM;AACtB,cAAM,cAAc,KAAK,kBAAkB,GAAG;AAC9C,YAAI,aAAa;AACf,gBAAM,WAAW,KAAK,YAAY,IAAI,WAAW,KAAK,CAAC;AACvD,mBAAS,KAAK,IAAI;AAClB,eAAK,YAAY,IAAI,aAAa,QAAQ;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAAyB;AAC/B,UAAM,QAAQ;AACd,UAAM,OAAO;AACb,UAAM,QAAQ;AAEd,UAAM,SAAS,oBAAI,IAAoB;AACvC,UAAM,SAAS,oBAAI,IAAoB;AAGvC,eAAW,QAAQ,KAAK,UAAU,KAAK,GAAG;AACxC,aAAO,IAAI,MAAM,KAAK;AAAA,IACxB;AAEA,UAAM,MAAM,CAAC,SAAgC;AAC3C,aAAO,IAAI,MAAM,IAAI;AAErB,YAAM,OAAO,KAAK,aAAa,IAAI,IAAI,KAAK,CAAC;AAC7C,iBAAW,OAAO,MAAM;AACtB,cAAM,UAAU,KAAK,kBAAkB,GAAG;AAC1C,YAAI,CAAC,QAAS;AAEd,cAAM,QAAQ,OAAO,IAAI,OAAO,KAAK;AAErC,YAAI,UAAU,MAAM;AAElB,gBAAM,QAAkB,CAAC,OAAO;AAChC,cAAI,UAAU;AACd,iBAAO,YAAY,SAAS;AAC1B,kBAAM,QAAQ,OAAO;AACrB,sBAAU,OAAO,IAAI,OAAO,KAAK;AAAA,UACnC;AACA,gBAAM,QAAQ,OAAO;AACrB,iBAAO,MAAM,KAAK,UAAK;AAAA,QACzB;AAEA,YAAI,UAAU,OAAO;AACnB,iBAAO,IAAI,SAAS,IAAI;AACxB,gBAAM,YAAY,IAAI,OAAO;AAC7B,cAAI,UAAW,QAAO;AAAA,QACxB;AAAA,MACF;AAEA,aAAO,IAAI,MAAM,KAAK;AACtB,aAAO;AAAA,IACT;AAEA,eAAW,QAAQ,KAAK,UAAU,KAAK,GAAG;AACxC,UAAI,OAAO,IAAI,IAAI,MAAM,OAAO;AAC9B,cAAM,YAAY,IAAI,IAAI;AAC1B,YAAI,WAAW;AACb,gBAAM,IAAI;AAAA,YACR,2CAA2C,SAAS;AAAA,UACtD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,KAA4B;AAEpD,QAAI,KAAK,UAAU,IAAI,GAAG,GAAG;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,UAAU,IAAI,GAAG,GAAG;AAC3B,aAAO,KAAK,UAAU,IAAI,GAAG,KAAK;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,QAA0B;AAErC,SAAK,QAAQ,IAAI,OAAO,MAAM,MAAM;AAGpC,QAAI,CAAC,OAAO,IAAI;AACd,WAAK,eAAe,OAAO,IAAI;AAAA,IACjC;AAGA,UAAM,cAAc,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC;AACtD,eAAW,UAAU,aAAa;AAChC,aAAO;AAAA,IACT;AACA,SAAK,QAAQ,OAAO,OAAO,IAAI;AAG/B,UAAM,MAAM,OAAO;AACnB,QAAI,QAAQ,OAAO,MAAM;AACvB,YAAM,aAAa,KAAK,QAAQ,IAAI,GAAG,KAAK,CAAC;AAC7C,iBAAW,UAAU,YAAY;AAC/B,eAAO;AAAA,MACT;AACA,WAAK,QAAQ,OAAO,GAAG;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,MAAoB;AAC7B,SAAK,YAAY,IAAI,IAAI;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAAmB,KAAsB;AAC/C,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AACA,WAAO,KAAK,YAAY,IAAI,YAAY;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,oBAAoB,MAA6B;AACrD,UAAM,OAAO,KAAK,aAAa,IAAI,IAAI;AACvC,QAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,OAAO,SAAO,KAAK,mBAAmB,GAAG,CAAC;AAClE,UAAM,eAAe,WAAW,IAAI,SAAO,KAAK,cAAc,GAAG,CAAC;AAClE,UAAM,QAAQ,IAAI,YAAY;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,WAAkC;AAEtD,UAAM,eAAe,KAAK,kBAAkB,SAAS;AACrD,QAAI,gBAAgB,KAAK,QAAQ,IAAI,YAAY,GAAG;AAClD,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAGA,QAAI,KAAK,QAAQ,IAAI,SAAS,GAAG;AAC/B,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAGA,WAAO,IAAI,QAAc,CAAAC,aAAW;AAClC,YAAM,UAAU,KAAK,QAAQ,IAAI,SAAS,KAAK,CAAC;AAChD,cAAQ,KAAKA,QAAO;AACpB,WAAK,QAAQ,IAAI,WAAW,OAAO;AAAA,IACrC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoB,MAA6B;AAC/C,UAAM,OAAO,KAAK,aAAa,IAAI,IAAI;AACvC,QAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,aAAO;AAAA,IACT;AAEA,eAAW,OAAO,MAAM;AACtB,YAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,UAAI,CAAC,aAAc;AAEnB,YAAM,SAAS,KAAK,QAAQ,IAAI,YAAY;AAC5C,UAAI,UAAU,CAAC,OAAO,IAAI;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAuB;AACrC,UAAM,OAAO,KAAK,aAAa,IAAI,IAAI;AACvC,WAAO,SAAS,UAAa,KAAK,SAAS;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAc,MAA0B;AACtD,SAAK,UAAU,IAAI,MAAM,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,MAAoB;AACpC,SAAK,UAAU,OAAO,IAAI;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAuB;AAC/B,WAAO,KAAK,YAAY,IAAI,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,YAA0B;AACvC,UAAM,aAAa,KAAK,YAAY,IAAI,UAAU,KAAK,CAAC;AAExD,eAAW,WAAW,YAAY;AAChC,YAAM,OAAO,KAAK,UAAU,IAAI,OAAO;AACvC,UAAI,MAAM,KAAK;AACb,aAAK,YAAY,IAAI,OAAO;AAE5B,iBAAS,KAAK,KAAK,WAAW,SAAO;AACnC,cAAI,KAAK;AAAA,UAET;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;;;ADnRO,SAAS,SACd,MACA,SAC+B;AAC/B,MAAI,CAAC,QAAS,QAAO,EAAE,GAAG,KAAK;AAE/B,QAAM,SAAS,EAAE,GAAG,KAAK;AACzB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,UAAU,MAAM;AAClB,aAAO,GAAG,IAAI;AAAA,IAChB,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,cACP,YACA,MACA,SACwB;AAExB,QAAM,SAAiC,CAAC;AACxC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,QAAW;AACvB,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAGA,SAAO,OAAO;AAGd,MAAI,SAAS;AACX,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAI,UAAU,MAAM;AAClB,eAAO,OAAO,GAAG;AAAA,MACnB,OAAO;AACL,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,YAAY,KAAqB;AAExC,MAAI,8BAA8B,KAAK,GAAG,GAAG;AAE3C,WAAO,IAAI,IAAI,QAAQ,MAAM,KAAK,CAAC;AAAA,EACrC;AACA,SAAO;AACT;AAOO,SAAS,qBAAqB,KAAqB;AACxD,QAAM,gBAAgB,QAAQ,aAAa,UAAU,MAAM;AAC3D,QAAM,eAAe,QAAQ,IAAI,QAAQ;AACzC,QAAM,WAAqB,CAAC;AAE5B,MAAI,UAAUC,SAAQ,GAAG;AAEzB,SAAO,MAAM;AACX,aAAS,KAAKC,MAAK,SAAS,gBAAgB,MAAM,CAAC;AACnD,UAAM,SAAS,QAAQ,OAAO;AAC9B,QAAI,WAAW,QAAS;AACxB,cAAU;AAAA,EACZ;AAEA,SAAO,CAAC,GAAG,UAAU,YAAY,EAAE,KAAK,aAAa;AACvD;AAMO,SAAS,iBACd,KACA,aACA,aACA,cACiB;AACjB,MAAI,OAAO,QAAQ,UAAU;AAE3B,QAAI,MAAM;AACV,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,YAAM,cAAc,YAAY,IAAI,WAAW,EAAE,KAAK,GAAG;AACzD,YAAM,GAAG,GAAG,IAAI,WAAW;AAAA,IAC7B;AAIA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,CAAC;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IACP;AAAA,EACF;AAGA,QAAM,OAAO,cAAc,CAAC,GAAG,IAAI,MAAM,GAAG,WAAW,IAAI,IAAI;AAG/D,QAAM,MAAM,SAAS,gBAAgB,CAAC,GAAG,IAAI,GAAG;AAEhD,SAAO;AAAA,IACL,KAAK,IAAI;AAAA,IACT;AAAA,IACA,KAAK,IAAI;AAAA,IACT,KAAK,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM;AAAA,IACzC,OAAO;AAAA;AAAA,IAEP,SAAS,IAAI,WAAW;AAAA,EAC1B;AACF;AAMA,eAAe,eACb,SACA,KACA,SACA,MAOC;AACD,QAAM,QAAQ,KAAK,IAAI;AAEvB,SAAO,IAAI,QAAQ,CAAAD,aAAW;AAG5B,UAAM,WAAW,QAAQ,SAAS,QAAQ,aAAa;AAEvD,UAAM,eAAe,QAAQ,OAAO;AACpC,UAAM,WAAW;AAAA,MACf,QAAQ;AAAA,MACR,qBAAqB,YAAY;AAAA,MACjC,QAAQ;AAAA,IACV;AACA,UAAM,OAAO,MAAM,QAAQ,KAAK,QAAQ,MAAM;AAAA,MAC5C,OAAO;AAAA,MACP,KAAK;AAAA,MACL,KAAK;AAAA,IACP,CAAC;AAGD,QAAI,WAAW,MAAM;AACnB,cAAQ,gBAAgB,MAAM,IAAI;AAAA,IACpC;AAEA,QAAI,SAAS;AACb,QAAI,WAAW;AACf,QAAI;AAGJ,QAAI,QAAQ,WAAW,KAAK,KAAK;AAC/B,YAAM,MAAM,KAAK;AACjB,kBAAY,WAAW,MAAM;AAC3B,mBAAW;AAEX,QAAAE,UAAS,KAAK,WAAW,SAAO;AAC9B,cAAI,KAAK;AAAA,UAET;AAAA,QACF,CAAC;AAAA,MACH,GAAG,QAAQ,OAAO;AAAA,IACpB;AAEA,SAAK,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACvC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACvC,gBAAU,KAAK,SAAS;AAAA,IAC1B,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,MAAM,WAAW;AAEjC,UAAI,WAAW;AACb,qBAAa,SAAS;AAAA,MACxB;AAGA,UAAI,WAAW,MAAM;AACnB,gBAAQ,kBAAkB,IAAI;AAAA,MAChC;AAEA,YAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,YAAM,SACJ,WAAW,aACX,SAAS,QACR,SAAS,UAAU,QAAQ,EAAE,KAAK;AAErC,MAAAF,SAAQ;AAAA,QACN,MAAM,QAAQ;AAAA,QACd;AAAA,QACA;AAAA,QACA,QAAQ,UAAU,CAAC;AAAA;AAAA,QACnB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,SAAK,GAAG,SAAS,SAAO;AAEtB,UAAI,WAAW;AACb,qBAAa,SAAS;AAAA,MACxB;AAGA,UAAI,WAAW,MAAM;AACnB,gBAAQ,kBAAkB,IAAI;AAAA,MAChC;AAEA,YAAM,aAAa,KAAK,IAAI,IAAI;AAChC,MAAAA,SAAQ;AAAA,QACN,MAAM;AAAA,QACN,QAAQ,8BAA8B,IAAI,OAAO;AAAA,QACjD;AAAA,QACA,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAKA,SAAS,cAAc,MAAc,SAA6B;AAChE,MAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AACpC,WAAO;AAAA,EACT;AAEA,SAAO,QAAQ,KAAK,YAAU;AAE5B,WAAO,SAAS,UAAU,KAAK,WAAW,GAAG,MAAM,GAAG;AAAA,EACxD,CAAC;AACH;AAKA,SAAS,sBACP,MACA,YACA,SACS;AACT,QAAM,OAAO,cAAc,YAAY,KAAK,GAAG;AAE/C,MAAI,cAAc,MAAM,OAAO,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,UAAU;AACjB,WAAO,KAAK,SAAS;AAAA,MAAK,WACxB,sBAAsB,OAAO,MAAM,OAAO;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO;AACT;AAUO,IAAM,qBAAN,MAAyB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACE,UAAyB,CAAC,GAC1B,WAA2B,iBAC3B,YAA6B,CAAC,GAC9B,YAA2C,CAAC,GAC5C;AACA,SAAK,UAAU;AACf,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,oBAAoB,IAAI,2BAA2B;AACxD,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,OAAkD;AAC1D,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,YAAY,KAAK,IAAI;AAG3B,SAAK,kBAAkB,WAAW,KAAK;AAGvC,UAAM,UAAU,SAAS,CAAC,GAAG,KAAK,SAAS;AAC3C,UAAM,UAAU,MAAM,KAAK,SAAS,OAAO,IAAI,YAAY,OAAO;AAElE,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,UAAM,QAAQ,QAAQ,MAAM,OAAK,EAAE,EAAE;AAErC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SACZ,OACA,YACA,WAAoD,YACpD,eAA8C,CAAC,GACxB;AAEvB,UAAM,gBAAgB,MAAM;AAAA,MAAO,UACjC,sBAAsB,MAAM,YAAY,KAAK,QAAQ,MAAM;AAAA,IAC7D;AAEA,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,CAAC;AAAA,IACV;AAEA,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,eAAO,QAAQ;AAAA,UACb,cAAc;AAAA,YAAI,UAChB,KAAK,QAAQ,MAAM,YAAY,YAAY;AAAA,UAC7C;AAAA,QACF;AAAA,MAEF,KAAK,cAAc;AACjB,cAAM,UAAwB,CAAC;AAC/B,mBAAW,QAAQ,eAAe;AAChC,kBAAQ,KAAK,MAAM,KAAK,QAAQ,MAAM,YAAY,YAAY,CAAC;AAAA,QACjE;AACA,eAAO;AAAA,MACT;AAAA,MAEA,KAAK,aAAa;AAChB,cAAM,UAAwB,CAAC;AAC/B,mBAAW,QAAQ,eAAe;AAChC,gBAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,YAAY,YAAY;AAChE,kBAAQ,KAAK,MAAM;AACnB,cAAI,CAAC,OAAO,IAAI;AACd;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,QACZ,MACA,YACA,eAA8C,CAAC,GAC1B;AACrB,UAAM,OAAO,cAAc,YAAY,KAAK,GAAG;AAG/C,UAAM,UAAU,SAAS,cAAc,KAAK,GAAG;AAG/C,SAAK,kBAAkB,WAAW,IAAI;AAGtC,SAAK,UAAU,cAAc,MAAM,KAAK,GAAG;AAG3C,QAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AAC7C,YAAM,QAAQ,KAAK,IAAI;AACvB,YAAM,eAAe,MAAM,KAAK;AAAA,QAC9B,KAAK;AAAA,QACL;AAAA,QACA,KAAK,YAAY;AAAA,QACjB;AAAA,MACF;AACA,YAAMG,cAAa,KAAK,IAAI,IAAI;AAEhC,YAAM,QAAQ,aAAa,MAAM,OAAK,EAAE,MAAM,EAAE,UAAU;AAG1D,YAAM,gBACJ,aAAa,SAAS,KAAK,aAAa,MAAM,OAAK,EAAE,UAAU;AACjE,YAAM,gBAAgB,aAAa,KAAK,OAAK,EAAE,UAAU;AAEzD,YAAMC,UAAqB;AAAA,QACzB,KAAK,KAAK;AAAA,QACV;AAAA,QACA,IAAI;AAAA,QACJ,MAAM,QAAQ,IAAI;AAAA,QAClB,YAAAD;AAAA,QACA,QAAQ;AAAA,QACR,aAAa,QACR,KAAK,gBAAgB,GAAG,KAAK,GAAG,iBAChC,KAAK,gBAAgB,GAAG,KAAK,GAAG;AAAA,QACrC,UAAU;AAAA,MACZ;AAGA,UAAI,eAAe;AACjB,QAAAC,QAAO,aAAa;AACpB,QAAAA,QAAO,eAAe,aAAa,CAAC,EAAE;AAAA,MACxC,WAAW,iBAAiB,CAAC,OAAO;AAAA,MAGpC;AAGA,WAAK,kBAAkB,aAAaA,OAAM;AAC1C,WAAK,UAAU,iBAAiBA,OAAM;AACtC,aAAOA;AAAA,IACT;AAGA,QAAI,CAAC,KAAK,KAAK;AACb,YAAMA,UAAqB;AAAA,QACzB,KAAK,KAAK;AAAA,QACV;AAAA,QACA,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,aAAa,GAAG,KAAK,GAAG;AAAA,MAC1B;AACA,WAAK,kBAAkB,aAAaA,OAAM;AAC1C,WAAK,UAAU,iBAAiBA,OAAM;AACtC,aAAOA;AAAA,IACT;AAGA,UAAM,cAAc,KAAK,QAAQ;AACjC,UAAM,UAAU;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AACA,UAAM,MAAM,KAAK,QAAQ,OAAO,QAAQ,IAAI;AAG5C,UAAM,EAAE,MAAM,QAAQ,YAAY,QAAQ,SAAS,IAAI,MAAM;AAAA,MAC3D;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AAEA,UAAM,KAAK,SAAS;AAGpB,QAAI,UAAU;AACZ,YAAMA,UAAqB;AAAA,QACzB,KAAK,KAAK;AAAA,QACV;AAAA,QACA,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,GAAG,KAAK,GAAG,qBAAqB,QAAQ,OAAO;AAAA,QAC5D,UAAU;AAAA,MACZ;AAEA,WAAK,kBAAkB,aAAaA,OAAM;AAC1C,WAAK,UAAU,iBAAiBA,OAAM;AACtC,aAAOA;AAAA,IACT;AAGA,QAAI,QAAQ;AAEV,YAAM,KAAK,kBAAkB,oBAAoB,IAAI;AACrD,YAAM,YAAY,KAAK,kBAAkB,oBAAoB,IAAI;AAEjE,YAAMA,UAAqB;AAAA,QACzB,KAAK,KAAK;AAAA,QACV;AAAA,QACA,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,GAAG,KAAK,GAAG;AAAA,QACxB,YAAY;AAAA,QACZ,cAAc,aAAa;AAAA,MAC7B;AAEA,WAAK,kBAAkB,aAAaA,OAAM;AAC1C,WAAK,UAAU,iBAAiBA,OAAM;AACtC,aAAOA;AAAA,IACT;AAGA,UAAM,YAAY,QAAQ,QACtB,QAAQ,MACR,GAAG,QAAQ,GAAG,IAAI,QAAQ,KAAK,KAAK,GAAG,CAAC;AAC5C,UAAM,SAAuB,KAAK,SAAS;AAAA,MACzC;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,IAAI;AACN,oBAAc,KAAK,eACf,GAAG,KAAK,GAAG,KAAK,KAAK,YAAY,KACjC,GAAG,KAAK,GAAG,KAAK,OAAO,OAAO;AAAA,IACpC,OAAO;AACL,oBAAc,KAAK,eACf,GAAG,KAAK,GAAG,KAAK,KAAK,YAAY,KACjC,GAAG,KAAK,GAAG,KAAK,OAAO,OAAO;AAAA,IACpC;AAEA,QAAI,SAAqB;AAAA,MACvB,KAAK,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,IAClB;AAGA,QAAI,KAAK,kBAAkB,gBAAgB,IAAI,GAAG;AAChD,YAAM,KAAK,kBAAkB,oBAAoB,IAAI;AAGrD,UAAI,CAAC,IAAI;AACP,cAAM,YAAY,KAAK,kBAAkB,oBAAoB,IAAI;AACjE,YAAI,WAAW;AACb,mBAAS;AAAA,YACP,GAAG;AAAA,YACH,YAAY;AAAA,YACZ,cAAc;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,SAAK,kBAAkB,aAAa,MAAM;AAC1C,SAAK,UAAU,iBAAiB,MAAM;AACtC,WAAO;AAAA,EACT;AACF;;;AErhBA,eAAsB,OACpB,QACA,YACuB;AACvB,QAAM,UAAU,aAAa,OAAO,SAAS,UAAU;AAGvD,MAAI,QAAQ,UAAU,QAAQ,OAAO,SAAS,GAAG;AAC/C,UAAM,WAAW,eAAe,OAAO,OAAO,QAAQ,MAAM;AAG5D,eAAW,KAAK,UAAU;AACxB,UAAI,EAAE,aAAa;AACjB,gBAAQ,MAAM,qBAAgB,EAAE,QAAQ,SAAS,EAAE,QAAQ,GAAG;AAAA,MAChE;AAAA,IACF;AAGA,YAAQ,SAAS,SAAS,IAAI,OAAK,EAAE,QAAQ;AAAA,EAC/C;AAGA,QAAM,WAAW,eAAe,OAAO;AAGvC,WAAS,UAAU,OAAO,KAAK;AAE/B,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,MACE,aAAa,CAAC,MAAM,QAAQ,SAAS,YAAY,MAAM,GAAG;AAAA,MAC1D,gBAAgB,CAAAC,YAAU,SAAS,eAAeA,OAAM;AAAA,IAC1D;AAAA,IACA,OAAO;AAAA,EACT;AAEA,QAAM,SAAS,MAAM,OAAO,IAAI,OAAO,KAAK;AAG5C,WAAS,WAAW;AAEpB,WAAS,WAAW,OAAO,OAAO,QAAQ,QAAQ,QAAQ;AAC1D,WAAS,cAAc,MAAM;AAE7B,SAAO;AACT;AAKA,eAAsB,iBACpB,MAAc,QAAQ,IAAI,GAC1B,YACuB;AACvB,QAAM,SAAS,MAAM,kBAAkB,KAAK,YAAY,GAAG;AAE3D,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,6BAA6B,GAAG;AAAA,IAClC;AAAA,EACF;AAEA,SAAO,OAAO,QAAQ,EAAE,GAAG,YAAY,IAAI,CAAC;AAC9C;","names":["existsSync","join","z","join","existsSync","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","resolve","errors","join","resolve","treeKill","resolve","resolve","join","treeKill","durationMs","result","result"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/discovery.ts","../src/schemas/package-json.ts","../src/filter.ts","../src/tree.ts","../src/init/detect.ts","../src/init/generate.ts","../src/init/prompts.ts","../src/init/write.ts","../src/init/index.ts","../src/parsers/biome.ts","../src/parsers/generic.ts","../src/parsers/gotest.ts","../src/parsers/tsc.ts","../src/parsers/vitest.ts","../src/parsers/index.ts","../src/spinner.ts","../src/reporter.ts","../src/runner.ts","../src/dependency-tracker.ts","../src/index.ts"],"sourcesContent":["import { existsSync } from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { z } from \"zod\"\nimport type { VerificationNode, VerifyConfig, VerifyOptions } from \"./types.js\"\n\n/**\n * Error thrown when config validation fails\n */\nexport class ConfigError extends Error {\n constructor(\n message: string,\n public readonly configPath?: string,\n ) {\n super(message)\n this.name = \"ConfigError\"\n }\n}\n\n/**\n * Reusable env schema - allows string or null values\n */\nconst EnvSchema = z.record(z.string(), z.string().nullable()).optional()\n\n/**\n * Zod schema for VerificationCommand\n */\nconst VerificationCommandSchema = z.object({\n cmd: z.string(),\n args: z.array(z.string()),\n cwd: z.string().optional(),\n env: EnvSchema,\n timeout: z.number().positive().optional(),\n})\n\n/**\n * Zod schema for VerificationNode (recursive)\n */\nconst VerificationNodeSchema: z.ZodType<VerificationNode> = z.lazy(() =>\n z.object({\n key: z\n .string()\n .min(1, \"Task key cannot be empty\")\n .refine(key => !key.includes(\":\"), {\n message: \"Task key cannot contain ':' (reserved for paths)\",\n }),\n name: z.string().optional(),\n run: z.union([z.string(), VerificationCommandSchema]).optional(),\n children: z.array(VerificationNodeSchema).optional(),\n strategy: z.enum([\"parallel\", \"sequential\", \"fail-fast\"]).optional(),\n parser: z.string().optional(),\n successLabel: z.string().optional(),\n failureLabel: z.string().optional(),\n reportingDependsOn: z.array(z.string()).optional(),\n timeout: z.number().positive().optional(),\n env: EnvSchema,\n }),\n) as z.ZodType<VerificationNode>\n\n/**\n * Zod schema for VerifyOptions\n */\nconst VerifyOptionsSchema = z.object({\n logs: z.enum([\"all\", \"failed\", \"none\"]).optional(),\n format: z.enum([\"human\", \"json\"]).optional(),\n filter: z.array(z.string()).optional(),\n cwd: z.string().optional(),\n noColor: z.boolean().optional(),\n topLevelOnly: z.boolean().optional(),\n noTty: z.boolean().optional(),\n passthrough: z.array(z.string()).optional(),\n})\n\n/**\n * Zod schema for PackageDiscoveryOptions\n */\nconst PackageDiscoveryOptionsSchema = z.object({\n patterns: z.array(z.string()).optional(),\n filter: z.array(z.string()).optional(),\n changed: z.boolean().optional(),\n})\n\n/**\n * Zod schema for VerifyConfig\n */\nconst VerifyConfigSchema = z.object({\n tasks: z.array(VerificationNodeSchema),\n packages: PackageDiscoveryOptionsSchema.optional(),\n options: VerifyOptionsSchema.optional(),\n env: EnvSchema,\n})\n\n/**\n * Validate a config object and return typed result\n */\nexport function validateConfig(\n value: unknown,\n configPath?: string,\n): VerifyConfig {\n const result = VerifyConfigSchema.safeParse(value)\n\n if (!result.success) {\n const errors = result.error.issues.map(issue => {\n const path = issue.path.join(\".\")\n return path ? `${path}: ${issue.message}` : issue.message\n })\n throw new ConfigError(\n `Invalid config:\\n - ${errors.join(\"\\n - \")}`,\n configPath,\n )\n }\n\n return result.data\n}\n\n/**\n * Helper function for defining config with type inference\n */\nexport function defineConfig(config: VerifyConfig): VerifyConfig {\n return config\n}\n\n/**\n * Helper function for defining a single verification task\n */\nexport function defineTask(task: VerificationNode): VerificationNode {\n return task\n}\n\n/**\n * Config file names to search for (in order of priority)\n */\nconst CONFIG_FILES = [\n \"verify.config.ts\",\n \"verify.config.mts\",\n \"verify.config.js\",\n \"verify.config.mjs\",\n]\n\n/**\n * Find config file in directory\n */\nexport function findConfigFile(cwd: string): string | null {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n if (existsSync(filepath)) {\n return filepath\n }\n }\n return null\n}\n\n/**\n * Load config from file\n */\nexport async function loadConfig(\n configPath: string,\n): Promise<VerifyConfig | null> {\n const absolutePath = resolve(configPath)\n\n if (!existsSync(absolutePath)) {\n return null\n }\n\n // Use dynamic import with file URL for cross-platform compatibility\n const fileUrl = pathToFileURL(absolutePath).href\n const module = (await import(fileUrl)) as { default?: unknown }\n\n if (!module.default) {\n throw new ConfigError(`Config file must have a default export`, configPath)\n }\n\n // Validate the config using zod\n return validateConfig(module.default, configPath)\n}\n\n/**\n * Load config from cwd or specified path\n */\nexport async function loadConfigFromCwd(\n cwd: string,\n configPath?: string,\n): Promise<VerifyConfig | null> {\n if (configPath) {\n return loadConfig(configPath)\n }\n\n const foundPath = findConfigFile(cwd)\n if (!foundPath) {\n return null\n }\n\n return loadConfig(foundPath)\n}\n\n/**\n * Helper type that requires all keys to be present but preserves original value types.\n * This is used to ensure mergeOptions handles all VerifyOptions properties.\n */\ntype AllKeys<T> = { [K in keyof Required<T>]: T[K] }\n\n/**\n * Merge options with defaults.\n *\n * NOTE: The `satisfies AllKeys<VerifyOptions>` ensures this function handles\n * all properties of VerifyOptions. If you add a new option to VerifyOptions,\n * TypeScript will error here until you add it to the return object.\n */\nexport function mergeOptions(\n configOptions?: VerifyOptions,\n cliOptions?: Partial<VerifyOptions>,\n): VerifyOptions {\n return {\n logs: cliOptions?.logs ?? configOptions?.logs ?? \"failed\",\n format: cliOptions?.format ?? configOptions?.format ?? \"human\",\n filter: cliOptions?.filter ?? configOptions?.filter,\n cwd: cliOptions?.cwd ?? configOptions?.cwd ?? process.cwd(),\n noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,\n topLevelOnly:\n cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,\n noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,\n quiet: cliOptions?.quiet ?? configOptions?.quiet ?? false,\n passthrough: cliOptions?.passthrough ?? configOptions?.passthrough,\n } satisfies AllKeys<VerifyOptions>\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\"\nimport { join, relative } from \"node:path\"\nimport { findConfigFile, loadConfig } from \"./config.js\"\nimport { parsePackageJson } from \"./schemas/package-json.js\"\nimport type { PackageDiscoveryOptions, VerifyConfig } from \"./types.js\"\n\n/**\n * Discovered package with its config\n */\nexport interface DiscoveredPackage {\n /** Package name from package.json */\n name: string\n /** Relative path from root */\n path: string\n /** Absolute path */\n absolutePath: string\n /** Loaded verify config (if exists) */\n config: VerifyConfig | null\n}\n\n/**\n * Default glob patterns for package discovery\n */\nconst DEFAULT_PATTERNS = [\"packages/*\", \"apps/*\"]\n\n/**\n * Find directories matching patterns\n */\nfunction findMatchingDirs(rootDir: string, patterns: string[]): string[] {\n const results: string[] = []\n\n for (const pattern of patterns) {\n // Handle simple patterns like \"packages/*\"\n if (pattern.endsWith(\"/*\")) {\n const parentDir = pattern.slice(0, -2)\n const parentPath = join(rootDir, parentDir)\n\n if (existsSync(parentPath) && statSync(parentPath).isDirectory()) {\n const entries = readdirSync(parentPath)\n for (const entry of entries) {\n const entryPath = join(parentPath, entry)\n if (statSync(entryPath).isDirectory()) {\n results.push(entryPath)\n }\n }\n }\n } else {\n // Direct path\n const dirPath = join(rootDir, pattern)\n if (existsSync(dirPath) && statSync(dirPath).isDirectory()) {\n results.push(dirPath)\n }\n }\n }\n\n return results\n}\n\n/**\n * Read package name from package.json\n */\nfunction getPackageName(packageDir: string): string | null {\n const packageJsonPath = join(packageDir, \"package.json\")\n if (!existsSync(packageJsonPath)) {\n return null\n }\n\n try {\n const content = readFileSync(packageJsonPath, \"utf-8\")\n const parsed = parsePackageJson(content)\n return parsed?.name ?? null\n } catch {\n // File read error\n return null\n }\n}\n\n/**\n * Discover packages in a monorepo\n */\nexport async function discoverPackages(\n rootDir: string,\n options: PackageDiscoveryOptions = {},\n): Promise<DiscoveredPackage[]> {\n const patterns = options.patterns ?? DEFAULT_PATTERNS\n const matchingDirs = findMatchingDirs(rootDir, patterns)\n\n const packages: DiscoveredPackage[] = []\n\n for (const dir of matchingDirs) {\n const name = getPackageName(dir)\n if (!name) continue // Skip directories without package.json\n\n // Check filter\n if (options.filter && options.filter.length > 0) {\n const matches = options.filter.some(\n f =>\n name === f || name.includes(f) || relative(rootDir, dir).includes(f),\n )\n if (!matches) continue\n }\n\n // Try to load verify config\n const configPath = findConfigFile(dir)\n const config = configPath ? await loadConfig(configPath) : null\n\n packages.push({\n name,\n path: relative(rootDir, dir),\n absolutePath: dir,\n config,\n })\n }\n\n return packages\n}\n\n/**\n * Check if a package has changed (git-aware)\n * This is a placeholder - full implementation would use git diff\n */\nexport async function hasPackageChanged(\n _packagePath: string,\n _baseBranch = \"main\",\n): Promise<boolean> {\n // TODO: Implement git-aware change detection\n // For now, always return true (include all packages)\n return true\n}\n","import { z } from \"zod\"\n\n/**\n * Minimal zod schema for package.json\n * Only validates the fields we actually use\n */\nexport const PackageJsonSchema = z\n .object({\n name: z.string().optional(),\n scripts: z.record(z.string(), z.string()).optional(),\n })\n .passthrough() // Allow other fields we don't care about\n\n/**\n * Typed result from parsing package.json\n */\nexport type PackageJson = z.infer<typeof PackageJsonSchema>\n\n/**\n * Parse package.json content safely\n * Returns null if parsing fails (invalid JSON or schema mismatch)\n */\nexport function parsePackageJson(content: string): PackageJson | null {\n try {\n const parsed: unknown = JSON.parse(content)\n const result = PackageJsonSchema.safeParse(parsed)\n return result.success ? result.data : null\n } catch {\n // JSON parse error\n return null\n }\n}\n","import leven from \"leven\"\nimport { collectPaths, PATH_SEPARATOR } from \"./tree.js\"\nimport type { VerificationNode } from \"./types.js\"\n\n/**\n * Result of resolving a filter to a valid task path\n */\nexport interface ResolvedFilter {\n /** The original filter string provided by the user */\n original: string\n /** The resolved full task path */\n resolved: string\n /** Whether this was resolved via child shortcut (e.g., \"tsc\" → \"types:tsc\") */\n wasShortcut: boolean\n}\n\n/**\n * Error thrown when a task filter doesn't match any existing task\n */\nexport class TaskNotFoundError extends Error {\n readonly exitCode = 2\n\n constructor(\n public readonly filter: string,\n public readonly suggestion: string | undefined,\n public readonly availableTasks: string[],\n ) {\n super(buildErrorMessage(filter, suggestion, availableTasks))\n this.name = \"TaskNotFoundError\"\n }\n}\n\n/**\n * Error thrown when a task filter matches multiple tasks ambiguously\n */\nexport class AmbiguousTaskError extends Error {\n readonly exitCode = 2\n\n constructor(\n public readonly filter: string,\n public readonly matches: string[],\n ) {\n super(buildAmbiguousErrorMessage(filter, matches))\n this.name = \"AmbiguousTaskError\"\n }\n}\n\n/**\n * Build error message for task not found\n */\nfunction buildErrorMessage(\n filter: string,\n suggestion: string | undefined,\n availableTasks: string[],\n): string {\n let message = `Task \"${filter}\" not found.`\n\n if (suggestion) {\n message += `\\n\\nDid you mean \"${suggestion}\"?`\n }\n\n message += \"\\n\\nAvailable tasks:\"\n for (const task of availableTasks) {\n message += `\\n ${task}`\n }\n\n return message\n}\n\n/**\n * Build error message for ambiguous task\n */\nfunction buildAmbiguousErrorMessage(filter: string, matches: string[]): string {\n let message = `Task \"${filter}\" is ambiguous.`\n message += \"\\n\\nMatches multiple tasks:\"\n for (const match of matches) {\n message += `\\n ${match}`\n }\n return message\n}\n\n/**\n * Find the single best suggestion using Levenshtein distance.\n * Returns undefined if no good match (distance > threshold).\n */\nexport function findBestSuggestion(\n availablePaths: string[],\n invalidFilter: string,\n): string | undefined {\n let bestPath: string | undefined\n let bestDistance = Number.POSITIVE_INFINITY\n\n // Threshold: distance <= 2 for short names, or <= length/3 for longer\n const threshold = Math.max(2, Math.floor(invalidFilter.length / 3))\n\n for (const path of availablePaths) {\n // Check against full path\n const distance = leven(invalidFilter, path)\n if (distance < bestDistance && distance <= threshold) {\n bestDistance = distance\n bestPath = path\n }\n\n // Also check against just the last segment (child key)\n const lastSegment = path.split(PATH_SEPARATOR).pop()\n if (lastSegment && lastSegment !== path) {\n const segmentDistance = leven(invalidFilter, lastSegment)\n if (segmentDistance < bestDistance && segmentDistance <= threshold) {\n bestDistance = segmentDistance\n bestPath = path\n }\n }\n }\n\n return bestPath\n}\n\n/**\n * Resolve a single filter to a valid task path.\n * Returns the resolved filter or throws an error.\n */\nfunction resolveFilter(\n filter: string,\n availablePaths: string[],\n): ResolvedFilter {\n // 1. Exact match - filter matches a path exactly\n if (availablePaths.includes(filter)) {\n return { original: filter, resolved: filter, wasShortcut: false }\n }\n\n // 2. Prefix match - filter is a prefix of paths (e.g., \"types\" matches \"types:tsc\")\n const prefixMatches = availablePaths.filter(\n path => path === filter || path.startsWith(`${filter}${PATH_SEPARATOR}`),\n )\n if (prefixMatches.length > 0) {\n // If the filter itself is a valid path (parent node), use it\n // The runner will handle running children\n return { original: filter, resolved: filter, wasShortcut: false }\n }\n\n // 3. Child shortcut - filter matches the last segment of path(s)\n const childMatches = availablePaths.filter(path => {\n const lastSegment = path.split(PATH_SEPARATOR).pop()\n return lastSegment === filter\n })\n\n if (childMatches.length === 1) {\n // Unambiguous child match\n return {\n original: filter,\n resolved: childMatches[0],\n wasShortcut: true,\n }\n }\n\n if (childMatches.length > 1) {\n // Ambiguous - multiple paths end with this key\n throw new AmbiguousTaskError(filter, childMatches)\n }\n\n // 4. No match - find suggestion and throw error\n const suggestion = findBestSuggestion(availablePaths, filter)\n throw new TaskNotFoundError(filter, suggestion, availablePaths)\n}\n\n/**\n * Resolve and validate all filters before running any tasks.\n * Fails fast on first invalid filter.\n *\n * @param nodes - The verification task tree\n * @param filters - User-provided filter strings\n * @returns Array of resolved filters\n * @throws TaskNotFoundError if a filter doesn't match any task\n * @throws AmbiguousTaskError if a filter matches multiple tasks\n */\nexport function resolveFilters(\n nodes: VerificationNode[],\n filters: string[],\n): ResolvedFilter[] {\n const availablePaths = collectPaths(nodes)\n const resolved: ResolvedFilter[] = []\n\n for (const filter of filters) {\n resolved.push(resolveFilter(filter, availablePaths))\n }\n\n return resolved\n}\n","import type { VerificationNode } from \"./types.js\"\n\n/**\n * Path separator used in task paths\n */\nexport const PATH_SEPARATOR = \":\"\n\n/**\n * Build a task path from parent path and key\n */\nexport function buildTaskPath(parentPath: string, key: string): string {\n return parentPath ? `${parentPath}${PATH_SEPARATOR}${key}` : key\n}\n\n/**\n * Visitor function called for each node during tree traversal\n */\nexport type NodeVisitor = (\n node: VerificationNode,\n path: string,\n depth: number,\n) => void\n\n/**\n * Walk all nodes in a verification tree in depth-first order\n *\n * @param nodes - The nodes to walk\n * @param visitor - Function called for each node with (node, path, depth)\n * @param parentPath - Parent path prefix (used for recursion)\n * @param depth - Current depth (used for recursion)\n */\nexport function walkNodes(\n nodes: VerificationNode[],\n visitor: NodeVisitor,\n parentPath = \"\",\n depth = 0,\n): void {\n for (const node of nodes) {\n const path = buildTaskPath(parentPath, node.key)\n visitor(node, path, depth)\n if (node.children) {\n walkNodes(node.children, visitor, path, depth + 1)\n }\n }\n}\n\n/**\n * Collect all task paths from a verification tree\n */\nexport function collectPaths(nodes: VerificationNode[]): string[] {\n const paths: string[] = []\n walkNodes(nodes, (_node, path) => {\n paths.push(path)\n })\n return paths\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { type PackageJson, parsePackageJson } from \"../schemas/package-json.js\"\n\n/**\n * A detected task candidate from package.json\n */\nexport interface DetectedTask {\n /** Suggested key for the task */\n key: string\n /** Human-readable name */\n name: string\n /** The npm script name that was detected */\n scriptName: string\n /** The command to run (optimized direct path when possible) */\n command: string\n /** Category for grouping (format, types, logic, build) */\n category: \"format\" | \"types\" | \"logic\" | \"build\" | \"other\"\n /** Parser to use for this task */\n parser?: string\n /**\n * Tasks that must pass for this task's failure to be reported.\n * Auto-populated based on category (types/logic/build depend on format).\n */\n reportingDependsOn?: string[]\n}\n\n/**\n * Tool detection patterns - maps script content to optimized commands\n */\ninterface ToolPattern {\n /** Regex to match in script content */\n pattern: RegExp\n /** Binary name in node_modules/.bin */\n binary: string\n /** Arguments to append (extracted from script or default) */\n getArgs: (match: RegExpMatchArray, scriptContent: string) => string\n /** Parser to use */\n parser?: string\n}\n\nconst TOOL_PATTERNS: ToolPattern[] = [\n // Biome\n {\n pattern: /\\bbiome\\s+(check|lint|format)/,\n binary: \"biome\",\n getArgs: (match, content) => {\n // Extract the full biome command with args\n const biomeMatch = content.match(/biome\\s+([^&|;]+)/)\n return biomeMatch ? biomeMatch[1].trim() : \"check .\"\n },\n parser: \"biome\",\n },\n // ESLint\n {\n pattern: /\\beslint\\b/,\n binary: \"eslint\",\n getArgs: (_, content) => {\n const eslintMatch = content.match(/eslint\\s+([^&|;]+)/)\n return eslintMatch ? eslintMatch[1].trim() : \".\"\n },\n },\n // Prettier\n {\n pattern: /\\bprettier\\b/,\n binary: \"prettier\",\n getArgs: (_, content) => {\n const prettierMatch = content.match(/prettier\\s+([^&|;]+)/)\n return prettierMatch ? prettierMatch[1].trim() : \"--check .\"\n },\n },\n // TypeScript\n {\n pattern: /\\btsc\\b/,\n binary: \"tsc\",\n getArgs: (_, content) => {\n const tscMatch = content.match(/tsc\\s+([^&|;]+)/)\n return tscMatch ? tscMatch[1].trim() : \"--noEmit\"\n },\n parser: \"tsc\",\n },\n // tsgo\n {\n pattern: /\\btsgo\\b/,\n binary: \"tsgo\",\n getArgs: (_, content) => {\n const tsgoMatch = content.match(/tsgo\\s+([^&|;]+)/)\n return tsgoMatch ? tsgoMatch[1].trim() : \"--noEmit\"\n },\n parser: \"tsc\",\n },\n // Vitest\n {\n pattern: /\\bvitest\\b/,\n binary: \"vitest\",\n getArgs: (_, content) => {\n // Check if it's watch mode or run mode\n if (content.includes(\"vitest run\")) return \"run\"\n if (content.includes(\"vitest watch\")) return \"run\" // Convert watch to run for verify\n return \"run\"\n },\n parser: \"vitest\",\n },\n // Jest\n {\n pattern: /\\bjest\\b/,\n binary: \"jest\",\n getArgs: () => \"\",\n },\n // Mocha\n {\n pattern: /\\bmocha\\b/,\n binary: \"mocha\",\n getArgs: () => \"\",\n },\n // tsup\n {\n pattern: /\\btsup\\b/,\n binary: \"tsup\",\n getArgs: (_, content) => {\n const tsupMatch = content.match(/tsup\\s+([^&|;]+)/)\n return tsupMatch ? tsupMatch[1].trim() : \"\"\n },\n },\n // esbuild\n {\n pattern: /\\besbuild\\b/,\n binary: \"esbuild\",\n getArgs: (_, content) => {\n const esbuildMatch = content.match(/esbuild\\s+([^&|;]+)/)\n return esbuildMatch ? esbuildMatch[1].trim() : \"\"\n },\n },\n]\n\n/**\n * Patterns to detect verification-related scripts by name\n */\nconst SCRIPT_NAME_PATTERNS: Array<{\n pattern: RegExp\n key: string\n name: string\n category: DetectedTask[\"category\"]\n}> = [\n // Format/Lint patterns\n {\n pattern: /^(lint|eslint|biome|prettier|format)$/i,\n key: \"format\",\n name: \"Format & Lint\",\n category: \"format\",\n },\n {\n pattern: /^(lint:fix|format:fix|fix)$/i,\n key: \"format\",\n name: \"Format & Lint\",\n category: \"format\",\n },\n {\n pattern: /^verify:format$/i,\n key: \"format\",\n name: \"Format\",\n category: \"format\",\n },\n\n // Type checking patterns\n {\n pattern: /^(typecheck|type-check|tsc|types|check-types)$/i,\n key: \"types\",\n name: \"Type Check\",\n category: \"types\",\n },\n {\n pattern: /^verify:types$/i,\n key: \"types\",\n name: \"Types\",\n category: \"types\",\n },\n\n // Test patterns\n {\n pattern: /^(test|tests|vitest|jest|mocha|ava)$/i,\n key: \"test\",\n name: \"Tests\",\n category: \"logic\",\n },\n {\n pattern: /^test:(unit|integration|e2e)$/i,\n key: \"test\",\n name: \"Tests\",\n category: \"logic\",\n },\n {\n pattern: /^verify:logic$/i,\n key: \"logic\",\n name: \"Logic Tests\",\n category: \"logic\",\n },\n\n // Build patterns\n {\n pattern: /^(build|compile)$/i,\n key: \"build\",\n name: \"Build\",\n category: \"build\",\n },\n]\n\n/**\n * Read and parse package.json from a directory\n */\nfunction readPackageJson(cwd: string): PackageJson | null {\n const packageJsonPath = join(cwd, \"package.json\")\n\n if (!existsSync(packageJsonPath)) {\n return null\n }\n\n try {\n const content = readFileSync(packageJsonPath, \"utf-8\")\n return parsePackageJson(content)\n } catch {\n return null\n }\n}\n\n/**\n * Check if a binary exists in node_modules/.bin\n */\nfunction binaryExists(cwd: string, binary: string): boolean {\n return existsSync(join(cwd, \"node_modules\", \".bin\", binary))\n}\n\n/**\n * Try to extract an optimized direct command from script content.\n * Returns clean binary names since verify automatically includes\n * node_modules/.bin in PATH.\n */\nfunction extractOptimizedCommand(\n cwd: string,\n scriptContent: string,\n): { command: string; parser?: string } | null {\n for (const tool of TOOL_PATTERNS) {\n const match = scriptContent.match(tool.pattern)\n if (match && binaryExists(cwd, tool.binary)) {\n const args = tool.getArgs(match, scriptContent)\n // Use clean binary name - verify automatically adds node_modules/.bin to PATH\n const command = args ? `${tool.binary} ${args}` : tool.binary\n return { command, parser: tool.parser }\n }\n }\n return null\n}\n\n/**\n * Detect verification tasks from package.json scripts\n */\nexport function detectFromPackageJson(cwd: string): DetectedTask[] {\n const pkg = readPackageJson(cwd)\n\n if (!pkg?.scripts) {\n return []\n }\n\n const detected: DetectedTask[] = []\n const seenKeys = new Set<string>()\n\n for (const [scriptName, scriptContent] of Object.entries(pkg.scripts)) {\n // Skip scripts that are just running other scripts (like \"verify\": \"run-s ...\")\n if (\n scriptContent.includes(\"run-s\") ||\n scriptContent.includes(\"run-p\") ||\n scriptContent.includes(\"npm-run-all\")\n ) {\n continue\n }\n\n // Check against detection patterns\n for (const { pattern, key, name, category } of SCRIPT_NAME_PATTERNS) {\n if (pattern.test(scriptName)) {\n // Avoid duplicates for the same key\n const uniqueKey = seenKeys.has(key) ? `${key}-${scriptName}` : key\n if (!seenKeys.has(uniqueKey)) {\n seenKeys.add(uniqueKey)\n\n // Try to extract optimized command\n const optimized = extractOptimizedCommand(cwd, scriptContent)\n\n detected.push({\n key: uniqueKey,\n name,\n scriptName,\n command: optimized?.command ?? `npm run ${scriptName}`,\n category,\n parser: optimized?.parser,\n })\n }\n break\n }\n }\n }\n\n // Sort by category priority: format -> types -> logic -> build -> other\n const categoryOrder: Record<DetectedTask[\"category\"], number> = {\n format: 0,\n types: 1,\n logic: 2,\n build: 3,\n other: 4,\n }\n\n detected.sort((a, b) => categoryOrder[a.category] - categoryOrder[b.category])\n\n // Add reportingDependsOn for non-format tasks if a format task exists\n // This reduces noise when a syntax error causes multiple tools to fail\n const hasFormatTask = detected.some(t => t.category === \"format\")\n if (hasFormatTask) {\n for (const task of detected) {\n if (task.category !== \"format\" && task.category !== \"other\") {\n task.reportingDependsOn = [\"format\"]\n }\n }\n }\n\n return detected\n}\n\n/**\n * Detect the package manager being used\n */\nexport function detectPackageManager(cwd: string): \"npm\" | \"pnpm\" | \"yarn\" {\n if (existsSync(join(cwd, \"pnpm-lock.yaml\"))) {\n return \"pnpm\"\n }\n if (existsSync(join(cwd, \"yarn.lock\"))) {\n return \"yarn\"\n }\n return \"npm\"\n}\n\n/**\n * Get the run command for a package manager\n */\nexport function getRunCommand(\n packageManager: \"npm\" | \"pnpm\" | \"yarn\",\n scriptName: string,\n): string {\n switch (packageManager) {\n case \"pnpm\":\n return `pnpm ${scriptName}`\n case \"yarn\":\n return `yarn ${scriptName}`\n default:\n return `npm run ${scriptName}`\n }\n}\n\n/**\n * Detect tasks with proper package manager commands\n * Uses optimized direct binary names when possible, falls back to package manager\n */\nexport function detectTasks(cwd: string): DetectedTask[] {\n const packageManager = detectPackageManager(cwd)\n const tasks = detectFromPackageJson(cwd)\n\n // For tasks without optimized commands, use package manager\n return tasks.map(task => {\n // If command is already optimized (doesn't start with npm/pnpm/yarn), keep it\n if (!task.command.startsWith(\"npm run \")) {\n return task\n }\n // Otherwise use package manager command\n return {\n ...task,\n command: getRunCommand(packageManager, task.scriptName),\n }\n })\n}\n","import type { DetectedTask } from \"./detect.js\"\n\n/**\n * Output format for the generated config\n */\nexport type OutputFormat = \"ts\" | \"mts\" | \"js\" | \"mjs\"\n\n/**\n * Determine output format from file path\n */\nexport function getOutputFormat(filePath: string): OutputFormat {\n if (filePath.endsWith(\".mts\")) return \"mts\"\n if (filePath.endsWith(\".mjs\")) return \"mjs\"\n if (filePath.endsWith(\".js\")) return \"js\"\n return \"ts\" // Default to TypeScript\n}\n\n/**\n * Generate the import statement based on format\n */\nfunction generateImport(format: OutputFormat): string {\n // All formats use ESM import syntax\n return `import { defineConfig } from \"@halecraft/verify\"`\n}\n\n/**\n * Generate a task object as a string\n */\nfunction generateTask(task: DetectedTask, indent: string): string {\n const parts = [`key: \"${task.key}\"`, `run: \"${task.command}\"`]\n if (task.parser) {\n parts.push(`parser: \"${task.parser}\"`)\n }\n if (task.reportingDependsOn && task.reportingDependsOn.length > 0) {\n const deps = task.reportingDependsOn.map(d => `\"${d}\"`).join(\", \")\n parts.push(`reportingDependsOn: [${deps}]`)\n }\n return `${indent}{ ${parts.join(\", \")} }`\n}\n\n/**\n * Generate the skeleton config when no tasks are detected\n */\nfunction generateSkeleton(format: OutputFormat): string {\n const importStatement = generateImport(format)\n\n return `${importStatement}\n\nexport default defineConfig({\n env: {\n NO_COLOR: \"1\",\n },\n tasks: [\n // Add your verification tasks here\n // Example:\n // { key: \"format\", run: \"biome check .\" },\n // { key: \"types\", run: \"tsc --noEmit\" },\n // { key: \"test\", run: \"vitest run\" },\n ],\n})\n`\n}\n\n/**\n * Generate config content from selected tasks\n */\nexport function generateConfigContent(\n tasks: DetectedTask[],\n format: OutputFormat,\n): string {\n // If no tasks, generate skeleton\n if (tasks.length === 0) {\n return generateSkeleton(format)\n }\n\n const importStatement = generateImport(format)\n const indent = \" \"\n\n // Group tasks by category for better organization\n const taskLines = tasks.map(task => generateTask(task, indent))\n\n return `${importStatement}\n\nexport default defineConfig({\n env: {\n NO_COLOR: \"1\",\n },\n tasks: [\n${taskLines.join(\",\\n\")},\n ],\n})\n`\n}\n\n/**\n * Get the default config filename\n */\nexport function getDefaultConfigPath(): string {\n return \"verify.config.ts\"\n}\n","import type { DetectedTask } from \"./detect.js\"\n\n/**\n * Options for the prompt flow\n */\nexport interface PromptOptions {\n /** Skip interactive prompts and auto-accept all */\n yes: boolean\n /** Whether we're in a TTY environment */\n isTTY: boolean\n}\n\n/**\n * Result of the prompt flow\n */\nexport interface PromptResult {\n /** Selected tasks */\n tasks: DetectedTask[]\n /** Whether the user cancelled */\n cancelled: boolean\n}\n\n/**\n * Check if we should skip prompts\n */\nexport function shouldSkipPrompts(options: PromptOptions): boolean {\n return options.yes || !options.isTTY\n}\n\n/**\n * Run the interactive task selection prompt\n */\nexport async function promptForTasks(\n detectedTasks: DetectedTask[],\n options: PromptOptions,\n): Promise<PromptResult> {\n // If no tasks detected, return empty (will use skeleton)\n if (detectedTasks.length === 0) {\n if (!shouldSkipPrompts(options)) {\n console.log(\n \"\\n⚠️ No verification scripts detected in package.json.\\n A skeleton config will be created.\\n\",\n )\n }\n return { tasks: [], cancelled: false }\n }\n\n // If skipping prompts, return all detected tasks\n if (shouldSkipPrompts(options)) {\n console.log(`\\n✓ Auto-selecting ${detectedTasks.length} detected task(s)\\n`)\n return { tasks: detectedTasks, cancelled: false }\n }\n\n // Dynamic import of @inquirer/prompts to avoid loading it when not needed\n try {\n const { checkbox } = await import(\"@inquirer/prompts\")\n\n console.log(\"\\n🔍 Detected verification scripts in package.json:\\n\")\n\n const choices = detectedTasks.map(task => ({\n name: `${task.name} (${task.command})`,\n value: task,\n checked: true, // Pre-select all by default\n }))\n\n const selected = await checkbox<DetectedTask>({\n message: \"Select tasks to include in your config:\",\n choices,\n instructions: false,\n })\n\n if (selected.length === 0) {\n console.log(\n \"\\n⚠️ No tasks selected. A skeleton config will be created.\\n\",\n )\n }\n\n return { tasks: selected, cancelled: false }\n } catch (error) {\n // Handle Ctrl+C or other cancellation\n if (\n error instanceof Error &&\n (error.message.includes(\"User force closed\") ||\n error.name === \"ExitPromptError\")\n ) {\n return { tasks: [], cancelled: true }\n }\n throw error\n }\n}\n","import { existsSync, writeFileSync } from \"node:fs\"\nimport { resolve } from \"node:path\"\nimport type { DetectedTask } from \"./detect.js\"\n\n/**\n * Result of checking if a file exists\n */\nexport interface FileCheckResult {\n exists: boolean\n path: string\n}\n\n/**\n * Check if the config file already exists\n */\nexport function checkConfigExists(\n cwd: string,\n configPath: string,\n): FileCheckResult {\n const absolutePath = resolve(cwd, configPath)\n return {\n exists: existsSync(absolutePath),\n path: absolutePath,\n }\n}\n\n/**\n * Write the config file\n */\nexport function writeConfigFile(\n cwd: string,\n configPath: string,\n content: string,\n): void {\n const absolutePath = resolve(cwd, configPath)\n writeFileSync(absolutePath, content, \"utf-8\")\n}\n\n/**\n * Print warning about existing file\n */\nexport function printExistsWarning(path: string): void {\n console.error(`\\n⚠️ Config file already exists: ${path}`)\n console.error(\" Use --force to overwrite.\\n\")\n}\n\n/**\n * Options for success message\n */\nexport interface SuccessOptions {\n /** Path to the created config file */\n configPath: string\n /** Tasks that were configured */\n tasks: DetectedTask[]\n /** Whether optimized commands were used */\n hasOptimizedCommands: boolean\n /** Script names that can potentially be removed */\n removableScripts: string[]\n}\n\n/**\n * Print success message with educational notes\n */\nexport function printSuccess(options: SuccessOptions): void {\n const { configPath, tasks, hasOptimizedCommands, removableScripts } = options\n\n console.log(`\\n✅ Created ${configPath}`)\n console.log(\"\")\n\n // Quick start\n console.log(\" Quick start:\")\n console.log(\" $ verify # Run all verifications\")\n console.log(\" $ verify --top-level # Show only top-level tasks\")\n console.log(\" $ verify format # Run only 'format' task\")\n console.log(\"\")\n\n // Performance note if optimized commands were used\n if (hasOptimizedCommands) {\n console.log(\n \" ⚡ Performance: Using direct tool paths for faster execution\",\n )\n console.log(\n \" (avoids ~250ms overhead per command from package manager)\",\n )\n console.log(\"\")\n }\n\n // Cleanup suggestion if there are removable scripts\n if (removableScripts.length > 0) {\n console.log(\" 💡 Optional cleanup:\")\n console.log(\n \" You can remove these scripts from package.json if you only\",\n )\n console.log(\" run them via 'verify' (keeps package.json cleaner):\")\n for (const script of removableScripts) {\n console.log(` - \"${script}\"`)\n }\n console.log(\"\")\n }\n\n // Parser note if parsers were detected\n const tasksWithParsers = tasks.filter(t => t.parser)\n if (tasksWithParsers.length > 0) {\n console.log(\" 📊 Rich output: Parsers detected for detailed summaries:\")\n for (const task of tasksWithParsers) {\n console.log(` - ${task.key}: ${task.parser}`)\n }\n console.log(\"\")\n }\n\n console.log(\" 📖 Docs: https://github.com/halecraft/verify\")\n console.log(\"\")\n}\n","import { detectTasks } from \"./detect.js\"\nimport {\n generateConfigContent,\n getDefaultConfigPath,\n getOutputFormat,\n} from \"./generate.js\"\nimport { promptForTasks, shouldSkipPrompts } from \"./prompts.js\"\nimport {\n checkConfigExists,\n printExistsWarning,\n printSuccess,\n writeConfigFile,\n} from \"./write.js\"\n\n/**\n * Options for the init command\n */\nexport interface InitOptions {\n /** Custom config output path */\n config?: string\n /** Force overwrite existing file */\n force: boolean\n /** Skip interactive prompts */\n yes: boolean\n /** Working directory */\n cwd: string\n}\n\n/**\n * Result of the init command\n */\nexport interface InitResult {\n /** Whether init succeeded */\n success: boolean\n /** Path to the created config file (if successful) */\n configPath?: string\n /** Error message (if failed) */\n error?: string\n}\n\n/**\n * Run the init command\n */\nexport async function runInit(options: InitOptions): Promise<InitResult> {\n const configPath = options.config ?? getDefaultConfigPath()\n const format = getOutputFormat(configPath)\n\n // Check if file already exists\n const fileCheck = checkConfigExists(options.cwd, configPath)\n if (fileCheck.exists && !options.force) {\n printExistsWarning(fileCheck.path)\n return {\n success: false,\n error: \"Config file already exists. Use --force to overwrite.\",\n }\n }\n\n // Detect tasks from package.json\n const detectedTasks = detectTasks(options.cwd)\n\n // Determine if we should skip prompts\n const isTTY = process.stdout.isTTY ?? false\n const promptOptions = {\n yes: options.yes,\n isTTY,\n }\n\n // If not skipping prompts, show what we're doing\n if (!shouldSkipPrompts(promptOptions)) {\n console.log(\"\\n🚀 Initializing @halecraft/verify config...\\n\")\n }\n\n // Run interactive prompts (or auto-select)\n const promptResult = await promptForTasks(detectedTasks, promptOptions)\n\n if (promptResult.cancelled) {\n console.log(\"\\n❌ Cancelled.\\n\")\n return {\n success: false,\n error: \"User cancelled\",\n }\n }\n\n // Generate config content\n const content = generateConfigContent(promptResult.tasks, format)\n\n // Determine if optimized commands were used\n const hasOptimizedCommands = promptResult.tasks.some(t =>\n t.command.startsWith(\"./node_modules/.bin/\"),\n )\n\n // Determine which scripts could be removed (those that were detected and optimized)\n const removableScripts = promptResult.tasks\n .filter(t => t.command.startsWith(\"./node_modules/.bin/\"))\n .map(t => t.scriptName)\n\n // Write the file\n try {\n writeConfigFile(options.cwd, configPath, content)\n printSuccess({\n configPath,\n tasks: promptResult.tasks,\n hasOptimizedCommands,\n removableScripts,\n })\n return {\n success: true,\n configPath,\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"Failed to write config file\"\n console.error(`\\n❌ Error: ${message}\\n`)\n return {\n success: false,\n error: message,\n }\n }\n}\n\n// Re-export types and utilities\nexport type { DetectedTask } from \"./detect.js\"\nexport { detectTasks } from \"./detect.js\"\nexport type { OutputFormat } from \"./generate.js\"\nexport { generateConfigContent, getOutputFormat } from \"./generate.js\"\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for Biome linter/formatter output\n * Extracts issue counts and file counts from biome check output\n */\nexport const biomeParser: OutputParser = {\n id: \"biome\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Extract file count from \"Checked N files in Xms\"\n const filesMatch = output.match(\n /Checked\\s+(\\d+)\\s+files?\\s+in\\s+[\\d.]+(?:ms|s)/i,\n )\n const fileCount = filesMatch\n ? Number.parseInt(filesMatch[1], 10)\n : undefined\n\n // Check for warnings in output like \"Found 1 warning.\"\n const warningMatch = output.match(/Found\\s+(\\d+)\\s+warning/i)\n const warnings = warningMatch ? Number.parseInt(warningMatch[1], 10) : 0\n\n if (exitCode === 0) {\n const filesPart = fileCount ? `passed ${fileCount} files` : \"passed\"\n const warningSuffix =\n warnings > 0 ? `, ${warnings} warning${warnings === 1 ? \"\" : \"s\"}` : \"\"\n return {\n summary: `${filesPart}${warningSuffix}`,\n metrics: { errors: 0, warnings, total: fileCount },\n }\n }\n\n // Biome outputs something like \"Found 5 errors and 2 warnings\"\n // or individual diagnostics\n const summaryMatch = output.match(\n /Found\\s+(\\d+)\\s+error(?:s)?(?:\\s+and\\s+(\\d+)\\s+warning(?:s)?)?/i,\n )\n\n if (summaryMatch) {\n const errors = Number.parseInt(summaryMatch[1], 10)\n const parsedWarnings = summaryMatch[2]\n ? Number.parseInt(summaryMatch[2], 10)\n : warnings\n\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errors} error${errors === 1 ? \"\" : \"s\"}${parsedWarnings > 0 ? `, ${parsedWarnings} warning${parsedWarnings === 1 ? \"\" : \"s\"}` : \"\"}${fileSuffix}`,\n metrics: { errors, warnings: parsedWarnings, total: fileCount },\n }\n }\n\n // Count individual error markers if no summary found\n // Biome uses \"error\" prefix for diagnostics\n const errorLines = output.match(/^\\s*error\\[/gm)\n const warningLines = output.match(/^\\s*warning\\[/gm)\n\n const errors = errorLines ? errorLines.length : 0\n const countedWarnings = warningLines ? warningLines.length : warnings\n\n if (errors > 0 || countedWarnings > 0) {\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errors} error${errors === 1 ? \"\" : \"s\"}${countedWarnings > 0 ? `, ${countedWarnings} warning${countedWarnings === 1 ? \"\" : \"s\"}` : \"\"}${fileSuffix}`,\n metrics: { errors, warnings: countedWarnings, total: fileCount },\n }\n }\n\n // No errors found but still have file count\n if (fileCount) {\n return {\n summary: `passed ${fileCount} files`,\n metrics: { errors: 0, warnings: 0, total: fileCount },\n }\n }\n\n return null\n },\n}\n","import type { ParsedResult } from \"../types.js\"\n\n/**\n * Generic fallback parser - just reports exit code\n * This parser always returns a result (never null)\n */\nexport const genericParser = {\n id: \"generic\",\n parse(_output: string, exitCode: number): ParsedResult {\n return {\n summary: exitCode === 0 ? \"passed\" : `failed (exit code ${exitCode})`,\n }\n },\n} as const\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for Go test output\n * Counts packages passed/failed from go test output\n */\nexport const gotestParser: OutputParser = {\n id: \"gotest\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Match \"ok\" and \"FAIL\" lines for packages\n // ok github.com/user/pkg 0.123s\n // FAIL github.com/user/pkg 0.456s\n const okMatches = output.match(/^ok\\s+\\S+/gm)\n const failMatches = output.match(/^FAIL\\s+\\S+/gm)\n\n const passed = okMatches ? okMatches.length : 0\n const failed = failMatches ? failMatches.length : 0\n const total = passed + failed\n\n if (total === 0) {\n // Try to detect \"no test files\" case\n if (output.includes(\"no test files\")) {\n return {\n summary: \"no test files\",\n metrics: { passed: 0, failed: 0, total: 0 },\n }\n }\n return null\n }\n\n // Extract total duration if present\n // \"PASS\" or \"FAIL\" at the end with duration\n const durationMatch = output.match(/(?:PASS|FAIL)\\s*$[\\s\\S]*?(\\d+\\.?\\d*s)/m)\n const duration = durationMatch ? durationMatch[1] : undefined\n\n if (exitCode === 0) {\n return {\n summary: `${passed} package${passed === 1 ? \"\" : \"s\"} passed${duration ? ` in ${duration}` : \"\"}`,\n metrics: { passed, failed: 0, total: passed, duration },\n }\n }\n\n return {\n summary: `${failed}/${total} package${total === 1 ? \"\" : \"s\"} failed`,\n metrics: { passed, failed, total, duration },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Parser for TypeScript compiler (tsc/tsgo) output\n * Counts type errors and extracts diagnostics info\n */\nexport const tscParser: OutputParser = {\n id: \"tsc\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Extract file count from diagnostics output: \"Files: 277\"\n const filesMatch = output.match(/^Files:\\s+(\\d+)/m)\n const fileCount = filesMatch\n ? Number.parseInt(filesMatch[1], 10)\n : undefined\n\n if (exitCode === 0) {\n const filesPart = fileCount ? `passed ${fileCount} files` : \"passed\"\n return {\n summary: filesPart,\n metrics: { errors: 0, total: fileCount },\n }\n }\n\n // Count error lines: \"src/file.ts(10,5): error TS2345: ...\"\n const errorMatches = output.match(/error TS\\d+:/g)\n const errorCount = errorMatches ? errorMatches.length : 0\n\n if (errorCount === 0) {\n // No recognizable errors but still failed\n return null\n }\n\n const fileSuffix = fileCount ? ` in ${fileCount} files` : \"\"\n return {\n summary: `${errorCount} type error${errorCount === 1 ? \"\" : \"s\"}${fileSuffix}`,\n metrics: { errors: errorCount, total: fileCount },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\n\n/**\n * Strip ANSI escape codes from string\n */\nfunction stripAnsi(str: string): string {\n // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape codes use control characters\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\")\n}\n\n/**\n * Parser for vitest output\n * Extracts test counts from vitest summary\n */\nexport const vitestParser: OutputParser = {\n id: \"vitest\",\n parse(output: string, exitCode: number): ParsedResult | null {\n // Strip ANSI codes for reliable parsing\n const cleanOutput = stripAnsi(output)\n\n // Match vitest summary line formats:\n // - \"Tests 26 passed (26)\" - all tests passed\n // - \"Tests 1 passed | 150 skipped (151)\" - filtered tests with some passing\n // - \"Tests 151 skipped (151)\" - all tests skipped (no matches)\n // - \"Tests 2 failed | 24 passed (26)\" - some tests failed\n const testsLineMatch = cleanOutput.match(/Tests\\s+(.+?)\\s*\\((\\d+)\\)/m)\n\n // Match: \"Duration 192ms\" or \"Duration 1.72s\"\n const durationMatch = cleanOutput.match(/Duration\\s+([\\d.]+(?:ms|s))\\b/m)\n\n if (!testsLineMatch) {\n return null\n }\n\n const statsStr = testsLineMatch[1]\n const total = Number.parseInt(testsLineMatch[2], 10)\n\n // Parse individual stats from the stats string (e.g., \"1 passed | 150 skipped\" or \"26 passed\")\n const passedMatch = statsStr.match(/(\\d+)\\s+passed/)\n const failedMatch = statsStr.match(/(\\d+)\\s+failed/)\n const skippedMatch = statsStr.match(/(\\d+)\\s+skipped/)\n\n const passed = passedMatch ? Number.parseInt(passedMatch[1], 10) : 0\n const skipped = skippedMatch ? Number.parseInt(skippedMatch[1], 10) : 0\n const duration = durationMatch ? durationMatch[1] : undefined\n\n // Calculate failed: either from explicit \"X failed\" or from total - passed - skipped\n const failed = failedMatch\n ? Number.parseInt(failedMatch[1], 10)\n : total - passed - skipped\n\n // Calculate how many tests actually ran (not skipped)\n const ran = passed + failed\n\n // Build appropriate summary\n let summary: string\n if (ran === 0 && skipped > 0) {\n // All tests were skipped (filter matched nothing)\n summary = `${skipped} tests skipped (no matches)`\n } else if (skipped > 0) {\n // Some tests ran, some skipped (filtered run)\n summary =\n exitCode === 0\n ? `passed ${passed}/${ran} tests (${skipped} skipped)`\n : `passed ${passed}/${ran} tests (${skipped} skipped, some failed)`\n } else {\n // Normal run, no skipped tests\n summary =\n exitCode === 0\n ? `passed ${passed}/${total} tests`\n : `passed ${passed}/${total} tests (some failed)`\n }\n\n return {\n summary,\n metrics: {\n passed,\n total,\n failed,\n skipped,\n duration,\n },\n }\n },\n}\n","import type { OutputParser, ParsedResult } from \"../types.js\"\nimport { biomeParser } from \"./biome.js\"\nimport { genericParser } from \"./generic.js\"\nimport { gotestParser } from \"./gotest.js\"\nimport { tscParser } from \"./tsc.js\"\nimport { vitestParser } from \"./vitest.js\"\n\n/**\n * Parser ID constants for type-safe parser references.\n * Use these instead of magic strings when specifying parsers in config.\n *\n * @example\n * ```typescript\n * import { parsers } from \"@halecraft/verify\"\n *\n * export default defineConfig({\n * tasks: [\n * { key: \"test\", run: \"vitest run\", parser: parsers.vitest },\n * ],\n * })\n * ```\n */\nexport const parsers = {\n /** Vitest/Jest test runner output parser */\n vitest: \"vitest\",\n /** TypeScript compiler (tsc/tsgo) output parser */\n tsc: \"tsc\",\n /** Biome/ESLint linter output parser */\n biome: \"biome\",\n /** Go test runner output parser */\n gotest: \"gotest\",\n /** Generic fallback parser */\n generic: \"generic\",\n} as const\n\n/** Type for valid parser IDs */\nexport type ParserId = (typeof parsers)[keyof typeof parsers]\n\n/**\n * Registry for output parsers\n */\nexport class ParserRegistry {\n private parsers = new Map<string, OutputParser>()\n\n constructor() {\n // Register built-in parsers\n this.register(genericParser)\n this.register(vitestParser)\n this.register(tscParser)\n this.register(biomeParser)\n this.register(gotestParser)\n }\n\n /**\n * Register a custom parser\n */\n register(parser: OutputParser): void {\n this.parsers.set(parser.id, parser)\n }\n\n /**\n * Get a parser by ID\n */\n get(id: string): OutputParser | undefined {\n return this.parsers.get(id)\n }\n\n /**\n * Auto-detect parser based on command\n */\n detectParser(cmd: string): ParserId {\n const cmdLower = cmd.toLowerCase()\n\n if (cmdLower.includes(\"vitest\") || cmdLower.includes(\"jest\")) {\n return parsers.vitest\n }\n if (cmdLower.includes(\"tsc\") || cmdLower.includes(\"tsgo\")) {\n return parsers.tsc\n }\n if (cmdLower.includes(\"biome\") || cmdLower.includes(\"eslint\")) {\n return parsers.biome\n }\n if (\n cmdLower.includes(\"go test\") ||\n (cmdLower.includes(\"go\") && cmdLower.includes(\"test\"))\n ) {\n return parsers.gotest\n }\n\n return parsers.generic\n }\n\n /**\n * Parse output using the specified or auto-detected parser\n */\n parse(\n output: string,\n exitCode: number,\n parserId?: string,\n cmd?: string,\n ): ParsedResult {\n const id = parserId ?? (cmd ? this.detectParser(cmd) : parsers.generic)\n const parser = this.parsers.get(id) ?? genericParser\n\n const result = parser.parse(output, exitCode)\n if (result) {\n return result\n }\n\n // Fallback to generic if parser returns null\n // genericParser.parse always returns a result, never null\n const fallback = genericParser.parse(output, exitCode)\n if (!fallback) {\n throw new Error(\"genericParser unexpectedly returned null\")\n }\n return fallback\n }\n}\n\n// Default registry instance\nexport const defaultRegistry = new ParserRegistry()\n\n// Re-export individual parsers\nexport { biomeParser } from \"./biome.js\"\nexport { genericParser } from \"./generic.js\"\nexport { gotestParser } from \"./gotest.js\"\nexport { tscParser } from \"./tsc.js\"\nexport { vitestParser } from \"./vitest.js\"\n","/**\n * Arc spinner frames for terminal animation\n */\nconst SPINNER_FRAMES = [\"◜\", \"◠\", \"◝\", \"◞\", \"◡\", \"◟\"]\n\n/**\n * Spinner animation interval in milliseconds\n */\nconst SPINNER_INTERVAL = 80\n\n/**\n * Manages spinner animation for terminal output\n */\nexport class SpinnerManager {\n private frames = SPINNER_FRAMES\n private frameIndex = 0\n private interval: ReturnType<typeof setInterval> | null = null\n\n /**\n * Start the spinner animation\n * @param onTick - Callback called on each frame update\n */\n start(onTick: () => void): void {\n if (this.interval) return\n\n this.interval = setInterval(() => {\n this.frameIndex = (this.frameIndex + 1) % this.frames.length\n onTick()\n }, SPINNER_INTERVAL)\n }\n\n /**\n * Stop the spinner animation\n */\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval)\n this.interval = null\n }\n }\n\n /**\n * Get the current spinner frame character\n */\n getFrame(): string {\n return this.frames[this.frameIndex]\n }\n\n /**\n * Check if spinner is currently running\n */\n isRunning(): boolean {\n return this.interval !== null\n }\n}\n","import { SpinnerManager } from \"./spinner.js\"\nimport { walkNodes } from \"./tree.js\"\nimport type {\n TaskResult,\n VerificationNode,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\n/**\n * ANSI color codes\n */\nconst ansi = {\n reset: \"\\u001b[0m\",\n dim: \"\\u001b[2m\",\n red: \"\\u001b[31m\",\n green: \"\\u001b[32m\",\n yellow: \"\\u001b[33m\",\n cyan: \"\\u001b[36m\",\n bold: \"\\u001b[1m\",\n}\n\n/**\n * ANSI cursor control codes\n */\nconst cursor = {\n hide: \"\\u001b[?25l\",\n show: \"\\u001b[?25h\",\n moveUp: (n: number) => `\\u001b[${n}A`,\n moveToStart: \"\\u001b[0G\",\n clearLine: \"\\u001b[2K\",\n}\n\n/**\n * Reporter interface\n */\nexport interface Reporter {\n /** Called before any tasks start - initialize display */\n onStart?(tasks: VerificationNode[]): void\n /** Called when a task starts */\n onTaskStart(path: string, key: string): void\n /** Called when a task completes */\n onTaskComplete(result: TaskResult): void\n /** Called when all tasks complete - cleanup display */\n onFinish?(): void\n /** Called to output task logs */\n outputLogs(results: TaskResult[], logsMode: \"all\" | \"failed\" | \"none\"): void\n /** Called to output final summary */\n outputSummary(result: VerifyResult): void\n}\n\n/**\n * Terminal capability context — the single point where globals are read.\n * Passed to pure decision functions for testability.\n */\nexport interface TerminalContext {\n isTTY: boolean\n env: Record<string, string | undefined>\n}\n\n/**\n * Read terminal capabilities from the current process.\n * This is the only function that touches process globals for terminal decisions.\n */\nexport function defaultTerminalContext(): TerminalContext {\n return { isTTY: !!process.stdout.isTTY, env: process.env }\n}\n\n/**\n * Check if colors should be enabled (pure function).\n */\nexport function shouldUseColors(\n options: VerifyOptions,\n ctx: TerminalContext,\n): boolean {\n if (options.noColor) return false\n if (options.format === \"json\") return false\n if (!ctx.isTTY) return false\n if (\"NO_COLOR\" in ctx.env) return false\n if (ctx.env.TERM === \"dumb\") return false\n return true\n}\n\n/**\n * Check if the live dashboard (animated) reporter is appropriate (pure function).\n * Returns false when running inside a wrapper TUI (e.g. turborepo) that\n * allocates a PTY but cannot interpret cursor-manipulation sequences.\n *\n * Detection strategy for turborepo:\n * - TURBO_IS_TUI=true: explicit signal (turbo v2.9+)\n * - TURBO_HASH + isTTY: fallback for older turbo versions (v2.8.x).\n * In stream mode turbo uses pipes (isTTY=false), so TURBO_HASH + isTTY\n * reliably indicates TUI mode even without TURBO_IS_TUI.\n */\nexport function shouldUseLiveDashboard(\n options: VerifyOptions,\n ctx: TerminalContext,\n): boolean {\n if (options.noTty) return false\n if (ctx.env.TURBO_IS_TUI === \"true\") return false\n if (ctx.isTTY && ctx.env.TURBO_HASH != null) return false\n if (!ctx.isTTY) return false\n return true\n}\n\n/**\n * Base Reporter - common functionality for all reporters\n */\nexport abstract class BaseReporter implements Reporter {\n protected colorEnabled: boolean\n protected stream: NodeJS.WriteStream\n protected taskDepths: Map<string, number> = new Map()\n\n constructor(options: VerifyOptions = {}, ctx?: TerminalContext) {\n const termCtx = ctx ?? defaultTerminalContext()\n this.colorEnabled = shouldUseColors(options, termCtx)\n this.stream = options.format === \"json\" ? process.stderr : process.stdout\n }\n\n /**\n * Apply ANSI color code to string (if colors enabled)\n */\n protected c(code: string, s: string): string {\n return this.colorEnabled ? `${code}${s}${ansi.reset}` : s\n }\n\n /**\n * Get success mark (✓ or OK)\n */\n protected okMark(): string {\n return this.colorEnabled ? this.c(ansi.green, \"✓\") : \"OK\"\n }\n\n /**\n * Get failure mark (✗ or FAIL)\n */\n protected failMark(): string {\n return this.colorEnabled ? this.c(ansi.red, \"✗\") : \"FAIL\"\n }\n\n /**\n * Get blocked mark (⊘ or BLOCK)\n */\n protected blockedMark(): string {\n return this.colorEnabled ? this.c(ansi.yellow, \"⊘\") : \"BLOCK\"\n }\n\n /**\n * Get arrow symbol (→ or ->)\n */\n protected arrow(): string {\n return this.colorEnabled ? this.c(ansi.cyan, \"→\") : \"->\"\n }\n\n /**\n * Get indentation string for a given depth\n */\n protected getIndent(depth: number): string {\n return \" \".repeat(depth)\n }\n\n /**\n * Get task depth from path\n */\n protected getTaskDepth(path: string): number {\n return this.taskDepths.get(path) ?? 0\n }\n\n /**\n * Collect task depths from verification tree using walkNodes\n */\n protected collectTaskDepths(nodes: VerificationNode[]): void {\n walkNodes(nodes, (_node, path, depth) => {\n this.taskDepths.set(path, depth)\n })\n }\n\n /**\n * Format a completed task result line in name-first format.\n * Shared by LiveDashboardReporter and SequentialReporter.\n */\n protected formatResultLine(name: string, result: TaskResult): string {\n const duration = this.c(ansi.dim, `${result.durationMs}ms`)\n\n if (result.blocked) {\n const reason = result.blockedBy\n ? `by ${result.blockedBy}`\n : \"by dependency\"\n return `${this.blockedMark()} ${this.c(ansi.bold, name)} blocked ${this.c(ansi.dim, `(${reason}, ${duration})`)}`\n }\n\n const summary = this.extractSummary(result)\n\n if (result.ok) {\n return `${this.okMark()} ${this.c(ansi.bold, name)} verified ${this.c(ansi.dim, `(${summary}, ${duration})`)}`\n }\n return `${this.failMark()} ${this.c(ansi.bold, name)} failed ${this.c(ansi.dim, `(${summary}, ${duration})`)}`\n }\n\n /**\n * Extract summary from task result\n */\n protected extractSummary(result: TaskResult): string {\n // Use the parsed summary from summaryLine (strip the \"key: \" prefix if present)\n // The parsers already format summaries nicely with file counts, test counts, etc.\n if (result.summaryLine) {\n const colonIndex = result.summaryLine.indexOf(\": \")\n if (colonIndex !== -1) {\n return result.summaryLine.slice(colonIndex + 2)\n }\n return result.summaryLine\n }\n\n return result.ok ? \"passed\" : \"failed\"\n }\n\n /**\n * Flatten nested task results into a single array\n */\n protected flattenResults(results: TaskResult[]): TaskResult[] {\n const flat: TaskResult[] = []\n for (const r of results) {\n flat.push(r)\n if (r.children) {\n flat.push(...this.flattenResults(r.children))\n }\n }\n return flat\n }\n\n /**\n * Output task logs\n */\n outputLogs(results: TaskResult[], logsMode: \"all\" | \"failed\" | \"none\"): void {\n if (logsMode === \"none\") return\n\n const flatResults = this.flattenResults(results)\n\n for (const r of flatResults) {\n if (r.children) continue\n if (logsMode === \"failed\" && r.ok) continue\n // Skip blocked tasks - their output is hidden to reduce noise\n if (r.blocked) continue\n\n const status = r.ok ? this.c(ansi.green, \"OK\") : this.c(ansi.red, \"FAIL\")\n\n this.stream.write(\n `\\n${this.c(ansi.bold, \"====\")} ${this.c(ansi.bold, r.path.toUpperCase())} ${status} ${this.c(ansi.bold, \"====\")}\\n`,\n )\n this.stream.write(r.output || \"(no output)\\n\")\n }\n }\n\n /**\n * Output final summary\n */\n outputSummary(result: VerifyResult): void {\n const finalMessage = result.ok\n ? this.c(ansi.green, \"\\n== verification: All correct ==\")\n : this.c(ansi.red, \"\\n== verification: Failed ==\")\n this.stream.write(`${finalMessage}\\n`)\n }\n\n // Abstract methods that subclasses must implement\n abstract onStart(tasks: VerificationNode[]): void\n abstract onTaskStart(path: string, key: string): void\n abstract onTaskComplete(result: TaskResult): void\n abstract onFinish(): void\n}\n\n/**\n * Task state for live dashboard\n */\ninterface TaskState {\n key: string\n path: string\n depth: number\n status: \"pending\" | \"running\" | \"completed\"\n result?: TaskResult\n}\n\n/**\n * Live Dashboard Reporter - animated in-place updates for TTY\n */\nexport class LiveDashboardReporter extends BaseReporter {\n private topLevelOnly: boolean\n private tasks: Map<string, TaskState> = new Map()\n private taskOrder: string[] = []\n private spinner: SpinnerManager\n private lineCount = 0\n\n constructor(options: VerifyOptions = {}, ctx?: TerminalContext) {\n super(options, ctx)\n this.topLevelOnly = options.topLevelOnly ?? false\n this.spinner = new SpinnerManager()\n\n // Handle Ctrl+C to restore cursor\n const cleanup = () => {\n this.spinner.stop()\n this.stream.write(cursor.show)\n process.exit(130)\n }\n process.on(\"SIGINT\", cleanup)\n process.on(\"SIGTERM\", cleanup)\n }\n\n /**\n * Initialize task list from verification nodes\n */\n onStart(tasks: VerificationNode[]): void {\n this.collectTasks(tasks)\n this.stream.write(cursor.hide)\n this.spinner.start(() => this.redraw())\n }\n\n /**\n * Collect tasks from verification tree using walkNodes\n */\n private collectTasks(nodes: VerificationNode[]): void {\n walkNodes(nodes, (node, path, depth) => {\n this.tasks.set(path, {\n key: node.key,\n path,\n depth,\n status: \"pending\",\n })\n this.taskOrder.push(path)\n // Also store in base class for consistency\n this.taskDepths.set(path, depth)\n })\n }\n\n /**\n * Get display key - shows :key for nested, key for root\n */\n private getDisplayKey(task: TaskState): string {\n if (task.depth === 0) {\n return task.key\n }\n return `:${task.key}`\n }\n\n /**\n * Check if task should be displayed based on topLevelOnly flag\n */\n private shouldDisplay(task: TaskState): boolean {\n if (this.topLevelOnly) return task.depth === 0\n return true\n }\n\n /**\n * Format a single task line\n */\n private formatLine(task: TaskState): string {\n const indent = this.getIndent(task.depth)\n const displayKey = this.getDisplayKey(task)\n\n if (task.status === \"running\") {\n const spinnerChar = this.c(ansi.dim, `(${this.spinner.getFrame()})`)\n return `${indent}${this.arrow()} verifying ${this.c(ansi.bold, displayKey)} ${spinnerChar}`\n }\n\n if (task.status === \"completed\" && task.result) {\n return `${indent}${this.formatResultLine(displayKey, task.result)}`\n }\n\n // Pending - don't show\n return \"\"\n }\n\n /**\n * Redraw all visible task lines\n */\n private redraw(): void {\n // Move cursor up to overwrite previous lines\n if (this.lineCount > 0) {\n this.stream.write(cursor.moveUp(this.lineCount))\n }\n\n // Build new output\n const lines: string[] = []\n for (const path of this.taskOrder) {\n const task = this.tasks.get(path)\n if (!task) continue\n if (!this.shouldDisplay(task)) continue\n if (task.status === \"pending\") continue\n\n const line = this.formatLine(task)\n if (line) {\n lines.push(line)\n }\n }\n\n // Write lines with clear\n for (const line of lines) {\n this.stream.write(`${cursor.clearLine}${cursor.moveToStart}${line}\\n`)\n }\n\n this.lineCount = lines.length\n }\n\n onTaskStart(path: string, _key: string): void {\n const task = this.tasks.get(path)\n if (task) {\n task.status = \"running\"\n }\n // Redraw happens on spinner tick\n }\n\n onTaskComplete(result: TaskResult): void {\n const task = this.tasks.get(result.path)\n if (task) {\n task.status = \"completed\"\n task.result = result\n }\n // Redraw happens on spinner tick, but do one now for immediate feedback\n this.redraw()\n }\n\n onFinish(): void {\n this.spinner.stop()\n this.redraw() // Final redraw\n this.stream.write(cursor.show)\n }\n}\n\n/**\n * Sequential Reporter - line-by-line output for non-TTY\n * No indentation since parallel execution means output order doesn't reflect hierarchy\n */\nexport class SequentialReporter extends BaseReporter {\n private topLevelOnly: boolean\n\n constructor(options: VerifyOptions = {}, ctx?: TerminalContext) {\n super(options, ctx)\n this.topLevelOnly = options.topLevelOnly ?? false\n }\n\n onStart(tasks: VerificationNode[]): void {\n // Collect task depths from the config tree\n this.collectTaskDepths(tasks)\n }\n\n /**\n * Check if task should be displayed based on topLevelOnly flag\n */\n private shouldDisplay(path: string): boolean {\n if (this.topLevelOnly) return this.getTaskDepth(path) === 0\n return true\n }\n\n onTaskStart(path: string, _key: string): void {\n if (!this.shouldDisplay(path)) return\n this.stream.write(`${this.arrow()} verifying ${this.c(ansi.bold, path)}\\n`)\n }\n\n onTaskComplete(result: TaskResult): void {\n if (!this.shouldDisplay(result.path)) return\n this.stream.write(`${this.formatResultLine(result.path, result)}\\n`)\n }\n\n onFinish(): void {\n // No cleanup needed for sequential output\n }\n}\n\n/**\n * JSON Reporter - machine-readable output\n */\nexport class JSONReporter implements Reporter {\n onStart(_tasks: VerificationNode[]): void {\n // No output during execution in JSON mode\n }\n\n onTaskStart(_path: string, _key: string): void {\n // No output during execution in JSON mode\n }\n\n onTaskComplete(_result: TaskResult): void {\n // No output during execution in JSON mode\n }\n\n onFinish(): void {\n // No cleanup needed for JSON output\n }\n\n outputLogs(\n _results: TaskResult[],\n _logsMode: \"all\" | \"failed\" | \"none\",\n ): void {\n // Logs are included in the JSON output\n }\n\n outputSummary(result: VerifyResult): void {\n const summary = {\n ok: result.ok,\n startedAt: result.startedAt,\n finishedAt: result.finishedAt,\n durationMs: result.durationMs,\n tasks: this.serializeTasks(result.tasks),\n }\n\n process.stdout.write(`${JSON.stringify(summary)}\\n`)\n }\n\n private serializeTasks(tasks: TaskResult[]): Array<{\n key: string\n path: string\n ok: boolean\n code: number\n durationMs: number\n summaryLine: string\n blocked?: boolean\n blockedBy?: string\n children?: ReturnType<JSONReporter[\"serializeTasks\"]>\n }> {\n return tasks.map(t => ({\n key: t.key,\n path: t.path,\n ok: t.ok,\n code: t.code,\n durationMs: t.durationMs,\n summaryLine: t.summaryLine,\n ...(t.blocked ? { blocked: t.blocked } : {}),\n ...(t.blockedBy ? { blockedBy: t.blockedBy } : {}),\n ...(t.children ? { children: this.serializeTasks(t.children) } : {}),\n }))\n }\n}\n\n/**\n * Quiet Reporter - minimal output (summary only)\n */\nexport class QuietReporter extends BaseReporter {\n onStart(_tasks: VerificationNode[]): void {\n // No output\n }\n\n onTaskStart(_path: string, _key: string): void {\n // No output\n }\n\n onTaskComplete(_result: TaskResult): void {\n // No output\n }\n\n onFinish(): void {\n // No cleanup needed\n }\n\n outputLogs(\n _results: TaskResult[],\n _logsMode: \"all\" | \"failed\" | \"none\",\n ): void {\n // No logs in quiet mode\n }\n\n outputSummary(result: VerifyResult): void {\n const message = result.ok\n ? this.c(ansi.green, \"✓ All verifications passed\")\n : this.c(ansi.red, \"✗ Some verifications failed\")\n process.stdout.write(`${message}\\n`)\n }\n}\n\n/**\n * Create appropriate reporter based on options.\n *\n * Decision tree: JSON → Quiet → LiveDashboard → Sequential\n */\nexport function createReporter(options: VerifyOptions): Reporter {\n const ctx = defaultTerminalContext()\n\n if (options.format === \"json\") {\n return new JSONReporter()\n }\n\n if (options.quiet) {\n return new QuietReporter(options, ctx)\n }\n\n if (shouldUseLiveDashboard(options, ctx)) {\n return new LiveDashboardReporter(options, ctx)\n }\n\n return new SequentialReporter(options, ctx)\n}\n\n// Keep TTYReporter as alias for backwards compatibility\nexport { SequentialReporter as TTYReporter }\n","import { spawn } from \"node:child_process\"\nimport { dirname, join, resolve } from \"node:path\"\nimport treeKill from \"tree-kill\"\nimport { ReportingDependencyTracker } from \"./dependency-tracker.js\"\nimport { defaultRegistry, type ParserRegistry } from \"./parsers/index.js\"\nimport { buildTaskPath } from \"./tree.js\"\nimport type {\n ParsedResult,\n TaskResult,\n VerificationCommand,\n VerificationNode,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\n// Re-export for backwards compatibility\nexport { ReportingDependencyTracker } from \"./dependency-tracker.js\"\n\n/**\n * Internal command representation that supports shell strings\n */\ninterface InternalCommand {\n /** The command/binary to run (or full shell command if shell is true) */\n cmd: string\n /** Arguments to pass to the command (empty if shell is true) */\n args: string[]\n /** Working directory (defaults to cwd) */\n cwd?: string\n /** Environment variables to set (null values will unset from process.env) */\n env?: Record<string, string | null>\n /** Whether to run through shell (true for string commands) */\n shell: boolean\n /** Timeout in milliseconds */\n timeout?: number\n}\n\n/**\n * Merge environment variables, handling null values as \"unset\".\n * Preserves null values in the result so they can unset process.env vars later.\n */\nexport function mergeEnv(\n base: Record<string, string | null>,\n overlay?: Record<string, string | null>,\n): Record<string, string | null> {\n if (!overlay) return { ...base }\n\n const result = { ...base }\n for (const [key, value] of Object.entries(overlay)) {\n if (value === null) {\n result[key] = null // Mark for unsetting (will be applied in executeCommand)\n } else {\n result[key] = value\n }\n }\n return result\n}\n\n/**\n * Apply environment overlay to process.env, handling null values as \"unset\".\n * Returns a clean Record<string, string> suitable for spawn().\n */\nfunction buildFinalEnv(\n processEnv: NodeJS.ProcessEnv,\n path: string,\n overlay?: Record<string, string | null>,\n): Record<string, string> {\n // Start with process.env (filter out undefined values)\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(processEnv)) {\n if (value !== undefined) {\n result[key] = value\n }\n }\n\n // Set PATH\n result.PATH = path\n\n // Apply overlay, handling nulls as unset\n if (overlay) {\n for (const [key, value] of Object.entries(overlay)) {\n if (value === null) {\n delete result[key] // Unset from process.env\n } else {\n result[key] = value\n }\n }\n }\n\n return result\n}\n\n/**\n * Escape a shell argument if it contains spaces or special characters\n */\nfunction shellEscape(arg: string): string {\n // If arg contains spaces, quotes, or shell metacharacters, wrap in quotes\n if (/[\\s\"'`$\\\\!&|;<>(){}[\\]*?#~]/.test(arg)) {\n // Escape any existing double quotes and wrap in double quotes\n return `\"${arg.replace(/\"/g, '\\\\\"')}\"`\n }\n return arg\n}\n\n/**\n * Build PATH with node_modules/.bin directories prepended.\n * Walks up from cwd to find all node_modules/.bin directories,\n * mimicking npm/pnpm/yarn script behavior.\n */\nexport function buildNodeModulesPath(cwd: string): string {\n const pathSeparator = process.platform === \"win32\" ? \";\" : \":\"\n const existingPath = process.env.PATH ?? \"\"\n const binPaths: string[] = []\n\n let current = resolve(cwd)\n\n while (true) {\n binPaths.push(join(current, \"node_modules\", \".bin\"))\n const parent = dirname(current)\n if (parent === current) break // Reached filesystem root\n current = parent\n }\n\n return [...binPaths, existingPath].join(pathSeparator)\n}\n\n/**\n * Normalize command to internal format\n * String commands use shell: true to properly handle quotes and special characters\n */\nexport function normalizeCommand(\n run: VerificationCommand | string,\n nodeTimeout?: number,\n passthrough?: string[],\n inheritedEnv?: Record<string, string | null>,\n): InternalCommand {\n if (typeof run === \"string\") {\n // Append passthrough args to the shell command string\n let cmd = run\n if (passthrough && passthrough.length > 0) {\n const escapedArgs = passthrough.map(shellEscape).join(\" \")\n cmd = `${run} ${escapedArgs}`\n }\n\n // Use shell to handle the command string - this properly handles quotes,\n // environment variables, pipes, and other shell features\n return {\n cmd,\n args: [],\n shell: true,\n timeout: nodeTimeout,\n env: inheritedEnv,\n }\n }\n\n // For object commands, append passthrough to args array\n const args = passthrough ? [...run.args, ...passthrough] : run.args\n\n // Merge inherited env with command-level env (command takes precedence)\n const env = mergeEnv(inheritedEnv ?? {}, run.env)\n\n return {\n cmd: run.cmd,\n args,\n cwd: run.cwd,\n env: Object.keys(env).length > 0 ? env : undefined,\n shell: false,\n // Command-level timeout takes precedence over node-level timeout\n timeout: run.timeout ?? nodeTimeout,\n }\n}\n\n/**\n * Execute a single command and capture output.\n * Optionally registers the process with a tracker for early termination support.\n */\nasync function executeCommand(\n command: InternalCommand,\n cwd: string,\n tracker?: ReportingDependencyTracker,\n path?: string,\n): Promise<{\n code: number\n output: string\n durationMs: number\n killed: boolean\n timedOut: boolean\n}> {\n const start = Date.now()\n\n return new Promise(resolve => {\n // Use shell: true for string commands (to handle quotes, pipes, etc.)\n // or on Windows for all commands\n const useShell = command.shell || process.platform === \"win32\"\n\n const effectiveCwd = command.cwd ?? cwd\n const finalEnv = buildFinalEnv(\n process.env,\n buildNodeModulesPath(effectiveCwd),\n command.env,\n )\n const proc = spawn(command.cmd, command.args, {\n shell: useShell,\n cwd: effectiveCwd,\n env: finalEnv,\n })\n\n // Register process for early termination\n if (tracker && path) {\n tracker.registerProcess(path, proc)\n }\n\n let output = \"\"\n let timedOut = false\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n\n // Set up timeout if configured\n if (command.timeout && proc.pid) {\n const pid = proc.pid // Capture pid to avoid non-null assertion in callback\n timeoutId = setTimeout(() => {\n timedOut = true\n // Use tree-kill to kill the process and all its children\n treeKill(pid, \"SIGTERM\", err => {\n if (err) {\n // Process may have already exited, ignore errors\n }\n })\n }, command.timeout)\n }\n\n proc.stdout.on(\"data\", (data: Buffer) => {\n output += data.toString()\n })\n\n proc.stderr.on(\"data\", (data: Buffer) => {\n output += data.toString()\n })\n\n proc.on(\"close\", (code, signal) => {\n // Clear timeout if set\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n\n // Unregister process\n if (tracker && path) {\n tracker.unregisterProcess(path)\n }\n\n const durationMs = Date.now() - start\n // Check if process was killed (SIGTERM = 15, exit code 143 = 128 + 15)\n const killed =\n signal === \"SIGTERM\" ||\n code === 143 ||\n (tracker?.wasKilled(path ?? \"\") ?? false)\n\n resolve({\n code: code ?? 1,\n output,\n durationMs,\n killed: killed && !timedOut, // Don't mark as killed if it was a timeout\n timedOut,\n })\n })\n\n proc.on(\"error\", err => {\n // Clear timeout if set\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n\n // Unregister process\n if (tracker && path) {\n tracker.unregisterProcess(path)\n }\n\n const durationMs = Date.now() - start\n resolve({\n code: 1,\n output: `Failed to execute command: ${err.message}`,\n durationMs,\n killed: false,\n timedOut: false,\n })\n })\n })\n}\n\n/**\n * Check if a path matches the filter\n */\nfunction matchesFilter(path: string, filters?: string[]): boolean {\n if (!filters || filters.length === 0) {\n return true\n }\n\n return filters.some(filter => {\n // Exact match or prefix match\n return path === filter || path.startsWith(`${filter}:`)\n })\n}\n\n/**\n * Check if any descendant matches the filter\n */\nfunction hasMatchingDescendant(\n node: VerificationNode,\n parentPath: string,\n filters?: string[],\n): boolean {\n const path = buildTaskPath(parentPath, node.key)\n\n if (matchesFilter(path, filters)) {\n return true\n }\n\n if (node.children) {\n return node.children.some(child =>\n hasMatchingDescendant(child, path, filters),\n )\n }\n\n return false\n}\n\nexport interface RunnerCallbacks {\n onTaskStart?: (path: string, key: string) => void\n onTaskComplete?: (result: TaskResult) => void\n}\n\n/**\n * Verification runner\n */\nexport class VerificationRunner {\n private registry: ParserRegistry\n private options: VerifyOptions\n private callbacks: RunnerCallbacks\n private dependencyTracker: ReportingDependencyTracker\n private configEnv: Record<string, string | null>\n\n constructor(\n options: VerifyOptions = {},\n registry: ParserRegistry = defaultRegistry,\n callbacks: RunnerCallbacks = {},\n configEnv: Record<string, string | null> = {},\n ) {\n this.options = options\n this.registry = registry\n this.callbacks = callbacks\n this.dependencyTracker = new ReportingDependencyTracker()\n this.configEnv = configEnv\n }\n\n /**\n * Run all verification tasks\n */\n async run(tasks: VerificationNode[]): Promise<VerifyResult> {\n const startedAt = new Date().toISOString()\n const wallStart = Date.now()\n\n // Initialize dependency tracker with all tasks (validates cycles)\n this.dependencyTracker.initialize(tasks)\n\n // Start with config-level env merged into an empty base\n const baseEnv = mergeEnv({}, this.configEnv)\n const results = await this.runNodes(tasks, \"\", \"parallel\", baseEnv)\n\n const finishedAt = new Date().toISOString()\n const durationMs = Date.now() - wallStart\n\n const allOk = results.every(r => r.ok)\n\n return {\n ok: allOk,\n startedAt,\n finishedAt,\n durationMs,\n tasks: results,\n }\n }\n\n /**\n * Run a list of nodes with the appropriate strategy\n */\n private async runNodes(\n nodes: VerificationNode[],\n parentPath: string,\n strategy: \"parallel\" | \"sequential\" | \"fail-fast\" = \"parallel\",\n inheritedEnv: Record<string, string | null> = {},\n ): Promise<TaskResult[]> {\n // Filter nodes based on filter option\n const filteredNodes = nodes.filter(node =>\n hasMatchingDescendant(node, parentPath, this.options.filter),\n )\n\n if (filteredNodes.length === 0) {\n return []\n }\n\n switch (strategy) {\n case \"parallel\":\n return Promise.all(\n filteredNodes.map(node =>\n this.runNode(node, parentPath, inheritedEnv),\n ),\n )\n\n case \"sequential\": {\n const results: TaskResult[] = []\n for (const node of filteredNodes) {\n results.push(await this.runNode(node, parentPath, inheritedEnv))\n }\n return results\n }\n\n case \"fail-fast\": {\n const results: TaskResult[] = []\n for (const node of filteredNodes) {\n const result = await this.runNode(node, parentPath, inheritedEnv)\n results.push(result)\n if (!result.ok) {\n break\n }\n }\n return results\n }\n }\n }\n\n /**\n * Run a single node (leaf or group)\n */\n private async runNode(\n node: VerificationNode,\n parentPath: string,\n inheritedEnv: Record<string, string | null> = {},\n ): Promise<TaskResult> {\n const path = buildTaskPath(parentPath, node.key)\n\n // Merge inherited env with node env (node takes precedence)\n const nodeEnv = mergeEnv(inheritedEnv, node.env)\n\n // Mark this task as active (will run) so dependencies know about it\n this.dependencyTracker.markActive(path)\n\n // Notify start\n this.callbacks.onTaskStart?.(path, node.key)\n\n // If this is a group node (has children), run children\n if (node.children && node.children.length > 0) {\n const start = Date.now()\n const childResults = await this.runNodes(\n node.children,\n path,\n node.strategy ?? \"parallel\",\n nodeEnv,\n )\n const durationMs = Date.now() - start\n\n const allOk = childResults.every(r => r.ok || r.blocked)\n\n // Propagate blocked status from children to parent\n const allBlocked =\n childResults.length > 0 && childResults.every(r => r.blocked)\n const anyBlocked = childResults.some(r => r.blocked)\n\n const result: TaskResult = {\n key: node.key,\n path,\n ok: allOk,\n code: allOk ? 0 : 1,\n durationMs,\n output: \"\",\n summaryLine: allOk\n ? (node.successLabel ?? `${node.key}: all passed`)\n : (node.failureLabel ?? `${node.key}: some failed`),\n children: childResults,\n }\n\n // If all children are blocked, parent is also blocked\n if (allBlocked) {\n result.blocked = true\n result.blockedBy = childResults[0].blockedBy\n } else if (anyBlocked && !allOk) {\n // Mixed: some blocked, some failed - don't block parent\n // The parent shows as failed with the actual failures visible\n }\n\n // Record result in tracker before emitting\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Leaf node - execute command\n if (!node.run) {\n const result: TaskResult = {\n key: node.key,\n path,\n ok: true,\n code: 0,\n durationMs: 0,\n output: \"\",\n summaryLine: `${node.key}: no command specified`,\n }\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Pass through args only if this is the filtered task (single task filter required)\n const passthrough = this.options.passthrough\n const command = normalizeCommand(\n node.run,\n node.timeout,\n passthrough,\n nodeEnv,\n )\n const cwd = this.options.cwd ?? process.cwd()\n\n // Pass tracker and path for early termination support\n const { code, output, durationMs, killed, timedOut } = await executeCommand(\n command,\n cwd,\n this.dependencyTracker,\n path,\n )\n\n const ok = code === 0\n\n // If process timed out, mark as failed with timeout info\n if (timedOut) {\n const result: TaskResult = {\n key: node.key,\n path,\n ok: false,\n code,\n durationMs,\n output,\n summaryLine: `${node.key}: timed out after ${command.timeout}ms`,\n timedOut: true,\n }\n\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // If process was killed (by dependency failure), mark as blocked\n if (killed) {\n // Wait for dependencies to get the failed dependency path\n await this.dependencyTracker.waitForDependencies(path)\n const failedDep = this.dependencyTracker.getFailedDependency(path)\n\n const result: TaskResult = {\n key: node.key,\n path,\n ok: false,\n code,\n durationMs,\n output,\n summaryLine: `${node.key}: terminated`,\n blocked: true,\n blockedBy: failedDep ?? \"unknown\",\n }\n\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n\n // Parse output - for shell commands, cmd is the full command string\n const cmdString = command.shell\n ? command.cmd\n : `${command.cmd} ${command.args.join(\" \")}`\n const parsed: ParsedResult = this.registry.parse(\n output,\n code,\n node.parser,\n cmdString,\n )\n\n // Build summary line\n let summaryLine: string\n if (ok) {\n summaryLine = node.successLabel\n ? `${node.key}: ${node.successLabel}`\n : `${node.key}: ${parsed.summary}`\n } else {\n summaryLine = node.failureLabel\n ? `${node.key}: ${node.failureLabel}`\n : `${node.key}: ${parsed.summary}`\n }\n\n let result: TaskResult = {\n key: node.key,\n path,\n ok,\n code,\n durationMs,\n output,\n summaryLine,\n metrics: parsed.metrics,\n }\n\n // If this task has reporting dependencies, wait for them and check for suppression\n if (this.dependencyTracker.hasDependencies(path)) {\n await this.dependencyTracker.waitForDependencies(path)\n\n // Check if any dependency failed - if so, block this task's failure\n if (!ok) {\n const failedDep = this.dependencyTracker.getFailedDependency(path)\n if (failedDep) {\n result = {\n ...result,\n blocked: true,\n blockedBy: failedDep,\n }\n }\n }\n }\n\n // Record result in tracker before emitting\n this.dependencyTracker.recordResult(result)\n this.callbacks.onTaskComplete?.(result)\n return result\n }\n}\n","import type { ChildProcess } from \"node:child_process\"\nimport treeKill from \"tree-kill\"\nimport { walkNodes } from \"./tree.js\"\nimport type { TaskResult, VerificationNode } from \"./types.js\"\n\n/**\n * Tracks reporting dependencies between tasks and coordinates result emission.\n * Allows tasks to wait for their dependencies to complete before emitting results,\n * and determines if a task's failure should be marked as blocked.\n * Also handles early termination by killing dependent processes when a dependency fails.\n */\nexport class ReportingDependencyTracker {\n /** Map of task path/key to their results */\n private results: Map<string, TaskResult> = new Map()\n\n /** Map of task path/key to waiters (callbacks to resolve when result is available) */\n private waiters: Map<string, Array<() => void>> = new Map()\n\n /** Map of task path to its key (for key-based lookups) */\n private pathToKey: Map<string, string> = new Map()\n\n /** Map of task key to its path (for key-based lookups) */\n private keyToPath: Map<string, string> = new Map()\n\n /** Map of task path to its reportingDependsOn array */\n private dependencies: Map<string, string[]> = new Map()\n\n /** Reverse map: task path → list of tasks that depend on it */\n private reverseDeps: Map<string, string[]> = new Map()\n\n /** Map of task path to its running ChildProcess */\n private processes: Map<string, ChildProcess> = new Map()\n\n /** Set of task paths that have been killed */\n private killedPaths: Set<string> = new Set()\n\n /** Set of task paths that will actually run (based on filter) */\n private activePaths: Set<string> = new Set()\n\n /**\n * Initialize the tracker with all tasks from the verification tree.\n * Also validates for circular dependencies and builds reverse dependency map.\n */\n initialize(nodes: VerificationNode[]): void {\n walkNodes(nodes, (node, path) => {\n this.pathToKey.set(path, node.key)\n this.keyToPath.set(node.key, path)\n\n if (node.reportingDependsOn && node.reportingDependsOn.length > 0) {\n this.dependencies.set(path, node.reportingDependsOn)\n }\n })\n\n this.validateNoCycles()\n this.buildReverseDeps()\n }\n\n /**\n * Build reverse dependency map (task → tasks that depend on it)\n */\n private buildReverseDeps(): void {\n for (const [path, deps] of this.dependencies.entries()) {\n for (const dep of deps) {\n const resolvedDep = this.resolveDependency(dep)\n if (resolvedDep) {\n const existing = this.reverseDeps.get(resolvedDep) ?? []\n existing.push(path)\n this.reverseDeps.set(resolvedDep, existing)\n }\n }\n }\n }\n\n /**\n * Validate that there are no circular dependencies using DFS with coloring.\n * Throws an error with the cycle path if a cycle is detected.\n */\n private validateNoCycles(): void {\n const WHITE = 0 // Not visited\n const GRAY = 1 // Currently visiting (in stack)\n const BLACK = 2 // Fully visited\n\n const colors = new Map<string, number>()\n const parent = new Map<string, string>()\n\n // Initialize all nodes as white\n for (const path of this.pathToKey.keys()) {\n colors.set(path, WHITE)\n }\n\n const dfs = (path: string): string | null => {\n colors.set(path, GRAY)\n\n const deps = this.dependencies.get(path) ?? []\n for (const dep of deps) {\n const depPath = this.resolveDependency(dep)\n if (!depPath) continue // Unknown dependency, skip\n\n const color = colors.get(depPath) ?? WHITE\n\n if (color === GRAY) {\n // Found a cycle - reconstruct the path\n const cycle: string[] = [depPath]\n let current = path\n while (current !== depPath) {\n cycle.unshift(current)\n current = parent.get(current) ?? \"\"\n }\n cycle.unshift(depPath)\n return cycle.join(\" → \")\n }\n\n if (color === WHITE) {\n parent.set(depPath, path)\n const cyclePath = dfs(depPath)\n if (cyclePath) return cyclePath\n }\n }\n\n colors.set(path, BLACK)\n return null\n }\n\n for (const path of this.pathToKey.keys()) {\n if (colors.get(path) === WHITE) {\n const cyclePath = dfs(path)\n if (cyclePath) {\n throw new Error(\n `Circular reporting dependency detected: ${cyclePath}`,\n )\n }\n }\n }\n }\n\n /**\n * Resolve a dependency identifier to a task path.\n * Tries exact path match first, then key match.\n */\n private resolveDependency(dep: string): string | null {\n // Try exact path match first\n if (this.pathToKey.has(dep)) {\n return dep\n }\n\n // Try key match\n if (this.keyToPath.has(dep)) {\n return this.keyToPath.get(dep) ?? null\n }\n\n return null\n }\n\n /**\n * Record a task result and notify any waiters.\n * If the task failed, kills all dependent processes for early termination.\n */\n recordResult(result: TaskResult): void {\n // Store by path\n this.results.set(result.path, result)\n\n // If this task failed, kill all dependent processes\n if (!result.ok) {\n this.killDependents(result.path)\n }\n\n // Notify waiters for this path\n const pathWaiters = this.waiters.get(result.path) ?? []\n for (const waiter of pathWaiters) {\n waiter()\n }\n this.waiters.delete(result.path)\n\n // Also notify waiters for the key (if different from path)\n const key = result.key\n if (key !== result.path) {\n const keyWaiters = this.waiters.get(key) ?? []\n for (const waiter of keyWaiters) {\n waiter()\n }\n this.waiters.delete(key)\n }\n }\n\n /**\n * Mark a task as active (will actually run).\n * Called before running each task to track which tasks are in the execution set.\n */\n markActive(path: string): void {\n this.activePaths.add(path)\n }\n\n /**\n * Check if a dependency is active (will run).\n * If not active, we shouldn't wait for it.\n */\n private isDependencyActive(dep: string): boolean {\n const resolvedPath = this.resolveDependency(dep)\n if (!resolvedPath) {\n return false\n }\n return this.activePaths.has(resolvedPath)\n }\n\n /**\n * Wait for all dependencies of a task to complete.\n * Only waits for dependencies that are actually active (will run).\n */\n async waitForDependencies(path: string): Promise<void> {\n const deps = this.dependencies.get(path)\n if (!deps || deps.length === 0) {\n return\n }\n\n // Only wait for dependencies that are active (will run)\n const activeDeps = deps.filter(dep => this.isDependencyActive(dep))\n const waitPromises = activeDeps.map(dep => this.waitForResult(dep))\n await Promise.all(waitPromises)\n }\n\n /**\n * Wait for a specific task result to be available.\n */\n private waitForResult(pathOrKey: string): Promise<void> {\n // Check if result already exists\n const resolvedPath = this.resolveDependency(pathOrKey)\n if (resolvedPath && this.results.has(resolvedPath)) {\n return Promise.resolve()\n }\n\n // Also check by the original identifier\n if (this.results.has(pathOrKey)) {\n return Promise.resolve()\n }\n\n // Register a waiter\n return new Promise<void>(resolve => {\n const waiters = this.waiters.get(pathOrKey) ?? []\n waiters.push(resolve)\n this.waiters.set(pathOrKey, waiters)\n })\n }\n\n /**\n * Check if any dependency of a task has failed.\n * Returns the path of the first failed dependency, or null if all passed.\n */\n getFailedDependency(path: string): string | null {\n const deps = this.dependencies.get(path)\n if (!deps || deps.length === 0) {\n return null\n }\n\n for (const dep of deps) {\n const resolvedPath = this.resolveDependency(dep)\n if (!resolvedPath) continue\n\n const result = this.results.get(resolvedPath)\n if (result && !result.ok) {\n return resolvedPath\n }\n }\n\n return null\n }\n\n /**\n * Check if a task has any reporting dependencies.\n */\n hasDependencies(path: string): boolean {\n const deps = this.dependencies.get(path)\n return deps !== undefined && deps.length > 0\n }\n\n /**\n * Register a running process for a task.\n */\n registerProcess(path: string, proc: ChildProcess): void {\n this.processes.set(path, proc)\n }\n\n /**\n * Unregister a process (called when it completes naturally).\n */\n unregisterProcess(path: string): void {\n this.processes.delete(path)\n }\n\n /**\n * Check if a task was killed.\n */\n wasKilled(path: string): boolean {\n return this.killedPaths.has(path)\n }\n\n /**\n * Kill all processes that depend on the failed task.\n * Called when a task fails to terminate dependent tasks early.\n */\n killDependents(failedPath: string): void {\n const dependents = this.reverseDeps.get(failedPath) ?? []\n\n for (const depPath of dependents) {\n const proc = this.processes.get(depPath)\n if (proc?.pid) {\n this.killedPaths.add(depPath)\n // Use tree-kill to kill the process and all its children\n treeKill(proc.pid, \"SIGTERM\", err => {\n if (err) {\n // Process may have already exited, ignore errors\n }\n })\n }\n }\n }\n}\n","// Types\n\n// Config helpers\nexport {\n ConfigError,\n defineConfig,\n defineTask,\n findConfigFile,\n loadConfig,\n loadConfigFromCwd,\n mergeOptions,\n validateConfig,\n} from \"./config.js\"\n// Discovery\nexport {\n type DiscoveredPackage,\n discoverPackages,\n hasPackageChanged,\n} from \"./discovery.js\"\n// Filter validation\nexport {\n AmbiguousTaskError,\n findBestSuggestion,\n type ResolvedFilter,\n resolveFilters,\n TaskNotFoundError,\n} from \"./filter.js\"\n// Init\nexport {\n type DetectedTask,\n detectTasks,\n generateConfigContent,\n type InitOptions,\n type InitResult,\n type OutputFormat,\n runInit,\n} from \"./init/index.js\"\n// Parsers\nexport {\n biomeParser,\n defaultRegistry,\n genericParser,\n gotestParser,\n type ParserId,\n ParserRegistry,\n parsers,\n tscParser,\n vitestParser,\n} from \"./parsers/index.js\"\n\n// Reporter\nexport {\n createReporter,\n JSONReporter,\n LiveDashboardReporter,\n QuietReporter,\n type Reporter,\n SequentialReporter,\n type TerminalContext,\n TTYReporter,\n} from \"./reporter.js\"\n// Runner\nexport { type RunnerCallbacks, VerificationRunner } from \"./runner.js\"\n// Tree utilities\nexport {\n buildTaskPath,\n collectPaths,\n type NodeVisitor,\n PATH_SEPARATOR,\n walkNodes,\n} from \"./tree.js\"\nexport type {\n ExecutionStrategy,\n OutputParser,\n PackageDiscoveryOptions,\n ParsedResult,\n TaskResult,\n VerificationCommand,\n VerificationNode,\n VerifyConfig,\n VerifyOptions,\n VerifyResult,\n} from \"./types.js\"\n\nimport { loadConfigFromCwd, mergeOptions } from \"./config.js\"\nimport { resolveFilters } from \"./filter.js\"\nimport { createReporter } from \"./reporter.js\"\nimport { VerificationRunner } from \"./runner.js\"\n// Main verify function\nimport type { VerifyConfig, VerifyOptions, VerifyResult } from \"./types.js\"\n\n/**\n * Run verification with the given config and options\n */\nexport async function verify(\n config: VerifyConfig,\n cliOptions?: Partial<VerifyOptions>,\n): Promise<VerifyResult> {\n const options = mergeOptions(config.options, cliOptions)\n\n // VALIDATION PHASE - fail fast before any execution\n if (options.filter && options.filter.length > 0) {\n const resolved = resolveFilters(config.tasks, options.filter)\n\n // Log info messages for any shortcuts used\n for (const r of resolved) {\n if (r.wasShortcut) {\n console.error(`→ Resolving \"${r.original}\" to \"${r.resolved}\"`)\n }\n }\n\n // Update options with resolved filters\n options.filter = resolved.map(r => r.resolved)\n }\n\n // EXECUTION PHASE - only runs if validation passed\n const reporter = createReporter(options)\n\n // Initialize reporter with task list (for live dashboard)\n reporter.onStart?.(config.tasks)\n\n const runner = new VerificationRunner(\n options,\n undefined,\n {\n onTaskStart: (path, key) => reporter.onTaskStart(path, key),\n onTaskComplete: result => reporter.onTaskComplete(result),\n },\n config.env,\n )\n\n const result = await runner.run(config.tasks)\n\n // Cleanup reporter (stop spinner, restore cursor)\n reporter.onFinish?.()\n\n reporter.outputLogs(result.tasks, options.logs ?? \"failed\")\n reporter.outputSummary(result)\n\n return result\n}\n\n/**\n * Run verification from config file in cwd\n */\nexport async function verifyFromConfig(\n cwd: string = process.cwd(),\n cliOptions?: Partial<VerifyOptions>,\n): Promise<VerifyResult> {\n const config = await loadConfigFromCwd(cwd, cliOptions?.cwd)\n\n if (!config) {\n throw new Error(\n `No verify config found in ${cwd}. Create a verify.config.ts file.`,\n )\n }\n\n return verify(config, { ...cliOptions, cwd })\n}\n"],"mappings":"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","names":["existsSync","join","z","join","existsSync","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","resolve","errors","join","resolve","treeKill","resolve","resolve","join","treeKill","durationMs","result","result"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halecraft/verify",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Hierarchical verification runner with parallel execution and terse output",
5
5
  "type": "module",
6
6
  "exports": {