specweave 0.28.3 â 0.28.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/README.md +31 -88
- package/dist/src/core/living-docs/feature-consistency-validator.d.ts +129 -0
- package/dist/src/core/living-docs/feature-consistency-validator.d.ts.map +1 -0
- package/dist/src/core/living-docs/feature-consistency-validator.js +445 -0
- package/dist/src/core/living-docs/feature-consistency-validator.js.map +1 -0
- package/dist/src/core/living-docs/index.d.ts +1 -0
- package/dist/src/core/living-docs/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/index.js +1 -0
- package/dist/src/core/living-docs/index.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +13 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +50 -0
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/commands/specweave-validate-features.md +203 -0
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +1 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1104 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-kafka/skills/kafka-mcp-integration/SKILL.md +17 -0
- package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +3 -1
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1017 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/plugins/specweave-ui/commands/ui-automate.md +5 -28
- package/src/templates/AGENTS.md.template +92 -9
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Consistency Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates and repairs consistency between:
|
|
5
|
+
* - .specweave/docs/internal/specs/_features/FS-XXX/
|
|
6
|
+
* - .specweave/docs/internal/specs/{project}/FS-XXX/
|
|
7
|
+
*
|
|
8
|
+
* PROBLEM SOLVED:
|
|
9
|
+
* Living docs sync creates _features/ and {project}/ folders sequentially.
|
|
10
|
+
* If sync fails midway or increment is deleted, folders can get out of sync.
|
|
11
|
+
*
|
|
12
|
+
* SOLUTION:
|
|
13
|
+
* 1. Detect discrepancies (orphaned _features without project folders)
|
|
14
|
+
* 2. Auto-repair by creating missing project folders
|
|
15
|
+
* 3. Report issues for manual intervention when auto-repair not possible
|
|
16
|
+
*
|
|
17
|
+
* @see ADR-0142 (if created) for architectural decision
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, promises as fs } from 'fs';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import yaml from 'yaml';
|
|
22
|
+
import { consoleLogger } from '../../utils/logger.js';
|
|
23
|
+
export class FeatureConsistencyValidator {
|
|
24
|
+
constructor(projectRoot, options = {}) {
|
|
25
|
+
this.projectRoot = projectRoot;
|
|
26
|
+
this.specsPath = path.join(projectRoot, '.specweave/docs/internal/specs');
|
|
27
|
+
this.incrementsPath = path.join(projectRoot, '.specweave/increments');
|
|
28
|
+
this.logger = options.logger ?? consoleLogger;
|
|
29
|
+
this.defaultProject = options.defaultProject ?? 'specweave';
|
|
30
|
+
this.includeArchived = options.includeArchived ?? false;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Validate consistency between _features and project folders
|
|
34
|
+
*
|
|
35
|
+
* @param autoRepair - If true, attempt to auto-repair discrepancies
|
|
36
|
+
* @returns Validation result with discrepancies and repair results
|
|
37
|
+
*/
|
|
38
|
+
async validate(autoRepair = false) {
|
|
39
|
+
const result = {
|
|
40
|
+
totalFeatures: 0,
|
|
41
|
+
consistentCount: 0,
|
|
42
|
+
discrepancies: [],
|
|
43
|
+
repairs: autoRepair ? [] : undefined
|
|
44
|
+
};
|
|
45
|
+
this.logger.log('đ Validating feature folder consistency...');
|
|
46
|
+
// Step 1: Get all features from _features folder
|
|
47
|
+
const featuresDir = path.join(this.specsPath, '_features');
|
|
48
|
+
if (!existsSync(featuresDir)) {
|
|
49
|
+
this.logger.log(' âšī¸ No _features folder found, nothing to validate');
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
const featureFolders = await this.getFeatureFolders(featuresDir);
|
|
53
|
+
result.totalFeatures = featureFolders.length;
|
|
54
|
+
// Step 2: Get all project folders
|
|
55
|
+
const projectFolders = await this.getProjectFolders();
|
|
56
|
+
// Step 3: Check each feature for consistency
|
|
57
|
+
for (const featureId of featureFolders) {
|
|
58
|
+
const discrepancy = await this.checkFeatureConsistency(featureId, projectFolders);
|
|
59
|
+
if (discrepancy) {
|
|
60
|
+
result.discrepancies.push(discrepancy);
|
|
61
|
+
// Attempt auto-repair if enabled
|
|
62
|
+
if (autoRepair && discrepancy.autoRepairable) {
|
|
63
|
+
const repairResult = await this.repairDiscrepancy(discrepancy);
|
|
64
|
+
result.repairs.push(repairResult);
|
|
65
|
+
if (repairResult.success) {
|
|
66
|
+
result.consistentCount++; // Count as consistent after repair
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
result.consistentCount++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Step 4: Log summary
|
|
75
|
+
this.logValidationSummary(result);
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get all feature folder IDs from _features directory
|
|
80
|
+
*/
|
|
81
|
+
async getFeatureFolders(featuresDir) {
|
|
82
|
+
const entries = await fs.readdir(featuresDir, { withFileTypes: true });
|
|
83
|
+
const folders = [];
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
if (!entry.isDirectory())
|
|
86
|
+
continue;
|
|
87
|
+
// Skip _archive unless includeArchived is true
|
|
88
|
+
if (entry.name === '_archive' && !this.includeArchived)
|
|
89
|
+
continue;
|
|
90
|
+
// Only include FS-XXX pattern folders
|
|
91
|
+
if (entry.name.startsWith('FS-')) {
|
|
92
|
+
folders.push(entry.name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return folders.sort();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get all project folder names (excluding _features, _epics, _archive)
|
|
99
|
+
*/
|
|
100
|
+
async getProjectFolders() {
|
|
101
|
+
if (!existsSync(this.specsPath)) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const entries = await fs.readdir(this.specsPath, { withFileTypes: true });
|
|
105
|
+
const projects = [];
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
if (!entry.isDirectory())
|
|
108
|
+
continue;
|
|
109
|
+
// Skip special folders
|
|
110
|
+
if (entry.name.startsWith('_'))
|
|
111
|
+
continue;
|
|
112
|
+
projects.push(entry.name);
|
|
113
|
+
}
|
|
114
|
+
return projects;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if a feature has consistent folders across _features and projects
|
|
118
|
+
*/
|
|
119
|
+
async checkFeatureConsistency(featureId, projectFolders) {
|
|
120
|
+
const featuresPath = path.join(this.specsPath, '_features', featureId);
|
|
121
|
+
const featureFilePath = path.join(featuresPath, 'FEATURE.md');
|
|
122
|
+
// Check if FEATURE.md exists
|
|
123
|
+
if (!existsSync(featureFilePath)) {
|
|
124
|
+
return {
|
|
125
|
+
featureId,
|
|
126
|
+
type: 'orphaned_feature',
|
|
127
|
+
description: `_features/${featureId}/ exists but has no FEATURE.md`,
|
|
128
|
+
autoRepairable: false,
|
|
129
|
+
featuresPath
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// Parse FEATURE.md to find linked increment
|
|
133
|
+
const linkedIncrement = await this.extractLinkedIncrement(featureFilePath);
|
|
134
|
+
const incrementExists = linkedIncrement
|
|
135
|
+
? this.checkIncrementExists(linkedIncrement)
|
|
136
|
+
: false;
|
|
137
|
+
// Check if feature exists in any project folder
|
|
138
|
+
let foundInProjects = [];
|
|
139
|
+
for (const project of projectFolders) {
|
|
140
|
+
const projectFeaturePath = path.join(this.specsPath, project, featureId);
|
|
141
|
+
if (existsSync(projectFeaturePath)) {
|
|
142
|
+
foundInProjects.push(project);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (foundInProjects.length === 0) {
|
|
146
|
+
// Check if this is an orphaned feature (increment deleted, not external)
|
|
147
|
+
const isExternalFeature = await this.isExternalFeature(featureFilePath);
|
|
148
|
+
if (!incrementExists && !isExternalFeature && linkedIncrement) {
|
|
149
|
+
// ORPHANED: Increment was deleted, feature is not external - should be archived
|
|
150
|
+
// This prevents creating project folders for features whose increments no longer exist
|
|
151
|
+
return {
|
|
152
|
+
featureId,
|
|
153
|
+
type: 'orphaned_feature',
|
|
154
|
+
description: `Feature ${featureId} references deleted increment ${linkedIncrement} - should be archived`,
|
|
155
|
+
autoRepairable: true, // Can auto-repair via archiver
|
|
156
|
+
featuresPath,
|
|
157
|
+
linkedIncrementId: linkedIncrement,
|
|
158
|
+
incrementExists: false
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
// Normal case: increment exists OR external feature OR no linked increment
|
|
162
|
+
// Create missing project folder
|
|
163
|
+
return {
|
|
164
|
+
featureId,
|
|
165
|
+
type: 'missing_project_folder',
|
|
166
|
+
description: `Feature ${featureId} exists in _features/ but not in any project folder`,
|
|
167
|
+
autoRepairable: true, // We can create the missing folder
|
|
168
|
+
featuresPath,
|
|
169
|
+
projectPath: path.join(this.specsPath, this.defaultProject, featureId),
|
|
170
|
+
linkedIncrementId: linkedIncrement,
|
|
171
|
+
incrementExists
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// Feature is consistent
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Check if a feature is from an external source (GitHub, JIRA, ADO)
|
|
179
|
+
* External features should NOT be considered orphaned even if local increment is missing
|
|
180
|
+
*/
|
|
181
|
+
async isExternalFeature(featureFilePath) {
|
|
182
|
+
try {
|
|
183
|
+
const content = await fs.readFile(featureFilePath, 'utf-8');
|
|
184
|
+
// Check frontmatter for external indicators
|
|
185
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
186
|
+
if (frontmatterMatch) {
|
|
187
|
+
try {
|
|
188
|
+
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
|
189
|
+
if (frontmatter.origin === 'external' ||
|
|
190
|
+
frontmatter.external_source ||
|
|
191
|
+
frontmatter.external_id) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Ignore YAML parse errors
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Check for external badges/markers in content
|
|
200
|
+
// đ = GitHub, đĢ = JIRA, đ = ADO
|
|
201
|
+
if (content.includes('origin: external') ||
|
|
202
|
+
content.includes('external_source:') ||
|
|
203
|
+
content.includes('external_id:')) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Extract linked increment ID from FEATURE.md
|
|
214
|
+
*/
|
|
215
|
+
async extractLinkedIncrement(featureFilePath) {
|
|
216
|
+
try {
|
|
217
|
+
const content = await fs.readFile(featureFilePath, 'utf-8');
|
|
218
|
+
// Look for increment link pattern: [0062-test-living-docs-auto-sync](...)
|
|
219
|
+
const incrementMatch = content.match(/\[(\d{4}-[^\]]+)\]\([^)]+\)/);
|
|
220
|
+
if (incrementMatch) {
|
|
221
|
+
return incrementMatch[1];
|
|
222
|
+
}
|
|
223
|
+
// Also check frontmatter
|
|
224
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
225
|
+
if (frontmatterMatch) {
|
|
226
|
+
try {
|
|
227
|
+
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
|
228
|
+
if (frontmatter.increment) {
|
|
229
|
+
return frontmatter.increment;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// Ignore YAML parse errors
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check if an increment exists (in active or archive folder)
|
|
244
|
+
*/
|
|
245
|
+
checkIncrementExists(incrementId) {
|
|
246
|
+
const activePath = path.join(this.incrementsPath, incrementId);
|
|
247
|
+
const archivePath = path.join(this.incrementsPath, '_archive', incrementId);
|
|
248
|
+
return existsSync(activePath) || existsSync(archivePath);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Attempt to repair a discrepancy
|
|
252
|
+
*/
|
|
253
|
+
async repairDiscrepancy(discrepancy) {
|
|
254
|
+
const result = {
|
|
255
|
+
featureId: discrepancy.featureId,
|
|
256
|
+
success: false,
|
|
257
|
+
action: ''
|
|
258
|
+
};
|
|
259
|
+
try {
|
|
260
|
+
switch (discrepancy.type) {
|
|
261
|
+
case 'missing_project_folder':
|
|
262
|
+
result.action = await this.repairMissingProjectFolder(discrepancy);
|
|
263
|
+
result.success = true;
|
|
264
|
+
break;
|
|
265
|
+
case 'orphaned_feature':
|
|
266
|
+
// Auto-archive orphaned features (increment was deleted)
|
|
267
|
+
if (discrepancy.autoRepairable) {
|
|
268
|
+
result.action = await this.archiveOrphanedFeature(discrepancy);
|
|
269
|
+
result.success = true;
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// No FEATURE.md or other issue - needs manual intervention
|
|
273
|
+
result.action = 'Skipped - requires manual intervention (no FEATURE.md)';
|
|
274
|
+
result.success = false;
|
|
275
|
+
}
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
result.action = 'Unknown discrepancy type';
|
|
279
|
+
result.success = false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
result.error = String(error);
|
|
284
|
+
result.action = `Failed: ${error}`;
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Archive an orphaned feature (increment was deleted)
|
|
290
|
+
* Delegates to FeatureArchiver for consistent archiving behavior
|
|
291
|
+
*/
|
|
292
|
+
async archiveOrphanedFeature(discrepancy) {
|
|
293
|
+
// Dynamic import to avoid circular dependency
|
|
294
|
+
const { FeatureArchiver } = await import('./feature-archiver.js');
|
|
295
|
+
const archiver = new FeatureArchiver(this.projectRoot);
|
|
296
|
+
this.logger.log(` đī¸ Archiving orphaned feature ${discrepancy.featureId} (increment deleted)...`);
|
|
297
|
+
const archiveResult = await archiver.archiveFeatures({
|
|
298
|
+
archiveOrphanedFeatures: true,
|
|
299
|
+
archiveOrphanedEpics: false, // Be conservative - only archive features
|
|
300
|
+
dryRun: false,
|
|
301
|
+
updateLinks: true,
|
|
302
|
+
customReason: `Increment ${discrepancy.linkedIncrementId || 'unknown'} was deleted`
|
|
303
|
+
});
|
|
304
|
+
if (archiveResult.archivedFeatures.includes(discrepancy.featureId)) {
|
|
305
|
+
this.logger.log(` â
Archived ${discrepancy.featureId} to _archive/`);
|
|
306
|
+
return `Archived orphaned feature ${discrepancy.featureId} (increment ${discrepancy.linkedIncrementId} deleted)`;
|
|
307
|
+
}
|
|
308
|
+
else if (archiveResult.errors.length > 0) {
|
|
309
|
+
throw new Error(archiveResult.errors.join(', '));
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// Feature might have been archived by another process or already in archive
|
|
313
|
+
return `Feature ${discrepancy.featureId} already archived or cleaned up`;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Create missing project folder for a feature
|
|
318
|
+
*/
|
|
319
|
+
async repairMissingProjectFolder(discrepancy) {
|
|
320
|
+
const projectPath = discrepancy.projectPath;
|
|
321
|
+
const featuresPath = discrepancy.featuresPath;
|
|
322
|
+
// Create project folder
|
|
323
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
324
|
+
// Extract info from FEATURE.md to create README.md
|
|
325
|
+
const featureFilePath = path.join(featuresPath, 'FEATURE.md');
|
|
326
|
+
const featureContent = await fs.readFile(featureFilePath, 'utf-8');
|
|
327
|
+
// Extract title from FEATURE.md
|
|
328
|
+
let title = discrepancy.featureId;
|
|
329
|
+
const titleMatch = featureContent.match(/^#\s+(.+)$/m);
|
|
330
|
+
if (titleMatch) {
|
|
331
|
+
title = titleMatch[1];
|
|
332
|
+
}
|
|
333
|
+
// Extract frontmatter
|
|
334
|
+
let status = 'in-progress';
|
|
335
|
+
const frontmatterMatch = featureContent.match(/^---\n([\s\S]*?)\n---/);
|
|
336
|
+
if (frontmatterMatch) {
|
|
337
|
+
try {
|
|
338
|
+
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
|
339
|
+
status = frontmatter.status || status;
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// Ignore YAML parse errors
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Create README.md in project folder
|
|
346
|
+
const readmeContent = `---
|
|
347
|
+
id: ${discrepancy.featureId}-${this.defaultProject}
|
|
348
|
+
title: "${title} - ${this.defaultProject.charAt(0).toUpperCase() + this.defaultProject.slice(1)} Implementation"
|
|
349
|
+
feature: ${discrepancy.featureId}
|
|
350
|
+
project: ${this.defaultProject}
|
|
351
|
+
type: feature-context
|
|
352
|
+
status: ${status}
|
|
353
|
+
auto_repaired: true
|
|
354
|
+
repaired_at: ${new Date().toISOString()}
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
# ${title}
|
|
358
|
+
|
|
359
|
+
**Feature**: [${discrepancy.featureId}](../../_features/${discrepancy.featureId}/FEATURE.md)
|
|
360
|
+
|
|
361
|
+
## Overview
|
|
362
|
+
|
|
363
|
+
This project context was auto-created by consistency validator.
|
|
364
|
+
|
|
365
|
+
## User Stories
|
|
366
|
+
|
|
367
|
+
See user story files in this directory.
|
|
368
|
+
|
|
369
|
+
## Note
|
|
370
|
+
|
|
371
|
+
This folder was auto-created because _features/${discrepancy.featureId}/ existed
|
|
372
|
+
but ${this.defaultProject}/${discrepancy.featureId}/ was missing.
|
|
373
|
+
|
|
374
|
+
${discrepancy.linkedIncrementId
|
|
375
|
+
? `**Linked Increment**: ${discrepancy.linkedIncrementId} (${discrepancy.incrementExists ? 'exists' : 'not found'})`
|
|
376
|
+
: '**Linked Increment**: Not found in FEATURE.md'}
|
|
377
|
+
`;
|
|
378
|
+
const readmePath = path.join(projectPath, 'README.md');
|
|
379
|
+
await fs.writeFile(readmePath, readmeContent, 'utf-8');
|
|
380
|
+
this.logger.log(` â
Created ${this.defaultProject}/${discrepancy.featureId}/README.md`);
|
|
381
|
+
return `Created ${projectPath}/README.md`;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Log validation summary
|
|
385
|
+
*/
|
|
386
|
+
logValidationSummary(result) {
|
|
387
|
+
this.logger.log('');
|
|
388
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
389
|
+
this.logger.log('đ FEATURE CONSISTENCY VALIDATION REPORT');
|
|
390
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
391
|
+
this.logger.log('');
|
|
392
|
+
this.logger.log(`Total features scanned: ${result.totalFeatures}`);
|
|
393
|
+
this.logger.log(`Consistent: ${result.consistentCount}`);
|
|
394
|
+
this.logger.log(`Discrepancies found: ${result.discrepancies.length}`);
|
|
395
|
+
this.logger.log('');
|
|
396
|
+
if (result.discrepancies.length > 0) {
|
|
397
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
398
|
+
this.logger.log('â ī¸ DISCREPANCIES');
|
|
399
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
400
|
+
for (const disc of result.discrepancies) {
|
|
401
|
+
this.logger.log('');
|
|
402
|
+
this.logger.log(`Feature: ${disc.featureId}`);
|
|
403
|
+
this.logger.log(`Type: ${disc.type}`);
|
|
404
|
+
this.logger.log(`Description: ${disc.description}`);
|
|
405
|
+
this.logger.log(`Auto-repairable: ${disc.autoRepairable ? 'Yes' : 'No'}`);
|
|
406
|
+
if (disc.linkedIncrementId) {
|
|
407
|
+
this.logger.log(`Linked increment: ${disc.linkedIncrementId} (${disc.incrementExists ? 'â
exists' : 'â not found'})`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (result.repairs && result.repairs.length > 0) {
|
|
412
|
+
this.logger.log('');
|
|
413
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
414
|
+
this.logger.log('đ§ REPAIR RESULTS');
|
|
415
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
416
|
+
for (const repair of result.repairs) {
|
|
417
|
+
const icon = repair.success ? 'â
' : 'â';
|
|
418
|
+
this.logger.log(`${icon} ${repair.featureId}: ${repair.action}`);
|
|
419
|
+
if (repair.error) {
|
|
420
|
+
this.logger.log(` Error: ${repair.error}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
this.logger.log('');
|
|
425
|
+
this.logger.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Quick check: Are there any discrepancies?
|
|
429
|
+
* Use this for fast validation without full report
|
|
430
|
+
*/
|
|
431
|
+
async hasDiscrepancies() {
|
|
432
|
+
const result = await this.validate(false);
|
|
433
|
+
return result.discrepancies.length > 0;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get list of orphaned features (features in _features without corresponding project folder)
|
|
437
|
+
*/
|
|
438
|
+
async getOrphanedFeatures() {
|
|
439
|
+
const result = await this.validate(false);
|
|
440
|
+
return result.discrepancies
|
|
441
|
+
.filter(d => d.type === 'missing_project_folder')
|
|
442
|
+
.map(d => d.featureId);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=feature-consistency-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-consistency-validator.js","sourceRoot":"","sources":["../../../../src/core/living-docs/feature-consistency-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAU,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAgD9D,MAAM,OAAO,2BAA2B;IAQtC,YAAY,WAAmB,EAAE,UAA4B,EAAE;QAC7D,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,gCAAgC,CAAC,CAAC;QAC1E,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;QACtE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,WAAW,CAAC;QAC5D,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC;IAC1D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,aAAsB,KAAK;QACxC,MAAM,MAAM,GAAqB;YAC/B,aAAa,EAAE,CAAC;YAChB,eAAe,EAAE,CAAC;YAClB,aAAa,EAAE,EAAE;YACjB,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;SACrC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAE/D,iDAAiD;QACjD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;YACzE,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACjE,MAAM,CAAC,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC;QAE7C,kCAAkC;QAClC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEtD,6CAA6C;QAC7C,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;YACvC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,uBAAuB,CACpD,SAAS,EACT,cAAc,CACf,CAAC;YAEF,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAEvC,iCAAiC;gBACjC,IAAI,UAAU,IAAI,WAAW,CAAC,cAAc,EAAE,CAAC;oBAC7C,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;oBAC/D,MAAM,CAAC,OAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oBAEnC,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;wBACzB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,mCAAmC;oBAC/D,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,eAAe,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAElC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,iBAAiB,CAAC,WAAmB;QACjD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YAEnC,+CAA+C;YAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,eAAe;gBAAE,SAAS;YAEjE,sCAAsC;YACtC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,iBAAiB;QAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YAEnC,uBAAuB;YACvB,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAEzC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,uBAAuB,CACnC,SAAiB,EACjB,cAAwB;QAExB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;QACvE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAE9D,6BAA6B;QAC7B,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,SAAS;gBACT,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE,aAAa,SAAS,gCAAgC;gBACnE,cAAc,EAAE,KAAK;gBACrB,YAAY;aACb,CAAC;QACJ,CAAC;QAED,4CAA4C;QAC5C,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,eAAe,CAAC,CAAC;QAC3E,MAAM,eAAe,GAAG,eAAe;YACrC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC;YAC5C,CAAC,CAAC,KAAK,CAAC;QAEV,gDAAgD;QAChD,IAAI,eAAe,GAAa,EAAE,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;YACzE,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACnC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,yEAAyE;YACzE,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;YAExE,IAAI,CAAC,eAAe,IAAI,CAAC,iBAAiB,IAAI,eAAe,EAAE,CAAC;gBAC9D,gFAAgF;gBAChF,uFAAuF;gBACvF,OAAO;oBACL,SAAS;oBACT,IAAI,EAAE,kBAAkB;oBACxB,WAAW,EAAE,WAAW,SAAS,iCAAiC,eAAe,uBAAuB;oBACxG,cAAc,EAAE,IAAI,EAAE,+BAA+B;oBACrD,YAAY;oBACZ,iBAAiB,EAAE,eAAe;oBAClC,eAAe,EAAE,KAAK;iBACvB,CAAC;YACJ,CAAC;YAED,2EAA2E;YAC3E,gCAAgC;YAChC,OAAO;gBACL,SAAS;gBACT,IAAI,EAAE,wBAAwB;gBAC9B,WAAW,EAAE,WAAW,SAAS,qDAAqD;gBACtF,cAAc,EAAE,IAAI,EAAE,mCAAmC;gBACzD,YAAY;gBACZ,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;gBACtE,iBAAiB,EAAE,eAAe;gBAClC,eAAe;aAChB,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB,CAAC,eAAuB;QACrD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;YAE5D,4CAA4C;YAC5C,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAChE,IAAI,gBAAgB,EAAE,CAAC;gBACrB,IAAI,CAAC;oBACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;oBACpD,IAAI,WAAW,CAAC,MAAM,KAAK,UAAU;wBACjC,WAAW,CAAC,eAAe;wBAC3B,WAAW,CAAC,WAAW,EAAE,CAAC;wBAC5B,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,2BAA2B;gBAC7B,CAAC;YACH,CAAC;YAED,+CAA+C;YAC/C,mCAAmC;YACnC,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBACpC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBACpC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,sBAAsB,CAAC,eAAuB;QAC1D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;YAE5D,0EAA0E;YAC1E,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;YACpE,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;YAC3B,CAAC;YAED,yBAAyB;YACzB,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAChE,IAAI,gBAAgB,EAAE,CAAC;gBACrB,IAAI,CAAC;oBACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;oBACpD,IAAI,WAAW,CAAC,SAAS,EAAE,CAAC;wBAC1B,OAAO,WAAW,CAAC,SAAS,CAAC;oBAC/B,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,2BAA2B;gBAC7B,CAAC;YACH,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,oBAAoB,CAAC,WAAmB;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QAC5E,OAAO,UAAU,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,iBAAiB,CAAC,WAA8B;QAC5D,MAAM,MAAM,GAAiB;YAC3B,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,EAAE;SACX,CAAC;QAEF,IAAI,CAAC;YACH,QAAQ,WAAW,CAAC,IAAI,EAAE,CAAC;gBACzB,KAAK,wBAAwB;oBAC3B,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC;oBACnE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;oBACtB,MAAM;gBAER,KAAK,kBAAkB;oBACrB,yDAAyD;oBACzD,IAAI,WAAW,CAAC,cAAc,EAAE,CAAC;wBAC/B,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;wBAC/D,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACN,2DAA2D;wBAC3D,MAAM,CAAC,MAAM,GAAG,wDAAwD,CAAC;wBACzE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;oBACzB,CAAC;oBACD,MAAM;gBAER;oBACE,MAAM,CAAC,MAAM,GAAG,0BAA0B,CAAC;oBAC3C,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,GAAG,WAAW,KAAK,EAAE,CAAC;QACrC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,sBAAsB,CAAC,WAA8B;QACjE,8CAA8C;QAC9C,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,sCAAsC,WAAW,CAAC,SAAS,yBAAyB,CAAC,CAAC;QAEtG,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC;YACnD,uBAAuB,EAAE,IAAI;YAC7B,oBAAoB,EAAE,KAAK,EAAE,0CAA0C;YACvE,MAAM,EAAE,KAAK;YACb,WAAW,EAAE,IAAI;YACjB,YAAY,EAAE,aAAa,WAAW,CAAC,iBAAiB,IAAI,SAAS,cAAc;SACpF,CAAC,CAAC;QAEH,IAAI,aAAa,CAAC,gBAAgB,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YACnE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,WAAW,CAAC,SAAS,eAAe,CAAC,CAAC;YACvE,OAAO,6BAA6B,WAAW,CAAC,SAAS,eAAe,WAAW,CAAC,iBAAiB,WAAW,CAAC;QACnH,CAAC;aAAM,IAAI,aAAa,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,4EAA4E;YAC5E,OAAO,WAAW,WAAW,CAAC,SAAS,iCAAiC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,0BAA0B,CAAC,WAA8B;QACrE,MAAM,WAAW,GAAG,WAAW,CAAC,WAAY,CAAC;QAC7C,MAAM,YAAY,GAAG,WAAW,CAAC,YAAa,CAAC;QAE/C,wBAAwB;QACxB,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEjD,mDAAmD;QACnD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC9D,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAEnE,gCAAgC;QAChC,IAAI,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;QAClC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACvD,IAAI,UAAU,EAAE,CAAC;YACf,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,GAAG,aAAa,CAAC;QAC3B,MAAM,gBAAgB,GAAG,cAAc,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvE,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpD,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,MAAM,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,2BAA2B;YAC7B,CAAC;QACH,CAAC;QAED,qCAAqC;QACrC,MAAM,aAAa,GAAG;MACpB,WAAW,CAAC,SAAS,IAAI,IAAI,CAAC,cAAc;UACxC,KAAK,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;WACpF,WAAW,CAAC,SAAS;WACrB,IAAI,CAAC,cAAc;;UAEpB,MAAM;;eAED,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;;;IAGnC,KAAK;;gBAEO,WAAW,CAAC,SAAS,qBAAqB,WAAW,CAAC,SAAS;;;;;;;;;;;;iDAY9B,WAAW,CAAC,SAAS;MAChE,IAAI,CAAC,cAAc,IAAI,WAAW,CAAC,SAAS;;EAEhD,WAAW,CAAC,iBAAiB;YAC7B,CAAC,CAAC,yBAAyB,WAAW,CAAC,iBAAiB,KAAK,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,GAAG;YACpH,CAAC,CAAC,+CAA+C;CAClD,CAAC;QAEE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACvD,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;QAEvD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,cAAc,IAAI,WAAW,CAAC,SAAS,YAAY,CAAC,CAAC;QAE1F,OAAO,WAAW,WAAW,YAAY,CAAC;IAC5C,CAAC;IAED;;OAEG;IACK,oBAAoB,CAAC,MAAwB;QACnD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QAC5D,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEpB,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAE3E,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;gBACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;gBAC9C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;gBACpD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC1E,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBAC3B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,iBAAiB,KAAK,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC;gBACxH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAE3E,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBACjE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB;QACpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO,MAAM,CAAC,aAAa;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,wBAAwB,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -17,5 +17,6 @@ export { ContentClassifier } from './content-classifier.js';
|
|
|
17
17
|
export { ProjectDetector } from './project-detector.js';
|
|
18
18
|
export { ContentDistributor } from './content-distributor.js';
|
|
19
19
|
export { CrossLinker } from './cross-linker.js';
|
|
20
|
+
export { FeatureConsistencyValidator } from './feature-consistency-validator.js';
|
|
20
21
|
export * from './types.js';
|
|
21
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,cAAc,YAAY,CAAC"}
|
|
@@ -21,5 +21,6 @@ export { ContentClassifier } from './content-classifier.js';
|
|
|
21
21
|
export { ProjectDetector } from './project-detector.js';
|
|
22
22
|
export { ContentDistributor } from './content-distributor.js';
|
|
23
23
|
export { CrossLinker } from './cross-linker.js';
|
|
24
|
+
export { FeatureConsistencyValidator } from './feature-consistency-validator.js';
|
|
24
25
|
export * from './types.js';
|
|
25
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/living-docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gEAAgE;AAChE,kDAAkD;AAClD,2DAA2D;AAE3D,0DAA0D;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/living-docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gEAAgE;AAChE,kDAAkD;AAClD,2DAA2D;AAE3D,0DAA0D;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,cAAc,YAAY,CAAC"}
|
|
@@ -221,5 +221,18 @@ export declare class LivingDocsSync {
|
|
|
221
221
|
* - Any other temporary files
|
|
222
222
|
*/
|
|
223
223
|
private cleanupTempFiles;
|
|
224
|
+
/**
|
|
225
|
+
* Validate and repair consistency between _features and project folders
|
|
226
|
+
*
|
|
227
|
+
* CRITICAL FIX (2025-11-25): Post-sync validation to prevent orphaned folders
|
|
228
|
+
*
|
|
229
|
+
* This method:
|
|
230
|
+
* 1. Checks if the just-synced feature exists in both _features/ and project folder
|
|
231
|
+
* 2. Auto-repairs if discrepancy found (creates missing project folder)
|
|
232
|
+
* 3. Logs warnings for manual intervention if auto-repair not possible
|
|
233
|
+
*
|
|
234
|
+
* @param featureId - Feature ID that was just synced (e.g., "FS-062")
|
|
235
|
+
*/
|
|
236
|
+
private validateAndRepairConsistency;
|
|
224
237
|
}
|
|
225
238
|
//# sourceMappingURL=living-docs-sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"living-docs-sync.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/living-docs-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"living-docs-sync.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/living-docs-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ import path from 'path';
|
|
|
13
13
|
import yaml from 'yaml';
|
|
14
14
|
import { FeatureIDManager } from './feature-id-manager.js';
|
|
15
15
|
import { TaskProjectSpecificGenerator } from './task-project-specific-generator.js';
|
|
16
|
+
import { FeatureConsistencyValidator } from './feature-consistency-validator.js';
|
|
16
17
|
import { consoleLogger } from '../../utils/logger.js';
|
|
17
18
|
// Helper functions for fs-extra compatibility
|
|
18
19
|
async function pathExists(filePath) {
|
|
@@ -179,6 +180,12 @@ export class LivingDocsSync {
|
|
|
179
180
|
if (!options.dryRun) {
|
|
180
181
|
await this.cleanupTempFiles(projectPath);
|
|
181
182
|
}
|
|
183
|
+
// Step 9: Validate consistency (auto-repair if needed)
|
|
184
|
+
// CRITICAL FIX (2025-11-25): Ensure _features and project folders are in sync
|
|
185
|
+
// This prevents orphaned _features folders without corresponding project folders
|
|
186
|
+
if (!options.dryRun) {
|
|
187
|
+
await this.validateAndRepairConsistency(featureId);
|
|
188
|
+
}
|
|
182
189
|
result.success = true;
|
|
183
190
|
this.logger.log(`â
Synced ${incrementId} â ${featureId}`);
|
|
184
191
|
this.logger.log(` Created: ${result.filesCreated.length} files`);
|
|
@@ -1046,5 +1053,48 @@ export class LivingDocsSync {
|
|
|
1046
1053
|
}
|
|
1047
1054
|
}
|
|
1048
1055
|
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Validate and repair consistency between _features and project folders
|
|
1058
|
+
*
|
|
1059
|
+
* CRITICAL FIX (2025-11-25): Post-sync validation to prevent orphaned folders
|
|
1060
|
+
*
|
|
1061
|
+
* This method:
|
|
1062
|
+
* 1. Checks if the just-synced feature exists in both _features/ and project folder
|
|
1063
|
+
* 2. Auto-repairs if discrepancy found (creates missing project folder)
|
|
1064
|
+
* 3. Logs warnings for manual intervention if auto-repair not possible
|
|
1065
|
+
*
|
|
1066
|
+
* @param featureId - Feature ID that was just synced (e.g., "FS-062")
|
|
1067
|
+
*/
|
|
1068
|
+
async validateAndRepairConsistency(featureId) {
|
|
1069
|
+
try {
|
|
1070
|
+
const validator = new FeatureConsistencyValidator(this.projectRoot, {
|
|
1071
|
+
logger: this.logger,
|
|
1072
|
+
defaultProject: 'specweave'
|
|
1073
|
+
});
|
|
1074
|
+
// Quick check for the specific feature we just synced
|
|
1075
|
+
const featuresPath = path.join(this.projectRoot, '.specweave/docs/internal/specs/_features', featureId);
|
|
1076
|
+
const projectPath = path.join(this.projectRoot, '.specweave/docs/internal/specs/specweave', featureId);
|
|
1077
|
+
// Check if _features exists but project folder doesn't
|
|
1078
|
+
if (existsSync(featuresPath) && !existsSync(projectPath)) {
|
|
1079
|
+
this.logger.warn(` â ī¸ Consistency issue detected: ${featureId} missing from specweave/`);
|
|
1080
|
+
// Run full validation with auto-repair for this feature
|
|
1081
|
+
const result = await validator.validate(true);
|
|
1082
|
+
if (result.repairs && result.repairs.length > 0) {
|
|
1083
|
+
const repair = result.repairs.find(r => r.featureId === featureId);
|
|
1084
|
+
if (repair?.success) {
|
|
1085
|
+
this.logger.log(` â
Auto-repaired: created specweave/${featureId}/`);
|
|
1086
|
+
}
|
|
1087
|
+
else {
|
|
1088
|
+
this.logger.warn(` â ī¸ Auto-repair failed for ${featureId}: ${repair?.error}`);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
catch (error) {
|
|
1094
|
+
// Non-fatal - log warning but continue
|
|
1095
|
+
this.logger.warn(` â ī¸ Consistency validation failed: ${error}`);
|
|
1096
|
+
this.logger.warn(` Sync completed but consistency not verified`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1049
1099
|
}
|
|
1050
1100
|
//# sourceMappingURL=living-docs-sync.js.map
|