@girardelli/architect 2.2.0 → 4.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/__test_agent_output__/INDEX.md +1 -0
- package/__test_agent_output__/agents/AGENT-ORCHESTRATOR.md +1 -0
- package/__test_agent_output__/agents/DATABASE-ENGINEER.md +174 -0
- package/__test_agent_output__/agents/QA-TEST-ENGINEER.md +138 -0
- package/__test_agent_output__/agents/SECURITY-AUDITOR.md +106 -0
- package/__test_agent_output__/agents/TECH-DEBT-CONTROLLER.md +104 -0
- package/__test_agent_output__/agents/TYPESCRIPT-BACKEND-DEVELOPER.md +135 -0
- package/__test_agent_output__/guards/CODE-REVIEW-CHECKLIST.md +95 -0
- package/__test_agent_output__/guards/PREFLIGHT.md +200 -0
- package/__test_agent_output__/guards/QUALITY-GATES.md +1 -0
- package/__test_agent_output__/rules/00-general.md +229 -0
- package/__test_agent_output__/rules/01-architecture.md +191 -0
- package/__test_agent_output__/rules/02-security.md +402 -0
- package/__test_agent_output__/rules/03-nestjs.md +124 -0
- package/__test_agent_output__/templates/ADR.md +95 -0
- package/__test_agent_output__/templates/BDD.md +58 -0
- package/__test_agent_output__/templates/C4.md +68 -0
- package/__test_agent_output__/templates/TDD.md +86 -0
- package/__test_agent_output__/templates/THREAT-MODEL.md +82 -0
- package/__test_agent_output__/workflows/fix-bug.md +228 -0
- package/__test_agent_output__/workflows/new-feature.md +311 -0
- package/__test_agent_output__/workflows/review.md +95 -0
- package/__test_context_7RvUrO/src/modules/empty/empty.ts +0 -0
- package/__test_context_Rf5fNJ/src/modules/mixed/mixed.ts +5 -0
- package/__test_context_WRCnYH/src/modules/test/test.ts +10 -0
- package/__test_context_YsnVS3/src/modules/test/test.ts +10 -0
- package/__test_context_w7XZeH/src/modules/mixed/mixed.ts +5 -0
- package/__test_context_y5noh6/src/modules/empty/empty.ts +0 -0
- package/__test_framework__24OjAu/package.json +1 -0
- package/__test_framework__3ZDZsx/pyproject.toml +8 -0
- package/__test_framework__4T54Jn/package.json +1 -0
- package/__test_framework__4tlXu9/pyproject.toml +8 -0
- package/__test_framework__6boWqQ/Pipfile +6 -0
- package/__test_framework__6gygMU/pom.xml +10 -0
- package/__test_framework__6kxj0N/go.mod +8 -0
- package/__test_framework__7CEoXw/pom.xml +10 -0
- package/__test_framework__85DDz0/Pipfile +6 -0
- package/__test_framework__9WrRIr/pom.xml +7 -0
- package/__test_framework__ANqGKl/Gemfile +5 -0
- package/__test_framework__BCXTEM/go.mod +3 -0
- package/__test_framework__BHiPNq/setup.py +2 -0
- package/__test_framework__BqkiKv/package.json +1 -0
- package/__test_framework__C5yd8X/Pipfile.lock +1 -0
- package/__test_framework__C5yd8X/requirements.txt +1 -0
- package/__test_framework__C87d3a/manage.py +1 -0
- package/__test_framework__C87d3a/requirements.txt +2 -0
- package/__test_framework__DXNwc5/build.gradle +7 -0
- package/__test_framework__GhHSt3/build.gradle.kts +4 -0
- package/__test_framework__GzklJP/Cargo.toml +7 -0
- package/__test_framework__H4hd13/go.mod +8 -0
- package/__test_framework__HKjOXO/composer.json +1 -0
- package/__test_framework__HaDN45/Gemfile +3 -0
- package/__test_framework__IBO7YG/pyproject.toml +9 -0
- package/__test_framework__JwSOyF/pyproject.toml +6 -0
- package/__test_framework__K6HrCr/build.gradle +2 -0
- package/__test_framework__KzRPlh/pubspec.yaml +9 -0
- package/__test_framework__L6uIym/pyproject.toml +6 -0
- package/__test_framework__LOdoGK/requirements.txt +4 -0
- package/__test_framework__LgHzss/package.json +1 -0
- package/__test_framework__M76M6q/Gemfile +5 -0
- package/__test_framework__Mr9vWW/composer.json +1 -0
- package/__test_framework__N03Gnv/package.json +1 -0
- package/__test_framework__Num4UE/requirements +1 -0
- package/__test_framework__OAGw3Y/build.gradle +7 -0
- package/__test_framework__OQc8yG/pubspec.yaml +9 -0
- package/__test_framework__OwKZcd/requirements.txt +3 -0
- package/__test_framework__P0gFv7/requirements +1 -0
- package/__test_framework__PN55Rq/package.json +1 -0
- package/__test_framework__PQiqX8/pubspec.yaml +3 -0
- package/__test_framework__RBHsg7/composer.json +1 -0
- package/__test_framework__RHxif4/Cargo.toml +7 -0
- package/__test_framework__T0v0p1/Cargo.toml +4 -0
- package/__test_framework__Tu0clt/Pipfile.lock +1 -0
- package/__test_framework__Tu0clt/requirements.txt +1 -0
- package/__test_framework__TwDj9P/Cargo.toml +4 -0
- package/__test_framework__VQJNC4/pom.xml +7 -0
- package/__test_framework__W6sm05/package.json +1 -0
- package/__test_framework__W7vBLy/pyproject.toml +4 -0
- package/__test_framework__WNJOWT/setup.py +2 -0
- package/__test_framework__WSJs7U/package.json +1 -0
- package/__test_framework__YQ5VpA/build.gradle.kts +4 -0
- package/__test_framework__ZNEUEs/package.json +1 -0
- package/__test_framework__Znt922/pom.xml +7 -0
- package/__test_framework__azyg0h/pom.xml +7 -0
- package/__test_framework__c6otLr/package.json +1 -0
- package/__test_framework__cl9S9G/build.gradle +2 -0
- package/__test_framework__eilvV4/composer.json +1 -0
- package/__test_framework__gQZxXO/manage.py +1 -0
- package/__test_framework__gQZxXO/requirements.txt +2 -0
- package/__test_framework__ghvl26/poetry.lock +1 -0
- package/__test_framework__ghvl26/pyproject.toml +2 -0
- package/__test_framework__hR7b9U/Makefile +11 -0
- package/__test_framework__iESVsi/composer.json +1 -0
- package/__test_framework__jm6TJy/package.json +1 -0
- package/__test_framework__kBUpjs/pyproject.toml +9 -0
- package/__test_framework__kqoZrw/requirements.txt +4 -0
- package/__test_framework__lWkoyO/pyproject.toml +4 -0
- package/__test_framework__mTKnUO/package.json +1 -0
- package/__test_framework__nCeZwe/Makefile +11 -0
- package/__test_framework__oljsU0/package.json +1 -0
- package/__test_framework__osRG4q/go.mod +3 -0
- package/__test_framework__pCHH4F/package.json +1 -0
- package/__test_framework__pExx6E/Gemfile +3 -0
- package/__test_framework__pyBoGd/pyproject.toml +5 -0
- package/__test_framework__qw16VQ/package.json +1 -0
- package/__test_framework__rRayrG/package.json +1 -0
- package/__test_framework__s82zO5/package.json +1 -0
- package/__test_framework__tp8MFK/pyproject.toml +5 -0
- package/__test_framework__w44k4w/composer.json +1 -0
- package/__test_framework__yefPZY/poetry.lock +1 -0
- package/__test_framework__yefPZY/pyproject.toml +2 -0
- package/__test_framework__zCiyDT/requirements.txt +3 -0
- package/__test_framework__zGZN3j/pubspec.yaml +3 -0
- package/__test_framework__zXpnxL/package.json +1 -0
- 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 +581 -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 +575 -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 +33 -0
- package/dist/agent-generator/index.d.ts.map +1 -0
- package/dist/agent-generator/index.js +477 -0
- package/dist/agent-generator/index.js.map +1 -0
- package/dist/agent-generator/stack-detector.d.ts +12 -0
- package/dist/agent-generator/stack-detector.d.ts.map +1 -0
- package/dist/agent-generator/stack-detector.js +128 -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 +1252 -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/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 +6 -0
- package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
- package/dist/agent-generator/templates/core/skills-generator.js +207 -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 +35 -4
- 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/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/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 +18 -0
- package/dist/project-summarizer.d.ts.map +1 -0
- package/dist/project-summarizer.js +306 -0
- package/dist/project-summarizer.js.map +1 -0
- package/dist/refactor-reporter.js +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -3
- package/src/agent-generator/context-enricher.ts +643 -0
- package/src/agent-generator/domain-inferrer.ts +625 -0
- package/src/agent-generator/framework-detector.ts +669 -0
- package/src/agent-generator/index.ts +555 -0
- package/src/agent-generator/stack-detector.ts +103 -0
- package/src/agent-generator/templates/core/agents.ts +1293 -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/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 +236 -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 +38 -4
- 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/cli.ts +316 -117
- package/src/html-reporter.ts +263 -13
- package/src/index.ts +92 -9
- package/src/project-summarizer.ts +347 -0
- package/src/refactor-reporter.ts +1 -1
- package/src/types.ts +10 -0
- package/tests/agent-generator.test.ts +411 -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/forecast.test.ts +509 -0
- package/tests/framework-detector.test.ts +1172 -0
- package/tests/git-history.test.ts +254 -0
- package/tests/scanner.test.ts +7 -8
- package/tests/scorer.test.ts +588 -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/html-reporter.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnalysisReport, AntiPattern, RefactoringPlan, RefactorStep } from './types.js';
|
|
2
|
-
import { AgentSuggestion } from './agent-generator.js';
|
|
2
|
+
import { AgentSuggestion } from './agent-generator/index.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Generates premium visual HTML reports from AnalysisReport.
|
|
@@ -25,6 +25,7 @@ ${this.renderHeader(report)}
|
|
|
25
25
|
<nav class="sidebar" id="reportSidebar">
|
|
26
26
|
<div class="sidebar-title">Navigation</div>
|
|
27
27
|
<a href="#score" class="sidebar-link active" data-section="score">📊 Score</a>
|
|
28
|
+
${report.projectSummary ? `<a href="#overview" class="sidebar-link" data-section="overview">📋 Overview</a>` : ''}
|
|
28
29
|
<a href="#layers" class="sidebar-link" data-section="layers">📐 Layers & Graph</a>
|
|
29
30
|
<a href="#anti-patterns" class="sidebar-link" data-section="anti-patterns">⚠️ Anti-Patterns (${report.antiPatterns.length})</a>
|
|
30
31
|
<a href="#suggestions" class="sidebar-link" data-section="suggestions">💡 Suggestions (${report.suggestions.length})</a>
|
|
@@ -40,6 +41,8 @@ ${this.renderHeader(report)}
|
|
|
40
41
|
${this.renderStats(report)}
|
|
41
42
|
</div>
|
|
42
43
|
|
|
44
|
+
${this.renderProjectOverview(report)}
|
|
45
|
+
|
|
43
46
|
<details class="section-accordion" id="layers" open>
|
|
44
47
|
<summary class="section-accordion-header">📐 Layer Analysis & Dependencies</summary>
|
|
45
48
|
<div class="section-accordion-body">
|
|
@@ -163,6 +166,75 @@ ${this.getScripts(report)}
|
|
|
163
166
|
</div>`;
|
|
164
167
|
}
|
|
165
168
|
|
|
169
|
+
private renderProjectOverview(report: AnalysisReport): string {
|
|
170
|
+
const summary = report.projectSummary;
|
|
171
|
+
if (!summary) return '';
|
|
172
|
+
|
|
173
|
+
const modulesHtml = summary.modules.length > 0
|
|
174
|
+
? summary.modules.map(m => `
|
|
175
|
+
<div class="overview-module">
|
|
176
|
+
<div class="overview-module-name">${this.esc(m.name)}</div>
|
|
177
|
+
<div class="overview-module-desc">${this.esc(m.description)}</div>
|
|
178
|
+
<div class="overview-module-files">${m.files} file${m.files > 1 ? 's' : ''}</div>
|
|
179
|
+
</div>`).join('')
|
|
180
|
+
: '<div class="overview-empty">Nenhum módulo detectado</div>';
|
|
181
|
+
|
|
182
|
+
const techHtml = summary.techStack
|
|
183
|
+
.map(t => `<span class="overview-tag tech-tag">${this.esc(t)}</span>`)
|
|
184
|
+
.join('');
|
|
185
|
+
|
|
186
|
+
const keywordsHtml = summary.keywords
|
|
187
|
+
.map(k => `<span class="overview-tag keyword-tag">${this.esc(k)}</span>`)
|
|
188
|
+
.join('');
|
|
189
|
+
|
|
190
|
+
const entryHtml = summary.entryPoints.length > 0
|
|
191
|
+
? summary.entryPoints.map(e => `<code class="overview-entry">${this.esc(e)}</code>`).join(' ')
|
|
192
|
+
: '<span class="overview-empty">—</span>';
|
|
193
|
+
|
|
194
|
+
return `
|
|
195
|
+
<details class="section-accordion" id="overview" open>
|
|
196
|
+
<summary class="section-accordion-header">📋 Project Overview</summary>
|
|
197
|
+
<div class="section-accordion-body">
|
|
198
|
+
<div class="overview-grid">
|
|
199
|
+
<div class="overview-card overview-main">
|
|
200
|
+
<div class="overview-label">O que é</div>
|
|
201
|
+
<div class="overview-description">${this.esc(summary.description)}</div>
|
|
202
|
+
<div class="overview-purpose-row">
|
|
203
|
+
<span class="overview-purpose-label">Tipo:</span>
|
|
204
|
+
<span class="overview-purpose-value">${this.esc(summary.purpose)}</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="overview-card">
|
|
208
|
+
<div class="overview-label">Tech Stack</div>
|
|
209
|
+
<div class="overview-tags">${techHtml || '<span class="overview-empty">—</span>'}</div>
|
|
210
|
+
</div>
|
|
211
|
+
<div class="overview-card">
|
|
212
|
+
<div class="overview-label">Keywords</div>
|
|
213
|
+
<div class="overview-tags">${keywordsHtml || '<span class="overview-empty">—</span>'}</div>
|
|
214
|
+
</div>
|
|
215
|
+
<div class="overview-card">
|
|
216
|
+
<div class="overview-label">Entry Points</div>
|
|
217
|
+
<div class="overview-entries">${entryHtml}</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
<div class="overview-modules-section">
|
|
221
|
+
<div class="overview-label">Módulos Detectados (${summary.modules.length})</div>
|
|
222
|
+
<div class="overview-modules-grid">
|
|
223
|
+
${modulesHtml}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
</details>`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private esc(text: string): string {
|
|
231
|
+
return text
|
|
232
|
+
.replace(/&/g, '&')
|
|
233
|
+
.replace(/</g, '<')
|
|
234
|
+
.replace(/>/g, '>')
|
|
235
|
+
.replace(/"/g, '"');
|
|
236
|
+
}
|
|
237
|
+
|
|
166
238
|
private renderScoreHero(report: AnalysisReport): string {
|
|
167
239
|
const overall = report.score.overall;
|
|
168
240
|
const circumference = 2 * Math.PI * 85;
|
|
@@ -301,6 +373,42 @@ ${this.getScripts(report)}
|
|
|
301
373
|
layer: layerMap[n] || 'Other',
|
|
302
374
|
}));
|
|
303
375
|
|
|
376
|
+
// ── Fallback: color by module/directory when layer detection is weak ──
|
|
377
|
+
const otherCount = allNodes.filter(n => n.layer === 'Other').length;
|
|
378
|
+
const useModuleColoring = allNodes.length > 0 && (otherCount / allNodes.length) > 0.7;
|
|
379
|
+
|
|
380
|
+
// Palette for module-based coloring (10 distinct, vibrant colors)
|
|
381
|
+
const modulePalette = [
|
|
382
|
+
'#3b82f6', '#ec4899', '#10b981', '#f59e0b', '#8b5cf6',
|
|
383
|
+
'#06b6d4', '#ef4444', '#84cc16', '#f97316', '#6366f1',
|
|
384
|
+
];
|
|
385
|
+
|
|
386
|
+
let moduleColorMap: Record<string, string> = {};
|
|
387
|
+
if (useModuleColoring) {
|
|
388
|
+
// Extract module (first meaningful directory) from each node path
|
|
389
|
+
const getModule = (filePath: string): string => {
|
|
390
|
+
const parts = filePath.split('/');
|
|
391
|
+
if (parts.length < 2) return 'root';
|
|
392
|
+
const first = parts[0];
|
|
393
|
+
// If first dir is common source dir, use second level
|
|
394
|
+
if (['src', 'lib', 'app', 'packages', 'modules', 'features', 'apps'].includes(first)) {
|
|
395
|
+
return parts.length > 2 ? parts[1] : first;
|
|
396
|
+
}
|
|
397
|
+
return first;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// Assign colors to modules
|
|
401
|
+
const moduleNames = [...new Set(allNodes.map(n => getModule(n.id)))];
|
|
402
|
+
moduleNames.forEach((mod, i) => {
|
|
403
|
+
moduleColorMap[mod] = modulePalette[i % modulePalette.length];
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Reassign layer field to module name for coloring
|
|
407
|
+
for (const node of allNodes) {
|
|
408
|
+
node.layer = getModule(node.id);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
304
412
|
// Build links only between real files
|
|
305
413
|
const allLinks = report.dependencyGraph.edges
|
|
306
414
|
.filter(e => realFiles.has(e.from) && realFiles.has(e.to))
|
|
@@ -314,25 +422,38 @@ ${this.getScripts(report)}
|
|
|
314
422
|
const limitedLinks = allLinks.filter(l => limitedNodeIds.has(l.source) && limitedNodeIds.has(l.target));
|
|
315
423
|
const isLimited = allNodes.length > maxNodes;
|
|
316
424
|
|
|
317
|
-
// Collect unique layers from limited nodes
|
|
425
|
+
// Collect unique layers/modules from limited nodes
|
|
318
426
|
const uniqueLayers = [...new Set(limitedNodes.map(n => n.layer))];
|
|
319
427
|
|
|
428
|
+
// Build dynamic color map for legend and D3
|
|
429
|
+
const colorMap: Record<string, string> = useModuleColoring
|
|
430
|
+
? moduleColorMap
|
|
431
|
+
: { API: '#ec4899', Service: '#3b82f6', Data: '#10b981', UI: '#f59e0b', Infrastructure: '#8b5cf6', Other: '#64748b' };
|
|
432
|
+
|
|
433
|
+
const legendLabel = useModuleColoring ? 'Colored by module' : 'Colored by layer';
|
|
434
|
+
|
|
435
|
+
const legendHtml = uniqueLayers.map(l => {
|
|
436
|
+
const color = colorMap[l] || '#64748b';
|
|
437
|
+
return `<span class="legend-item"><span class="legend-dot" style="background: ${color}"></span> ${l}</span>`;
|
|
438
|
+
}).join('');
|
|
439
|
+
|
|
440
|
+
const filterHtml = uniqueLayers.map(l => {
|
|
441
|
+
const color = colorMap[l] || '#64748b';
|
|
442
|
+
return `<label class="graph-filter-check"><input type="checkbox" checked data-layer="${l}" onchange="toggleGraphLayer('${l}', this.checked)"><span class="legend-dot" style="background: ${color}"></span> ${l}</label>`;
|
|
443
|
+
}).join('');
|
|
444
|
+
|
|
320
445
|
return `
|
|
321
446
|
<h2 class="section-title">🔗 Dependency Graph</h2>
|
|
322
447
|
<div class="card graph-card">
|
|
323
448
|
<div class="graph-controls">
|
|
324
449
|
<div class="graph-legend">
|
|
325
|
-
<span class="legend-
|
|
326
|
-
|
|
327
|
-
<span class="legend-item"><span class="legend-dot" style="background: #10b981"></span> Data</span>
|
|
328
|
-
<span class="legend-item"><span class="legend-dot" style="background: #f59e0b"></span> UI</span>
|
|
329
|
-
<span class="legend-item"><span class="legend-dot" style="background: #8b5cf6"></span> Infra</span>
|
|
330
|
-
<span class="legend-item"><span class="legend-dot" style="background: #64748b"></span> Other</span>
|
|
450
|
+
<span class="legend-label" style="color:#94a3b8;font-size:11px;margin-right:8px;">${legendLabel}:</span>
|
|
451
|
+
${legendHtml}
|
|
331
452
|
</div>
|
|
332
453
|
<div class="graph-filters">
|
|
333
454
|
<input type="text" id="graphSearch" class="graph-search" placeholder="🔍 Search node..." oninput="filterGraphNodes(this.value)">
|
|
334
455
|
<div class="graph-layer-filters">
|
|
335
|
-
${
|
|
456
|
+
${filterHtml}
|
|
336
457
|
</div>
|
|
337
458
|
</div>
|
|
338
459
|
${isLimited ? `<div class="graph-limit-notice">Showing top ${maxNodes} of ${allNodes.length} source files (most connected) · ${limitedLinks.length} links</div>` : ''}
|
|
@@ -340,8 +461,9 @@ ${this.getScripts(report)}
|
|
|
340
461
|
<div id="dep-graph" style="width:100%; min-height:500px;"></div>
|
|
341
462
|
<div class="graph-hint">🖱️ Drag nodes • Scroll to zoom • Double-click to reset • Node size = connections</div>
|
|
342
463
|
</div>
|
|
343
|
-
<script type="application/json" id="graph-nodes">${JSON.stringify(limitedNodes)}
|
|
344
|
-
<script type="application/json" id="graph-links">${JSON.stringify(limitedLinks)}
|
|
464
|
+
<script type="application/json" id="graph-nodes">${JSON.stringify(limitedNodes)}${'</'+'script>'}
|
|
465
|
+
<script type="application/json" id="graph-links">${JSON.stringify(limitedLinks)}${'</'+'script>'}
|
|
466
|
+
<script type="application/json" id="graph-colors">${JSON.stringify(colorMap)}${'</'+'script>'}`;
|
|
345
467
|
}
|
|
346
468
|
|
|
347
469
|
/**
|
|
@@ -465,7 +587,7 @@ ${this.getScripts(report)}
|
|
|
465
587
|
private renderFooter(): string {
|
|
466
588
|
return `
|
|
467
589
|
<div class="footer">
|
|
468
|
-
<p>Generated by <a href="https://github.com/camilooscargbaptista/architect"
|
|
590
|
+
<p>Generated by <a href="https://github.com/camilooscargbaptista/architect">⚡ Architect v3.1</a> — Enterprise Architecture Intelligence</p>
|
|
469
591
|
<p>By <strong>Camilo Girardelli</strong> · <a href="https://www.girardellitecnologia.com">Girardelli Tecnologia</a></p>
|
|
470
592
|
</div>`;
|
|
471
593
|
}
|
|
@@ -764,7 +886,9 @@ function animateCounter(el, target) {
|
|
|
764
886
|
const height = 500;
|
|
765
887
|
container.style.height = height + 'px';
|
|
766
888
|
|
|
767
|
-
|
|
889
|
+
// Dynamic color map — loaded from JSON (supports both layer and module coloring)
|
|
890
|
+
const colorsEl = document.getElementById('graph-colors');
|
|
891
|
+
const layerColors = colorsEl ? JSON.parse(colorsEl.textContent || '{}') : {
|
|
768
892
|
API: '#ec4899', Service: '#3b82f6', Data: '#10b981',
|
|
769
893
|
UI: '#f59e0b', Infrastructure: '#8b5cf6', Other: '#64748b',
|
|
770
894
|
};
|
|
@@ -1357,6 +1481,132 @@ function animateCounter(el, target) {
|
|
|
1357
1481
|
.section-accordion-header::-webkit-details-marker { display: none; }
|
|
1358
1482
|
.section-accordion-body { padding: 0.5rem 0; }
|
|
1359
1483
|
|
|
1484
|
+
/* ── Project Overview ── */
|
|
1485
|
+
.overview-grid {
|
|
1486
|
+
display: grid;
|
|
1487
|
+
grid-template-columns: 1fr 1fr;
|
|
1488
|
+
gap: 1rem;
|
|
1489
|
+
margin-bottom: 1.5rem;
|
|
1490
|
+
}
|
|
1491
|
+
.overview-card {
|
|
1492
|
+
background: rgba(255,255,255,0.03);
|
|
1493
|
+
border: 1px solid #334155;
|
|
1494
|
+
border-radius: 12px;
|
|
1495
|
+
padding: 1.25rem;
|
|
1496
|
+
}
|
|
1497
|
+
.overview-main {
|
|
1498
|
+
grid-column: 1 / -1;
|
|
1499
|
+
background: linear-gradient(135deg, rgba(59,130,246,0.08), rgba(139,92,246,0.08));
|
|
1500
|
+
border-color: #3b82f6;
|
|
1501
|
+
}
|
|
1502
|
+
.overview-label {
|
|
1503
|
+
font-size: 0.75rem;
|
|
1504
|
+
font-weight: 600;
|
|
1505
|
+
text-transform: uppercase;
|
|
1506
|
+
letter-spacing: 0.05em;
|
|
1507
|
+
color: #94a3b8;
|
|
1508
|
+
margin-bottom: 0.75rem;
|
|
1509
|
+
}
|
|
1510
|
+
.overview-description {
|
|
1511
|
+
font-size: 1.1rem;
|
|
1512
|
+
color: #e2e8f0;
|
|
1513
|
+
line-height: 1.6;
|
|
1514
|
+
margin-bottom: 0.75rem;
|
|
1515
|
+
}
|
|
1516
|
+
.overview-purpose-row {
|
|
1517
|
+
display: flex;
|
|
1518
|
+
align-items: center;
|
|
1519
|
+
gap: 0.5rem;
|
|
1520
|
+
}
|
|
1521
|
+
.overview-purpose-label {
|
|
1522
|
+
font-size: 0.8rem;
|
|
1523
|
+
color: #64748b;
|
|
1524
|
+
}
|
|
1525
|
+
.overview-purpose-value {
|
|
1526
|
+
font-size: 0.85rem;
|
|
1527
|
+
color: #a78bfa;
|
|
1528
|
+
font-weight: 600;
|
|
1529
|
+
background: rgba(139,92,246,0.1);
|
|
1530
|
+
padding: 0.2rem 0.6rem;
|
|
1531
|
+
border-radius: 6px;
|
|
1532
|
+
}
|
|
1533
|
+
.overview-tags {
|
|
1534
|
+
display: flex;
|
|
1535
|
+
flex-wrap: wrap;
|
|
1536
|
+
gap: 0.4rem;
|
|
1537
|
+
}
|
|
1538
|
+
.overview-tag {
|
|
1539
|
+
font-size: 0.75rem;
|
|
1540
|
+
padding: 0.25rem 0.6rem;
|
|
1541
|
+
border-radius: 6px;
|
|
1542
|
+
font-weight: 500;
|
|
1543
|
+
}
|
|
1544
|
+
.tech-tag {
|
|
1545
|
+
background: rgba(59,130,246,0.15);
|
|
1546
|
+
color: #60a5fa;
|
|
1547
|
+
border: 1px solid rgba(59,130,246,0.3);
|
|
1548
|
+
}
|
|
1549
|
+
.keyword-tag {
|
|
1550
|
+
background: rgba(16,185,129,0.1);
|
|
1551
|
+
color: #34d399;
|
|
1552
|
+
border: 1px solid rgba(16,185,129,0.2);
|
|
1553
|
+
}
|
|
1554
|
+
.overview-entry {
|
|
1555
|
+
font-size: 0.8rem;
|
|
1556
|
+
background: rgba(255,255,255,0.05);
|
|
1557
|
+
padding: 0.25rem 0.5rem;
|
|
1558
|
+
border-radius: 4px;
|
|
1559
|
+
color: #e2e8f0;
|
|
1560
|
+
font-family: 'SF Mono', monospace;
|
|
1561
|
+
}
|
|
1562
|
+
.overview-entries {
|
|
1563
|
+
display: flex;
|
|
1564
|
+
flex-wrap: wrap;
|
|
1565
|
+
gap: 0.4rem;
|
|
1566
|
+
}
|
|
1567
|
+
.overview-modules-section {
|
|
1568
|
+
margin-top: 0.5rem;
|
|
1569
|
+
}
|
|
1570
|
+
.overview-modules-grid {
|
|
1571
|
+
display: grid;
|
|
1572
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
1573
|
+
gap: 0.75rem;
|
|
1574
|
+
margin-top: 0.5rem;
|
|
1575
|
+
}
|
|
1576
|
+
.overview-module {
|
|
1577
|
+
background: rgba(255,255,255,0.03);
|
|
1578
|
+
border: 1px solid #1e293b;
|
|
1579
|
+
border-radius: 8px;
|
|
1580
|
+
padding: 0.75rem 1rem;
|
|
1581
|
+
transition: border-color 0.2s;
|
|
1582
|
+
}
|
|
1583
|
+
.overview-module:hover {
|
|
1584
|
+
border-color: #3b82f6;
|
|
1585
|
+
}
|
|
1586
|
+
.overview-module-name {
|
|
1587
|
+
font-weight: 600;
|
|
1588
|
+
color: #e2e8f0;
|
|
1589
|
+
font-size: 0.9rem;
|
|
1590
|
+
margin-bottom: 0.25rem;
|
|
1591
|
+
}
|
|
1592
|
+
.overview-module-desc {
|
|
1593
|
+
color: #94a3b8;
|
|
1594
|
+
font-size: 0.75rem;
|
|
1595
|
+
margin-bottom: 0.25rem;
|
|
1596
|
+
}
|
|
1597
|
+
.overview-module-files {
|
|
1598
|
+
color: #64748b;
|
|
1599
|
+
font-size: 0.7rem;
|
|
1600
|
+
}
|
|
1601
|
+
.overview-empty {
|
|
1602
|
+
color: #475569;
|
|
1603
|
+
font-size: 0.85rem;
|
|
1604
|
+
font-style: italic;
|
|
1605
|
+
}
|
|
1606
|
+
@media (max-width: 768px) {
|
|
1607
|
+
.overview-grid { grid-template-columns: 1fr; }
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1360
1610
|
/* ── Operations Accordion (inside refactoring steps) ── */
|
|
1361
1611
|
.rstep-ops-accordion {
|
|
1362
1612
|
margin: 0.75rem 0; border: 1px solid #1e293b; border-radius: 10px; overflow: hidden;
|
package/src/index.ts
CHANGED
|
@@ -6,13 +6,27 @@ import { DiagramGenerator } from './diagram.js';
|
|
|
6
6
|
import { ReportGenerator } from './reporter.js';
|
|
7
7
|
import { HtmlReportGenerator } from './html-reporter.js';
|
|
8
8
|
import { RefactorEngine } from './refactor-engine.js';
|
|
9
|
-
import { AgentGenerator, AgentSuggestion } from './agent-generator.js';
|
|
9
|
+
import { AgentGenerator, AgentSuggestion } from './agent-generator/index.js';
|
|
10
|
+
import { ProjectSummarizer } from './project-summarizer.js';
|
|
10
11
|
import { ConfigLoader } from './config.js';
|
|
11
12
|
import { AnalysisReport, RefactoringPlan } from './types.js';
|
|
12
13
|
import { relative } from 'path';
|
|
13
14
|
|
|
15
|
+
export type ProgressPhase =
|
|
16
|
+
| 'scan' | 'dependencies' | 'layers' | 'antipatterns'
|
|
17
|
+
| 'scoring' | 'summarize' | 'normalize';
|
|
18
|
+
|
|
19
|
+
export interface ProgressEvent {
|
|
20
|
+
phase: ProgressPhase;
|
|
21
|
+
status: 'start' | 'complete';
|
|
22
|
+
detail?: string;
|
|
23
|
+
metrics?: Record<string, number | string>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ProgressCallback = (event: ProgressEvent) => void;
|
|
27
|
+
|
|
14
28
|
export interface ArchitectCommand {
|
|
15
|
-
analyze: (path: string) => Promise<AnalysisReport>;
|
|
29
|
+
analyze: (path: string, onProgress?: ProgressCallback) => Promise<AnalysisReport>;
|
|
16
30
|
refactor: (report: AnalysisReport, projectPath: string) => RefactoringPlan;
|
|
17
31
|
diagram: (path: string) => Promise<string>;
|
|
18
32
|
score: (path: string) => Promise<{ overall: number; breakdown: Record<string, number> }>;
|
|
@@ -21,19 +35,26 @@ export interface ArchitectCommand {
|
|
|
21
35
|
}
|
|
22
36
|
|
|
23
37
|
class Architect implements ArchitectCommand {
|
|
24
|
-
async analyze(projectPath: string): Promise<AnalysisReport> {
|
|
38
|
+
async analyze(projectPath: string, onProgress?: ProgressCallback): Promise<AnalysisReport> {
|
|
39
|
+
const emit = onProgress || (() => {});
|
|
25
40
|
const config = ConfigLoader.loadConfig(projectPath);
|
|
26
41
|
|
|
42
|
+
// ── Phase 1: File Scanning ──
|
|
43
|
+
emit({ phase: 'scan', status: 'start' });
|
|
27
44
|
const scanner = new ProjectScanner(projectPath, config);
|
|
28
45
|
const projectInfo = scanner.scan();
|
|
29
|
-
|
|
30
46
|
if (!projectInfo.fileTree) {
|
|
31
47
|
throw new Error('Failed to scan project');
|
|
32
48
|
}
|
|
49
|
+
emit({
|
|
50
|
+
phase: 'scan', status: 'complete',
|
|
51
|
+
metrics: { files: projectInfo.totalFiles, lines: projectInfo.totalLines, languages: projectInfo.primaryLanguages.length },
|
|
52
|
+
});
|
|
33
53
|
|
|
54
|
+
// ── Phase 2: Dependency Analysis ──
|
|
55
|
+
emit({ phase: 'dependencies', status: 'start' });
|
|
34
56
|
const analyzer = new ArchitectureAnalyzer(projectPath);
|
|
35
57
|
const dependencies = new Map();
|
|
36
|
-
|
|
37
58
|
for (const [file, imports] of analyzer
|
|
38
59
|
.analyzeDependencies(projectInfo.fileTree)
|
|
39
60
|
.reduce(
|
|
@@ -49,19 +70,50 @@ class Architect implements ArchitectCommand {
|
|
|
49
70
|
.entries()) {
|
|
50
71
|
dependencies.set(file, imports);
|
|
51
72
|
}
|
|
52
|
-
|
|
53
73
|
const edges = analyzer.analyzeDependencies(projectInfo.fileTree);
|
|
74
|
+
emit({
|
|
75
|
+
phase: 'dependencies', status: 'complete',
|
|
76
|
+
metrics: { edges: edges.length, modules: dependencies.size },
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ── Phase 3: Layer Detection ──
|
|
80
|
+
emit({ phase: 'layers', status: 'start' });
|
|
54
81
|
const layers = analyzer.detectLayers(projectInfo.fileTree);
|
|
82
|
+
emit({
|
|
83
|
+
phase: 'layers', status: 'complete',
|
|
84
|
+
metrics: { layers: layers.length, classified: layers.reduce((s, l) => s + l.files.length, 0) },
|
|
85
|
+
});
|
|
55
86
|
|
|
87
|
+
// ── Phase 4: Anti-Pattern Detection ──
|
|
88
|
+
emit({ phase: 'antipatterns', status: 'start' });
|
|
56
89
|
const detector = new AntiPatternDetector(config);
|
|
57
90
|
const antiPatterns = detector.detect(projectInfo.fileTree, dependencies);
|
|
91
|
+
emit({
|
|
92
|
+
phase: 'antipatterns', status: 'complete',
|
|
93
|
+
metrics: {
|
|
94
|
+
total: antiPatterns.length,
|
|
95
|
+
critical: antiPatterns.filter(p => p.severity === 'CRITICAL').length,
|
|
96
|
+
high: antiPatterns.filter(p => p.severity === 'HIGH').length,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
58
99
|
|
|
100
|
+
// ── Phase 5: Architecture Scoring ──
|
|
101
|
+
emit({ phase: 'scoring', status: 'start' });
|
|
59
102
|
const scorer = new ArchitectureScorer();
|
|
60
103
|
const score = scorer.score(edges, antiPatterns, projectInfo.totalFiles);
|
|
104
|
+
emit({
|
|
105
|
+
phase: 'scoring', status: 'complete',
|
|
106
|
+
metrics: {
|
|
107
|
+
overall: score.overall,
|
|
108
|
+
modularity: score.breakdown.modularity,
|
|
109
|
+
coupling: score.breakdown.coupling,
|
|
110
|
+
cohesion: score.breakdown.cohesion,
|
|
111
|
+
layering: score.breakdown.layering,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
61
114
|
|
|
62
115
|
const diagramGenerator = new DiagramGenerator();
|
|
63
116
|
const layerDiagram = diagramGenerator.generateLayerDiagram(layers);
|
|
64
|
-
|
|
65
117
|
const suggestions = this.generateSuggestions(antiPatterns, score, edges);
|
|
66
118
|
|
|
67
119
|
const report: AnalysisReport = {
|
|
@@ -81,8 +133,24 @@ class Architect implements ArchitectCommand {
|
|
|
81
133
|
},
|
|
82
134
|
};
|
|
83
135
|
|
|
84
|
-
//
|
|
85
|
-
|
|
136
|
+
// ── Phase 6: Normalize Paths ──
|
|
137
|
+
emit({ phase: 'normalize', status: 'start' });
|
|
138
|
+
const normalized = this.relativizePaths(report, projectPath);
|
|
139
|
+
emit({ phase: 'normalize', status: 'complete' });
|
|
140
|
+
|
|
141
|
+
// ── Phase 7: Project Summary ──
|
|
142
|
+
emit({ phase: 'summarize', status: 'start' });
|
|
143
|
+
const summarizer = new ProjectSummarizer();
|
|
144
|
+
normalized.projectSummary = summarizer.summarize(projectPath, normalized);
|
|
145
|
+
emit({
|
|
146
|
+
phase: 'summarize', status: 'complete',
|
|
147
|
+
metrics: {
|
|
148
|
+
modules: normalized.projectSummary?.modules?.length || 0,
|
|
149
|
+
techStack: normalized.projectSummary?.techStack?.length || 0,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return normalized;
|
|
86
154
|
}
|
|
87
155
|
|
|
88
156
|
/**
|
|
@@ -309,3 +377,18 @@ export {
|
|
|
309
377
|
ConfigLoader,
|
|
310
378
|
};
|
|
311
379
|
|
|
380
|
+
// ── v4.0: Temporal & Predictive Analyzers ──
|
|
381
|
+
export { GitHistoryAnalyzer, TemporalScorer, ForecastEngine } from './analyzers/index.js';
|
|
382
|
+
export { saveToCache, loadFromCache } from './analyzers/git-cache.js';
|
|
383
|
+
export type {
|
|
384
|
+
GitHistoryReport, FileHistory, ModuleHistory, VelocityVector,
|
|
385
|
+
ChangeCoupling, GitAnalyzerConfig,
|
|
386
|
+
} from './analyzers/git-history.js';
|
|
387
|
+
export type {
|
|
388
|
+
Trend, TemporalScore, TemporalReport, TemporalScorerConfig,
|
|
389
|
+
} from './analyzers/temporal-scorer.js';
|
|
390
|
+
export type {
|
|
391
|
+
PreAntiPatternType, PreAntiPattern, ModuleForecast,
|
|
392
|
+
WeatherForecast, ForecastConfig,
|
|
393
|
+
} from './analyzers/forecast.js';
|
|
394
|
+
|