@girardelli/architect 1.3.0 → 2.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.
Files changed (58) hide show
  1. package/README.md +111 -112
  2. package/dist/agent-generator.d.ts +106 -0
  3. package/dist/agent-generator.d.ts.map +1 -0
  4. package/dist/agent-generator.js +1398 -0
  5. package/dist/agent-generator.js.map +1 -0
  6. package/dist/cli.js +132 -15
  7. package/dist/cli.js.map +1 -1
  8. package/dist/html-reporter.d.ts +8 -2
  9. package/dist/html-reporter.d.ts.map +1 -1
  10. package/dist/html-reporter.js +773 -50
  11. package/dist/html-reporter.js.map +1 -1
  12. package/dist/index.d.ts +26 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +25 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/refactor-engine.d.ts +18 -0
  17. package/dist/refactor-engine.d.ts.map +1 -0
  18. package/dist/refactor-engine.js +86 -0
  19. package/dist/refactor-engine.js.map +1 -0
  20. package/dist/refactor-reporter.d.ts +20 -0
  21. package/dist/refactor-reporter.d.ts.map +1 -0
  22. package/dist/refactor-reporter.js +389 -0
  23. package/dist/refactor-reporter.js.map +1 -0
  24. package/dist/rules/barrel-optimizer.d.ts +13 -0
  25. package/dist/rules/barrel-optimizer.d.ts.map +1 -0
  26. package/dist/rules/barrel-optimizer.js +77 -0
  27. package/dist/rules/barrel-optimizer.js.map +1 -0
  28. package/dist/rules/dead-code-detector.d.ts +21 -0
  29. package/dist/rules/dead-code-detector.d.ts.map +1 -0
  30. package/dist/rules/dead-code-detector.js +117 -0
  31. package/dist/rules/dead-code-detector.js.map +1 -0
  32. package/dist/rules/hub-splitter.d.ts +13 -0
  33. package/dist/rules/hub-splitter.d.ts.map +1 -0
  34. package/dist/rules/hub-splitter.js +110 -0
  35. package/dist/rules/hub-splitter.js.map +1 -0
  36. package/dist/rules/import-organizer.d.ts +13 -0
  37. package/dist/rules/import-organizer.d.ts.map +1 -0
  38. package/dist/rules/import-organizer.js +85 -0
  39. package/dist/rules/import-organizer.js.map +1 -0
  40. package/dist/rules/module-grouper.d.ts +13 -0
  41. package/dist/rules/module-grouper.d.ts.map +1 -0
  42. package/dist/rules/module-grouper.js +110 -0
  43. package/dist/rules/module-grouper.js.map +1 -0
  44. package/dist/types.d.ts +51 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +1 -1
  47. package/src/agent-generator.ts +1526 -0
  48. package/src/cli.ts +150 -15
  49. package/src/html-reporter.ts +799 -51
  50. package/src/index.ts +39 -1
  51. package/src/refactor-engine.ts +117 -0
  52. package/src/refactor-reporter.ts +408 -0
  53. package/src/rules/barrel-optimizer.ts +97 -0
  54. package/src/rules/dead-code-detector.ts +132 -0
  55. package/src/rules/hub-splitter.ts +123 -0
  56. package/src/rules/import-organizer.ts +98 -0
  57. package/src/rules/module-grouper.ts +124 -0
  58. package/src/types.ts +52 -0
package/src/cli.ts CHANGED
@@ -16,6 +16,7 @@
16
16
  import { architect } from './index.js';
17
17
  import { ReportGenerator } from './reporter.js';
18
18
  import { HtmlReportGenerator } from './html-reporter.js';
19
+ import { RefactorReportGenerator } from './refactor-reporter.js';
19
20
  import { writeFileSync } from 'fs';
20
21
  import { resolve, basename } from 'path';
21
22
 
@@ -28,6 +29,45 @@ interface CliOptions {
28
29
  output?: string;
29
30
  }
30
31
 
