@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.
- package/dist/src/adapters/cli.js +226 -8
- package/dist/src/adapters/cli.js.map +1 -1
- package/dist/src/adapters/html-reporter/sections/agents.js.map +1 -1
- package/dist/src/adapters/html-reporter/sections/layers.js.map +1 -1
- package/dist/src/adapters/html-reporter/utils_adapters.js.map +1 -1
- package/dist/src/adapters/progress-logger.js +21 -21
- package/dist/src/adapters/progress-logger.js.map +1 -1
- package/dist/src/adapters/refactor-reporter.js.map +1 -1
- package/dist/src/adapters/reporter.js.map +1 -1
- package/dist/src/core/GenesisTerminal.d.ts +1 -0
- package/dist/src/core/GenesisTerminal.js +126 -35
- package/dist/src/core/GenesisTerminal.js.map +1 -1
- package/dist/src/core/architect.js +12 -7
- package/dist/src/core/architect.js.map +1 -1
- package/dist/src/core/interactive-refactor.d.ts +84 -0
- package/dist/src/core/interactive-refactor.js +440 -0
- package/dist/src/core/interactive-refactor.js.map +1 -0
- package/dist/tests/github-action.test.js.map +1 -1
- package/dist/tests/interactive-refactor.test.d.ts +7 -0
- package/dist/tests/interactive-refactor.test.js +125 -0
- package/dist/tests/interactive-refactor.test.js.map +1 -0
- package/package.json +1 -1
- package/src/adapters/cli.ts +255 -13
- package/src/adapters/html-reporter/sections/agents.ts +10 -9
- package/src/adapters/html-reporter/sections/layers.ts +3 -3
- package/src/adapters/html-reporter/utils_adapters.ts +3 -3
- package/src/adapters/progress-logger.ts +19 -19
- package/src/adapters/refactor-reporter.ts +2 -2
- package/src/adapters/reporter.ts +2 -2
- package/src/core/GenesisTerminal.ts +129 -35
- package/src/core/architect.ts +13 -8
- package/src/core/interactive-refactor.ts +552 -0
- package/tests/github-action.test.ts +4 -4
- 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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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!
|
|
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
|
|
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
|
|
package/src/core/architect.ts
CHANGED
|
@@ -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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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]
|
|
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
|
|
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
|
|
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',
|