claude-flow-novice 1.3.1 → 1.3.3

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.
@@ -0,0 +1,581 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import pkg from 'glob';
4
+ const { glob } = pkg;
5
+
6
+ /**
7
+ * Language Detection System
8
+ *
9
+ * Scans project files to detect programming languages, frameworks, and dependencies
10
+ * Provides confidence scoring and detailed analysis for CLAUDE.md generation
11
+ */
12
+ export class LanguageDetector {
13
+ constructor(projectPath = process.cwd()) {
14
+ this.projectPath = projectPath;
15
+ this.detectionResults = {
16
+ languages: {},
17
+ frameworks: {},
18
+ dependencies: {},
19
+ projectType: null,
20
+ confidence: 0,
21
+ metadata: {},
22
+ };
23
+
24
+ // Language patterns and scoring weights
25
+ this.languagePatterns = {
26
+ javascript: {
27
+ extensions: ['.js', '.mjs', '.cjs'],
28
+ files: ['package.json', '.eslintrc*', 'babel.config.*'],
29
+ patterns: [/require\(/, /import\s+.*from/, /module\.exports/, /export\s+(default\s+)?/],
30
+ weight: 1.0,
31
+ },
32
+ typescript: {
33
+ extensions: ['.ts', '.tsx'],
34
+ files: ['tsconfig.json', 'tslint.json', '.tsconfig.json'],
35
+ patterns: [/interface\s+\w+/, /type\s+\w+\s*=/, /:\s*\w+(\[\])?/, /import.*from.*\.ts/],
36
+ weight: 1.2,
37
+ },
38
+ python: {
39
+ extensions: ['.py', '.pyx', '.pyw'],
40
+ files: ['requirements.txt', 'setup.py', 'pyproject.toml', 'Pipfile', '__init__.py'],
41
+ patterns: [/def\s+\w+\s*\(/, /import\s+\w+/, /from\s+\w+\s+import/, /class\s+\w+/],
42
+ weight: 1.0,
43
+ },
44
+ java: {
45
+ extensions: ['.java'],
46
+ files: ['pom.xml', 'build.gradle', '.gradle'],
47
+ patterns: [/public\s+class/, /package\s+[\w.]+/, /import\s+[\w.]+/],
48
+ weight: 1.0,
49
+ },
50
+ go: {
51
+ extensions: ['.go'],
52
+ files: ['go.mod', 'go.sum'],
53
+ patterns: [/package\s+main/, /func\s+\w+/, /import\s*\(/, /var\s+\w+\s+\w+/],
54
+ weight: 1.0,
55
+ },
56
+ rust: {
57
+ extensions: ['.rs'],
58
+ files: ['Cargo.toml', 'Cargo.lock'],
59
+ patterns: [/fn\s+\w+/, /struct\s+\w+/, /impl\s+\w+/, /use\s+[\w:]+/],
60
+ weight: 1.0,
61
+ },
62
+ };
63
+
64
+ // Framework detection patterns
65
+ this.frameworkPatterns = {
66
+ react: {
67
+ dependencies: ['react', '@types/react', 'react-dom'],
68
+ patterns: [/import.*React/, /from\s+['"]react['"]/, /jsx?/, /\.tsx?$/],
69
+ files: ['.babelrc', 'next.config.js'],
70
+ weight: 1.5,
71
+ },
72
+ nextjs: {
73
+ dependencies: ['next'],
74
+ patterns: [/from\s+['"]next\//, /export.*getServerSideProps/, /export.*getStaticProps/],
75
+ files: ['next.config.js', 'pages/', 'app/'],
76
+ weight: 1.8,
77
+ },
78
+ vue: {
79
+ dependencies: ['vue', '@vue/cli'],
80
+ patterns: [/import.*Vue/, /<template>/, /<script>/, /\.vue$/],
81
+ files: ['vue.config.js'],
82
+ weight: 1.5,
83
+ },
84
+ angular: {
85
+ dependencies: ['@angular/core', '@angular/cli'],
86
+ patterns: [/import.*@angular/, /@Component/, /@Injectable/, /\.component\.ts$/],
87
+ files: ['angular.json', '.angular-cli.json'],
88
+ weight: 1.5,
89
+ },
90
+ express: {
91
+ dependencies: ['express'],
92
+ patterns: [/require\(['"]express['"]/, /app\.get/, /app\.post/, /app\.listen/],
93
+ files: [],
94
+ weight: 1.3,
95
+ },
96
+ fastify: {
97
+ dependencies: ['fastify'],
98
+ patterns: [/require\(['"]fastify['"]/, /fastify\.register/, /fastify\.listen/],
99
+ files: [],
100
+ weight: 1.3,
101
+ },
102
+ django: {
103
+ dependencies: ['django'],
104
+ patterns: [/from\s+django/, /django\./, /INSTALLED_APPS/, /urls\.py$/],
105
+ files: ['manage.py', 'settings.py', 'wsgi.py'],
106
+ weight: 1.5,
107
+ },
108
+ flask: {
109
+ dependencies: ['flask'],
110
+ patterns: [/from\s+flask/, /Flask\(__name__\)/, /app\.route/, /@app\.route/],
111
+ files: ['app.py', 'wsgi.py'],
112
+ weight: 1.3,
113
+ },
114
+ fastapi: {
115
+ dependencies: ['fastapi'],
116
+ patterns: [/from\s+fastapi/, /FastAPI\(\)/, /@app\.get/, /@app\.post/],
117
+ files: ['main.py'],
118
+ weight: 1.4,
119
+ },
120
+ spring: {
121
+ dependencies: ['spring-boot-starter'],
122
+ patterns: [/@SpringBootApplication/, /@RestController/, /@Service/],
123
+ files: ['application.properties', 'application.yml'],
124
+ weight: 1.5,
125
+ },
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Main detection method - analyzes the entire project
131
+ */
132
+ async detectProject() {
133
+ console.log(`🔍 Scanning project at: ${this.projectPath}`);
134
+
135
+ try {
136
+ // Parallel detection for better performance
137
+ await Promise.all([
138
+ this.scanPackageFiles(),
139
+ this.scanSourceFiles(),
140
+ this.analyzeProjectStructure(),
141
+ this.detectBuildTools(),
142
+ ]);
143
+
144
+ // Calculate confidence scores
145
+ this.calculateConfidenceScores();
146
+
147
+ // Determine primary project type
148
+ this.determinePrimaryProjectType();
149
+
150
+ console.log(
151
+ `✅ Detection complete. Found ${Object.keys(this.detectionResults.languages).length} languages`,
152
+ );
153
+ return this.detectionResults;
154
+ } catch (error) {
155
+ console.error(`❌ Detection failed: ${error.message}`);
156
+ throw error;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Scan package management files (package.json, requirements.txt, etc.)
162
+ */
163
+ async scanPackageFiles() {
164
+ const packageFiles = [
165
+ 'package.json',
166
+ 'requirements.txt',
167
+ 'pyproject.toml',
168
+ 'Pipfile',
169
+ 'pom.xml',
170
+ 'build.gradle',
171
+ 'Cargo.toml',
172
+ 'go.mod',
173
+ ];
174
+
175
+ for (const file of packageFiles) {
176
+ const filePath = path.join(this.projectPath, file);
177
+
178
+ try {
179
+ const content = await fs.readFile(filePath, 'utf8');
180
+ await this.analyzePackageFile(file, content);
181
+ } catch (error) {
182
+ // File doesn't exist, continue
183
+ continue;
184
+ }
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Analyze specific package files for dependencies and metadata
190
+ */
191
+ async analyzePackageFile(filename, content) {
192
+ switch (filename) {
193
+ case 'package.json':
194
+ await this.analyzePackageJson(content);
195
+ break;
196
+ case 'requirements.txt':
197
+ await this.analyzeRequirementsTxt(content);
198
+ break;
199
+ case 'pyproject.toml':
200
+ await this.analyzePyprojectToml(content);
201
+ break;
202
+ case 'pom.xml':
203
+ await this.analyzePomXml(content);
204
+ break;
205
+ case 'Cargo.toml':
206
+ await this.analyzeCargoToml(content);
207
+ break;
208
+ case 'go.mod':
209
+ await this.analyzeGoMod(content);
210
+ break;
211
+ }
212
+ }
213
+
214
+ async analyzePackageJson(content) {
215
+ try {
216
+ const pkg = JSON.parse(content);
217
+ const allDeps = {
218
+ ...pkg.dependencies,
219
+ ...pkg.devDependencies,
220
+ ...pkg.peerDependencies,
221
+ };
222
+
223
+ // Detect JavaScript/TypeScript
224
+ this.incrementLanguageScore('javascript', 0.8);
225
+
226
+ if (allDeps.typescript || allDeps['@types/node']) {
227
+ this.incrementLanguageScore('typescript', 1.2);
228
+ }
229
+
230
+ // Detect frameworks
231
+ for (const [framework, config] of Object.entries(this.frameworkPatterns)) {
232
+ const hasFramework = config.dependencies.some((dep) =>
233
+ Object.keys(allDeps).some(
234
+ (installedDep) => installedDep.includes(dep) || dep.includes(installedDep),
235
+ ),
236
+ );
237
+
238
+ if (hasFramework) {
239
+ this.incrementFrameworkScore(framework, config.weight);
240
+ }
241
+ }
242
+
243
+ // Store metadata
244
+ this.detectionResults.metadata.packageManager = 'npm';
245
+ this.detectionResults.metadata.projectName = pkg.name;
246
+ this.detectionResults.metadata.scripts = pkg.scripts || {};
247
+ this.detectionResults.dependencies = { ...this.detectionResults.dependencies, ...allDeps };
248
+ } catch (error) {
249
+ console.warn(`Failed to parse package.json: ${error.message}`);
250
+ }
251
+ }
252
+
253
+ async analyzeRequirementsTxt(content) {
254
+ const lines = content.split('\n').filter((line) => line.trim() && !line.startsWith('#'));
255
+
256
+ this.incrementLanguageScore('python', 0.9);
257
+ this.detectionResults.metadata.packageManager = 'pip';
258
+
259
+ // Extract package names and detect frameworks
260
+ for (const line of lines) {
261
+ const packageName = line
262
+ .split(/[>=<~!]/)[0]
263
+ .toLowerCase()
264
+ .trim();
265
+ this.detectionResults.dependencies[packageName] = line;
266
+
267
+ // Check for Python frameworks
268
+ for (const [framework, config] of Object.entries(this.frameworkPatterns)) {
269
+ if (config.dependencies.some((dep) => packageName.includes(dep.toLowerCase()))) {
270
+ this.incrementFrameworkScore(framework, config.weight);
271
+ }
272
+ }
273
+ }
274
+ }
275
+
276
+ async analyzePyprojectToml(content) {
277
+ this.incrementLanguageScore('python', 0.8);
278
+ this.detectionResults.metadata.packageManager = 'poetry';
279
+
280
+ // Basic TOML parsing for dependencies
281
+ const depMatches = content.match(/\[tool\.poetry\.dependencies\]([\s\S]*?)(?=\[|$)/);
282
+ if (depMatches) {
283
+ const depSection = depMatches[1];
284
+ const deps = depSection.match(/^(\w+)\s*=/gm);
285
+ if (deps) {
286
+ deps.forEach((dep) => {
287
+ const name = dep.split('=')[0].trim();
288
+ this.detectionResults.dependencies[name] = dep;
289
+ });
290
+ }
291
+ }
292
+ }
293
+
294
+ async analyzePomXml(content) {
295
+ this.incrementLanguageScore('java', 1.0);
296
+ this.detectionResults.metadata.packageManager = 'maven';
297
+
298
+ // Extract Spring Boot detection
299
+ if (content.includes('spring-boot')) {
300
+ this.incrementFrameworkScore('spring', 1.5);
301
+ }
302
+ }
303
+
304
+ async analyzeCargoToml(content) {
305
+ this.incrementLanguageScore('rust', 1.0);
306
+ this.detectionResults.metadata.packageManager = 'cargo';
307
+ }
308
+
309
+ async analyzeGoMod(content) {
310
+ this.incrementLanguageScore('go', 1.0);
311
+ this.detectionResults.metadata.packageManager = 'go';
312
+ }
313
+
314
+ /**
315
+ * Scan source files for language patterns
316
+ */
317
+ async scanSourceFiles() {
318
+ const sourceFiles = await glob('**/*.{js,ts,tsx,jsx,py,java,go,rs,vue}', {
319
+ cwd: this.projectPath,
320
+ ignore: ['node_modules/**', 'dist/**', 'build/**', '.git/**', 'vendor/**', 'target/**'],
321
+ });
322
+
323
+ console.log(`📁 Found ${sourceFiles.length} source files to analyze`);
324
+
325
+ // Process files in batches for performance
326
+ const batchSize = 50;
327
+ for (let i = 0; i < sourceFiles.length; i += batchSize) {
328
+ const batch = sourceFiles.slice(i, i + batchSize);
329
+ await Promise.all(batch.map((file) => this.analyzeSourceFile(file)));
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Analyze individual source file
335
+ */
336
+ async analyzeSourceFile(relativePath) {
337
+ const filePath = path.join(this.projectPath, relativePath);
338
+ const ext = path.extname(relativePath);
339
+
340
+ try {
341
+ const content = await fs.readFile(filePath, 'utf8');
342
+
343
+ // Detect language by extension
344
+ for (const [lang, config] of Object.entries(this.languagePatterns)) {
345
+ if (config.extensions.includes(ext)) {
346
+ this.incrementLanguageScore(lang, 0.5);
347
+
348
+ // Check for language-specific patterns
349
+ config.patterns.forEach((pattern) => {
350
+ if (pattern.test(content)) {
351
+ this.incrementLanguageScore(lang, 0.3);
352
+ }
353
+ });
354
+ }
355
+ }
356
+
357
+ // Check for framework patterns
358
+ for (const [framework, config] of Object.entries(this.frameworkPatterns)) {
359
+ config.patterns.forEach((pattern) => {
360
+ if (pattern.test(content) || pattern.test(relativePath)) {
361
+ this.incrementFrameworkScore(framework, 0.4);
362
+ }
363
+ });
364
+ }
365
+ } catch (error) {
366
+ console.warn(`Could not analyze ${relativePath}: ${error.message}`);
367
+ }
368
+ }
369
+
370
+ /**
371
+ * Analyze project structure for additional clues
372
+ */
373
+ async analyzeProjectStructure() {
374
+ const directories = [
375
+ 'src',
376
+ 'lib',
377
+ 'app',
378
+ 'pages',
379
+ 'components',
380
+ 'views',
381
+ 'models',
382
+ 'controllers',
383
+ 'routes',
384
+ ];
385
+
386
+ for (const dir of directories) {
387
+ const dirPath = path.join(this.projectPath, dir);
388
+ try {
389
+ const stat = await fs.stat(dirPath);
390
+ if (stat.isDirectory()) {
391
+ this.detectionResults.metadata.directories =
392
+ this.detectionResults.metadata.directories || [];
393
+ this.detectionResults.metadata.directories.push(dir);
394
+
395
+ // Specific directory patterns
396
+ if (dir === 'pages' || dir === 'app') {
397
+ this.incrementFrameworkScore('nextjs', 0.5);
398
+ }
399
+ if (dir === 'components') {
400
+ this.incrementFrameworkScore('react', 0.3);
401
+ this.incrementFrameworkScore('vue', 0.3);
402
+ }
403
+ }
404
+ } catch (error) {
405
+ // Directory doesn't exist
406
+ continue;
407
+ }
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Detect build tools and configuration files
413
+ */
414
+ async detectBuildTools() {
415
+ const buildFiles = {
416
+ 'webpack.config.js': { tool: 'webpack', score: 0.5 },
417
+ 'vite.config.js': { tool: 'vite', score: 0.5 },
418
+ 'rollup.config.js': { tool: 'rollup', score: 0.5 },
419
+ 'gulpfile.js': { tool: 'gulp', score: 0.5 },
420
+ Makefile: { tool: 'make', score: 0.5 },
421
+ 'docker-compose.yml': { tool: 'docker', score: 0.7 },
422
+ Dockerfile: { tool: 'docker', score: 0.7 },
423
+ };
424
+
425
+ for (const [file, config] of Object.entries(buildFiles)) {
426
+ try {
427
+ await fs.access(path.join(this.projectPath, file));
428
+ this.detectionResults.metadata.buildTools = this.detectionResults.metadata.buildTools || {};
429
+ this.detectionResults.metadata.buildTools[config.tool] = config.score;
430
+ } catch (error) {
431
+ // File doesn't exist
432
+ continue;
433
+ }
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Helper methods for scoring
439
+ */
440
+ incrementLanguageScore(language, score) {
441
+ this.detectionResults.languages[language] =
442
+ (this.detectionResults.languages[language] || 0) + score;
443
+ }
444
+
445
+ incrementFrameworkScore(framework, score) {
446
+ this.detectionResults.frameworks[framework] =
447
+ (this.detectionResults.frameworks[framework] || 0) + score;
448
+ }
449
+
450
+ /**
451
+ * Calculate confidence scores for all detected technologies
452
+ */
453
+ calculateConfidenceScores() {
454
+ // Normalize language scores
455
+ const maxLangScore = Math.max(...Object.values(this.detectionResults.languages));
456
+ if (maxLangScore > 0) {
457
+ for (const lang in this.detectionResults.languages) {
458
+ this.detectionResults.languages[lang] = Math.min(
459
+ this.detectionResults.languages[lang] / maxLangScore,
460
+ 1.0,
461
+ );
462
+ }
463
+ }
464
+
465
+ // Normalize framework scores
466
+ const maxFrameworkScore = Math.max(...Object.values(this.detectionResults.frameworks), 1);
467
+ for (const framework in this.detectionResults.frameworks) {
468
+ this.detectionResults.frameworks[framework] = Math.min(
469
+ this.detectionResults.frameworks[framework] / maxFrameworkScore,
470
+ 1.0,
471
+ );
472
+ }
473
+
474
+ // Calculate overall confidence
475
+ const totalLanguages = Object.keys(this.detectionResults.languages).length;
476
+ const totalFrameworks = Object.keys(this.detectionResults.frameworks).length;
477
+ this.detectionResults.confidence = Math.min(
478
+ (totalLanguages * 0.6 + totalFrameworks * 0.4) / 2,
479
+ 1.0,
480
+ );
481
+ }
482
+
483
+ /**
484
+ * Determine the primary project type based on scores
485
+ */
486
+ determinePrimaryProjectType() {
487
+ const languages = this.detectionResults.languages;
488
+ const frameworks = this.detectionResults.frameworks;
489
+
490
+ const primaryLang = Object.keys(languages).reduce(
491
+ (a, b) => (languages[a] > languages[b] ? a : b),
492
+ Object.keys(languages)[0],
493
+ );
494
+
495
+ const primaryFramework = Object.keys(frameworks).reduce(
496
+ (a, b) => (frameworks[a] > frameworks[b] ? a : b),
497
+ Object.keys(frameworks)[0],
498
+ );
499
+
500
+ // Determine project type
501
+ if (frameworks.react && languages.typescript) {
502
+ this.detectionResults.projectType = 'react-typescript';
503
+ } else if (frameworks.react) {
504
+ this.detectionResults.projectType = 'react';
505
+ } else if (frameworks.nextjs) {
506
+ this.detectionResults.projectType = 'nextjs';
507
+ } else if (frameworks.vue) {
508
+ this.detectionResults.projectType = 'vue';
509
+ } else if (frameworks.express) {
510
+ this.detectionResults.projectType = 'express-api';
511
+ } else if (frameworks.django) {
512
+ this.detectionResults.projectType = 'django';
513
+ } else if (frameworks.flask) {
514
+ this.detectionResults.projectType = 'flask';
515
+ } else if (frameworks.fastapi) {
516
+ this.detectionResults.projectType = 'fastapi';
517
+ } else if (primaryLang) {
518
+ this.detectionResults.projectType = primaryLang;
519
+ } else {
520
+ this.detectionResults.projectType = 'unknown';
521
+ }
522
+
523
+ this.detectionResults.metadata.primaryLanguage = primaryLang;
524
+ this.detectionResults.metadata.primaryFramework = primaryFramework;
525
+ }
526
+
527
+ /**
528
+ * Get recommendations for tooling and best practices
529
+ */
530
+ getRecommendations() {
531
+ const recommendations = {
532
+ linting: [],
533
+ testing: [],
534
+ building: [],
535
+ deployment: [],
536
+ };
537
+
538
+ const { languages, frameworks } = this.detectionResults;
539
+
540
+ // Linting recommendations
541
+ if (languages.javascript || languages.typescript) {
542
+ recommendations.linting.push('ESLint', 'Prettier');
543
+ }
544
+ if (languages.python) {
545
+ recommendations.linting.push('Black', 'Flake8', 'mypy');
546
+ }
547
+
548
+ // Testing recommendations
549
+ if (frameworks.react || frameworks.nextjs) {
550
+ recommendations.testing.push('Jest', 'React Testing Library');
551
+ } else if (languages.javascript || languages.typescript) {
552
+ recommendations.testing.push('Jest', 'Vitest');
553
+ }
554
+ if (languages.python) {
555
+ recommendations.testing.push('pytest', 'unittest');
556
+ }
557
+
558
+ // Build recommendations
559
+ if (frameworks.react && !frameworks.nextjs) {
560
+ recommendations.building.push('Vite', 'Create React App');
561
+ }
562
+ if (languages.typescript) {
563
+ recommendations.building.push('tsc', 'esbuild');
564
+ }
565
+
566
+ return recommendations;
567
+ }
568
+
569
+ /**
570
+ * Export results for use by other systems
571
+ */
572
+ exportResults() {
573
+ return {
574
+ ...this.detectionResults,
575
+ timestamp: new Date().toISOString(),
576
+ recommendations: this.getRecommendations(),
577
+ };
578
+ }
579
+ }
580
+
581
+ export default LanguageDetector;