sdd-mcp-server 1.3.5 → 1.3.6
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/documentGenerator.js +214 -9
- package/mcp-server.js +34 -2
- package/package.json +1 -1
package/documentGenerator.js
CHANGED
|
@@ -26,18 +26,33 @@ export async function analyzeProject(projectPath) {
|
|
|
26
26
|
packageManager: 'npm'
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
console.log(`Analyzing project at: ${projectPath}`);
|
|
30
|
+
|
|
29
31
|
try {
|
|
30
32
|
// Check for package.json
|
|
31
33
|
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
32
34
|
if (fs.existsSync(packageJsonPath)) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
console.log('Found package.json, parsing...');
|
|
36
|
+
try {
|
|
37
|
+
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
|
|
38
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
39
|
+
|
|
40
|
+
// Extract project information with better fallbacks
|
|
41
|
+
analysis.name = packageJson.name || getDirectoryBasedName(projectPath);
|
|
42
|
+
analysis.description = packageJson.description || generateSmartDescription(analysis.name);
|
|
43
|
+
analysis.version = packageJson.version || '1.0.0';
|
|
44
|
+
analysis.type = packageJson.type === 'module' ? 'ES Module' : 'CommonJS';
|
|
45
|
+
analysis.dependencies = Object.keys(packageJson.dependencies || {});
|
|
46
|
+
analysis.devDependencies = Object.keys(packageJson.devDependencies || {});
|
|
47
|
+
analysis.scripts = packageJson.scripts || {};
|
|
48
|
+
|
|
49
|
+
console.log(`Extracted: name=${analysis.name}, deps=${analysis.dependencies.length}, devDeps=${analysis.devDependencies.length}`);
|
|
50
|
+
} catch (parseError) {
|
|
51
|
+
console.log('Error parsing package.json:', parseError.message);
|
|
52
|
+
// Use fallbacks if package.json is malformed
|
|
53
|
+
analysis.name = getDirectoryBasedName(projectPath);
|
|
54
|
+
analysis.description = generateSmartDescription(analysis.name);
|
|
55
|
+
}
|
|
41
56
|
|
|
42
57
|
// Detect framework
|
|
43
58
|
if (analysis.dependencies.includes('express') || analysis.devDependencies.includes('express')) {
|
|
@@ -87,6 +102,11 @@ export async function analyzeProject(projectPath) {
|
|
|
87
102
|
} else if (analysis.scripts.build?.includes('rollup')) {
|
|
88
103
|
analysis.buildTool = 'Rollup';
|
|
89
104
|
}
|
|
105
|
+
} else {
|
|
106
|
+
console.log('No package.json found, using directory-based fallbacks');
|
|
107
|
+
// No package.json found, use directory-based fallbacks
|
|
108
|
+
analysis.name = getDirectoryBasedName(projectPath);
|
|
109
|
+
analysis.description = generateSmartDescription(analysis.name);
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
// Check for Java/Maven/Gradle projects
|
|
@@ -193,8 +213,93 @@ export async function analyzeProject(projectPath) {
|
|
|
193
213
|
|
|
194
214
|
} catch (error) {
|
|
195
215
|
console.error('Error analyzing project:', error);
|
|
216
|
+
// Even if analysis fails, provide meaningful fallbacks
|
|
217
|
+
analysis.name = getDirectoryBasedName(projectPath);
|
|
218
|
+
analysis.description = generateSmartDescription(analysis.name);
|
|
196
219
|
}
|
|
197
220
|
|
|
221
|
+
// Validate and improve analysis results before returning
|
|
222
|
+
const finalAnalysis = validateAndImproveAnalysis(analysis, projectPath);
|
|
223
|
+
console.log(`Final analysis: ${finalAnalysis.name} - ${finalAnalysis.architecture}`);
|
|
224
|
+
|
|
225
|
+
return finalAnalysis;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Extract project name from directory path
|
|
230
|
+
*/
|
|
231
|
+
function getDirectoryBasedName(projectPath) {
|
|
232
|
+
const dirName = path.basename(projectPath);
|
|
233
|
+
// Convert kebab-case, snake_case to proper names
|
|
234
|
+
return dirName
|
|
235
|
+
.replace(/[-_]/g, ' ')
|
|
236
|
+
.split(' ')
|
|
237
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
238
|
+
.join(' ');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Generate smart description based on project name and structure
|
|
243
|
+
*/
|
|
244
|
+
function generateSmartDescription(projectName) {
|
|
245
|
+
const name = projectName.toLowerCase();
|
|
246
|
+
|
|
247
|
+
if (name.includes('api')) {
|
|
248
|
+
return `RESTful API service for ${projectName.replace(/api/i, '').trim()} application`;
|
|
249
|
+
}
|
|
250
|
+
if (name.includes('server')) {
|
|
251
|
+
return `Server application for ${projectName.replace(/server/i, '').trim()} services`;
|
|
252
|
+
}
|
|
253
|
+
if (name.includes('client')) {
|
|
254
|
+
return `Client application for ${projectName.replace(/client/i, '').trim()} interaction`;
|
|
255
|
+
}
|
|
256
|
+
if (name.includes('mcp')) {
|
|
257
|
+
return 'Model Context Protocol (MCP) server for AI tool integration';
|
|
258
|
+
}
|
|
259
|
+
if (name.includes('bot')) {
|
|
260
|
+
return `Bot application for automated ${projectName.replace(/bot/i, '').trim()} tasks`;
|
|
261
|
+
}
|
|
262
|
+
if (name.includes('web')) {
|
|
263
|
+
return `Web application for ${projectName.replace(/web/i, '').trim()} services`;
|
|
264
|
+
}
|
|
265
|
+
if (name.includes('tool')) {
|
|
266
|
+
return `Development tool for ${projectName.replace(/tool/i, '').trim()} workflows`;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return `${projectName} application providing core functionality and services`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Validate analysis results and improve them with smart fallbacks
|
|
274
|
+
*/
|
|
275
|
+
function validateAndImproveAnalysis(analysis, projectPath) {
|
|
276
|
+
// Improve architecture detection based on available information
|
|
277
|
+
if (analysis.architecture === 'unknown') {
|
|
278
|
+
if (analysis.dependencies.includes('@modelcontextprotocol/sdk')) {
|
|
279
|
+
analysis.architecture = 'Model Context Protocol Server';
|
|
280
|
+
} else if (analysis.dependencies.includes('express')) {
|
|
281
|
+
analysis.architecture = 'REST API Server';
|
|
282
|
+
} else if (analysis.dependencies.includes('react')) {
|
|
283
|
+
analysis.architecture = 'Frontend Application';
|
|
284
|
+
} else if (analysis.hasTests && analysis.directories.length > 3) {
|
|
285
|
+
analysis.architecture = 'Full-stack Application';
|
|
286
|
+
} else if (analysis.scripts.build) {
|
|
287
|
+
analysis.architecture = 'Build-based Application';
|
|
288
|
+
} else {
|
|
289
|
+
analysis.architecture = 'Node.js Application';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Ensure version is meaningful
|
|
294
|
+
if (analysis.version === '0.0.0' && analysis.dependencies.length > 0) {
|
|
295
|
+
analysis.version = '1.0.0';
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Ensure type is meaningful
|
|
299
|
+
if (analysis.type === 'unknown' && analysis.dependencies.length > 0) {
|
|
300
|
+
analysis.type = 'Application';
|
|
301
|
+
}
|
|
302
|
+
|
|
198
303
|
return analysis;
|
|
199
304
|
}
|
|
200
305
|
|
|
@@ -202,6 +307,12 @@ export async function analyzeProject(projectPath) {
|
|
|
202
307
|
* Generates dynamic product.md content based on project analysis
|
|
203
308
|
*/
|
|
204
309
|
export function generateProductDocument(analysis) {
|
|
310
|
+
// Validate analysis has meaningful content
|
|
311
|
+
if (isAnalysisGeneric(analysis)) {
|
|
312
|
+
console.log('Analysis appears generic, enhancing with intelligent defaults');
|
|
313
|
+
analysis = enhanceGenericAnalysis(analysis);
|
|
314
|
+
}
|
|
315
|
+
|
|
205
316
|
const features = extractFeatures(analysis);
|
|
206
317
|
const valueProps = generateValuePropositions(analysis);
|
|
207
318
|
const targetUsers = identifyTargetUsers(analysis);
|
|
@@ -235,6 +346,54 @@ ${generateTechnicalAdvantages(analysis).map(a => `- ${a}`).join('\n')}
|
|
|
235
346
|
`;
|
|
236
347
|
}
|
|
237
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Check if analysis contains only generic/default values
|
|
351
|
+
*/
|
|
352
|
+
function isAnalysisGeneric(analysis) {
|
|
353
|
+
return analysis.name === 'Unknown Project' ||
|
|
354
|
+
analysis.description === 'No description available' ||
|
|
355
|
+
analysis.version === '0.0.0' ||
|
|
356
|
+
analysis.architecture === 'unknown';
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Enhance generic analysis with intelligent defaults
|
|
361
|
+
*/
|
|
362
|
+
function enhanceGenericAnalysis(analysis) {
|
|
363
|
+
const enhanced = { ...analysis };
|
|
364
|
+
|
|
365
|
+
// If still using defaults, make educated guesses based on directory structure and files
|
|
366
|
+
if (enhanced.name === 'Unknown Project') {
|
|
367
|
+
enhanced.name = getDirectoryBasedName(process.cwd());
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (enhanced.description === 'No description available') {
|
|
371
|
+
enhanced.description = generateSmartDescription(enhanced.name);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (enhanced.version === '0.0.0') {
|
|
375
|
+
enhanced.version = '1.0.0';
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (enhanced.architecture === 'unknown') {
|
|
379
|
+
// Make intelligent architecture guesses
|
|
380
|
+
const name = enhanced.name.toLowerCase();
|
|
381
|
+
if (name.includes('server') || name.includes('api')) {
|
|
382
|
+
enhanced.architecture = 'Server Application';
|
|
383
|
+
} else if (name.includes('client') || name.includes('frontend')) {
|
|
384
|
+
enhanced.architecture = 'Frontend Application';
|
|
385
|
+
} else if (name.includes('mcp')) {
|
|
386
|
+
enhanced.architecture = 'Model Context Protocol Server';
|
|
387
|
+
} else if (enhanced.directories.includes('src')) {
|
|
388
|
+
enhanced.architecture = 'Source-based Application';
|
|
389
|
+
} else {
|
|
390
|
+
enhanced.architecture = 'Node.js Application';
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return enhanced;
|
|
395
|
+
}
|
|
396
|
+
|
|
238
397
|
/**
|
|
239
398
|
* Generates dynamic tech.md content based on project analysis
|
|
240
399
|
*/
|
|
@@ -350,7 +509,31 @@ function extractFeatures(analysis) {
|
|
|
350
509
|
features.push('Spec-driven development workflow');
|
|
351
510
|
}
|
|
352
511
|
|
|
353
|
-
|
|
512
|
+
// Ensure we always have meaningful features
|
|
513
|
+
if (features.length === 0) {
|
|
514
|
+
// Add intelligent default features based on project characteristics
|
|
515
|
+
features.push('Core application functionality');
|
|
516
|
+
|
|
517
|
+
if (analysis.architecture.includes('Server')) {
|
|
518
|
+
features.push('Server-side request processing');
|
|
519
|
+
features.push('API endpoint management');
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (analysis.architecture.includes('Frontend')) {
|
|
523
|
+
features.push('User interface components');
|
|
524
|
+
features.push('Client-side interaction handling');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (analysis.directories.includes('src')) {
|
|
528
|
+
features.push('Modular source code organization');
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (analysis.language === 'typescript' || analysis.language === 'javascript') {
|
|
532
|
+
features.push('JavaScript/Node.js runtime environment');
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return features;
|
|
354
537
|
}
|
|
355
538
|
|
|
356
539
|
function generateValuePropositions(analysis) {
|
|
@@ -384,6 +567,28 @@ function generateValuePropositions(analysis) {
|
|
|
384
567
|
});
|
|
385
568
|
}
|
|
386
569
|
|
|
570
|
+
// Ensure we always have meaningful value propositions
|
|
571
|
+
if (props.length === 0) {
|
|
572
|
+
props.push({
|
|
573
|
+
title: 'Development Efficiency',
|
|
574
|
+
description: 'Streamlined development process with modern tooling'
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
if (analysis.architecture.includes('Server')) {
|
|
578
|
+
props.push({
|
|
579
|
+
title: 'Scalable Architecture',
|
|
580
|
+
description: 'Server-based design supports multiple clients and scaling'
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (analysis.directories.includes('src')) {
|
|
585
|
+
props.push({
|
|
586
|
+
title: 'Maintainable Codebase',
|
|
587
|
+
description: 'Organized source structure facilitates long-term maintenance'
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
387
592
|
return props;
|
|
388
593
|
}
|
|
389
594
|
|
package/mcp-server.js
CHANGED
|
@@ -758,13 +758,32 @@ server.registerTool("sdd-steering", {
|
|
|
758
758
|
}
|
|
759
759
|
|
|
760
760
|
// Analyze project structure dynamically
|
|
761
|
+
console.log('Starting project analysis...');
|
|
761
762
|
const projectAnalysis = await analyzeProject(currentPath);
|
|
763
|
+
console.log('Project analysis completed:', {
|
|
764
|
+
name: projectAnalysis.name,
|
|
765
|
+
description: projectAnalysis.description?.substring(0, 50) + '...',
|
|
766
|
+
architecture: projectAnalysis.architecture,
|
|
767
|
+
deps: projectAnalysis.dependencies.length,
|
|
768
|
+
devDeps: projectAnalysis.devDependencies.length
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// Validate analysis results
|
|
772
|
+
if (isAnalysisInsufficient(projectAnalysis)) {
|
|
773
|
+
console.log('Analysis insufficient, applying fallback enhancements...');
|
|
774
|
+
// Apply additional fallback logic here if needed
|
|
775
|
+
}
|
|
762
776
|
|
|
763
777
|
// Generate dynamic documents based on actual project analysis
|
|
764
778
|
const productContent = generateProductDocument(projectAnalysis);
|
|
765
779
|
const techContent = generateTechDocument(projectAnalysis);
|
|
766
780
|
const structureContent = generateStructureDocument(projectAnalysis);
|
|
767
781
|
|
|
782
|
+
// Validate generated content before writing
|
|
783
|
+
if (contentContainsGenericPlaceholders(productContent)) {
|
|
784
|
+
console.log('Warning: Product document contains generic content');
|
|
785
|
+
}
|
|
786
|
+
|
|
768
787
|
// Write the dynamically generated documents
|
|
769
788
|
await fs.writeFile(path.join(steeringPath, 'product.md'), productContent);
|
|
770
789
|
await fs.writeFile(path.join(steeringPath, 'tech.md'), techContent);
|
|
@@ -800,7 +819,7 @@ server.registerTool("sdd-steering", {
|
|
|
800
819
|
- \`.kiro/steering/structure.md\` - Project organization and architectural decisions (dynamically generated)
|
|
801
820
|
|
|
802
821
|
**Dynamic Analysis Results**:
|
|
803
|
-
- **Language**: ${projectAnalysis.language === 'typescript' ? 'TypeScript' : 'JavaScript'}
|
|
822
|
+
- **Language**: ${projectAnalysis.language === 'typescript' ? 'TypeScript' : projectAnalysis.language === 'java' ? 'Java' : projectAnalysis.language === 'python' ? 'Python' : projectAnalysis.language === 'go' ? 'Go' : projectAnalysis.language === 'ruby' ? 'Ruby' : projectAnalysis.language === 'php' ? 'PHP' : projectAnalysis.language === 'rust' ? 'Rust' : projectAnalysis.language === 'csharp' ? 'C#' : projectAnalysis.language === 'scala' ? 'Scala' : 'JavaScript'}
|
|
804
823
|
- **Framework**: ${projectAnalysis.framework || 'None detected'}
|
|
805
824
|
- **Dependencies**: ${projectAnalysis.dependencies.length} production, ${projectAnalysis.devDependencies.length} development
|
|
806
825
|
- **Test Framework**: ${projectAnalysis.testFramework || 'None detected'}
|
|
@@ -809,7 +828,7 @@ server.registerTool("sdd-steering", {
|
|
|
809
828
|
- **CI/CD**: ${projectAnalysis.hasCI ? 'Configured' : 'Not configured'}
|
|
810
829
|
- **Docker**: ${projectAnalysis.hasDocker ? 'Configured' : 'Not configured'}
|
|
811
830
|
|
|
812
|
-
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions
|
|
831
|
+
These steering documents were dynamically generated based on actual project analysis and provide accurate, up-to-date context for AI interactions.${contentContainsGenericPlaceholders(productContent) ? '\n\n**Note**: Some content may be generic due to limited project metadata. Consider adding more descriptive information to package.json or project files.' : ''}`
|
|
813
832
|
}]
|
|
814
833
|
};
|
|
815
834
|
} catch (error) {
|
|
@@ -1432,4 +1451,17 @@ server.registerTool("sdd-spec-impl", {
|
|
|
1432
1451
|
});
|
|
1433
1452
|
|
|
1434
1453
|
const transport = new StdioServerTransport();
|
|
1454
|
+
// Helper functions for validation
|
|
1455
|
+
function isAnalysisInsufficient(analysis) {
|
|
1456
|
+
return analysis.name === 'Unknown Project' &&
|
|
1457
|
+
analysis.description === 'No description available' &&
|
|
1458
|
+
analysis.dependencies.length === 0;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
function contentContainsGenericPlaceholders(content) {
|
|
1462
|
+
return content.includes('Unknown Project') ||
|
|
1463
|
+
content.includes('No description available') ||
|
|
1464
|
+
content.includes('unknown');
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1435
1467
|
await server.connect(transport);
|