@girardelli/architect 2.2.0 → 5.0.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 +105 -116
- package/architect-run.sh +431 -0
- package/assets/banner-v3.html +561 -0
- package/dist/agent-generator/context-enricher.d.ts +58 -0
- package/dist/agent-generator/context-enricher.d.ts.map +1 -0
- package/dist/agent-generator/context-enricher.js +613 -0
- package/dist/agent-generator/context-enricher.js.map +1 -0
- package/dist/agent-generator/domain-inferrer.d.ts +52 -0
- package/dist/agent-generator/domain-inferrer.d.ts.map +1 -0
- package/dist/agent-generator/domain-inferrer.js +585 -0
- package/dist/agent-generator/domain-inferrer.js.map +1 -0
- package/dist/agent-generator/framework-detector.d.ts +40 -0
- package/dist/agent-generator/framework-detector.d.ts.map +1 -0
- package/dist/agent-generator/framework-detector.js +611 -0
- package/dist/agent-generator/framework-detector.js.map +1 -0
- package/dist/agent-generator/index.d.ts +47 -0
- package/dist/agent-generator/index.d.ts.map +1 -0
- package/dist/agent-generator/index.js +545 -0
- package/dist/agent-generator/index.js.map +1 -0
- package/dist/agent-generator/stack-detector.d.ts +14 -0
- package/dist/agent-generator/stack-detector.d.ts.map +1 -0
- package/dist/agent-generator/stack-detector.js +124 -0
- package/dist/agent-generator/stack-detector.js.map +1 -0
- package/dist/agent-generator/templates/core/agents.d.ts +17 -0
- package/dist/agent-generator/templates/core/agents.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/agents.js +1256 -0
- package/dist/agent-generator/templates/core/agents.js.map +1 -0
- package/dist/agent-generator/templates/core/architecture-rules.d.ts +7 -0
- package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/architecture-rules.js +274 -0
- package/dist/agent-generator/templates/core/architecture-rules.js.map +1 -0
- package/dist/agent-generator/templates/core/general-rules.d.ts +8 -0
- package/dist/agent-generator/templates/core/general-rules.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/general-rules.js +301 -0
- package/dist/agent-generator/templates/core/general-rules.js.map +1 -0
- package/dist/agent-generator/templates/core/hooks-generator.d.ts +21 -0
- package/dist/agent-generator/templates/core/hooks-generator.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/hooks-generator.js +233 -0
- package/dist/agent-generator/templates/core/hooks-generator.js.map +1 -0
- package/dist/agent-generator/templates/core/index-md.d.ts +7 -0
- package/dist/agent-generator/templates/core/index-md.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/index-md.js +246 -0
- package/dist/agent-generator/templates/core/index-md.js.map +1 -0
- package/dist/agent-generator/templates/core/orchestrator.d.ts +8 -0
- package/dist/agent-generator/templates/core/orchestrator.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/orchestrator.js +422 -0
- package/dist/agent-generator/templates/core/orchestrator.js.map +1 -0
- package/dist/agent-generator/templates/core/preflight.d.ts +8 -0
- package/dist/agent-generator/templates/core/preflight.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/preflight.js +213 -0
- package/dist/agent-generator/templates/core/preflight.js.map +1 -0
- package/dist/agent-generator/templates/core/quality-gates.d.ts +11 -0
- package/dist/agent-generator/templates/core/quality-gates.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/quality-gates.js +254 -0
- package/dist/agent-generator/templates/core/quality-gates.js.map +1 -0
- package/dist/agent-generator/templates/core/security-rules.d.ts +7 -0
- package/dist/agent-generator/templates/core/security-rules.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/security-rules.js +528 -0
- package/dist/agent-generator/templates/core/security-rules.js.map +1 -0
- package/dist/agent-generator/templates/core/skills-generator.d.ts +19 -0
- package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/skills-generator.js +546 -0
- package/dist/agent-generator/templates/core/skills-generator.js.map +1 -0
- package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +7 -0
- package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/workflow-fix-bug.js +237 -0
- package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
- package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +8 -0
- package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/workflow-new-feature.js +321 -0
- package/dist/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
- package/dist/agent-generator/templates/core/workflow-review.d.ts +7 -0
- package/dist/agent-generator/templates/core/workflow-review.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/workflow-review.js +104 -0
- package/dist/agent-generator/templates/core/workflow-review.js.map +1 -0
- package/dist/agent-generator/templates/domain/index.d.ts +22 -0
- package/dist/agent-generator/templates/domain/index.d.ts.map +1 -0
- package/dist/agent-generator/templates/domain/index.js +1176 -0
- package/dist/agent-generator/templates/domain/index.js.map +1 -0
- package/dist/agent-generator/templates/stack/index.d.ts +8 -0
- package/dist/agent-generator/templates/stack/index.d.ts.map +1 -0
- package/dist/agent-generator/templates/stack/index.js +695 -0
- package/dist/agent-generator/templates/stack/index.js.map +1 -0
- package/dist/agent-generator/templates/template-helpers.d.ts +75 -0
- package/dist/agent-generator/templates/template-helpers.d.ts.map +1 -0
- package/dist/agent-generator/templates/template-helpers.js +726 -0
- package/dist/agent-generator/templates/template-helpers.js.map +1 -0
- package/dist/agent-generator/types.d.ts +196 -0
- package/dist/agent-generator/types.d.ts.map +1 -0
- package/dist/agent-generator/types.js +27 -0
- package/dist/agent-generator/types.js.map +1 -0
- package/dist/analyzer.d.ts +5 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +46 -5
- package/dist/analyzer.js.map +1 -1
- package/dist/analyzers/forecast.d.ts +85 -0
- package/dist/analyzers/forecast.d.ts.map +1 -0
- package/dist/analyzers/forecast.js +337 -0
- package/dist/analyzers/forecast.js.map +1 -0
- package/dist/analyzers/git-cache.d.ts +7 -0
- package/dist/analyzers/git-cache.d.ts.map +1 -0
- package/dist/analyzers/git-cache.js +41 -0
- package/dist/analyzers/git-cache.js.map +1 -0
- package/dist/analyzers/git-history.d.ts +113 -0
- package/dist/analyzers/git-history.d.ts.map +1 -0
- package/dist/analyzers/git-history.js +333 -0
- package/dist/analyzers/git-history.js.map +1 -0
- package/dist/analyzers/index.d.ts +10 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +7 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/temporal-scorer.d.ts +72 -0
- package/dist/analyzers/temporal-scorer.d.ts.map +1 -0
- package/dist/analyzers/temporal-scorer.js +140 -0
- package/dist/analyzers/temporal-scorer.js.map +1 -0
- package/dist/anti-patterns.d.ts +7 -0
- package/dist/anti-patterns.d.ts.map +1 -1
- package/dist/anti-patterns.js +25 -6
- package/dist/anti-patterns.js.map +1 -1
- package/dist/cli.d.ts +2 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +275 -113
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +48 -11
- package/dist/config.js.map +1 -1
- package/dist/html-reporter.d.ts +3 -1
- package/dist/html-reporter.d.ts.map +1 -1
- package/dist/html-reporter.js +248 -12
- package/dist/html-reporter.js.map +1 -1
- package/dist/index.d.ts +16 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -4
- package/dist/index.js.map +1 -1
- package/dist/project-summarizer.d.ts +38 -0
- package/dist/project-summarizer.d.ts.map +1 -0
- package/dist/project-summarizer.js +463 -0
- package/dist/project-summarizer.js.map +1 -0
- package/dist/refactor-reporter.js +1 -1
- package/dist/scanner.d.ts +8 -2
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +153 -113
- package/dist/scanner.js.map +1 -1
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +24 -11
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -3
- package/src/agent-generator/context-enricher.ts +672 -0
- package/src/agent-generator/domain-inferrer.ts +635 -0
- package/src/agent-generator/framework-detector.ts +669 -0
- package/src/agent-generator/index.ts +634 -0
- package/src/agent-generator/stack-detector.ts +115 -0
- package/src/agent-generator/templates/core/agents.ts +1296 -0
- package/src/agent-generator/templates/core/architecture-rules.ts +287 -0
- package/src/agent-generator/templates/core/general-rules.ts +306 -0
- package/src/agent-generator/templates/core/hooks-generator.ts +242 -0
- package/src/agent-generator/templates/core/index-md.ts +260 -0
- package/src/agent-generator/templates/core/orchestrator.ts +459 -0
- package/src/agent-generator/templates/core/preflight.ts +215 -0
- package/src/agent-generator/templates/core/quality-gates.ts +256 -0
- package/src/agent-generator/templates/core/security-rules.ts +543 -0
- package/src/agent-generator/templates/core/skills-generator.ts +585 -0
- package/src/agent-generator/templates/core/workflow-fix-bug.ts +239 -0
- package/src/agent-generator/templates/core/workflow-new-feature.ts +323 -0
- package/src/agent-generator/templates/core/workflow-review.ts +106 -0
- package/src/agent-generator/templates/domain/index.ts +1201 -0
- package/src/agent-generator/templates/stack/index.ts +705 -0
- package/src/agent-generator/templates/template-helpers.ts +776 -0
- package/src/agent-generator/types.ts +232 -0
- package/src/analyzer.ts +51 -5
- package/src/analyzers/forecast.ts +496 -0
- package/src/analyzers/git-cache.ts +52 -0
- package/src/analyzers/git-history.ts +488 -0
- package/src/analyzers/index.ts +33 -0
- package/src/analyzers/temporal-scorer.ts +227 -0
- package/src/anti-patterns.ts +29 -6
- package/src/cli.ts +316 -117
- package/src/config.ts +52 -11
- package/src/html-reporter.ts +263 -13
- package/src/index.ts +93 -10
- package/src/project-summarizer.ts +521 -0
- package/src/refactor-reporter.ts +1 -1
- package/src/scanner.ts +136 -90
- package/src/scorer.ts +26 -11
- package/src/types.ts +27 -0
- package/tests/agent-generator.test.ts +427 -0
- package/tests/analyzers-integration.test.ts +174 -0
- package/tests/architect-adapter-enrichment.test.ts +9 -0
- package/tests/context-enricher.test.ts +971 -0
- package/tests/fixtures/monorepo/package.json +6 -0
- package/tests/fixtures/monorepo/packages/app/package.json +12 -0
- package/tests/fixtures/monorepo/packages/app/src/index.ts +6 -0
- package/tests/fixtures/monorepo/packages/core/package.json +7 -0
- package/tests/fixtures/monorepo/packages/core/src/index.ts +7 -0
- package/tests/forecast.test.ts +509 -0
- package/tests/framework-detector.test.ts +1172 -0
- package/tests/git-history.test.ts +254 -0
- package/tests/monorepo-scan.test.ts +170 -0
- package/tests/scanner.test.ts +7 -8
- package/tests/scorer.test.ts +594 -0
- package/tests/stack-detector.test.ts +241 -0
- package/tests/template-generation.test.ts +706 -0
- package/tests/template-helpers.test.ts +1152 -0
- package/tests/temporal-scorer.test.ts +307 -0
- package/dist/agent-generator.d.ts +0 -106
- package/dist/agent-generator.d.ts.map +0 -1
- package/dist/agent-generator.js +0 -1398
- package/dist/agent-generator.js.map +0 -1
- package/src/agent-generator.ts +0 -1526
package/src/scanner.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { globSync } from 'glob';
|
|
2
|
-
import { readFileSync, lstatSync } from 'fs';
|
|
3
|
-
import { join, relative, extname } from 'path';
|
|
4
|
-
import { FileNode, ProjectInfo, ArchitectConfig } from './types.js';
|
|
2
|
+
import { readFileSync, lstatSync, existsSync } from 'fs';
|
|
3
|
+
import { join, relative, extname, resolve } from 'path';
|
|
4
|
+
import { FileNode, ProjectInfo, ArchitectConfig, WorkspaceInfo } from './types.js';
|
|
5
5
|
|
|
6
6
|
export class ProjectScanner {
|
|
7
7
|
private projectPath: string;
|
|
@@ -17,14 +17,19 @@ export class ProjectScanner {
|
|
|
17
17
|
const files = this.scanDirectory();
|
|
18
18
|
const fileTree = this.buildFileTree(files);
|
|
19
19
|
|
|
20
|
-
// Detect
|
|
21
|
-
const
|
|
22
|
-
const allFilesForDetection = [...files, ...parentPackageJsons];
|
|
23
|
-
const frameworks = this.detectFrameworks(allFilesForDetection);
|
|
20
|
+
// Detect workspaces from root package.json
|
|
21
|
+
const workspaces = this.detectWorkspaces();
|
|
24
22
|
|
|
23
|
+
// Detect frameworks ONLY from root + workspace package.json files (never from node_modules)
|
|
24
|
+
const workspacePkgJsonPaths = [
|
|
25
|
+
join(this.projectPath, 'package.json'),
|
|
26
|
+
...workspaces.map(ws => join(ws.path, 'package.json')),
|
|
27
|
+
].filter(p => existsSync(p));
|
|
28
|
+
|
|
29
|
+
const frameworks = this.detectFrameworks(workspacePkgJsonPaths);
|
|
25
30
|
const languages = this.detectLanguages(files);
|
|
26
31
|
const totalLines = this.countTotalLines(files);
|
|
27
|
-
const projectName = this.resolveProjectName(
|
|
32
|
+
const projectName = this.resolveProjectName(workspacePkgJsonPaths);
|
|
28
33
|
|
|
29
34
|
return {
|
|
30
35
|
path: this.projectPath,
|
|
@@ -34,31 +39,66 @@ export class ProjectScanner {
|
|
|
34
39
|
totalLines,
|
|
35
40
|
primaryLanguages: languages,
|
|
36
41
|
fileTree,
|
|
42
|
+
workspaces: workspaces.length > 0 ? workspaces : undefined,
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
/**
|
|
41
|
-
*
|
|
47
|
+
* Detect npm/yarn/pnpm workspaces from root package.json.
|
|
48
|
+
* Reads the "workspaces" field and resolves each workspace to its package.json.
|
|
42
49
|
*/
|
|
43
|
-
private
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
private detectWorkspaces(): WorkspaceInfo[] {
|
|
51
|
+
const rootPkgPath = join(this.projectPath, 'package.json');
|
|
52
|
+
if (!existsSync(rootPkgPath)) return [];
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'));
|
|
56
|
+
let workspaceGlobs: string[] = [];
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(rootPkg.workspaces)) {
|
|
59
|
+
workspaceGlobs = rootPkg.workspaces;
|
|
60
|
+
} else if (rootPkg.workspaces?.packages && Array.isArray(rootPkg.workspaces.packages)) {
|
|
61
|
+
workspaceGlobs = rootPkg.workspaces.packages;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (workspaceGlobs.length === 0) return [];
|
|
65
|
+
|
|
66
|
+
const workspaces: WorkspaceInfo[] = [];
|
|
67
|
+
|
|
68
|
+
for (const pattern of workspaceGlobs) {
|
|
69
|
+
// Resolve glob patterns like "packages/*"
|
|
70
|
+
const dirs = globSync(pattern, {
|
|
71
|
+
cwd: this.projectPath,
|
|
72
|
+
absolute: true,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
for (const dir of dirs) {
|
|
76
|
+
const pkgPath = join(dir, 'package.json');
|
|
77
|
+
if (!existsSync(pkgPath)) continue;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
81
|
+
workspaces.push({
|
|
82
|
+
name: pkg.name || relative(this.projectPath, dir),
|
|
83
|
+
path: dir,
|
|
84
|
+
relativePath: relative(this.projectPath, dir),
|
|
85
|
+
description: pkg.description || '',
|
|
86
|
+
version: pkg.version || '0.0.0',
|
|
87
|
+
dependencies: pkg.dependencies || {},
|
|
88
|
+
devDependencies: pkg.devDependencies || {},
|
|
89
|
+
bin: pkg.bin || undefined,
|
|
90
|
+
main: pkg.main || undefined,
|
|
91
|
+
});
|
|
92
|
+
} catch {
|
|
93
|
+
// Skip unparseable package.json
|
|
94
|
+
}
|
|
95
|
+
}
|
|
56
96
|
}
|
|
57
|
-
dir = join(dir, '..');
|
|
58
|
-
depth++;
|
|
59
|
-
}
|
|
60
97
|
|
|
61
|
-
|
|
98
|
+
return workspaces;
|
|
99
|
+
} catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
62
102
|
}
|
|
63
103
|
|
|
64
104
|
/**
|
|
@@ -81,7 +121,6 @@ export class ProjectScanner {
|
|
|
81
121
|
|
|
82
122
|
private scanDirectory(): string[] {
|
|
83
123
|
const ignorePatterns = this.config.ignore || [];
|
|
84
|
-
const negatedPatterns = ignorePatterns.map((p) => `!**/${p}/**`);
|
|
85
124
|
|
|
86
125
|
const files = globSync('**/*', {
|
|
87
126
|
cwd: this.projectPath,
|
|
@@ -167,82 +206,89 @@ export class ProjectScanner {
|
|
|
167
206
|
return root;
|
|
168
207
|
}
|
|
169
208
|
|
|
170
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Detect frameworks ONLY from specified package.json files.
|
|
211
|
+
* Never reads package.json from node_modules.
|
|
212
|
+
* No string-matching fallback — only structured dependency key detection.
|
|
213
|
+
*/
|
|
214
|
+
private detectFrameworks(packageJsonPaths: string[]): Set<string> {
|
|
171
215
|
const frameworks = new Set<string>();
|
|
172
216
|
|
|
173
|
-
for (const file of
|
|
174
|
-
if (file.endsWith('package.json'))
|
|
175
|
-
try {
|
|
176
|
-
const content = readFileSync(file, 'utf-8');
|
|
177
|
-
const parsed = JSON.parse(content);
|
|
178
|
-
const allDeps = {
|
|
179
|
-
...parsed.dependencies,
|
|
180
|
-
...parsed.devDependencies,
|
|
181
|
-
};
|
|
217
|
+
for (const file of packageJsonPaths) {
|
|
218
|
+
if (!file.endsWith('package.json')) continue;
|
|
182
219
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (allDeps['react'] || allDeps['react-dom']) frameworks.add('React');
|
|
186
|
-
if (allDeps['@angular/core']) frameworks.add('Angular');
|
|
187
|
-
if (allDeps['vue'] || allDeps['@vue/core']) frameworks.add('Vue.js');
|
|
188
|
-
if (allDeps['express']) frameworks.add('Express.js');
|
|
189
|
-
if (allDeps['next']) frameworks.add('Next.js');
|
|
190
|
-
if (allDeps['fastify']) frameworks.add('Fastify');
|
|
191
|
-
if (allDeps['typeorm']) frameworks.add('TypeORM');
|
|
192
|
-
if (allDeps['prisma'] || allDeps['@prisma/client']) frameworks.add('Prisma');
|
|
193
|
-
if (allDeps['sequelize']) frameworks.add('Sequelize');
|
|
194
|
-
if (allDeps['mongoose']) frameworks.add('Mongoose');
|
|
195
|
-
} catch {
|
|
196
|
-
// Fallback: simple string matching
|
|
197
|
-
try {
|
|
198
|
-
const content = readFileSync(file, 'utf-8');
|
|
199
|
-
if (content.includes('@nestjs')) frameworks.add('NestJS');
|
|
200
|
-
if (content.includes('react')) frameworks.add('React');
|
|
201
|
-
if (content.includes('angular')) frameworks.add('Angular');
|
|
202
|
-
if (content.includes('vue')) frameworks.add('Vue.js');
|
|
203
|
-
if (content.includes('express')) frameworks.add('Express.js');
|
|
204
|
-
if (content.includes('next')) frameworks.add('Next.js');
|
|
205
|
-
} catch {
|
|
206
|
-
// skip
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
220
|
+
// Safety: skip any path that includes node_modules
|
|
221
|
+
if (file.includes('node_modules')) continue;
|
|
210
222
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
try {
|
|
224
|
+
const content = readFileSync(file, 'utf-8');
|
|
225
|
+
const parsed = JSON.parse(content);
|
|
226
|
+
const allDeps = {
|
|
227
|
+
...parsed.dependencies,
|
|
228
|
+
...parsed.devDependencies,
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Detect from actual dependency keys — no string fallback
|
|
232
|
+
if (allDeps['@nestjs/core'] || allDeps['@nestjs/common']) frameworks.add('NestJS');
|
|
233
|
+
if (allDeps['react'] || allDeps['react-dom']) frameworks.add('React');
|
|
234
|
+
if (allDeps['@angular/core']) frameworks.add('Angular');
|
|
235
|
+
if (allDeps['vue'] || allDeps['@vue/core']) frameworks.add('Vue.js');
|
|
236
|
+
if (allDeps['express']) frameworks.add('Express.js');
|
|
237
|
+
if (allDeps['next']) frameworks.add('Next.js');
|
|
238
|
+
if (allDeps['fastify']) frameworks.add('Fastify');
|
|
239
|
+
if (allDeps['typeorm']) frameworks.add('TypeORM');
|
|
240
|
+
if (allDeps['prisma'] || allDeps['@prisma/client']) frameworks.add('Prisma');
|
|
241
|
+
if (allDeps['sequelize']) frameworks.add('Sequelize');
|
|
242
|
+
if (allDeps['mongoose']) frameworks.add('Mongoose');
|
|
243
|
+
if (allDeps['@modelcontextprotocol/sdk']) frameworks.add('MCP SDK');
|
|
244
|
+
if (allDeps['probot']) frameworks.add('Probot');
|
|
245
|
+
if (allDeps['hono']) frameworks.add('Hono');
|
|
246
|
+
} catch {
|
|
247
|
+
// Skip unparseable files — NO fallback string matching
|
|
219
248
|
}
|
|
249
|
+
}
|
|
220
250
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
251
|
+
// Check for pom.xml only at project root
|
|
252
|
+
const pomPath = join(this.projectPath, 'pom.xml');
|
|
253
|
+
if (existsSync(pomPath)) {
|
|
254
|
+
try {
|
|
255
|
+
const content = readFileSync(pomPath, 'utf-8');
|
|
256
|
+
if (content.includes('spring-boot')) frameworks.add('Spring Boot');
|
|
257
|
+
if (content.includes('spring') && !content.includes('spring-boot')) frameworks.add('Spring');
|
|
258
|
+
} catch {
|
|
259
|
+
// skip
|
|
230
260
|
}
|
|
261
|
+
}
|
|
231
262
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
263
|
+
// Check for requirements.txt only at project root
|
|
264
|
+
const reqPath = join(this.projectPath, 'requirements.txt');
|
|
265
|
+
if (existsSync(reqPath)) {
|
|
266
|
+
try {
|
|
267
|
+
const content = readFileSync(reqPath, 'utf-8');
|
|
268
|
+
if (content.includes('django')) frameworks.add('Django');
|
|
269
|
+
if (content.includes('flask')) frameworks.add('Flask');
|
|
270
|
+
if (content.includes('fastapi')) frameworks.add('FastAPI');
|
|
271
|
+
} catch {
|
|
272
|
+
// skip
|
|
239
273
|
}
|
|
274
|
+
}
|
|
240
275
|
|
|
241
|
-
|
|
242
|
-
|
|
276
|
+
// Check for Gemfile only at project root
|
|
277
|
+
const gemPath = join(this.projectPath, 'Gemfile');
|
|
278
|
+
if (existsSync(gemPath)) {
|
|
279
|
+
try {
|
|
280
|
+
const content = readFileSync(gemPath, 'utf-8');
|
|
281
|
+
if (content.includes('rails')) frameworks.add('Ruby on Rails');
|
|
282
|
+
} catch {
|
|
283
|
+
// skip
|
|
243
284
|
}
|
|
244
285
|
}
|
|
245
286
|
|
|
287
|
+
// Check for go.mod only at project root
|
|
288
|
+
if (existsSync(join(this.projectPath, 'go.mod'))) {
|
|
289
|
+
frameworks.add('Go');
|
|
290
|
+
}
|
|
291
|
+
|
|
246
292
|
return frameworks;
|
|
247
293
|
}
|
|
248
294
|
|
package/src/scorer.ts
CHANGED
|
@@ -24,7 +24,7 @@ export class ArchitectureScorer {
|
|
|
24
24
|
this.calculateModularity(edges, totalFiles);
|
|
25
25
|
this.calculateCoupling(edges, totalFiles);
|
|
26
26
|
this.calculateCohesion(edges);
|
|
27
|
-
this.calculateLayering(antiPatterns);
|
|
27
|
+
this.calculateLayering(antiPatterns, totalFiles);
|
|
28
28
|
|
|
29
29
|
const components = [
|
|
30
30
|
{
|
|
@@ -213,7 +213,7 @@ export class ArchitectureScorer {
|
|
|
213
213
|
return fromTopLevel === toTopLevel;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
private calculateLayering(antiPatterns: AntiPattern[]): void {
|
|
216
|
+
private calculateLayering(antiPatterns: AntiPattern[], totalFiles?: number): void {
|
|
217
217
|
const layeringViolations = antiPatterns.filter(
|
|
218
218
|
(p) =>
|
|
219
219
|
p.name === 'Leaky Abstraction' ||
|
|
@@ -223,16 +223,31 @@ export class ArchitectureScorer {
|
|
|
223
223
|
|
|
224
224
|
if (layeringViolations === 0) {
|
|
225
225
|
this.layering = 95;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Use ratio-based scoring: violations per 100 files
|
|
230
|
+
// This makes scoring fair regardless of project size
|
|
231
|
+
const fileCount = Math.max(totalFiles || 50, 10);
|
|
232
|
+
const violationRatio = layeringViolations / fileCount;
|
|
233
|
+
|
|
234
|
+
if (violationRatio < 0.02) {
|
|
235
|
+
// < 2% — e.g. 1 violation in 50 files
|
|
236
|
+
this.layering = 90;
|
|
237
|
+
} else if (violationRatio < 0.05) {
|
|
238
|
+
// < 5% — e.g. 2-3 violations in 50 files
|
|
239
|
+
this.layering = 80;
|
|
240
|
+
} else if (violationRatio < 0.1) {
|
|
241
|
+
// < 10% — e.g. 5 violations in 50 files
|
|
242
|
+
this.layering = 65;
|
|
243
|
+
} else if (violationRatio < 0.2) {
|
|
244
|
+
// < 20% — significant issues
|
|
245
|
+
this.layering = 50;
|
|
246
|
+
} else if (violationRatio < 0.35) {
|
|
247
|
+
this.layering = 35;
|
|
234
248
|
} else {
|
|
235
|
-
|
|
249
|
+
// > 35% — severe layering problems
|
|
250
|
+
this.layering = 20;
|
|
236
251
|
}
|
|
237
252
|
}
|
|
238
253
|
}
|
package/src/types.ts
CHANGED
|
@@ -52,6 +52,18 @@ export interface ArchitectureScore {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
export interface WorkspaceInfo {
|
|
56
|
+
name: string;
|
|
57
|
+
path: string;
|
|
58
|
+
relativePath: string;
|
|
59
|
+
description: string;
|
|
60
|
+
version: string;
|
|
61
|
+
dependencies: Record<string, string>;
|
|
62
|
+
devDependencies: Record<string, string>;
|
|
63
|
+
bin?: Record<string, string>;
|
|
64
|
+
main?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
export interface ProjectInfo {
|
|
56
68
|
path: string;
|
|
57
69
|
name: string;
|
|
@@ -60,6 +72,7 @@ export interface ProjectInfo {
|
|
|
60
72
|
totalLines: number;
|
|
61
73
|
primaryLanguages: string[];
|
|
62
74
|
fileTree?: FileNode;
|
|
75
|
+
workspaces?: WorkspaceInfo[];
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
export interface AnalysisReport {
|
|
@@ -82,6 +95,16 @@ export interface AnalysisReport {
|
|
|
82
95
|
mermaid: string;
|
|
83
96
|
type: 'component' | 'layer' | 'dependency';
|
|
84
97
|
};
|
|
98
|
+
projectSummary?: ProjectSummary;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ProjectSummary {
|
|
102
|
+
description: string;
|
|
103
|
+
purpose: string;
|
|
104
|
+
modules: { name: string; files: number; description: string }[];
|
|
105
|
+
techStack: string[];
|
|
106
|
+
entryPoints: string[];
|
|
107
|
+
keywords: string[];
|
|
85
108
|
}
|
|
86
109
|
|
|
87
110
|
export interface ArchitectConfig {
|
|
@@ -104,6 +127,10 @@ export interface ArchitectConfig {
|
|
|
104
127
|
cohesion?: number;
|
|
105
128
|
layering?: number;
|
|
106
129
|
};
|
|
130
|
+
monorepo?: {
|
|
131
|
+
enabled?: boolean;
|
|
132
|
+
treatPackagesAsModules?: boolean;
|
|
133
|
+
};
|
|
107
134
|
}
|
|
108
135
|
|
|
109
136
|
export interface ParsedImport {
|