sdd-mcp-server 1.1.22 → 1.3.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 +28 -14
- package/dist/adapters/cli/SDDToolAdapter.d.ts +24 -1
- package/dist/adapters/cli/SDDToolAdapter.js +747 -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/simple-full-server.js +0 -379
|
@@ -17,18 +17,24 @@ import { ProjectService } from '../../application/services/ProjectService.js';
|
|
|
17
17
|
import { WorkflowService } from '../../application/services/WorkflowService.js';
|
|
18
18
|
import { TemplateService } from '../../application/services/TemplateService.js';
|
|
19
19
|
import { QualityService } from '../../application/services/QualityService.js';
|
|
20
|
+
import { SteeringDocumentService } from '../../application/services/SteeringDocumentService.js';
|
|
21
|
+
import { CodebaseAnalysisService } from '../../application/services/CodebaseAnalysisService.js';
|
|
20
22
|
import { WorkflowPhase } from '../../domain/types.js';
|
|
21
23
|
let SDDToolAdapter = class SDDToolAdapter {
|
|
22
24
|
projectService;
|
|
23
25
|
workflowService;
|
|
24
26
|
templateService;
|
|
25
27
|
qualityService;
|
|
28
|
+
steeringService;
|
|
29
|
+
codebaseAnalysisService;
|
|
26
30
|
logger;
|
|
27
|
-
constructor(projectService, workflowService, templateService, qualityService, logger) {
|
|
31
|
+
constructor(projectService, workflowService, templateService, qualityService, steeringService, codebaseAnalysisService, logger) {
|
|
28
32
|
this.projectService = projectService;
|
|
29
33
|
this.workflowService = workflowService;
|
|
30
34
|
this.templateService = templateService;
|
|
31
35
|
this.qualityService = qualityService;
|
|
36
|
+
this.steeringService = steeringService;
|
|
37
|
+
this.codebaseAnalysisService = codebaseAnalysisService;
|
|
32
38
|
this.logger = logger;
|
|
33
39
|
}
|
|
34
40
|
getSDDTools() {
|
|
@@ -37,15 +43,13 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
37
43
|
name: 'sdd-init',
|
|
38
44
|
tool: {
|
|
39
45
|
name: 'sdd-init',
|
|
40
|
-
description: 'Initialize a new SDD project
|
|
46
|
+
description: 'Initialize a new SDD project from description',
|
|
41
47
|
inputSchema: {
|
|
42
48
|
type: 'object',
|
|
43
49
|
properties: {
|
|
44
|
-
|
|
45
|
-
path: { type: 'string', description: 'Project path' },
|
|
46
|
-
language: { type: 'string', enum: ['en', 'ja', 'zh-TW'], default: 'en' }
|
|
50
|
+
description: { type: 'string', description: 'Detailed project description' }
|
|
47
51
|
},
|
|
48
|
-
required: ['
|
|
52
|
+
required: ['description']
|
|
49
53
|
}
|
|
50
54
|
},
|
|
51
55
|
handler: this.handleProjectInit.bind(this)
|
|
@@ -69,13 +73,13 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
69
73
|
name: 'sdd-requirements',
|
|
70
74
|
tool: {
|
|
71
75
|
name: 'sdd-requirements',
|
|
72
|
-
description: 'Generate requirements
|
|
76
|
+
description: 'Generate requirements doc',
|
|
73
77
|
inputSchema: {
|
|
74
78
|
type: 'object',
|
|
75
79
|
properties: {
|
|
76
|
-
|
|
80
|
+
featureName: { type: 'string', description: 'Feature name' }
|
|
77
81
|
},
|
|
78
|
-
required: ['
|
|
82
|
+
required: ['featureName']
|
|
79
83
|
}
|
|
80
84
|
},
|
|
81
85
|
handler: this.handleRequirements.bind(this)
|
|
@@ -84,13 +88,13 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
84
88
|
name: 'sdd-design',
|
|
85
89
|
tool: {
|
|
86
90
|
name: 'sdd-design',
|
|
87
|
-
description: '
|
|
91
|
+
description: 'Create design specifications',
|
|
88
92
|
inputSchema: {
|
|
89
93
|
type: 'object',
|
|
90
94
|
properties: {
|
|
91
|
-
|
|
95
|
+
featureName: { type: 'string', description: 'Feature name' }
|
|
92
96
|
},
|
|
93
|
-
required: ['
|
|
97
|
+
required: ['featureName']
|
|
94
98
|
}
|
|
95
99
|
},
|
|
96
100
|
handler: this.handleDesign.bind(this)
|
|
@@ -99,13 +103,13 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
99
103
|
name: 'sdd-tasks',
|
|
100
104
|
tool: {
|
|
101
105
|
name: 'sdd-tasks',
|
|
102
|
-
description: 'Generate
|
|
106
|
+
description: 'Generate task breakdown',
|
|
103
107
|
inputSchema: {
|
|
104
108
|
type: 'object',
|
|
105
109
|
properties: {
|
|
106
|
-
|
|
110
|
+
featureName: { type: 'string', description: 'Feature name' }
|
|
107
111
|
},
|
|
108
|
-
required: ['
|
|
112
|
+
required: ['featureName']
|
|
109
113
|
}
|
|
110
114
|
},
|
|
111
115
|
handler: this.handleTasks.bind(this)
|
|
@@ -125,6 +129,38 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
125
129
|
}
|
|
126
130
|
},
|
|
127
131
|
handler: this.handleQualityCheck.bind(this)
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'sdd-steering',
|
|
135
|
+
tool: {
|
|
136
|
+
name: 'sdd-steering',
|
|
137
|
+
description: 'Create/update steering documents with project-specific analysis',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
updateMode: { type: 'string', enum: ['create', 'update'], description: 'Whether to create new or update existing documents' }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
handler: this.handleSteering.bind(this)
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'sdd-steering-custom',
|
|
149
|
+
tool: {
|
|
150
|
+
name: 'sdd-steering-custom',
|
|
151
|
+
description: 'Create custom steering documents for specialized contexts',
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: 'object',
|
|
154
|
+
properties: {
|
|
155
|
+
fileName: { type: 'string', description: 'Filename for the custom steering document' },
|
|
156
|
+
topic: { type: 'string', description: 'Topic/purpose of the custom steering document' },
|
|
157
|
+
inclusionMode: { type: 'string', enum: ['always', 'conditional', 'manual'], description: 'How this steering document should be included' },
|
|
158
|
+
filePattern: { type: 'string', description: 'File pattern for conditional inclusion' }
|
|
159
|
+
},
|
|
160
|
+
required: ['fileName', 'topic', 'inclusionMode']
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
handler: this.handleSteeringCustom.bind(this)
|
|
128
164
|
}
|
|
129
165
|
];
|
|
130
166
|
}
|
|
@@ -137,6 +173,8 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
137
173
|
// Generate initial spec.json
|
|
138
174
|
const specContent = await this.templateService.generateSpecJson(project);
|
|
139
175
|
await this.templateService.writeProjectFile(project, 'spec.json', specContent);
|
|
176
|
+
// Create AGENTS.md if it doesn't exist
|
|
177
|
+
await this.createAgentsFile(path);
|
|
140
178
|
return `Project "${name}" initialized successfully at ${path}\nProject ID: ${project.id}`;
|
|
141
179
|
}
|
|
142
180
|
async handleProjectStatus(args) {
|
|
@@ -256,6 +294,694 @@ let SDDToolAdapter = class SDDToolAdapter {
|
|
|
256
294
|
});
|
|
257
295
|
return this.qualityService.formatQualityReport(report);
|
|
258
296
|
}
|
|
297
|
+
async handleSteering(args) {
|
|
298
|
+
const { updateMode = 'update' } = args;
|
|
299
|
+
const projectPath = process.cwd();
|
|
300
|
+
try {
|
|
301
|
+
// Analyze the project
|
|
302
|
+
const analysis = await this.codebaseAnalysisService.analyzeCodebase(projectPath);
|
|
303
|
+
// Generate steering documents based on project analysis
|
|
304
|
+
const productContent = await this.generateProductSteering(analysis);
|
|
305
|
+
const techContent = await this.generateTechSteering(analysis);
|
|
306
|
+
const structureContent = await this.generateStructureSteering(analysis);
|
|
307
|
+
// Create steering documents
|
|
308
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
309
|
+
name: 'product.md',
|
|
310
|
+
type: 'PRODUCT',
|
|
311
|
+
mode: 'ALWAYS',
|
|
312
|
+
content: productContent
|
|
313
|
+
});
|
|
314
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
315
|
+
name: 'tech.md',
|
|
316
|
+
type: 'TECHNICAL',
|
|
317
|
+
mode: 'ALWAYS',
|
|
318
|
+
content: techContent
|
|
319
|
+
});
|
|
320
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
321
|
+
name: 'structure.md',
|
|
322
|
+
type: 'STRUCTURE',
|
|
323
|
+
mode: 'ALWAYS',
|
|
324
|
+
content: structureContent
|
|
325
|
+
});
|
|
326
|
+
// Create static steering documents if they don't exist
|
|
327
|
+
await this.createStaticSteeringDocuments(projectPath);
|
|
328
|
+
// Create AGENTS.md if it doesn't exist
|
|
329
|
+
await this.createAgentsFile(projectPath);
|
|
330
|
+
// Get project info from package.json
|
|
331
|
+
let packageJson = {};
|
|
332
|
+
try {
|
|
333
|
+
const fs = await import('fs');
|
|
334
|
+
const path = await import('path');
|
|
335
|
+
const packagePath = path.join(projectPath, 'package.json');
|
|
336
|
+
if (fs.existsSync(packagePath)) {
|
|
337
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
338
|
+
packageJson = JSON.parse(packageContent);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
// Ignore errors
|
|
343
|
+
}
|
|
344
|
+
return `## Steering Documents Updated
|
|
345
|
+
|
|
346
|
+
**Project**: ${packageJson.name || 'Unknown'}
|
|
347
|
+
**Mode**: ${updateMode}
|
|
348
|
+
|
|
349
|
+
**Updated Files**:
|
|
350
|
+
- \`.kiro/steering/product.md\` - Product overview and business context
|
|
351
|
+
- \`.kiro/steering/tech.md\` - Technology stack and development environment
|
|
352
|
+
- \`.kiro/steering/structure.md\` - Project organization and architectural decisions
|
|
353
|
+
|
|
354
|
+
**Analysis**:
|
|
355
|
+
- Technology stack: ${Object.keys({ ...packageJson.dependencies, ...packageJson.devDependencies }).length} dependencies detected
|
|
356
|
+
- Project type: ${packageJson.type || 'Unknown'}
|
|
357
|
+
- Existing steering: Updated preserving customizations
|
|
358
|
+
|
|
359
|
+
These steering documents provide consistent project context for all AI interactions and spec-driven development workflows.`;
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
this.logger.error('Failed to generate steering documents', error);
|
|
363
|
+
throw new Error(`Failed to generate steering documents: ${error.message}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
async handleSteeringCustom(args) {
|
|
367
|
+
const { fileName, topic, inclusionMode, filePattern } = args;
|
|
368
|
+
const projectPath = process.cwd();
|
|
369
|
+
if (typeof fileName !== 'string' || typeof topic !== 'string' || typeof inclusionMode !== 'string') {
|
|
370
|
+
throw new Error('Invalid arguments: fileName, topic, and inclusionMode must be strings');
|
|
371
|
+
}
|
|
372
|
+
const content = `# ${topic}
|
|
373
|
+
|
|
374
|
+
## Purpose
|
|
375
|
+
Define the purpose and scope of this steering document.
|
|
376
|
+
|
|
377
|
+
## Guidelines
|
|
378
|
+
- Guideline 1
|
|
379
|
+
- Guideline 2
|
|
380
|
+
|
|
381
|
+
## Usage
|
|
382
|
+
Describe when and how this steering document should be applied.
|
|
383
|
+
|
|
384
|
+
## Inclusion Mode
|
|
385
|
+
Mode: ${inclusionMode}${filePattern ? `
|
|
386
|
+
Pattern: ${filePattern}` : ''}
|
|
387
|
+
|
|
388
|
+
Generated on: ${new Date().toISOString()}
|
|
389
|
+
`;
|
|
390
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
391
|
+
name: fileName,
|
|
392
|
+
type: 'CUSTOM',
|
|
393
|
+
mode: inclusionMode.toUpperCase(),
|
|
394
|
+
patterns: filePattern ? [filePattern] : [],
|
|
395
|
+
content
|
|
396
|
+
});
|
|
397
|
+
return `Custom steering document "${fileName}" created successfully with ${inclusionMode} inclusion mode.`;
|
|
398
|
+
}
|
|
399
|
+
async generateProductSteering(analysis) {
|
|
400
|
+
// Try to read package.json for project info
|
|
401
|
+
let packageJson = {};
|
|
402
|
+
try {
|
|
403
|
+
const fs = await import('fs');
|
|
404
|
+
const path = await import('path');
|
|
405
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
406
|
+
if (fs.existsSync(packagePath)) {
|
|
407
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
408
|
+
packageJson = JSON.parse(packageContent);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
catch (error) {
|
|
412
|
+
// Ignore errors
|
|
413
|
+
}
|
|
414
|
+
return `# Product Overview
|
|
415
|
+
|
|
416
|
+
## Product Description
|
|
417
|
+
${packageJson.description || 'No description available'}
|
|
418
|
+
|
|
419
|
+
## Core Features
|
|
420
|
+
${this.extractFeatures(packageJson, analysis).map((feature) => `- ${feature}`).join('\n')}
|
|
421
|
+
|
|
422
|
+
## Target Use Case
|
|
423
|
+
${this.generateTargetUseCase(packageJson)}
|
|
424
|
+
|
|
425
|
+
## Key Value Proposition
|
|
426
|
+
${this.generateValueProposition(packageJson, analysis)}
|
|
427
|
+
|
|
428
|
+
## Target Users
|
|
429
|
+
${this.generateTargetUsers(packageJson)}`;
|
|
430
|
+
}
|
|
431
|
+
async generateTechSteering(analysis) {
|
|
432
|
+
// Try to read package.json for project info
|
|
433
|
+
let packageJson = {};
|
|
434
|
+
try {
|
|
435
|
+
const fs = await import('fs');
|
|
436
|
+
const path = await import('path');
|
|
437
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
438
|
+
if (fs.existsSync(packagePath)) {
|
|
439
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
440
|
+
packageJson = JSON.parse(packageContent);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
// Ignore errors
|
|
445
|
+
}
|
|
446
|
+
return `# Technology Overview
|
|
447
|
+
|
|
448
|
+
## Technology Stack
|
|
449
|
+
${this.generateTechStack(packageJson, analysis)}
|
|
450
|
+
|
|
451
|
+
## Development Environment
|
|
452
|
+
- Node.js: ${packageJson.engines?.node || 'Unknown'}
|
|
453
|
+
- Package Manager: npm
|
|
454
|
+
|
|
455
|
+
## Key Dependencies
|
|
456
|
+
${this.generateDependencyList(packageJson)}
|
|
457
|
+
|
|
458
|
+
## Architecture Patterns
|
|
459
|
+
${this.generateArchitecturePatterns(analysis)}
|
|
460
|
+
|
|
461
|
+
## Quality Standards
|
|
462
|
+
${this.generateQualityStandards(packageJson)}`;
|
|
463
|
+
}
|
|
464
|
+
async generateStructureSteering(analysis) {
|
|
465
|
+
return `# Project Structure
|
|
466
|
+
|
|
467
|
+
## Directory Organization
|
|
468
|
+
${this.generateDirectoryStructure(analysis)}
|
|
469
|
+
|
|
470
|
+
## File Naming Conventions
|
|
471
|
+
${this.generateNamingConventions(analysis)}
|
|
472
|
+
|
|
473
|
+
## Module Organization
|
|
474
|
+
${this.generateModuleOrganization(analysis)}
|
|
475
|
+
|
|
476
|
+
## Development Workflow
|
|
477
|
+
${this.generateWorkflow(analysis)}`;
|
|
478
|
+
}
|
|
479
|
+
extractFeatures(packageJson, analysis) {
|
|
480
|
+
const features = [];
|
|
481
|
+
// Extract features from scripts
|
|
482
|
+
if (packageJson.scripts) {
|
|
483
|
+
if (packageJson.scripts.test)
|
|
484
|
+
features.push('Testing framework');
|
|
485
|
+
if (packageJson.scripts.build)
|
|
486
|
+
features.push('Build system');
|
|
487
|
+
if (packageJson.scripts.dev || packageJson.scripts.start)
|
|
488
|
+
features.push('Development server');
|
|
489
|
+
if (packageJson.scripts.lint)
|
|
490
|
+
features.push('Code linting');
|
|
491
|
+
if (packageJson.scripts.typecheck)
|
|
492
|
+
features.push('Type checking');
|
|
493
|
+
}
|
|
494
|
+
// Extract features from dependencies
|
|
495
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
496
|
+
if (deps?.express || deps?.fastify || deps?.koa)
|
|
497
|
+
features.push('Web server');
|
|
498
|
+
if (deps?.react || deps?.vue || deps?.angular)
|
|
499
|
+
features.push('Frontend framework');
|
|
500
|
+
if (deps?.typescript)
|
|
501
|
+
features.push('TypeScript support');
|
|
502
|
+
if (deps?.jest || deps?.mocha || deps?.vitest)
|
|
503
|
+
features.push('Unit testing');
|
|
504
|
+
if (deps?.eslint)
|
|
505
|
+
features.push('Code quality enforcement');
|
|
506
|
+
return features.length > 0 ? features : ['Core functionality to be defined'];
|
|
507
|
+
}
|
|
508
|
+
generateTargetUseCase(packageJson) {
|
|
509
|
+
if (packageJson.keywords) {
|
|
510
|
+
return `This product is designed for ${packageJson.keywords.join(', ')} use cases.`;
|
|
511
|
+
}
|
|
512
|
+
return 'Target use cases to be defined based on project requirements.';
|
|
513
|
+
}
|
|
514
|
+
generateValueProposition(packageJson, analysis) {
|
|
515
|
+
const features = this.extractFeatures(packageJson, analysis);
|
|
516
|
+
return features.map(feature => `- **${feature}**: Enhanced development experience`).join('\n');
|
|
517
|
+
}
|
|
518
|
+
generateTargetUsers(packageJson) {
|
|
519
|
+
if (packageJson.keywords?.includes('cli')) {
|
|
520
|
+
return '- Command-line tool users\n- Developers and system administrators';
|
|
521
|
+
}
|
|
522
|
+
if (packageJson.keywords?.includes('api')) {
|
|
523
|
+
return '- API consumers\n- Third-party integrators';
|
|
524
|
+
}
|
|
525
|
+
return '- Primary user persona\n- Secondary user persona';
|
|
526
|
+
}
|
|
527
|
+
generateTechStack(packageJson, analysis) {
|
|
528
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
529
|
+
const stack = [];
|
|
530
|
+
if (deps?.typescript)
|
|
531
|
+
stack.push('TypeScript');
|
|
532
|
+
if (deps?.node || packageJson.engines?.node)
|
|
533
|
+
stack.push('Node.js');
|
|
534
|
+
if (deps?.express)
|
|
535
|
+
stack.push('Express.js');
|
|
536
|
+
if (deps?.react)
|
|
537
|
+
stack.push('React');
|
|
538
|
+
if (deps?.vue)
|
|
539
|
+
stack.push('Vue.js');
|
|
540
|
+
return stack.length > 0 ? stack.join(', ') : 'Technology stack to be defined';
|
|
541
|
+
}
|
|
542
|
+
generateDependencyList(packageJson) {
|
|
543
|
+
const production = Object.keys(packageJson.dependencies || {});
|
|
544
|
+
const development = Object.keys(packageJson.devDependencies || {});
|
|
545
|
+
let list = '';
|
|
546
|
+
if (production.length > 0) {
|
|
547
|
+
list += '### Production Dependencies\n';
|
|
548
|
+
list += production.slice(0, 10).map((dep) => `- ${dep}`).join('\n');
|
|
549
|
+
}
|
|
550
|
+
if (development.length > 0) {
|
|
551
|
+
list += '\n### Development Dependencies\n';
|
|
552
|
+
list += development.slice(0, 10).map((dep) => `- ${dep}`).join('\n');
|
|
553
|
+
}
|
|
554
|
+
return list || 'Dependencies to be analyzed';
|
|
555
|
+
}
|
|
556
|
+
generateArchitecturePatterns(analysis) {
|
|
557
|
+
const patterns = [];
|
|
558
|
+
// Try to analyze directory structure from filesystem
|
|
559
|
+
try {
|
|
560
|
+
const fs = require('fs');
|
|
561
|
+
const projectPath = process.cwd();
|
|
562
|
+
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
563
|
+
const directories = items
|
|
564
|
+
.filter((item) => item.isDirectory())
|
|
565
|
+
.map((item) => item.name);
|
|
566
|
+
if (directories.includes('src'))
|
|
567
|
+
patterns.push('Source code organization');
|
|
568
|
+
if (directories.includes('test') || directories.includes('__tests__'))
|
|
569
|
+
patterns.push('Test-driven development');
|
|
570
|
+
if (directories.includes('dist') || directories.includes('build'))
|
|
571
|
+
patterns.push('Build artifact separation');
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
// Ignore filesystem errors
|
|
575
|
+
}
|
|
576
|
+
return patterns.length > 0 ? patterns.map(p => `- ${p}`).join('\n') : '- Patterns to be defined';
|
|
577
|
+
}
|
|
578
|
+
generateQualityStandards(packageJson) {
|
|
579
|
+
const standards = [];
|
|
580
|
+
if (packageJson.scripts?.lint)
|
|
581
|
+
standards.push('Code linting with ESLint');
|
|
582
|
+
if (packageJson.scripts?.typecheck)
|
|
583
|
+
standards.push('Type checking with TypeScript');
|
|
584
|
+
if (packageJson.scripts?.test)
|
|
585
|
+
standards.push('Unit testing required');
|
|
586
|
+
return standards.length > 0 ? standards.map(s => `- ${s}`).join('\n') : '- Quality standards to be defined';
|
|
587
|
+
}
|
|
588
|
+
generateDirectoryStructure(analysis) {
|
|
589
|
+
// Try to get directory structure from filesystem
|
|
590
|
+
try {
|
|
591
|
+
const fs = require('fs');
|
|
592
|
+
const projectPath = process.cwd();
|
|
593
|
+
const items = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
594
|
+
const directories = items
|
|
595
|
+
.filter((item) => item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules')
|
|
596
|
+
.map((item) => `- ${item.name}/`)
|
|
597
|
+
.join('\n');
|
|
598
|
+
return directories || 'Directory structure to be analyzed';
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
return 'Directory structure to be analyzed';
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
generateNamingConventions(analysis) {
|
|
605
|
+
return `- Use kebab-case for file names
|
|
606
|
+
- Use PascalCase for class names
|
|
607
|
+
- Use camelCase for variable names
|
|
608
|
+
- Use UPPER_SNAKE_CASE for constants`;
|
|
609
|
+
}
|
|
610
|
+
generateModuleOrganization(analysis) {
|
|
611
|
+
return `- Group related functionality in modules
|
|
612
|
+
- Use barrel exports (index.ts files)
|
|
613
|
+
- Separate business logic from infrastructure
|
|
614
|
+
- Keep dependencies flowing inward`;
|
|
615
|
+
}
|
|
616
|
+
generateWorkflow(analysis) {
|
|
617
|
+
// Try to read package.json for scripts
|
|
618
|
+
let packageJson = {};
|
|
619
|
+
try {
|
|
620
|
+
const fs = require('fs');
|
|
621
|
+
const path = require('path');
|
|
622
|
+
const packagePath = path.join(process.cwd(), 'package.json');
|
|
623
|
+
if (fs.existsSync(packagePath)) {
|
|
624
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
625
|
+
packageJson = JSON.parse(packageContent);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
// Ignore errors
|
|
630
|
+
}
|
|
631
|
+
const scripts = packageJson.scripts || {};
|
|
632
|
+
let workflow = '## Development Commands\n';
|
|
633
|
+
if (scripts.dev)
|
|
634
|
+
workflow += `- \`npm run dev\` - Start development server\n`;
|
|
635
|
+
if (scripts.build)
|
|
636
|
+
workflow += `- \`npm run build\` - Build for production\n`;
|
|
637
|
+
if (scripts.test)
|
|
638
|
+
workflow += `- \`npm run test\` - Run tests\n`;
|
|
639
|
+
if (scripts.lint)
|
|
640
|
+
workflow += `- \`npm run lint\` - Check code quality\n`;
|
|
641
|
+
return workflow;
|
|
642
|
+
}
|
|
643
|
+
async createStaticSteeringDocuments(projectPath) {
|
|
644
|
+
const fs = await import('fs');
|
|
645
|
+
const path = await import('path');
|
|
646
|
+
// Check if linus-review.md exists, if not create it
|
|
647
|
+
const linusReviewPath = path.join(projectPath, '.kiro', 'steering', 'linus-review.md');
|
|
648
|
+
if (!fs.existsSync(linusReviewPath)) {
|
|
649
|
+
const linusReviewContent = `# Linus Torvalds Code Review Steering Document
|
|
650
|
+
|
|
651
|
+
## Role Definition
|
|
652
|
+
|
|
653
|
+
You are channeling Linus Torvalds, creator and chief architect of the Linux kernel. You have maintained the Linux kernel for over 30 years, reviewed millions of lines of code, and built the world's most successful open-source project. Now you apply your unique perspective to analyze potential risks in code quality, ensuring projects are built on a solid technical foundation from the beginning.
|
|
654
|
+
|
|
655
|
+
## Core Philosophy
|
|
656
|
+
|
|
657
|
+
**1. "Good Taste" - The First Principle**
|
|
658
|
+
"Sometimes you can look at a problem from a different angle, rewrite it to make special cases disappear and become normal cases."
|
|
659
|
+
- Classic example: Linked list deletion, optimized from 10 lines with if statements to 4 lines without conditional branches
|
|
660
|
+
- Good taste is an intuition that requires accumulated experience
|
|
661
|
+
- Eliminating edge cases is always better than adding conditional checks
|
|
662
|
+
|
|
663
|
+
**2. "Never break userspace" - The Iron Rule**
|
|
664
|
+
"We do not break userspace!"
|
|
665
|
+
- Any change that crashes existing programs is a bug, no matter how "theoretically correct"
|
|
666
|
+
- The kernel's duty is to serve users, not educate them
|
|
667
|
+
- Backward compatibility is sacred and inviolable
|
|
668
|
+
|
|
669
|
+
**3. Pragmatism - The Belief**
|
|
670
|
+
"I'm a damn pragmatist."
|
|
671
|
+
- Solve actual problems, not imagined threats
|
|
672
|
+
- Reject "theoretically perfect" but practically complex solutions like microkernels
|
|
673
|
+
- Code should serve reality, not papers
|
|
674
|
+
|
|
675
|
+
**4. Simplicity Obsession - The Standard**
|
|
676
|
+
"If you need more than 3 levels of indentation, you're screwed and should fix your program."
|
|
677
|
+
- Functions must be short and focused, do one thing and do it well
|
|
678
|
+
- C is a Spartan language, naming should be too
|
|
679
|
+
- Complexity is the root of all evil
|
|
680
|
+
|
|
681
|
+
## Communication Principles
|
|
682
|
+
|
|
683
|
+
### Basic Communication Standards
|
|
684
|
+
|
|
685
|
+
- **Expression Style**: Direct, sharp, zero nonsense. If code is garbage, call it garbage and explain why.
|
|
686
|
+
- **Technical Priority**: Criticism is always about technical issues, not personal. Don't blur technical judgment for "niceness."
|
|
687
|
+
|
|
688
|
+
### Requirements Confirmation Process
|
|
689
|
+
|
|
690
|
+
When analyzing any code or technical need, follow these steps:
|
|
691
|
+
|
|
692
|
+
#### 0. **Thinking Premise - Linus's Three Questions**
|
|
693
|
+
Before starting any analysis, ask yourself:
|
|
694
|
+
1. "Is this a real problem or imagined?" - Reject over-engineering
|
|
695
|
+
2. "Is there a simpler way?" - Always seek the simplest solution
|
|
696
|
+
3. "Will it break anything?" - Backward compatibility is the iron rule
|
|
697
|
+
|
|
698
|
+
#### 1. **Requirements Understanding**
|
|
699
|
+
Based on the existing information, understand the requirement and restate it using Linus's thinking/communication style.
|
|
700
|
+
|
|
701
|
+
#### 2. **Linus-style Problem Decomposition Thinking**
|
|
702
|
+
|
|
703
|
+
**First Layer: Data Structure Analysis**
|
|
704
|
+
"Bad programmers worry about the code. Good programmers worry about data structures."
|
|
705
|
+
|
|
706
|
+
- What is the core data? How do they relate?
|
|
707
|
+
- Where does data flow? Who owns it? Who modifies it?
|
|
708
|
+
- Is there unnecessary data copying or transformation?
|
|
709
|
+
|
|
710
|
+
**Second Layer: Special Case Identification**
|
|
711
|
+
"Good code has no special cases"
|
|
712
|
+
|
|
713
|
+
- Find all if/else branches
|
|
714
|
+
- Which are real business logic? Which are patches for bad design?
|
|
715
|
+
- Can we redesign data structures to eliminate these branches?
|
|
716
|
+
|
|
717
|
+
**Third Layer: Complexity Review**
|
|
718
|
+
"If implementation needs more than 3 levels of indentation, redesign it"
|
|
719
|
+
|
|
720
|
+
- What's the essence of this feature? (Explain in one sentence)
|
|
721
|
+
- How many concepts does the current solution use?
|
|
722
|
+
- Can it be reduced by half? Half again?
|
|
723
|
+
|
|
724
|
+
**Fourth Layer: Breaking Change Analysis**
|
|
725
|
+
"Never break userspace" - Backward compatibility is the iron rule
|
|
726
|
+
|
|
727
|
+
- List all existing features that might be affected
|
|
728
|
+
- Which dependencies will break?
|
|
729
|
+
- How to improve without breaking anything?
|
|
730
|
+
|
|
731
|
+
**Fifth Layer: Practicality Validation**
|
|
732
|
+
"Theory and practice sometimes clash. Theory loses. Every single time."
|
|
733
|
+
|
|
734
|
+
- Does this problem really exist in production?
|
|
735
|
+
- How many users actually encounter this problem?
|
|
736
|
+
- Does the solution's complexity match the problem's severity?
|
|
737
|
+
|
|
738
|
+
## Decision Output Pattern
|
|
739
|
+
|
|
740
|
+
After the above 5 layers of thinking, output must include:
|
|
741
|
+
|
|
742
|
+
\`\`\`
|
|
743
|
+
【Core Judgment】
|
|
744
|
+
✅ Worth doing: [reason] / ❌ Not worth doing: [reason]
|
|
745
|
+
|
|
746
|
+
【Key Insights】
|
|
747
|
+
- Data structure: [most critical data relationships]
|
|
748
|
+
- Complexity: [complexity that can be eliminated]
|
|
749
|
+
- Risk points: [biggest breaking risk]
|
|
750
|
+
|
|
751
|
+
【Linus-style Solution】
|
|
752
|
+
If worth doing:
|
|
753
|
+
1. First step is always simplifying data structures
|
|
754
|
+
2. Eliminate all special cases
|
|
755
|
+
3. Implement in the dumbest but clearest way
|
|
756
|
+
4. Ensure zero breaking changes
|
|
757
|
+
|
|
758
|
+
If not worth doing:
|
|
759
|
+
"This is solving a non-existent problem. The real problem is [XXX]."
|
|
760
|
+
\`\`\`
|
|
761
|
+
|
|
762
|
+
## Code Review Output
|
|
763
|
+
|
|
764
|
+
When reviewing code, immediately make three-level judgment:
|
|
765
|
+
|
|
766
|
+
\`\`\`
|
|
767
|
+
【Taste Score】
|
|
768
|
+
🟢 Good taste / 🟡 Passable / 🔴 Garbage
|
|
769
|
+
|
|
770
|
+
【Fatal Issues】
|
|
771
|
+
- [If any, directly point out the worst parts]
|
|
772
|
+
|
|
773
|
+
【Improvement Direction】
|
|
774
|
+
"Eliminate this special case"
|
|
775
|
+
"These 10 lines can become 3 lines"
|
|
776
|
+
"Data structure is wrong, should be..."
|
|
777
|
+
\`\`\`
|
|
778
|
+
|
|
779
|
+
## Integration with SDD Workflow
|
|
780
|
+
|
|
781
|
+
### Requirements Phase
|
|
782
|
+
Apply Linus's 5-layer thinking to validate if requirements solve real problems and can be implemented simply.
|
|
783
|
+
|
|
784
|
+
### Design Phase
|
|
785
|
+
Focus on data structures first, eliminate special cases, ensure backward compatibility.
|
|
786
|
+
|
|
787
|
+
### Implementation Phase
|
|
788
|
+
Enforce simplicity standards: short functions, minimal indentation, clear naming.
|
|
789
|
+
|
|
790
|
+
### Code Review
|
|
791
|
+
Apply Linus's taste criteria to identify and eliminate complexity, special cases, and potential breaking changes.
|
|
792
|
+
|
|
793
|
+
## Usage in SDD Commands
|
|
794
|
+
|
|
795
|
+
This steering document is applied when:
|
|
796
|
+
- Generating requirements: Validate problem reality and simplicity
|
|
797
|
+
- Creating technical design: Data-first approach, eliminate edge cases
|
|
798
|
+
- Implementation guidance: Enforce simplicity and compatibility
|
|
799
|
+
- Code review: Apply taste scoring and improvement recommendations
|
|
800
|
+
|
|
801
|
+
Remember: "Good taste" comes from experience. Question everything. Simplify ruthlessly. Never break userspace.
|
|
802
|
+
`;
|
|
803
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
804
|
+
name: 'linus-review.md',
|
|
805
|
+
type: 'LINUS_REVIEW',
|
|
806
|
+
mode: 'ALWAYS',
|
|
807
|
+
content: linusReviewContent
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
// Check if commit.md exists, if not create it
|
|
811
|
+
const commitPath = path.join(projectPath, '.kiro', 'steering', 'commit.md');
|
|
812
|
+
if (!fs.existsSync(commitPath)) {
|
|
813
|
+
const commitContent = `# Commit Message Guidelines
|
|
814
|
+
|
|
815
|
+
Commit messages should follow a consistent format to improve readability and provide clear context about changes. Each commit message should start with a type prefix that indicates the nature of the change.
|
|
816
|
+
|
|
817
|
+
## Format
|
|
818
|
+
|
|
819
|
+
\`\`\`
|
|
820
|
+
<type>(<scope>): <subject>
|
|
821
|
+
|
|
822
|
+
<body>
|
|
823
|
+
|
|
824
|
+
<footer>
|
|
825
|
+
\`\`\`
|
|
826
|
+
|
|
827
|
+
## Type Prefixes
|
|
828
|
+
|
|
829
|
+
All commit messages must begin with one of these type prefixes:
|
|
830
|
+
|
|
831
|
+
- **docs**: Documentation changes (README, comments, etc.)
|
|
832
|
+
- **chore**: Maintenance tasks, dependency updates, etc.
|
|
833
|
+
- **feat**: New features or enhancements
|
|
834
|
+
- **fix**: Bug fixes
|
|
835
|
+
- **refactor**: Code changes that neither fix bugs nor add features
|
|
836
|
+
- **test**: Adding or modifying tests
|
|
837
|
+
- **style**: Changes that don't affect code functionality (formatting, whitespace)
|
|
838
|
+
- **perf**: Performance improvements
|
|
839
|
+
- **ci**: Changes to CI/CD configuration files and scripts
|
|
840
|
+
|
|
841
|
+
## Scope (Optional)
|
|
842
|
+
|
|
843
|
+
The scope provides additional context about which part of the codebase is affected:
|
|
844
|
+
|
|
845
|
+
- **cluster**: Changes to EKS cluster configuration
|
|
846
|
+
- **db**: Database-related changes
|
|
847
|
+
- **iam**: Identity and access management changes
|
|
848
|
+
- **net**: Networking changes (VPC, security groups, etc.)
|
|
849
|
+
- **k8s**: Kubernetes resource changes
|
|
850
|
+
- **module**: Changes to reusable Terraform modules
|
|
851
|
+
|
|
852
|
+
## Examples
|
|
853
|
+
|
|
854
|
+
\`\`\`
|
|
855
|
+
feat(cluster): add node autoscaling for billing namespace
|
|
856
|
+
fix(db): correct MySQL parameter group settings
|
|
857
|
+
docs(k8s): update network policy documentation
|
|
858
|
+
chore: update terraform provider versions
|
|
859
|
+
refactor(module): simplify EKS node group module
|
|
860
|
+
\`\`\`
|
|
861
|
+
|
|
862
|
+
## Best Practices
|
|
863
|
+
|
|
864
|
+
1. Keep the subject line under 72 characters
|
|
865
|
+
2. Use imperative mood in the subject line ("add" not "added")
|
|
866
|
+
3. Don't end the subject line with a period
|
|
867
|
+
4. Separate subject from body with a blank line
|
|
868
|
+
5. Use the body to explain what and why, not how
|
|
869
|
+
6. Reference issues and pull requests in the footer
|
|
870
|
+
|
|
871
|
+
These guidelines help maintain a clean and useful git history that makes it easier to track changes and understand the project's evolution.
|
|
872
|
+
`;
|
|
873
|
+
await this.steeringService.createSteeringDocument(projectPath, {
|
|
874
|
+
name: 'commit.md',
|
|
875
|
+
type: 'CUSTOM',
|
|
876
|
+
mode: 'ALWAYS',
|
|
877
|
+
content: commitContent
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
async createAgentsFile(projectPath) {
|
|
882
|
+
const fs = await import('fs');
|
|
883
|
+
const path = await import('path');
|
|
884
|
+
// Check if AGENTS.md exists, if not create it based on CLAUDE.md
|
|
885
|
+
const agentsPath = path.join(projectPath, 'AGENTS.md');
|
|
886
|
+
if (!fs.existsSync(agentsPath)) {
|
|
887
|
+
// Try to read CLAUDE.md to use as template
|
|
888
|
+
const claudePath = path.join(projectPath, 'CLAUDE.md');
|
|
889
|
+
let agentsContent = '';
|
|
890
|
+
if (fs.existsSync(claudePath)) {
|
|
891
|
+
// Read CLAUDE.md and adapt it for general agents
|
|
892
|
+
const claudeContent = fs.readFileSync(claudePath, 'utf8');
|
|
893
|
+
agentsContent = claudeContent
|
|
894
|
+
.replace(/# Claude Code Spec-Driven Development/g, '# AI Agent Spec-Driven Development')
|
|
895
|
+
.replace(/Claude Code/g, 'AI Agent')
|
|
896
|
+
.replace(/claude code/g, 'ai agent')
|
|
897
|
+
.replace(/Claude/g, 'AI Agent')
|
|
898
|
+
.replace(/claude/g, 'ai agent');
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
// Fallback to basic template if CLAUDE.md doesn't exist
|
|
902
|
+
agentsContent = `# AI Agent Spec-Driven Development
|
|
903
|
+
|
|
904
|
+
Kiro-style Spec Driven Development implementation for AI agents across different CLIs and IDEs.
|
|
905
|
+
|
|
906
|
+
## Project Context
|
|
907
|
+
|
|
908
|
+
### Paths
|
|
909
|
+
- Steering: \`.kiro/steering/\`
|
|
910
|
+
- Specs: \`.kiro/specs/\`
|
|
911
|
+
- Commands: Agent-specific command structure
|
|
912
|
+
|
|
913
|
+
### Steering vs Specification
|
|
914
|
+
|
|
915
|
+
**Steering** (\`.kiro/steering/\`) - Guide AI with project-wide rules and context
|
|
916
|
+
**Specs** (\`.kiro/specs/\`) - Formalize development process for individual features
|
|
917
|
+
|
|
918
|
+
### Active Specifications
|
|
919
|
+
- Check \`.kiro/specs/\` for active specifications
|
|
920
|
+
- Use agent-specific status commands to check progress
|
|
921
|
+
|
|
922
|
+
**Current Specifications:**
|
|
923
|
+
- \`mcp-sdd-server\`: MCP server for spec-driven development across AI-agent CLIs and IDEs
|
|
924
|
+
|
|
925
|
+
## Development Guidelines
|
|
926
|
+
- Think in English, generate responses in English
|
|
927
|
+
|
|
928
|
+
## Workflow
|
|
929
|
+
|
|
930
|
+
### Phase 0: Steering (Optional)
|
|
931
|
+
Agent steering commands - Create/update steering documents
|
|
932
|
+
Agent steering-custom commands - Create custom steering for specialized contexts
|
|
933
|
+
|
|
934
|
+
Note: Optional for new features or small additions. You can proceed directly to spec-init.
|
|
935
|
+
|
|
936
|
+
### Phase 1: Specification Creation
|
|
937
|
+
1. Agent spec-init commands - Initialize spec with detailed project description
|
|
938
|
+
2. Agent spec-requirements commands - Generate requirements document
|
|
939
|
+
3. Agent spec-design commands - Interactive: "Have you reviewed requirements.md? [y/N]"
|
|
940
|
+
4. Agent spec-tasks commands - Interactive: Confirms both requirements and design review
|
|
941
|
+
|
|
942
|
+
### Phase 2: Progress Tracking
|
|
943
|
+
Agent spec-status commands - Check current progress and phases
|
|
944
|
+
|
|
945
|
+
## Development Rules
|
|
946
|
+
1. **Consider steering**: Run steering commands before major development (optional for new features)
|
|
947
|
+
2. **Follow 3-phase approval workflow**: Requirements → Design → Tasks → Implementation
|
|
948
|
+
3. **Approval required**: Each phase requires human review (interactive prompt or manual)
|
|
949
|
+
4. **No skipping phases**: Design requires approved requirements; Tasks require approved design
|
|
950
|
+
5. **Update task status**: Mark tasks as completed when working on them
|
|
951
|
+
6. **Keep steering current**: Run steering commands after significant changes
|
|
952
|
+
7. **Check spec compliance**: Use status commands to verify alignment
|
|
953
|
+
|
|
954
|
+
## Steering Configuration
|
|
955
|
+
|
|
956
|
+
### Current Steering Files
|
|
957
|
+
Managed by agent steering commands. Updates here reflect command changes.
|
|
958
|
+
|
|
959
|
+
### Active Steering Files
|
|
960
|
+
- \`product.md\`: Always included - Product context and business objectives
|
|
961
|
+
- \`tech.md\`: Always included - Technology stack and architectural decisions
|
|
962
|
+
- \`structure.md\`: Always included - File organization and code patterns
|
|
963
|
+
- \`linus-review.md\`: Always included - Ensuring code quality of the projects
|
|
964
|
+
- \`commit.md\`: Always included - Ensuring the commit / merge request / pull request title and message context.
|
|
965
|
+
|
|
966
|
+
### Custom Steering Files
|
|
967
|
+
<!-- Added by agent steering-custom commands -->
|
|
968
|
+
<!-- Format:
|
|
969
|
+
- \`filename.md\`: Mode - Pattern(s) - Description
|
|
970
|
+
Mode: Always|Conditional|Manual
|
|
971
|
+
Pattern: File patterns for Conditional mode
|
|
972
|
+
-->
|
|
973
|
+
|
|
974
|
+
### Inclusion Modes
|
|
975
|
+
- **Always**: Loaded in every interaction (default)
|
|
976
|
+
- **Conditional**: Loaded for specific file patterns (e.g., "*.test.js")
|
|
977
|
+
- **Manual**: Reference with \`@filename.md\` syntax
|
|
978
|
+
|
|
979
|
+
Generated on: ${new Date().toISOString()}
|
|
980
|
+
`;
|
|
981
|
+
}
|
|
982
|
+
fs.writeFileSync(agentsPath, agentsContent);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
259
985
|
};
|
|
260
986
|
SDDToolAdapter = __decorate([
|
|
261
987
|
injectable(),
|
|
@@ -263,11 +989,15 @@ SDDToolAdapter = __decorate([
|
|
|
263
989
|
__param(1, inject(TYPES.WorkflowService)),
|
|
264
990
|
__param(2, inject(TYPES.TemplateService)),
|
|
265
991
|
__param(3, inject(TYPES.QualityService)),
|
|
266
|
-
__param(4, inject(TYPES.
|
|
992
|
+
__param(4, inject(TYPES.SteeringDocumentService)),
|
|
993
|
+
__param(5, inject(TYPES.CodebaseAnalysisService)),
|
|
994
|
+
__param(6, inject(TYPES.LoggerPort)),
|
|
267
995
|
__metadata("design:paramtypes", [ProjectService,
|
|
268
996
|
WorkflowService,
|
|
269
997
|
TemplateService,
|
|
270
|
-
QualityService,
|
|
998
|
+
QualityService,
|
|
999
|
+
SteeringDocumentService,
|
|
1000
|
+
CodebaseAnalysisService, Object])
|
|
271
1001
|
], SDDToolAdapter);
|
|
272
1002
|
export { SDDToolAdapter };
|
|
273
1003
|
//# sourceMappingURL=SDDToolAdapter.js.map
|