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.
@@ -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
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
34
- analysis.name = packageJson.name || analysis.name;
35
- analysis.description = packageJson.description || analysis.description;
36
- analysis.version = packageJson.version || analysis.version;
37
- analysis.type = packageJson.type === 'module' ? 'ES Module' : 'CommonJS';
38
- analysis.dependencies = Object.keys(packageJson.dependencies || {});
39
- analysis.devDependencies = Object.keys(packageJson.devDependencies || {});
40
- analysis.scripts = packageJson.scripts || {};
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
- return features.length > 0 ? features : ['Core application functionality'];
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-mcp-server",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "MCP server for spec-driven development workflows across AI-agent CLIs and IDEs",
5
5
  "main": "dist/index.js",
6
6
  "bin": {