32
+ /**
33
+ * CLI Progress Logger — mostra estágio atual e tempo decorrido
34
+ * Usa output síncrono (console.log) porque as operações do Architect bloqueiam o event loop.
35
+ */
36
+ class ProgressLogger {
37
+ private startTime: number;
38
+ private stageStart: number;
39
+ private currentStage = '';
40
+
41
+ constructor() {
42
+ this.startTime = Date.now();
43
+ this.stageStart = Date.now();
44
+ }
45
+
46
+ start(stage: string): void {
47
+ this.currentStage = stage;
48
+ this.stageStart = Date.now();
49
+ // Print immediately so user sees it BEFORE the blocking operation
50
+ console.log(`⏳ ${stage}`);
51
+ }
52
+
53
+ complete(message?: string): void {
54
+ const elapsed = ((Date.now() - this.stageStart) / 1000).toFixed(1);
55
+ const total = ((Date.now() - this.startTime) / 1000).toFixed(1);
56
+ const displayMsg = message || this.currentStage;
57
+ console.log(`✅ ${displayMsg} (${elapsed}s | total: ${total}s)`);
58
+ }
59
+
60
+ fail(message: string): void {
61
+ const elapsed = ((Date.now() - this.stageStart) / 1000).toFixed(1);
62
+ console.log(`⚠️ ${message} (${elapsed}s)`);
63
+ }
64
+
65
+ summary(lines: string[]): void {
66
+ const total = ((Date.now() - this.startTime) / 1000).toFixed(1);
67
+ console.log(`\n⏱️ Completed in ${total}s`);
68
+ lines.forEach(l => console.log(l));
69
+ }
70
+ }
31
71
  function parseArgs(args: string[]): CliOptions {
32
72
  const command = args[0] || 'analyze';
33
73
  const pathArg = args.find((a) => !a.startsWith('--') && a !== command) || '.';
@@ -48,6 +88,8 @@ Usage:
48
88
 
49
89
  Commands:
50
90
  analyze Full architecture analysis (default)
91
+ refactor Generate refactoring plan with actionable steps
92
+ agents Generate/audit .agent/ directory with AI agents
51
93
  diagram Generate architecture diagram only
52
94
  score Calculate quality score only
53
95
  anti-patterns Detect anti-patterns only
@@ -84,39 +126,132 @@ async function main(): Promise<void> {
84
126
  try {
85
127
  switch (options.command) {
86
128
  case 'analyze': {
129
+ const progress = new ProgressLogger();
130
+
131
+ progress.start('Scanning files & analyzing architecture...');
87
132
  const report = await architect.analyze(options.path);
133
+ progress.complete(`Scanned ${report.projectInfo.totalFiles} files (${report.projectInfo.totalLines.toLocaleString()} lines)`);
134
+
135
+ progress.start('Generating refactoring plan...');
136
+ const plan = architect.refactor(report, options.path);
137
+ progress.complete(`Refactoring plan: ${plan.steps.length} steps, ${plan.totalOperations} operations`);
138
+
139
+ progress.start('Analyzing agent system...');
140
+ const agentSuggestion = architect.suggestAgents(report, plan, options.path);
141
+ progress.complete(`Agents: ${agentSuggestion.suggestedAgents.length} suggested${agentSuggestion.hasExistingAgents ? ' (existing .agent/ audited)' : ''}`);
142
+
88
143
  const projectName = report.projectInfo.name || basename(options.path);
89
144
 
90
145
  if (options.format === 'html') {
146
+ progress.start('Building HTML report...');
91
147
  const htmlGenerator = new HtmlReportGenerator();
92
- const html = htmlGenerator.generateHtml(report);
148
+ const html = htmlGenerator.generateHtml(report, plan, agentSuggestion);
93
149
  const outputPath = options.output || `architect-report-${projectName}.html`;
94
150
  writeFileSync(outputPath, html);
95
- console.log(`✅ HTML report saved to: ${outputPath}`);
96
- console.log(`📊 Score: ${report.score.overall}/100`);
97
- console.log(`⚠️ Anti-patterns: ${report.antiPatterns.length}`);
151
+ progress.complete(`HTML report saved: ${outputPath}`);
98
152
  } else if (options.format === 'markdown') {
153
+ progress.start('Building Markdown report...');
99
154
  const mdGenerator = new ReportGenerator();
100
155
  const markdown = mdGenerator.generateMarkdownReport(report);
101
156
  const outputPath = options.output || `architect-report-${projectName}.md`;
102
157
  writeFileSync(outputPath, markdown);
103
- console.log(`✅ Markdown report saved to: ${outputPath}`);
158
+ progress.complete(`Markdown report saved: ${outputPath}`);
104
159
  } else {
160
+ progress.start('Building JSON report...');
105
161
  const outputPath = options.output || `architect-report-${projectName}.json`;
106
- writeFileSync(outputPath, JSON.stringify(report, null, 2));
107
- console.log(`✅ JSON report saved to: ${outputPath}`);
162
+ writeFileSync(outputPath, JSON.stringify({ report, plan, agentSuggestion }, null, 2));
163
+ progress.complete(`JSON report saved: ${outputPath}`);
108
164
  }
109
165
 
110
- // Print summary to console
166
+ // Print summary
167
+ progress.summary([
168
+ ``,
169
+ `═══════════════════════════════════════`,
170
+ ` SCORE: ${report.score.overall}/100`,
171
+ `═══════════════════════════════════════`,
172
+ `├─ Modularity: ${report.score.breakdown.modularity}`,
173
+ `├─ Coupling: ${report.score.breakdown.coupling}`,
174
+ `├─ Cohesion: ${report.score.breakdown.cohesion}`,
175
+ `└─ Layering: ${report.score.breakdown.layering}`,
176
+ ``,
177
+ `📁 Files: ${report.projectInfo.totalFiles} | 📝 Lines: ${report.projectInfo.totalLines.toLocaleString()}`,
178
+ `⚠️ Anti-patterns: ${report.antiPatterns.length}`,
179
+ `🔧 Refactoring: ${plan.steps.length} steps (${plan.totalOperations} ops)`,
180
+ `🤖 Agents: ${agentSuggestion.suggestedAgents.length} suggested`,
181
+ ]);
182
+ break;
183
+ }
184
+
185
+ case 'refactor': {
186
+ const report = await architect.analyze(options.path);
187
+ const plan = architect.refactor(report, options.path);
188
+ const projectName = report.projectInfo.name || basename(options.path);
189
+
190
+ if (options.format === 'json') {
191
+ const outputPath = options.output || `refactor-plan-${projectName}.json`;
192
+ writeFileSync(outputPath, JSON.stringify(plan, null, 2));
193
+ console.log(`✅ JSON refactoring plan saved to: ${outputPath}`);
194
+ } else {
195
+ const refactorReporter = new RefactorReportGenerator();
196
+ const html = refactorReporter.generateHtml(plan);
197
+ const outputPath = options.output || `refactor-plan-${projectName}.html`;
198
+ writeFileSync(outputPath, html);
199
+ console.log(`✅ Refactoring plan saved to: ${outputPath}`);
200
+ }
201
+
202
+ console.log(`\n═══════════════════════════════════════`);
203
+ console.log(` REFACTORING PLAN`);
204
+ console.log(`═══════════════════════════════════════`);
205
+ console.log(`├─ Steps: ${plan.steps.length}`);
206
+ console.log(`├─ Operations: ${plan.totalOperations}`);
207
+ console.log(`├─ Tier 1: ${plan.tier1Steps} (rule-based)`);
208
+ console.log(`├─ Tier 2: ${plan.tier2Steps} (AST-based)`);
209
+ console.log(`├─ Current: ${plan.currentScore.overall}/100`);
210
+ console.log(`└─ Estimated: ${plan.estimatedScoreAfter.overall}/100 (+${plan.estimatedScoreAfter.overall - plan.currentScore.overall})`);
211
+ break;
212
+ }
213
+
214
+ case 'agents': {
215
+ const report = await architect.analyze(options.path);
216
+ const plan = architect.refactor(report, options.path);
217
+ const outputDir = options.output || undefined;
218
+ const result = architect.agents(report, plan, options.path, outputDir);
219
+
111
220
  console.log(`\n═══════════════════════════════════════`);
112
- console.log(` SCORE: ${report.score.overall}/100`);
221
+ console.log(` 🤖 AGENT SYSTEM`);
113
222
  console.log(`═══════════════════════════════════════`);
114
- console.log(`├─ Modularity: ${report.score.breakdown.modularity}`);
115
- console.log(`├─ Coupling: ${report.score.breakdown.coupling}`);
116
- console.log(`├─ Cohesion: ${report.score.breakdown.cohesion}`);
117
- console.log(`└─ Layering: ${report.score.breakdown.layering}`);
118
- console.log(`\n📁 Files: ${report.projectInfo.totalFiles} | 📝 Lines: ${report.projectInfo.totalLines.toLocaleString()}`);
119
- console.log(`⚠️ Anti-patterns: ${report.antiPatterns.length}`);
223
+
224
+ if (result.generated.length > 0) {
225
+ console.log(`\n✅ Generated ${result.generated.length} files:`);
226
+ for (const file of result.generated) {
227
+ console.log(` 📄 ${file}`);
228
+ }
229
+ }
230
+
231
+ if (result.audit.length > 0) {
232
+ const missing = result.audit.filter(f => f.type === 'MISSING');
233
+ const improvements = result.audit.filter(f => f.type === 'IMPROVEMENT');
234
+ const ok = result.audit.filter(f => f.type === 'OK');
235
+
236
+ if (ok.length > 0) {
237
+ console.log(`\n✅ ${ok.length} checks passed`);
238
+ }
239
+ if (missing.length > 0) {
240
+ console.log(`\n❌ ${missing.length} missing (auto-generated):`);
241
+ for (const f of missing) {
242
+ console.log(` 📄 ${f.file} — ${f.description}`);
243
+ }
244
+ }
245
+ if (improvements.length > 0) {
246
+ console.log(`\n💡 ${improvements.length} improvement suggestions:`);
247
+ for (const f of improvements) {
248
+ console.log(` ⚡ ${f.description}`);
249
+ if (f.suggestion) console.log(` → ${f.suggestion}`);
250
+ }
251
+ }
252
+ }
253
+
254
+ console.log(`\n📊 Score: ${report.score.overall}/100`);
120
255
  break;
121
256
  }
122
257