sdd-mcp-server 1.1.21 → 1.2.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/README.md +67 -30
- package/dist/adapters/cli/SDDToolAdapter.d.ts +22 -1
- package/dist/adapters/cli/SDDToolAdapter.js +399 -17
- package/dist/adapters/cli/SDDToolAdapter.js.map +1 -1
- package/dist/application/services/TemplateService.d.ts +17 -0
- package/dist/application/services/TemplateService.js +367 -24
- package/dist/application/services/TemplateService.js.map +1 -1
- package/dist/index.js +1210 -13
- package/dist/index.js.map +1 -1
- package/mcp-server.js +1501 -0
- package/package.json +3 -3
- package/minimal-working-server.js +0 -66
package/dist/index.js
CHANGED
|
@@ -7,7 +7,8 @@ const isMCPMode = process.argv[1]?.includes('sdd-mcp-server') ||
|
|
|
7
7
|
process.env.npm_execpath?.includes('npx') || // Executed via npx
|
|
8
8
|
(process.stdin.isTTY === false) || // MCP servers communicate via stdio pipes
|
|
9
9
|
process.argv.includes('--mcp-mode') || // Explicit MCP mode flag
|
|
10
|
-
|
|
10
|
+
process.argv.includes('--simplified') || // Use simplified mode flag
|
|
11
|
+
false; // Default to full server for better functionality
|
|
11
12
|
if (isMCPMode) {
|
|
12
13
|
// Completely silence all console output for MCP mode
|
|
13
14
|
console.log = () => { };
|
|
@@ -53,34 +54,104 @@ async function createSimpleMCPServer() {
|
|
|
53
54
|
const { ListToolsRequestSchema, CallToolRequestSchema, InitializedNotificationSchema } = await import('@modelcontextprotocol/sdk/types.js');
|
|
54
55
|
const server = new Server({
|
|
55
56
|
name: 'sdd-mcp-server',
|
|
56
|
-
version: '1.
|
|
57
|
+
version: '1.2.0'
|
|
57
58
|
}, {
|
|
58
59
|
capabilities: {
|
|
59
60
|
tools: {}
|
|
60
61
|
}
|
|
61
62
|
});
|
|
62
|
-
// Add
|
|
63
|
+
// Add ALL SDD tools (not just basic ones)
|
|
63
64
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
64
65
|
return {
|
|
65
66
|
tools: [
|
|
66
67
|
{
|
|
67
68
|
name: 'sdd-init',
|
|
68
|
-
description: 'Initialize a new SDD project',
|
|
69
|
+
description: 'Initialize a new SDD project from description',
|
|
69
70
|
inputSchema: {
|
|
70
71
|
type: 'object',
|
|
71
72
|
properties: {
|
|
72
|
-
|
|
73
|
-
description: { type: 'string' }
|
|
73
|
+
description: { type: 'string', description: 'Detailed project description' }
|
|
74
74
|
},
|
|
75
|
-
required: ['
|
|
75
|
+
required: ['description']
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'sdd-requirements',
|
|
80
|
+
description: 'Generate requirements doc',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
featureName: { type: 'string' }
|
|
85
|
+
},
|
|
86
|
+
required: ['featureName']
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'sdd-design',
|
|
91
|
+
description: 'Create design specifications',
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
featureName: { type: 'string' }
|
|
96
|
+
},
|
|
97
|
+
required: ['featureName']
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'sdd-tasks',
|
|
102
|
+
description: 'Generate task breakdown',
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
properties: {
|
|
106
|
+
featureName: { type: 'string' }
|
|
107
|
+
},
|
|
108
|
+
required: ['featureName']
|
|
76
109
|
}
|
|
77
110
|
},
|
|
78
111
|
{
|
|
79
112
|
name: 'sdd-status',
|
|
80
|
-
description: '
|
|
113
|
+
description: 'Check workflow progress',
|
|
81
114
|
inputSchema: {
|
|
82
115
|
type: 'object',
|
|
83
|
-
properties: {
|
|
116
|
+
properties: {
|
|
117
|
+
featureName: { type: 'string' }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'sdd-steering',
|
|
123
|
+
description: 'Create/update steering documents',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
updateMode: { type: 'string', enum: ['create', 'update'] }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'sdd-steering-custom',
|
|
133
|
+
description: 'Create custom steering documents',
|
|
134
|
+
inputSchema: {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
fileName: { type: 'string' },
|
|
138
|
+
topic: { type: 'string' },
|
|
139
|
+
inclusionMode: { type: 'string', enum: ['always', 'conditional', 'manual'] },
|
|
140
|
+
filePattern: { type: 'string' }
|
|
141
|
+
},
|
|
142
|
+
required: ['fileName', 'topic', 'inclusionMode']
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: 'sdd-quality-check',
|
|
147
|
+
description: 'Code quality analysis',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {
|
|
151
|
+
code: { type: 'string' },
|
|
152
|
+
language: { type: 'string' }
|
|
153
|
+
},
|
|
154
|
+
required: ['code']
|
|
84
155
|
}
|
|
85
156
|
}
|
|
86
157
|
]
|
|
@@ -90,17 +161,29 @@ async function createSimpleMCPServer() {
|
|
|
90
161
|
const { name, arguments: args } = request.params;
|
|
91
162
|
switch (name) {
|
|
92
163
|
case 'sdd-init':
|
|
164
|
+
return await handleInitSimplified(args);
|
|
165
|
+
case 'sdd-status':
|
|
93
166
|
return {
|
|
94
167
|
content: [{
|
|
95
168
|
type: 'text',
|
|
96
|
-
text:
|
|
169
|
+
text: 'SDD project status: No active project found. Use sdd-init to create a new project.'
|
|
97
170
|
}]
|
|
98
171
|
};
|
|
99
|
-
case 'sdd-
|
|
172
|
+
case 'sdd-steering':
|
|
173
|
+
return await handleSteeringSimplified(args);
|
|
174
|
+
case 'sdd-steering-custom':
|
|
175
|
+
return await handleSteeringCustomSimplified(args);
|
|
176
|
+
case 'sdd-requirements':
|
|
177
|
+
return await handleRequirementsSimplified(args);
|
|
178
|
+
case 'sdd-design':
|
|
179
|
+
return await handleDesignSimplified(args);
|
|
180
|
+
case 'sdd-tasks':
|
|
181
|
+
return await handleTasksSimplified(args);
|
|
182
|
+
case 'sdd-quality-check':
|
|
100
183
|
return {
|
|
101
184
|
content: [{
|
|
102
185
|
type: 'text',
|
|
103
|
-
text: '
|
|
186
|
+
text: 'Code quality analysis would be performed here. (Simplified MCP mode)'
|
|
104
187
|
}]
|
|
105
188
|
};
|
|
106
189
|
default:
|
|
@@ -114,6 +197,1120 @@ async function createSimpleMCPServer() {
|
|
|
114
197
|
const transport = new StdioServerTransport();
|
|
115
198
|
await server.connect(transport);
|
|
116
199
|
}
|
|
200
|
+
// Simplified steering implementation for MCP mode
|
|
201
|
+
async function handleSteeringSimplified(args) {
|
|
202
|
+
const fs = await import('fs');
|
|
203
|
+
const path = await import('path');
|
|
204
|
+
try {
|
|
205
|
+
const projectPath = process.cwd();
|
|
206
|
+
// Read package.json for project analysis
|
|
207
|
+
let packageJson = {};
|
|
208
|
+
try {
|
|
209
|
+
const packagePath = path.join(projectPath, 'package.json');
|
|
210
|
+
if (fs.existsSync(packagePath)) {
|
|
211
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
212
|
+
packageJson = JSON.parse(packageContent);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
// Ignore package.json parsing errors
|
|
217
|
+
}
|
|
218
|
+
// Create .kiro/steering directory if it doesn't exist
|
|
219
|
+
const steeringDir = path.join(projectPath, '.kiro', 'steering');
|
|
220
|
+
if (!fs.existsSync(steeringDir)) {
|
|
221
|
+
fs.mkdirSync(steeringDir, { recursive: true });
|
|
222
|
+
}
|
|
223
|
+
// Generate product.md with real project data
|
|
224
|
+
const productContent = `# Product Overview
|
|
225
|
+
|
|
226
|
+
## Product Description
|
|
227
|
+
${packageJson.description || 'No description available'}
|
|
228
|
+
|
|
229
|
+
## Core Features
|
|
230
|
+
${extractFeaturesSimplified(packageJson).map(feature => `- ${feature}`).join('\n')}
|
|
231
|
+
|
|
232
|
+
## Target Use Case
|
|
233
|
+
This product is designed for ${packageJson.keywords ? packageJson.keywords.join(', ') : 'general'} use cases.
|
|
234
|
+
|
|
235
|
+
## Key Value Proposition
|
|
236
|
+
${extractFeaturesSimplified(packageJson).map(feature => `- **${feature}**: Enhanced development experience`).join('\n')}
|
|
237
|
+
|
|
238
|
+
## Target Users
|
|
239
|
+
${generateTargetUsersSimplified(packageJson)}`;
|
|
240
|
+
// Generate tech.md with real dependency analysis
|
|
241
|
+
const techContent = `# Technology Overview
|
|
242
|
+
|
|
243
|
+
## Technology Stack
|
|
244
|
+
${generateTechStackSimplified(packageJson)}
|
|
245
|
+
|
|
246
|
+
## Development Environment
|
|
247
|
+
- Node.js: ${packageJson.engines?.node || 'Unknown'}
|
|
248
|
+
- Package Manager: npm
|
|
249
|
+
|
|
250
|
+
## Key Dependencies
|
|
251
|
+
${generateDependencyListSimplified(packageJson)}
|
|
252
|
+
|
|
253
|
+
## Development Commands
|
|
254
|
+
${generateWorkflowSimplified(packageJson)}`;
|
|
255
|
+
// Generate structure.md
|
|
256
|
+
const structureContent = `# Project Structure
|
|
257
|
+
|
|
258
|
+
## Directory Organization
|
|
259
|
+
${generateDirectoryStructureSimplified(projectPath)}
|
|
260
|
+
|
|
261
|
+
## File Naming Conventions
|
|
262
|
+
- Use kebab-case for file names
|
|
263
|
+
- Use PascalCase for class names
|
|
264
|
+
- Use camelCase for variable names
|
|
265
|
+
- Use UPPER_SNAKE_CASE for constants
|
|
266
|
+
|
|
267
|
+
## Module Organization
|
|
268
|
+
- Group related functionality in modules
|
|
269
|
+
- Use barrel exports (index.ts files)
|
|
270
|
+
- Separate business logic from infrastructure
|
|
271
|
+
- Keep dependencies flowing inward`;
|
|
272
|
+
// Write the files
|
|
273
|
+
fs.writeFileSync(path.join(steeringDir, 'product.md'), productContent);
|
|
274
|
+
fs.writeFileSync(path.join(steeringDir, 'tech.md'), techContent);
|
|
275
|
+
fs.writeFileSync(path.join(steeringDir, 'structure.md'), structureContent);
|
|
276
|
+
return {
|
|
277
|
+
content: [{
|
|
278
|
+
type: 'text',
|
|
279
|
+
text: `## Steering Documents Updated
|
|
280
|
+
|
|
281
|
+
**Project**: ${packageJson.name || 'Unknown'}
|
|
282
|
+
**Mode**: update
|
|
283
|
+
|
|
284
|
+
**Updated Files**:
|
|
285
|
+
- \`.kiro/steering/product.md\` - Product overview and business context
|
|
286
|
+
- \`.kiro/steering/tech.md\` - Technology stack and development environment
|
|
287
|
+
- \`.kiro/steering/structure.md\` - Project organization and architectural decisions
|
|
288
|
+
|
|
289
|
+
**Analysis**:
|
|
290
|
+
- Technology stack: ${Object.keys({ ...packageJson.dependencies, ...packageJson.devDependencies }).length} dependencies detected
|
|
291
|
+
- Project type: ${packageJson.type || 'CommonJS'}
|
|
292
|
+
- Existing steering: Updated preserving customizations
|
|
293
|
+
|
|
294
|
+
These steering documents provide consistent project context for all AI interactions and spec-driven development workflows.`
|
|
295
|
+
}]
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
return {
|
|
300
|
+
content: [{
|
|
301
|
+
type: 'text',
|
|
302
|
+
text: `Error generating steering documents: ${error.message}`
|
|
303
|
+
}],
|
|
304
|
+
isError: true
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async function handleSteeringCustomSimplified(args) {
|
|
309
|
+
const fs = await import('fs');
|
|
310
|
+
const path = await import('path');
|
|
311
|
+
try {
|
|
312
|
+
const { fileName, topic, inclusionMode, filePattern } = args;
|
|
313
|
+
if (!fileName || !topic || !inclusionMode) {
|
|
314
|
+
throw new Error('fileName, topic, and inclusionMode are required');
|
|
315
|
+
}
|
|
316
|
+
const projectPath = process.cwd();
|
|
317
|
+
const steeringDir = path.join(projectPath, '.kiro', 'steering');
|
|
318
|
+
if (!fs.existsSync(steeringDir)) {
|
|
319
|
+
fs.mkdirSync(steeringDir, { recursive: true });
|
|
320
|
+
}
|
|
321
|
+
const content = `# ${topic}
|
|
322
|
+
|
|
323
|
+
## Purpose
|
|
324
|
+
Define the purpose and scope of this steering document.
|
|
325
|
+
|
|
326
|
+
## Guidelines
|
|
327
|
+
- Guideline 1
|
|
328
|
+
- Guideline 2
|
|
329
|
+
|
|
330
|
+
## Usage
|
|
331
|
+
Describe when and how this steering document should be applied.
|
|
332
|
+
|
|
333
|
+
## Inclusion Mode
|
|
334
|
+
Mode: ${inclusionMode}${filePattern ? `
|
|
335
|
+
Pattern: ${filePattern}` : ''}
|
|
336
|
+
|
|
337
|
+
Generated on: ${new Date().toISOString()}
|
|
338
|
+
`;
|
|
339
|
+
fs.writeFileSync(path.join(steeringDir, fileName), content);
|
|
340
|
+
return {
|
|
341
|
+
content: [{
|
|
342
|
+
type: 'text',
|
|
343
|
+
text: `Custom steering document "${fileName}" created successfully with ${inclusionMode} inclusion mode.`
|
|
344
|
+
}]
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
return {
|
|
349
|
+
content: [{
|
|
350
|
+
type: 'text',
|
|
351
|
+
text: `Error creating custom steering document: ${error.message}`
|
|
352
|
+
}],
|
|
353
|
+
isError: true
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Helper functions for simplified analysis
|
|
358
|
+
function extractFeaturesSimplified(packageJson) {
|
|
359
|
+
const features = [];
|
|
360
|
+
// Extract features from scripts
|
|
361
|
+
if (packageJson.scripts) {
|
|
362
|
+
if (packageJson.scripts.test)
|
|
363
|
+
features.push('Testing framework');
|
|
364
|
+
if (packageJson.scripts.build)
|
|
365
|
+
features.push('Build system');
|
|
366
|
+
if (packageJson.scripts.dev || packageJson.scripts.start)
|
|
367
|
+
features.push('Development server');
|
|
368
|
+
if (packageJson.scripts.lint)
|
|
369
|
+
features.push('Code linting');
|
|
370
|
+
if (packageJson.scripts.typecheck)
|
|
371
|
+
features.push('Type checking');
|
|
372
|
+
}
|
|
373
|
+
// Extract features from dependencies
|
|
374
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
375
|
+
if (deps?.express || deps?.fastify || deps?.koa)
|
|
376
|
+
features.push('Web server');
|
|
377
|
+
if (deps?.react || deps?.vue || deps?.angular)
|
|
378
|
+
features.push('Frontend framework');
|
|
379
|
+
if (deps?.typescript)
|
|
380
|
+
features.push('TypeScript support');
|
|
381
|
+
if (deps?.jest || deps?.mocha || deps?.vitest)
|
|
382
|
+
features.push('Unit testing');
|
|
383
|
+
if (deps?.eslint)
|
|
384
|
+
features.push('Code quality enforcement');
|
|
385
|
+
return features.length > 0 ? features : ['Core functionality'];
|
|
386
|
+
}
|
|
387
|
+
function generateTargetUsersSimplified(packageJson) {
|
|
388
|
+
if (packageJson.keywords?.includes('cli')) {
|
|
389
|
+
return '- Command-line tool users\n- Developers and system administrators';
|
|
390
|
+
}
|
|
391
|
+
if (packageJson.keywords?.includes('api')) {
|
|
392
|
+
return '- API consumers\n- Third-party integrators';
|
|
393
|
+
}
|
|
394
|
+
return '- Primary user persona\n- Secondary user persona';
|
|
395
|
+
}
|
|
396
|
+
function generateTechStackSimplified(packageJson) {
|
|
397
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
398
|
+
const stack = [];
|
|
399
|
+
if (deps?.typescript)
|
|
400
|
+
stack.push('TypeScript');
|
|
401
|
+
if (deps?.node || packageJson.engines?.node)
|
|
402
|
+
stack.push('Node.js');
|
|
403
|
+
if (deps?.express)
|
|
404
|
+
stack.push('Express.js');
|
|
405
|
+
if (deps?.react)
|
|
406
|
+
stack.push('React');
|
|
407
|
+
if (deps?.vue)
|
|
408
|
+
stack.push('Vue.js');
|
|
409
|
+
return stack.length > 0 ? stack.join(', ') : 'Technology stack to be defined';
|
|
410
|
+
}
|
|
411
|
+
function generateDependencyListSimplified(packageJson) {
|
|
412
|
+
const deps = packageJson.dependencies || {};
|
|
413
|
+
const devDeps = packageJson.devDependencies || {};
|
|
414
|
+
let list = '';
|
|
415
|
+
const depList = Object.keys(deps);
|
|
416
|
+
const devDepList = Object.keys(devDeps);
|
|
417
|
+
if (depList.length > 0) {
|
|
418
|
+
list += '### Production Dependencies\n';
|
|
419
|
+
list += depList.slice(0, 10).map(dep => `- ${dep}`).join('\n');
|
|
420
|
+
}
|
|
421
|
+
if (devDepList.length > 0) {
|
|
422
|
+
list += '\n### Development Dependencies\n';
|
|
423
|
+
list += devDepList.slice(0, 10).map(dep => `- ${dep}`).join('\n');
|
|
424
|
+
}
|
|
425
|
+
return list || 'Dependencies to be analyzed';
|
|
426
|
+
}
|
|
427
|
+
function generateWorkflowSimplified(packageJson) {
|
|
428
|
+
const scripts = packageJson.scripts || {};
|
|
429
|
+
let workflow = '## Development Commands\n';
|
|
430
|
+
if (scripts.dev)
|
|
431
|
+
workflow += `- \`npm run dev\` - Start development server\n`;
|
|
432
|
+
if (scripts.build)
|
|
433
|
+
workflow += `- \`npm run build\` - Build for production\n`;
|
|
434
|
+
if (scripts.test)
|
|
435
|
+
workflow += `- \`npm run test\` - Run tests\n`;
|
|
436
|
+
if (scripts.lint)
|
|
437
|
+
workflow += `- \`npm run lint\` - Check code quality\n`;
|
|
438
|
+
return workflow;
|
|
439
|
+
}
|
|
440
|
+
function generateDirectoryStructureSimplified(projectPath) {
|
|
441
|
+
const fs = require('fs');
|
|
442
|
+
try {
|
|
443
|
+
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
444
|
+
const directories = items
|
|
445
|
+
.filter((item) => item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules')
|
|
446
|
+
.map((item) => `- ${item.name}/`)
|
|
447
|
+
.join('\n');
|
|
448
|
+
return directories || 'Directory structure to be analyzed';
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
return 'Directory structure to be analyzed';
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Additional context-aware SDD tools
|
|
455
|
+
async function handleRequirementsSimplified(args) {
|
|
456
|
+
const fs = await import('fs');
|
|
457
|
+
const path = await import('path');
|
|
458
|
+
try {
|
|
459
|
+
const { featureName } = args;
|
|
460
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
461
|
+
throw new Error('Feature name is required for requirements generation');
|
|
462
|
+
}
|
|
463
|
+
// Load spec context
|
|
464
|
+
const { spec, requirements } = await loadSpecContext(featureName);
|
|
465
|
+
if (!spec) {
|
|
466
|
+
throw new Error(`Feature "${featureName}" not found. Run sdd-init first.`);
|
|
467
|
+
}
|
|
468
|
+
// Extract project description from spec
|
|
469
|
+
let projectDescription = 'Feature requirements specification';
|
|
470
|
+
if (requirements) {
|
|
471
|
+
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
472
|
+
if (descMatch) {
|
|
473
|
+
projectDescription = descMatch[1].trim();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
// Generate EARS-formatted requirements based on description
|
|
477
|
+
const requirementsContent = `# Requirements Document
|
|
478
|
+
|
|
479
|
+
## Introduction
|
|
480
|
+
${generateIntroductionFromDescription(projectDescription)}
|
|
481
|
+
|
|
482
|
+
## Requirements
|
|
483
|
+
|
|
484
|
+
### Requirement 1: Core Functionality
|
|
485
|
+
**Objective:** As a user, I want ${extractPrimaryObjective(projectDescription)}, so that ${extractPrimaryBenefit(projectDescription)}
|
|
486
|
+
|
|
487
|
+
#### Acceptance Criteria
|
|
488
|
+
${generateEARSRequirements(projectDescription).map((req, index) => `${index + 1}. ${req}`).join('\n')}
|
|
489
|
+
|
|
490
|
+
### Requirement 2: System Quality
|
|
491
|
+
**Objective:** As a user, I want the system to be reliable and performant, so that I can depend on it for my work
|
|
492
|
+
|
|
493
|
+
#### Acceptance Criteria
|
|
494
|
+
1. WHEN the system is used THEN it SHALL respond within acceptable time limits
|
|
495
|
+
2. IF errors occur THEN the system SHALL handle them gracefully and provide meaningful feedback
|
|
496
|
+
3. WHILE the system is running THE system SHALL maintain data integrity and consistency
|
|
497
|
+
|
|
498
|
+
### Requirement 3: Usability
|
|
499
|
+
**Objective:** As a user, I want the system to be intuitive and well-documented, so that I can use it effectively
|
|
500
|
+
|
|
501
|
+
#### Acceptance Criteria
|
|
502
|
+
1. WHEN I use the system for the first time THEN I SHALL be able to complete basic tasks without extensive training
|
|
503
|
+
2. WHERE help is needed THE system SHALL provide clear documentation and guidance
|
|
504
|
+
3. IF I make mistakes THEN the system SHALL provide helpful error messages and recovery options
|
|
505
|
+
`;
|
|
506
|
+
// Update spec.json with phase information
|
|
507
|
+
const specDir = path.join(process.cwd(), '.kiro', 'specs', featureName);
|
|
508
|
+
const updatedSpec = {
|
|
509
|
+
...spec,
|
|
510
|
+
phase: 'requirements-generated',
|
|
511
|
+
approvals: {
|
|
512
|
+
...spec.approvals,
|
|
513
|
+
requirements: {
|
|
514
|
+
generated: true,
|
|
515
|
+
approved: false
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
updated_at: new Date().toISOString()
|
|
519
|
+
};
|
|
520
|
+
fs.writeFileSync(path.join(specDir, 'spec.json'), JSON.stringify(updatedSpec, null, 2));
|
|
521
|
+
fs.writeFileSync(path.join(specDir, 'requirements.md'), requirementsContent);
|
|
522
|
+
return {
|
|
523
|
+
content: [{
|
|
524
|
+
type: 'text',
|
|
525
|
+
text: `## Requirements Document Generated
|
|
526
|
+
|
|
527
|
+
**Feature**: \`${featureName}\`
|
|
528
|
+
**File**: \`.kiro/specs/${featureName}/requirements.md\`
|
|
529
|
+
|
|
530
|
+
**Generated Requirements**:
|
|
531
|
+
- Core functionality requirements with EARS format
|
|
532
|
+
- System quality and reliability requirements
|
|
533
|
+
- Usability and user experience requirements
|
|
534
|
+
|
|
535
|
+
**Project Description Analyzed**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? '...' : ''}"
|
|
536
|
+
|
|
537
|
+
**Workflow Phase**: Requirements Generated
|
|
538
|
+
**Next Step**: Run \`sdd-design ${featureName}\` to create technical design (after requirements review)`
|
|
539
|
+
}]
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
return {
|
|
544
|
+
content: [{
|
|
545
|
+
type: 'text',
|
|
546
|
+
text: `Error generating requirements document: ${error.message}`
|
|
547
|
+
}],
|
|
548
|
+
isError: true
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
async function handleDesignSimplified(args) {
|
|
553
|
+
const fs = await import('fs');
|
|
554
|
+
const path = await import('path');
|
|
555
|
+
try {
|
|
556
|
+
const { featureName } = args;
|
|
557
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
558
|
+
throw new Error('Feature name is required for design generation');
|
|
559
|
+
}
|
|
560
|
+
// Load spec context
|
|
561
|
+
const { spec, requirements } = await loadSpecContext(featureName);
|
|
562
|
+
if (!spec) {
|
|
563
|
+
throw new Error(`Feature "${featureName}" not found. Run sdd-init first.`);
|
|
564
|
+
}
|
|
565
|
+
// Validate phase - requirements must be generated
|
|
566
|
+
if (!spec.approvals?.requirements?.generated) {
|
|
567
|
+
throw new Error(`Requirements must be generated before design. Run sdd-requirements ${featureName} first.`);
|
|
568
|
+
}
|
|
569
|
+
// Extract project description from requirements
|
|
570
|
+
let projectDescription = 'Technical design specification';
|
|
571
|
+
if (requirements) {
|
|
572
|
+
const descMatch = requirements.match(/## Project Description \(Input\)\n([\s\S]*?)(?:\n##|$)/);
|
|
573
|
+
if (descMatch) {
|
|
574
|
+
projectDescription = descMatch[1].trim();
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
// Generate design document based on requirements
|
|
578
|
+
const designContent = `# Technical Design Document
|
|
579
|
+
|
|
580
|
+
## Overview
|
|
581
|
+
This design document specifies the technical implementation approach for ${spec.feature_name}.
|
|
582
|
+
|
|
583
|
+
**Purpose**: ${projectDescription}
|
|
584
|
+
|
|
585
|
+
**Goals**:
|
|
586
|
+
- Deliver a robust and maintainable solution
|
|
587
|
+
- Ensure scalability and performance
|
|
588
|
+
- Follow established architectural patterns
|
|
589
|
+
|
|
590
|
+
## Architecture
|
|
591
|
+
|
|
592
|
+
### High-Level Architecture
|
|
593
|
+
The system follows a modular architecture with clear separation of concerns:
|
|
594
|
+
|
|
595
|
+
- **Input Layer**: Handles user input validation and processing
|
|
596
|
+
- **Core Logic**: Implements business logic and rules
|
|
597
|
+
- **Output Layer**: Manages results presentation and formatting
|
|
598
|
+
- **Error Handling**: Provides comprehensive error management
|
|
599
|
+
|
|
600
|
+
### System Flow
|
|
601
|
+
1. **Input Processing**: Validate and sanitize user input
|
|
602
|
+
2. **Business Logic**: Execute core functionality
|
|
603
|
+
3. **Result Generation**: Process and format outputs
|
|
604
|
+
4. **Error Management**: Handle exceptions and edge cases
|
|
605
|
+
|
|
606
|
+
## Components and Interfaces
|
|
607
|
+
|
|
608
|
+
### Core Components
|
|
609
|
+
|
|
610
|
+
#### Input Processor
|
|
611
|
+
- **Responsibility**: Input validation and sanitization
|
|
612
|
+
- **Interface**:
|
|
613
|
+
- \`validateInput(data: InputData): ValidationResult\`
|
|
614
|
+
- \`sanitizeInput(data: InputData): CleanData\`
|
|
615
|
+
|
|
616
|
+
#### Business Logic Engine
|
|
617
|
+
- **Responsibility**: Core functionality implementation
|
|
618
|
+
- **Interface**:
|
|
619
|
+
- \`processRequest(input: CleanData): ProcessingResult\`
|
|
620
|
+
- \`handleBusinessRules(data: CleanData): RuleResult\`
|
|
621
|
+
|
|
622
|
+
#### Output Formatter
|
|
623
|
+
- **Responsibility**: Result formatting and presentation
|
|
624
|
+
- **Interface**:
|
|
625
|
+
- \`formatResult(result: ProcessingResult): FormattedOutput\`
|
|
626
|
+
- \`handleError(error: Error): ErrorResponse\`
|
|
627
|
+
|
|
628
|
+
## Data Models
|
|
629
|
+
|
|
630
|
+
### Input Data Model
|
|
631
|
+
\`\`\`typescript
|
|
632
|
+
interface InputData {
|
|
633
|
+
// Input structure based on requirements
|
|
634
|
+
payload: unknown;
|
|
635
|
+
metadata: Record<string, unknown>;
|
|
636
|
+
}
|
|
637
|
+
\`\`\`
|
|
638
|
+
|
|
639
|
+
### Processing Result Model
|
|
640
|
+
\`\`\`typescript
|
|
641
|
+
interface ProcessingResult {
|
|
642
|
+
success: boolean;
|
|
643
|
+
data: unknown;
|
|
644
|
+
metadata: ResultMetadata;
|
|
645
|
+
}
|
|
646
|
+
\`\`\`
|
|
647
|
+
|
|
648
|
+
## Error Handling
|
|
649
|
+
|
|
650
|
+
### Error Categories
|
|
651
|
+
- **Validation Errors**: Invalid input format or content
|
|
652
|
+
- **Processing Errors**: Failures during business logic execution
|
|
653
|
+
- **System Errors**: Infrastructure or dependency failures
|
|
654
|
+
|
|
655
|
+
### Error Response Strategy
|
|
656
|
+
- Clear error messages for user-facing issues
|
|
657
|
+
- Detailed logging for system debugging
|
|
658
|
+
- Graceful degradation where possible
|
|
659
|
+
|
|
660
|
+
## Testing Strategy
|
|
661
|
+
|
|
662
|
+
### Unit Tests
|
|
663
|
+
- Input validation functions
|
|
664
|
+
- Business logic components
|
|
665
|
+
- Output formatting utilities
|
|
666
|
+
|
|
667
|
+
### Integration Tests
|
|
668
|
+
- End-to-end workflow validation
|
|
669
|
+
- Error handling scenarios
|
|
670
|
+
- Performance under load
|
|
671
|
+
|
|
672
|
+
### Quality Assurance
|
|
673
|
+
- Code coverage requirements
|
|
674
|
+
- Performance benchmarks
|
|
675
|
+
- Security validation
|
|
676
|
+
`;
|
|
677
|
+
// Update spec.json with phase information
|
|
678
|
+
const specDir = path.join(process.cwd(), '.kiro', 'specs', featureName);
|
|
679
|
+
const updatedSpec = {
|
|
680
|
+
...spec,
|
|
681
|
+
phase: 'design-generated',
|
|
682
|
+
approvals: {
|
|
683
|
+
...spec.approvals,
|
|
684
|
+
design: {
|
|
685
|
+
generated: true,
|
|
686
|
+
approved: false
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
updated_at: new Date().toISOString()
|
|
690
|
+
};
|
|
691
|
+
fs.writeFileSync(path.join(specDir, 'spec.json'), JSON.stringify(updatedSpec, null, 2));
|
|
692
|
+
fs.writeFileSync(path.join(specDir, 'design.md'), designContent);
|
|
693
|
+
return {
|
|
694
|
+
content: [{
|
|
695
|
+
type: 'text',
|
|
696
|
+
text: `## Design Document Generated
|
|
697
|
+
|
|
698
|
+
**Feature**: \`${featureName}\`
|
|
699
|
+
**File**: \`.kiro/specs/${featureName}/design.md\`
|
|
700
|
+
|
|
701
|
+
**Design Elements**:
|
|
702
|
+
- Modular architecture with clear component separation
|
|
703
|
+
- Comprehensive interface specifications
|
|
704
|
+
- Data models and error handling strategy
|
|
705
|
+
- Complete testing approach
|
|
706
|
+
|
|
707
|
+
**Project Description**: "${projectDescription.substring(0, 100)}${projectDescription.length > 100 ? '...' : ''}"
|
|
708
|
+
|
|
709
|
+
**Workflow Phase**: Design Generated
|
|
710
|
+
**Next Step**: Run \`sdd-tasks ${featureName}\` to generate implementation tasks (after design review)`
|
|
711
|
+
}]
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
catch (error) {
|
|
715
|
+
return {
|
|
716
|
+
content: [{
|
|
717
|
+
type: 'text',
|
|
718
|
+
text: `Error generating design document: ${error.message}`
|
|
719
|
+
}],
|
|
720
|
+
isError: true
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
async function handleTasksSimplified(args) {
|
|
725
|
+
const fs = await import('fs');
|
|
726
|
+
const path = await import('path');
|
|
727
|
+
try {
|
|
728
|
+
const { featureName } = args;
|
|
729
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
730
|
+
throw new Error('Feature name is required for tasks generation');
|
|
731
|
+
}
|
|
732
|
+
// Load spec context
|
|
733
|
+
const { spec } = await loadSpecContext(featureName);
|
|
734
|
+
if (!spec) {
|
|
735
|
+
throw new Error(`Feature "${featureName}" not found. Run sdd-init first.`);
|
|
736
|
+
}
|
|
737
|
+
// Validate phase - design must be generated
|
|
738
|
+
if (!spec.approvals?.design?.generated) {
|
|
739
|
+
throw new Error(`Design must be generated before tasks. Run sdd-design ${featureName} first.`);
|
|
740
|
+
}
|
|
741
|
+
// Generate implementation tasks following kiro format
|
|
742
|
+
const tasksContent = `# Implementation Plan
|
|
743
|
+
|
|
744
|
+
- [ ] 1. Set up project foundation and infrastructure
|
|
745
|
+
- [ ] 1.1 Initialize project structure and configuration
|
|
746
|
+
- Create directory structure as per design
|
|
747
|
+
- Set up build configuration and tooling
|
|
748
|
+
- Initialize version control and documentation
|
|
749
|
+
- _Requirements: All requirements need foundational setup_
|
|
750
|
+
|
|
751
|
+
- [ ] 1.2 Implement core infrastructure components
|
|
752
|
+
- Set up error handling framework
|
|
753
|
+
- Create logging and monitoring utilities
|
|
754
|
+
- Establish configuration management
|
|
755
|
+
- _Requirements: System quality requirements_
|
|
756
|
+
|
|
757
|
+
- [ ] 2. Implement core functionality
|
|
758
|
+
- [ ] 2.1 Develop input processing components
|
|
759
|
+
- Build input validation system
|
|
760
|
+
- Implement data sanitization logic
|
|
761
|
+
- Create input parsing utilities
|
|
762
|
+
- _Requirements: 1.1, 1.2_
|
|
763
|
+
|
|
764
|
+
- [ ] 2.2 Build business logic engine
|
|
765
|
+
- Implement core processing algorithms
|
|
766
|
+
- Create business rule validation
|
|
767
|
+
- Develop result generation logic
|
|
768
|
+
- _Requirements: 1.1, 1.3_
|
|
769
|
+
|
|
770
|
+
- [ ] 2.3 Create output formatting system
|
|
771
|
+
- Build result formatting utilities
|
|
772
|
+
- Implement response generation
|
|
773
|
+
- Create output validation
|
|
774
|
+
- _Requirements: 1.2, 1.3_
|
|
775
|
+
|
|
776
|
+
- [ ] 3. Implement error handling and validation
|
|
777
|
+
- [ ] 3.1 Build comprehensive error management
|
|
778
|
+
- Create error classification system
|
|
779
|
+
- Implement error recovery mechanisms
|
|
780
|
+
- Build error logging and reporting
|
|
781
|
+
- _Requirements: 2.1, 2.2_
|
|
782
|
+
|
|
783
|
+
- [ ] 3.2 Add input/output validation
|
|
784
|
+
- Implement schema validation
|
|
785
|
+
- Create boundary condition checks
|
|
786
|
+
- Add security validation layers
|
|
787
|
+
- _Requirements: 2.1, 3.1_
|
|
788
|
+
|
|
789
|
+
- [ ] 4. Develop testing and quality assurance
|
|
790
|
+
- [ ] 4.1 Create unit test suite
|
|
791
|
+
- Test input processing components
|
|
792
|
+
- Test business logic functions
|
|
793
|
+
- Test output formatting utilities
|
|
794
|
+
- _Requirements: All functional requirements_
|
|
795
|
+
|
|
796
|
+
- [ ] 4.2 Build integration test framework
|
|
797
|
+
- Test end-to-end workflows
|
|
798
|
+
- Test error handling scenarios
|
|
799
|
+
- Test performance benchmarks
|
|
800
|
+
- _Requirements: 2.1, 2.2, 2.3_
|
|
801
|
+
|
|
802
|
+
- [ ] 5. Finalize implementation and deployment
|
|
803
|
+
- [ ] 5.1 Integrate all components
|
|
804
|
+
- Wire together all system components
|
|
805
|
+
- Implement final error handling
|
|
806
|
+
- Add performance optimizations
|
|
807
|
+
- _Requirements: All requirements integration_
|
|
808
|
+
|
|
809
|
+
- [ ] 5.2 Prepare for deployment
|
|
810
|
+
- Create deployment configuration
|
|
811
|
+
- Add production monitoring
|
|
812
|
+
- Finalize documentation
|
|
813
|
+
- _Requirements: System quality and deployment_
|
|
814
|
+
`;
|
|
815
|
+
// Update spec.json with phase information
|
|
816
|
+
const specDir = path.join(process.cwd(), '.kiro', 'specs', featureName);
|
|
817
|
+
const updatedSpec = {
|
|
818
|
+
...spec,
|
|
819
|
+
phase: 'tasks-generated',
|
|
820
|
+
approvals: {
|
|
821
|
+
...spec.approvals,
|
|
822
|
+
tasks: {
|
|
823
|
+
generated: true,
|
|
824
|
+
approved: false
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
ready_for_implementation: true,
|
|
828
|
+
updated_at: new Date().toISOString()
|
|
829
|
+
};
|
|
830
|
+
fs.writeFileSync(path.join(specDir, 'spec.json'), JSON.stringify(updatedSpec, null, 2));
|
|
831
|
+
fs.writeFileSync(path.join(specDir, 'tasks.md'), tasksContent);
|
|
832
|
+
return {
|
|
833
|
+
content: [{
|
|
834
|
+
type: 'text',
|
|
835
|
+
text: `## Implementation Tasks Generated
|
|
836
|
+
|
|
837
|
+
**Feature**: \`${featureName}\`
|
|
838
|
+
**File**: \`.kiro/specs/${featureName}/tasks.md\`
|
|
839
|
+
|
|
840
|
+
**Generated Tasks**:
|
|
841
|
+
- 5 major task groups with 10 sub-tasks total
|
|
842
|
+
- Properly sequenced with dependency tracking
|
|
843
|
+
- Requirement traceability for all tasks
|
|
844
|
+
- Coverage of setup, core functionality, validation, testing, and deployment
|
|
845
|
+
|
|
846
|
+
**Workflow Phase**: Tasks Generated
|
|
847
|
+
**Status**: Ready for Implementation
|
|
848
|
+
**Next Step**: Begin implementation following the task sequence`
|
|
849
|
+
}]
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
catch (error) {
|
|
853
|
+
return {
|
|
854
|
+
content: [{
|
|
855
|
+
type: 'text',
|
|
856
|
+
text: `Error generating tasks document: ${error.message}`
|
|
857
|
+
}],
|
|
858
|
+
isError: true
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
// Helper functions for simplified tool implementations
|
|
863
|
+
function analyzeProjectStructureSync(projectPath) {
|
|
864
|
+
const fs = require('fs');
|
|
865
|
+
try {
|
|
866
|
+
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
867
|
+
return {
|
|
868
|
+
directories: items.filter((item) => item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules').map((item) => item.name),
|
|
869
|
+
files: items.filter((item) => item.isFile()).map((item) => item.name),
|
|
870
|
+
hasSource: items.some((item) => item.isDirectory() && item.name === 'src'),
|
|
871
|
+
hasTests: items.some((item) => item.isDirectory() && (item.name === 'test' || item.name === '__tests__')),
|
|
872
|
+
hasDocs: items.some((item) => item.isDirectory() && (item.name === 'docs' || item.name === 'documentation'))
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
catch (error) {
|
|
876
|
+
return { directories: [], files: [] };
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
function generateCoreObjectiveSimplified(packageJson, projectAnalysis) {
|
|
880
|
+
if (packageJson.description) {
|
|
881
|
+
return `Deliver ${packageJson.description} with full functionality and reliability`;
|
|
882
|
+
}
|
|
883
|
+
if (packageJson.keywords?.length > 0) {
|
|
884
|
+
return `Implement ${packageJson.keywords.join(', ')} functionality`;
|
|
885
|
+
}
|
|
886
|
+
return 'Deliver core application functionality';
|
|
887
|
+
}
|
|
888
|
+
function generateAcceptanceCriteriaSimplified(packageJson, projectAnalysis) {
|
|
889
|
+
const criteria = [];
|
|
890
|
+
if (packageJson.scripts?.test) {
|
|
891
|
+
criteria.push('WHEN tests are run THEN all tests SHALL pass');
|
|
892
|
+
}
|
|
893
|
+
if (packageJson.scripts?.build) {
|
|
894
|
+
criteria.push('WHEN build is executed THEN system SHALL compile without errors');
|
|
895
|
+
}
|
|
896
|
+
if (packageJson.scripts?.lint) {
|
|
897
|
+
criteria.push('WHERE code quality is checked THE system SHALL meet linting standards');
|
|
898
|
+
}
|
|
899
|
+
if (packageJson.main || packageJson.bin) {
|
|
900
|
+
criteria.push('WHEN application starts THEN system SHALL initialize successfully');
|
|
901
|
+
}
|
|
902
|
+
criteria.push('IF errors occur THEN system SHALL handle them gracefully');
|
|
903
|
+
return criteria.length > 0 ? criteria : ['System SHALL meet functional requirements'];
|
|
904
|
+
}
|
|
905
|
+
function generateTechRequirementsSimplified(packageJson) {
|
|
906
|
+
const requirements = [];
|
|
907
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
908
|
+
if (deps?.typescript) {
|
|
909
|
+
requirements.push('System SHALL use TypeScript for type safety');
|
|
910
|
+
}
|
|
911
|
+
if (deps?.express || deps?.fastify) {
|
|
912
|
+
requirements.push('System SHALL implement RESTful API endpoints');
|
|
913
|
+
}
|
|
914
|
+
if (deps?.react || deps?.vue || deps?.angular) {
|
|
915
|
+
requirements.push('System SHALL provide responsive user interface');
|
|
916
|
+
}
|
|
917
|
+
if (deps?.jest || deps?.mocha || deps?.vitest) {
|
|
918
|
+
requirements.push('System SHALL include comprehensive test coverage');
|
|
919
|
+
}
|
|
920
|
+
return requirements.length > 0 ? requirements : ['System SHALL integrate required technologies'];
|
|
921
|
+
}
|
|
922
|
+
function generateQualityRequirementsSimplified(packageJson) {
|
|
923
|
+
const requirements = [];
|
|
924
|
+
if (packageJson.scripts?.lint) {
|
|
925
|
+
requirements.push('Code SHALL pass linting checks');
|
|
926
|
+
}
|
|
927
|
+
if (packageJson.scripts?.typecheck) {
|
|
928
|
+
requirements.push('Code SHALL pass type checking');
|
|
929
|
+
}
|
|
930
|
+
if (packageJson.scripts?.test) {
|
|
931
|
+
requirements.push('Code SHALL maintain test coverage standards');
|
|
932
|
+
}
|
|
933
|
+
requirements.push('Code SHALL follow established conventions');
|
|
934
|
+
return requirements;
|
|
935
|
+
}
|
|
936
|
+
function generateArchitectureDescriptionSimplified(packageJson, projectAnalysis) {
|
|
937
|
+
let description = '';
|
|
938
|
+
if (packageJson.type === 'module') {
|
|
939
|
+
description += 'Modern ES Module-based architecture. ';
|
|
940
|
+
}
|
|
941
|
+
if (projectAnalysis.hasSource) {
|
|
942
|
+
description += 'Modular source code organization with clear separation of concerns. ';
|
|
943
|
+
}
|
|
944
|
+
if (packageJson.dependencies?.express) {
|
|
945
|
+
description += 'RESTful API server architecture using Express.js framework. ';
|
|
946
|
+
}
|
|
947
|
+
if (packageJson.dependencies?.typescript || packageJson.devDependencies?.typescript) {
|
|
948
|
+
description += 'Type-safe development with TypeScript compilation. ';
|
|
949
|
+
}
|
|
950
|
+
return description || 'Application architecture to be defined based on requirements.';
|
|
951
|
+
}
|
|
952
|
+
function generateComponentDescriptionsSimplified(projectAnalysis) {
|
|
953
|
+
const components = [];
|
|
954
|
+
if (projectAnalysis.hasSource) {
|
|
955
|
+
components.push({ name: 'Core Module', description: 'Main application logic and business rules' });
|
|
956
|
+
}
|
|
957
|
+
if (projectAnalysis.hasTests) {
|
|
958
|
+
components.push({ name: 'Test Suite', description: 'Automated testing framework and test cases' });
|
|
959
|
+
}
|
|
960
|
+
if (projectAnalysis.hasDocs) {
|
|
961
|
+
components.push({ name: 'Documentation', description: 'Project documentation and API specifications' });
|
|
962
|
+
}
|
|
963
|
+
return components.length > 0 ? components : [
|
|
964
|
+
{ name: 'Application Core', description: 'Main application functionality' }
|
|
965
|
+
];
|
|
966
|
+
}
|
|
967
|
+
function generateDataModelsSimplified(packageJson, projectAnalysis) {
|
|
968
|
+
const models = [];
|
|
969
|
+
if (packageJson.dependencies?.mongoose || packageJson.dependencies?.mongodb) {
|
|
970
|
+
models.push('MongoDB Document Models');
|
|
971
|
+
}
|
|
972
|
+
if (packageJson.dependencies?.sequelize || packageJson.dependencies?.typeorm) {
|
|
973
|
+
models.push('Relational Database Models');
|
|
974
|
+
}
|
|
975
|
+
if (packageJson.dependencies?.graphql) {
|
|
976
|
+
models.push('GraphQL Schema Models');
|
|
977
|
+
}
|
|
978
|
+
return models.length > 0 ? models : ['Application Data Models'];
|
|
979
|
+
}
|
|
980
|
+
function generateDetailedTechStackSimplified(packageJson) {
|
|
981
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
982
|
+
const stack = [];
|
|
983
|
+
if (deps?.typescript)
|
|
984
|
+
stack.push('- **TypeScript**: Type-safe JavaScript development');
|
|
985
|
+
if (deps?.node || packageJson.engines?.node)
|
|
986
|
+
stack.push(`- **Node.js**: ${packageJson.engines?.node || 'Runtime environment'}`);
|
|
987
|
+
if (deps?.express)
|
|
988
|
+
stack.push('- **Express.js**: Web application framework');
|
|
989
|
+
if (deps?.react)
|
|
990
|
+
stack.push('- **React**: User interface library');
|
|
991
|
+
if (deps?.vue)
|
|
992
|
+
stack.push('- **Vue.js**: Progressive frontend framework');
|
|
993
|
+
if (deps?.jest)
|
|
994
|
+
stack.push('- **Jest**: Testing framework');
|
|
995
|
+
return stack.length > 0 ? stack.join('\n') : '- Technology stack to be defined';
|
|
996
|
+
}
|
|
997
|
+
function generateDesignPatternsSimplified(packageJson, projectAnalysis) {
|
|
998
|
+
const patterns = [];
|
|
999
|
+
if (packageJson.dependencies?.inversify) {
|
|
1000
|
+
patterns.push('Dependency Injection');
|
|
1001
|
+
}
|
|
1002
|
+
if (projectAnalysis.hasSource) {
|
|
1003
|
+
patterns.push('Modular Architecture');
|
|
1004
|
+
}
|
|
1005
|
+
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1006
|
+
patterns.push('MVC Pattern');
|
|
1007
|
+
}
|
|
1008
|
+
return patterns.length > 0 ? patterns : ['Standard Design Patterns'];
|
|
1009
|
+
}
|
|
1010
|
+
function generateDependencyAnalysisSimplified(packageJson) {
|
|
1011
|
+
const production = Object.keys(packageJson.dependencies || {});
|
|
1012
|
+
const development = Object.keys(packageJson.devDependencies || {});
|
|
1013
|
+
let analysis = '';
|
|
1014
|
+
if (production.length > 0) {
|
|
1015
|
+
analysis += `**Production Dependencies:** ${production.length} packages\n`;
|
|
1016
|
+
analysis += production.slice(0, 5).map(dep => `- ${dep}`).join('\n');
|
|
1017
|
+
if (production.length > 5)
|
|
1018
|
+
analysis += `\n- ... and ${production.length - 5} more`;
|
|
1019
|
+
}
|
|
1020
|
+
if (development.length > 0) {
|
|
1021
|
+
analysis += `\n\n**Development Dependencies:** ${development.length} packages\n`;
|
|
1022
|
+
analysis += development.slice(0, 5).map(dep => `- ${dep}`).join('\n');
|
|
1023
|
+
if (development.length > 5)
|
|
1024
|
+
analysis += `\n- ... and ${development.length - 5} more`;
|
|
1025
|
+
}
|
|
1026
|
+
return analysis || 'Dependencies to be analyzed';
|
|
1027
|
+
}
|
|
1028
|
+
function generateAPIInterfacesSimplified(packageJson, projectAnalysis) {
|
|
1029
|
+
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1030
|
+
return `RESTful API endpoints following OpenAPI specification:
|
|
1031
|
+
- GET /api/health - Health check endpoint
|
|
1032
|
+
- Authentication and authorization middleware
|
|
1033
|
+
- Request/response validation
|
|
1034
|
+
- Error handling middleware`;
|
|
1035
|
+
}
|
|
1036
|
+
return 'Interface specifications to be defined';
|
|
1037
|
+
}
|
|
1038
|
+
function generateModuleInterfacesSimplified(projectAnalysis) {
|
|
1039
|
+
if (projectAnalysis.hasSource) {
|
|
1040
|
+
return `Internal module interfaces:
|
|
1041
|
+
- Clear module boundaries and exports
|
|
1042
|
+
- Consistent API patterns across modules
|
|
1043
|
+
- Type definitions for all public interfaces`;
|
|
1044
|
+
}
|
|
1045
|
+
return 'Module interfaces to be defined';
|
|
1046
|
+
}
|
|
1047
|
+
function generateEnvVarSpecsSimplified(packageJson) {
|
|
1048
|
+
const envVars = [];
|
|
1049
|
+
if (packageJson.dependencies?.express || packageJson.dependencies?.fastify) {
|
|
1050
|
+
envVars.push('- `PORT`: Server port (default: 3000)');
|
|
1051
|
+
envVars.push('- `NODE_ENV`: Environment mode (development/production)');
|
|
1052
|
+
}
|
|
1053
|
+
envVars.push('- `LOG_LEVEL`: Logging level (debug/info/warn/error)');
|
|
1054
|
+
return envVars.join('\n');
|
|
1055
|
+
}
|
|
1056
|
+
function generateBuildConfigSimplified(packageJson) {
|
|
1057
|
+
let config = '';
|
|
1058
|
+
if (packageJson.scripts?.build) {
|
|
1059
|
+
config += `Build process: \`${packageJson.scripts.build}\`\n`;
|
|
1060
|
+
}
|
|
1061
|
+
if (packageJson.scripts?.start) {
|
|
1062
|
+
config += `Start command: \`${packageJson.scripts.start}\`\n`;
|
|
1063
|
+
}
|
|
1064
|
+
if (packageJson.type === 'module') {
|
|
1065
|
+
config += 'Module type: ES Modules\n';
|
|
1066
|
+
}
|
|
1067
|
+
return config || 'Build configuration to be defined';
|
|
1068
|
+
}
|
|
1069
|
+
function generateImplementationTasksSimplified(packageJson, projectAnalysis) {
|
|
1070
|
+
const tasks = {
|
|
1071
|
+
development: [],
|
|
1072
|
+
integration: [],
|
|
1073
|
+
quality: [],
|
|
1074
|
+
deployment: []
|
|
1075
|
+
};
|
|
1076
|
+
// Development tasks
|
|
1077
|
+
if (projectAnalysis.hasSource) {
|
|
1078
|
+
tasks.development.push({
|
|
1079
|
+
title: 'Implement Core Modules',
|
|
1080
|
+
subtasks: ['Set up module structure', 'Implement business logic', 'Add error handling'],
|
|
1081
|
+
requirements: 'FR-1, FR-2'
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
if (packageJson.dependencies?.express) {
|
|
1085
|
+
tasks.development.push({
|
|
1086
|
+
title: 'Develop API Endpoints',
|
|
1087
|
+
subtasks: ['Create route handlers', 'Add middleware', 'Implement validation'],
|
|
1088
|
+
requirements: 'FR-2'
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
// Integration tasks
|
|
1092
|
+
if (packageJson.dependencies?.mongodb || packageJson.dependencies?.mongoose) {
|
|
1093
|
+
tasks.integration.push({
|
|
1094
|
+
title: 'Database Integration',
|
|
1095
|
+
subtasks: ['Set up database connection', 'Create data models', 'Implement queries'],
|
|
1096
|
+
requirements: 'NFR-2'
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
// Quality tasks
|
|
1100
|
+
if (packageJson.scripts?.test) {
|
|
1101
|
+
tasks.quality.push({
|
|
1102
|
+
title: 'Test Implementation',
|
|
1103
|
+
subtasks: ['Write unit tests', 'Add integration tests', 'Ensure test coverage'],
|
|
1104
|
+
requirements: 'FR-3, NFR-3'
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
if (packageJson.scripts?.lint) {
|
|
1108
|
+
tasks.quality.push({
|
|
1109
|
+
title: 'Code Quality Assurance',
|
|
1110
|
+
subtasks: ['Run linting checks', 'Fix code style issues', 'Add documentation'],
|
|
1111
|
+
requirements: 'NFR-3'
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
// Deployment tasks
|
|
1115
|
+
if (packageJson.scripts?.build) {
|
|
1116
|
+
tasks.deployment.push({
|
|
1117
|
+
title: 'Build and Package',
|
|
1118
|
+
subtasks: ['Run build process', 'Optimize for production', 'Create deployment artifacts'],
|
|
1119
|
+
requirements: 'NFR-1'
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
tasks.deployment.push({
|
|
1123
|
+
title: 'Deployment Configuration',
|
|
1124
|
+
subtasks: ['Set up environment variables', 'Configure production settings', 'Deploy to target environment'],
|
|
1125
|
+
requirements: 'NFR-1, NFR-2'
|
|
1126
|
+
});
|
|
1127
|
+
return tasks;
|
|
1128
|
+
}
|
|
1129
|
+
// Helper functions for requirement generation from description
|
|
1130
|
+
function generateIntroductionFromDescription(description) {
|
|
1131
|
+
const systemName = extractSystemName(description);
|
|
1132
|
+
return `This document specifies the requirements for ${systemName}. The system aims to ${description.toLowerCase()}.`;
|
|
1133
|
+
}
|
|
1134
|
+
function extractSystemName(description) {
|
|
1135
|
+
// Extract a system name from description
|
|
1136
|
+
const words = description.split(' ');
|
|
1137
|
+
if (words.length >= 2) {
|
|
1138
|
+
return `the ${words.slice(0, 3).join(' ')}`;
|
|
1139
|
+
}
|
|
1140
|
+
return 'the system';
|
|
1141
|
+
}
|
|
1142
|
+
function extractPrimaryObjective(description) {
|
|
1143
|
+
// Convert description into user objective
|
|
1144
|
+
if (description.toLowerCase().includes('tool') || description.toLowerCase().includes('cli')) {
|
|
1145
|
+
return `use a tool that ${description.toLowerCase()}`;
|
|
1146
|
+
}
|
|
1147
|
+
if (description.toLowerCase().includes('system') || description.toLowerCase().includes('application')) {
|
|
1148
|
+
return `access a system that ${description.toLowerCase()}`;
|
|
1149
|
+
}
|
|
1150
|
+
return `have functionality that ${description.toLowerCase()}`;
|
|
1151
|
+
}
|
|
1152
|
+
function extractPrimaryBenefit(description) {
|
|
1153
|
+
// Infer benefit from description
|
|
1154
|
+
if (description.toLowerCase().includes('automate')) {
|
|
1155
|
+
return 'I can save time and reduce manual effort';
|
|
1156
|
+
}
|
|
1157
|
+
if (description.toLowerCase().includes('analyze') || description.toLowerCase().includes('review')) {
|
|
1158
|
+
return 'I can make better informed decisions';
|
|
1159
|
+
}
|
|
1160
|
+
if (description.toLowerCase().includes('manage') || description.toLowerCase().includes('organize')) {
|
|
1161
|
+
return 'I can maintain better control and organization';
|
|
1162
|
+
}
|
|
1163
|
+
return 'I can accomplish my goals more effectively';
|
|
1164
|
+
}
|
|
1165
|
+
function generateEARSRequirements(description) {
|
|
1166
|
+
const requirements = [];
|
|
1167
|
+
// Core functional requirement
|
|
1168
|
+
requirements.push(`WHEN I use the system THEN it SHALL provide ${description.toLowerCase()} functionality`);
|
|
1169
|
+
// Input/output handling
|
|
1170
|
+
requirements.push('WHEN I provide input THEN the system SHALL validate and process it correctly');
|
|
1171
|
+
// Error handling
|
|
1172
|
+
requirements.push('IF invalid input is provided THEN the system SHALL reject it with clear error messages');
|
|
1173
|
+
// Success condition
|
|
1174
|
+
requirements.push('WHEN all inputs are valid THEN the system SHALL complete the requested operation successfully');
|
|
1175
|
+
return requirements;
|
|
1176
|
+
}
|
|
1177
|
+
// Helper functions for kiro-style workflow
|
|
1178
|
+
function generateFeatureName(description) {
|
|
1179
|
+
// Extract feature name from description - similar to kiro spec-init
|
|
1180
|
+
const cleaned = description
|
|
1181
|
+
.toLowerCase()
|
|
1182
|
+
.replace(/[^a-z0-9\s]/g, '')
|
|
1183
|
+
.trim()
|
|
1184
|
+
.split(/\s+/)
|
|
1185
|
+
.slice(0, 4) // Take first 4 words
|
|
1186
|
+
.join('-');
|
|
1187
|
+
// Ensure it's not empty
|
|
1188
|
+
return cleaned || 'new-feature';
|
|
1189
|
+
}
|
|
1190
|
+
function ensureUniqueFeatureName(baseName) {
|
|
1191
|
+
const fs = require('fs');
|
|
1192
|
+
const path = require('path');
|
|
1193
|
+
const specsDir = path.join(process.cwd(), '.kiro', 'specs');
|
|
1194
|
+
if (!fs.existsSync(specsDir)) {
|
|
1195
|
+
return baseName;
|
|
1196
|
+
}
|
|
1197
|
+
let counter = 1;
|
|
1198
|
+
let featureName = baseName;
|
|
1199
|
+
while (fs.existsSync(path.join(specsDir, featureName))) {
|
|
1200
|
+
featureName = `${baseName}-${counter}`;
|
|
1201
|
+
counter++;
|
|
1202
|
+
}
|
|
1203
|
+
return featureName;
|
|
1204
|
+
}
|
|
1205
|
+
async function loadSpecContext(featureName) {
|
|
1206
|
+
const fs = await import('fs');
|
|
1207
|
+
const path = await import('path');
|
|
1208
|
+
const specDir = path.join(process.cwd(), '.kiro', 'specs', featureName);
|
|
1209
|
+
const specJsonPath = path.join(specDir, 'spec.json');
|
|
1210
|
+
const requirementsPath = path.join(specDir, 'requirements.md');
|
|
1211
|
+
let spec = null;
|
|
1212
|
+
let requirements = null;
|
|
1213
|
+
try {
|
|
1214
|
+
if (fs.existsSync(specJsonPath)) {
|
|
1215
|
+
const specContent = fs.readFileSync(specJsonPath, 'utf8');
|
|
1216
|
+
spec = JSON.parse(specContent);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
catch (error) {
|
|
1220
|
+
// Ignore spec.json parse errors
|
|
1221
|
+
}
|
|
1222
|
+
try {
|
|
1223
|
+
if (fs.existsSync(requirementsPath)) {
|
|
1224
|
+
requirements = fs.readFileSync(requirementsPath, 'utf8');
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
catch (error) {
|
|
1228
|
+
// Ignore requirements.md read errors
|
|
1229
|
+
}
|
|
1230
|
+
return { spec, requirements };
|
|
1231
|
+
}
|
|
1232
|
+
async function handleInitSimplified(args) {
|
|
1233
|
+
const fs = await import('fs');
|
|
1234
|
+
const path = await import('path');
|
|
1235
|
+
try {
|
|
1236
|
+
const { description } = args;
|
|
1237
|
+
if (!description || typeof description !== 'string') {
|
|
1238
|
+
throw new Error('Description is required for project initialization');
|
|
1239
|
+
}
|
|
1240
|
+
const projectPath = process.cwd();
|
|
1241
|
+
// Generate feature name from description
|
|
1242
|
+
const baseFeatureName = generateFeatureName(description);
|
|
1243
|
+
const featureName = ensureUniqueFeatureName(baseFeatureName);
|
|
1244
|
+
// Create .kiro/specs/[feature-name] directory
|
|
1245
|
+
const specDir = path.join(projectPath, '.kiro', 'specs', featureName);
|
|
1246
|
+
if (!fs.existsSync(specDir)) {
|
|
1247
|
+
fs.mkdirSync(specDir, { recursive: true });
|
|
1248
|
+
}
|
|
1249
|
+
// Create spec.json with metadata
|
|
1250
|
+
const specContent = {
|
|
1251
|
+
feature_name: featureName,
|
|
1252
|
+
created_at: new Date().toISOString(),
|
|
1253
|
+
updated_at: new Date().toISOString(),
|
|
1254
|
+
language: 'en',
|
|
1255
|
+
phase: 'initialized',
|
|
1256
|
+
approvals: {
|
|
1257
|
+
requirements: {
|
|
1258
|
+
generated: false,
|
|
1259
|
+
approved: false
|
|
1260
|
+
},
|
|
1261
|
+
design: {
|
|
1262
|
+
generated: false,
|
|
1263
|
+
approved: false
|
|
1264
|
+
},
|
|
1265
|
+
tasks: {
|
|
1266
|
+
generated: false,
|
|
1267
|
+
approved: false
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
ready_for_implementation: false
|
|
1271
|
+
};
|
|
1272
|
+
fs.writeFileSync(path.join(specDir, 'spec.json'), JSON.stringify(specContent, null, 2));
|
|
1273
|
+
// Create requirements.md template with project description
|
|
1274
|
+
const requirementsTemplate = `# Requirements Document
|
|
1275
|
+
|
|
1276
|
+
## Project Description (Input)
|
|
1277
|
+
${description}
|
|
1278
|
+
|
|
1279
|
+
## Requirements
|
|
1280
|
+
<!-- Will be generated in sdd-requirements phase -->
|
|
1281
|
+
`;
|
|
1282
|
+
fs.writeFileSync(path.join(specDir, 'requirements.md'), requirementsTemplate);
|
|
1283
|
+
return {
|
|
1284
|
+
content: [{
|
|
1285
|
+
type: 'text',
|
|
1286
|
+
text: `## SDD Project Initialized Successfully
|
|
1287
|
+
|
|
1288
|
+
**Feature Name**: \`${featureName}\`
|
|
1289
|
+
**Description**: ${description}
|
|
1290
|
+
|
|
1291
|
+
**Created Files**:
|
|
1292
|
+
- \`.kiro/specs/${featureName}/spec.json\` - Project metadata and phase tracking
|
|
1293
|
+
- \`.kiro/specs/${featureName}/requirements.md\` - Initial requirements template
|
|
1294
|
+
|
|
1295
|
+
**Next Steps**:
|
|
1296
|
+
1. Run \`sdd-requirements ${featureName}\` to generate detailed requirements
|
|
1297
|
+
2. Follow the SDD workflow: Requirements → Design → Tasks → Implementation
|
|
1298
|
+
|
|
1299
|
+
**Workflow Phase**: Initialized
|
|
1300
|
+
**Ready for**: Requirements generation`
|
|
1301
|
+
}]
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
catch (error) {
|
|
1305
|
+
return {
|
|
1306
|
+
content: [{
|
|
1307
|
+
type: 'text',
|
|
1308
|
+
text: `Error initializing SDD project: ${error.message}`
|
|
1309
|
+
}],
|
|
1310
|
+
isError: true
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
117
1314
|
async function main() {
|
|
118
1315
|
try {
|
|
119
1316
|
if (isMCPMode) {
|
|
@@ -121,7 +1318,7 @@ async function main() {
|
|
|
121
1318
|
await createSimpleMCPServer();
|
|
122
1319
|
}
|
|
123
1320
|
else {
|
|
124
|
-
// Use full featured server for
|
|
1321
|
+
// Use full featured server for development/testing mode
|
|
125
1322
|
const server = await createMCPServer();
|
|
126
1323
|
const { logger, mcpServer, pluginManager, hookSystem, toolRegistry, steeringRegistry } = server;
|
|
127
1324
|
logger.info('MCP SDD Server starting...', {
|