kiro-spec-engine 1.4.4 → 1.5.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/CHANGELOG.md +90 -1
- package/README.md +16 -0
- package/README.zh.md +380 -0
- package/bin/kiro-spec-engine.js +102 -44
- package/docs/adoption-guide.md +53 -0
- package/docs/document-governance.md +864 -0
- package/docs/spec-numbering-guide.md +348 -0
- package/docs/spec-workflow.md +65 -0
- package/docs/troubleshooting.md +339 -0
- package/docs/zh/spec-numbering-guide.md +348 -0
- package/lib/adoption/adoption-strategy.js +26 -15
- package/lib/adoption/conflict-resolver.js +239 -0
- package/lib/adoption/diff-viewer.js +226 -0
- package/lib/backup/selective-backup.js +207 -0
- package/lib/commands/adopt.js +95 -10
- package/lib/commands/docs.js +717 -0
- package/lib/commands/doctor.js +141 -3
- package/lib/commands/status.js +77 -5
- package/lib/governance/archive-tool.js +231 -0
- package/lib/governance/cleanup-tool.js +237 -0
- package/lib/governance/config-manager.js +186 -0
- package/lib/governance/diagnostic-engine.js +271 -0
- package/lib/governance/execution-logger.js +243 -0
- package/lib/governance/file-scanner.js +285 -0
- package/lib/governance/hooks-manager.js +333 -0
- package/lib/governance/reporter.js +337 -0
- package/lib/governance/validation-engine.js +181 -0
- package/package.json +1 -1
- package/template/.kiro/README.md +237 -197
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Engine
|
|
3
|
+
*
|
|
4
|
+
* Validates project documentation structure
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const FileScanner = require('./file-scanner');
|
|
9
|
+
|
|
10
|
+
class ValidationEngine {
|
|
11
|
+
constructor(projectPath, config) {
|
|
12
|
+
this.projectPath = projectPath;
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.scanner = new FileScanner(projectPath);
|
|
15
|
+
this.validationErrors = [];
|
|
16
|
+
this.validationWarnings = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate project structure
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} options - Validation options
|
|
23
|
+
* @param {string} options.spec - Specific Spec to validate
|
|
24
|
+
* @param {boolean} options.all - Validate all Specs
|
|
25
|
+
* @returns {Promise<ValidationReport>}
|
|
26
|
+
*/
|
|
27
|
+
async validate(options = {}) {
|
|
28
|
+
this.validationErrors = []; // Reset
|
|
29
|
+
this.validationWarnings = []; // Reset
|
|
30
|
+
|
|
31
|
+
await this.validateRootDirectory();
|
|
32
|
+
|
|
33
|
+
if (options.spec) {
|
|
34
|
+
await this.validateSpec(options.spec);
|
|
35
|
+
} else if (options.all) {
|
|
36
|
+
await this.validateAllSpecs();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return this.generateReport();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validate root directory
|
|
44
|
+
*
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
async validateRootDirectory() {
|
|
48
|
+
const mdFiles = await this.scanner.findMarkdownFiles(this.projectPath);
|
|
49
|
+
const allowedFiles = this.config.rootAllowedFiles || [];
|
|
50
|
+
|
|
51
|
+
for (const filePath of mdFiles) {
|
|
52
|
+
const basename = path.basename(filePath);
|
|
53
|
+
|
|
54
|
+
if (!allowedFiles.includes(basename)) {
|
|
55
|
+
this.validationErrors.push({
|
|
56
|
+
type: 'root_violation',
|
|
57
|
+
path: filePath,
|
|
58
|
+
message: `Unexpected markdown file in root: ${basename}`,
|
|
59
|
+
recommendation: 'Move to appropriate location or delete if temporary'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validate all Spec directories
|
|
67
|
+
*
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async validateAllSpecs() {
|
|
71
|
+
const specDirs = await this.scanner.findSpecDirectories();
|
|
72
|
+
|
|
73
|
+
for (const specDir of specDirs) {
|
|
74
|
+
const specName = path.basename(specDir);
|
|
75
|
+
await this.validateSpec(specName);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Validate a Spec directory
|
|
81
|
+
*
|
|
82
|
+
* @param {string} specName - Spec name
|
|
83
|
+
* @returns {Promise<void>}
|
|
84
|
+
*/
|
|
85
|
+
async validateSpec(specName) {
|
|
86
|
+
const specPath = this.scanner.getSpecDirectory(specName);
|
|
87
|
+
|
|
88
|
+
// Check if Spec directory exists
|
|
89
|
+
if (!await this.scanner.exists(specPath)) {
|
|
90
|
+
this.validationErrors.push({
|
|
91
|
+
type: 'missing_spec',
|
|
92
|
+
path: specPath,
|
|
93
|
+
message: `Spec directory does not exist: ${specName}`,
|
|
94
|
+
recommendation: `Create Spec directory at ${specPath}`
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check required files
|
|
100
|
+
const requiredFiles = ['requirements.md', 'design.md', 'tasks.md'];
|
|
101
|
+
for (const file of requiredFiles) {
|
|
102
|
+
const filePath = path.join(specPath, file);
|
|
103
|
+
if (!await this.scanner.exists(filePath)) {
|
|
104
|
+
this.validationErrors.push({
|
|
105
|
+
type: 'missing_required_file',
|
|
106
|
+
path: filePath,
|
|
107
|
+
message: `Missing required file: ${file}`,
|
|
108
|
+
recommendation: `Create ${file} in ${specName}`
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check for misplaced artifacts
|
|
114
|
+
const files = await this.scanner.getFiles(specPath);
|
|
115
|
+
const allowedSubdirs = this.config.specSubdirs || [];
|
|
116
|
+
|
|
117
|
+
for (const filePath of files) {
|
|
118
|
+
const basename = path.basename(filePath);
|
|
119
|
+
|
|
120
|
+
// Skip required files
|
|
121
|
+
if (requiredFiles.includes(basename)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.validationWarnings.push({
|
|
126
|
+
type: 'misplaced_artifact',
|
|
127
|
+
path: filePath,
|
|
128
|
+
message: `Artifact not in subdirectory: ${basename}`,
|
|
129
|
+
recommendation: `Move to appropriate subdirectory (${allowedSubdirs.join(', ')})`
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check subdirectory naming
|
|
134
|
+
const subdirs = await this.scanner.getSubdirectories(specPath);
|
|
135
|
+
|
|
136
|
+
for (const subdirPath of subdirs) {
|
|
137
|
+
const subdirName = path.basename(subdirPath);
|
|
138
|
+
|
|
139
|
+
// Skip hidden directories
|
|
140
|
+
if (subdirName.startsWith('.')) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!allowedSubdirs.includes(subdirName)) {
|
|
145
|
+
this.validationWarnings.push({
|
|
146
|
+
type: 'invalid_subdirectory',
|
|
147
|
+
path: subdirPath,
|
|
148
|
+
message: `Non-standard subdirectory: ${subdirName}`,
|
|
149
|
+
recommendation: `Rename to one of: ${allowedSubdirs.join(', ')}, or remove if not needed`
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate validation report
|
|
157
|
+
*
|
|
158
|
+
* @returns {ValidationReport}
|
|
159
|
+
*/
|
|
160
|
+
generateReport() {
|
|
161
|
+
return {
|
|
162
|
+
valid: this.validationErrors.length === 0,
|
|
163
|
+
errors: this.validationErrors,
|
|
164
|
+
warnings: this.validationWarnings,
|
|
165
|
+
summary: {
|
|
166
|
+
totalErrors: this.validationErrors.length,
|
|
167
|
+
totalWarnings: this.validationWarnings.length
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @typedef {Object} ValidationReport
|
|
175
|
+
* @property {boolean} valid - Whether validation passed
|
|
176
|
+
* @property {Object[]} errors - Validation errors
|
|
177
|
+
* @property {Object[]} warnings - Validation warnings
|
|
178
|
+
* @property {Object} summary - Summary statistics
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
module.exports = ValidationEngine;
|
package/package.json
CHANGED