wegho-agentes 4.0.1

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 (94) hide show
  1. package/.agents/AGENT_WORKFLOW.md +528 -0
  2. package/.agents/AI_COMPATIBILITY.md +332 -0
  3. package/.agents/CLI.md +222 -0
  4. package/.agents/README.md +130 -0
  5. package/.agents/cli.js +389 -0
  6. package/.agents/code-auditor-agent.ts +333 -0
  7. package/.agents/config.ts +145 -0
  8. package/.agents/context-loader.ts +300 -0
  9. package/.agents/core/agent-parallelizer.test.ts +94 -0
  10. package/.agents/core/agent-parallelizer.ts +108 -0
  11. package/.agents/core/architecture-agent.ts +237 -0
  12. package/.agents/core/base-agent.ts +311 -0
  13. package/.agents/core/cache-manager.test.ts +147 -0
  14. package/.agents/core/cache-manager.ts +184 -0
  15. package/.agents/core/documentation-agent.ts +183 -0
  16. package/.agents/core/feedback-collector.ts +207 -0
  17. package/.agents/core/frontend-agent.ts +210 -0
  18. package/.agents/core/inventory-agent.ts +582 -0
  19. package/.agents/core/memory-system.ts +397 -0
  20. package/.agents/core/quality-agent.ts +268 -0
  21. package/.agents/core/retry-utility.test.ts +165 -0
  22. package/.agents/core/retry-utility.ts +140 -0
  23. package/.agents/core/security-agent.ts +217 -0
  24. package/.agents/core/workflow-validator.test.ts +171 -0
  25. package/.agents/core/workflow-validator.ts +158 -0
  26. package/.agents/domains/README.md +53 -0
  27. package/.agents/domains/logistics/route-agent.ts +177 -0
  28. package/.agents/domains/news/cms-agent.ts +158 -0
  29. package/.agents/domains/news/seo-agent.ts +170 -0
  30. package/.agents/domains/production/production-control-agent.ts +169 -0
  31. package/.agents/example-learning-system.js +118 -0
  32. package/.agents/init.ts +164 -0
  33. package/.agents/memory/architecture-agent/failures.json +1 -0
  34. package/.agents/memory/architecture-agent/learnings.json +1 -0
  35. package/.agents/memory/architecture-agent/specialty.md +31 -0
  36. package/.agents/memory/architecture-agent/successes.json +16 -0
  37. package/.agents/memory/cms-agent/failures.json +1 -0
  38. package/.agents/memory/cms-agent/learnings.json +1 -0
  39. package/.agents/memory/cms-agent/specialty.md +30 -0
  40. package/.agents/memory/cms-agent/successes.json +16 -0
  41. package/.agents/memory/documentation-agent/failures.json +1 -0
  42. package/.agents/memory/documentation-agent/learnings.json +1 -0
  43. package/.agents/memory/documentation-agent/specialty.md +33 -0
  44. package/.agents/memory/documentation-agent/successes.json +16 -0
  45. package/.agents/memory/frontend-agent/failures.json +1 -0
  46. package/.agents/memory/frontend-agent/learnings.json +1 -0
  47. package/.agents/memory/frontend-agent/specialty.md +30 -0
  48. package/.agents/memory/frontend-agent/successes.json +16 -0
  49. package/.agents/memory/inventory-agent/failures.json +1 -0
  50. package/.agents/memory/inventory-agent/inventory/index.json +8 -0
  51. package/.agents/memory/inventory-agent/inventory/types.json +77716 -0
  52. package/.agents/memory/inventory-agent/inventory/variables.json +405 -0
  53. package/.agents/memory/inventory-agent/learnings.json +1 -0
  54. package/.agents/memory/inventory-agent/specialty.md +129 -0
  55. package/.agents/memory/inventory-agent/successes.json +30 -0
  56. package/.agents/memory/production-control-agent/failures.json +1 -0
  57. package/.agents/memory/production-control-agent/learnings.json +1 -0
  58. package/.agents/memory/production-control-agent/specialty.md +29 -0
  59. package/.agents/memory/production-control-agent/successes.json +16 -0
  60. package/.agents/memory/quality-agent/failures.json +16 -0
  61. package/.agents/memory/quality-agent/learnings.json +1 -0
  62. package/.agents/memory/quality-agent/specialty.md +31 -0
  63. package/.agents/memory/quality-agent/successes.json +1 -0
  64. package/.agents/memory/reference-repositories.json +271 -0
  65. package/.agents/memory/route-agent/failures.json +1 -0
  66. package/.agents/memory/route-agent/learnings.json +1 -0
  67. package/.agents/memory/route-agent/specialty.md +29 -0
  68. package/.agents/memory/route-agent/successes.json +16 -0
  69. package/.agents/memory/security-agent/failures.json +1 -0
  70. package/.agents/memory/security-agent/learnings.json +1 -0
  71. package/.agents/memory/security-agent/specialty.md +31 -0
  72. package/.agents/memory/security-agent/successes.json +16 -0
  73. package/.agents/memory/seo-agent/failures.json +1 -0
  74. package/.agents/memory/seo-agent/learnings.json +1 -0
  75. package/.agents/memory/seo-agent/specialty.md +31 -0
  76. package/.agents/memory/seo-agent/successes.json +16 -0
  77. package/.agents/orchestrator.ts +438 -0
  78. package/.agents/project-discovery-agent.ts +342 -0
  79. package/.agents/security/pentesting-agent.py +387 -0
  80. package/.agents/security/python-bridge.ts +193 -0
  81. package/.agents/security/vulnerability-db.json +201 -0
  82. package/.agents/task-analyzer-agent.ts +346 -0
  83. package/.agents/test-init-context.js +67 -0
  84. package/INSTALL.md +300 -0
  85. package/LICENSE +21 -0
  86. package/README.md +315 -0
  87. package/docs/AGENT_RULES.md +292 -0
  88. package/docs/BUILD_HISTORY.md +65 -0
  89. package/docs/DESIGN_SYSTEM.md +256 -0
  90. package/docs/LEARNING_SYSTEM.md +326 -0
  91. package/docs/SYMBOLS_TREE.md +182 -0
  92. package/docs/VERSION.md +6 -0
  93. package/docs/architecture.md +111 -0
  94. package/package.json +60 -0
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Architecture Agent (com Memória)
3
+ *
4
+ * Responsabilidades:
5
+ * - Validar estrutura de arquivos
6
+ * - Garantir limite de 500 linhas por arquivo
7
+ * - Detectar duplicação de código
8
+ * - Validar separação de camadas
9
+ * - Aprender padrões arquiteturais que funcionam
10
+ */
11
+
12
+ import * as fs from 'fs';
13
+ import * as path from 'path';
14
+ import { BaseAgent, TaskContext, TaskResult } from './base-agent';
15
+ import { validateFileLines } from '../config';
16
+
17
+ export interface ArchitectureCheckResult extends TaskResult {
18
+ violations: Array<{
19
+ type: string;
20
+ file: string;
21
+ severity: 'error' | 'warning';
22
+ message: string;
23
+ suggestion: string;
24
+ }>;
25
+ }
26
+
27
+ export class ArchitectureAgent extends BaseAgent {
28
+ constructor(memoryBasePath: string = '.agents/memory') {
29
+ super('architecture-agent', memoryBasePath);
30
+ }
31
+
32
+ /**
33
+ * Implementação da validação arquitetural
34
+ */
35
+ async executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult> {
36
+ const violations: ArchitectureCheckResult['violations'] = [];
37
+
38
+ for (const filePath of context.files) {
39
+ if (!fs.existsSync(filePath)) {
40
+ continue;
41
+ }
42
+
43
+ // 1. Verificar limite de 500 linhas
44
+ const lineCheck = validateFileLines(filePath, 500);
45
+ if (!lineCheck.valid) {
46
+ violations.push({
47
+ type: 'file-too-long',
48
+ file: filePath,
49
+ severity: 'error',
50
+ message: `Arquivo tem ${lineCheck.lineCount} linhas (limite: 500)`,
51
+ suggestion: 'Refatorar: extrair funções, componentes ou classes para arquivos separados'
52
+ });
53
+ }
54
+
55
+ const content = fs.readFileSync(filePath, 'utf-8');
56
+
57
+ // 2. Detectar duplicação de código
58
+ const duplicates = this.detectCodeDuplication(content);
59
+ if (duplicates.length > 0) {
60
+ violations.push({
61
+ type: 'code-duplication',
62
+ file: filePath,
63
+ severity: 'warning',
64
+ message: `${duplicates.length} bloco(s) de código duplicado detectado(s)`,
65
+ suggestion: 'Extrair código duplicado para funções/componentes reutilizáveis'
66
+ });
67
+ }
68
+
69
+ // 3. Validar separação de camadas
70
+ const layerViolations = this.validateLayerSeparation(filePath, content);
71
+ violations.push(...layerViolations);
72
+
73
+ // 4. Verificar nomenclatura
74
+ const namingIssues = this.validateNaming(filePath);
75
+ violations.push(...namingIssues);
76
+ }
77
+
78
+ const errors = violations.filter(v => v.severity === 'error');
79
+ const success = errors.length === 0;
80
+
81
+ const details = this.formatViolations(violations);
82
+
83
+ return {
84
+ success,
85
+ details,
86
+ issues: errors.map(v => v.message),
87
+ warnings: violations.filter(v => v.severity === 'warning').map(v => v.message),
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Detecta duplicação de código
93
+ */
94
+ private detectCodeDuplication(content: string): string[] {
95
+ const duplicates: string[] = [];
96
+ const lines = content.split('\n');
97
+ const blockSize = 5; // Mínimo de 5 linhas para considerar duplicação
98
+
99
+ // Algoritmo simplificado - em produção usaria algo como jscpd
100
+ const blocks = new Map<string, number>();
101
+
102
+ for (let i = 0; i <= lines.length - blockSize; i++) {
103
+ const block = lines.slice(i, i + blockSize).join('\n').trim();
104
+ if (block.length > 50) { // Ignorar blocos muito pequenos
105
+ const count = blocks.get(block) || 0;
106
+ blocks.set(block, count + 1);
107
+ }
108
+ }
109
+
110
+ blocks.forEach((count, block) => {
111
+ if (count > 1) {
112
+ duplicates.push(block.substring(0, 100) + '...');
113
+ }
114
+ });
115
+
116
+ return duplicates;
117
+ }
118
+
119
+ /**
120
+ * Valida separação de camadas
121
+ */
122
+ private validateLayerSeparation(filePath: string, content: string): ArchitectureCheckResult['violations'] {
123
+ const violations: ArchitectureCheckResult['violations'] = [];
124
+
125
+ // Componentes não devem ter lógica de API direta
126
+ if (filePath.includes('components/') && !filePath.includes('pages/')) {
127
+ if (content.match(/fetch\(|axios\.|supabase\./)) {
128
+ violations.push({
129
+ type: 'layer-violation',
130
+ file: filePath,
131
+ severity: 'warning',
132
+ message: 'Componente com chamada de API direta',
133
+ suggestion: 'Extrair lógica de API para hook customizado ou service'
134
+ });
135
+ }
136
+ }
137
+
138
+ // Utils não devem importar componentes
139
+ if (filePath.includes('utils/') || filePath.includes('lib/')) {
140
+ if (content.match(/import.*from.*components/)) {
141
+ violations.push({
142
+ type: 'layer-violation',
143
+ file: filePath,
144
+ severity: 'error',
145
+ message: 'Arquivo de utilidade importando componente',
146
+ suggestion: 'Utils devem ser independentes de componentes UI'
147
+ });
148
+ }
149
+ }
150
+
151
+ return violations;
152
+ }
153
+
154
+ /**
155
+ * Valida nomenclatura de arquivos
156
+ */
157
+ private validateNaming(filePath: string): ArchitectureCheckResult['violations'] {
158
+ const violations: ArchitectureCheckResult['violations'] = [];
159
+ const fileName = path.basename(filePath);
160
+
161
+ // Componentes React devem usar PascalCase
162
+ if (filePath.includes('components/') && fileName.match(/^[a-z]/)) {
163
+ violations.push({
164
+ type: 'naming-convention',
165
+ file: filePath,
166
+ severity: 'warning',
167
+ message: 'Componente deve usar PascalCase',
168
+ suggestion: `Renomear para ${fileName.charAt(0).toUpperCase() + fileName.slice(1)}`
169
+ });
170
+ }
171
+
172
+ // Hooks devem começar com 'use'
173
+ if (filePath.includes('hooks/') && !fileName.startsWith('use')) {
174
+ violations.push({
175
+ type: 'naming-convention',
176
+ file: filePath,
177
+ severity: 'warning',
178
+ message: 'Hook customizado deve começar com "use"',
179
+ suggestion: `Renomear para use${fileName.charAt(0).toUpperCase() + fileName.slice(1)}`
180
+ });
181
+ }
182
+
183
+ return violations;
184
+ }
185
+
186
+ /**
187
+ * Formata violações
188
+ */
189
+ private formatViolations(violations: ArchitectureCheckResult['violations']): string {
190
+ if (violations.length === 0) {
191
+ return 'Arquitetura validada com sucesso';
192
+ }
193
+
194
+ const errors = violations.filter(v => v.severity === 'error').length;
195
+ const warnings = violations.filter(v => v.severity === 'warning').length;
196
+
197
+ return `Violações: ${errors} erro(s), ${warnings} aviso(s)`;
198
+ }
199
+
200
+ /**
201
+ * Especialidade padrão do Architecture Agent
202
+ */
203
+ protected getDefaultSpecialty(): string {
204
+ return `# Architecture Agent - Especialidade
205
+
206
+ ## Responsabilidades
207
+ - Validar estrutura de arquivos
208
+ - Garantir limite de 500 linhas por arquivo
209
+ - Detectar duplicação de código
210
+ - Validar separação de camadas (MVC, Clean Architecture)
211
+ - Verificar nomenclatura consistente
212
+
213
+ ## Expertise
214
+ - Design Patterns (Factory, Strategy, Observer, etc.)
215
+ - SOLID Principles
216
+ - Clean Architecture
217
+ - Microservices Architecture
218
+ - Modularização e Componentização
219
+ - DRY (Don't Repeat Yourself)
220
+
221
+ ## Regras
222
+ - Máximo 500 linhas por arquivo
223
+ - Sem duplicação de código (DRY)
224
+ - Separação clara de responsabilidades
225
+ - Nomenclatura consistente (PascalCase para componentes, camelCase para funções)
226
+ - Componentes UI não devem ter lógica de API
227
+ - Utils devem ser independentes de UI
228
+
229
+ ## Tarefas Típicas
230
+ - Validar estrutura de novos componentes
231
+ - Detectar código duplicado
232
+ - Sugerir refatorações
233
+ - Validar separação de camadas
234
+ - Revisar nomenclatura de arquivos
235
+ `;
236
+ }
237
+ }
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Base Agent - Classe base para todos os agentes
3
+ *
4
+ * Responsabilidades:
5
+ * - Fornecer interface comum para todos os agentes
6
+ * - Integrar sistema de memória
7
+ * - Gerenciar consulta e registro de resultados
8
+ * - Implementar aprendizado contínuo
9
+ */
10
+
11
+ import { MemorySystem, MemoryEntry } from './memory-system';
12
+ import { WorkflowStep } from './workflow-validator';
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+
16
+ export interface TaskContext {
17
+ files: string[];
18
+ areas: string[];
19
+ complexity: 'low' | 'medium' | 'high';
20
+ }
21
+
22
+ export interface TaskResult {
23
+ success: boolean;
24
+ details: string;
25
+ issues?: string[];
26
+ warnings?: string[];
27
+ recommendations?: string[];
28
+ }
29
+
30
+ export interface UserFeedback {
31
+ satisfied: boolean;
32
+ likes: string[];
33
+ dislikes: string[];
34
+ suggestions: string[];
35
+ }
36
+
37
+ /**
38
+ * Classe base abstrata para agentes
39
+ */
40
+ export abstract class BaseAgent {
41
+ protected agentName: string;
42
+ protected memory: MemorySystem;
43
+ protected specialtyPath: string;
44
+ protected workflowSteps: WorkflowStep[] = [];
45
+ protected referenceReposPath: string;
46
+
47
+ constructor(agentName: string, memoryBasePath: string = '.agents/memory') {
48
+ this.agentName = agentName;
49
+ this.memory = new MemorySystem(memoryBasePath);
50
+ this.specialtyPath = path.join(memoryBasePath, agentName, 'specialty.md');
51
+ this.referenceReposPath = path.join(memoryBasePath, 'reference-repositories.json');
52
+ this.ensureSpecialtyFile();
53
+ this.initializeWorkflowSteps();
54
+ }
55
+
56
+ /**
57
+ * Método abstrato: cada agente implementa sua lógica
58
+ */
59
+ abstract executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult>;
60
+
61
+ /**
62
+ * Executa tarefa consultando memória
63
+ */
64
+ async executeWithMemory(taskDescription: string, context: TaskContext): Promise<TaskResult> {
65
+ console.log(`\n${'='.repeat(60)}`);
66
+ console.log(`🤖 AGENTE ATIVO: ${this.agentName.toUpperCase()}`);
67
+ console.log(`${'='.repeat(60)}`);
68
+ console.log(`📋 Tarefa: ${taskDescription}`);
69
+ console.log(`⏰ Início: ${new Date().toLocaleTimeString('pt-BR')}\n`);
70
+
71
+ // PASSO 1: Consultar casos similares
72
+ this.markStepCompleted('Consultar Memória', { count: 0 });
73
+ const similarCases = this.memory.getSimilarCases(this.agentName, taskDescription, 5);
74
+
75
+ if (similarCases.length > 0) {
76
+ console.log(`💭 [${this.agentName}] Encontrei ${similarCases.length} caso(s) similar(es):`);
77
+ similarCases.forEach((case_, index) => {
78
+ const emoji = case_.result === 'success' ? '✅' : '❌';
79
+ console.log(` ${index + 1}. ${emoji} ${case_.taskDescription}`);
80
+ if (case_.userFeedback) {
81
+ console.log(` Feedback: ${case_.userFeedback.satisfied ? '👍' : '👎'}`);
82
+ }
83
+ });
84
+ this.updateStepDetails('Consultar Memória', { count: similarCases.length });
85
+ }
86
+
87
+ // PASSO 2: Obter recomendações baseadas em aprendizados
88
+ this.markStepCompleted('Obter Recomendações', { count: 0 });
89
+ const recommendations = this.memory.getRecommendations(this.agentName, taskDescription);
90
+
91
+ if (recommendations.length > 0) {
92
+ console.log(`\n💡 [${this.agentName}] Recomendações baseadas em aprendizados:`);
93
+ recommendations.forEach((rec, index) => {
94
+ console.log(` ${index + 1}. ${rec}`);
95
+ });
96
+ this.updateStepDetails('Obter Recomendações', { count: recommendations.length });
97
+ }
98
+
99
+ // PASSO 3: Consultar repositórios de referência
100
+ this.markStepCompleted('Consultar Repositórios');
101
+ await this.consultReferenceRepositories();
102
+
103
+ // PASSO 4: Aplicar aprendizados com alta confiança
104
+ this.markStepCompleted('Aplicar Aprendizados');
105
+ this.applyHighConfidenceLearnings(recommendations);
106
+
107
+ // Executar tarefa
108
+ console.log(`\n⚙️ [${this.agentName}] Executando tarefa...\n`);
109
+ const result = await this.executeTask(taskDescription, context);
110
+
111
+ // PASSO 5: Registrar resultado
112
+ this.markStepCompleted('Registrar Resultado');
113
+ await this.recordOutcome(taskDescription, context, result);
114
+
115
+ const status = result.success ? '✅ SUCESSO' : '❌ FALHA';
116
+ console.log(`\n${status} [${this.agentName}] Tarefa concluída`);
117
+ console.log(`⏰ Término: ${new Date().toLocaleTimeString('pt-BR')}`);
118
+ console.log(`${'='.repeat(60)}\n`);
119
+
120
+ return result;
121
+ }
122
+
123
+ /**
124
+ * Registra resultado na memória
125
+ */
126
+ async recordOutcome(
127
+ taskDescription: string,
128
+ context: TaskContext,
129
+ result: TaskResult,
130
+ userFeedback?: UserFeedback
131
+ ): Promise<void> {
132
+ if (result.success) {
133
+ this.memory.recordSuccess(
134
+ this.agentName,
135
+ taskDescription,
136
+ context,
137
+ result.details,
138
+ userFeedback
139
+ );
140
+ } else {
141
+ this.memory.recordFailure(
142
+ this.agentName,
143
+ taskDescription,
144
+ context,
145
+ result.details,
146
+ userFeedback
147
+ );
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Adiciona aprendizado baseado em feedback
153
+ */
154
+ async learn(
155
+ pattern: string,
156
+ description: string,
157
+ recommendation: string,
158
+ exampleIds: string[] = []
159
+ ): Promise<void> {
160
+ this.memory.addLearning(
161
+ this.agentName,
162
+ pattern,
163
+ description,
164
+ recommendation,
165
+ exampleIds
166
+ );
167
+ }
168
+
169
+ /**
170
+ * Obtém estatísticas do agente
171
+ */
172
+ getStats() {
173
+ return this.memory.getStats(this.agentName);
174
+ }
175
+
176
+ /**
177
+ * Lê arquivo de especialidade
178
+ */
179
+ getSpecialty(): string {
180
+ if (fs.existsSync(this.specialtyPath)) {
181
+ return fs.readFileSync(this.specialtyPath, 'utf-8');
182
+ }
183
+ return 'Especialidade não definida';
184
+ }
185
+
186
+ /**
187
+ * Garante que arquivo de especialidade existe
188
+ */
189
+ private ensureSpecialtyFile(): void {
190
+ const agentDir = path.dirname(this.specialtyPath);
191
+
192
+ if (!fs.existsSync(agentDir)) {
193
+ fs.mkdirSync(agentDir, { recursive: true });
194
+ }
195
+
196
+ if (!fs.existsSync(this.specialtyPath)) {
197
+ const defaultSpecialty = this.getDefaultSpecialty();
198
+ fs.writeFileSync(this.specialtyPath, defaultSpecialty, 'utf-8');
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Retorna especialidade padrão (pode ser sobrescrito)
204
+ */
205
+ protected getDefaultSpecialty(): string {
206
+ return `# ${this.agentName} - Especialidade
207
+
208
+ ## Responsabilidades
209
+ - Definir responsabilidades específicas
210
+
211
+ ## Expertise
212
+ - Definir áreas de expertise
213
+
214
+ ## Regras
215
+ - Definir regras específicas
216
+
217
+ ## Tarefas Típicas
218
+ - Listar tarefas típicas
219
+ `;
220
+ }
221
+
222
+ /**
223
+ * Inicializa os passos do workflow
224
+ */
225
+ private initializeWorkflowSteps(): void {
226
+ this.workflowSteps = [
227
+ { name: 'Consultar Memória', required: true, completed: false },
228
+ { name: 'Obter Recomendações', required: true, completed: false },
229
+ { name: 'Consultar Repositórios', required: true, completed: false },
230
+ { name: 'Aplicar Aprendizados', required: true, completed: false },
231
+ { name: 'Registrar Resultado', required: true, completed: false },
232
+ { name: 'Gerar Aprendizados', required: false, completed: false }
233
+ ];
234
+ }
235
+
236
+ /**
237
+ * Marca um passo como completado
238
+ */
239
+ protected markStepCompleted(stepName: string, details?: any): void {
240
+ const step = this.workflowSteps.find(s => s.name === stepName);
241
+ if (step) {
242
+ step.completed = true;
243
+ step.timestamp = new Date();
244
+ step.details = details;
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Atualiza detalhes de um passo
250
+ */
251
+ protected updateStepDetails(stepName: string, details: any): void {
252
+ const step = this.workflowSteps.find(s => s.name === stepName);
253
+ if (step) {
254
+ step.details = { ...step.details, ...details };
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Retorna os passos do workflow para validação
260
+ */
261
+ getWorkflowSteps(): WorkflowStep[] {
262
+ return [...this.workflowSteps];
263
+ }
264
+
265
+ /**
266
+ * Consulta repositórios de referência relevantes
267
+ */
268
+ protected async consultReferenceRepositories(): Promise<void> {
269
+ try {
270
+ if (!fs.existsSync(this.referenceReposPath)) {
271
+ console.log(`⚠️ [${this.agentName}] Arquivo de repositórios não encontrado`);
272
+ return;
273
+ }
274
+
275
+ const repos = JSON.parse(fs.readFileSync(this.referenceReposPath, 'utf-8'));
276
+ const relevantRepos = this.getRelevantRepositories(repos);
277
+
278
+ if (relevantRepos.length > 0) {
279
+ console.log(`\n📚 [${this.agentName}] Consultando repositórios de referência:`);
280
+ relevantRepos.forEach(repo => {
281
+ console.log(` - ${repo.name}: ${repo.url}`);
282
+ });
283
+ }
284
+ } catch (error: any) {
285
+ console.log(`⚠️ [${this.agentName}] Erro ao consultar repositórios:`, error.message);
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Retorna repositórios relevantes para este agente (pode ser sobrescrito)
291
+ */
292
+ protected getRelevantRepositories(repos: any): Array<{ name: string; url: string }> {
293
+ // Implementação padrão - pode ser sobrescrita por agentes específicos
294
+ return [];
295
+ }
296
+
297
+ /**
298
+ * Aplica aprendizados com alta confiança
299
+ */
300
+ protected applyHighConfidenceLearnings(recommendations: string[]): void {
301
+ const memory = this.memory.loadMemory(this.agentName);
302
+ const highConfidenceLearnings = memory.learnings.filter(l => l.confidence > 0.7);
303
+
304
+ if (highConfidenceLearnings.length > 0) {
305
+ console.log(`\n🎯 [${this.agentName}] Aplicando ${highConfidenceLearnings.length} aprendizado(s) de alta confiança:`);
306
+ highConfidenceLearnings.forEach((learning, index) => {
307
+ console.log(` ${index + 1}. ${learning.recommendation} (confiança: ${(learning.confidence * 100).toFixed(0)}%)`);
308
+ });
309
+ }
310
+ }
311
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Testes para CacheManager
3
+ */
4
+
5
+ import { CacheManager } from './cache-manager';
6
+
7
+ describe('CacheManager', () => {
8
+ let cache: CacheManager;
9
+
10
+ beforeEach(() => {
11
+ cache = new CacheManager(1000, 100); // 1s TTL, max 100 entries
12
+ });
13
+
14
+ afterEach(() => {
15
+ cache.clear();
16
+ });
17
+
18
+ describe('get and set', () => {
19
+ test('deve armazenar e recuperar valores', () => {
20
+ cache.set('key1', 'value1');
21
+ const result = cache.get<string>('key1');
22
+
23
+ expect(result).toBe('value1');
24
+ });
25
+
26
+ test('deve retornar null para chave inexistente', () => {
27
+ const result = cache.get('nonexistent');
28
+
29
+ expect(result).toBeNull();
30
+ });
31
+
32
+ test('deve expirar entradas após TTL', async () => {
33
+ cache.set('key1', 'value1', 100); // 100ms TTL
34
+
35
+ expect(cache.get('key1')).toBe('value1');
36
+
37
+ await new Promise(resolve => setTimeout(resolve, 150));
38
+
39
+ expect(cache.get('key1')).toBeNull();
40
+ });
41
+
42
+ test('deve usar TTL customizado', async () => {
43
+ cache.set('key1', 'value1', 200); // 200ms TTL
44
+
45
+ await new Promise(resolve => setTimeout(resolve, 150));
46
+ expect(cache.get('key1')).toBe('value1'); // Ainda válido
47
+
48
+ await new Promise(resolve => setTimeout(resolve, 100));
49
+ expect(cache.get('key1')).toBeNull(); // Expirou
50
+ });
51
+ });
52
+
53
+ describe('statistics', () => {
54
+ test('deve rastrear hits e misses', () => {
55
+ cache.set('key1', 'value1');
56
+
57
+ cache.get('key1'); // hit
58
+ cache.get('key2'); // miss
59
+ cache.get('key1'); // hit
60
+
61
+ const stats = cache.getStats();
62
+
63
+ expect(stats.hits).toBe(2);
64
+ expect(stats.misses).toBe(1);
65
+ expect(stats.hitRate).toBeCloseTo(66.67, 1);
66
+ });
67
+
68
+ test('deve resetar estatísticas', () => {
69
+ cache.set('key1', 'value1');
70
+ cache.get('key1');
71
+ cache.get('key2');
72
+
73
+ cache.resetStats();
74
+ const stats = cache.getStats();
75
+
76
+ expect(stats.hits).toBe(0);
77
+ expect(stats.misses).toBe(0);
78
+ });
79
+ });
80
+
81
+ describe('cleanup', () => {
82
+ test('deve remover entradas expiradas', async () => {
83
+ cache.set('key1', 'value1', 100);
84
+ cache.set('key2', 'value2', 1000);
85
+
86
+ await new Promise(resolve => setTimeout(resolve, 150));
87
+
88
+ const removed = cache.cleanup();
89
+
90
+ expect(removed).toBe(1);
91
+ expect(cache.size()).toBe(1);
92
+ expect(cache.get('key2')).toBe('value2');
93
+ });
94
+ });
95
+
96
+ describe('LRU eviction', () => {
97
+ test('deve remover entrada menos usada quando atingir limite', () => {
98
+ const smallCache = new CacheManager(1000, 3);
99
+
100
+ smallCache.set('key1', 'value1');
101
+ smallCache.set('key2', 'value2');
102
+ smallCache.set('key3', 'value3');
103
+
104
+ // Acessar key1 e key2 para aumentar hits
105
+ smallCache.get('key1');
106
+ smallCache.get('key2');
107
+
108
+ // Adicionar key4 deve remover key3 (menos usada)
109
+ smallCache.set('key4', 'value4');
110
+
111
+ expect(smallCache.has('key3')).toBe(false);
112
+ expect(smallCache.has('key1')).toBe(true);
113
+ expect(smallCache.size()).toBe(3);
114
+ });
115
+ });
116
+
117
+ describe('has', () => {
118
+ test('deve verificar existência de chave', () => {
119
+ cache.set('key1', 'value1');
120
+
121
+ expect(cache.has('key1')).toBe(true);
122
+ expect(cache.has('key2')).toBe(false);
123
+ });
124
+
125
+ test('deve retornar false para chave expirada', async () => {
126
+ cache.set('key1', 'value1', 100);
127
+
128
+ expect(cache.has('key1')).toBe(true);
129
+
130
+ await new Promise(resolve => setTimeout(resolve, 150));
131
+
132
+ expect(cache.has('key1')).toBe(false);
133
+ });
134
+ });
135
+
136
+ describe('clear', () => {
137
+ test('deve limpar todo o cache', () => {
138
+ cache.set('key1', 'value1');
139
+ cache.set('key2', 'value2');
140
+
141
+ cache.clear();
142
+
143
+ expect(cache.size()).toBe(0);
144
+ expect(cache.get('key1')).toBeNull();
145
+ });
146
+ });
147
+ });