@girardelli/architect 8.1.0 → 8.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 (34) hide show
  1. package/dist/src/adapters/cli.js +226 -8
  2. package/dist/src/adapters/cli.js.map +1 -1
  3. package/dist/src/adapters/html-reporter/sections/agents.js.map +1 -1
  4. package/dist/src/adapters/html-reporter/sections/layers.js.map +1 -1
  5. package/dist/src/adapters/html-reporter/utils_adapters.js.map +1 -1
  6. package/dist/src/adapters/progress-logger.js +21 -21
  7. package/dist/src/adapters/progress-logger.js.map +1 -1
  8. package/dist/src/adapters/refactor-reporter.js.map +1 -1
  9. package/dist/src/adapters/reporter.js.map +1 -1
  10. package/dist/src/core/GenesisTerminal.d.ts +1 -0
  11. package/dist/src/core/GenesisTerminal.js +126 -35
  12. package/dist/src/core/GenesisTerminal.js.map +1 -1
  13. package/dist/src/core/architect.js +12 -7
  14. package/dist/src/core/architect.js.map +1 -1
  15. package/dist/src/core/interactive-refactor.d.ts +84 -0
  16. package/dist/src/core/interactive-refactor.js +440 -0
  17. package/dist/src/core/interactive-refactor.js.map +1 -0
  18. package/dist/tests/github-action.test.js.map +1 -1
  19. package/dist/tests/interactive-refactor.test.d.ts +7 -0
  20. package/dist/tests/interactive-refactor.test.js +125 -0
  21. package/dist/tests/interactive-refactor.test.js.map +1 -0
  22. package/package.json +1 -1
  23. package/src/adapters/cli.ts +255 -13
  24. package/src/adapters/html-reporter/sections/agents.ts +10 -9
  25. package/src/adapters/html-reporter/sections/layers.ts +3 -3
  26. package/src/adapters/html-reporter/utils_adapters.ts +3 -3
  27. package/src/adapters/progress-logger.ts +19 -19
  28. package/src/adapters/refactor-reporter.ts +2 -2
  29. package/src/adapters/reporter.ts +2 -2
  30. package/src/core/GenesisTerminal.ts +129 -35
  31. package/src/core/architect.ts +13 -8
  32. package/src/core/interactive-refactor.ts +552 -0
  33. package/tests/github-action.test.ts +4 -4
  34. package/tests/interactive-refactor.test.ts +141 -0
@@ -2,10 +2,12 @@ import { select, confirm } from '@inquirer/prompts';
2
2
  import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import { Architect, ProgressEvent } from './architect.js';
5
+ import type { RefactoringPlan } from '@girardelli/architect-core/src/core/types/rules.js';
5
6
  import { AgentExecutor } from '@girardelli/architect-agents/src/core/agent-runtime/executor.js';
6
7
  import { ProgressReporter, c } from '../adapters/progress-logger.js';
7
8
  import { HtmlReportGenerator } from '../adapters/html-reporter.js';
8
9
  import * as fs from 'fs';
10
+ import { execSync } from 'child_process';
9
11
 
