opencode-conductor-cdd-plugin 1.0.0-beta.18 → 1.0.0-beta.19
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/prompts/cdd/setup.json +2 -2
- package/dist/prompts/cdd/setup.test.js +40 -118
- package/dist/prompts/cdd/setup.test.ts +40 -143
- package/dist/utils/codebaseAnalysis.d.ts +61 -0
- package/dist/utils/codebaseAnalysis.js +429 -0
- package/dist/utils/codebaseAnalysis.test.d.ts +1 -0
- package/dist/utils/codebaseAnalysis.test.js +556 -0
- package/dist/utils/documentGeneration.d.ts +97 -0
- package/dist/utils/documentGeneration.js +301 -0
- package/dist/utils/documentGeneration.test.d.ts +1 -0
- package/dist/utils/documentGeneration.test.js +380 -0
- package/dist/utils/interactiveMenu.d.ts +56 -0
- package/dist/utils/interactiveMenu.js +144 -0
- package/dist/utils/interactiveMenu.test.d.ts +1 -0
- package/dist/utils/interactiveMenu.test.js +231 -0
- package/dist/utils/interactiveSetup.d.ts +43 -0
- package/dist/utils/interactiveSetup.js +131 -0
- package/dist/utils/interactiveSetup.test.d.ts +1 -0
- package/dist/utils/interactiveSetup.test.js +124 -0
- package/dist/utils/projectMaturity.d.ts +53 -0
- package/dist/utils/projectMaturity.js +179 -0
- package/dist/utils/projectMaturity.test.d.ts +1 -0
- package/dist/utils/projectMaturity.test.js +298 -0
- package/dist/utils/questionGenerator.d.ts +51 -0
- package/dist/utils/questionGenerator.js +535 -0
- package/dist/utils/questionGenerator.test.d.ts +1 -0
- package/dist/utils/questionGenerator.test.js +328 -0
- package/dist/utils/setupIntegration.d.ts +72 -0
- package/dist/utils/setupIntegration.js +179 -0
- package/dist/utils/setupIntegration.test.d.ts +1 -0
- package/dist/utils/setupIntegration.test.js +344 -0
- package/package.json +1 -1
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
/**
|
|
5
|
+
* Parse ignore files with precedence: .geminiignore > .ignore > .gitignore
|
|
6
|
+
*/
|
|
7
|
+
export function parseIgnoreFiles(projectPath) {
|
|
8
|
+
const ignoreFiles = ['.geminiignore', '.ignore', '.gitignore'];
|
|
9
|
+
for (const ignoreFile of ignoreFiles) {
|
|
10
|
+
const ignoreFilePath = path.join(projectPath, ignoreFile);
|
|
11
|
+
if (fs.existsSync(ignoreFilePath)) {
|
|
12
|
+
return parseIgnoreFile(ignoreFilePath);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a single ignore file
|
|
19
|
+
*/
|
|
20
|
+
function parseIgnoreFile(filePath) {
|
|
21
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
const lines = content.split('\n');
|
|
23
|
+
const patterns = [];
|
|
24
|
+
for (const line of lines) {
|
|
25
|
+
const trimmed = line.trim();
|
|
26
|
+
// Skip empty lines and comments
|
|
27
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
// Handle negation patterns
|
|
31
|
+
if (trimmed.startsWith('!')) {
|
|
32
|
+
patterns.push({
|
|
33
|
+
pattern: trimmed.substring(1),
|
|
34
|
+
negated: true,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
patterns.push({
|
|
39
|
+
pattern: trimmed,
|
|
40
|
+
negated: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return patterns;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Detect and parse dependency manifests
|
|
48
|
+
*/
|
|
49
|
+
export function detectManifests(projectPath) {
|
|
50
|
+
const manifests = [];
|
|
51
|
+
// package.json (Node.js)
|
|
52
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
53
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
54
|
+
try {
|
|
55
|
+
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
56
|
+
manifests.push({
|
|
57
|
+
type: 'package.json',
|
|
58
|
+
path: packageJsonPath,
|
|
59
|
+
metadata: {
|
|
60
|
+
name: content.name,
|
|
61
|
+
version: content.version,
|
|
62
|
+
description: content.description,
|
|
63
|
+
},
|
|
64
|
+
dependencies: {
|
|
65
|
+
...content.dependencies,
|
|
66
|
+
...content.devDependencies,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Malformed JSON - return partial data
|
|
72
|
+
manifests.push({
|
|
73
|
+
type: 'package.json',
|
|
74
|
+
path: packageJsonPath,
|
|
75
|
+
metadata: { error: 'Malformed JSON' },
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// pom.xml (Maven)
|
|
80
|
+
const pomPath = path.join(projectPath, 'pom.xml');
|
|
81
|
+
if (fs.existsSync(pomPath)) {
|
|
82
|
+
const content = fs.readFileSync(pomPath, 'utf-8');
|
|
83
|
+
const groupId = content.match(/<groupId>(.*?)<\/groupId>/)?.[1];
|
|
84
|
+
const artifactId = content.match(/<artifactId>(.*?)<\/artifactId>/)?.[1];
|
|
85
|
+
const version = content.match(/<version>(.*?)<\/version>/)?.[1];
|
|
86
|
+
manifests.push({
|
|
87
|
+
type: 'pom.xml',
|
|
88
|
+
path: pomPath,
|
|
89
|
+
metadata: { groupId, artifactId, version },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// requirements.txt (Python)
|
|
93
|
+
const requirementsPath = path.join(projectPath, 'requirements.txt');
|
|
94
|
+
if (fs.existsSync(requirementsPath)) {
|
|
95
|
+
const content = fs.readFileSync(requirementsPath, 'utf-8');
|
|
96
|
+
const dependencies = {};
|
|
97
|
+
content.split('\n').forEach(line => {
|
|
98
|
+
const trimmed = line.trim();
|
|
99
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
100
|
+
const match = trimmed.match(/^([^=<>]+)(==|>=|<=|>|<)(.+)$/);
|
|
101
|
+
if (match) {
|
|
102
|
+
dependencies[match[1].trim()] = match[3].trim();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
manifests.push({
|
|
107
|
+
type: 'requirements.txt',
|
|
108
|
+
path: requirementsPath,
|
|
109
|
+
metadata: {},
|
|
110
|
+
dependencies,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// go.mod (Go)
|
|
114
|
+
const goModPath = path.join(projectPath, 'go.mod');
|
|
115
|
+
if (fs.existsSync(goModPath)) {
|
|
116
|
+
const content = fs.readFileSync(goModPath, 'utf-8');
|
|
117
|
+
const moduleName = content.match(/^module\s+(.+)$/m)?.[1];
|
|
118
|
+
manifests.push({
|
|
119
|
+
type: 'go.mod',
|
|
120
|
+
path: goModPath,
|
|
121
|
+
metadata: { module: moduleName },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
// Cargo.toml (Rust)
|
|
125
|
+
const cargoPath = path.join(projectPath, 'Cargo.toml');
|
|
126
|
+
if (fs.existsSync(cargoPath)) {
|
|
127
|
+
const content = fs.readFileSync(cargoPath, 'utf-8');
|
|
128
|
+
const name = content.match(/^\[package\][\s\S]*?name\s*=\s*"(.+?)"/m)?.[1];
|
|
129
|
+
const version = content.match(/^\[package\][\s\S]*?version\s*=\s*"(.+?)"/m)?.[1];
|
|
130
|
+
manifests.push({
|
|
131
|
+
type: 'Cargo.toml',
|
|
132
|
+
path: cargoPath,
|
|
133
|
+
metadata: { name, version },
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Gemfile (Ruby)
|
|
137
|
+
const gemfilePath = path.join(projectPath, 'Gemfile');
|
|
138
|
+
if (fs.existsSync(gemfilePath)) {
|
|
139
|
+
const content = fs.readFileSync(gemfilePath, 'utf-8');
|
|
140
|
+
const dependencies = {};
|
|
141
|
+
content.split('\n').forEach(line => {
|
|
142
|
+
const match = line.match(/gem\s+['"](.+?)['"](?:,\s*['"](.+?)['"])?/);
|
|
143
|
+
if (match) {
|
|
144
|
+
dependencies[match[1]] = match[2] || '*';
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
manifests.push({
|
|
148
|
+
type: 'Gemfile',
|
|
149
|
+
path: gemfilePath,
|
|
150
|
+
metadata: {},
|
|
151
|
+
dependencies,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return manifests;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Infer architecture patterns from project structure
|
|
158
|
+
*/
|
|
159
|
+
export function inferArchitecture(projectPath) {
|
|
160
|
+
const architectures = [];
|
|
161
|
+
// Check for monorepo indicators
|
|
162
|
+
if (fs.existsSync(path.join(projectPath, 'packages')) ||
|
|
163
|
+
fs.existsSync(path.join(projectPath, 'apps'))) {
|
|
164
|
+
architectures.push('monorepo');
|
|
165
|
+
}
|
|
166
|
+
// Check package.json workspaces
|
|
167
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
168
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
169
|
+
try {
|
|
170
|
+
const content = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
171
|
+
if (content.workspaces) {
|
|
172
|
+
architectures.push('monorepo');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
// Ignore malformed JSON
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Check for lerna.json
|
|
180
|
+
if (fs.existsSync(path.join(projectPath, 'lerna.json'))) {
|
|
181
|
+
architectures.push('monorepo');
|
|
182
|
+
}
|
|
183
|
+
// Check for microservices (multiple service directories with manifests)
|
|
184
|
+
try {
|
|
185
|
+
const entries = fs.readdirSync(projectPath, { withFileTypes: true });
|
|
186
|
+
const serviceDirs = entries.filter(e => e.isDirectory() &&
|
|
187
|
+
(e.name.includes('service') || e.name.includes('api')) &&
|
|
188
|
+
fs.existsSync(path.join(projectPath, e.name, 'package.json')));
|
|
189
|
+
if (serviceDirs.length >= 2) {
|
|
190
|
+
architectures.push('microservices');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
// Directory read error
|
|
195
|
+
}
|
|
196
|
+
// Check for MVC pattern
|
|
197
|
+
const hasMVC = fs.existsSync(path.join(projectPath, 'models')) &&
|
|
198
|
+
fs.existsSync(path.join(projectPath, 'views')) &&
|
|
199
|
+
fs.existsSync(path.join(projectPath, 'controllers'));
|
|
200
|
+
if (hasMVC) {
|
|
201
|
+
architectures.push('mvc');
|
|
202
|
+
}
|
|
203
|
+
// Check for Clean Architecture
|
|
204
|
+
const hasCleanArch = fs.existsSync(path.join(projectPath, 'domain')) &&
|
|
205
|
+
fs.existsSync(path.join(projectPath, 'application')) &&
|
|
206
|
+
fs.existsSync(path.join(projectPath, 'infrastructure'));
|
|
207
|
+
if (hasCleanArch) {
|
|
208
|
+
architectures.push('clean-architecture');
|
|
209
|
+
}
|
|
210
|
+
// Check for Hexagonal Architecture
|
|
211
|
+
const hasHexagonal = fs.existsSync(path.join(projectPath, 'adapters')) &&
|
|
212
|
+
fs.existsSync(path.join(projectPath, 'ports'));
|
|
213
|
+
if (hasHexagonal) {
|
|
214
|
+
architectures.push('hexagonal-architecture');
|
|
215
|
+
}
|
|
216
|
+
// Check for Layered Architecture
|
|
217
|
+
const srcPath = path.join(projectPath, 'src');
|
|
218
|
+
if (fs.existsSync(srcPath)) {
|
|
219
|
+
const hasLayered = fs.existsSync(path.join(srcPath, 'api')) &&
|
|
220
|
+
fs.existsSync(path.join(srcPath, 'services')) &&
|
|
221
|
+
fs.existsSync(path.join(srcPath, 'data'));
|
|
222
|
+
if (hasLayered) {
|
|
223
|
+
architectures.push('layered-architecture');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return architectures.length > 0 ? architectures : ['unknown'];
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Detect programming languages by file extensions
|
|
230
|
+
*/
|
|
231
|
+
export function detectLanguages(projectPath) {
|
|
232
|
+
const languageExtensions = {
|
|
233
|
+
'.ts': 'TypeScript',
|
|
234
|
+
'.tsx': 'TypeScript',
|
|
235
|
+
'.js': 'JavaScript',
|
|
236
|
+
'.jsx': 'JavaScript',
|
|
237
|
+
'.py': 'Python',
|
|
238
|
+
'.go': 'Go',
|
|
239
|
+
'.rs': 'Rust',
|
|
240
|
+
'.rb': 'Ruby',
|
|
241
|
+
'.java': 'Java',
|
|
242
|
+
};
|
|
243
|
+
const counts = {};
|
|
244
|
+
function scanDirectory(dirPath, depth = 0) {
|
|
245
|
+
if (depth > 5)
|
|
246
|
+
return; // Limit recursion depth
|
|
247
|
+
try {
|
|
248
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
// Skip common directories to avoid
|
|
251
|
+
if (entry.isDirectory() && ['node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
255
|
+
if (entry.isDirectory()) {
|
|
256
|
+
scanDirectory(fullPath, depth + 1);
|
|
257
|
+
}
|
|
258
|
+
else if (entry.isFile()) {
|
|
259
|
+
const ext = path.extname(entry.name);
|
|
260
|
+
const language = languageExtensions[ext];
|
|
261
|
+
if (language) {
|
|
262
|
+
counts[language] = (counts[language] || 0) + 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
// Permission error or other issue
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
scanDirectory(projectPath);
|
|
272
|
+
// Convert to percentages
|
|
273
|
+
const total = Object.values(counts).reduce((sum, count) => sum + count, 0);
|
|
274
|
+
if (total === 0)
|
|
275
|
+
return {};
|
|
276
|
+
const percentages = {};
|
|
277
|
+
for (const [lang, count] of Object.entries(counts)) {
|
|
278
|
+
percentages[lang] = Math.round((count / total) * 100);
|
|
279
|
+
}
|
|
280
|
+
return percentages;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Detect frameworks from manifests
|
|
284
|
+
*/
|
|
285
|
+
export function detectFrameworks(manifests) {
|
|
286
|
+
const frontend = new Set();
|
|
287
|
+
const backend = new Set();
|
|
288
|
+
const frameworkMap = {
|
|
289
|
+
'react': { type: 'frontend', name: 'React' },
|
|
290
|
+
'next': { type: 'frontend', name: 'Next.js' },
|
|
291
|
+
'vue': { type: 'frontend', name: 'Vue' },
|
|
292
|
+
'angular': { type: 'frontend', name: 'Angular' },
|
|
293
|
+
'svelte': { type: 'frontend', name: 'Svelte' },
|
|
294
|
+
'express': { type: 'backend', name: 'Express' },
|
|
295
|
+
'fastify': { type: 'backend', name: 'Fastify' },
|
|
296
|
+
'koa': { type: 'backend', name: 'Koa' },
|
|
297
|
+
'django': { type: 'backend', name: 'Django' },
|
|
298
|
+
'flask': { type: 'backend', name: 'Flask' },
|
|
299
|
+
'spring-boot': { type: 'backend', name: 'Spring Boot' },
|
|
300
|
+
'spring': { type: 'backend', name: 'Spring' },
|
|
301
|
+
};
|
|
302
|
+
for (const manifest of manifests) {
|
|
303
|
+
if (!manifest.dependencies)
|
|
304
|
+
continue;
|
|
305
|
+
for (const [depName] of Object.entries(manifest.dependencies)) {
|
|
306
|
+
const lowerDep = depName.toLowerCase();
|
|
307
|
+
for (const [key, value] of Object.entries(frameworkMap)) {
|
|
308
|
+
if (lowerDep.includes(key)) {
|
|
309
|
+
if (value.type === 'frontend') {
|
|
310
|
+
frontend.add(value.name);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
backend.add(value.name);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
frontend: Array.from(frontend),
|
|
321
|
+
backend: Array.from(backend),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Detect database drivers from manifests
|
|
326
|
+
*/
|
|
327
|
+
function detectDatabases(manifests) {
|
|
328
|
+
const databases = new Set();
|
|
329
|
+
const dbDrivers = {
|
|
330
|
+
'mongoose': 'MongoDB',
|
|
331
|
+
'mongodb': 'MongoDB',
|
|
332
|
+
'pg': 'PostgreSQL',
|
|
333
|
+
'postgres': 'PostgreSQL',
|
|
334
|
+
'mysql': 'MySQL',
|
|
335
|
+
'mysql2': 'MySQL',
|
|
336
|
+
'sqlite': 'SQLite',
|
|
337
|
+
'sqlite3': 'SQLite',
|
|
338
|
+
'redis': 'Redis',
|
|
339
|
+
};
|
|
340
|
+
for (const manifest of manifests) {
|
|
341
|
+
if (!manifest.dependencies)
|
|
342
|
+
continue;
|
|
343
|
+
for (const [depName] of Object.entries(manifest.dependencies)) {
|
|
344
|
+
const lowerDep = depName.toLowerCase();
|
|
345
|
+
for (const [key, value] of Object.entries(dbDrivers)) {
|
|
346
|
+
if (lowerDep.includes(key)) {
|
|
347
|
+
databases.add(value);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return Array.from(databases);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Extract project goal from README or package.json
|
|
356
|
+
*/
|
|
357
|
+
function extractProjectGoal(projectPath, manifests) {
|
|
358
|
+
// Check README.md first
|
|
359
|
+
const readmePath = path.join(projectPath, 'README.md');
|
|
360
|
+
if (fs.existsSync(readmePath)) {
|
|
361
|
+
const content = fs.readFileSync(readmePath, 'utf-8');
|
|
362
|
+
// Get first paragraph after title
|
|
363
|
+
const lines = content.split('\n');
|
|
364
|
+
for (let i = 0; i < Math.min(lines.length, 10); i++) {
|
|
365
|
+
const line = lines[i].trim();
|
|
366
|
+
if (line && !line.startsWith('#') && line.length > 20) {
|
|
367
|
+
return line;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// Fallback to package.json description
|
|
372
|
+
const packageManifest = manifests.find(m => m.type === 'package.json');
|
|
373
|
+
if (packageManifest?.metadata?.description) {
|
|
374
|
+
return packageManifest.metadata.description;
|
|
375
|
+
}
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Get list of files using git ls-files or fallback to manual scan
|
|
380
|
+
*/
|
|
381
|
+
function getFileList(projectPath) {
|
|
382
|
+
try {
|
|
383
|
+
// Try git ls-files first (faster and respects .gitignore)
|
|
384
|
+
const output = execSync('git ls-files --exclude-standard -co', {
|
|
385
|
+
cwd: projectPath,
|
|
386
|
+
encoding: 'utf-8',
|
|
387
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
388
|
+
});
|
|
389
|
+
return output.trim().split('\n').filter(Boolean);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
// Fallback to manual scan
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Read file with size limit (for large files, read only first/last 20 lines)
|
|
398
|
+
*/
|
|
399
|
+
function readFileWithLimit(filePath, maxSize = 1024 * 1024) {
|
|
400
|
+
const stats = fs.statSync(filePath);
|
|
401
|
+
if (stats.size > maxSize) {
|
|
402
|
+
// File is too large, read only first and last 20 lines
|
|
403
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
404
|
+
const lines = content.split('\n');
|
|
405
|
+
const first20 = lines.slice(0, 20).join('\n');
|
|
406
|
+
const last20 = lines.slice(-20).join('\n');
|
|
407
|
+
return `${first20}\n\n... (file truncated) ...\n\n${last20}`;
|
|
408
|
+
}
|
|
409
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Main function: Analyze entire codebase
|
|
413
|
+
*/
|
|
414
|
+
export function analyzeCodebase(projectPath) {
|
|
415
|
+
const manifests = detectManifests(projectPath);
|
|
416
|
+
const languages = detectLanguages(projectPath);
|
|
417
|
+
const frameworks = detectFrameworks(manifests);
|
|
418
|
+
const databases = detectDatabases(manifests);
|
|
419
|
+
const architecture = inferArchitecture(projectPath);
|
|
420
|
+
const projectGoal = extractProjectGoal(projectPath, manifests);
|
|
421
|
+
return {
|
|
422
|
+
languages,
|
|
423
|
+
frameworks,
|
|
424
|
+
databases,
|
|
425
|
+
architecture,
|
|
426
|
+
manifests,
|
|
427
|
+
projectGoal,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|