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,694 @@
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 path from 'path';
16
+ import { TYPES } from '../../infrastructure/di/types.js';
17
+ import { SteeringDocumentType, SteeringMode } from '../../domain/context/ProjectContext.js';
18
+ let SteeringDocumentService = class SteeringDocumentService {
19
+ fileSystem;
20
+ logger;
21
+ validation;
22
+ pluginSteeringRegistry;
23
+ defaultSteeringDocuments = [
24
+ 'product.md',
25
+ 'tech.md',
26
+ 'structure.md',
27
+ 'linus-review.md'
28
+ ];
29
+ constructor(fileSystem, logger, validation, pluginSteeringRegistry) {
30
+ this.fileSystem = fileSystem;
31
+ this.logger = logger;
32
+ this.validation = validation;
33
+ this.pluginSteeringRegistry = pluginSteeringRegistry;
34
+ }
35
+ async loadSteeringContext(projectPath, preferences = this.getDefaultPreferences()) {
36
+ const correlationId = uuidv4();
37
+ this.logger.info('Loading steering context', {
38
+ correlationId,
39
+ projectPath,
40
+ preferences
41
+ });
42
+ const steeringPath = path.join(projectPath, '.kiro', 'steering');
43
+ const documents = [];
44
+ try {
45
+ if (await this.fileSystem.exists(steeringPath)) {
46
+ const files = await this.fileSystem.readdir(steeringPath);
47
+ for (const file of files) {
48
+ if (file.endsWith('.md')) {
49
+ const document = await this.loadSteeringDocument(path.join(steeringPath, file), preferences);
50
+ if (document) {
51
+ documents.push(document);
52
+ }
53
+ }
54
+ }
55
+ }
56
+ // Sort documents by priority
57
+ documents.sort((a, b) => b.priority - a.priority);
58
+ // Include plugin steering documents
59
+ const pluginDocuments = await this.loadPluginSteeringDocuments(projectPath, preferences);
60
+ documents.push(...pluginDocuments);
61
+ // Re-sort with plugin documents included
62
+ documents.sort((a, b) => b.priority - a.priority);
63
+ const activeDocuments = this.determineActiveDocuments(documents, preferences);
64
+ this.logger.info('Steering context loaded', {
65
+ correlationId,
66
+ documentCount: documents.length,
67
+ activeCount: activeDocuments.length,
68
+ pluginDocuments: pluginDocuments.length
69
+ });
70
+ return {
71
+ documents,
72
+ mode: this.determineOverallMode(documents),
73
+ activeDocuments,
74
+ lastRefresh: new Date(),
75
+ preferences
76
+ };
77
+ }
78
+ catch (error) {
79
+ this.logger.error('Failed to load steering context', error, {
80
+ correlationId,
81
+ projectPath
82
+ });
83
+ return {
84
+ documents: [],
85
+ mode: SteeringMode.MANUAL,
86
+ activeDocuments: [],
87
+ lastRefresh: new Date(),
88
+ preferences
89
+ };
90
+ }
91
+ }
92
+ async loadSteeringDocument(filePath, preferences) {
93
+ try {
94
+ const fileName = path.basename(filePath);
95
+ const content = await this.fileSystem.readFile(filePath);
96
+ const stat = await this.fileSystem.stat(filePath);
97
+ const type = this.determineDocumentType(fileName, content);
98
+ const mode = this.determineDocumentMode(fileName, content, preferences);
99
+ const patterns = this.extractPatterns(fileName, content, preferences);
100
+ const priority = this.calculatePriority(fileName, type, preferences);
101
+ // Validate document
102
+ const validation = await this.validateSteeringDocument(content, type);
103
+ const document = {
104
+ name: fileName,
105
+ path: filePath,
106
+ type,
107
+ mode,
108
+ content,
109
+ patterns,
110
+ priority,
111
+ lastModified: stat.mtime || new Date(),
112
+ isValid: validation.isValid
113
+ };
114
+ if (!validation.isValid) {
115
+ document.errors = validation.errors;
116
+ }
117
+ return document;
118
+ }
119
+ catch (error) {
120
+ this.logger.warn('Failed to load steering document', {
121
+ filePath,
122
+ error: error.message
123
+ });
124
+ return null;
125
+ }
126
+ }
127
+ determineDocumentType(fileName, content) {
128
+ const nameLower = fileName.toLowerCase();
129
+ if (nameLower.includes('product')) {
130
+ return SteeringDocumentType.PRODUCT;
131
+ }
132
+ if (nameLower.includes('tech') || nameLower.includes('technical')) {
133
+ return SteeringDocumentType.TECHNICAL;
134
+ }
135
+ if (nameLower.includes('structure') || nameLower.includes('architecture')) {
136
+ return SteeringDocumentType.STRUCTURE;
137
+ }
138
+ if (nameLower.includes('linus') || content.includes('Linus Torvalds')) {
139
+ return SteeringDocumentType.LINUS_REVIEW;
140
+ }
141
+ return SteeringDocumentType.CUSTOM;
142
+ }
143
+ determineDocumentMode(fileName, content, preferences) {
144
+ // Check if specific mode is set in preferences
145
+ if (preferences.priority[fileName]) {
146
+ return preferences.priority[fileName] > 0 ? SteeringMode.ALWAYS : SteeringMode.MANUAL;
147
+ }
148
+ // Check for mode indicators in content
149
+ if (content.includes('Mode: Always') || content.includes('Always included')) {
150
+ return SteeringMode.ALWAYS;
151
+ }
152
+ if (content.includes('Mode: Conditional') || content.includes('Pattern:')) {
153
+ return SteeringMode.CONDITIONAL;
154
+ }
155
+ if (content.includes('Mode: Manual') || content.includes('Reference with @')) {
156
+ return SteeringMode.MANUAL;
157
+ }
158
+ // Default modes for standard documents
159
+ const standardDocuments = ['product.md', 'tech.md', 'structure.md', 'linus-review.md'];
160
+ if (standardDocuments.includes(fileName.toLowerCase())) {
161
+ return SteeringMode.ALWAYS;
162
+ }
163
+ return SteeringMode.CONDITIONAL;
164
+ }
165
+ extractPatterns(fileName, content, preferences) {
166
+ const patterns = [];
167
+ // Extract patterns from content
168
+ const patternMatches = content.match(/Pattern:\s*([^\n]+)/g);
169
+ if (patternMatches) {
170
+ for (const match of patternMatches) {
171
+ const pattern = match.replace('Pattern:', '').trim();
172
+ patterns.push(pattern);
173
+ }
174
+ }
175
+ // Add patterns from preferences
176
+ if (preferences.conditionalPatterns[fileName]) {
177
+ patterns.push(...preferences.conditionalPatterns[fileName]);
178
+ }
179
+ // Default patterns for specific document types
180
+ if (fileName.toLowerCase().includes('test')) {
181
+ patterns.push('*.test.js', '*.spec.js', '*.test.ts', '*.spec.ts');
182
+ }
183
+ if (fileName.toLowerCase().includes('api')) {
184
+ patterns.push('*/api/*', '*/routes/*', '*/controllers/*');
185
+ }
186
+ return patterns;
187
+ }
188
+ calculatePriority(fileName, type, preferences) {
189
+ // Use explicit priority from preferences
190
+ if (preferences.priority[fileName] !== undefined) {
191
+ return preferences.priority[fileName];
192
+ }
193
+ // Default priorities by type
194
+ const typePriorities = {
195
+ [SteeringDocumentType.PRODUCT]: 100,
196
+ [SteeringDocumentType.TECHNICAL]: 90,
197
+ [SteeringDocumentType.STRUCTURE]: 80,
198
+ [SteeringDocumentType.LINUS_REVIEW]: 70,
199
+ [SteeringDocumentType.CUSTOM]: 50
200
+ };
201
+ return typePriorities[type] || 50;
202
+ }
203
+ async validateSteeringDocument(content, type) {
204
+ const errors = [];
205
+ const warnings = [];
206
+ const suggestions = [];
207
+ // Basic content validation
208
+ if (content.trim().length < 50) {
209
+ errors.push('Steering document is too short (less than 50 characters)');
210
+ }
211
+ // Type-specific validation
212
+ switch (type) {
213
+ case SteeringDocumentType.PRODUCT:
214
+ if (!content.toLowerCase().includes('product') && !content.toLowerCase().includes('user')) {
215
+ warnings.push('Product steering document should mention product goals or users');
216
+ }
217
+ break;
218
+ case SteeringDocumentType.TECHNICAL:
219
+ if (!content.toLowerCase().includes('technology') && !content.toLowerCase().includes('architecture')) {
220
+ warnings.push('Technical steering document should mention technology choices or architecture');
221
+ }
222
+ break;
223
+ case SteeringDocumentType.LINUS_REVIEW:
224
+ const linusKeywords = ['complexity', 'simple', 'taste', 'special case'];
225
+ const hasLinusContent = linusKeywords.some(keyword => content.toLowerCase().includes(keyword));
226
+ if (!hasLinusContent) {
227
+ warnings.push('Linus review document should include code review principles');
228
+ }
229
+ break;
230
+ }
231
+ // Check for markdown structure
232
+ if (!content.includes('#')) {
233
+ suggestions.push('Consider adding markdown headers for better structure');
234
+ }
235
+ // Check for actionable content
236
+ if (!content.includes('-') && !content.includes('*') && !content.includes('1.')) {
237
+ suggestions.push('Consider adding lists or numbered items for actionable guidance');
238
+ }
239
+ return {
240
+ isValid: errors.length === 0,
241
+ errors,
242
+ warnings,
243
+ suggestions
244
+ };
245
+ }
246
+ determineActiveDocuments(documents, preferences) {
247
+ const active = [];
248
+ for (const doc of documents) {
249
+ // Always include ALWAYS mode documents
250
+ if (doc.mode === SteeringMode.ALWAYS && doc.isValid) {
251
+ active.push(doc.name);
252
+ continue;
253
+ }
254
+ // Skip MANUAL mode documents (they need explicit reference)
255
+ if (doc.mode === SteeringMode.MANUAL) {
256
+ continue;
257
+ }
258
+ // Include CONDITIONAL documents if they match patterns
259
+ if (doc.mode === SteeringMode.CONDITIONAL && doc.isValid) {
260
+ // For now, include all conditional documents
261
+ // TODO: Implement pattern matching based on current context
262
+ active.push(doc.name);
263
+ }
264
+ }
265
+ return active;
266
+ }
267
+ determineOverallMode(documents) {
268
+ if (documents.length === 0) {
269
+ return SteeringMode.MANUAL;
270
+ }
271
+ const hasAlways = documents.some(doc => doc.mode === SteeringMode.ALWAYS);
272
+ const hasConditional = documents.some(doc => doc.mode === SteeringMode.CONDITIONAL);
273
+ if (hasAlways) {
274
+ return SteeringMode.ALWAYS;
275
+ }
276
+ if (hasConditional) {
277
+ return SteeringMode.CONDITIONAL;
278
+ }
279
+ return SteeringMode.MANUAL;
280
+ }
281
+ async applySteeringContext(steeringContext, currentContext) {
282
+ const correlationId = uuidv4();
283
+ this.logger.debug('Applying steering context', {
284
+ correlationId,
285
+ activeDocuments: steeringContext.activeDocuments.length,
286
+ currentContext
287
+ });
288
+ const appliedDocuments = [];
289
+ const skippedDocuments = [];
290
+ let contextText = '';
291
+ const metadata = {};
292
+ // Apply file-based steering documents
293
+ for (const document of steeringContext.documents) {
294
+ let shouldApply = false;
295
+ // Always apply ALWAYS mode documents that are active
296
+ if (document.mode === SteeringMode.ALWAYS && steeringContext.activeDocuments.includes(document.name)) {
297
+ shouldApply = true;
298
+ }
299
+ // Apply CONDITIONAL documents if patterns match
300
+ if (document.mode === SteeringMode.CONDITIONAL && document.patterns.length > 0) {
301
+ shouldApply = this.matchesPatterns(document.patterns, currentContext);
302
+ }
303
+ if (shouldApply && document.isValid) {
304
+ appliedDocuments.push(document.name);
305
+ contextText += `\n\n## ${document.name}\n\n${document.content}`;
306
+ metadata[document.name] = {
307
+ type: document.type,
308
+ priority: document.priority,
309
+ lastModified: document.lastModified
310
+ };
311
+ }
312
+ else {
313
+ skippedDocuments.push(document.name);
314
+ }
315
+ }
316
+ // Apply plugin steering documents
317
+ const pluginSteeringContext = {
318
+ projectPath: steeringContext.documents[0]?.path.split('/.kiro/')[0] || process.cwd(),
319
+ workingDirectory: process.cwd(),
320
+ variables: {},
321
+ metadata: {
322
+ correlationId,
323
+ timestamp: new Date().toISOString()
324
+ }
325
+ };
326
+ // Only add optional properties if they have values
327
+ if (currentContext.fileName) {
328
+ pluginSteeringContext.currentFile = currentContext.fileName;
329
+ pluginSteeringContext.variables.fileName = currentContext.fileName;
330
+ }
331
+ if (currentContext.filePath) {
332
+ pluginSteeringContext.variables.filePath = currentContext.filePath;
333
+ }
334
+ if (currentContext.operation) {
335
+ pluginSteeringContext.variables.operation = currentContext.operation;
336
+ }
337
+ if (currentContext.language) {
338
+ pluginSteeringContext.variables.language = currentContext.language;
339
+ }
340
+ try {
341
+ const pluginResults = await this.pluginSteeringRegistry.getApplicableSteeringDocuments(pluginSteeringContext);
342
+ for (const result of pluginResults) {
343
+ if (result.applicable && result.content) {
344
+ const documentId = `plugin:${result.priority}`;
345
+ appliedDocuments.push(documentId);
346
+ contextText += `\n\n## Plugin Steering (Priority ${result.priority})\n\n${result.content}`;
347
+ metadata[documentId] = {
348
+ type: 'plugin',
349
+ priority: result.priority,
350
+ conflicts: result.conflictsWith
351
+ };
352
+ }
353
+ }
354
+ this.logger.debug('Plugin steering context applied', {
355
+ correlationId,
356
+ pluginResults: pluginResults.length
357
+ });
358
+ }
359
+ catch (error) {
360
+ this.logger.error('Failed to apply plugin steering context', error, {
361
+ correlationId
362
+ });
363
+ }
364
+ this.logger.debug('Steering context applied', {
365
+ correlationId,
366
+ appliedCount: appliedDocuments.length,
367
+ skippedCount: skippedDocuments.length
368
+ });
369
+ return {
370
+ appliedDocuments,
371
+ skippedDocuments,
372
+ context: contextText.trim(),
373
+ metadata
374
+ };
375
+ }
376
+ matchesPatterns(patterns, context) {
377
+ if (patterns.length === 0) {
378
+ return true; // No patterns means always apply
379
+ }
380
+ for (const pattern of patterns) {
381
+ // Simple pattern matching
382
+ if (context.fileName && this.matchPattern(pattern, context.fileName)) {
383
+ return true;
384
+ }
385
+ if (context.filePath && this.matchPattern(pattern, context.filePath)) {
386
+ return true;
387
+ }
388
+ if (context.operation && pattern.toLowerCase().includes(context.operation.toLowerCase())) {
389
+ return true;
390
+ }
391
+ if (context.language && pattern.toLowerCase().includes(context.language.toLowerCase())) {
392
+ return true;
393
+ }
394
+ }
395
+ return false;
396
+ }
397
+ matchPattern(pattern, text) {
398
+ // Convert glob pattern to regex (simplified)
399
+ const regexPattern = pattern
400
+ .replace(/\./g, '\\.')
401
+ .replace(/\*/g, '.*')
402
+ .replace(/\?/g, '.');
403
+ try {
404
+ const regex = new RegExp(`^${regexPattern}$`, 'i');
405
+ return regex.test(text);
406
+ }
407
+ catch {
408
+ // Fallback to simple includes
409
+ return text.toLowerCase().includes(pattern.toLowerCase());
410
+ }
411
+ }
412
+ async refreshSteeringContext(projectPath, currentContext) {
413
+ const correlationId = uuidv4();
414
+ this.logger.info('Refreshing steering context', {
415
+ correlationId,
416
+ projectPath,
417
+ currentDocumentCount: currentContext.documents.length
418
+ });
419
+ // Check if any documents have been modified
420
+ let hasChanges = false;
421
+ const updatedDocuments = [];
422
+ for (const doc of currentContext.documents) {
423
+ try {
424
+ const stat = await this.fileSystem.stat(doc.path);
425
+ const lastModified = stat.mtime || new Date();
426
+ if (lastModified.getTime() > doc.lastModified.getTime()) {
427
+ hasChanges = true;
428
+ const updatedDoc = await this.loadSteeringDocument(doc.path, currentContext.preferences);
429
+ if (updatedDoc) {
430
+ updatedDocuments.push(updatedDoc);
431
+ }
432
+ }
433
+ else {
434
+ updatedDocuments.push(doc);
435
+ }
436
+ }
437
+ catch (error) {
438
+ this.logger.warn('Document no longer accessible', { path: doc.path });
439
+ hasChanges = true;
440
+ // Skip this document (it was deleted or moved)
441
+ }
442
+ }
443
+ // Check for new documents
444
+ const steeringPath = path.join(projectPath, '.kiro', 'steering');
445
+ if (await this.fileSystem.exists(steeringPath)) {
446
+ const files = await this.fileSystem.readdir(steeringPath);
447
+ const existingPaths = new Set(currentContext.documents.map(d => d.path));
448
+ for (const file of files) {
449
+ if (file.endsWith('.md')) {
450
+ const filePath = path.join(steeringPath, file);
451
+ if (!existingPaths.has(filePath)) {
452
+ hasChanges = true;
453
+ const newDoc = await this.loadSteeringDocument(filePath, currentContext.preferences);
454
+ if (newDoc) {
455
+ updatedDocuments.push(newDoc);
456
+ }
457
+ }
458
+ }
459
+ }
460
+ }
461
+ if (!hasChanges) {
462
+ this.logger.debug('No changes detected in steering context', { correlationId });
463
+ return {
464
+ ...currentContext,
465
+ lastRefresh: new Date()
466
+ };
467
+ }
468
+ // Sort and determine active documents
469
+ updatedDocuments.sort((a, b) => b.priority - a.priority);
470
+ const activeDocuments = this.determineActiveDocuments(updatedDocuments, currentContext.preferences);
471
+ this.logger.info('Steering context refreshed', {
472
+ correlationId,
473
+ documentCount: updatedDocuments.length,
474
+ activeCount: activeDocuments.length,
475
+ hasChanges
476
+ });
477
+ return {
478
+ documents: updatedDocuments,
479
+ mode: this.determineOverallMode(updatedDocuments),
480
+ activeDocuments,
481
+ lastRefresh: new Date(),
482
+ preferences: currentContext.preferences
483
+ };
484
+ }
485
+ async createSteeringDocument(projectPath, config) {
486
+ const correlationId = uuidv4();
487
+ this.logger.info('Creating steering document', {
488
+ correlationId,
489
+ projectPath,
490
+ name: config.name,
491
+ type: config.type
492
+ });
493
+ const steeringPath = path.join(projectPath, '.kiro', 'steering');
494
+ // Ensure steering directory exists
495
+ if (!(await this.fileSystem.exists(steeringPath))) {
496
+ await this.fileSystem.mkdir(steeringPath);
497
+ }
498
+ const filePath = path.join(steeringPath, config.name);
499
+ const content = config.content || this.generateDefaultContent(config.type, config.name);
500
+ await this.fileSystem.writeFile(filePath, content);
501
+ const document = {
502
+ name: config.name,
503
+ path: filePath,
504
+ type: config.type,
505
+ mode: config.mode || SteeringMode.CONDITIONAL,
506
+ content,
507
+ patterns: config.patterns || [],
508
+ priority: config.priority || 50,
509
+ lastModified: new Date(),
510
+ isValid: true
511
+ };
512
+ this.logger.info('Steering document created', {
513
+ correlationId,
514
+ name: config.name,
515
+ path: filePath
516
+ });
517
+ return document;
518
+ }
519
+ generateDefaultContent(type, name) {
520
+ const timestamp = new Date().toISOString();
521
+ switch (type) {
522
+ case SteeringDocumentType.PRODUCT:
523
+ return `# Product Steering Document
524
+
525
+ ## Project Overview
526
+ Define the product vision, target users, and business objectives.
527
+
528
+ ## Target Users
529
+ - Primary user persona
530
+ - Secondary user persona
531
+
532
+ ## Success Metrics
533
+ - Key performance indicators
534
+ - Success criteria
535
+
536
+ ## Constraints
537
+ - Business constraints
538
+ - Technical constraints
539
+
540
+ Generated on: ${timestamp}
541
+ `;
542
+ case SteeringDocumentType.TECHNICAL:
543
+ return `# Technical Steering Document
544
+
545
+ ## Technology Stack
546
+ Define the approved technologies, frameworks, and tools.
547
+
548
+ ## Architecture Principles
549
+ - Principle 1
550
+ - Principle 2
551
+
552
+ ## Quality Standards
553
+ - Code quality requirements
554
+ - Testing requirements
555
+ - Performance requirements
556
+
557
+ ## Security Guidelines
558
+ - Security best practices
559
+ - Compliance requirements
560
+
561
+ Generated on: ${timestamp}
562
+ `;
563
+ case SteeringDocumentType.STRUCTURE:
564
+ return `# Structure Steering Document
565
+
566
+ ## Directory Structure
567
+ Define the project organization and file naming conventions.
568
+
569
+ ## Code Organization
570
+ - Module structure
571
+ - File naming conventions
572
+ - Import/export patterns
573
+
574
+ ## Documentation Standards
575
+ - README requirements
576
+ - Code documentation
577
+ - API documentation
578
+
579
+ Generated on: ${timestamp}
580
+ `;
581
+ default:
582
+ return `# ${name}
583
+
584
+ ## Purpose
585
+ Define the purpose and scope of this steering document.
586
+
587
+ ## Guidelines
588
+ - Guideline 1
589
+ - Guideline 2
590
+
591
+ ## Usage
592
+ Describe when and how this steering document should be applied.
593
+
594
+ Generated on: ${timestamp}
595
+ `;
596
+ }
597
+ }
598
+ async loadPluginSteeringDocuments(projectPath, preferences) {
599
+ const documents = [];
600
+ try {
601
+ // Get steering documents from all modes
602
+ const alwaysDocuments = await this.pluginSteeringRegistry.getSteeringDocumentsByMode(SteeringMode.ALWAYS);
603
+ const conditionalDocuments = await this.pluginSteeringRegistry.getSteeringDocumentsByMode(SteeringMode.CONDITIONAL);
604
+ const manualDocuments = await this.pluginSteeringRegistry.getSteeringDocumentsByMode(SteeringMode.MANUAL);
605
+ // Convert plugin documents to steering documents
606
+ for (const pluginDoc of [...alwaysDocuments, ...conditionalDocuments, ...manualDocuments]) {
607
+ const steeringDoc = {
608
+ name: `${pluginDoc.pluginId}:${pluginDoc.name}`,
609
+ path: `plugin:${pluginDoc.id}`,
610
+ type: this.mapPluginDocumentType(pluginDoc.type),
611
+ mode: pluginDoc.mode,
612
+ content: pluginDoc.content || pluginDoc.template,
613
+ patterns: pluginDoc.patterns,
614
+ priority: pluginDoc.priority,
615
+ lastModified: pluginDoc.lastUpdated,
616
+ isValid: true
617
+ };
618
+ documents.push(steeringDoc);
619
+ }
620
+ this.logger.debug('Loaded plugin steering documents', {
621
+ projectPath,
622
+ documentCount: documents.length,
623
+ alwaysCount: alwaysDocuments.length,
624
+ conditionalCount: conditionalDocuments.length,
625
+ manualCount: manualDocuments.length
626
+ });
627
+ }
628
+ catch (error) {
629
+ this.logger.error('Failed to load plugin steering documents', error, {
630
+ projectPath
631
+ });
632
+ }
633
+ return documents;
634
+ }
635
+ mapPluginDocumentType(pluginType) {
636
+ // Map plugin document types to steering document types
637
+ switch (pluginType) {
638
+ case 'product':
639
+ return SteeringDocumentType.PRODUCT;
640
+ case 'technical':
641
+ return SteeringDocumentType.TECHNICAL;
642
+ case 'structure':
643
+ return SteeringDocumentType.STRUCTURE;
644
+ case 'quality':
645
+ return SteeringDocumentType.LINUS_REVIEW;
646
+ case 'process':
647
+ case 'custom':
648
+ default:
649
+ return SteeringDocumentType.CUSTOM;
650
+ }
651
+ }
652
+ getDefaultPreferences() {
653
+ return {
654
+ autoRefresh: true,
655
+ conditionalPatterns: {},
656
+ excludePatterns: ['node_modules/**', 'dist/**', 'build/**'],
657
+ priority: {
658
+ 'product.md': 100,
659
+ 'tech.md': 90,
660
+ 'structure.md': 80,
661
+ 'linus-review.md': 70
662
+ }
663
+ };
664
+ }
665
+ async getSteeringStats(steeringContext) {
666
+ const documentsByType = {};
667
+ const documentsByMode = {};
668
+ let validDocuments = 0;
669
+ for (const doc of steeringContext.documents) {
670
+ documentsByType[doc.type] = (documentsByType[doc.type] || 0) + 1;
671
+ documentsByMode[doc.mode] = (documentsByMode[doc.mode] || 0) + 1;
672
+ if (doc.isValid)
673
+ validDocuments++;
674
+ }
675
+ return {
676
+ totalDocuments: steeringContext.documents.length,
677
+ activeDocuments: steeringContext.activeDocuments.length,
678
+ documentsByType,
679
+ documentsByMode,
680
+ validDocuments,
681
+ lastRefresh: steeringContext.lastRefresh
682
+ };
683
+ }
684
+ };
685
+ SteeringDocumentService = __decorate([
686
+ injectable(),
687
+ __param(0, inject(TYPES.FileSystemPort)),
688
+ __param(1, inject(TYPES.LoggerPort)),
689
+ __param(2, inject(TYPES.ValidationPort)),
690
+ __param(3, inject(TYPES.PluginSteeringRegistry)),
691
+ __metadata("design:paramtypes", [Object, Object, Object, Function])
692
+ ], SteeringDocumentService);
693
+ export { SteeringDocumentService };
694
+ //# sourceMappingURL=SteeringDocumentService.js.map