specweave 0.23.2 → 0.23.5
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/CLAUDE.md +367 -0
- package/dist/plugins/specweave/lib/utils/fs-native.d.ts +133 -0
- package/dist/plugins/specweave/lib/utils/fs-native.d.ts.map +1 -0
- package/dist/plugins/specweave/lib/utils/fs-native.js +224 -0
- package/dist/plugins/specweave/lib/utils/fs-native.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +52 -20
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +24 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -1
- package/dist/src/cli/helpers/init/initial-increment-generator.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/initial-increment-generator.js +2 -1
- package/dist/src/cli/helpers/init/initial-increment-generator.js.map +1 -1
- package/dist/src/core/ac-test-validator-cli.d.ts +16 -0
- package/dist/src/core/ac-test-validator-cli.d.ts.map +1 -0
- package/dist/src/core/ac-test-validator-cli.js +118 -0
- package/dist/src/core/ac-test-validator-cli.js.map +1 -0
- package/dist/src/core/ac-test-validator.d.ts +111 -0
- package/dist/src/core/ac-test-validator.d.ts.map +1 -0
- package/dist/src/core/ac-test-validator.js +292 -0
- package/dist/src/core/ac-test-validator.js.map +1 -0
- package/dist/src/core/increment/desync-detector.d.ts +142 -0
- package/dist/src/core/increment/desync-detector.d.ts.map +1 -0
- package/dist/src/core/increment/desync-detector.js +270 -0
- package/dist/src/core/increment/desync-detector.js.map +1 -0
- package/dist/src/core/increment/metadata-manager.d.ts +8 -4
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +45 -21
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/qa/qa-runner.js +9 -2
- package/dist/src/core/qa/qa-runner.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +1 -1
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +40 -2
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/utils/fs-native.d.ts +133 -0
- package/dist/src/utils/fs-native.d.ts.map +1 -0
- package/dist/src/utils/fs-native.js +224 -0
- package/dist/src/utils/fs-native.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +12 -0
- package/plugins/specweave/agents/AGENTS-INDEX.md +216 -0
- package/plugins/specweave/agents/architect/AGENT.md +17 -0
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +16 -0
- package/plugins/specweave/agents/docs-writer/AGENT.md +16 -0
- package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +704 -0
- package/plugins/specweave/agents/infrastructure/AGENT.md +16 -0
- package/plugins/specweave/agents/performance/AGENT.md +16 -0
- package/plugins/specweave/agents/pm/AGENT.md +17 -0
- package/plugins/specweave/agents/qa-lead/AGENT.md +15 -0
- package/plugins/specweave/agents/reflective-reviewer/AGENT.md +16 -0
- package/plugins/specweave/agents/security/AGENT.md +16 -0
- package/plugins/specweave/agents/tdd-orchestrator/AGENT.md +16 -0
- package/plugins/specweave/agents/tech-lead/AGENT.md +16 -0
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +16 -0
- package/plugins/specweave/agents/translator/AGENT.md +13 -0
- package/plugins/specweave/commands/specweave-done.md +14 -0
- package/plugins/specweave/commands/specweave-qa.md +11 -1
- package/plugins/specweave/commands/specweave-sync-status.md +356 -0
- package/plugins/specweave/commands/specweave-validate.md +10 -1
- package/plugins/specweave/hooks/pre-task-completion.sh +196 -0
- package/plugins/specweave/lib/hooks/git-diff-analyzer.js +3 -3
- package/plugins/specweave/lib/hooks/git-diff-analyzer.ts +3 -3
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js +3 -2
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts +3 -2
- package/plugins/specweave/lib/hooks/prepare-reflection-context.js +3 -3
- package/plugins/specweave/lib/hooks/prepare-reflection-context.ts +3 -3
- package/plugins/specweave/lib/hooks/reflection-config-loader.js +4 -4
- package/plugins/specweave/lib/hooks/reflection-config-loader.ts +4 -4
- package/plugins/specweave/lib/hooks/reflection-storage.js +9 -9
- package/plugins/specweave/lib/hooks/reflection-storage.ts +9 -9
- package/plugins/specweave/lib/hooks/sync-cache.js +9 -8
- package/plugins/specweave/lib/hooks/sync-living-docs.js +57 -6
- package/plugins/specweave/lib/hooks/sync-us-tasks.js +6 -6
- package/plugins/specweave/lib/hooks/translate-file.js +3 -2
- package/plugins/specweave/lib/hooks/translate-file.ts +3 -2
- package/plugins/specweave/lib/hooks/translate-living-docs.js +4 -3
- package/plugins/specweave/lib/hooks/translate-living-docs.ts +4 -3
- package/plugins/specweave/lib/hooks/update-tasks-md.js +3 -3
- package/plugins/specweave/lib/hooks/update-tasks-md.ts +3 -3
- package/plugins/specweave/lib/utils/fs-native.js +182 -0
- package/plugins/specweave/lib/utils/fs-native.ts +283 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +8 -4
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +45 -21
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -1
- package/plugins/specweave/skills/SKILLS-INDEX.md +26 -2
- package/plugins/specweave/skills/increment-planner/SKILL.md +2 -2
- package/plugins/specweave-ado/commands/specweave-ado-close-workitem.md +1 -1
- package/plugins/specweave-ado/commands/specweave-ado-create-workitem.md +1 -1
- package/plugins/specweave-ado/commands/specweave-ado-status.md +1 -1
- package/plugins/specweave-ado/commands/specweave-ado-sync.md +1 -1
- package/plugins/specweave-diagrams/agents/diagrams-architect/AGENT.md +1 -1
- package/plugins/specweave-diagrams/skills/diagrams-generator/SKILL.md +4 -4
- package/plugins/specweave-github/lib/github-client-v2.js +2 -1
- package/plugins/specweave-github/lib/github-client-v2.ts +1 -1
- package/plugins/specweave-github/lib/github-feature-sync.js +30 -17
- package/plugins/specweave-github/lib/github-feature-sync.ts +54 -24
- package/plugins/specweave-github/lib/user-story-issue-builder.js +24 -0
- package/plugins/specweave-github/lib/user-story-issue-builder.ts +33 -0
- package/plugins/specweave-mobile/README.md +1 -1
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +72 -0
- package/src/templates/CLAUDE.md.template +13 -0
- package/plugins/specweave/skills/task-builder/README.md +0 -84
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AC Test Validator CLI
|
|
4
|
+
*
|
|
5
|
+
* Command-line interface for validating Acceptance Criteria tests before task completion.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node ac-test-validator-cli.js <increment-id>
|
|
9
|
+
*
|
|
10
|
+
* Exit codes:
|
|
11
|
+
* 0 - All AC tests passed
|
|
12
|
+
* 1 - Validation failed (tests failed or missing)
|
|
13
|
+
* 2 - Configuration error (missing files, invalid setup)
|
|
14
|
+
*/
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import fs from 'fs-extra';
|
|
17
|
+
import { createACTestValidator } from './ac-test-validator.js';
|
|
18
|
+
import { parseTasksWithUSLinks, getAllTasks } from '../generators/spec/task-parser.js';
|
|
19
|
+
import chalk from 'chalk';
|
|
20
|
+
async function main() {
|
|
21
|
+
// Parse arguments
|
|
22
|
+
const incrementId = process.argv[2];
|
|
23
|
+
if (!incrementId) {
|
|
24
|
+
console.error(chalk.red('Error: Missing increment ID'));
|
|
25
|
+
console.error(chalk.gray('Usage: node ac-test-validator-cli.js <increment-id>'));
|
|
26
|
+
process.exit(2);
|
|
27
|
+
}
|
|
28
|
+
// Find project root
|
|
29
|
+
const projectRoot = process.cwd();
|
|
30
|
+
// Validate increment exists
|
|
31
|
+
const incrementPath = path.join(projectRoot, '.specweave/increments', incrementId);
|
|
32
|
+
if (!await fs.pathExists(incrementPath)) {
|
|
33
|
+
console.error(chalk.red(`Error: Increment not found: ${incrementId}`));
|
|
34
|
+
process.exit(2);
|
|
35
|
+
}
|
|
36
|
+
const tasksPath = path.join(incrementPath, 'tasks.md');
|
|
37
|
+
if (!await fs.pathExists(tasksPath)) {
|
|
38
|
+
console.error(chalk.red(`Error: tasks.md not found in ${incrementId}`));
|
|
39
|
+
process.exit(2);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
// Parse tasks
|
|
43
|
+
console.log(chalk.blue('\n[AC Test Validator]') + ' Parsing tasks...');
|
|
44
|
+
const tasksByUS = parseTasksWithUSLinks(tasksPath);
|
|
45
|
+
const tasks = getAllTasks(tasksByUS);
|
|
46
|
+
// Filter tasks being marked complete (looking for recently modified tasks)
|
|
47
|
+
// For now, validate ALL tasks with ACs
|
|
48
|
+
const tasksToValidate = tasks.filter(t => {
|
|
49
|
+
return t.satisfiesACs && t.satisfiesACs.length > 0 && t.status === 'completed';
|
|
50
|
+
});
|
|
51
|
+
if (tasksToValidate.length === 0) {
|
|
52
|
+
console.log(chalk.yellow('No completed tasks with Acceptance Criteria to validate.'));
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
console.log(chalk.blue(`Found ${tasksToValidate.length} completed task(s) with ACs to validate\n`));
|
|
56
|
+
// Create validator
|
|
57
|
+
const validator = await createACTestValidator(projectRoot);
|
|
58
|
+
// Validate each task
|
|
59
|
+
const results = [];
|
|
60
|
+
let allPassed = true;
|
|
61
|
+
for (const task of tasksToValidate) {
|
|
62
|
+
console.log(chalk.bold(`\nValidating ${task.id}: ${task.title}`));
|
|
63
|
+
const result = await validator.validateTask(task, projectRoot);
|
|
64
|
+
results.push(result);
|
|
65
|
+
// Display formatted result
|
|
66
|
+
console.log(validator.formatResult(result));
|
|
67
|
+
if (!result.passed) {
|
|
68
|
+
allPassed = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Overall summary
|
|
72
|
+
console.log(chalk.bold('\n' + '='.repeat(60)));
|
|
73
|
+
console.log(chalk.bold('OVERALL VALIDATION SUMMARY'));
|
|
74
|
+
console.log('='.repeat(60));
|
|
75
|
+
const totalTasks = results.length;
|
|
76
|
+
const passedTasks = results.filter(r => r.passed).length;
|
|
77
|
+
const failedTasks = totalTasks - passedTasks;
|
|
78
|
+
console.log(`Tasks Validated: ${totalTasks}`);
|
|
79
|
+
console.log(`Passed: ${chalk.green(passedTasks)}`);
|
|
80
|
+
console.log(`Failed: ${chalk.red(failedTasks)}`);
|
|
81
|
+
const totalACs = results.reduce((sum, r) => sum + r.summary.totalACs, 0);
|
|
82
|
+
const acsPassed = results.reduce((sum, r) => sum + r.summary.acsTested, 0);
|
|
83
|
+
const acsFailed = totalACs - acsPassed;
|
|
84
|
+
console.log(`\nTotal ACs: ${totalACs}`);
|
|
85
|
+
console.log(`ACs with Passing Tests: ${chalk.green(acsPassed)}`);
|
|
86
|
+
console.log(`ACs with Failing Tests: ${chalk.red(acsFailed)}`);
|
|
87
|
+
console.log('='.repeat(60));
|
|
88
|
+
if (allPassed) {
|
|
89
|
+
console.log(chalk.green.bold('\n✓ ALL VALIDATIONS PASSED\n'));
|
|
90
|
+
console.log(chalk.green('All Acceptance Criteria have passing tests.'));
|
|
91
|
+
console.log(chalk.green('Task completion allowed.\n'));
|
|
92
|
+
process.exit(0);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log(chalk.red.bold('\n✗ VALIDATION FAILED\n'));
|
|
96
|
+
console.log(chalk.red('Some Acceptance Criteria have failing or missing tests.'));
|
|
97
|
+
console.log(chalk.red('Task completion blocked until all tests pass.\n'));
|
|
98
|
+
console.log(chalk.yellow('Fix the failing tests and try again.'));
|
|
99
|
+
console.log(chalk.gray('Run tests manually: npm test\n'));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
console.error(chalk.red('\nValidation Error:'));
|
|
105
|
+
console.error(chalk.red(error.message));
|
|
106
|
+
if (error.stack) {
|
|
107
|
+
console.error(chalk.gray('\nStack trace:'));
|
|
108
|
+
console.error(chalk.gray(error.stack));
|
|
109
|
+
}
|
|
110
|
+
process.exit(2);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Run CLI
|
|
114
|
+
main().catch(error => {
|
|
115
|
+
console.error(chalk.red('Fatal error:'), error);
|
|
116
|
+
process.exit(2);
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=ac-test-validator-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ac-test-validator-cli.js","sourceRoot":"","sources":["../../../src/core/ac-test-validator-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AC Test Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates that all Acceptance Criteria linked to a task have passing tests
|
|
5
|
+
* before allowing the task to be marked complete.
|
|
6
|
+
*
|
|
7
|
+
* **CRITICAL QUALITY GATE**: This is the enforcement point that prevents
|
|
8
|
+
* tasks from being marked complete without validated ACs.
|
|
9
|
+
*
|
|
10
|
+
* Workflow:
|
|
11
|
+
* 1. Task completion requested via TodoWrite
|
|
12
|
+
* 2. Validator extracts task's satisfiesACs field
|
|
13
|
+
* 3. Validator finds corresponding test files from Test Plan section
|
|
14
|
+
* 4. Validator runs tests using configured test runner (vitest/jest)
|
|
15
|
+
* 5. If ALL tests pass → Allow completion, auto-check ACs in spec.md
|
|
16
|
+
* 6. If ANY test fails → Block completion, show detailed error
|
|
17
|
+
*/
|
|
18
|
+
import { Task } from '../generators/spec/task-parser.js';
|
|
19
|
+
/**
|
|
20
|
+
* Test validation result
|
|
21
|
+
*/
|
|
22
|
+
export interface ACTestValidationResult {
|
|
23
|
+
/** Whether all tests passed */
|
|
24
|
+
passed: boolean;
|
|
25
|
+
/** Task ID being validated */
|
|
26
|
+
taskId: string;
|
|
27
|
+
/** AC-IDs this task satisfies */
|
|
28
|
+
acIds: string[];
|
|
29
|
+
/** Test results by AC-ID */
|
|
30
|
+
testResults: Map<string, ACTestResult>;
|
|
31
|
+
/** Overall summary */
|
|
32
|
+
summary: {
|
|
33
|
+
totalACs: number;
|
|
34
|
+
acsTested: number;
|
|
35
|
+
acsUntested: number;
|
|
36
|
+
testsPassed: number;
|
|
37
|
+
testsFailed: number;
|
|
38
|
+
};
|
|
39
|
+
/** Detailed error messages (if validation failed) */
|
|
40
|
+
errors: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Test result for a single AC
|
|
44
|
+
*/
|
|
45
|
+
export interface ACTestResult {
|
|
46
|
+
acId: string;
|
|
47
|
+
testFile?: string;
|
|
48
|
+
testCases: string[];
|
|
49
|
+
passed: boolean;
|
|
50
|
+
duration: number;
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Test runner configuration
|
|
55
|
+
*/
|
|
56
|
+
export interface TestRunnerConfig {
|
|
57
|
+
/** Test runner command (e.g., "npm test", "vitest run") */
|
|
58
|
+
command: string;
|
|
59
|
+
/** Test file pattern (glob pattern for test files) */
|
|
60
|
+
pattern: string;
|
|
61
|
+
/** Working directory for test execution */
|
|
62
|
+
cwd: string;
|
|
63
|
+
/** Environment variables for test execution */
|
|
64
|
+
env?: Record<string, string>;
|
|
65
|
+
/** Timeout in milliseconds (default: 30000) */
|
|
66
|
+
timeout?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* AC Test Validator - Core validation engine
|
|
70
|
+
*/
|
|
71
|
+
export declare class ACTestValidator {
|
|
72
|
+
private config;
|
|
73
|
+
constructor(config: TestRunnerConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Validate all ACs for a task have passing tests
|
|
76
|
+
*
|
|
77
|
+
* @param task - Task to validate (must have satisfiesACs field)
|
|
78
|
+
* @param projectRoot - Project root directory
|
|
79
|
+
* @returns Validation result
|
|
80
|
+
*/
|
|
81
|
+
validateTask(task: Task, projectRoot: string): Promise<ACTestValidationResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Validate a single AC has passing tests
|
|
84
|
+
*/
|
|
85
|
+
private validateAC;
|
|
86
|
+
/**
|
|
87
|
+
* Build test command with AC-ID filter
|
|
88
|
+
*/
|
|
89
|
+
private buildTestCommand;
|
|
90
|
+
/**
|
|
91
|
+
* Extract test case names from test output
|
|
92
|
+
*/
|
|
93
|
+
private extractTestCases;
|
|
94
|
+
/**
|
|
95
|
+
* Extract failure message from test output
|
|
96
|
+
*/
|
|
97
|
+
private extractFailureMessage;
|
|
98
|
+
/**
|
|
99
|
+
* Extract test file path from task description (Test Plan section)
|
|
100
|
+
*/
|
|
101
|
+
private extractTestFile;
|
|
102
|
+
/**
|
|
103
|
+
* Format validation result for display
|
|
104
|
+
*/
|
|
105
|
+
formatResult(result: ACTestValidationResult): string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create AC test validator from project config
|
|
109
|
+
*/
|
|
110
|
+
export declare function createACTestValidator(projectRoot: string): Promise<ACTestValidator>;
|
|
111
|
+
//# sourceMappingURL=ac-test-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ac-test-validator.d.ts","sourceRoot":"","sources":["../../../src/core/ac-test-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,mCAAmC,CAAC;AASzD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;IAEhB,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IAEf,iCAAiC;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAEhB,4BAA4B;IAC5B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEvC,sBAAsB;IACtB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF,qDAAqD;IACrD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAEhB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IAEZ,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,EAAE,gBAAgB;IAOpC;;;;;;OAMG;IACG,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiEpF;;OAEG;YACW,UAAU;IA2DxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAiB7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM;CA0DrD;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAwBzF"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AC Test Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates that all Acceptance Criteria linked to a task have passing tests
|
|
5
|
+
* before allowing the task to be marked complete.
|
|
6
|
+
*
|
|
7
|
+
* **CRITICAL QUALITY GATE**: This is the enforcement point that prevents
|
|
8
|
+
* tasks from being marked complete without validated ACs.
|
|
9
|
+
*
|
|
10
|
+
* Workflow:
|
|
11
|
+
* 1. Task completion requested via TodoWrite
|
|
12
|
+
* 2. Validator extracts task's satisfiesACs field
|
|
13
|
+
* 3. Validator finds corresponding test files from Test Plan section
|
|
14
|
+
* 4. Validator runs tests using configured test runner (vitest/jest)
|
|
15
|
+
* 5. If ALL tests pass → Allow completion, auto-check ACs in spec.md
|
|
16
|
+
* 6. If ANY test fails → Block completion, show detailed error
|
|
17
|
+
*/
|
|
18
|
+
import { exec } from 'child_process';
|
|
19
|
+
import { promisify } from 'util';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import fs from 'fs-extra';
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
const execAsync = promisify(exec);
|
|
24
|
+
/**
|
|
25
|
+
* AC Test Validator - Core validation engine
|
|
26
|
+
*/
|
|
27
|
+
export class ACTestValidator {
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.config = {
|
|
30
|
+
timeout: 30000, // 30 second default timeout
|
|
31
|
+
...config
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Validate all ACs for a task have passing tests
|
|
36
|
+
*
|
|
37
|
+
* @param task - Task to validate (must have satisfiesACs field)
|
|
38
|
+
* @param projectRoot - Project root directory
|
|
39
|
+
* @returns Validation result
|
|
40
|
+
*/
|
|
41
|
+
async validateTask(task, projectRoot) {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
// Initialize result
|
|
44
|
+
const result = {
|
|
45
|
+
passed: false,
|
|
46
|
+
taskId: task.id,
|
|
47
|
+
acIds: task.satisfiesACs || [],
|
|
48
|
+
testResults: new Map(),
|
|
49
|
+
summary: {
|
|
50
|
+
totalACs: 0,
|
|
51
|
+
acsTested: 0,
|
|
52
|
+
acsUntested: 0,
|
|
53
|
+
testsPassed: 0,
|
|
54
|
+
testsFailed: 0
|
|
55
|
+
},
|
|
56
|
+
errors: []
|
|
57
|
+
};
|
|
58
|
+
// Check if task has ACs to validate
|
|
59
|
+
if (!task.satisfiesACs || task.satisfiesACs.length === 0) {
|
|
60
|
+
result.errors.push(`Task ${task.id} has no Acceptance Criteria linked (satisfiesACs field missing or empty)`);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
result.summary.totalACs = task.satisfiesACs.length;
|
|
64
|
+
// Extract test file from task's Test Plan section
|
|
65
|
+
const testFile = this.extractTestFile(task);
|
|
66
|
+
if (!testFile) {
|
|
67
|
+
result.errors.push(`Task ${task.id} has no Test Plan section or test file specified`);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
// Check test file exists
|
|
71
|
+
const testFilePath = path.join(projectRoot, testFile);
|
|
72
|
+
if (!await fs.pathExists(testFilePath)) {
|
|
73
|
+
result.errors.push(`Test file not found: ${testFile}`);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
// Run tests for each AC
|
|
77
|
+
for (const acId of task.satisfiesACs) {
|
|
78
|
+
const acTestResult = await this.validateAC(acId, testFile, projectRoot);
|
|
79
|
+
result.testResults.set(acId, acTestResult);
|
|
80
|
+
if (acTestResult.passed) {
|
|
81
|
+
result.summary.acsTested++;
|
|
82
|
+
result.summary.testsPassed++;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
result.summary.acsUntested++;
|
|
86
|
+
result.summary.testsFailed++;
|
|
87
|
+
result.errors.push(`AC ${acId} tests failed: ${acTestResult.error || 'Unknown error'}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Overall pass/fail
|
|
91
|
+
result.passed = result.summary.testsFailed === 0 && result.summary.acsTested === result.summary.totalACs;
|
|
92
|
+
const duration = Date.now() - startTime;
|
|
93
|
+
console.log(`\n${chalk.blue('[AC Test Validator]')} Validated task ${task.id} in ${duration}ms`);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate a single AC has passing tests
|
|
98
|
+
*/
|
|
99
|
+
async validateAC(acId, testFile, projectRoot) {
|
|
100
|
+
const startTime = Date.now();
|
|
101
|
+
const result = {
|
|
102
|
+
acId,
|
|
103
|
+
testFile,
|
|
104
|
+
testCases: [],
|
|
105
|
+
passed: false,
|
|
106
|
+
duration: 0
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
// Run test file with filter for AC-ID
|
|
110
|
+
// Most test runners support filtering: vitest -t "AC-US1-01", jest --testNamePattern="AC-US1-01"
|
|
111
|
+
const command = this.buildTestCommand(testFile, acId);
|
|
112
|
+
console.log(` ${chalk.gray('Running:')} ${command}`);
|
|
113
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
114
|
+
cwd: this.config.cwd,
|
|
115
|
+
env: { ...process.env, ...this.config.env },
|
|
116
|
+
timeout: this.config.timeout
|
|
117
|
+
});
|
|
118
|
+
// Parse test output (basic implementation - can be enhanced)
|
|
119
|
+
const output = stdout + stderr;
|
|
120
|
+
result.testCases = this.extractTestCases(output, acId);
|
|
121
|
+
// Check for test failures
|
|
122
|
+
const hasFailures = output.includes('FAIL') ||
|
|
123
|
+
output.includes('failed') ||
|
|
124
|
+
output.includes('✗') ||
|
|
125
|
+
output.includes('0 passed');
|
|
126
|
+
result.passed = !hasFailures && result.testCases.length > 0;
|
|
127
|
+
if (!result.passed) {
|
|
128
|
+
result.error = this.extractFailureMessage(output);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
result.passed = false;
|
|
133
|
+
result.error = error.message || 'Test execution failed';
|
|
134
|
+
// Check if it's a timeout
|
|
135
|
+
if (error.killed && error.signal === 'SIGTERM') {
|
|
136
|
+
result.error = `Test timeout (exceeded ${this.config.timeout}ms)`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
result.duration = Date.now() - startTime;
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Build test command with AC-ID filter
|
|
144
|
+
*/
|
|
145
|
+
buildTestCommand(testFile, acId) {
|
|
146
|
+
// Detect test runner from config command
|
|
147
|
+
const command = this.config.command.toLowerCase();
|
|
148
|
+
if (command.includes('vitest')) {
|
|
149
|
+
// Vitest: vitest run <file> -t "AC-US1-01"
|
|
150
|
+
return `${this.config.command} ${testFile} -t "${acId}"`;
|
|
151
|
+
}
|
|
152
|
+
else if (command.includes('jest')) {
|
|
153
|
+
// Jest: jest <file> --testNamePattern="AC-US1-01"
|
|
154
|
+
return `${this.config.command} ${testFile} --testNamePattern="${acId}"`;
|
|
155
|
+
}
|
|
156
|
+
else if (command.includes('npm test')) {
|
|
157
|
+
// NPM script - try to pass args
|
|
158
|
+
return `${this.config.command} -- ${testFile} -t "${acId}"`;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Default: assume vitest-style
|
|
162
|
+
return `${this.config.command} ${testFile} -t "${acId}"`;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Extract test case names from test output
|
|
167
|
+
*/
|
|
168
|
+
extractTestCases(output, acId) {
|
|
169
|
+
const testCases = [];
|
|
170
|
+
// Look for lines containing the AC-ID and test indicators
|
|
171
|
+
const lines = output.split('\n');
|
|
172
|
+
for (const line of lines) {
|
|
173
|
+
if (line.includes(acId) && (line.includes('✓') || line.includes('PASS') || line.includes('√'))) {
|
|
174
|
+
// Extract test name (basic heuristic)
|
|
175
|
+
const match = line.match(/✓\s+(.+)/) || line.match(/PASS\s+(.+)/);
|
|
176
|
+
if (match) {
|
|
177
|
+
testCases.push(match[1].trim());
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return testCases;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Extract failure message from test output
|
|
185
|
+
*/
|
|
186
|
+
extractFailureMessage(output) {
|
|
187
|
+
const lines = output.split('\n');
|
|
188
|
+
// Find first error/failure message
|
|
189
|
+
for (let i = 0; i < lines.length; i++) {
|
|
190
|
+
const line = lines[i];
|
|
191
|
+
if (line.includes('FAIL') || line.includes('✗') || line.includes('Error:')) {
|
|
192
|
+
// Collect next few lines for context
|
|
193
|
+
const errorLines = lines.slice(i, i + 5).join('\n');
|
|
194
|
+
return errorLines.substring(0, 200); // Truncate long messages
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Fallback: return last few lines
|
|
198
|
+
return lines.slice(-5).join('\n');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extract test file path from task description (Test Plan section)
|
|
202
|
+
*/
|
|
203
|
+
extractTestFile(task) {
|
|
204
|
+
if (!task.description)
|
|
205
|
+
return null;
|
|
206
|
+
// Look for Test Plan section with file path
|
|
207
|
+
// Format: **Test Plan**:
|
|
208
|
+
// - **File**: `tests/unit/component.test.ts`
|
|
209
|
+
const testFileRegex = /\*\*File\*\*:\s*`([^`]+)`/;
|
|
210
|
+
const match = task.description.match(testFileRegex);
|
|
211
|
+
return match ? match[1] : null;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Format validation result for display
|
|
215
|
+
*/
|
|
216
|
+
formatResult(result) {
|
|
217
|
+
const lines = [];
|
|
218
|
+
lines.push(chalk.bold(`\nAC Test Validation: ${result.taskId}`));
|
|
219
|
+
lines.push(chalk.gray('─'.repeat(60)));
|
|
220
|
+
// Summary
|
|
221
|
+
lines.push(chalk.bold('Summary:'));
|
|
222
|
+
lines.push(` Total ACs: ${result.summary.totalACs}`);
|
|
223
|
+
lines.push(` ACs Tested: ${chalk.green(result.summary.acsTested)}`);
|
|
224
|
+
lines.push(` ACs Untested: ${chalk.red(result.summary.acsUntested)}`);
|
|
225
|
+
lines.push(` Tests Passed: ${chalk.green(result.summary.testsPassed)}`);
|
|
226
|
+
lines.push(` Tests Failed: ${chalk.red(result.summary.testsFailed)}`);
|
|
227
|
+
// Overall status
|
|
228
|
+
lines.push('');
|
|
229
|
+
if (result.passed) {
|
|
230
|
+
lines.push(chalk.green.bold('✓ VALIDATION PASSED'));
|
|
231
|
+
lines.push(chalk.green('All Acceptance Criteria have passing tests. Task can be marked complete.'));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
lines.push(chalk.red.bold('✗ VALIDATION FAILED'));
|
|
235
|
+
lines.push(chalk.red('Task cannot be marked complete until all AC tests pass.'));
|
|
236
|
+
}
|
|
237
|
+
// Errors
|
|
238
|
+
if (result.errors.length > 0) {
|
|
239
|
+
lines.push('');
|
|
240
|
+
lines.push(chalk.bold('Errors:'));
|
|
241
|
+
result.errors.forEach(error => {
|
|
242
|
+
lines.push(chalk.red(` • ${error}`));
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
// Test details
|
|
246
|
+
if (result.testResults.size > 0) {
|
|
247
|
+
lines.push('');
|
|
248
|
+
lines.push(chalk.bold('Test Results:'));
|
|
249
|
+
result.testResults.forEach((acResult, acId) => {
|
|
250
|
+
const icon = acResult.passed ? chalk.green('✓') : chalk.red('✗');
|
|
251
|
+
const status = acResult.passed ? chalk.green('PASSED') : chalk.red('FAILED');
|
|
252
|
+
lines.push(` ${icon} ${acId}: ${status} (${acResult.duration}ms)`);
|
|
253
|
+
if (acResult.testCases.length > 0) {
|
|
254
|
+
acResult.testCases.forEach(testCase => {
|
|
255
|
+
lines.push(chalk.gray(` - ${testCase}`));
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (acResult.error) {
|
|
259
|
+
lines.push(chalk.red(` Error: ${acResult.error}`));
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
lines.push(chalk.gray('─'.repeat(60)));
|
|
264
|
+
return lines.join('\n');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Create AC test validator from project config
|
|
269
|
+
*/
|
|
270
|
+
export async function createACTestValidator(projectRoot) {
|
|
271
|
+
// Read test configuration from package.json or specweave config
|
|
272
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
273
|
+
let testCommand = 'npm test';
|
|
274
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
275
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
276
|
+
// Detect test runner
|
|
277
|
+
if (packageJson.devDependencies?.vitest || packageJson.dependencies?.vitest) {
|
|
278
|
+
testCommand = 'npx vitest run';
|
|
279
|
+
}
|
|
280
|
+
else if (packageJson.devDependencies?.jest || packageJson.dependencies?.jest) {
|
|
281
|
+
testCommand = 'npx jest';
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const config = {
|
|
285
|
+
command: testCommand,
|
|
286
|
+
pattern: 'tests/**/*.test.ts',
|
|
287
|
+
cwd: projectRoot,
|
|
288
|
+
timeout: 30000
|
|
289
|
+
};
|
|
290
|
+
return new ACTestValidator(config);
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=ac-test-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ac-test-validator.js","sourceRoot":"","sources":["../../../src/core/ac-test-validator.ts"],"names":[],"mappings":"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"}
|