@vibe-validate/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/bin.js +88 -13
- package/dist/bin.js.map +1 -1
- package/dist/commands/cleanup.d.ts +4 -0
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +94 -2
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +83 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +306 -28
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate-workflow.d.ts +4 -0
- package/dist/commands/generate-workflow.d.ts.map +1 -1
- package/dist/commands/generate-workflow.js +157 -48
- package/dist/commands/generate-workflow.js.map +1 -1
- package/dist/commands/history.d.ts +13 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +415 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +181 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pre-commit.d.ts +4 -0
- package/dist/commands/pre-commit.d.ts.map +1 -1
- package/dist/commands/pre-commit.js +158 -7
- package/dist/commands/pre-commit.js.map +1 -1
- package/dist/commands/state.d.ts +5 -1
- package/dist/commands/state.d.ts.map +1 -1
- package/dist/commands/state.js +192 -18
- package/dist/commands/state.js.map +1 -1
- package/dist/commands/sync-check.d.ts +4 -0
- package/dist/commands/sync-check.d.ts.map +1 -1
- package/dist/commands/sync-check.js +98 -2
- package/dist/commands/sync-check.js.map +1 -1
- package/dist/commands/validate.d.ts +5 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +184 -28
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/watch-pr.d.ts +4 -0
- package/dist/commands/watch-pr.d.ts.map +1 -1
- package/dist/commands/watch-pr.js +175 -14
- package/dist/commands/watch-pr.js.map +1 -1
- package/dist/schemas/watch-pr-schema.d.ts +40 -40
- package/dist/schemas/watch-pr-schema.js +1 -1
- package/dist/schemas/watch-pr-schema.js.map +1 -1
- package/dist/services/ci-provider.d.ts +13 -8
- package/dist/services/ci-provider.d.ts.map +1 -1
- package/dist/services/ci-providers/github-actions.d.ts +5 -4
- package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
- package/dist/services/ci-providers/github-actions.js +36 -27
- package/dist/services/ci-providers/github-actions.js.map +1 -1
- package/dist/utils/check-validation.d.ts +7 -4
- package/dist/utils/check-validation.d.ts.map +1 -1
- package/dist/utils/check-validation.js +129 -48
- package/dist/utils/check-validation.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.d.ts +1 -0
- package/dist/utils/runner-adapter.d.ts.map +1 -1
- package/dist/utils/runner-adapter.js +25 -17
- package/dist/utils/runner-adapter.js.map +1 -1
- package/dist/utils/setup-checks/gitignore-check.d.ts +10 -15
- package/dist/utils/setup-checks/gitignore-check.d.ts.map +1 -1
- package/dist/utils/setup-checks/gitignore-check.js +20 -137
- package/dist/utils/setup-checks/gitignore-check.js.map +1 -1
- package/dist/utils/validate-workflow.d.ts +28 -0
- package/dist/utils/validate-workflow.d.ts.map +1 -0
- package/dist/utils/validate-workflow.js +247 -0
- package/dist/utils/validate-workflow.js.map +1 -0
- 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 +16 -14
- package/watch-pr-result.schema.json +1 -1
- package/LICENSE +0 -21
|
@@ -1,155 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gitignore Setup Check
|
|
2
|
+
* Gitignore Setup Check (DEPRECATED)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* @deprecated Since v0.12.0 - State file (.vibe-validate-state.yaml) is deprecated.
|
|
5
|
+
* Validation history is now stored in git notes instead of a state file.
|
|
6
|
+
* This check always passes and does not modify .gitignore.
|
|
7
|
+
*
|
|
8
|
+
* Use `vibe-validate doctor` to detect and remove deprecated state file entries.
|
|
6
9
|
*/
|
|
7
|
-
import { readFile, writeFile } from 'fs/promises';
|
|
8
|
-
import { existsSync } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
import { splitLines } from '../normalize-line-endings.js';
|
|
11
|
-
const STATE_FILE_ENTRY = '.vibe-validate-state.yaml';
|
|
12
10
|
export class GitignoreSetupCheck {
|
|
13
11
|
id = 'gitignore';
|
|
14
|
-
name = 'Gitignore Setup';
|
|
15
|
-
async check(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Check if .gitignore exists
|
|
19
|
-
if (!existsSync(gitignorePath)) {
|
|
20
|
-
return {
|
|
21
|
-
passed: false,
|
|
22
|
-
message: '.gitignore not found',
|
|
23
|
-
suggestion: `Create .gitignore and add ${STATE_FILE_ENTRY}`,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
// Read .gitignore content
|
|
27
|
-
const content = await readFile(gitignorePath, 'utf-8');
|
|
28
|
-
// Check if state file entry exists (with flexible whitespace)
|
|
29
|
-
const hasEntry = splitLines(content)
|
|
30
|
-
.some(line => line.trim() === STATE_FILE_ENTRY);
|
|
31
|
-
if (!hasEntry) {
|
|
32
|
-
return {
|
|
33
|
-
passed: false,
|
|
34
|
-
message: `.gitignore missing ${STATE_FILE_ENTRY} entry`,
|
|
35
|
-
suggestion: `Add ${STATE_FILE_ENTRY} to .gitignore`,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
12
|
+
name = 'Gitignore Setup (deprecated)';
|
|
13
|
+
async check(_options) {
|
|
14
|
+
// DEPRECATED: State file is no longer used (git notes replaced it in v0.12.0)
|
|
15
|
+
// Always return passed - no .gitignore modifications needed
|
|
38
16
|
return {
|
|
39
17
|
passed: true,
|
|
40
|
-
message: '.gitignore
|
|
18
|
+
message: '.gitignore check skipped (state file deprecated in v0.12.0)',
|
|
41
19
|
};
|
|
42
20
|
}
|
|
43
|
-
async preview(
|
|
44
|
-
|
|
45
|
-
const gitignorePath = join(cwd, '.gitignore');
|
|
46
|
-
// Check current state
|
|
47
|
-
const checkResult = await this.check(options);
|
|
48
|
-
if (checkResult.passed) {
|
|
49
|
-
return {
|
|
50
|
-
description: '.gitignore already configured correctly',
|
|
51
|
-
filesAffected: [],
|
|
52
|
-
changes: [],
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
// If .gitignore doesn't exist
|
|
56
|
-
if (!existsSync(gitignorePath)) {
|
|
57
|
-
const content = this.generateNewGitignoreContent();
|
|
58
|
-
return {
|
|
59
|
-
description: 'Create new .gitignore with vibe-validate state file entry',
|
|
60
|
-
filesAffected: ['.gitignore'],
|
|
61
|
-
changes: [
|
|
62
|
-
{
|
|
63
|
-
file: '.gitignore',
|
|
64
|
-
action: 'create',
|
|
65
|
-
content,
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
// If .gitignore exists but missing entry
|
|
21
|
+
async preview(_options) {
|
|
22
|
+
// DEPRECATED: No .gitignore modifications needed (state file deprecated)
|
|
71
23
|
return {
|
|
72
|
-
description:
|
|
73
|
-
filesAffected: [
|
|
74
|
-
changes: [
|
|
75
|
-
{
|
|
76
|
-
file: '.gitignore',
|
|
77
|
-
action: 'modify',
|
|
78
|
-
},
|
|
79
|
-
],
|
|
24
|
+
description: 'Gitignore check deprecated (state file no longer used)',
|
|
25
|
+
filesAffected: [],
|
|
26
|
+
changes: [],
|
|
80
27
|
};
|
|
81
28
|
}
|
|
82
|
-
async fix(
|
|
83
|
-
|
|
84
|
-
const gitignorePath = join(cwd, '.gitignore');
|
|
85
|
-
const dryRun = options?.dryRun ?? false;
|
|
86
|
-
// Check current state
|
|
87
|
-
const checkResult = await this.check(options);
|
|
88
|
-
if (checkResult.passed && !options?.force) {
|
|
89
|
-
return {
|
|
90
|
-
success: true,
|
|
91
|
-
message: '.gitignore already configured correctly',
|
|
92
|
-
filesChanged: [],
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
if (dryRun) {
|
|
96
|
-
return {
|
|
97
|
-
success: true,
|
|
98
|
-
message: '[dry-run] Would update .gitignore',
|
|
99
|
-
filesChanged: [],
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
// If .gitignore doesn't exist, create it
|
|
103
|
-
if (!existsSync(gitignorePath)) {
|
|
104
|
-
const content = this.generateNewGitignoreContent();
|
|
105
|
-
await writeFile(gitignorePath, content, 'utf-8');
|
|
106
|
-
return {
|
|
107
|
-
success: true,
|
|
108
|
-
message: 'Created .gitignore with state file entry',
|
|
109
|
-
filesChanged: ['.gitignore'],
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// If .gitignore exists, add entry if missing
|
|
113
|
-
const content = await readFile(gitignorePath, 'utf-8');
|
|
114
|
-
const hasEntry = splitLines(content)
|
|
115
|
-
.some(line => line.trim() === STATE_FILE_ENTRY);
|
|
116
|
-
if (hasEntry) {
|
|
117
|
-
// Entry already exists (idempotent)
|
|
118
|
-
return {
|
|
119
|
-
success: true,
|
|
120
|
-
message: '.gitignore already contains state file entry',
|
|
121
|
-
filesChanged: [],
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
// Add entry to existing .gitignore
|
|
125
|
-
const updatedContent = this.addEntryToGitignore(content);
|
|
126
|
-
await writeFile(gitignorePath, updatedContent, 'utf-8');
|
|
29
|
+
async fix(_options) {
|
|
30
|
+
// DEPRECATED: No .gitignore modifications needed (state file deprecated)
|
|
127
31
|
return {
|
|
128
32
|
success: true,
|
|
129
|
-
message:
|
|
130
|
-
filesChanged: [
|
|
33
|
+
message: 'Gitignore check deprecated (state file no longer used)',
|
|
34
|
+
filesChanged: [],
|
|
131
35
|
};
|
|
132
36
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Generate content for a new .gitignore file
|
|
135
|
-
*/
|
|
136
|
-
generateNewGitignoreContent() {
|
|
137
|
-
return `# vibe-validate
|
|
138
|
-
${STATE_FILE_ENTRY}
|
|
139
|
-
`;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Add state file entry to existing .gitignore content
|
|
143
|
-
*/
|
|
144
|
-
addEntryToGitignore(content) {
|
|
145
|
-
// Ensure content ends with newline
|
|
146
|
-
let updatedContent = content;
|
|
147
|
-
if (!content.endsWith('\n')) {
|
|
148
|
-
updatedContent += '\n';
|
|
149
|
-
}
|
|
150
|
-
// Add vibe-validate section
|
|
151
|
-
updatedContent += `\n# vibe-validate\n${STATE_FILE_ENTRY}\n`;
|
|
152
|
-
return updatedContent;
|
|
153
|
-
}
|
|
154
37
|
}
|
|
155
38
|
//# sourceMappingURL=gitignore-check.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitignore-check.js","sourceRoot":"","sources":["../../../src/utils/setup-checks/gitignore-check.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"gitignore-check.js","sourceRoot":"","sources":["../../../src/utils/setup-checks/gitignore-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,OAAO,mBAAmB;IACrB,EAAE,GAAG,WAAW,CAAC;IACjB,IAAI,GAAG,8BAA8B,CAAC;IAE/C,KAAK,CAAC,KAAK,CAAC,QAAqB;QAC/B,8EAA8E;QAC9E,4DAA4D;QAC5D,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,6DAA6D;SACvE,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAqB;QACjC,yEAAyE;QACzE,OAAO;YACL,WAAW,EAAE,wDAAwD;YACrE,aAAa,EAAE,EAAE;YACjB,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAqB;QAC7B,yEAAyE;QACzE,OAAO;YACL,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,wDAAwD;YACjE,YAAY,EAAE,EAAE;SACjB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Validation Workflow
|
|
3
|
+
*
|
|
4
|
+
* Core validation logic used by both validate and pre-commit commands.
|
|
5
|
+
* Handles caching, history recording, and output formatting.
|
|
6
|
+
*/
|
|
7
|
+
import type { VibeValidateConfig } from '@vibe-validate/config';
|
|
8
|
+
import type { ValidationResult } from '@vibe-validate/core';
|
|
9
|
+
import type { AgentContext } from './context-detector.js';
|
|
10
|
+
export interface ValidateWorkflowOptions {
|
|
11
|
+
force?: boolean;
|
|
12
|
+
verbose?: boolean;
|
|
13
|
+
yaml?: boolean;
|
|
14
|
+
check?: boolean;
|
|
15
|
+
context: AgentContext;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execute validation workflow with caching, history recording, and output formatting.
|
|
19
|
+
*
|
|
20
|
+
* This is the shared implementation used by both `validate` and `pre-commit` commands.
|
|
21
|
+
*
|
|
22
|
+
* @param config - Loaded vibe-validate configuration
|
|
23
|
+
* @param options - Validation options (force, verbose, yaml, check, context)
|
|
24
|
+
* @returns Validation result
|
|
25
|
+
* @throws Error if validation encounters fatal error
|
|
26
|
+
*/
|
|
27
|
+
export declare function runValidateWorkflow(config: VibeValidateConfig, options: ValidateWorkflowOptions): Promise<ValidationResult>;
|
|
28
|
+
//# sourceMappingURL=validate-workflow.d.ts.map
|
|
@@ -0,0 +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;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAmP3B"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Validation Workflow
|
|
3
|
+
*
|
|
4
|
+
* Core validation logic used by both validate and pre-commit commands.
|
|
5
|
+
* Handles caching, history recording, and output formatting.
|
|
6
|
+
*/
|
|
7
|
+
import { runValidation } from '@vibe-validate/core';
|
|
8
|
+
import { getGitTreeHash } from '@vibe-validate/git';
|
|
9
|
+
import { recordValidationHistory, checkWorktreeStability, checkHistoryHealth, readHistoryNote, } from '@vibe-validate/history';
|
|
10
|
+
import { createRunnerConfig } from './runner-adapter.js';
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
import { stringify as yamlStringify } from 'yaml';
|
|
13
|
+
/**
|
|
14
|
+
* Execute validation workflow with caching, history recording, and output formatting.
|
|
15
|
+
*
|
|
16
|
+
* This is the shared implementation used by both `validate` and `pre-commit` commands.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Loaded vibe-validate configuration
|
|
19
|
+
* @param options - Validation options (force, verbose, yaml, check, context)
|
|
20
|
+
* @returns Validation result
|
|
21
|
+
* @throws Error if validation encounters fatal error
|
|
22
|
+
*/
|
|
23
|
+
export async function runValidateWorkflow(config, options) {
|
|
24
|
+
try {
|
|
25
|
+
// If --check flag is used, only check validation state without running
|
|
26
|
+
if (options.check) {
|
|
27
|
+
const yaml = options.yaml ?? false;
|
|
28
|
+
const { checkValidationStatus } = await import('./check-validation.js');
|
|
29
|
+
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
|
+
throw new Error('checkValidationStatus should have exited');
|
|
33
|
+
}
|
|
34
|
+
const verbose = options.verbose ?? false;
|
|
35
|
+
const yaml = options.yaml ?? false;
|
|
36
|
+
// Create runner config
|
|
37
|
+
const runnerConfig = createRunnerConfig(config, {
|
|
38
|
+
force: options.force,
|
|
39
|
+
verbose,
|
|
40
|
+
yaml,
|
|
41
|
+
context: options.context,
|
|
42
|
+
});
|
|
43
|
+
// Get tree hash BEFORE validation (for caching and stability check)
|
|
44
|
+
let treeHashBefore = null;
|
|
45
|
+
try {
|
|
46
|
+
treeHashBefore = await getGitTreeHash();
|
|
47
|
+
}
|
|
48
|
+
catch (_error) {
|
|
49
|
+
// Not in git repo or git command failed - continue without history
|
|
50
|
+
if (verbose) {
|
|
51
|
+
console.warn(chalk.yellow('⚠️ Could not get git tree hash - history recording disabled'));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Check cache: if validation already passed for this tree hash, skip re-running
|
|
55
|
+
if (treeHashBefore && !options.force) {
|
|
56
|
+
try {
|
|
57
|
+
const historyNote = await readHistoryNote(treeHashBefore);
|
|
58
|
+
if (historyNote && historyNote.runs.length > 0) {
|
|
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
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Display tree hash before running validation (debugging/transparency aid)
|
|
109
|
+
// This goes to stderr, so it's visible even in YAML mode
|
|
110
|
+
if (treeHashBefore) {
|
|
111
|
+
console.error(chalk.gray(`🌳 Working tree: ${treeHashBefore.slice(0, 12)}...`));
|
|
112
|
+
if (!yaml) {
|
|
113
|
+
console.log(''); // Blank line for readability (human mode only)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Run validation
|
|
117
|
+
const result = await runValidation(runnerConfig);
|
|
118
|
+
// Record validation history (if in git repo and stability check passes)
|
|
119
|
+
if (treeHashBefore) {
|
|
120
|
+
try {
|
|
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
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Proactive health check (non-blocking)
|
|
151
|
+
try {
|
|
152
|
+
const health = await checkHistoryHealth();
|
|
153
|
+
if (health.shouldWarn) {
|
|
154
|
+
console.log('');
|
|
155
|
+
console.log(chalk.blue(health.warningMessage));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Silent failure - don't block validation
|
|
160
|
+
}
|
|
161
|
+
// If validation failed, show agent-friendly error details
|
|
162
|
+
if (!result.passed) {
|
|
163
|
+
console.error(chalk.blue('\n📋 View error details:'), chalk.white('vibe-validate state'));
|
|
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
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Output YAML validation result if --yaml flag is set
|
|
195
|
+
if (yaml) {
|
|
196
|
+
// Small delay to ensure stderr is flushed before writing to stdout
|
|
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
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.error(chalk.red('❌ Validation failed with error:'), error);
|
|
220
|
+
// If YAML mode, output error as YAML to stdout for CI extraction
|
|
221
|
+
if (options.yaml) {
|
|
222
|
+
const errorResult = {
|
|
223
|
+
passed: false,
|
|
224
|
+
timestamp: new Date().toISOString(),
|
|
225
|
+
error: error instanceof Error ? error.message : String(error),
|
|
226
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
227
|
+
};
|
|
228
|
+
// Small delay to ensure stderr is flushed before writing to stdout
|
|
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
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// Re-throw to allow caller to handle exit
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=validate-workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Command-line interface for vibe-validate validation framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,6 +20,14 @@
|
|
|
20
20
|
"watch-pr-result.schema.json",
|
|
21
21
|
"README.md"
|
|
22
22
|
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc && node dist/scripts/generate-watch-pr-schema.js",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"test:coverage": "vitest run --coverage",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"lint": "eslint src/ --max-warnings 0"
|
|
30
|
+
},
|
|
23
31
|
"keywords": [
|
|
24
32
|
"validation",
|
|
25
33
|
"testing",
|
|
@@ -54,26 +62,20 @@
|
|
|
54
62
|
"access": "public"
|
|
55
63
|
},
|
|
56
64
|
"dependencies": {
|
|
65
|
+
"@vibe-validate/config": "workspace:*",
|
|
66
|
+
"@vibe-validate/core": "workspace:*",
|
|
67
|
+
"@vibe-validate/extractors": "workspace:*",
|
|
68
|
+
"@vibe-validate/git": "workspace:*",
|
|
69
|
+
"@vibe-validate/history": "workspace:*",
|
|
57
70
|
"chalk": "^5.3.0",
|
|
58
71
|
"commander": "^12.1.0",
|
|
59
72
|
"yaml": "^2.6.1",
|
|
60
73
|
"zod": "^3.24.1",
|
|
61
|
-
"zod-to-json-schema": "^3.24.6"
|
|
62
|
-
"@vibe-validate/config": "0.11.0",
|
|
63
|
-
"@vibe-validate/git": "0.11.0",
|
|
64
|
-
"@vibe-validate/core": "0.11.0"
|
|
74
|
+
"zod-to-json-schema": "^3.24.6"
|
|
65
75
|
},
|
|
66
76
|
"devDependencies": {
|
|
67
77
|
"@types/node": "^20.14.8",
|
|
68
78
|
"typescript": "^5.5.2",
|
|
69
79
|
"vitest": "^2.0.5"
|
|
70
|
-
},
|
|
71
|
-
"scripts": {
|
|
72
|
-
"build": "tsc && node dist/scripts/generate-watch-pr-schema.js",
|
|
73
|
-
"test": "vitest run",
|
|
74
|
-
"test:watch": "vitest",
|
|
75
|
-
"test:coverage": "vitest run --coverage",
|
|
76
|
-
"typecheck": "tsc --noEmit",
|
|
77
|
-
"lint": "eslint src/ --max-warnings 0"
|
|
78
80
|
}
|
|
79
|
-
}
|
|
81
|
+
}
|