@vibe-validate/cli 0.14.1 → 0.14.3
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 +2 -2
- package/config-templates/README.md +1 -1
- package/dist/bin.js +23 -17
- package/dist/bin.js.map +1 -1
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +32 -19
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +23 -12
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +221 -198
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-workflow.d.ts.map +1 -1
- package/dist/commands/generate-workflow.js +22 -12
- package/dist/commands/generate-workflow.js.map +1 -1
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +46 -34
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/init.js +17 -19
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pre-commit.d.ts.map +1 -1
- package/dist/commands/pre-commit.js +2 -1
- package/dist/commands/pre-commit.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +8 -9
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +2 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/watch-pr.d.ts.map +1 -1
- package/dist/commands/watch-pr.js +43 -36
- package/dist/commands/watch-pr.js.map +1 -1
- package/dist/schemas/watch-pr-schema.d.ts +31 -31
- package/dist/scripts/generate-watch-pr-schema.js +3 -3
- package/dist/scripts/generate-watch-pr-schema.js.map +1 -1
- package/dist/services/ci-providers/github-actions.d.ts +25 -0
- package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
- package/dist/services/ci-providers/github-actions.js +83 -46
- package/dist/services/ci-providers/github-actions.js.map +1 -1
- package/dist/utils/check-validation.d.ts.map +1 -1
- package/dist/utils/check-validation.js +9 -5
- package/dist/utils/check-validation.js.map +1 -1
- package/dist/utils/config-error-reporter.d.ts +59 -0
- package/dist/utils/config-error-reporter.d.ts.map +1 -0
- package/dist/utils/config-error-reporter.js +105 -0
- package/dist/utils/config-error-reporter.js.map +1 -0
- package/dist/utils/config-loader.js +5 -5
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/git-detection.d.ts +0 -22
- package/dist/utils/git-detection.d.ts.map +1 -1
- package/dist/utils/git-detection.js +64 -56
- package/dist/utils/git-detection.js.map +1 -1
- package/dist/utils/pid-lock.d.ts.map +1 -1
- package/dist/utils/pid-lock.js +10 -7
- package/dist/utils/pid-lock.js.map +1 -1
- package/dist/utils/project-id.d.ts.map +1 -1
- package/dist/utils/project-id.js +9 -6
- package/dist/utils/project-id.js.map +1 -1
- package/dist/utils/run-validation-with-cache.d.ts +48 -0
- package/dist/utils/run-validation-with-cache.d.ts.map +1 -0
- package/dist/utils/run-validation-with-cache.js +123 -0
- package/dist/utils/run-validation-with-cache.js.map +1 -0
- package/dist/utils/runner-adapter.js +1 -1
- package/dist/utils/runner-adapter.js.map +1 -1
- package/dist/utils/setup-checks/hooks-check.js +3 -3
- package/dist/utils/setup-checks/hooks-check.js.map +1 -1
- package/dist/utils/setup-checks/workflow-check.js +3 -3
- package/dist/utils/setup-checks/workflow-check.js.map +1 -1
- package/dist/utils/template-discovery.d.ts.map +1 -1
- package/dist/utils/template-discovery.js +13 -19
- package/dist/utils/template-discovery.js.map +1 -1
- package/dist/utils/validate-workflow.d.ts.map +1 -1
- package/dist/utils/validate-workflow.js +164 -150
- package/dist/utils/validate-workflow.js.map +1 -1
- package/dist/utils/validation-cache.d.ts +30 -0
- package/dist/utils/validation-cache.d.ts.map +1 -0
- package/dist/utils/validation-cache.js +57 -0
- package/dist/utils/validation-cache.js.map +1 -0
- package/package.json +7 -7
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Discovers and reads metadata from config templates in the config-templates/ directory.
|
|
5
5
|
*/
|
|
6
|
-
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
7
|
-
import { join, dirname } from 'path';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
6
|
+
import { readdirSync, readFileSync, existsSync } from 'node:fs';
|
|
7
|
+
import { join, dirname } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { splitLines } from './normalize-line-endings.js';
|
|
10
10
|
/**
|
|
11
11
|
* Get the absolute path to the config-templates directory
|
|
@@ -15,24 +15,17 @@ import { splitLines } from './normalize-line-endings.js';
|
|
|
15
15
|
* @returns Absolute path to config-templates directory
|
|
16
16
|
*/
|
|
17
17
|
function getTemplatesDir() {
|
|
18
|
-
//
|
|
19
|
-
// In development, templates are at <repo-root>/config-templates
|
|
18
|
+
// Templates are at packages/cli/config-templates (permanent location)
|
|
20
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
20
|
const __dirname = dirname(__filename);
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
// Path is the same for both dev and production:
|
|
22
|
+
// Development: packages/cli/src/utils/../../config-templates
|
|
23
|
+
// Production: packages/cli/dist/utils/../../config-templates
|
|
24
|
+
const templatesPath = join(__dirname, '../../config-templates');
|
|
25
|
+
if (!existsSync(templatesPath)) {
|
|
26
|
+
throw new Error(`Config templates directory not found at ${templatesPath}`);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
const prodPath = join(__dirname, '../../../config-templates');
|
|
30
|
-
if (existsSync(prodPath)) {
|
|
31
|
-
return prodPath;
|
|
32
|
-
}
|
|
33
|
-
// 3. Fallback: assume monorepo root
|
|
34
|
-
const fallbackPath = join(process.cwd(), 'config-templates');
|
|
35
|
-
return fallbackPath;
|
|
28
|
+
return templatesPath;
|
|
36
29
|
}
|
|
37
30
|
/**
|
|
38
31
|
* Extract template metadata from YAML file
|
|
@@ -58,7 +51,7 @@ function parseTemplateMetadata(filename, content) {
|
|
|
58
51
|
let displayName = filename.replace('.yaml', '');
|
|
59
52
|
const titleLine = lines.find(line => line.includes('CONFIGURATION TEMPLATE -'));
|
|
60
53
|
if (titleLine) {
|
|
61
|
-
const match =
|
|
54
|
+
const match = /CONFIGURATION TEMPLATE\s*-\s*(.+)/.exec(titleLine);
|
|
62
55
|
if (match) {
|
|
63
56
|
displayName = match[1].trim();
|
|
64
57
|
// Remove "vibe-validate for " prefix if present
|
|
@@ -98,6 +91,7 @@ export function discoverTemplates() {
|
|
|
98
91
|
// Read all .yaml files
|
|
99
92
|
const files = readdirSync(templatesDir)
|
|
100
93
|
.filter(file => file.endsWith('.yaml'))
|
|
94
|
+
// eslint-disable-next-line sonarjs/no-alphabetical-sort -- Alphabetical sorting is intentional for template list display
|
|
101
95
|
.sort();
|
|
102
96
|
// Parse metadata from each template
|
|
103
97
|
const templates = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-discovery.js","sourceRoot":"","sources":["../../src/utils/template-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"template-discovery.js","sourceRoot":"","sources":["../../src/utils/template-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-workflow.d.ts","sourceRoot":"","sources":["../../src/utils/validate-workflow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"validate-workflow.d.ts","sourceRoot":"","sources":["../../src/utils/validate-workflow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAK1D,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;CACvB;AA2KD;;;;;;;;;GASG;AAEH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAgG3B"}
|
|
@@ -10,6 +10,157 @@ import { recordValidationHistory, checkWorktreeStability, checkHistoryHealth, re
|
|
|
10
10
|
import { createRunnerConfig } from './runner-adapter.js';
|
|
11
11
|
import chalk from 'chalk';
|
|
12
12
|
import { stringify as yamlStringify } from 'yaml';
|
|
13
|
+
/**
|
|
14
|
+
* Wait for stdout to flush before continuing
|
|
15
|
+
*
|
|
16
|
+
* Critical for YAML output when stdout is redirected to a file (CI).
|
|
17
|
+
* Without this, process.exit() can kill the process before the write buffer flushes.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
async function flushStdout() {
|
|
22
|
+
await new Promise(resolve => {
|
|
23
|
+
if (process.stdout.write('')) {
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
process.stdout.once('drain', resolve);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Output validation result as YAML
|
|
33
|
+
*
|
|
34
|
+
* @param result - Validation result to output
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
async function outputYaml(result) {
|
|
38
|
+
// Small delay to ensure stderr is flushed before writing to stdout
|
|
39
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
40
|
+
// Output YAML document separator (RFC 4627)
|
|
41
|
+
process.stdout.write('---\n');
|
|
42
|
+
process.stdout.write(yamlStringify(result));
|
|
43
|
+
await flushStdout();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check cache for passing validation run
|
|
47
|
+
*
|
|
48
|
+
* @param treeHash - Git tree hash to check
|
|
49
|
+
* @param yaml - Whether YAML output mode is enabled
|
|
50
|
+
* @returns Cached result if found, null otherwise
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
async function checkCache(treeHash, yaml) {
|
|
54
|
+
try {
|
|
55
|
+
const historyNote = await readHistoryNote(treeHash);
|
|
56
|
+
if (historyNote && historyNote.runs.length > 0) {
|
|
57
|
+
// Find most recent passing run
|
|
58
|
+
const passingRun = [...historyNote.runs]
|
|
59
|
+
.reverse()
|
|
60
|
+
.find(run => run.passed);
|
|
61
|
+
if (passingRun) {
|
|
62
|
+
if (yaml) {
|
|
63
|
+
await outputYaml(passingRun.result);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const durationSecs = (passingRun.duration / 1000).toFixed(1);
|
|
67
|
+
console.log(chalk.green('✅ Validation already passed for current working tree'));
|
|
68
|
+
console.log(chalk.gray(` Tree hash: ${treeHash.substring(0, 12)}...`));
|
|
69
|
+
console.log(chalk.gray(` Last validated: ${passingRun.timestamp}`));
|
|
70
|
+
console.log(chalk.gray(` Duration: ${durationSecs}s`));
|
|
71
|
+
console.log(chalk.gray(` Branch: ${passingRun.branch}`));
|
|
72
|
+
if (passingRun.result.phases) {
|
|
73
|
+
const totalSteps = passingRun.result.phases.reduce((sum, phase) => sum + phase.steps.length, 0);
|
|
74
|
+
console.log(chalk.gray(` Phases: ${passingRun.result.phases.length}, Steps: ${totalSteps}`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Mark result as from cache
|
|
78
|
+
const result = passingRun.result;
|
|
79
|
+
result._fromCache = true;
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Cache check failed - proceed with validation
|
|
86
|
+
console.debug(`Cache check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Record validation history with stability check
|
|
92
|
+
*
|
|
93
|
+
* @param treeHashBefore - Tree hash before validation
|
|
94
|
+
* @param result - Validation result to record
|
|
95
|
+
* @param verbose - Whether verbose output is enabled
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
async function recordHistory(treeHashBefore, result, verbose) {
|
|
99
|
+
try {
|
|
100
|
+
// Check if worktree changed during validation
|
|
101
|
+
const stability = await checkWorktreeStability(treeHashBefore);
|
|
102
|
+
if (!stability.stable) {
|
|
103
|
+
console.warn(chalk.yellow('\n⚠️ Worktree changed during validation'));
|
|
104
|
+
console.warn(chalk.yellow(` Before: ${stability.treeHashBefore.slice(0, 12)}...`));
|
|
105
|
+
console.warn(chalk.yellow(` After: ${stability.treeHashAfter.slice(0, 12)}...`));
|
|
106
|
+
console.warn(chalk.yellow(' Results valid but history not recorded (unstable state)'));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Record to git notes
|
|
110
|
+
const recordResult = await recordValidationHistory(treeHashBefore, result);
|
|
111
|
+
if (recordResult.recorded) {
|
|
112
|
+
if (verbose) {
|
|
113
|
+
console.log(chalk.gray(`\n📝 History recorded (tree: ${treeHashBefore.slice(0, 12)})`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (verbose) {
|
|
117
|
+
console.warn(chalk.yellow(`⚠️ History recording failed: ${recordResult.reason}`));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// Silent failure - don't block validation
|
|
123
|
+
if (verbose) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
console.warn(chalk.yellow(`⚠️ History recording error: ${errorMessage}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Display failure information and extraction quality feedback
|
|
131
|
+
*
|
|
132
|
+
* @param result - Validation result (failed)
|
|
133
|
+
* @param config - Vibe validate configuration
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
function displayFailureInfo(result, config) {
|
|
137
|
+
console.error(chalk.blue('\n📋 View error details:'), chalk.white('vibe-validate state'));
|
|
138
|
+
if (result.rerunCommand) {
|
|
139
|
+
console.error(chalk.blue('🔄 To retry:'), chalk.white(result.rerunCommand));
|
|
140
|
+
}
|
|
141
|
+
if (result.fullLogFile) {
|
|
142
|
+
console.error(chalk.blue('📄 Full log:'), chalk.gray(result.fullLogFile));
|
|
143
|
+
}
|
|
144
|
+
// Context-aware extraction quality feedback (only when developerFeedback is enabled)
|
|
145
|
+
if (config.developerFeedback) {
|
|
146
|
+
const poorExtractionSteps = result.phases
|
|
147
|
+
?.flatMap(phase => phase.steps)
|
|
148
|
+
.filter(step => !step.passed && step.extractionQuality && step.extractionQuality.score < 50);
|
|
149
|
+
if (poorExtractionSteps && poorExtractionSteps.length > 0) {
|
|
150
|
+
const isDogfooding = process.cwd().includes('vibe-validate');
|
|
151
|
+
console.error('');
|
|
152
|
+
console.error(chalk.yellow('⚠️ Poor extraction quality detected'));
|
|
153
|
+
if (isDogfooding) {
|
|
154
|
+
console.error(chalk.yellow(' 💡 vibe-validate improvement opportunity: Improve extractors in packages/extractors/'));
|
|
155
|
+
console.error(chalk.gray(' See packages/extractors/test/samples/ for how to add test cases'));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.error(chalk.yellow(' 💡 Help improve vibe-validate by reporting this extraction issue'));
|
|
159
|
+
console.error(chalk.gray(' https://github.com/anthropics/vibe-validate/issues/new?template=extractor-improvement.yml'));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
13
164
|
/**
|
|
14
165
|
* Execute validation workflow with caching, history recording, and output formatting.
|
|
15
166
|
*
|
|
@@ -20,6 +171,7 @@ import { stringify as yamlStringify } from 'yaml';
|
|
|
20
171
|
* @returns Validation result
|
|
21
172
|
* @throws Error if validation encounters fatal error
|
|
22
173
|
*/
|
|
174
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- Complexity 27 acceptable for workflow orchestration (down from 81) - coordinates caching, validation, history recording, and output formatting
|
|
23
175
|
export async function runValidateWorkflow(config, options) {
|
|
24
176
|
try {
|
|
25
177
|
// If --check flag is used, only check validation state without running
|
|
@@ -27,8 +179,6 @@ export async function runValidateWorkflow(config, options) {
|
|
|
27
179
|
const yaml = options.yaml ?? false;
|
|
28
180
|
const { checkValidationStatus } = await import('./check-validation.js');
|
|
29
181
|
await checkValidationStatus(config, yaml);
|
|
30
|
-
// checkValidationStatus calls process.exit, so this line never executes
|
|
31
|
-
// But TypeScript doesn't know that, so we need to satisfy the return type
|
|
32
182
|
throw new Error('checkValidationStatus should have exited');
|
|
33
183
|
}
|
|
34
184
|
const verbose = options.verbose ?? false;
|
|
@@ -45,68 +195,20 @@ export async function runValidateWorkflow(config, options) {
|
|
|
45
195
|
try {
|
|
46
196
|
treeHashBefore = await getGitTreeHash();
|
|
47
197
|
}
|
|
48
|
-
catch (
|
|
49
|
-
|
|
198
|
+
catch (error) {
|
|
199
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
50
200
|
if (verbose) {
|
|
51
|
-
console.warn(chalk.yellow(
|
|
201
|
+
console.warn(chalk.yellow(`⚠️ Could not get git tree hash - history recording disabled: ${errorMsg}`));
|
|
52
202
|
}
|
|
53
203
|
}
|
|
54
204
|
// Check cache: if validation already passed for this tree hash, skip re-running
|
|
55
205
|
if (treeHashBefore && !options.force) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Find most recent passing run
|
|
60
|
-
const passingRun = [...historyNote.runs]
|
|
61
|
-
.reverse()
|
|
62
|
-
.find(run => run.passed);
|
|
63
|
-
if (passingRun) {
|
|
64
|
-
if (yaml) {
|
|
65
|
-
// YAML mode: Output cached result as YAML to stdout
|
|
66
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
67
|
-
// Output YAML document separator (RFC 4627)
|
|
68
|
-
process.stdout.write('---\n');
|
|
69
|
-
process.stdout.write(yamlStringify(passingRun.result));
|
|
70
|
-
// Wait for stdout to flush before exiting
|
|
71
|
-
await new Promise(resolve => {
|
|
72
|
-
if (process.stdout.write('')) {
|
|
73
|
-
resolve();
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
process.stdout.once('drain', resolve);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// Human-readable mode: Display cache hit message
|
|
82
|
-
const durationSecs = (passingRun.duration / 1000).toFixed(1);
|
|
83
|
-
console.log(chalk.green('✅ Validation already passed for current working tree'));
|
|
84
|
-
console.log(chalk.gray(` Tree hash: ${treeHashBefore.substring(0, 12)}...`));
|
|
85
|
-
console.log(chalk.gray(` Last validated: ${passingRun.timestamp}`));
|
|
86
|
-
console.log(chalk.gray(` Duration: ${durationSecs}s`));
|
|
87
|
-
console.log(chalk.gray(` Branch: ${passingRun.branch}`));
|
|
88
|
-
if (passingRun.result?.phases) {
|
|
89
|
-
const totalSteps = passingRun.result.phases.reduce((sum, phase) => sum + (phase.steps?.length || 0), 0);
|
|
90
|
-
console.log(chalk.gray(` Phases: ${passingRun.result.phases.length}, Steps: ${totalSteps}`));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Cache hit - return early without calling process.exit
|
|
94
|
-
// This allows tests to complete without throwing process.exit errors
|
|
95
|
-
// In production, Commander will exit with code 0
|
|
96
|
-
// Mark result as from cache so caller knows not to call process.exit
|
|
97
|
-
const result = passingRun.result;
|
|
98
|
-
result._fromCache = true;
|
|
99
|
-
return result;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch (_error) {
|
|
104
|
-
// Cache check failed - proceed with validation
|
|
105
|
-
// This is expected for first-time validation
|
|
206
|
+
const cachedResult = await checkCache(treeHashBefore, yaml);
|
|
207
|
+
if (cachedResult) {
|
|
208
|
+
return cachedResult;
|
|
106
209
|
}
|
|
107
210
|
}
|
|
108
|
-
// Display tree hash before running validation
|
|
109
|
-
// This goes to stderr, so it's visible even in YAML mode
|
|
211
|
+
// Display tree hash before running validation
|
|
110
212
|
if (treeHashBefore) {
|
|
111
213
|
console.error(chalk.gray(`🌳 Working tree: ${treeHashBefore.slice(0, 12)}...`));
|
|
112
214
|
if (!yaml) {
|
|
@@ -115,37 +217,9 @@ export async function runValidateWorkflow(config, options) {
|
|
|
115
217
|
}
|
|
116
218
|
// Run validation
|
|
117
219
|
const result = await runValidation(runnerConfig);
|
|
118
|
-
// Record validation history (if in git repo
|
|
220
|
+
// Record validation history (if in git repo)
|
|
119
221
|
if (treeHashBefore) {
|
|
120
|
-
|
|
121
|
-
// Check if worktree changed during validation
|
|
122
|
-
const stability = await checkWorktreeStability(treeHashBefore);
|
|
123
|
-
if (!stability.stable) {
|
|
124
|
-
console.warn(chalk.yellow('\n⚠️ Worktree changed during validation'));
|
|
125
|
-
console.warn(chalk.yellow(` Before: ${stability.treeHashBefore.slice(0, 12)}...`));
|
|
126
|
-
console.warn(chalk.yellow(` After: ${stability.treeHashAfter.slice(0, 12)}...`));
|
|
127
|
-
console.warn(chalk.yellow(' Results valid but history not recorded (unstable state)'));
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
// Record to git notes
|
|
131
|
-
const recordResult = await recordValidationHistory(treeHashBefore, result);
|
|
132
|
-
if (recordResult.recorded) {
|
|
133
|
-
if (verbose) {
|
|
134
|
-
console.log(chalk.gray(`\n📝 History recorded (tree: ${treeHashBefore.slice(0, 12)})`));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else if (verbose) {
|
|
138
|
-
console.warn(chalk.yellow(`⚠️ History recording failed: ${recordResult.reason}`));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
// Silent failure - don't block validation
|
|
144
|
-
if (verbose) {
|
|
145
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
146
|
-
console.warn(chalk.yellow(`⚠️ History recording error: ${errorMessage}`));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
222
|
+
await recordHistory(treeHashBefore, result, verbose);
|
|
149
223
|
}
|
|
150
224
|
// Proactive health check (non-blocking)
|
|
151
225
|
try {
|
|
@@ -160,58 +234,11 @@ export async function runValidateWorkflow(config, options) {
|
|
|
160
234
|
}
|
|
161
235
|
// If validation failed, show agent-friendly error details
|
|
162
236
|
if (!result.passed) {
|
|
163
|
-
|
|
164
|
-
if (result.rerunCommand) {
|
|
165
|
-
console.error(chalk.blue('🔄 To retry:'), chalk.white(result.rerunCommand));
|
|
166
|
-
}
|
|
167
|
-
if (result.fullLogFile) {
|
|
168
|
-
console.error(chalk.blue('📄 Full log:'), chalk.gray(result.fullLogFile));
|
|
169
|
-
}
|
|
170
|
-
// Context-aware extraction quality feedback (only when developerFeedback is enabled)
|
|
171
|
-
if (config.developerFeedback) {
|
|
172
|
-
// Check if any steps had poor extraction quality
|
|
173
|
-
const poorExtractionSteps = result.phases
|
|
174
|
-
?.flatMap(phase => phase.steps || [])
|
|
175
|
-
.filter(step => !step.passed && step.extractionQuality && step.extractionQuality.score < 50);
|
|
176
|
-
if (poorExtractionSteps && poorExtractionSteps.length > 0) {
|
|
177
|
-
// Detect if we're dogfooding (in the vibe-validate project itself)
|
|
178
|
-
const isDogfooding = process.cwd().includes('vibe-validate');
|
|
179
|
-
console.error('');
|
|
180
|
-
console.error(chalk.yellow('⚠️ Poor extraction quality detected'));
|
|
181
|
-
if (isDogfooding) {
|
|
182
|
-
// Developing vibe-validate itself: direct contributor call-to-action
|
|
183
|
-
console.error(chalk.yellow(' 💡 vibe-validate improvement opportunity: Improve extractors in packages/extractors/'));
|
|
184
|
-
console.error(chalk.gray(' See packages/extractors/test/samples/ for how to add test cases'));
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
// External project: user feedback to improve vibe-validate
|
|
188
|
-
console.error(chalk.yellow(' 💡 Help improve vibe-validate by reporting this extraction issue'));
|
|
189
|
-
console.error(chalk.gray(' https://github.com/anthropics/vibe-validate/issues/new?template=extractor-improvement.yml'));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
237
|
+
displayFailureInfo(result, config);
|
|
193
238
|
}
|
|
194
239
|
// Output YAML validation result if --yaml flag is set
|
|
195
240
|
if (yaml) {
|
|
196
|
-
|
|
197
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
198
|
-
// Output YAML document separator (RFC 4627) to mark transition from stderr to stdout
|
|
199
|
-
process.stdout.write('---\n');
|
|
200
|
-
// Output pure YAML without headers (workflow provides display framing)
|
|
201
|
-
process.stdout.write(yamlStringify(result));
|
|
202
|
-
// CRITICAL: Wait for stdout to flush before exiting
|
|
203
|
-
// When stdout is redirected to a file (CI), process.exit() can kill the process
|
|
204
|
-
// before the write buffer is flushed, causing truncated output
|
|
205
|
-
await new Promise(resolve => {
|
|
206
|
-
if (process.stdout.write('')) {
|
|
207
|
-
// Write buffer is empty, can exit immediately
|
|
208
|
-
resolve();
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
// Wait for drain event
|
|
212
|
-
process.stdout.once('drain', resolve);
|
|
213
|
-
}
|
|
214
|
-
});
|
|
241
|
+
await outputYaml(result);
|
|
215
242
|
}
|
|
216
243
|
return result;
|
|
217
244
|
}
|
|
@@ -225,20 +252,7 @@ export async function runValidateWorkflow(config, options) {
|
|
|
225
252
|
error: error instanceof Error ? error.message : String(error),
|
|
226
253
|
errorStack: error instanceof Error ? error.stack : undefined,
|
|
227
254
|
};
|
|
228
|
-
|
|
229
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
230
|
-
// Output YAML document separator
|
|
231
|
-
process.stdout.write('---\n');
|
|
232
|
-
process.stdout.write(yamlStringify(errorResult));
|
|
233
|
-
// Wait for stdout to flush before exiting
|
|
234
|
-
await new Promise(resolve => {
|
|
235
|
-
if (process.stdout.write('')) {
|
|
236
|
-
resolve();
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
process.stdout.once('drain', resolve);
|
|
240
|
-
}
|
|
241
|
-
});
|
|
255
|
+
await outputYaml(errorResult);
|
|
242
256
|
}
|
|
243
257
|
// Re-throw to allow caller to handle exit
|
|
244
258
|
throw error;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-workflow.js","sourceRoot":"","sources":["../../src/utils/validate-workflow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAUlD
|
|
1
|
+
{"version":3,"file":"validate-workflow.js","sourceRoot":"","sources":["../../src/utils/validate-workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Cache Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides git tree hash-based caching for validation results.
|
|
5
|
+
* Used by both validate and pre-commit commands to avoid redundant validation.
|
|
6
|
+
*/
|
|
7
|
+
import type { ValidationResult } from '@vibe-validate/core';
|
|
8
|
+
export interface CacheCheckResult {
|
|
9
|
+
/** Whether a cached passing result was found */
|
|
10
|
+
cacheHit: boolean;
|
|
11
|
+
/** The git tree hash that was checked */
|
|
12
|
+
treeHash: string | null;
|
|
13
|
+
/** The cached validation result (if cache hit) */
|
|
14
|
+
cachedResult?: ValidationResult;
|
|
15
|
+
/** Metadata about the cached run */
|
|
16
|
+
cachedRun?: {
|
|
17
|
+
timestamp: string;
|
|
18
|
+
duration: number;
|
|
19
|
+
branch: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if validation has already passed for the current working tree.
|
|
24
|
+
* Returns cache hit info including the cached result if found.
|
|
25
|
+
*
|
|
26
|
+
* @param force - If true, bypass cache and force re-validation
|
|
27
|
+
* @returns Cache check result with tree hash and optional cached result
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkValidationCache(force?: boolean): Promise<CacheCheckResult>;
|
|
30
|
+
//# sourceMappingURL=validation-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-cache.d.ts","sourceRoot":"","sources":["../../src/utils/validation-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,EAAE,OAAO,CAAC;IAElB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,kDAAkD;IAClD,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAEhC,oCAAoC;IACpC,SAAS,CAAC,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2CnF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Cache Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides git tree hash-based caching for validation results.
|
|
5
|
+
* Used by both validate and pre-commit commands to avoid redundant validation.
|
|
6
|
+
*/
|
|
7
|
+
import { getGitTreeHash } from '@vibe-validate/git';
|
|
8
|
+
import { readHistoryNote } from '@vibe-validate/history';
|
|
9
|
+
/**
|
|
10
|
+
* Check if validation has already passed for the current working tree.
|
|
11
|
+
* Returns cache hit info including the cached result if found.
|
|
12
|
+
*
|
|
13
|
+
* @param force - If true, bypass cache and force re-validation
|
|
14
|
+
* @returns Cache check result with tree hash and optional cached result
|
|
15
|
+
*/
|
|
16
|
+
export async function checkValidationCache(force = false) {
|
|
17
|
+
// Get tree hash for current working directory
|
|
18
|
+
let treeHash = null;
|
|
19
|
+
try {
|
|
20
|
+
treeHash = await getGitTreeHash();
|
|
21
|
+
}
|
|
22
|
+
catch (_error) {
|
|
23
|
+
// Not in git repo or git command failed
|
|
24
|
+
return { cacheHit: false, treeHash: null };
|
|
25
|
+
}
|
|
26
|
+
// If force flag set, skip cache check
|
|
27
|
+
if (force) {
|
|
28
|
+
return { cacheHit: false, treeHash };
|
|
29
|
+
}
|
|
30
|
+
// Check git notes for cached validation result
|
|
31
|
+
try {
|
|
32
|
+
const historyNote = await readHistoryNote(treeHash);
|
|
33
|
+
if (historyNote && historyNote.runs.length > 0) {
|
|
34
|
+
// Find most recent passing run
|
|
35
|
+
const passingRun = [...historyNote.runs]
|
|
36
|
+
.reverse()
|
|
37
|
+
.find(run => run.passed);
|
|
38
|
+
if (passingRun && passingRun.result) {
|
|
39
|
+
return {
|
|
40
|
+
cacheHit: true,
|
|
41
|
+
treeHash,
|
|
42
|
+
cachedResult: passingRun.result,
|
|
43
|
+
cachedRun: {
|
|
44
|
+
timestamp: passingRun.timestamp,
|
|
45
|
+
duration: passingRun.duration,
|
|
46
|
+
branch: passingRun.branch,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (_error) {
|
|
53
|
+
// Cache read failed - proceed without cache
|
|
54
|
+
}
|
|
55
|
+
return { cacheHit: false, treeHash };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=validation-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-cache.js","sourceRoot":"","sources":["../../src/utils/validation-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAqBzD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAAK,GAAG,KAAK;IACtD,8CAA8C;IAC9C,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,wCAAwC;QACxC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7C,CAAC;IAED,sCAAsC;IACtC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IACvC,CAAC;IAED,+CAA+C;IAC/C,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;QAEpD,IAAI,WAAW,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,+BAA+B;YAC/B,MAAM,UAAU,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC;iBACrC,OAAO,EAAE;iBACT,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE3B,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;gBACpC,OAAO;oBACL,QAAQ,EAAE,IAAI;oBACd,QAAQ;oBACR,YAAY,EAAE,UAAU,CAAC,MAAM;oBAC/B,SAAS,EAAE;wBACT,SAAS,EAAE,UAAU,CAAC,SAAS;wBAC/B,QAAQ,EAAE,UAAU,CAAC,QAAQ;wBAC7B,MAAM,EAAE,UAAU,CAAC,MAAM;qBAC1B;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,4CAA4C;IAC9C,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACvC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-validate/cli",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
4
4
|
"description": "Command-line interface for vibe-validate validation framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,11 +60,11 @@
|
|
|
60
60
|
"yaml": "^2.6.1",
|
|
61
61
|
"zod": "^3.24.1",
|
|
62
62
|
"zod-to-json-schema": "^3.24.6",
|
|
63
|
-
"@vibe-validate/
|
|
64
|
-
"@vibe-validate/
|
|
65
|
-
"@vibe-validate/extractors": "0.14.
|
|
66
|
-
"@vibe-validate/
|
|
67
|
-
"@vibe-validate/history": "0.14.
|
|
63
|
+
"@vibe-validate/config": "0.14.3",
|
|
64
|
+
"@vibe-validate/core": "0.14.3",
|
|
65
|
+
"@vibe-validate/extractors": "0.14.3",
|
|
66
|
+
"@vibe-validate/git": "0.14.3",
|
|
67
|
+
"@vibe-validate/history": "0.14.3"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/node": "^20.14.8",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"vitest": "^2.0.5"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
|
-
"build": "tsc && node dist/scripts/generate-watch-pr-schema.js
|
|
75
|
+
"build": "tsc && node dist/scripts/generate-watch-pr-schema.js",
|
|
76
76
|
"test": "vitest run",
|
|
77
77
|
"test:watch": "vitest",
|
|
78
78
|
"test:coverage": "vitest run --coverage",
|