@halecraft/verify 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -1
- package/bin/verify.mjs +12 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +94 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ import { defineConfig } from "@halecraft/verify";
|
|
|
40
40
|
|
|
41
41
|
export default defineConfig({
|
|
42
42
|
tasks: [
|
|
43
|
-
{ key: "format", run: "biome check ." },
|
|
43
|
+
{ key: "format", run: "biome check .", fix: "biome check --write ." },
|
|
44
44
|
{ key: "types", run: "tsc --noEmit" },
|
|
45
45
|
{ key: "test", run: "vitest run" },
|
|
46
46
|
],
|
|
@@ -73,6 +73,12 @@ pnpm exec verify --verbose
|
|
|
73
73
|
|
|
74
74
|
# Output JSON (for CI)
|
|
75
75
|
pnpm exec verify --json
|
|
76
|
+
|
|
77
|
+
# Run fix commands where defined
|
|
78
|
+
pnpm exec verify --fix
|
|
79
|
+
|
|
80
|
+
# Fix a specific task
|
|
81
|
+
pnpm exec verify format --fix
|
|
76
82
|
```
|
|
77
83
|
|
|
78
84
|
Or you can add `"verify": "verify"` to package.json scripts and run:
|
|
@@ -108,6 +114,10 @@ interface VerificationNode {
|
|
|
108
114
|
timeout?: number;
|
|
109
115
|
};
|
|
110
116
|
|
|
117
|
+
// Command to run in fix mode (leaf nodes only)
|
|
118
|
+
// Falls back to run when not specified
|
|
119
|
+
fix?: string | { cmd: string; args: string[]; cwd?: string; env?: Record<string, string | null>; timeout?: number };
|
|
120
|
+
|
|
111
121
|
// Child tasks (for grouping)
|
|
112
122
|
children?: VerificationNode[];
|
|
113
123
|
|
|
@@ -277,6 +287,52 @@ When a command exceeds its timeout:
|
|
|
277
287
|
|
|
278
288
|
**Note:** For object commands, the `timeout` on the command takes precedence over the node-level `timeout`.
|
|
279
289
|
|
|
290
|
+
### Fix Mode
|
|
291
|
+
|
|
292
|
+
Many verification tools have a dual nature: a check mode that reports problems and a fix mode that auto-corrects them. The `fix` property lets you declare the fix variant alongside `run`:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { defineConfig } from "@halecraft/verify";
|
|
296
|
+
|
|
297
|
+
export default defineConfig({
|
|
298
|
+
tasks: [
|
|
299
|
+
{ key: "format", run: "biome check .", fix: "biome check --write ." },
|
|
300
|
+
{ key: "lint", run: "eslint .", fix: "eslint . --fix" },
|
|
301
|
+
{ key: "types", run: "tsc --noEmit" }, // No fix mode for type-checking
|
|
302
|
+
{ key: "test", run: "vitest run" },
|
|
303
|
+
],
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Run fix commands with the `--fix` flag:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# Fix all tasks that define a fix command (others run normally)
|
|
311
|
+
verify --fix
|
|
312
|
+
|
|
313
|
+
# Fix a specific task
|
|
314
|
+
verify format --fix
|
|
315
|
+
|
|
316
|
+
# Combine with passthrough args
|
|
317
|
+
verify format --fix -- --extra-arg
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
When a normal `verify` run fails and at least one failed task has a `fix` command defined, the output includes a hint:
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
✗ format failed (2 errors in 24 files)
|
|
324
|
+
✓ types verified (no errors, 150ms)
|
|
325
|
+
|
|
326
|
+
== verification: Failed ==
|
|
327
|
+
|
|
328
|
+
💡 Tip: run "verify --fix" to attempt auto-fixes
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Behavior:**
|
|
332
|
+
- Tasks without `fix` run their normal `run` command even with `--fix`
|
|
333
|
+
- Passthrough args, timeouts, env inheritance, and `reportingDependsOn` all work identically with fix commands
|
|
334
|
+
- Fix mode is a simple command swap — there's no automatic re-check after fixing
|
|
335
|
+
|
|
280
336
|
### Environment Variables
|
|
281
337
|
|
|
282
338
|
Set environment variables at the config level (applies to all tasks) or at the task level (inherits to children):
|
|
@@ -347,6 +403,7 @@ Flags:
|
|
|
347
403
|
--init Initialize a new verify.config.ts file
|
|
348
404
|
--force Overwrite existing config file (with --init)
|
|
349
405
|
--yes, -y Skip interactive prompts, auto-accept detected tasks
|
|
406
|
+
--fix Run fix commands instead of check commands where available
|
|
350
407
|
--help, -h Show this help message
|
|
351
408
|
```
|
|
352
409
|
|
|
@@ -459,6 +516,7 @@ interface VerifyResult {
|
|
|
459
516
|
finishedAt: string; // ISO timestamp when run finished
|
|
460
517
|
durationMs: number; // Total duration in milliseconds
|
|
461
518
|
tasks: TaskResult[]; // Individual task results
|
|
519
|
+
fixAvailable?: boolean; // True when at least one failed task defines a fix command
|
|
462
520
|
}
|
|
463
521
|
|
|
464
522
|
interface TaskResult {
|
package/bin/verify.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// JSON import requires Node 18.20+ (engines permits 18.0+ but this is theoretical;
|
|
4
|
+
// Node 18 is EOL since April 2025 and real-world users are on 18.20+ or newer.)
|
|
5
|
+
import pkg from "../package.json" with { type: "json" }
|
|
3
6
|
import { cli } from "cleye"
|
|
4
7
|
import {
|
|
5
8
|
AmbiguousTaskError,
|
|
@@ -11,7 +14,7 @@ import {
|
|
|
11
14
|
const argv = cli(
|
|
12
15
|
{
|
|
13
16
|
name: "verify",
|
|
14
|
-
version:
|
|
17
|
+
version: pkg.version,
|
|
15
18
|
description: "Hierarchical verification runner with parallel execution",
|
|
16
19
|
|
|
17
20
|
parameters: [
|
|
@@ -63,6 +66,11 @@ const argv = cli(
|
|
|
63
66
|
description: "Initialize a new verify.config.ts file",
|
|
64
67
|
default: false,
|
|
65
68
|
},
|
|
69
|
+
fix: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
description: "Run fix commands instead of check commands where available",
|
|
72
|
+
default: false,
|
|
73
|
+
},
|
|
66
74
|
force: {
|
|
67
75
|
type: Boolean,
|
|
68
76
|
description: "Overwrite existing config file (with --init)",
|
|
@@ -85,6 +93,8 @@ const argv = cli(
|
|
|
85
93
|
"verify --top-level Show only top-level tasks",
|
|
86
94
|
"verify --json Output JSON for CI",
|
|
87
95
|
"verify --logs=all Show all output",
|
|
96
|
+
"verify --fix Run auto-fix commands where defined",
|
|
97
|
+
"verify format --fix Fix a specific task",
|
|
88
98
|
"verify --init Create config interactively",
|
|
89
99
|
"verify --init -y Create config with all detected tasks",
|
|
90
100
|
"verify --init --force Overwrite existing config",
|
|
@@ -139,6 +149,7 @@ async function main() {
|
|
|
139
149
|
topLevelOnly: flags.topLevel,
|
|
140
150
|
noTty: flags.noTty,
|
|
141
151
|
quiet: flags.quiet,
|
|
152
|
+
fix: flags.fix,
|
|
142
153
|
passthrough: passthrough && passthrough.length > 0 ? passthrough : undefined,
|
|
143
154
|
}
|
|
144
155
|
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,8 @@ interface VerificationNode {
|
|
|
56
56
|
name?: string;
|
|
57
57
|
/** Command to run (leaf nodes only) - string commands are executed via shell */
|
|
58
58
|
run?: VerificationCommand | string;
|
|
59
|
+
/** Command to run in fix mode (leaf nodes only). Falls back to run when not specified. */
|
|
60
|
+
fix?: VerificationCommand | string;
|
|
59
61
|
/** Child verification nodes */
|
|
60
62
|
children?: VerificationNode[];
|
|
61
63
|
/** Execution strategy for children (default: parallel) */
|
|
@@ -109,6 +111,8 @@ interface VerifyOptions {
|
|
|
109
111
|
quiet?: boolean;
|
|
110
112
|
/** Arguments to pass through to the underlying command (requires single task filter) */
|
|
111
113
|
passthrough?: string[];
|
|
114
|
+
/** Run fix commands instead of check commands where available */
|
|
115
|
+
fix?: boolean;
|
|
112
116
|
}
|
|
113
117
|
/**
|
|
114
118
|
* Package discovery options for monorepos
|
|
@@ -190,6 +194,8 @@ interface VerifyResult {
|
|
|
190
194
|
durationMs: number;
|
|
191
195
|
/** Individual task results */
|
|
192
196
|
tasks: TaskResult[];
|
|
197
|
+
/** True when at least one failed task defines a fix command */
|
|
198
|
+
fixAvailable?: boolean;
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
/**
|
|
@@ -323,6 +329,8 @@ interface DetectedTask {
|
|
|
323
329
|
* Auto-populated based on category (types/logic/build depend on format).
|
|
324
330
|
*/
|
|
325
331
|
reportingDependsOn?: string[];
|
|
332
|
+
/** Command to run in fix mode (auto-detected for known tools) */
|
|
333
|
+
fixCommand?: string;
|
|
326
334
|
}
|
|
327
335
|
/**
|
|
328
336
|
* Detect tasks with proper package manager commands
|
|
@@ -471,6 +479,8 @@ interface Reporter {
|
|
|
471
479
|
outputLogs(results: TaskResult[], logsMode: "all" | "failed" | "none"): void;
|
|
472
480
|
/** Called to output final summary */
|
|
473
481
|
outputSummary(result: VerifyResult): void;
|
|
482
|
+
/** Called to hint that fix commands are available */
|
|
483
|
+
outputFixHint?(result: VerifyResult): void;
|
|
474
484
|
}
|
|
475
485
|
/**
|
|
476
486
|
* Terminal capability context — the single point where globals are read.
|
|
@@ -541,6 +551,7 @@ declare abstract class BaseReporter implements Reporter {
|
|
|
541
551
|
* Output final summary
|
|
542
552
|
*/
|
|
543
553
|
outputSummary(result: VerifyResult): void;
|
|
554
|
+
outputFixHint(result: VerifyResult): void;
|
|
544
555
|
abstract onStart(tasks: VerificationNode[]): void;
|
|
545
556
|
abstract onTaskStart(path: string, key: string): void;
|
|
546
557
|
abstract onTaskComplete(result: TaskResult): void;
|
|
@@ -622,6 +633,7 @@ declare class QuietReporter extends BaseReporter {
|
|
|
622
633
|
onFinish(): void;
|
|
623
634
|
outputLogs(_results: TaskResult[], _logsMode: "all" | "failed" | "none"): void;
|
|
624
635
|
outputSummary(result: VerifyResult): void;
|
|
636
|
+
outputFixHint(result: VerifyResult): void;
|
|
625
637
|
}
|
|
626
638
|
/**
|
|
627
639
|
* Create appropriate reporter based on options.
|
|
@@ -630,6 +642,12 @@ declare class QuietReporter extends BaseReporter {
|
|
|
630
642
|
*/
|
|
631
643
|
declare function createReporter(options: VerifyOptions): Reporter;
|
|
632
644
|
|
|
645
|
+
/**
|
|
646
|
+
* Resolve which command to execute for a node based on fix mode.
|
|
647
|
+
* Returns `node.fix` when in fix mode and a fix command is defined,
|
|
648
|
+
* otherwise falls back to `node.run`.
|
|
649
|
+
*/
|
|
650
|
+
declare function resolveCommand(node: VerificationNode, fix: boolean): VerificationCommand | string | undefined;
|
|
633
651
|
interface RunnerCallbacks {
|
|
634
652
|
onTaskStart?: (path: string, key: string) => void;
|
|
635
653
|
onTaskComplete?: (result: TaskResult) => void;
|
|
@@ -683,6 +701,12 @@ declare function walkNodes(nodes: VerificationNode[], visitor: NodeVisitor, pare
|
|
|
683
701
|
* Collect all task paths from a verification tree
|
|
684
702
|
*/
|
|
685
703
|
declare function collectPaths(nodes: VerificationNode[]): string[];
|
|
704
|
+
/**
|
|
705
|
+
* Check whether at least one failed (non-blocked) task defines a fix command.
|
|
706
|
+
* Only considers tasks that actually ran and failed — filtered-out tasks
|
|
707
|
+
* won't appear in results and can't trigger a false positive.
|
|
708
|
+
*/
|
|
709
|
+
declare function hasFixAvailable(tasks: VerificationNode[], results: TaskResult[]): boolean;
|
|
686
710
|
|
|
687
711
|
/**
|
|
688
712
|
* Run verification with the given config and options
|
|
@@ -693,4 +717,4 @@ declare function verify(config: VerifyConfig, cliOptions?: Partial<VerifyOptions
|
|
|
693
717
|
*/
|
|
694
718
|
declare function verifyFromConfig(cwd?: string, cliOptions?: Partial<VerifyOptions>): Promise<VerifyResult>;
|
|
695
719
|
|
|
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 };
|
|
720
|
+
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, hasFixAvailable, hasPackageChanged, loadConfig, loadConfigFromCwd, mergeOptions, parsers, resolveCommand, resolveFilters, runInit, tscParser, validateConfig, verify, verifyFromConfig, vitestParser, walkNodes };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ var VerificationNodeSchema = z.lazy(
|
|
|
25
25
|
}),
|
|
26
26
|
name: z.string().optional(),
|
|
27
27
|
run: z.union([z.string(), VerificationCommandSchema]).optional(),
|
|
28
|
+
fix: z.union([z.string(), VerificationCommandSchema]).optional(),
|
|
28
29
|
children: z.array(VerificationNodeSchema).optional(),
|
|
29
30
|
strategy: z.enum(["parallel", "sequential", "fail-fast"]).optional(),
|
|
30
31
|
parser: z.string().optional(),
|
|
@@ -43,7 +44,9 @@ var VerifyOptionsSchema = z.object({
|
|
|
43
44
|
noColor: z.boolean().optional(),
|
|
44
45
|
topLevelOnly: z.boolean().optional(),
|
|
45
46
|
noTty: z.boolean().optional(),
|
|
46
|
-
|
|
47
|
+
quiet: z.boolean().optional(),
|
|
48
|
+
passthrough: z.array(z.string()).optional(),
|
|
49
|
+
fix: z.boolean().optional()
|
|
47
50
|
});
|
|
48
51
|
var PackageDiscoveryOptionsSchema = z.object({
|
|
49
52
|
patterns: z.array(z.string()).optional(),
|
|
@@ -124,7 +127,8 @@ function mergeOptions(configOptions, cliOptions) {
|
|
|
124
127
|
topLevelOnly: cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,
|
|
125
128
|
noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,
|
|
126
129
|
quiet: cliOptions?.quiet ?? configOptions?.quiet ?? false,
|
|
127
|
-
passthrough: cliOptions?.passthrough ?? configOptions?.passthrough
|
|
130
|
+
passthrough: cliOptions?.passthrough ?? configOptions?.passthrough,
|
|
131
|
+
fix: cliOptions?.fix ?? configOptions?.fix ?? false
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -239,6 +243,33 @@ function collectPaths(nodes) {
|
|
|
239
243
|
});
|
|
240
244
|
return paths;
|
|
241
245
|
}
|
|
246
|
+
function flattenResults(results) {
|
|
247
|
+
const flat = [];
|
|
248
|
+
for (const r of results) {
|
|
249
|
+
flat.push(r);
|
|
250
|
+
if (r.children) {
|
|
251
|
+
flat.push(...flattenResults(r.children));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return flat;
|
|
255
|
+
}
|
|
256
|
+
function hasFixAvailable(tasks, results) {
|
|
257
|
+
const failedPaths = /* @__PURE__ */ new Set();
|
|
258
|
+
for (const r of flattenResults(results)) {
|
|
259
|
+
if (!r.ok && !r.blocked) {
|
|
260
|
+
failedPaths.add(r.path);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (failedPaths.size === 0) return false;
|
|
264
|
+
let found = false;
|
|
265
|
+
walkNodes(tasks, (node, path) => {
|
|
266
|
+
if (found) return;
|
|
267
|
+
if (node.fix && !node.children && failedPaths.has(path)) {
|
|
268
|
+
found = true;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
return found;
|
|
272
|
+
}
|
|
242
273
|
|
|
243
274
|
// src/filter.ts
|
|
244
275
|
var TaskNotFoundError = class extends Error {
|
|
@@ -352,6 +383,12 @@ var TOOL_PATTERNS = [
|
|
|
352
383
|
const biomeMatch = content.match(/biome\s+([^&|;]+)/);
|
|
353
384
|
return biomeMatch ? biomeMatch[1].trim() : "check .";
|
|
354
385
|
},
|
|
386
|
+
getFixArgs: (match, content) => {
|
|
387
|
+
const biomeMatch = content.match(/biome\s+([^&|;]+)/);
|
|
388
|
+
const args = biomeMatch ? biomeMatch[1].trim() : "check .";
|
|
389
|
+
if (args.includes("--write")) return null;
|
|
390
|
+
return args.replace(/^(check|lint|format)/, "$1 --write");
|
|
391
|
+
},
|
|
355
392
|
parser: "biome"
|
|
356
393
|
},
|
|
357
394
|
// ESLint
|
|
@@ -361,6 +398,12 @@ var TOOL_PATTERNS = [
|
|
|
361
398
|
getArgs: (_, content) => {
|
|
362
399
|
const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
|
|
363
400
|
return eslintMatch ? eslintMatch[1].trim() : ".";
|
|
401
|
+
},
|
|
402
|
+
getFixArgs: (_, content) => {
|
|
403
|
+
const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
|
|
404
|
+
const args = eslintMatch ? eslintMatch[1].trim() : ".";
|
|
405
|
+
if (args.includes("--fix")) return null;
|
|
406
|
+
return `${args} --fix`;
|
|
364
407
|
}
|
|
365
408
|
},
|
|
366
409
|
// Prettier
|
|
@@ -370,6 +413,13 @@ var TOOL_PATTERNS = [
|
|
|
370
413
|
getArgs: (_, content) => {
|
|
371
414
|
const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
|
|
372
415
|
return prettierMatch ? prettierMatch[1].trim() : "--check .";
|
|
416
|
+
},
|
|
417
|
+
getFixArgs: (_, content) => {
|
|
418
|
+
const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
|
|
419
|
+
const args = prettierMatch ? prettierMatch[1].trim() : "--check .";
|
|
420
|
+
if (args.includes("--write")) return null;
|
|
421
|
+
if (args.includes("--check")) return args.replace("--check", "--write");
|
|
422
|
+
return `--write ${args}`;
|
|
373
423
|
}
|
|
374
424
|
},
|
|
375
425
|
// TypeScript
|
|
@@ -515,7 +565,14 @@ function extractOptimizedCommand(cwd, scriptContent) {
|
|
|
515
565
|
if (match && binaryExists(cwd, tool.binary)) {
|
|
516
566
|
const args = tool.getArgs(match, scriptContent);
|
|
517
567
|
const command = args ? `${tool.binary} ${args}` : tool.binary;
|
|
518
|
-
|
|
568
|
+
let fixCommand;
|
|
569
|
+
if (tool.getFixArgs) {
|
|
570
|
+
const fixArgs = tool.getFixArgs(match, scriptContent);
|
|
571
|
+
if (fixArgs) {
|
|
572
|
+
fixCommand = `${tool.binary} ${fixArgs}`;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return { command, parser: tool.parser, fixCommand };
|
|
519
576
|
}
|
|
520
577
|
}
|
|
521
578
|
return null;
|
|
@@ -543,7 +600,8 @@ function detectFromPackageJson(cwd) {
|
|
|
543
600
|
scriptName,
|
|
544
601
|
command: optimized?.command ?? `npm run ${scriptName}`,
|
|
545
602
|
category,
|
|
546
|
-
parser: optimized?.parser
|
|
603
|
+
parser: optimized?.parser,
|
|
604
|
+
fixCommand: optimized?.fixCommand
|
|
547
605
|
});
|
|
548
606
|
}
|
|
549
607
|
break;
|
|
@@ -613,6 +671,9 @@ function generateImport(format) {
|
|
|
613
671
|
}
|
|
614
672
|
function generateTask(task, indent) {
|
|
615
673
|
const parts = [`key: "${task.key}"`, `run: "${task.command}"`];
|
|
674
|
+
if (task.fixCommand) {
|
|
675
|
+
parts.push(`fix: "${task.fixCommand}"`);
|
|
676
|
+
}
|
|
616
677
|
if (task.parser) {
|
|
617
678
|
parts.push(`parser: "${task.parser}"`);
|
|
618
679
|
}
|
|
@@ -1269,6 +1330,13 @@ ${this.c(ansi.bold, "====")} ${this.c(ansi.bold, r.path.toUpperCase())} ${status
|
|
|
1269
1330
|
this.stream.write(`${finalMessage}
|
|
1270
1331
|
`);
|
|
1271
1332
|
}
|
|
1333
|
+
outputFixHint(result) {
|
|
1334
|
+
if (result.fixAvailable && !result.ok) {
|
|
1335
|
+
this.stream.write(`
|
|
1336
|
+
\u{1F4A1} Tip: run "verify --fix" to attempt auto-fixes
|
|
1337
|
+
`);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1272
1340
|
};
|
|
1273
1341
|
var LiveDashboardReporter = class extends BaseReporter {
|
|
1274
1342
|
topLevelOnly;
|
|
@@ -1432,6 +1500,7 @@ var JSONReporter = class {
|
|
|
1432
1500
|
startedAt: result.startedAt,
|
|
1433
1501
|
finishedAt: result.finishedAt,
|
|
1434
1502
|
durationMs: result.durationMs,
|
|
1503
|
+
...result.fixAvailable ? { fixAvailable: result.fixAvailable } : {},
|
|
1435
1504
|
tasks: this.serializeTasks(result.tasks)
|
|
1436
1505
|
};
|
|
1437
1506
|
process.stdout.write(`${JSON.stringify(summary)}
|
|
@@ -1467,6 +1536,12 @@ var QuietReporter = class extends BaseReporter {
|
|
|
1467
1536
|
process.stdout.write(`${message}
|
|
1468
1537
|
`);
|
|
1469
1538
|
}
|
|
1539
|
+
outputFixHint(result) {
|
|
1540
|
+
if (result.fixAvailable && !result.ok) {
|
|
1541
|
+
process.stdout.write(`\u{1F4A1} fix available: verify --fix
|
|
1542
|
+
`);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1470
1545
|
};
|
|
1471
1546
|
function createReporter(options) {
|
|
1472
1547
|
const ctx = defaultTerminalContext();
|
|
@@ -1736,6 +1811,10 @@ var ReportingDependencyTracker = class {
|
|
|
1736
1811
|
};
|
|
1737
1812
|
|
|
1738
1813
|
// src/runner.ts
|
|
1814
|
+
function resolveCommand(node, fix) {
|
|
1815
|
+
if (fix && node.fix) return node.fix;
|
|
1816
|
+
return node.run;
|
|
1817
|
+
}
|
|
1739
1818
|
function mergeEnv(base, overlay) {
|
|
1740
1819
|
if (!overlay) return { ...base };
|
|
1741
1820
|
const result = { ...base };
|
|
@@ -1931,12 +2010,14 @@ var VerificationRunner = class {
|
|
|
1931
2010
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1932
2011
|
const durationMs = Date.now() - wallStart;
|
|
1933
2012
|
const allOk = results.every((r) => r.ok);
|
|
2013
|
+
const fixAvailable = hasFixAvailable(tasks, results);
|
|
1934
2014
|
return {
|
|
1935
2015
|
ok: allOk,
|
|
1936
2016
|
startedAt,
|
|
1937
2017
|
finishedAt,
|
|
1938
2018
|
durationMs,
|
|
1939
|
-
tasks: results
|
|
2019
|
+
tasks: results,
|
|
2020
|
+
...fixAvailable ? { fixAvailable } : {}
|
|
1940
2021
|
};
|
|
1941
2022
|
}
|
|
1942
2023
|
/**
|
|
@@ -2015,7 +2096,8 @@ var VerificationRunner = class {
|
|
|
2015
2096
|
this.callbacks.onTaskComplete?.(result2);
|
|
2016
2097
|
return result2;
|
|
2017
2098
|
}
|
|
2018
|
-
|
|
2099
|
+
const effectiveRun = resolveCommand(node, this.options.fix ?? false);
|
|
2100
|
+
if (!effectiveRun) {
|
|
2019
2101
|
const result2 = {
|
|
2020
2102
|
key: node.key,
|
|
2021
2103
|
path,
|
|
@@ -2031,7 +2113,7 @@ var VerificationRunner = class {
|
|
|
2031
2113
|
}
|
|
2032
2114
|
const passthrough = this.options.passthrough;
|
|
2033
2115
|
const command = normalizeCommand(
|
|
2034
|
-
|
|
2116
|
+
effectiveRun,
|
|
2035
2117
|
node.timeout,
|
|
2036
2118
|
passthrough,
|
|
2037
2119
|
nodeEnv
|
|
@@ -2146,6 +2228,9 @@ async function verify(config, cliOptions) {
|
|
|
2146
2228
|
reporter.onFinish?.();
|
|
2147
2229
|
reporter.outputLogs(result.tasks, options.logs ?? "failed");
|
|
2148
2230
|
reporter.outputSummary(result);
|
|
2231
|
+
if (!options.fix) {
|
|
2232
|
+
reporter.outputFixHint?.(result);
|
|
2233
|
+
}
|
|
2149
2234
|
return result;
|
|
2150
2235
|
}
|
|
2151
2236
|
async function verifyFromConfig(cwd = process.cwd(), cliOptions) {
|
|
@@ -2183,11 +2268,13 @@ export {
|
|
|
2183
2268
|
generateConfigContent,
|
|
2184
2269
|
genericParser,
|
|
2185
2270
|
gotestParser,
|
|
2271
|
+
hasFixAvailable,
|
|
2186
2272
|
hasPackageChanged,
|
|
2187
2273
|
loadConfig,
|
|
2188
2274
|
loadConfigFromCwd,
|
|
2189
2275
|
mergeOptions,
|
|
2190
2276
|
parsers,
|
|
2277
|
+
resolveCommand,
|
|
2191
2278
|
resolveFilters,
|
|
2192
2279
|
runInit,
|
|
2193
2280
|
tscParser,
|
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 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"]}
|
|
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 fix: 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 quiet: z.boolean().optional(),\n passthrough: z.array(z.string()).optional(),\n fix: z.boolean().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 fix: cliOptions?.fix ?? configOptions?.fix ?? false,\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 { TaskResult, 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\n/**\n * Flatten nested task results into a single array\n */\nfunction 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(...flattenResults(r.children))\n }\n }\n return flat\n}\n\n/**\n * Check whether at least one failed (non-blocked) task defines a fix command.\n * Only considers tasks that actually ran and failed — filtered-out tasks\n * won't appear in results and can't trigger a false positive.\n */\nexport function hasFixAvailable(\n tasks: VerificationNode[],\n results: TaskResult[],\n): boolean {\n // Build set of paths that failed and are not blocked\n const failedPaths = new Set<string>()\n for (const r of flattenResults(results)) {\n if (!r.ok && !r.blocked) {\n failedPaths.add(r.path)\n }\n }\n\n if (failedPaths.size === 0) return false\n\n // Walk nodes — any leaf with `fix` whose path is in the failed set\n let found = false\n walkNodes(tasks, (node, path) => {\n if (found) return\n if (node.fix && !node.children && failedPaths.has(path)) {\n found = true\n }\n })\n return found\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 /** Command to run in fix mode (auto-detected for known tools) */\n fixCommand?: 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 /** Returns fix-mode args, or null if the tool has no fix mode */\n getFixArgs?: (match: RegExpMatchArray, scriptContent: string) => string | null\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 getFixArgs: (match, content) => {\n const biomeMatch = content.match(/biome\\s+([^&|;]+)/)\n const args = biomeMatch ? biomeMatch[1].trim() : \"check .\"\n // Already has --write, no separate fix needed\n if (args.includes(\"--write\")) return null\n // Insert --write after the subcommand (check/lint/format)\n return args.replace(/^(check|lint|format)/, \"$1 --write\")\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 getFixArgs: (_, content) => {\n const eslintMatch = content.match(/eslint\\s+([^&|;]+)/)\n const args = eslintMatch ? eslintMatch[1].trim() : \".\"\n if (args.includes(\"--fix\")) return null\n return `${args} --fix`\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 getFixArgs: (_, content) => {\n const prettierMatch = content.match(/prettier\\s+([^&|;]+)/)\n const args = prettierMatch ? prettierMatch[1].trim() : \"--check .\"\n if (args.includes(\"--write\")) return null\n // Replace --check with --write\n if (args.includes(\"--check\")) return args.replace(\"--check\", \"--write\")\n return `--write ${args}`\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; fixCommand?: 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\n // Derive fix command if the tool supports it\n let fixCommand: string | undefined\n if (tool.getFixArgs) {\n const fixArgs = tool.getFixArgs(match, scriptContent)\n if (fixArgs) {\n fixCommand = `${tool.binary} ${fixArgs}`\n }\n }\n\n return { command, parser: tool.parser, fixCommand }\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 fixCommand: optimized?.fixCommand,\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.fixCommand) {\n parts.push(`fix: \"${task.fixCommand}\"`)\n }\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 /** Called to hint that fix commands are available */\n outputFixHint?(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 outputFixHint(result: VerifyResult): void {\n if (result.fixAvailable && !result.ok) {\n this.stream.write(`\\n💡 Tip: run \"verify --fix\" to attempt auto-fixes\\n`)\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 ...(result.fixAvailable ? { fixAvailable: result.fixAvailable } : {}),\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 outputFixHint(result: VerifyResult): void {\n if (result.fixAvailable && !result.ok) {\n process.stdout.write(`💡 fix available: verify --fix\\n`)\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, hasFixAvailable } 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 * Resolve which command to execute for a node based on fix mode.\n * Returns `node.fix` when in fix mode and a fix command is defined,\n * otherwise falls back to `node.run`.\n */\nexport function resolveCommand(\n node: VerificationNode,\n fix: boolean,\n): VerificationCommand | string | undefined {\n if (fix && node.fix) return node.fix\n return node.run\n}\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 const fixAvailable = hasFixAvailable(tasks, results)\n\n return {\n ok: allOk,\n startedAt,\n finishedAt,\n durationMs,\n tasks: results,\n ...(fixAvailable ? { fixAvailable } : {}),\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 - resolve effective command (fix mode swaps fix for run)\n const effectiveRun = resolveCommand(node, this.options.fix ?? false)\n if (!effectiveRun) {\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 effectiveRun,\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 {\n resolveCommand,\n type RunnerCallbacks,\n VerificationRunner,\n} from \"./runner.js\"\n// Tree utilities\nexport {\n buildTaskPath,\n collectPaths,\n hasFixAvailable,\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 // Hint about --fix when not already in fix mode\n if (!options.fix) {\n reporter.outputFixHint?.(result)\n }\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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@halecraft/verify",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Hierarchical verification runner with parallel execution
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "Hierarchical verification runner with parallel execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|