sdd-mcp-server 1.3.4 → 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/dist/utils/documentGenerator.d.ts +1 -0
- package/dist/utils/documentGenerator.js +522 -28
- package/dist/utils/documentGenerator.js.map +1 -1
- package/documentGenerator.js +456 -53
- 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,61 @@ 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);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check for Java/Maven/Gradle projects
|
|
113
|
+
const pomPath = path.join(projectPath, 'pom.xml');
|
|
114
|
+
const gradlePath = path.join(projectPath, 'build.gradle');
|
|
115
|
+
const gradleKtsPath = path.join(projectPath, 'build.gradle.kts');
|
|
116
|
+
if (fs.existsSync(pomPath) || fs.existsSync(gradlePath) || fs.existsSync(gradleKtsPath)) {
|
|
117
|
+
analysis.language = 'java';
|
|
118
|
+
if (fs.existsSync(pomPath)) {
|
|
119
|
+
analysis.packageManager = 'maven';
|
|
120
|
+
analysis.buildTool = 'Maven';
|
|
121
|
+
try {
|
|
122
|
+
const pom = fs.readFileSync(pomPath, 'utf8');
|
|
123
|
+
if (/spring-boot/i.test(pom) || /org\.springframework\.boot/i.test(pom)) {
|
|
124
|
+
analysis.framework = 'Spring Boot';
|
|
125
|
+
analysis.architecture = 'Spring Boot Application';
|
|
126
|
+
}
|
|
127
|
+
// Detect modules in aggregator POM
|
|
128
|
+
const moduleMatches = pom.match(/<module>[^<]+<\/module>/g) || [];
|
|
129
|
+
if (moduleMatches.length > 1) {
|
|
130
|
+
analysis.architecture = 'Microservices (Spring Boot)';
|
|
131
|
+
}
|
|
132
|
+
if (/junit|jupiter/i.test(pom)) {
|
|
133
|
+
analysis.testFramework = 'JUnit';
|
|
134
|
+
analysis.hasTests = true;
|
|
135
|
+
}
|
|
136
|
+
} catch {}
|
|
137
|
+
} else {
|
|
138
|
+
analysis.packageManager = 'gradle';
|
|
139
|
+
analysis.buildTool = 'Gradle';
|
|
140
|
+
try {
|
|
141
|
+
const gradle = fs.readFileSync(fs.existsSync(gradlePath) ? gradlePath : gradleKtsPath, 'utf8');
|
|
142
|
+
if (/org\.springframework\.boot|spring-boot/i.test(gradle)) {
|
|
143
|
+
analysis.framework = 'Spring Boot';
|
|
144
|
+
analysis.architecture = 'Spring Boot Application';
|
|
145
|
+
}
|
|
146
|
+
if (/subprojects\s*\{|include\s+\(/i.test(gradle)) {
|
|
147
|
+
analysis.architecture = 'Microservices (Spring Boot)';
|
|
148
|
+
}
|
|
149
|
+
if (/junit|jupiter|testImplementation\s+['"]org\.junit/i.test(gradle)) {
|
|
150
|
+
analysis.testFramework = 'JUnit';
|
|
151
|
+
analysis.hasTests = true;
|
|
152
|
+
}
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
155
|
+
// Detect conventional test dirs
|
|
156
|
+
if (fs.existsSync(path.join(projectPath, 'src', 'test', 'java'))) {
|
|
157
|
+
analysis.hasTests = true;
|
|
158
|
+
if (!analysis.testFramework) analysis.testFramework = 'JUnit';
|
|
159
|
+
}
|
|
90
160
|
}
|
|
91
161
|
|
|
92
162
|
// Check for yarn or pnpm
|
|
@@ -143,8 +213,93 @@ export async function analyzeProject(projectPath) {
|
|
|
143
213
|
|
|
144
214
|
} catch (error) {
|
|
145
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);
|
|
146
219
|
}
|
|
147
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
|
+
|
|
148
303
|
return analysis;
|
|
149
304
|
}
|
|
150
305
|
|
|
@@ -152,6 +307,12 @@ export async function analyzeProject(projectPath) {
|
|
|
152
307
|
* Generates dynamic product.md content based on project analysis
|
|
153
308
|
*/
|
|
154
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
|
+
|
|
155
316
|
const features = extractFeatures(analysis);
|
|
156
317
|
const valueProps = generateValuePropositions(analysis);
|
|
157
318
|
const targetUsers = identifyTargetUsers(analysis);
|
|
@@ -185,6 +346,54 @@ ${generateTechnicalAdvantages(analysis).map(a => `- ${a}`).join('\n')}
|
|
|
185
346
|
`;
|
|
186
347
|
}
|
|
187
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
|
+
|
|
188
397
|
/**
|
|
189
398
|
* Generates dynamic tech.md content based on project analysis
|
|
190
399
|
*/
|
|
@@ -197,8 +406,8 @@ export function generateTechDocument(analysis) {
|
|
|
197
406
|
|
|
198
407
|
## Architecture
|
|
199
408
|
**Type**: ${analysis.architecture}
|
|
200
|
-
**Language**: ${analysis.language === 'typescript' ? 'TypeScript' : 'JavaScript'}
|
|
201
|
-
|
|
409
|
+
**Language**: ${analysis.language === 'typescript' ? 'TypeScript' : analysis.language === 'java' ? 'Java' : analysis.language === 'python' ? 'Python' : analysis.language === 'go' ? 'Go' : analysis.language === 'ruby' ? 'Ruby' : analysis.language === 'php' ? 'PHP' : analysis.language === 'rust' ? 'Rust' : analysis.language === 'csharp' ? 'C#' : analysis.language === 'scala' ? 'Scala' : 'JavaScript'}
|
|
410
|
+
${(analysis.language === 'javascript' || analysis.language === 'typescript') ? `**Module System**: ${analysis.type} ` : ''}
|
|
202
411
|
${analysis.framework ? `**Framework**: ${analysis.framework}` : ''}
|
|
203
412
|
${analysis.buildTool ? `**Build Tool**: ${analysis.buildTool}` : ''}
|
|
204
413
|
|
|
@@ -208,9 +417,8 @@ ${architecture}
|
|
|
208
417
|
${techStack.map(t => `- **${t.name}**: ${t.description}`).join('\n')}
|
|
209
418
|
|
|
210
419
|
## Development Environment
|
|
211
|
-
|
|
212
|
-
- **
|
|
213
|
-
- **Language**: ${analysis.language === 'typescript' ? 'TypeScript with type safety' : 'JavaScript'}
|
|
420
|
+
${analysis.language === 'java' ? `- **JDK**: ${getJavaVersion(projectPathFromCwd())}\n` : analysis.language === 'go' ? `- **Go**: ${getGoVersion(projectPathFromCwd())}\n` : analysis.language === 'python' ? `- **Python**: ${getPythonVersion(projectPathFromCwd())}\n` : analysis.language === 'ruby' ? `- **Ruby**: ${getRubyVersion(projectPathFromCwd())}\n` : analysis.language === 'php' ? `- **PHP**: ${getPhpVersion(projectPathFromCwd())}\n` : analysis.language === 'rust' ? `- **Rust**: ${getRustToolchain(projectPathFromCwd())}\n` : analysis.language === 'csharp' ? `- **.NET SDK**: ${getDotnetTarget(projectPathFromCwd())}\n` : `- **Node Version**: ${getNodeVersion()}\n`}- **Package Manager/Build**: ${analysis.packageManager}
|
|
421
|
+
- **Language**: ${analysis.language === 'typescript' ? 'TypeScript with type safety' : analysis.language ? analysis.language[0].toUpperCase() + analysis.language.slice(1) : 'JavaScript'}
|
|
214
422
|
${analysis.testFramework ? `- **Testing**: ${analysis.testFramework}` : ''}
|
|
215
423
|
|
|
216
424
|
## Dependencies Analysis
|
|
@@ -301,7 +509,31 @@ function extractFeatures(analysis) {
|
|
|
301
509
|
features.push('Spec-driven development workflow');
|
|
302
510
|
}
|
|
303
511
|
|
|
304
|
-
|
|
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;
|
|
305
537
|
}
|
|
306
538
|
|
|
307
539
|
function generateValuePropositions(analysis) {
|
|
@@ -335,6 +567,28 @@ function generateValuePropositions(analysis) {
|
|
|
335
567
|
});
|
|
336
568
|
}
|
|
337
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
|
+
|
|
338
592
|
return props;
|
|
339
593
|
}
|
|
340
594
|
|
|
@@ -416,27 +670,25 @@ function generateTechnicalAdvantages(analysis) {
|
|
|
416
670
|
|
|
417
671
|
function buildTechStack(analysis) {
|
|
418
672
|
const stack = [];
|
|
419
|
-
|
|
420
673
|
// Core runtime
|
|
421
|
-
stack.push({
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
|
|
674
|
+
if (analysis.language === 'java') stack.push({ name: 'Java', description: 'JDK runtime for backend services' });
|
|
675
|
+
else if (analysis.language === 'python') stack.push({ name: 'Python', description: 'Python runtime for applications and APIs' });
|
|
676
|
+
else if (analysis.language === 'go') stack.push({ name: 'Go', description: 'Go toolchain for building static binaries' });
|
|
677
|
+
else if (analysis.language === 'ruby') stack.push({ name: 'Ruby', description: 'Ruby runtime for web applications' });
|
|
678
|
+
else if (analysis.language === 'php') stack.push({ name: 'PHP', description: 'PHP runtime for web applications' });
|
|
679
|
+
else if (analysis.language === 'rust') stack.push({ name: 'Rust', description: 'Rust toolchain for systems and APIs' });
|
|
680
|
+
else if (analysis.language === 'csharp') stack.push({ name: 'C#/.NET', description: '.NET runtime and SDK' });
|
|
681
|
+
else if (analysis.language === 'scala') stack.push({ name: 'Scala', description: 'JVM language for backend systems' });
|
|
682
|
+
else stack.push({ name: 'Node.js', description: 'JavaScript runtime for server-side execution' });
|
|
683
|
+
|
|
684
|
+
// Language/Framework highlights
|
|
427
685
|
if (analysis.language === 'typescript') {
|
|
428
|
-
stack.push({
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
});
|
|
686
|
+
stack.push({ name: 'TypeScript', description: 'Typed superset of JavaScript for enhanced developer experience' });
|
|
687
|
+
} else if (analysis.language === 'java') {
|
|
688
|
+
stack.push({ name: 'Spring Boot', description: 'Opinionated framework for building production-ready services' });
|
|
432
689
|
}
|
|
433
|
-
|
|
434
|
-
// Framework
|
|
435
690
|
if (analysis.framework) {
|
|
436
|
-
stack.push({
|
|
437
|
-
name: analysis.framework,
|
|
438
|
-
description: getFrameworkDescription(analysis.framework)
|
|
439
|
-
});
|
|
691
|
+
stack.push({ name: analysis.framework, description: getFrameworkDescription(analysis.framework) });
|
|
440
692
|
}
|
|
441
693
|
|
|
442
694
|
// Testing
|
|
@@ -469,33 +721,79 @@ function buildTechStack(analysis) {
|
|
|
469
721
|
}
|
|
470
722
|
|
|
471
723
|
function extractDevCommands(analysis) {
|
|
472
|
-
if (Object.keys(analysis.scripts).length === 0) {
|
|
473
|
-
return 'No npm scripts defined';
|
|
474
|
-
}
|
|
475
|
-
|
|
476
724
|
let commands = '```bash\n';
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
commands +=
|
|
491
|
-
|
|
725
|
+
switch (analysis.language) {
|
|
726
|
+
case 'java':
|
|
727
|
+
if (analysis.packageManager === 'maven') {
|
|
728
|
+
commands += 'mvn clean install # Build project\n';
|
|
729
|
+
commands += 'mvn test # Run tests\n';
|
|
730
|
+
if (analysis.framework === 'Spring Boot') commands += 'mvn spring-boot:run # Run application\n';
|
|
731
|
+
} else {
|
|
732
|
+
commands += 'gradle build # Build project\n';
|
|
733
|
+
commands += 'gradle test # Run tests\n';
|
|
734
|
+
if (analysis.framework === 'Spring Boot') commands += 'gradle bootRun # Run application\n';
|
|
735
|
+
}
|
|
736
|
+
break;
|
|
737
|
+
case 'python':
|
|
738
|
+
commands += 'pip install -r requirements.txt # Install deps\n';
|
|
739
|
+
commands += (analysis.framework === 'Django') ? 'python manage.py runserver # Run server\n' :
|
|
740
|
+
(analysis.framework === 'FastAPI' || analysis.framework === 'Flask') ? 'uvicorn app:app --reload # Run dev server\n' : '';
|
|
741
|
+
commands += 'pytest # Run tests\n';
|
|
742
|
+
break;
|
|
743
|
+
case 'go':
|
|
744
|
+
commands += 'go build ./... # Build\n';
|
|
745
|
+
commands += 'go test ./... # Tests\n';
|
|
746
|
+
commands += 'go run ./cmd/... # Run (example)\n';
|
|
747
|
+
break;
|
|
748
|
+
case 'ruby':
|
|
749
|
+
commands += 'bundle install # Install deps\n';
|
|
750
|
+
commands += (analysis.framework === 'Rails') ? 'rails server # Run server\n' : '';
|
|
751
|
+
commands += (analysis.testFramework === 'RSpec') ? 'rspec # Run tests\n' : 'rake test # Run tests\n';
|
|
752
|
+
break;
|
|
753
|
+
case 'php':
|
|
754
|
+
commands += 'composer install # Install deps\n';
|
|
755
|
+
commands += (analysis.framework === 'Laravel') ? 'php artisan serve # Run server\n' : '';
|
|
756
|
+
commands += 'vendor/bin/phpunit # Run tests\n';
|
|
757
|
+
break;
|
|
758
|
+
case 'rust':
|
|
759
|
+
commands += 'cargo build # Build\n';
|
|
760
|
+
commands += 'cargo test # Tests\n';
|
|
761
|
+
commands += 'cargo run # Run\n';
|
|
762
|
+
break;
|
|
763
|
+
case 'csharp':
|
|
764
|
+
commands += 'dotnet build # Build\n';
|
|
765
|
+
commands += 'dotnet test # Tests\n';
|
|
766
|
+
commands += 'dotnet run # Run\n';
|
|
767
|
+
break;
|
|
768
|
+
case 'scala':
|
|
769
|
+
commands += 'sbt compile # Build\n';
|
|
770
|
+
commands += 'sbt test # Tests\n';
|
|
771
|
+
commands += 'sbt run # Run\n';
|
|
772
|
+
break;
|
|
773
|
+
default:
|
|
774
|
+
if (Object.keys(analysis.scripts).length === 0) return 'No npm scripts defined';
|
|
775
|
+
const order = ['dev', 'start', 'build', 'test', 'lint', 'typecheck', 'coverage'];
|
|
776
|
+
for (const cmd of order) {
|
|
777
|
+
if (analysis.scripts[cmd]) commands += `${analysis.packageManager} run ${cmd} # ${describeCommand(cmd, analysis.scripts[cmd])}\n`;
|
|
778
|
+
}
|
|
779
|
+
for (const [cmd, script] of Object.entries(analysis.scripts)) {
|
|
780
|
+
if (!order.includes(cmd)) commands += `${analysis.packageManager} run ${cmd} # ${script.substring(0, 50)}${script.length > 50 ? '...' : ''}\n`;
|
|
781
|
+
}
|
|
492
782
|
}
|
|
493
|
-
|
|
494
783
|
commands += '```';
|
|
495
784
|
return commands;
|
|
496
785
|
}
|
|
497
786
|
|
|
498
787
|
function describeArchitecture(analysis) {
|
|
788
|
+
if (analysis.architecture.includes('Spring Boot')) {
|
|
789
|
+
return `
|
|
790
|
+
### Spring Boot Service Architecture
|
|
791
|
+
The project uses Spring Boot conventions:
|
|
792
|
+
- **Configuration**: application.yml/properties per service
|
|
793
|
+
- **Layers**: Controller → Service → Repository
|
|
794
|
+
- **Build**: ${analysis.buildTool || 'Maven/Gradle'} with ${analysis.testFramework || 'JUnit'} tests
|
|
795
|
+
${analysis.architecture.includes('Microservices') ? '- **Topology**: Multiple modules/services (microservices)\n' : ''}`;
|
|
796
|
+
}
|
|
499
797
|
if (analysis.architecture === 'Domain-Driven Design (DDD)') {
|
|
500
798
|
return `
|
|
501
799
|
### Domain-Driven Design Architecture
|
|
@@ -647,7 +945,15 @@ function buildDirectoryTree(analysis) {
|
|
|
647
945
|
tree += `├── Dockerfile # Container configuration\n`;
|
|
648
946
|
}
|
|
649
947
|
|
|
650
|
-
tree += `├──
|
|
948
|
+
if (analysis.language === 'java') tree += `├── pom.xml or build.gradle # Build configuration\n`;
|
|
949
|
+
else if (analysis.language === 'python') tree += `├── pyproject.toml / requirements.txt # Python config\n`;
|
|
950
|
+
else if (analysis.language === 'go') tree += `├── go.mod # Go modules\n`;
|
|
951
|
+
else if (analysis.language === 'ruby') tree += `├── Gemfile # Ruby dependencies\n`;
|
|
952
|
+
else if (analysis.language === 'php') tree += `├── composer.json # PHP dependencies\n`;
|
|
953
|
+
else if (analysis.language === 'rust') tree += `├── Cargo.toml # Rust package config\n`;
|
|
954
|
+
else if (analysis.language === 'csharp') tree += `├── *.csproj # .NET project file\n`;
|
|
955
|
+
else if (analysis.language === 'scala') tree += `├── build.sbt # SBT build\n`;
|
|
956
|
+
else tree += `├── package.json # Project configuration\n`;
|
|
651
957
|
|
|
652
958
|
if (analysis.language === 'typescript') {
|
|
653
959
|
tree += `├── tsconfig.json # TypeScript configuration\n`;
|
|
@@ -929,4 +1235,101 @@ function getNodeVersion() {
|
|
|
929
1235
|
// Ignore
|
|
930
1236
|
}
|
|
931
1237
|
return '>= 18.0.0';
|
|
932
|
-
}
|
|
1238
|
+
}
|
|
1239
|
+
function getGoVersion(projectPath) {
|
|
1240
|
+
try {
|
|
1241
|
+
const gomod = path.join(projectPath, 'go.mod');
|
|
1242
|
+
if (fs.existsSync(gomod)) {
|
|
1243
|
+
const content = fs.readFileSync(gomod, 'utf8');
|
|
1244
|
+
const m = content.match(/^go\s+([0-9.]+)/m);
|
|
1245
|
+
if (m) return `Go ${m[1]}`;
|
|
1246
|
+
}
|
|
1247
|
+
} catch {}
|
|
1248
|
+
return 'Go (version unknown)';
|
|
1249
|
+
}
|
|
1250
|
+
function getPythonVersion(projectPath) {
|
|
1251
|
+
try {
|
|
1252
|
+
const pyproject = path.join(projectPath, 'pyproject.toml');
|
|
1253
|
+
if (fs.existsSync(pyproject)) {
|
|
1254
|
+
const txt = fs.readFileSync(pyproject, 'utf8');
|
|
1255
|
+
const m = txt.match(/python\s*[=><~!]*\s*['"]([^'"]+)['"]/i);
|
|
1256
|
+
if (m) return `Python ${m[1]}`;
|
|
1257
|
+
}
|
|
1258
|
+
const vfile = path.join(projectPath, '.python-version');
|
|
1259
|
+
if (fs.existsSync(vfile)) {
|
|
1260
|
+
return `Python ${fs.readFileSync(vfile, 'utf8').trim()}`;
|
|
1261
|
+
}
|
|
1262
|
+
} catch {}
|
|
1263
|
+
return 'Python (version unknown)';
|
|
1264
|
+
}
|
|
1265
|
+
function getRubyVersion(projectPath) {
|
|
1266
|
+
try {
|
|
1267
|
+
const rv = path.join(projectPath, '.ruby-version');
|
|
1268
|
+
if (fs.existsSync(rv)) return `Ruby ${fs.readFileSync(rv, 'utf8').trim()}`;
|
|
1269
|
+
const gem = path.join(projectPath, 'Gemfile');
|
|
1270
|
+
if (fs.existsSync(gem)) {
|
|
1271
|
+
const txt = fs.readFileSync(gem, 'utf8');
|
|
1272
|
+
const m = txt.match(/ruby\s+['"]([^'"]+)['"]/i);
|
|
1273
|
+
if (m) return `Ruby ${m[1]}`;
|
|
1274
|
+
}
|
|
1275
|
+
} catch {}
|
|
1276
|
+
return 'Ruby (version unknown)';
|
|
1277
|
+
}
|
|
1278
|
+
function getPhpVersion(projectPath) {
|
|
1279
|
+
try {
|
|
1280
|
+
const composer = path.join(projectPath, 'composer.json');
|
|
1281
|
+
if (fs.existsSync(composer)) {
|
|
1282
|
+
const pkg = JSON.parse(fs.readFileSync(composer, 'utf8'));
|
|
1283
|
+
const req = pkg.require || {};
|
|
1284
|
+
if (req.php) return `PHP ${req.php}`;
|
|
1285
|
+
}
|
|
1286
|
+
} catch {}
|
|
1287
|
+
return 'PHP (version unknown)';
|
|
1288
|
+
}
|
|
1289
|
+
function getRustToolchain(projectPath) {
|
|
1290
|
+
try {
|
|
1291
|
+
const tool = path.join(projectPath, 'rust-toolchain');
|
|
1292
|
+
if (fs.existsSync(tool)) return `Rust ${fs.readFileSync(tool, 'utf8').trim()}`;
|
|
1293
|
+
const cargo = path.join(projectPath, 'Cargo.toml');
|
|
1294
|
+
if (fs.existsSync(cargo)) {
|
|
1295
|
+
const txt = fs.readFileSync(cargo, 'utf8');
|
|
1296
|
+
const m = txt.match(/edition\s*=\s*"(\d{4})"/);
|
|
1297
|
+
if (m) return `Rust (edition ${m[1]})`;
|
|
1298
|
+
}
|
|
1299
|
+
} catch {}
|
|
1300
|
+
return 'Rust (toolchain unknown)';
|
|
1301
|
+
}
|
|
1302
|
+
function getDotnetTarget(projectPath) {
|
|
1303
|
+
try {
|
|
1304
|
+
const files = fs.readdirSync(projectPath).filter(f => f.endsWith('.csproj'));
|
|
1305
|
+
for (const f of files) {
|
|
1306
|
+
const txt = fs.readFileSync(path.join(projectPath, f), 'utf8');
|
|
1307
|
+
const m = txt.match(/<TargetFramework>([^<]+)<\/TargetFramework>/);
|
|
1308
|
+
if (m) return m[1];
|
|
1309
|
+
}
|
|
1310
|
+
} catch {}
|
|
1311
|
+
return '.NET (target unknown)';
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function projectPathFromCwd() {
|
|
1315
|
+
try { return process.cwd(); } catch { return '.'; }
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
function getJavaVersion(projectPath) {
|
|
1319
|
+
try {
|
|
1320
|
+
const pomPath = path.join(projectPath, 'pom.xml');
|
|
1321
|
+
if (fs.existsSync(pomPath)) {
|
|
1322
|
+
const pom = fs.readFileSync(pomPath, 'utf8');
|
|
1323
|
+
const m = pom.match(/<maven\.compiler\.source>([^<]+)<\/maven\.compiler\.source>/);
|
|
1324
|
+
const v = m?.[1] || (pom.match(/<java\.version>([^<]+)<\/java\.version>/)?.[1]);
|
|
1325
|
+
if (v) return `JDK ${v}`;
|
|
1326
|
+
}
|
|
1327
|
+
const gradlePath = fs.existsSync(path.join(projectPath, 'build.gradle.kts')) ? path.join(projectPath, 'build.gradle.kts') : path.join(projectPath, 'build.gradle');
|
|
1328
|
+
if (fs.existsSync(gradlePath)) {
|
|
1329
|
+
const gradle = fs.readFileSync(gradlePath, 'utf8');
|
|
1330
|
+
const m = gradle.match(/sourceCompatibility\s*=\s*['"]([^'"]+)['"]/i) || gradle.match(/sourceCompatibility\s+['"]([^'"]+)['"]/i);
|
|
1331
|
+
if (m?.[1]) return `JDK ${m[1]}`;
|
|
1332
|
+
}
|
|
1333
|
+
} catch {}
|
|
1334
|
+
return 'JDK (version unknown)';
|
|
1335
|
+
}
|