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.
- package/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/__tests__/setup.d.ts +44 -0
- package/dist/__tests__/setup.js +178 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/__tests__/test-helpers/mock-factories.d.ts +26 -0
- package/dist/__tests__/test-helpers/mock-factories.js +466 -0
- package/dist/__tests__/test-helpers/mock-factories.js.map +1 -0
- package/dist/adapters/cli/SDDToolAdapter.d.ts +26 -0
- package/dist/adapters/cli/SDDToolAdapter.js +273 -0
- package/dist/adapters/cli/SDDToolAdapter.js.map +1 -0
- package/dist/application/services/CodebaseAnalysisService.d.ts +38 -0
- package/dist/application/services/CodebaseAnalysisService.js +737 -0
- package/dist/application/services/CodebaseAnalysisService.js.map +1 -0
- package/dist/application/services/LocalizationService.d.ts +184 -0
- package/dist/application/services/LocalizationService.js +536 -0
- package/dist/application/services/LocalizationService.js.map +1 -0
- package/dist/application/services/ProjectContextService.d.ts +61 -0
- package/dist/application/services/ProjectContextService.js +550 -0
- package/dist/application/services/ProjectContextService.js.map +1 -0
- package/dist/application/services/ProjectInitializationService.d.ts +57 -0
- package/dist/application/services/ProjectInitializationService.js +485 -0
- package/dist/application/services/ProjectInitializationService.js.map +1 -0
- package/dist/application/services/ProjectService.d.ts +19 -0
- package/dist/application/services/ProjectService.js +159 -0
- package/dist/application/services/ProjectService.js.map +1 -0
- package/dist/application/services/QualityGateService.d.ts +62 -0
- package/dist/application/services/QualityGateService.js +428 -0
- package/dist/application/services/QualityGateService.js.map +1 -0
- package/dist/application/services/QualityService.d.ts +43 -0
- package/dist/application/services/QualityService.js +245 -0
- package/dist/application/services/QualityService.js.map +1 -0
- package/dist/application/services/SteeringDocumentService.d.ts +62 -0
- package/dist/application/services/SteeringDocumentService.js +694 -0
- package/dist/application/services/SteeringDocumentService.js.map +1 -0
- package/dist/application/services/TemplateService.d.ts +47 -0
- package/dist/application/services/TemplateService.js +438 -0
- package/dist/application/services/TemplateService.js.map +1 -0
- package/dist/application/services/WorkflowEngineService.d.ts +56 -0
- package/dist/application/services/WorkflowEngineService.js +348 -0
- package/dist/application/services/WorkflowEngineService.js.map +1 -0
- package/dist/application/services/WorkflowService.d.ts +22 -0
- package/dist/application/services/WorkflowService.js +147 -0
- package/dist/application/services/WorkflowService.js.map +1 -0
- package/dist/application/services/WorkflowValidationService.d.ts +51 -0
- package/dist/application/services/WorkflowValidationService.js +665 -0
- package/dist/application/services/WorkflowValidationService.js.map +1 -0
- package/dist/domain/context/ProjectContext.d.ts +350 -0
- package/dist/domain/context/ProjectContext.js +138 -0
- package/dist/domain/context/ProjectContext.js.map +1 -0
- package/dist/domain/i18n/index.d.ts +286 -0
- package/dist/domain/i18n/index.js +97 -0
- package/dist/domain/i18n/index.js.map +1 -0
- package/dist/domain/plugins/index.d.ts +498 -0
- package/dist/domain/plugins/index.js +157 -0
- package/dist/domain/plugins/index.js.map +1 -0
- package/dist/domain/ports.d.ts +54 -0
- package/dist/domain/ports.js +3 -0
- package/dist/domain/ports.js.map +1 -0
- package/dist/domain/quality/index.d.ts +361 -0
- package/dist/domain/quality/index.js +113 -0
- package/dist/domain/quality/index.js.map +1 -0
- package/dist/domain/services/DomainService.d.ts +18 -0
- package/dist/domain/services/DomainService.js +71 -0
- package/dist/domain/services/DomainService.js.map +1 -0
- package/dist/domain/templates/index.d.ts +158 -0
- package/dist/domain/templates/index.js +22 -0
- package/dist/domain/templates/index.js.map +1 -0
- package/dist/domain/types.d.ts +115 -0
- package/dist/domain/types.js +37 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/domain/workflow/WorkflowStateMachine.d.ts +62 -0
- package/dist/domain/workflow/WorkflowStateMachine.js +286 -0
- package/dist/domain/workflow/WorkflowStateMachine.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/adapters/AjvValidationAdapter.d.ts +7 -0
- package/dist/infrastructure/adapters/AjvValidationAdapter.js +37 -0
- package/dist/infrastructure/adapters/AjvValidationAdapter.js.map +1 -0
- package/dist/infrastructure/adapters/ConsoleLoggerAdapter.d.ts +8 -0
- package/dist/infrastructure/adapters/ConsoleLoggerAdapter.js +41 -0
- package/dist/infrastructure/adapters/ConsoleLoggerAdapter.js.map +1 -0
- package/dist/infrastructure/adapters/FileBasedTaskTracker.d.ts +9 -0
- package/dist/infrastructure/adapters/FileBasedTaskTracker.js +41 -0
- package/dist/infrastructure/adapters/FileBasedTaskTracker.js.map +1 -0
- package/dist/infrastructure/adapters/HandlebarsTemplateEngine.d.ts +8 -0
- package/dist/infrastructure/adapters/HandlebarsTemplateEngine.js +38 -0
- package/dist/infrastructure/adapters/HandlebarsTemplateEngine.js.map +1 -0
- package/dist/infrastructure/adapters/JsonConfigurationAdapter.d.ts +7 -0
- package/dist/infrastructure/adapters/JsonConfigurationAdapter.js +24 -0
- package/dist/infrastructure/adapters/JsonConfigurationAdapter.js.map +1 -0
- package/dist/infrastructure/adapters/LinusQualityAnalyzer.d.ts +9 -0
- package/dist/infrastructure/adapters/LinusQualityAnalyzer.js +75 -0
- package/dist/infrastructure/adapters/LinusQualityAnalyzer.js.map +1 -0
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.d.ts +12 -0
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.js +39 -0
- package/dist/infrastructure/adapters/NodeFileSystemAdapter.js.map +1 -0
- package/dist/infrastructure/di/container.d.ts +3 -0
- package/dist/infrastructure/di/container.js +98 -0
- package/dist/infrastructure/di/container.js.map +1 -0
- package/dist/infrastructure/di/types.d.ts +39 -0
- package/dist/infrastructure/di/types.js +45 -0
- package/dist/infrastructure/di/types.js.map +1 -0
- package/dist/infrastructure/i18n/I18nextService.d.ts +27 -0
- package/dist/infrastructure/i18n/I18nextService.js +357 -0
- package/dist/infrastructure/i18n/I18nextService.js.map +1 -0
- package/dist/infrastructure/mcp/CapabilityNegotiator.d.ts +21 -0
- package/dist/infrastructure/mcp/CapabilityNegotiator.js +75 -0
- package/dist/infrastructure/mcp/CapabilityNegotiator.js.map +1 -0
- package/dist/infrastructure/mcp/ErrorHandler.d.ts +29 -0
- package/dist/infrastructure/mcp/ErrorHandler.js +101 -0
- package/dist/infrastructure/mcp/ErrorHandler.js.map +1 -0
- package/dist/infrastructure/mcp/MCPServer.d.ts +25 -0
- package/dist/infrastructure/mcp/MCPServer.js +246 -0
- package/dist/infrastructure/mcp/MCPServer.js.map +1 -0
- package/dist/infrastructure/mcp/PromptManager.d.ts +18 -0
- package/dist/infrastructure/mcp/PromptManager.js +373 -0
- package/dist/infrastructure/mcp/PromptManager.js.map +1 -0
- package/dist/infrastructure/mcp/ResourceManager.d.ts +15 -0
- package/dist/infrastructure/mcp/ResourceManager.js +229 -0
- package/dist/infrastructure/mcp/ResourceManager.js.map +1 -0
- package/dist/infrastructure/mcp/SessionManager.d.ts +64 -0
- package/dist/infrastructure/mcp/SessionManager.js +221 -0
- package/dist/infrastructure/mcp/SessionManager.js.map +1 -0
- package/dist/infrastructure/mcp/ToolRegistry.d.ts +48 -0
- package/dist/infrastructure/mcp/ToolRegistry.js +235 -0
- package/dist/infrastructure/mcp/ToolRegistry.js.map +1 -0
- package/dist/infrastructure/platform/PlatformAdapter.d.ts +46 -0
- package/dist/infrastructure/platform/PlatformAdapter.js +355 -0
- package/dist/infrastructure/platform/PlatformAdapter.js.map +1 -0
- package/dist/infrastructure/plugins/HookSystem.d.ts +40 -0
- package/dist/infrastructure/plugins/HookSystem.js +415 -0
- package/dist/infrastructure/plugins/HookSystem.js.map +1 -0
- package/dist/infrastructure/plugins/PluginManager.d.ts +51 -0
- package/dist/infrastructure/plugins/PluginManager.js +650 -0
- package/dist/infrastructure/plugins/PluginManager.js.map +1 -0
- package/dist/infrastructure/plugins/PluginSteeringRegistry.d.ts +63 -0
- package/dist/infrastructure/plugins/PluginSteeringRegistry.js +439 -0
- package/dist/infrastructure/plugins/PluginSteeringRegistry.js.map +1 -0
- package/dist/infrastructure/plugins/PluginToolRegistry.d.ts +54 -0
- package/dist/infrastructure/plugins/PluginToolRegistry.js +490 -0
- package/dist/infrastructure/plugins/PluginToolRegistry.js.map +1 -0
- package/dist/infrastructure/quality/ASTAnalyzer.d.ts +65 -0
- package/dist/infrastructure/quality/ASTAnalyzer.js +439 -0
- package/dist/infrastructure/quality/ASTAnalyzer.js.map +1 -0
- package/dist/infrastructure/quality/LinusCodeReviewer.d.ts +52 -0
- package/dist/infrastructure/quality/LinusCodeReviewer.js +551 -0
- package/dist/infrastructure/quality/LinusCodeReviewer.js.map +1 -0
- package/dist/infrastructure/repositories/InMemoryProjectRepository.d.ts +10 -0
- package/dist/infrastructure/repositories/InMemoryProjectRepository.js +35 -0
- package/dist/infrastructure/repositories/InMemoryProjectRepository.js.map +1 -0
- package/dist/infrastructure/schemas/project.schema.d.ts +192 -0
- package/dist/infrastructure/schemas/project.schema.js +114 -0
- package/dist/infrastructure/schemas/project.schema.js.map +1 -0
- package/dist/infrastructure/templates/FileGenerator.d.ts +15 -0
- package/dist/infrastructure/templates/FileGenerator.js +385 -0
- package/dist/infrastructure/templates/FileGenerator.js.map +1 -0
- package/dist/infrastructure/templates/HandlebarsRenderer.d.ts +16 -0
- package/dist/infrastructure/templates/HandlebarsRenderer.js +252 -0
- package/dist/infrastructure/templates/HandlebarsRenderer.js.map +1 -0
- package/dist/infrastructure/templates/TemplateManager.d.ts +36 -0
- package/dist/infrastructure/templates/TemplateManager.js +777 -0
- package/dist/infrastructure/templates/TemplateManager.js.map +1 -0
- 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
|