10
12
  export class GenesisTerminal {
11
13
  private architect: Architect;
@@ -19,37 +21,67 @@ export class GenesisTerminal {
19
21
  console.log(chalk.cyan.bold('\nWelcome to Architect Genesis v8.0'));
20
22
  console.log(chalk.gray('The Autonomous Architecture Intent Compiler\n'));
21
23
 
22
- const action = await select({
23
- message: 'What would you like to build today?',
24
- choices: [
25
- {
26
- name: 'šŸ›”ļø Scan Security & Anti-Pattern Boundaries',
27
- value: 'scan',
28
- description: 'Runs an O(N²) Matrix Analysis on your Codebase',
29
- },
30
- {
31
- name: 'šŸ› ļø Refactor System Anti-Patterns (God Mode)',
32
- value: 'refactor',
33
- description: 'Let AI Autonomous Agents rewrite your technical debt',
34
- },
35
- {
36
- name: 'šŸ—ļø Architect a New Technical Feature',
37
- value: 'feature',
38
- description: 'Build a new cross-layer feature dynamically',
39
- },
40
- ],
41
- });
24
+ let active = true;
25
+ while (active) {
26
+ const action = await select({
27
+ message: 'What would you like to build today?',
28
+ choices: [
29
+ {
30
+ name: 'šŸ›”ļø Scan Security & Anti-Pattern Boundaries',
31
+ value: 'scan',
32
+ description: 'Runs an O(N²) Matrix Analysis on your Codebase',
33
+ },
34
+ {
35
+ name: 'šŸ› ļø Refactor System Anti-Patterns (God Mode)',
36
+ value: 'refactor',
37
+ description: 'Let AI Autonomous Agents rewrite your technical debt',
38
+ },
39
+ {
40
+ name: 'šŸ—ļø Architect a New Technical Feature',
41
+ value: 'feature',
42
+ description: 'Build a new cross-layer feature dynamically',
43
+ },
44
+ {
45
+ name: 'āœ… Validate Architecture & PR Deltas',
46
+ value: 'validate',
47
+ description: 'Check architecture rules and PR diffs against standards',
48
+ },
49
+ {
50
+ name: '🚪 Exit',
51
+ value: 'exit',
52
+ description: 'Return to orbit',
53
+ }
54
+ ],
55
+ });
42
56
 
43
- switch (action) {
44
- case 'scan':
45
- await this.runScan();
46
- break;
47
- case 'refactor':
48
- await this.runAutonomousRefactor();
49
- break;
50
- case 'feature':
51
- console.log(chalk.yellow('\nFeature architecture mode is coming in Phase 7.0!'));
52
- break;
57
+ switch (action) {
58
+ case 'scan':
59
+ await this.runScan();
60
+ break;
61
+ case 'refactor':
62
+ await this.runAutonomousRefactor();
63
+ break;
64
+ case 'feature':
65
+ console.log(chalk.yellow('\nFeature architecture mode is coming in Phase 7.0!'));
66
+ break;
67
+ case 'validate':
68
+ console.log(chalk.cyan('\n[System] Invoking Rules Engine...'));
69
+ console.log(chalk.gray('> architect check'));
70
+ try {
71
+ execSync('node dist/src/adapters/cli.js check', { stdio: 'inherit' });
72
+ } catch(e) {
73
+ // Error is handled by inheritance
74
+ }
75
+ break;
76
+ case 'exit':
77
+ console.log(chalk.gray('\nGoodbye! Closing Genesis terminal.'));
78
+ active = false;
79
+ break;
80
+ }
81
+
82
+ if (active) {
83
+ console.log('\n' + chalk.gray('──────────────────────────────────────────────────') + '\n');
84
+ }
53
85
  }
54
86
  }
55
87
 
@@ -86,7 +118,38 @@ export class GenesisTerminal {
86
118
  antiPatterns: report.antiPatterns.length
87
119
  });
88
120
 
89
- console.log(chalk.green(`\nšŸš€ Done! Open ${chalk.bold.cyan(htmlPath)} in your browser to see the graphics!`));
121
+ console.log(chalk.green(`\nšŸš€ Done! Opening ${chalk.bold.cyan(htmlPath)} in your browser to see the graphics!`));
122
+ try {
123
+ execSync(`open "${htmlPath}"`);
124
+ } catch (err) {
125
+ console.error(chalk.yellow(`Could not automatically open browser. Please open ${htmlPath} manually.`));
126
+ }
127
+
128
+ // ── Post-Scan Autonomous Trigger ──
129
+ console.log(chalk.yellow(`\nāš ļø I have generated the O(N²) Matrix and found ${plan.steps.length} Refactoring Steps.`));
130
+
131
+ const executionMode = await select({
132
+ message: 'Select AI Execution Mode:',
133
+ choices: [
134
+ { name: 'šŸ¤– Execute via Anthropic (Claude)', value: 'Anthropic' },
135
+ { name: 'šŸ¤– Execute via OpenAI (GPT)', value: 'OpenAI' },
136
+ { name: 'šŸ¤– Execute via Google (Gemini)', value: 'Gemini' },
137
+ { name: 'šŸ“„ Export Offline Prompts (Manual Web UI Mode)', value: 'offline' },
138
+ { name: '🚪 Abort Refactoring', value: 'abort' }
139
+ ]
140
+ });
141
+
142
+ if (executionMode === 'abort') {
143
+ console.log(chalk.yellow('Refactor Aborted. Returning to orbit.'));
144
+ } else if (executionMode === 'offline') {
145
+ console.log(chalk.cyan('\n[System] Initializing Offline Prompt Generator...'));
146
+ const { OfflinePromptGenerator } = await import('@girardelli/architect-agents/src/core/agent-runtime/offline-prompt-generator.js');
147
+ const generator = new OfflinePromptGenerator();
148
+ generator.generate(plan);
149
+ console.log(chalk.green(`\nāœ… Offline Prompts exported successfully to packages/architect/prompts/!`));
150
+ } else {
151
+ await this.runAutonomousExecution(plan, executionMode);
152
+ }
90
153
 
91
154
  } catch (e: any) {
92
155
  console.error(chalk.red(`\nāŒ Analysis Failed: ${e.message}`));
@@ -94,6 +157,39 @@ export class GenesisTerminal {
94
157
  }
95
158
 
96
159
  private async runAutonomousRefactor() {
160
+ console.log(chalk.cyan('\n[System] Running Quick Scan before Refactoring...'));
161
+ try {
162
+ const report = await this.architect.analyze('.');
163
+ const plan = this.architect.refactor(report, '.');
164
+
165
+ const executionMode = await select({
166
+ message: 'Select AI Execution Mode:',
167
+ choices: [
168
+ { name: 'šŸ¤– Execute via Anthropic (Claude)', value: 'Anthropic' },
169
+ { name: 'šŸ¤– Execute via OpenAI (GPT)', value: 'OpenAI' },
170
+ { name: 'šŸ¤– Execute via Google (Gemini)', value: 'Gemini' },
171
+ { name: 'šŸ“„ Export Offline Prompts (Manual Web UI Mode)', value: 'offline' },
172
+ { name: '🚪 Abort Refactoring', value: 'abort' }
173
+ ]
174
+ });
175
+
176
+ if (executionMode === 'abort') {
177
+ return;
178
+ } else if (executionMode === 'offline') {
179
+ const { OfflinePromptGenerator } = await import('@girardelli/architect-agents/src/core/agent-runtime/offline-prompt-generator.js');
180
+ const generator = new OfflinePromptGenerator();
181
+ generator.generate(plan);
182
+ console.log(chalk.green(`\nāœ… Offline Prompts exported successfully to packages/architect/prompts/!`));
183
+ return;
184
+ }
185
+
186
+ await this.runAutonomousExecution(plan, executionMode);
187
+ } catch (e: any) {
188
+ console.error(chalk.red(`\nāŒ Scan Failed: ${e.message}`));
189
+ }
190
+ }
191
+
192
+ private async runAutonomousExecution(plan: RefactoringPlan, providerType?: string) {
97
193
  console.log(chalk.blue('\n[System] Initializing AgentExecutor Runtime...'));
98
194
 
99
195
  // Confirm Action
@@ -111,11 +207,9 @@ export class GenesisTerminal {
111
207
 
112
208
  try {
113
209
  const executor = new AgentExecutor(isDangerous);
114
- const report = await this.architect.analyze('.');
115
- const plan = this.architect.refactor(report, '.');
116
210
 
117
- spinner.succeed(chalk.green('Refactor Plan Successfully Created!'));
118
- await executor.executePlan(plan);
211
+ spinner.succeed(chalk.green('Refactor Protocol Engaged!'));
212
+ await executor.executePlan(plan, providerType);
119
213
 
120
214
  console.log(chalk.gray('Check your `git diff` to review the Agent changes before committing.'));
121
215
 
@@ -204,11 +204,16 @@ export class Architect implements ArchitectCommand {
204
204
  return p;
205
205
  };
206
206
 
207
- report.antiPatterns = report.antiPatterns.map((p) => ({
208
- ...p,
209
- location: rel(p.location),
210
- affectedFiles: p.affectedFiles?.map(rel),
211
- }));
207
+ report.antiPatterns = report.antiPatterns.map((p) => {
208
+ const mapped = {
209
+ ...p,
210
+ location: rel(p.location),
211
+ };
212
+ if (p.affectedFiles) {
213
+ (mapped as any).affectedFiles = p.affectedFiles.map(rel);
214
+ }
215
+ return mapped;
216
+ });
212
217
 
213
218
  report.layers = report.layers.map((l) => ({
214
219
  ...l,
@@ -331,7 +336,7 @@ export class Architect implements ArchitectCommand {
331
336
  const toDir = edge.to.split('/').slice(0, -1).join('/');
332
337
  if (fromDir !== toDir) {
333
338
  if (!crossBoundary[edge.from]) crossBoundary[edge.from] = new Set();
334
- crossBoundary[edge.from].add(toDir);
339
+ crossBoundary[edge.from]!.add(toDir);
335
340
  }
336
341
  }
337
342
 
@@ -351,7 +356,7 @@ export class Architect implements ArchitectCommand {
351
356
  }
352
357
 
353
358
  // 4. Score-based suggestions (only if no specific suggestions cover it)
354
- if (score.breakdown.coupling < 70 && !suggestions.some(s => s.title.startsWith('Hub File'))) {
359
+ if ((score.breakdown['coupling'] ?? 100) < 70 && !suggestions.some(s => s.title.startsWith('Hub File'))) {
355
360
  suggestions.push({
356
361
  priority: 'HIGH',
357
362
  title: 'Reduce Coupling',
@@ -360,7 +365,7 @@ export class Architect implements ArchitectCommand {
360
365
  });
361
366
  }
362
367
 
363
- if (score.breakdown.cohesion < 70 && !suggestions.some(s => s.title.startsWith('Cross-boundary'))) {
368
+ if ((score.breakdown['cohesion'] ?? 100) < 70 && !suggestions.some(s => s.title.startsWith('Cross-boundary'))) {
364
369
  suggestions.push({
365
370
  priority: 'MEDIUM',
366
371
  title: 'Improve Cohesion',