sdd-mcp-server 1.0.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.
Files changed (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +256 -0
  3. package/dist/__tests__/setup.d.ts +44 -0
  4. package/dist/__tests__/setup.js +178 -0
  5. package/dist/__tests__/setup.js.map +1 -0
  6. package/dist/__tests__/test-helpers/mock-factories.d.ts +26 -0
  7. package/dist/__tests__/test-helpers/mock-factories.js +466 -0
  8. package/dist/__tests__/test-helpers/mock-factories.js.map +1 -0
  9. package/dist/adapters/cli/SDDToolAdapter.d.ts +26 -0
  10. package/dist/adapters/cli/SDDToolAdapter.js +273 -0
  11. package/dist/adapters/cli/SDDToolAdapter.js.map +1 -0
  12. package/dist/application/services/CodebaseAnalysisService.d.ts +38 -0
  13. package/dist/application/services/CodebaseAnalysisService.js +737 -0
  14. package/dist/application/services/CodebaseAnalysisService.js.map +1 -0
  15. package/dist/application/services/LocalizationService.d.ts +184 -0
  16. package/dist/application/services/LocalizationService.js +536 -0
  17. package/dist/application/services/LocalizationService.js.map +1 -0
  18. package/dist/application/services/ProjectContextService.d.ts +61 -0
  19. package/dist/application/services/ProjectContextService.js +550 -0
  20. package/dist/application/services/ProjectContextService.js.map +1 -0
  21. package/dist/application/services/ProjectInitializationService.d.ts +57 -0
  22. package/dist/application/services/ProjectInitializationService.js +485 -0
  23. package/dist/application/services/ProjectInitializationService.js.map +1 -0
  24. package/dist/application/services/ProjectService.d.ts +19 -0
  25. package/dist/application/services/ProjectService.js +159 -0
  26. package/dist/application/services/ProjectService.js.map +1 -0
  27. package/dist/application/services/QualityGateService.d.ts +62 -0
  28. package/dist/application/services/QualityGateService.js +428 -0
  29. package/dist/application/services/QualityGateService.js.map +1 -0
  30. package/dist/application/services/QualityService.d.ts +43 -0
  31. package/dist/application/services/QualityService.js +245 -0
  32. package/dist/application/services/QualityService.js.map +1 -0
  33. package/dist/application/services/SteeringDocumentService.d.ts +62 -0
  34. package/dist/application/services/SteeringDocumentService.js +694 -0
  35. package/dist/application/services/SteeringDocumentService.js.map +1 -0
  36. package/dist/application/services/TemplateService.d.ts +47 -0
  37. package/dist/application/services/TemplateService.js +438 -0
  38. package/dist/application/services/TemplateService.js.map +1 -0
  39. package/dist/application/services/WorkflowEngineService.d.ts +56 -0
  40. package/dist/application/services/WorkflowEngineService.js +348 -0
  41. package/dist/application/services/WorkflowEngineService.js.map +1 -0
  42. package/dist/application/services/WorkflowService.d.ts +22 -0
  43. package/dist/application/services/WorkflowService.js +147 -0
  44. package/dist/application/services/WorkflowService.js.map +1 -0
  45. package/dist/application/services/WorkflowValidationService.d.ts +51 -0
  46. package/dist/application/services/WorkflowValidationService.js +665 -0
  47. package/dist/application/services/WorkflowValidationService.js.map +1 -0
  48. package/dist/domain/context/ProjectContext.d.ts +350 -0
  49. package/dist/domain/context/ProjectContext.js +138 -0
  50. package/dist/domain/context/ProjectContext.js.map +1 -0
  51. package/dist/domain/i18n/index.d.ts +286 -0
  52. package/dist/domain/i18n/index.js +97 -0
  53. package/dist/domain/i18n/index.js.map +1 -0
  54. package/dist/domain/plugins/index.d.ts +498 -0
  55. package/dist/domain/plugins/index.js +157 -0
  56. package/dist/domain/plugins/index.js.map +1 -0
  57. package/dist/domain/ports.d.ts +54 -0
  58. package/dist/domain/ports.js +3 -0
  59. package/dist/domain/ports.js.map +1 -0
  60. package/dist/domain/quality/index.d.ts +361 -0
  61. package/dist/domain/quality/index.js +113 -0
  62. package/dist/domain/quality/index.js.map +1 -0
  63. package/dist/domain/services/DomainService.d.ts +18 -0
  64. package/dist/domain/services/DomainService.js +71 -0
  65. package/dist/domain/services/DomainService.js.map +1 -0
  66. package/dist/domain/templates/index.d.ts +158 -0
  67. package/dist/domain/templates/index.js +22 -0
  68. package/dist/domain/templates/index.js.map +1 -0
  69. package/dist/domain/types.d.ts +115 -0
  70. package/dist/domain/types.js +37 -0
  71. package/dist/domain/types.js.map +1 -0
  72. package/dist/domain/workflow/WorkflowStateMachine.d.ts +62 -0
  73. package/dist/domain/workflow/WorkflowStateMachine.js +286 -0
  74. package/dist/domain/workflow/WorkflowStateMachine.js.map +1 -0
  75. package/dist/index.d.ts +19 -0
  76. package/dist/index.js +97 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/infrastructure/adapters/AjvValidationAdapter.d.ts +7 -0
  79. package/dist/infrastructure/adapters/AjvValidationAdapter.js +37 -0
  80. package/dist/infrastructure/adapters/AjvValidationAdapter.js.map +1 -0
  81. package/dist/infrastructure/adapters/ConsoleLoggerAdapter.d.ts +8 -0
  82. package/dist/infrastructure/adapters/ConsoleLoggerAdapter.js +41 -0
  83. package/dist/infrastructure/adapters/ConsoleLoggerAdapter.js.map +1 -0
  84. package/dist/infrastructure/adapters/FileBasedTaskTracker.d.ts +9 -0
  85. package/dist/infrastructure/adapters/FileBasedTaskTracker.js +41 -0
  86. package/dist/infrastructure/adapters/FileBasedTaskTracker.js.map +1 -0
  87. package/dist/infrastructure/adapters/HandlebarsTemplateEngine.d.ts +8 -0
  88. package/dist/infrastructure/adapters/HandlebarsTemplateEngine.js +38 -0
  89. package/dist/infrastructure/adapters/HandlebarsTemplateEngine.js.map +1 -0
  90. package/dist/infrastructure/adapters/JsonConfigurationAdapter.d.ts +7 -0
  91. package/dist/infrastructure/adapters/JsonConfigurationAdapter.js +24 -0
  92. package/dist/infrastructure/adapters/JsonConfigurationAdapter.js.map +1 -0
  93. package/dist/infrastructure/adapters/LinusQualityAnalyzer.d.ts +9 -0
  94. package/dist/infrastructure/adapters/LinusQualityAnalyzer.js +75 -0
  95. package/dist/infrastructure/adapters/LinusQualityAnalyzer.js.map +1 -0
  96. package/dist/infrastructure/adapters/NodeFileSystemAdapter.d.ts +12 -0
  97. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js +39 -0
  98. package/dist/infrastructure/adapters/NodeFileSystemAdapter.js.map +1 -0
  99. package/dist/infrastructure/di/container.d.ts +3 -0
  100. package/dist/infrastructure/di/container.js +98 -0
  101. package/dist/infrastructure/di/container.js.map +1 -0
  102. package/dist/infrastructure/di/types.d.ts +39 -0
  103. package/dist/infrastructure/di/types.js +45 -0
  104. package/dist/infrastructure/di/types.js.map +1 -0
  105. package/dist/infrastructure/i18n/I18nextService.d.ts +27 -0
  106. package/dist/infrastructure/i18n/I18nextService.js +357 -0
  107. package/dist/infrastructure/i18n/I18nextService.js.map +1 -0
  108. package/dist/infrastructure/mcp/CapabilityNegotiator.d.ts +21 -0
  109. package/dist/infrastructure/mcp/CapabilityNegotiator.js +75 -0
  110. package/dist/infrastructure/mcp/CapabilityNegotiator.js.map +1 -0
  111. package/dist/infrastructure/mcp/ErrorHandler.d.ts +29 -0
  112. package/dist/infrastructure/mcp/ErrorHandler.js +101 -0
  113. package/dist/infrastructure/mcp/ErrorHandler.js.map +1 -0
  114. package/dist/infrastructure/mcp/MCPServer.d.ts +25 -0
  115. package/dist/infrastructure/mcp/MCPServer.js +246 -0
  116. package/dist/infrastructure/mcp/MCPServer.js.map +1 -0
  117. package/dist/infrastructure/mcp/PromptManager.d.ts +18 -0
  118. package/dist/infrastructure/mcp/PromptManager.js +373 -0
  119. package/dist/infrastructure/mcp/PromptManager.js.map +1 -0
  120. package/dist/infrastructure/mcp/ResourceManager.d.ts +15 -0
  121. package/dist/infrastructure/mcp/ResourceManager.js +229 -0
  122. package/dist/infrastructure/mcp/ResourceManager.js.map +1 -0
  123. package/dist/infrastructure/mcp/SessionManager.d.ts +64 -0
  124. package/dist/infrastructure/mcp/SessionManager.js +221 -0
  125. package/dist/infrastructure/mcp/SessionManager.js.map +1 -0
  126. package/dist/infrastructure/mcp/ToolRegistry.d.ts +48 -0
  127. package/dist/infrastructure/mcp/ToolRegistry.js +235 -0
  128. package/dist/infrastructure/mcp/ToolRegistry.js.map +1 -0
  129. package/dist/infrastructure/platform/PlatformAdapter.d.ts +46 -0
  130. package/dist/infrastructure/platform/PlatformAdapter.js +355 -0
  131. package/dist/infrastructure/platform/PlatformAdapter.js.map +1 -0
  132. package/dist/infrastructure/plugins/HookSystem.d.ts +40 -0
  133. package/dist/infrastructure/plugins/HookSystem.js +415 -0
  134. package/dist/infrastructure/plugins/HookSystem.js.map +1 -0
  135. package/dist/infrastructure/plugins/PluginManager.d.ts +51 -0
  136. package/dist/infrastructure/plugins/PluginManager.js +650 -0
  137. package/dist/infrastructure/plugins/PluginManager.js.map +1 -0
  138. package/dist/infrastructure/plugins/PluginSteeringRegistry.d.ts +63 -0
  139. package/dist/infrastructure/plugins/PluginSteeringRegistry.js +439 -0
  140. package/dist/infrastructure/plugins/PluginSteeringRegistry.js.map +1 -0
  141. package/dist/infrastructure/plugins/PluginToolRegistry.d.ts +54 -0
  142. package/dist/infrastructure/plugins/PluginToolRegistry.js +490 -0
  143. package/dist/infrastructure/plugins/PluginToolRegistry.js.map +1 -0
  144. package/dist/infrastructure/quality/ASTAnalyzer.d.ts +65 -0
  145. package/dist/infrastructure/quality/ASTAnalyzer.js +439 -0
  146. package/dist/infrastructure/quality/ASTAnalyzer.js.map +1 -0
  147. package/dist/infrastructure/quality/LinusCodeReviewer.d.ts +52 -0
  148. package/dist/infrastructure/quality/LinusCodeReviewer.js +551 -0
  149. package/dist/infrastructure/quality/LinusCodeReviewer.js.map +1 -0
  150. package/dist/infrastructure/repositories/InMemoryProjectRepository.d.ts +10 -0
  151. package/dist/infrastructure/repositories/InMemoryProjectRepository.js +35 -0
  152. package/dist/infrastructure/repositories/InMemoryProjectRepository.js.map +1 -0
  153. package/dist/infrastructure/schemas/project.schema.d.ts +192 -0
  154. package/dist/infrastructure/schemas/project.schema.js +114 -0
  155. package/dist/infrastructure/schemas/project.schema.js.map +1 -0
  156. package/dist/infrastructure/templates/FileGenerator.d.ts +15 -0
  157. package/dist/infrastructure/templates/FileGenerator.js +385 -0
  158. package/dist/infrastructure/templates/FileGenerator.js.map +1 -0
  159. package/dist/infrastructure/templates/HandlebarsRenderer.d.ts +16 -0
  160. package/dist/infrastructure/templates/HandlebarsRenderer.js +252 -0
  161. package/dist/infrastructure/templates/HandlebarsRenderer.js.map +1 -0
  162. package/dist/infrastructure/templates/TemplateManager.d.ts +36 -0
  163. package/dist/infrastructure/templates/TemplateManager.js +777 -0
  164. package/dist/infrastructure/templates/TemplateManager.js.map +1 -0
  165. package/package.json +89 -0
@@ -0,0 +1,665 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { injectable, inject } from 'inversify';
14
+ import { v4 as uuidv4 } from 'uuid';
15
+ import { TYPES } from '../../infrastructure/di/types.js';
16
+ import { WorkflowPhase } from '../../domain/types.js';
17
+ import { WorkflowStateMachine } from '../../domain/workflow/WorkflowStateMachine.js';
18
+ let WorkflowValidationService = class WorkflowValidationService {
19
+ projectRepository;
20
+ fileSystem;
21
+ validation;
22
+ logger;
23
+ stateMachine;
24
+ constructor(projectRepository, fileSystem, validation, logger) {
25
+ this.projectRepository = projectRepository;
26
+ this.fileSystem = fileSystem;
27
+ this.validation = validation;
28
+ this.logger = logger;
29
+ this.stateMachine = new WorkflowStateMachine();
30
+ }
31
+ async validateRequirementsCompletion(projectId) {
32
+ const correlationId = uuidv4();
33
+ this.logger.info('Validating requirements completion', {
34
+ correlationId,
35
+ projectId
36
+ });
37
+ const project = await this.projectRepository.findById(projectId);
38
+ if (!project) {
39
+ return {
40
+ isComplete: false,
41
+ missingItems: ['Project not found'],
42
+ qualityIssues: [],
43
+ readinessScore: 0,
44
+ recommendations: []
45
+ };
46
+ }
47
+ const missingItems = [];
48
+ const qualityIssues = [];
49
+ const recommendations = [];
50
+ let readinessScore = 0;
51
+ try {
52
+ // Check if requirements document exists
53
+ const requirementsPath = `${project.path}/.kiro/specs/${project.name}/requirements.md`;
54
+ if (!(await this.fileSystem.exists(requirementsPath))) {
55
+ missingItems.push('requirements.md file not found');
56
+ }
57
+ else {
58
+ const content = await this.fileSystem.readFile(requirementsPath);
59
+ // Basic content validation
60
+ if (content.trim().length < 100) {
61
+ qualityIssues.push('Requirements document is too short (less than 100 characters)');
62
+ }
63
+ // Check for EARS format patterns
64
+ const earsPatterns = ['WHEN', 'WHERE', 'IF', 'THEN', 'SHALL'];
65
+ const hasEarsFormat = earsPatterns.some(pattern => content.includes(pattern));
66
+ if (!hasEarsFormat) {
67
+ qualityIssues.push('Requirements do not follow EARS format (missing WHEN/WHERE/IF...THEN/SHALL patterns)');
68
+ }
69
+ else {
70
+ readinessScore += 30;
71
+ }
72
+ // Check for acceptance criteria
73
+ if (content.includes('Acceptance Criteria') || content.includes('acceptance criteria')) {
74
+ readinessScore += 20;
75
+ }
76
+ else {
77
+ missingItems.push('Acceptance criteria sections');
78
+ }
79
+ // Check for requirement numbering
80
+ const requirementCount = (content.match(/### Requirement \d+:/g) || []).length;
81
+ if (requirementCount === 0) {
82
+ missingItems.push('Numbered requirement sections');
83
+ }
84
+ else {
85
+ readinessScore += 20;
86
+ }
87
+ if (requirementCount >= 3) {
88
+ readinessScore += 10; // Bonus for having multiple requirements
89
+ }
90
+ }
91
+ // Check approval status
92
+ if (project.metadata.approvals.requirements.generated) {
93
+ readinessScore += 10;
94
+ }
95
+ else {
96
+ missingItems.push('Requirements generation flag');
97
+ }
98
+ if (project.metadata.approvals.requirements.approved) {
99
+ readinessScore += 10;
100
+ }
101
+ else {
102
+ recommendations.push('Requirements need review and approval before proceeding to design');
103
+ }
104
+ // Generate recommendations
105
+ if (missingItems.length > 0) {
106
+ recommendations.push('Complete missing requirements items before approval');
107
+ }
108
+ if (qualityIssues.length > 0) {
109
+ recommendations.push('Address quality issues to improve requirements clarity');
110
+ }
111
+ if (readinessScore >= 80) {
112
+ recommendations.push('Requirements are ready for design phase');
113
+ }
114
+ else if (readinessScore >= 60) {
115
+ recommendations.push('Requirements need minor improvements before design');
116
+ }
117
+ else {
118
+ recommendations.push('Requirements need significant work before design phase');
119
+ }
120
+ this.logger.info('Requirements validation completed', {
121
+ correlationId,
122
+ projectId,
123
+ readinessScore,
124
+ missingCount: missingItems.length,
125
+ qualityIssueCount: qualityIssues.length
126
+ });
127
+ return {
128
+ isComplete: missingItems.length === 0 && qualityIssues.length === 0,
129
+ missingItems,
130
+ qualityIssues,
131
+ readinessScore: Math.min(readinessScore, 100),
132
+ recommendations
133
+ };
134
+ }
135
+ catch (error) {
136
+ this.logger.error('Requirements validation failed', error, {
137
+ correlationId,
138
+ projectId
139
+ });
140
+ return {
141
+ isComplete: false,
142
+ missingItems: [`Validation error: ${error.message}`],
143
+ qualityIssues: [],
144
+ readinessScore: 0,
145
+ recommendations: ['Fix validation errors and try again']
146
+ };
147
+ }
148
+ }
149
+ async validateDesignApproval(projectId) {
150
+ const correlationId = uuidv4();
151
+ this.logger.info('Validating design approval readiness', {
152
+ correlationId,
153
+ projectId
154
+ });
155
+ const project = await this.projectRepository.findById(projectId);
156
+ if (!project) {
157
+ return {
158
+ isComplete: false,
159
+ missingItems: ['Project not found'],
160
+ qualityIssues: [],
161
+ readinessScore: 0,
162
+ recommendations: []
163
+ };
164
+ }
165
+ const missingItems = [];
166
+ const qualityIssues = [];
167
+ const recommendations = [];
168
+ let readinessScore = 0;
169
+ try {
170
+ // Check if design document exists
171
+ const designPath = `${project.path}/.kiro/specs/${project.name}/design.md`;
172
+ if (!(await this.fileSystem.exists(designPath))) {
173
+ missingItems.push('design.md file not found');
174
+ }
175
+ else {
176
+ const content = await this.fileSystem.readFile(designPath);
177
+ // Basic content validation
178
+ if (content.trim().length < 200) {
179
+ qualityIssues.push('Design document is too short (less than 200 characters)');
180
+ }
181
+ // Check for key design sections
182
+ const designSections = [
183
+ 'Architecture',
184
+ 'Components',
185
+ 'Interface',
186
+ 'Data Model',
187
+ 'Technology'
188
+ ];
189
+ let foundSections = 0;
190
+ for (const section of designSections) {
191
+ if (content.toLowerCase().includes(section.toLowerCase())) {
192
+ foundSections++;
193
+ }
194
+ }
195
+ readinessScore += (foundSections / designSections.length) * 40;
196
+ if (foundSections < 3) {
197
+ missingItems.push(`Design missing key sections (found ${foundSections}/${designSections.length})`);
198
+ }
199
+ // Check for architectural diagrams or descriptions
200
+ if (content.includes('```') || content.includes('diagram') || content.includes('architecture')) {
201
+ readinessScore += 20;
202
+ }
203
+ else {
204
+ qualityIssues.push('Design lacks architectural diagrams or detailed descriptions');
205
+ }
206
+ // Check for technology decisions
207
+ if (content.toLowerCase().includes('technology') || content.toLowerCase().includes('stack')) {
208
+ readinessScore += 15;
209
+ }
210
+ else {
211
+ missingItems.push('Technology stack decisions');
212
+ }
213
+ }
214
+ // Validate requirements are approved first
215
+ if (!project.metadata.approvals.requirements.approved) {
216
+ missingItems.push('Requirements must be approved before design approval');
217
+ }
218
+ else {
219
+ readinessScore += 15;
220
+ }
221
+ // Check approval status
222
+ if (project.metadata.approvals.design.generated) {
223
+ readinessScore += 5;
224
+ }
225
+ else {
226
+ missingItems.push('Design generation flag');
227
+ }
228
+ if (project.metadata.approvals.design.approved) {
229
+ readinessScore += 5;
230
+ }
231
+ else {
232
+ recommendations.push('Design needs review and approval before proceeding to tasks');
233
+ }
234
+ // Generate recommendations
235
+ if (readinessScore >= 80) {
236
+ recommendations.push('Design is ready for tasks phase');
237
+ }
238
+ else if (readinessScore >= 60) {
239
+ recommendations.push('Design needs minor improvements before tasks');
240
+ }
241
+ else {
242
+ recommendations.push('Design needs significant work before tasks phase');
243
+ }
244
+ this.logger.info('Design validation completed', {
245
+ correlationId,
246
+ projectId,
247
+ readinessScore,
248
+ missingCount: missingItems.length,
249
+ qualityIssueCount: qualityIssues.length
250
+ });
251
+ return {
252
+ isComplete: missingItems.length === 0 && qualityIssues.length === 0,
253
+ missingItems,
254
+ qualityIssues,
255
+ readinessScore: Math.min(readinessScore, 100),
256
+ recommendations
257
+ };
258
+ }
259
+ catch (error) {
260
+ this.logger.error('Design validation failed', error, {
261
+ correlationId,
262
+ projectId
263
+ });
264
+ return {
265
+ isComplete: false,
266
+ missingItems: [`Validation error: ${error.message}`],
267
+ qualityIssues: [],
268
+ readinessScore: 0,
269
+ recommendations: ['Fix validation errors and try again']
270
+ };
271
+ }
272
+ }
273
+ async validateTaskApproval(projectId) {
274
+ const correlationId = uuidv4();
275
+ this.logger.info('Validating task approval readiness', {
276
+ correlationId,
277
+ projectId
278
+ });
279
+ const project = await this.projectRepository.findById(projectId);
280
+ if (!project) {
281
+ return {
282
+ isComplete: false,
283
+ missingItems: ['Project not found'],
284
+ qualityIssues: [],
285
+ readinessScore: 0,
286
+ recommendations: []
287
+ };
288
+ }
289
+ const missingItems = [];
290
+ const qualityIssues = [];
291
+ const recommendations = [];
292
+ let readinessScore = 0;
293
+ try {
294
+ // Check if tasks document exists
295
+ const tasksPath = `${project.path}/.kiro/specs/${project.name}/tasks.md`;
296
+ if (!(await this.fileSystem.exists(tasksPath))) {
297
+ missingItems.push('tasks.md file not found');
298
+ }
299
+ else {
300
+ const content = await this.fileSystem.readFile(tasksPath);
301
+ // Basic content validation
302
+ if (content.trim().length < 150) {
303
+ qualityIssues.push('Tasks document is too short (less than 150 characters)');
304
+ }
305
+ // Count tasks
306
+ const taskMatches = content.match(/- \[ \] \d+\./g) || [];
307
+ const taskCount = taskMatches.length;
308
+ if (taskCount === 0) {
309
+ missingItems.push('No tasks found in checkbox format');
310
+ }
311
+ else {
312
+ readinessScore += Math.min(taskCount * 5, 30); // Up to 30 points for tasks
313
+ }
314
+ // Check for requirement references
315
+ const requirementRefs = (content.match(/_Requirements: /g) || []).length;
316
+ if (requirementRefs === 0) {
317
+ qualityIssues.push('Tasks missing requirement traceability references');
318
+ }
319
+ else {
320
+ readinessScore += 20;
321
+ }
322
+ // Check for subtasks
323
+ const subtaskMatches = content.match(/ - [A-Z]/g) || [];
324
+ if (subtaskMatches.length === 0) {
325
+ qualityIssues.push('Tasks missing detailed subtasks');
326
+ }
327
+ else {
328
+ readinessScore += 15;
329
+ }
330
+ // Check task categories/organization
331
+ if (content.includes('# Implementation Plan') || content.includes('## ')) {
332
+ readinessScore += 10;
333
+ }
334
+ else {
335
+ qualityIssues.push('Tasks lack proper organization/categorization');
336
+ }
337
+ }
338
+ // Validate design is approved first
339
+ if (!project.metadata.approvals.design.approved) {
340
+ missingItems.push('Design must be approved before task approval');
341
+ }
342
+ else {
343
+ readinessScore += 15;
344
+ }
345
+ // Check approval status
346
+ if (project.metadata.approvals.tasks.generated) {
347
+ readinessScore += 5;
348
+ }
349
+ else {
350
+ missingItems.push('Tasks generation flag');
351
+ }
352
+ if (project.metadata.approvals.tasks.approved) {
353
+ readinessScore += 5;
354
+ }
355
+ else {
356
+ recommendations.push('Tasks need review and approval before proceeding to implementation');
357
+ }
358
+ // Generate recommendations
359
+ if (readinessScore >= 80) {
360
+ recommendations.push('Tasks are ready for implementation phase');
361
+ recommendations.push('Begin implementing tasks in order of priority');
362
+ }
363
+ else if (readinessScore >= 60) {
364
+ recommendations.push('Tasks need minor improvements before implementation');
365
+ }
366
+ else {
367
+ recommendations.push('Tasks need significant work before implementation phase');
368
+ }
369
+ this.logger.info('Tasks validation completed', {
370
+ correlationId,
371
+ projectId,
372
+ readinessScore,
373
+ missingCount: missingItems.length,
374
+ qualityIssueCount: qualityIssues.length
375
+ });
376
+ return {
377
+ isComplete: missingItems.length === 0 && qualityIssues.length === 0,
378
+ missingItems,
379
+ qualityIssues,
380
+ readinessScore: Math.min(readinessScore, 100),
381
+ recommendations
382
+ };
383
+ }
384
+ catch (error) {
385
+ this.logger.error('Tasks validation failed', error, {
386
+ correlationId,
387
+ projectId
388
+ });
389
+ return {
390
+ isComplete: false,
391
+ missingItems: [`Validation error: ${error.message}`],
392
+ qualityIssues: [],
393
+ readinessScore: 0,
394
+ recommendations: ['Fix validation errors and try again']
395
+ };
396
+ }
397
+ }
398
+ async validateCrossPhaseConsistency(projectId) {
399
+ const correlationId = uuidv4();
400
+ this.logger.info('Validating cross-phase consistency', {
401
+ correlationId,
402
+ projectId
403
+ });
404
+ const project = await this.projectRepository.findById(projectId);
405
+ if (!project) {
406
+ return {
407
+ isConsistent: false,
408
+ inconsistencies: ['Project not found'],
409
+ traceabilityIssues: [],
410
+ coverageGaps: []
411
+ };
412
+ }
413
+ const inconsistencies = [];
414
+ const traceabilityIssues = [];
415
+ const coverageGaps = [];
416
+ try {
417
+ const basePath = `${project.path}/.kiro/specs/${project.name}`;
418
+ // Read all phase documents
419
+ const documents = {};
420
+ const files = ['requirements.md', 'design.md', 'tasks.md'];
421
+ for (const file of files) {
422
+ const filePath = `${basePath}/${file}`;
423
+ if (await this.fileSystem.exists(filePath)) {
424
+ documents[file] = await this.fileSystem.readFile(filePath);
425
+ }
426
+ }
427
+ // Validate Requirements -> Design traceability
428
+ if (documents['requirements.md'] && documents['design.md']) {
429
+ const requirements = documents['requirements.md'];
430
+ const design = documents['design.md'];
431
+ // Extract requirement titles
432
+ const reqMatches = requirements.match(/### Requirement \d+: (.+)/g) || [];
433
+ const requirementTitles = reqMatches.map(match => match.replace(/### Requirement \d+: /, '').trim());
434
+ // Check if design addresses all requirements
435
+ for (const reqTitle of requirementTitles) {
436
+ const keywords = reqTitle.split(' ').filter(word => word.length > 3);
437
+ const hasReference = keywords.some(keyword => design.toLowerCase().includes(keyword.toLowerCase()));
438
+ if (!hasReference) {
439
+ traceabilityIssues.push(`Design may not address requirement: "${reqTitle}"`);
440
+ }
441
+ }
442
+ }
443
+ // Validate Design -> Tasks traceability
444
+ if (documents['design.md'] && documents['tasks.md']) {
445
+ const design = documents['design.md'];
446
+ const tasks = documents['tasks.md'];
447
+ // Look for component mentions in design
448
+ const componentMatches = design.match(/## (.+Component|.+Service|.+Manager)/g) || [];
449
+ const components = componentMatches.map(match => match.replace('## ', '').trim());
450
+ // Check if tasks cover all components
451
+ for (const component of components) {
452
+ const keywords = component.split(' ').filter(word => word.length > 3);
453
+ const hasCoverage = keywords.some(keyword => tasks.toLowerCase().includes(keyword.toLowerCase()));
454
+ if (!hasCoverage) {
455
+ coverageGaps.push(`Tasks may not cover design component: "${component}"`);
456
+ }
457
+ }
458
+ }
459
+ // Validate phase consistency with project metadata
460
+ const { phase, metadata } = project;
461
+ if (phase === WorkflowPhase.REQUIREMENTS && !metadata.approvals.requirements.generated) {
462
+ inconsistencies.push('Project in requirements phase but requirements not marked as generated');
463
+ }
464
+ if (phase === WorkflowPhase.DESIGN && !metadata.approvals.design.generated) {
465
+ inconsistencies.push('Project in design phase but design not marked as generated');
466
+ }
467
+ if (phase === WorkflowPhase.TASKS && !metadata.approvals.tasks.generated) {
468
+ inconsistencies.push('Project in tasks phase but tasks not marked as generated');
469
+ }
470
+ // Check for orphaned approvals (approved but not generated)
471
+ Object.entries(metadata.approvals).forEach(([phaseName, approval]) => {
472
+ if (approval.approved && !approval.generated) {
473
+ inconsistencies.push(`${phaseName} marked as approved but not generated`);
474
+ }
475
+ });
476
+ this.logger.info('Cross-phase validation completed', {
477
+ correlationId,
478
+ projectId,
479
+ inconsistencyCount: inconsistencies.length,
480
+ traceabilityIssueCount: traceabilityIssues.length,
481
+ coverageGapCount: coverageGaps.length
482
+ });
483
+ return {
484
+ isConsistent: inconsistencies.length === 0 &&
485
+ traceabilityIssues.length === 0 &&
486
+ coverageGaps.length === 0,
487
+ inconsistencies,
488
+ traceabilityIssues,
489
+ coverageGaps
490
+ };
491
+ }
492
+ catch (error) {
493
+ this.logger.error('Cross-phase validation failed', error, {
494
+ correlationId,
495
+ projectId
496
+ });
497
+ return {
498
+ isConsistent: false,
499
+ inconsistencies: [`Validation error: ${error.message}`],
500
+ traceabilityIssues: [],
501
+ coverageGaps: []
502
+ };
503
+ }
504
+ }
505
+ async validateWorkflowRollback(projectId, targetPhase) {
506
+ const correlationId = uuidv4();
507
+ this.logger.info('Validating workflow rollback', {
508
+ correlationId,
509
+ projectId,
510
+ targetPhase
511
+ });
512
+ const project = await this.projectRepository.findById(projectId);
513
+ if (!project) {
514
+ return {
515
+ canRollback: false,
516
+ reason: 'Project not found',
517
+ impactedItems: [],
518
+ rollbackActions: []
519
+ };
520
+ }
521
+ const impactedItems = [];
522
+ const rollbackActions = [];
523
+ try {
524
+ // Check if rollback is valid
525
+ const validation = this.stateMachine.canTransition(project, targetPhase);
526
+ if (!validation.allowed) {
527
+ return {
528
+ canRollback: false,
529
+ reason: validation.reason,
530
+ impactedItems: [],
531
+ rollbackActions: []
532
+ };
533
+ }
534
+ // Identify impacted items based on rollback target
535
+ const currentPhase = project.phase;
536
+ switch (currentPhase) {
537
+ case WorkflowPhase.REQUIREMENTS:
538
+ if (targetPhase === WorkflowPhase.INIT) {
539
+ impactedItems.push('Requirements document and approval status');
540
+ rollbackActions.push('Reset requirements approval status');
541
+ rollbackActions.push('Optionally backup requirements.md');
542
+ }
543
+ break;
544
+ case WorkflowPhase.DESIGN:
545
+ if (targetPhase === WorkflowPhase.REQUIREMENTS) {
546
+ impactedItems.push('Design document and approval status');
547
+ rollbackActions.push('Reset design approval status');
548
+ rollbackActions.push('Optionally backup design.md');
549
+ }
550
+ break;
551
+ case WorkflowPhase.TASKS:
552
+ if (targetPhase === WorkflowPhase.DESIGN) {
553
+ impactedItems.push('Tasks document and approval status');
554
+ rollbackActions.push('Reset tasks approval status');
555
+ rollbackActions.push('Optionally backup tasks.md');
556
+ }
557
+ break;
558
+ case WorkflowPhase.IMPLEMENTATION:
559
+ if (targetPhase === WorkflowPhase.TASKS) {
560
+ impactedItems.push('Implementation progress');
561
+ rollbackActions.push('Implementation work may be lost');
562
+ rollbackActions.push('Consider backing up current implementation');
563
+ }
564
+ break;
565
+ }
566
+ // Add general rollback actions
567
+ rollbackActions.push('Update project phase in spec.json');
568
+ rollbackActions.push('Update project metadata timestamps');
569
+ rollbackActions.push('Create audit trail entry');
570
+ this.logger.info('Workflow rollback validation completed', {
571
+ correlationId,
572
+ projectId,
573
+ currentPhase,
574
+ targetPhase,
575
+ impactedCount: impactedItems.length
576
+ });
577
+ return {
578
+ canRollback: true,
579
+ impactedItems,
580
+ rollbackActions
581
+ };
582
+ }
583
+ catch (error) {
584
+ this.logger.error('Workflow rollback validation failed', error, {
585
+ correlationId,
586
+ projectId,
587
+ targetPhase
588
+ });
589
+ return {
590
+ canRollback: false,
591
+ reason: `Validation error: ${error.message}`,
592
+ impactedItems: [],
593
+ rollbackActions: []
594
+ };
595
+ }
596
+ }
597
+ async generateComprehensiveValidationReport(projectId) {
598
+ const project = await this.projectRepository.findById(projectId);
599
+ if (!project) {
600
+ return null;
601
+ }
602
+ const phases = {
603
+ requirements: await this.validateRequirementsCompletion(projectId),
604
+ design: await this.validateDesignApproval(projectId),
605
+ tasks: await this.validateTaskApproval(projectId)
606
+ };
607
+ const crossPhase = await this.validateCrossPhaseConsistency(projectId);
608
+ // Calculate overall readiness
609
+ const phaseScores = [
610
+ phases.requirements.readinessScore,
611
+ phases.design.readinessScore,
612
+ phases.tasks.readinessScore
613
+ ];
614
+ const overallScore = Math.round(phaseScores.reduce((sum, score) => sum + score, 0) / 3);
615
+ // Determine overall validity
616
+ const isValid = phases.requirements.isComplete &&
617
+ phases.design.isComplete &&
618
+ phases.tasks.isComplete &&
619
+ crossPhase.isConsistent;
620
+ // Check if can progress
621
+ const nextPhase = this.stateMachine.getNextPhase(project.phase);
622
+ const canProgress = nextPhase ?
623
+ this.stateMachine.canTransition(project, nextPhase).allowed : false;
624
+ // Collect recommendations
625
+ const recommendations = [
626
+ ...phases.requirements.recommendations,
627
+ ...phases.design.recommendations,
628
+ ...phases.tasks.recommendations
629
+ ];
630
+ // Generate next actions
631
+ const nextActions = [];
632
+ if (!canProgress && nextPhase) {
633
+ nextActions.push(`Complete requirements for ${nextPhase} phase progression`);
634
+ }
635
+ if (crossPhase.inconsistencies.length > 0) {
636
+ nextActions.push('Resolve cross-phase consistency issues');
637
+ }
638
+ if (isValid && canProgress) {
639
+ nextActions.push('Project is ready for phase progression');
640
+ }
641
+ return {
642
+ project,
643
+ overall: {
644
+ isValid,
645
+ readinessScore: overallScore,
646
+ phase: project.phase,
647
+ canProgress
648
+ },
649
+ phases,
650
+ crossPhase,
651
+ recommendations: [...new Set(recommendations)], // Remove duplicates
652
+ nextActions
653
+ };
654
+ }
655
+ };
656
+ WorkflowValidationService = __decorate([
657
+ injectable(),
658
+ __param(0, inject(TYPES.ProjectRepository)),
659
+ __param(1, inject(TYPES.FileSystemPort)),
660
+ __param(2, inject(TYPES.ValidationPort)),
661
+ __param(3, inject(TYPES.LoggerPort)),
662
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
663
+ ], WorkflowValidationService);
664
+ export { WorkflowValidationService };
665
+ //# sourceMappingURL=WorkflowValidationService.js.map