ccsetup 1.1.0 → 1.2.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 +100 -342
- package/bin/create-project.js +1616 -60
- package/bin/lib/claudeInterface.js +209 -0
- package/bin/lib/contextGenerator.js +287 -0
- package/bin/lib/scanner/index.js +28 -0
- package/bin/scan.js +367 -0
- package/lib/aiAgentSelector.js +155 -0
- package/lib/aiMergeHelper.js +112 -0
- package/lib/contextGenerator.js +574 -0
- package/lib/contextMerger.js +812 -0
- package/lib/progressReporter.js +88 -0
- package/lib/scanConfig.js +200 -0
- package/lib/scanner/fileAnalyzer.js +605 -0
- package/lib/scanner/index.js +164 -0
- package/lib/scanner/patterns.js +277 -0
- package/lib/scanner/projectDetector.js +147 -0
- package/lib/templates/README.md +176 -0
- package/lib/templates/catalog.js +230 -0
- package/lib/templates/filter.js +257 -0
- package/lib/templates/index.js +45 -0
- package/lib/templates/metadata/agents.json +413 -0
- package/lib/templates/metadata-extractor.js +329 -0
- package/lib/templates/search.js +356 -0
- package/package.json +11 -4
- package/template/{agents → .claude/agents}/checker.md +29 -0
- package/template/.claude/settings.json +15 -0
- package/template/.claude/skills/prd/SKILL.md +343 -0
- package/template/.claude/skills/ralph/SKILL.md +339 -0
- package/template/CLAUDE.md +39 -21
- package/template/CONTRIBUTING.md +37 -0
- package/template/GEMINI.md +126 -0
- package/template/agents/README.md +15 -171
- package/template/docs/ROADMAP.md +0 -36
- package/template/docs/agent-orchestration.md +24 -141
- package/template/hooks/workflow-selector/index.js +398 -0
- package/template/scripts/ralph/CLAUDE.md +174 -0
- package/template/scripts/ralph/ralph.sh +127 -0
- package/template/tickets/ticket-list.md +17 -68
- package/template/agents/ai-engineer.md +0 -31
- package/template/agents/api-documenter.md +0 -31
- package/template/agents/architect-review.md +0 -42
- package/template/agents/backend-architect.md +0 -29
- package/template/agents/business-analyst.md +0 -34
- package/template/agents/c-pro.md +0 -34
- package/template/agents/cloud-architect.md +0 -31
- package/template/agents/code-reviewer.md +0 -28
- package/template/agents/content-marketer.md +0 -34
- package/template/agents/context-manager.md +0 -63
- package/template/agents/cpp-pro.md +0 -37
- package/template/agents/customer-support.md +0 -34
- package/template/agents/data-engineer.md +0 -31
- package/template/agents/data-scientist.md +0 -28
- package/template/agents/database-admin.md +0 -31
- package/template/agents/database-optimizer.md +0 -31
- package/template/agents/debugger.md +0 -29
- package/template/agents/deployment-engineer.md +0 -31
- package/template/agents/devops-troubleshooter.md +0 -31
- package/template/agents/dx-optimizer.md +0 -62
- package/template/agents/error-detective.md +0 -31
- package/template/agents/frontend-developer.md +0 -30
- package/template/agents/golang-pro.md +0 -31
- package/template/agents/graphql-architect.md +0 -31
- package/template/agents/incident-responder.md +0 -73
- package/template/agents/javascript-pro.md +0 -34
- package/template/agents/legacy-modernizer.md +0 -31
- package/template/agents/ml-engineer.md +0 -31
- package/template/agents/mlops-engineer.md +0 -56
- package/template/agents/mobile-developer.md +0 -31
- package/template/agents/network-engineer.md +0 -31
- package/template/agents/payment-integration.md +0 -31
- package/template/agents/performance-engineer.md +0 -31
- package/template/agents/prompt-engineer.md +0 -58
- package/template/agents/python-pro.md +0 -31
- package/template/agents/quant-analyst.md +0 -31
- package/template/agents/risk-manager.md +0 -40
- package/template/agents/rust-pro.md +0 -34
- package/template/agents/sales-automator.md +0 -34
- package/template/agents/search-specialist.md +0 -58
- package/template/agents/security-auditor.md +0 -31
- package/template/agents/sql-pro.md +0 -34
- package/template/agents/terraform-specialist.md +0 -34
- package/template/agents/test-automator.md +0 -31
- /package/template/{agents → .claude/agents}/backend.md +0 -0
- /package/template/{agents → .claude/agents}/blockchain.md +0 -0
- /package/template/{agents → .claude/agents}/coder.md +0 -0
- /package/template/{agents → .claude/agents}/frontend.md +0 -0
- /package/template/{agents → .claude/agents}/planner.md +0 -0
- /package/template/{agents → .claude/agents}/researcher.md +0 -0
- /package/template/{agents → .claude/agents}/shadcn.md +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const ProjectDetector = require('./projectDetector');
|
|
4
|
+
const FileAnalyzer = require('./fileAnalyzer');
|
|
5
|
+
|
|
6
|
+
class RepositoryScanner {
|
|
7
|
+
constructor(projectPath, options = {}) {
|
|
8
|
+
this.projectPath = path.resolve(projectPath);
|
|
9
|
+
this.options = {
|
|
10
|
+
maxFiles: 1000,
|
|
11
|
+
timeout: 30000,
|
|
12
|
+
respectGitignore: true,
|
|
13
|
+
maxFileSize: 1024 * 1024, // 1MB
|
|
14
|
+
maxDepth: options.maxDepth || options.depth || 5,
|
|
15
|
+
ignorePatterns: this.parseIgnorePatterns(options.ignorePatterns || options.ignore),
|
|
16
|
+
...options
|
|
17
|
+
};
|
|
18
|
+
this.projectDetector = new ProjectDetector(this.projectPath);
|
|
19
|
+
this.fileAnalyzer = new FileAnalyzer(this.projectPath, this.options);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
parseIgnorePatterns(patterns) {
|
|
23
|
+
if (!patterns) return [];
|
|
24
|
+
if (typeof patterns === 'string') {
|
|
25
|
+
return patterns.split(',').map(p => p.trim()).filter(Boolean);
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(patterns)) {
|
|
28
|
+
return patterns.map(p => String(p).trim()).filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
shouldIgnorePath(filePath) {
|
|
34
|
+
const relativePath = path.relative(this.projectPath, filePath);
|
|
35
|
+
const depth = relativePath.split(path.sep).length;
|
|
36
|
+
|
|
37
|
+
if (depth > this.options.maxDepth) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
for (const pattern of this.options.ignorePatterns) {
|
|
42
|
+
try {
|
|
43
|
+
const minimatch = require('minimatch');
|
|
44
|
+
if (minimatch(relativePath, pattern)) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (relativePath.includes(pattern)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async scan(progressReporter = null) {
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (progressReporter) {
|
|
62
|
+
progressReporter.start('Scanning repository...');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let projectType, structure, dependencies, commands, patterns;
|
|
66
|
+
|
|
67
|
+
if (progressReporter) {
|
|
68
|
+
progressReporter.phase('Analyzing project structure');
|
|
69
|
+
structure = await this.analyzeStructure();
|
|
70
|
+
progressReporter.phaseComplete('Analyzing project structure', `${structure.totalFiles || 0} files`);
|
|
71
|
+
|
|
72
|
+
progressReporter.phase('Detecting project type');
|
|
73
|
+
projectType = await this.detectProjectType();
|
|
74
|
+
progressReporter.phaseComplete('Detecting project type', projectType?.primary?.type || 'unknown');
|
|
75
|
+
|
|
76
|
+
progressReporter.phase('Extracting dependencies');
|
|
77
|
+
dependencies = await this.extractDependencies();
|
|
78
|
+
const depCount = dependencies?.runtime?.length || 0;
|
|
79
|
+
progressReporter.phaseComplete('Extracting dependencies', `${depCount} packages`);
|
|
80
|
+
|
|
81
|
+
progressReporter.phase('Extracting commands');
|
|
82
|
+
commands = await this.extractCommands();
|
|
83
|
+
const cmdCount = Object.values(commands || {}).reduce((sum, cmds) => sum + cmds.length, 0);
|
|
84
|
+
progressReporter.phaseComplete('Extracting commands', `${cmdCount} scripts`);
|
|
85
|
+
|
|
86
|
+
progressReporter.phase('Detecting patterns');
|
|
87
|
+
patterns = await this.detectPatterns();
|
|
88
|
+
const patternCount = Object.values(patterns || {}).reduce((sum, patterns) => sum + patterns.length, 0);
|
|
89
|
+
progressReporter.phaseComplete('Detecting patterns', `${patternCount} patterns`);
|
|
90
|
+
} else {
|
|
91
|
+
[projectType, structure, dependencies, commands, patterns] = await Promise.all([
|
|
92
|
+
this.detectProjectType(),
|
|
93
|
+
this.analyzeStructure(),
|
|
94
|
+
this.extractDependencies(),
|
|
95
|
+
this.extractCommands(),
|
|
96
|
+
this.detectPatterns()
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const scanTime = Date.now() - startTime;
|
|
101
|
+
|
|
102
|
+
const results = {
|
|
103
|
+
projectType,
|
|
104
|
+
structure,
|
|
105
|
+
dependencies,
|
|
106
|
+
commands,
|
|
107
|
+
patterns,
|
|
108
|
+
scanDate: new Date().toISOString(),
|
|
109
|
+
scanTimeMs: scanTime,
|
|
110
|
+
projectPath: this.projectPath
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (progressReporter) {
|
|
114
|
+
progressReporter.success('Repository scan completed');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return results;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (progressReporter) {
|
|
120
|
+
progressReporter.fail(`Repository scan failed: ${error.message}`);
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Repository scan failed: ${error.message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async detectProjectType() {
|
|
127
|
+
return await this.projectDetector.detect();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async analyzeStructure() {
|
|
131
|
+
return await this.fileAnalyzer.analyzeStructure();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async extractDependencies() {
|
|
135
|
+
return await this.fileAnalyzer.extractDependencies();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async extractCommands() {
|
|
139
|
+
return await this.fileAnalyzer.extractCommands();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async detectPatterns() {
|
|
143
|
+
return await this.fileAnalyzer.detectPatterns();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
isValidProject() {
|
|
147
|
+
try {
|
|
148
|
+
const stats = fs.statSync(this.projectPath);
|
|
149
|
+
return stats.isDirectory();
|
|
150
|
+
} catch (error) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static async quickScan(projectPath) {
|
|
156
|
+
const scanner = new RepositoryScanner(projectPath, {
|
|
157
|
+
maxFiles: 100,
|
|
158
|
+
timeout: 10000
|
|
159
|
+
});
|
|
160
|
+
return await scanner.scan();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = RepositoryScanner;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
const PROJECT_TYPES = {
|
|
2
|
+
nodejs: {
|
|
3
|
+
indicators: [
|
|
4
|
+
{ type: 'file', file: 'package.json', weight: 30 },
|
|
5
|
+
{ type: 'file', file: 'package-lock.json', weight: 10 },
|
|
6
|
+
{ type: 'file', file: 'yarn.lock', weight: 10 },
|
|
7
|
+
{ type: 'directory', file: 'node_modules', weight: 20 },
|
|
8
|
+
{ type: 'file', file: '.nvmrc', weight: 5 }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
python: {
|
|
12
|
+
indicators: [
|
|
13
|
+
{ type: 'file', file: 'requirements.txt', weight: 25 },
|
|
14
|
+
{ type: 'file', file: 'setup.py', weight: 20 },
|
|
15
|
+
{ type: 'file', file: 'pyproject.toml', weight: 20 },
|
|
16
|
+
{ type: 'file', file: 'Pipfile', weight: 15 },
|
|
17
|
+
{ type: 'file', file: 'poetry.lock', weight: 10 },
|
|
18
|
+
{ type: 'directory', file: 'venv', weight: 10 },
|
|
19
|
+
{ type: 'directory', file: '.venv', weight: 10 }
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
go: {
|
|
23
|
+
indicators: [
|
|
24
|
+
{ type: 'file', file: 'go.mod', weight: 30 },
|
|
25
|
+
{ type: 'file', file: 'go.sum', weight: 15 },
|
|
26
|
+
{ type: 'file', file: 'main.go', weight: 20 },
|
|
27
|
+
{ type: 'directory', file: 'cmd', weight: 10 },
|
|
28
|
+
{ type: 'directory', file: 'pkg', weight: 10 }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
rust: {
|
|
32
|
+
indicators: [
|
|
33
|
+
{ type: 'file', file: 'Cargo.toml', weight: 30 },
|
|
34
|
+
{ type: 'file', file: 'Cargo.lock', weight: 15 },
|
|
35
|
+
{ type: 'directory', file: 'src', weight: 20 },
|
|
36
|
+
{ type: 'directory', file: 'target', weight: 10 }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
java: {
|
|
40
|
+
indicators: [
|
|
41
|
+
{ type: 'file', file: 'pom.xml', weight: 25 },
|
|
42
|
+
{ type: 'file', file: 'build.gradle', weight: 25 },
|
|
43
|
+
{ type: 'file', file: 'settings.gradle', weight: 10 },
|
|
44
|
+
{ type: 'directory', file: 'src/main/java', weight: 20 },
|
|
45
|
+
{ type: 'directory', file: 'target', weight: 10 },
|
|
46
|
+
{ type: 'directory', file: 'build', weight: 10 }
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
csharp: {
|
|
50
|
+
indicators: [
|
|
51
|
+
{ type: 'file', file: '*.csproj', weight: 30 },
|
|
52
|
+
{ type: 'file', file: '*.sln', weight: 25 },
|
|
53
|
+
{ type: 'directory', file: 'bin', weight: 10 },
|
|
54
|
+
{ type: 'directory', file: 'obj', weight: 10 }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
php: {
|
|
58
|
+
indicators: [
|
|
59
|
+
{ type: 'file', file: 'composer.json', weight: 25 },
|
|
60
|
+
{ type: 'file', file: 'composer.lock', weight: 15 },
|
|
61
|
+
{ type: 'directory', file: 'vendor', weight: 20 },
|
|
62
|
+
{ type: 'file', file: 'index.php', weight: 15 }
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
ruby: {
|
|
66
|
+
indicators: [
|
|
67
|
+
{ type: 'file', file: 'Gemfile', weight: 25 },
|
|
68
|
+
{ type: 'file', file: 'Gemfile.lock', weight: 15 },
|
|
69
|
+
{ type: 'file', file: 'config.ru', weight: 20 },
|
|
70
|
+
{ type: 'directory', file: 'app', weight: 15 }
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
flutter: {
|
|
74
|
+
indicators: [
|
|
75
|
+
{ type: 'file', file: 'pubspec.yaml', weight: 30 },
|
|
76
|
+
{ type: 'file', file: 'pubspec.lock', weight: 10 },
|
|
77
|
+
{ type: 'directory', file: 'lib', weight: 20 },
|
|
78
|
+
{ type: 'directory', file: 'android', weight: 15 },
|
|
79
|
+
{ type: 'directory', file: 'ios', weight: 15 }
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
react: {
|
|
83
|
+
indicators: [
|
|
84
|
+
{ type: 'content', file: 'package.json', pattern: '"react"', weight: 25 },
|
|
85
|
+
{ type: 'directory', file: 'src', weight: 15 },
|
|
86
|
+
{ type: 'directory', file: 'public', weight: 10 },
|
|
87
|
+
{ type: 'file', file: 'src/App.js', weight: 20 },
|
|
88
|
+
{ type: 'file', file: 'src/App.tsx', weight: 20 }
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
vue: {
|
|
92
|
+
indicators: [
|
|
93
|
+
{ type: 'content', file: 'package.json', pattern: '"vue"', weight: 25 },
|
|
94
|
+
{ type: 'file', file: 'vue.config.js', weight: 15 },
|
|
95
|
+
{ type: 'directory', file: 'src', weight: 15 },
|
|
96
|
+
{ type: 'file', file: 'src/App.vue', weight: 20 }
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
angular: {
|
|
100
|
+
indicators: [
|
|
101
|
+
{ type: 'file', file: 'angular.json', weight: 30 },
|
|
102
|
+
{ type: 'content', file: 'package.json', pattern: '"@angular/core"', weight: 25 },
|
|
103
|
+
{ type: 'directory', file: 'src/app', weight: 20 },
|
|
104
|
+
{ type: 'file', file: 'src/main.ts', weight: 15 }
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const FRAMEWORKS = {
|
|
110
|
+
nodejs: {
|
|
111
|
+
express: [
|
|
112
|
+
{ type: 'content', file: 'package.json', pattern: '"express"' }
|
|
113
|
+
],
|
|
114
|
+
nestjs: [
|
|
115
|
+
{ type: 'content', file: 'package.json', pattern: '"@nestjs/core"' }
|
|
116
|
+
],
|
|
117
|
+
fastify: [
|
|
118
|
+
{ type: 'content', file: 'package.json', pattern: '"fastify"' }
|
|
119
|
+
],
|
|
120
|
+
koa: [
|
|
121
|
+
{ type: 'content', file: 'package.json', pattern: '"koa"' }
|
|
122
|
+
],
|
|
123
|
+
next: [
|
|
124
|
+
{ type: 'content', file: 'package.json', pattern: '"next"' },
|
|
125
|
+
{ type: 'file', file: 'next.config.js' }
|
|
126
|
+
],
|
|
127
|
+
nuxt: [
|
|
128
|
+
{ type: 'content', file: 'package.json', pattern: '"nuxt"' },
|
|
129
|
+
{ type: 'file', file: 'nuxt.config.js' }
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
python: {
|
|
133
|
+
django: [
|
|
134
|
+
{ type: 'content', file: 'requirements.txt', pattern: 'Django' },
|
|
135
|
+
{ type: 'file', file: 'manage.py' }
|
|
136
|
+
],
|
|
137
|
+
flask: [
|
|
138
|
+
{ type: 'content', file: 'requirements.txt', pattern: 'Flask' }
|
|
139
|
+
],
|
|
140
|
+
fastapi: [
|
|
141
|
+
{ type: 'content', file: 'requirements.txt', pattern: 'fastapi' }
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
go: {
|
|
145
|
+
gin: [
|
|
146
|
+
{ type: 'content', file: 'go.mod', pattern: 'gin-gonic/gin' }
|
|
147
|
+
],
|
|
148
|
+
echo: [
|
|
149
|
+
{ type: 'content', file: 'go.mod', pattern: 'labstack/echo' }
|
|
150
|
+
],
|
|
151
|
+
fiber: [
|
|
152
|
+
{ type: 'content', file: 'go.mod', pattern: 'gofiber/fiber' }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const BUILD_TOOLS = {
|
|
158
|
+
webpack: [
|
|
159
|
+
{ type: 'file', file: 'webpack.config.js' },
|
|
160
|
+
{ type: 'content', file: 'package.json', pattern: '"webpack"' }
|
|
161
|
+
],
|
|
162
|
+
vite: [
|
|
163
|
+
{ type: 'file', file: 'vite.config.js' },
|
|
164
|
+
{ type: 'file', file: 'vite.config.ts' },
|
|
165
|
+
{ type: 'content', file: 'package.json', pattern: '"vite"' }
|
|
166
|
+
],
|
|
167
|
+
rollup: [
|
|
168
|
+
{ type: 'file', file: 'rollup.config.js' },
|
|
169
|
+
{ type: 'content', file: 'package.json', pattern: '"rollup"' }
|
|
170
|
+
],
|
|
171
|
+
parcel: [
|
|
172
|
+
{ type: 'content', file: 'package.json', pattern: '"parcel"' }
|
|
173
|
+
],
|
|
174
|
+
esbuild: [
|
|
175
|
+
{ type: 'content', file: 'package.json', pattern: '"esbuild"' }
|
|
176
|
+
],
|
|
177
|
+
make: [
|
|
178
|
+
{ type: 'file', file: 'Makefile' }
|
|
179
|
+
],
|
|
180
|
+
cmake: [
|
|
181
|
+
{ type: 'file', file: 'CMakeLists.txt' }
|
|
182
|
+
],
|
|
183
|
+
gradle: [
|
|
184
|
+
{ type: 'file', file: 'build.gradle' },
|
|
185
|
+
{ type: 'file', file: 'settings.gradle' }
|
|
186
|
+
],
|
|
187
|
+
maven: [
|
|
188
|
+
{ type: 'file', file: 'pom.xml' }
|
|
189
|
+
]
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const KEY_FILES = [
|
|
193
|
+
'readme.md', 'readme.txt', 'readme.rst',
|
|
194
|
+
'license', 'license.txt', 'license.md',
|
|
195
|
+
'changelog.md', 'changelog.txt',
|
|
196
|
+
'contributing.md', 'contributing.txt',
|
|
197
|
+
'package.json', 'package-lock.json', 'yarn.lock',
|
|
198
|
+
'requirements.txt', 'setup.py', 'pyproject.toml',
|
|
199
|
+
'go.mod', 'go.sum',
|
|
200
|
+
'cargo.toml', 'cargo.lock',
|
|
201
|
+
'pom.xml', 'build.gradle',
|
|
202
|
+
'dockerfile', 'docker-compose.yml',
|
|
203
|
+
'makefile', 'cmakeLists.txt',
|
|
204
|
+
'.gitignore', '.env.example', '.env.template',
|
|
205
|
+
'tsconfig.json', 'jsconfig.json',
|
|
206
|
+
'.eslintrc.js', '.eslintrc.json',
|
|
207
|
+
'.prettierrc', 'prettier.config.js'
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
const CONFIG_FILES = [
|
|
211
|
+
/.*config\.(js|json|yaml|yml|toml)$/i,
|
|
212
|
+
/.*\.config\.(js|json|yaml|yml|toml)$/i,
|
|
213
|
+
/.*rc\.(js|json|yaml|yml)$/i,
|
|
214
|
+
/^\.(.*rc|.*config)$/i
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
const FRAMEWORK_PACKAGES = {
|
|
218
|
+
'express': 'Express.js',
|
|
219
|
+
'@nestjs/core': 'NestJS',
|
|
220
|
+
'fastify': 'Fastify',
|
|
221
|
+
'koa': 'Koa.js',
|
|
222
|
+
'next': 'Next.js',
|
|
223
|
+
'nuxt': 'Nuxt.js',
|
|
224
|
+
'react': 'React',
|
|
225
|
+
'vue': 'Vue.js',
|
|
226
|
+
'@angular/core': 'Angular',
|
|
227
|
+
'svelte': 'Svelte',
|
|
228
|
+
'solid-js': 'SolidJS',
|
|
229
|
+
'lit': 'Lit',
|
|
230
|
+
'astro': 'Astro',
|
|
231
|
+
'gatsby': 'Gatsby',
|
|
232
|
+
'remix': 'Remix',
|
|
233
|
+
'vite': 'Vite',
|
|
234
|
+
'webpack': 'Webpack',
|
|
235
|
+
'rollup': 'Rollup',
|
|
236
|
+
'parcel': 'Parcel',
|
|
237
|
+
'esbuild': 'esbuild',
|
|
238
|
+
'typescript': 'TypeScript',
|
|
239
|
+
'babel': 'Babel',
|
|
240
|
+
'eslint': 'ESLint',
|
|
241
|
+
'prettier': 'Prettier',
|
|
242
|
+
'jest': 'Jest',
|
|
243
|
+
'vitest': 'Vitest',
|
|
244
|
+
'cypress': 'Cypress',
|
|
245
|
+
'playwright': 'Playwright',
|
|
246
|
+
'storybook': 'Storybook',
|
|
247
|
+
'tailwindcss': 'Tailwind CSS',
|
|
248
|
+
'styled-components': 'Styled Components',
|
|
249
|
+
'@emotion/react': 'Emotion',
|
|
250
|
+
'sass': 'Sass',
|
|
251
|
+
'less': 'Less',
|
|
252
|
+
'prisma': 'Prisma',
|
|
253
|
+
'mongoose': 'Mongoose',
|
|
254
|
+
'sequelize': 'Sequelize',
|
|
255
|
+
'typeorm': 'TypeORM',
|
|
256
|
+
'apollo-server': 'Apollo Server',
|
|
257
|
+
'graphql': 'GraphQL',
|
|
258
|
+
'socket.io': 'Socket.IO',
|
|
259
|
+
'passport': 'Passport.js',
|
|
260
|
+
'jsonwebtoken': 'JWT',
|
|
261
|
+
'bcrypt': 'bcrypt',
|
|
262
|
+
'lodash': 'Lodash',
|
|
263
|
+
'moment': 'Moment.js',
|
|
264
|
+
'dayjs': 'Day.js',
|
|
265
|
+
'axios': 'Axios',
|
|
266
|
+
'got': 'Got',
|
|
267
|
+
'node-fetch': 'node-fetch'
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
module.exports = {
|
|
271
|
+
PROJECT_TYPES,
|
|
272
|
+
FRAMEWORKS,
|
|
273
|
+
BUILD_TOOLS,
|
|
274
|
+
KEY_FILES,
|
|
275
|
+
CONFIG_FILES,
|
|
276
|
+
FRAMEWORK_PACKAGES
|
|
277
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const patterns = require('./patterns');
|
|
4
|
+
|
|
5
|
+
class ProjectDetector {
|
|
6
|
+
constructor(projectPath) {
|
|
7
|
+
this.projectPath = projectPath;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async detect() {
|
|
11
|
+
const detectionResults = [];
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
for (const [projectType, config] of Object.entries(patterns.PROJECT_TYPES)) {
|
|
15
|
+
const confidence = await this.calculateConfidence(projectType, config);
|
|
16
|
+
if (confidence > 0) {
|
|
17
|
+
detectionResults.push({
|
|
18
|
+
type: projectType,
|
|
19
|
+
confidence,
|
|
20
|
+
indicators: config.indicators.filter(indicator =>
|
|
21
|
+
this.checkIndicator(indicator)
|
|
22
|
+
)
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
detectionResults.sort((a, b) => b.confidence - a.confidence);
|
|
28
|
+
|
|
29
|
+
const primaryType = detectionResults[0] || { type: 'unknown', confidence: 0, indicators: [] };
|
|
30
|
+
const secondaryTypes = detectionResults.slice(1, 3);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
primary: primaryType,
|
|
34
|
+
secondary: secondaryTypes,
|
|
35
|
+
framework: await this.detectFramework(primaryType.type),
|
|
36
|
+
language: await this.detectLanguage(),
|
|
37
|
+
buildTools: await this.detectBuildTools()
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
primary: { type: 'unknown', confidence: 0, indicators: [] },
|
|
42
|
+
secondary: [],
|
|
43
|
+
framework: null,
|
|
44
|
+
language: 'unknown',
|
|
45
|
+
buildTools: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async calculateConfidence(projectType, config) {
|
|
51
|
+
let confidence = 0;
|
|
52
|
+
const maxConfidence = config.indicators.length * 10;
|
|
53
|
+
|
|
54
|
+
for (const indicator of config.indicators) {
|
|
55
|
+
if (this.checkIndicator(indicator)) {
|
|
56
|
+
confidence += indicator.weight || 10;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return Math.min(100, (confidence / maxConfidence) * 100);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
checkIndicator(indicator) {
|
|
64
|
+
const filePath = path.join(this.projectPath, indicator.file);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
if (indicator.type === 'file') {
|
|
68
|
+
return fs.existsSync(filePath);
|
|
69
|
+
} else if (indicator.type === 'directory') {
|
|
70
|
+
const stats = fs.statSync(filePath);
|
|
71
|
+
return stats.isDirectory();
|
|
72
|
+
} else if (indicator.type === 'content') {
|
|
73
|
+
if (!fs.existsSync(filePath)) return false;
|
|
74
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
75
|
+
return indicator.pattern ? new RegExp(indicator.pattern).test(content) : true;
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async detectFramework(projectType) {
|
|
85
|
+
const frameworkPatterns = patterns.FRAMEWORKS[projectType];
|
|
86
|
+
if (!frameworkPatterns) return null;
|
|
87
|
+
|
|
88
|
+
for (const [framework, indicators] of Object.entries(frameworkPatterns)) {
|
|
89
|
+
let matches = 0;
|
|
90
|
+
for (const indicator of indicators) {
|
|
91
|
+
if (this.checkIndicator(indicator)) {
|
|
92
|
+
matches++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (matches > 0) {
|
|
96
|
+
return { name: framework, confidence: (matches / indicators.length) * 100 };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async detectLanguage() {
|
|
104
|
+
const languageIndicators = {
|
|
105
|
+
javascript: ['package.json', '*.js', '*.mjs'],
|
|
106
|
+
typescript: ['tsconfig.json', '*.ts', '*.tsx'],
|
|
107
|
+
python: ['requirements.txt', 'pyproject.toml', '*.py'],
|
|
108
|
+
go: ['go.mod', 'go.sum', '*.go'],
|
|
109
|
+
rust: ['Cargo.toml', 'Cargo.lock', '*.rs'],
|
|
110
|
+
java: ['pom.xml', 'build.gradle', '*.java'],
|
|
111
|
+
csharp: ['*.csproj', '*.sln'],
|
|
112
|
+
php: ['composer.json', '*.php'],
|
|
113
|
+
ruby: ['Gemfile', '*.rb'],
|
|
114
|
+
cpp: ['CMakeLists.txt', '*.cpp', '*.cc', '*.cxx'],
|
|
115
|
+
c: ['Makefile', '*.c', '*.h']
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
for (const [language, indicators] of Object.entries(languageIndicators)) {
|
|
119
|
+
for (const indicator of indicators) {
|
|
120
|
+
const fullPath = path.join(this.projectPath, indicator);
|
|
121
|
+
if (fs.existsSync(fullPath)) {
|
|
122
|
+
return language;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return 'unknown';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async detectBuildTools() {
|
|
131
|
+
const buildTools = [];
|
|
132
|
+
const buildToolPatterns = patterns.BUILD_TOOLS;
|
|
133
|
+
|
|
134
|
+
for (const [tool, indicators] of Object.entries(buildToolPatterns)) {
|
|
135
|
+
for (const indicator of indicators) {
|
|
136
|
+
if (this.checkIndicator(indicator)) {
|
|
137
|
+
buildTools.push(tool);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return buildTools;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = ProjectDetector;
|