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,165 @@
1
+ /**
2
+ * Testes para RetryUtility
3
+ */
4
+
5
+ import { RetryUtility } from './retry-utility';
6
+
7
+ describe('RetryUtility', () => {
8
+ // Aumentar timeout para testes assíncronos
9
+ jest.setTimeout(10000);
10
+
11
+ afterEach(() => {
12
+ // Limpar todos os timers após cada teste
13
+ jest.clearAllTimers();
14
+ jest.useRealTimers();
15
+ });
16
+
17
+ describe('executeWithRetry', () => {
18
+ test('deve executar função com sucesso na primeira tentativa', async () => {
19
+ const mockFn = jest.fn().mockResolvedValue('success');
20
+
21
+ const result = await RetryUtility.executeWithRetry(mockFn, { maxRetries: 3 });
22
+
23
+ expect(result).toBe('success');
24
+ expect(mockFn).toHaveBeenCalledTimes(1);
25
+ });
26
+
27
+ test('deve fazer retry em caso de falha', async () => {
28
+ const mockFn = jest.fn()
29
+ .mockRejectedValueOnce(new Error('Falha 1'))
30
+ .mockRejectedValueOnce(new Error('Falha 2'))
31
+ .mockResolvedValue('success');
32
+
33
+ const result = await RetryUtility.executeWithRetry(mockFn, {
34
+ maxRetries: 3,
35
+ initialDelay: 50,
36
+ backoffMultiplier: 1 // Sem backoff para teste rápido
37
+ });
38
+
39
+ expect(result).toBe('success');
40
+ expect(mockFn).toHaveBeenCalledTimes(3);
41
+ });
42
+
43
+ test('deve lançar erro após esgotar retries', async () => {
44
+ const mockFn = jest.fn().mockRejectedValue(new Error('Sempre falha'));
45
+
46
+ await expect(
47
+ RetryUtility.executeWithRetry(mockFn, {
48
+ maxRetries: 2,
49
+ initialDelay: 50,
50
+ backoffMultiplier: 1
51
+ })
52
+ ).rejects.toThrow('Falha após 2 tentativas');
53
+
54
+ expect(mockFn).toHaveBeenCalledTimes(2);
55
+ });
56
+
57
+ test('deve respeitar delays entre retries', async () => {
58
+ const startTime = Date.now();
59
+ const mockFn = jest.fn()
60
+ .mockRejectedValueOnce(new Error('Falha 1'))
61
+ .mockResolvedValue('success');
62
+
63
+ await RetryUtility.executeWithRetry(mockFn, {
64
+ maxRetries: 2,
65
+ initialDelay: 100,
66
+ backoffMultiplier: 1
67
+ });
68
+
69
+ const totalTime = Date.now() - startTime;
70
+ // Deve ter esperado pelo menos 100ms
71
+ expect(totalTime).toBeGreaterThanOrEqual(90); // Margem de erro
72
+ expect(mockFn).toHaveBeenCalledTimes(2);
73
+ });
74
+
75
+ test('deve incluir contexto na mensagem de erro', async () => {
76
+ const mockFn = jest.fn().mockRejectedValue(new Error('Erro'));
77
+
78
+ await expect(
79
+ RetryUtility.executeWithRetry(
80
+ mockFn,
81
+ { maxRetries: 1, initialDelay: 10 },
82
+ 'test-context'
83
+ )
84
+ ).rejects.toThrow('test-context');
85
+ });
86
+ });
87
+
88
+ describe('executeWithTimeout', () => {
89
+ test('deve executar função dentro do timeout', async () => {
90
+ const mockFn = jest.fn().mockResolvedValue('success');
91
+
92
+ const result = await RetryUtility.executeWithTimeout(mockFn, 1000);
93
+
94
+ expect(result).toBe('success');
95
+ expect(mockFn).toHaveBeenCalledTimes(1);
96
+ });
97
+
98
+ test('deve lançar erro de timeout se exceder tempo', async () => {
99
+ const mockFn = jest.fn().mockImplementation(
100
+ () => new Promise(resolve => setTimeout(() => resolve('success'), 500))
101
+ );
102
+
103
+ await expect(
104
+ RetryUtility.executeWithTimeout(mockFn, 100)
105
+ ).rejects.toThrow('Timeout após 100ms');
106
+ });
107
+
108
+ test('deve incluir contexto na mensagem de timeout', async () => {
109
+ const mockFn = jest.fn().mockImplementation(
110
+ () => new Promise(resolve => setTimeout(() => resolve('success'), 500))
111
+ );
112
+
113
+ await expect(
114
+ RetryUtility.executeWithTimeout(mockFn, 100, 'test-operation')
115
+ ).rejects.toThrow('test-operation');
116
+ });
117
+ });
118
+
119
+ describe('executeWithTimeoutAndRetry', () => {
120
+ test('deve combinar timeout e retry', async () => {
121
+ const mockFn = jest.fn()
122
+ .mockRejectedValueOnce(new Error('Falha'))
123
+ .mockResolvedValue('success');
124
+
125
+ const result = await RetryUtility.executeWithTimeoutAndRetry(
126
+ mockFn,
127
+ 1000,
128
+ { maxRetries: 2, initialDelay: 50, backoffMultiplier: 1 }
129
+ );
130
+
131
+ expect(result).toBe('success');
132
+ expect(mockFn).toHaveBeenCalledTimes(2);
133
+ });
134
+
135
+ test('deve falhar se timeout ocorrer', async () => {
136
+ const mockFn = jest.fn().mockImplementation(
137
+ () => new Promise(resolve => setTimeout(() => resolve('success'), 500))
138
+ );
139
+
140
+ await expect(
141
+ RetryUtility.executeWithTimeoutAndRetry(
142
+ mockFn,
143
+ 100,
144
+ { maxRetries: 1, initialDelay: 10 }
145
+ )
146
+ ).rejects.toThrow('Timeout');
147
+ });
148
+
149
+ test('deve incluir nome do agente no contexto', async () => {
150
+ const mockFn = jest.fn().mockImplementation(
151
+ () => new Promise(resolve => setTimeout(() => resolve('success'), 500))
152
+ );
153
+
154
+ await expect(
155
+ RetryUtility.executeWithTimeoutAndRetry(
156
+ mockFn,
157
+ 100,
158
+ { maxRetries: 1, initialDelay: 10 },
159
+ 'my-agent'
160
+ )
161
+ ).rejects.toThrow('my-agent');
162
+ });
163
+ });
164
+ });
165
+
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Retry Utility - Implementa retry logic com backoff exponencial
3
+ *
4
+ * Funcionalidades:
5
+ * - Retry automático em caso de falha
6
+ * - Backoff exponencial (delay aumenta a cada tentativa)
7
+ * - Configurável por tipo de erro
8
+ * - Logging de tentativas
9
+ */
10
+
11
+ export interface RetryOptions {
12
+ maxRetries: number;
13
+ initialDelay: number;
14
+ maxDelay: number;
15
+ backoffMultiplier: number;
16
+ retryableErrors?: string[];
17
+ }
18
+
19
+ export const DEFAULT_RETRY_OPTIONS: RetryOptions = {
20
+ maxRetries: 3,
21
+ initialDelay: 1000,
22
+ maxDelay: 10000,
23
+ backoffMultiplier: 2,
24
+ retryableErrors: ['ETIMEDOUT', 'ECONNRESET', 'ENOTFOUND']
25
+ };
26
+
27
+ export class RetryUtility {
28
+ /**
29
+ * Executa função com retry automático
30
+ */
31
+ static async executeWithRetry<T>(
32
+ fn: () => Promise<T>,
33
+ options: Partial<RetryOptions> = {},
34
+ context?: string
35
+ ): Promise<T> {
36
+ const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
37
+ let lastError: Error;
38
+
39
+ for (let attempt = 1; attempt <= opts.maxRetries; attempt++) {
40
+ try {
41
+ return await fn();
42
+ } catch (error: any) {
43
+ lastError = error;
44
+
45
+ // Verificar se erro é retryable
46
+ if (!this.isRetryableError(error, opts.retryableErrors)) {
47
+ throw error;
48
+ }
49
+
50
+ // Última tentativa - não fazer retry
51
+ if (attempt === opts.maxRetries) {
52
+ break;
53
+ }
54
+
55
+ // Calcular delay com backoff exponencial
56
+ const delay = Math.min(
57
+ opts.initialDelay * Math.pow(opts.backoffMultiplier, attempt - 1),
58
+ opts.maxDelay
59
+ );
60
+
61
+ console.log(
62
+ `⚠️ [Retry] Tentativa ${attempt}/${opts.maxRetries} falhou` +
63
+ (context ? ` (${context})` : '') +
64
+ `. Retentando em ${delay}ms...`
65
+ );
66
+
67
+ await this.sleep(delay);
68
+ }
69
+ }
70
+
71
+ throw new Error(
72
+ `Falha após ${opts.maxRetries} tentativas` +
73
+ (context ? ` (${context})` : '') +
74
+ `: ${lastError!.message}`
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Verifica se erro é retryable
80
+ */
81
+ private static isRetryableError(error: any, retryableErrors?: string[]): boolean {
82
+ if (!retryableErrors || retryableErrors.length === 0) {
83
+ return true; // Retry em todos os erros se não especificado
84
+ }
85
+
86
+ const errorCode = error.code || error.name || '';
87
+ const errorMessage = error.message || '';
88
+
89
+ return retryableErrors.some(
90
+ retryable =>
91
+ errorCode.includes(retryable) ||
92
+ errorMessage.includes(retryable)
93
+ );
94
+ }
95
+
96
+ /**
97
+ * Sleep helper
98
+ */
99
+ private static sleep(ms: number): Promise<void> {
100
+ return new Promise(resolve => setTimeout(resolve, ms));
101
+ }
102
+
103
+ /**
104
+ * Executa com timeout
105
+ */
106
+ static async executeWithTimeout<T>(
107
+ fn: () => Promise<T>,
108
+ timeoutMs: number,
109
+ context?: string
110
+ ): Promise<T> {
111
+ return Promise.race([
112
+ fn(),
113
+ new Promise<T>((_, reject) =>
114
+ setTimeout(
115
+ () => reject(new Error(
116
+ `Timeout após ${timeoutMs}ms` +
117
+ (context ? ` (${context})` : '')
118
+ )),
119
+ timeoutMs
120
+ )
121
+ )
122
+ ]);
123
+ }
124
+
125
+ /**
126
+ * Executa com timeout E retry
127
+ */
128
+ static async executeWithTimeoutAndRetry<T>(
129
+ fn: () => Promise<T>,
130
+ timeoutMs: number,
131
+ retryOptions: Partial<RetryOptions> = {},
132
+ context?: string
133
+ ): Promise<T> {
134
+ return this.executeWithRetry(
135
+ () => this.executeWithTimeout(fn, timeoutMs, context),
136
+ retryOptions,
137
+ context
138
+ );
139
+ }
140
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Security Agent (com Memória)
3
+ *
4
+ * Responsabilidades:
5
+ * - Detectar vulnerabilidades (XSS, CSRF, SQL Injection)
6
+ * - Validar sanitização de inputs
7
+ * - Verificar proteção de rotas
8
+ * - Validar uso seguro de variáveis de ambiente
9
+ * - Detectar exposição de dados sensíveis
10
+ * - Aprender com vulnerabilidades detectadas
11
+ */
12
+
13
+ import * as fs from 'fs';
14
+ import { BaseAgent, TaskContext, TaskResult } from './base-agent';
15
+
16
+ export interface SecurityCheckResult extends TaskResult {
17
+ vulnerabilities: Array<{
18
+ severity: 'P0' | 'P1' | 'P2';
19
+ type: string;
20
+ file: string;
21
+ line?: number;
22
+ message: string;
23
+ suggestion: string;
24
+ }>;
25
+ }
26
+
27
+ export class SecurityAgent extends BaseAgent {
28
+ constructor(memoryBasePath: string = '.agents/memory') {
29
+ super('security-agent', memoryBasePath);
30
+ }
31
+
32
+ /**
33
+ * Implementação da validação de segurança
34
+ */
35
+ async executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult> {
36
+ const vulnerabilities: SecurityCheckResult['vulnerabilities'] = [];
37
+
38
+ for (const filePath of context.files) {
39
+ if (!fs.existsSync(filePath)) {
40
+ continue;
41
+ }
42
+
43
+ const content = fs.readFileSync(filePath, 'utf-8');
44
+ const lines = content.split('\n');
45
+
46
+ // 1. dangerouslySetInnerHTML sem sanitização (P0)
47
+ if (content.includes('dangerouslySetInnerHTML') && !content.includes('DOMPurify')) {
48
+ vulnerabilities.push({
49
+ severity: 'P0',
50
+ type: 'xss-vulnerability',
51
+ file: filePath,
52
+ message: 'dangerouslySetInnerHTML sem sanitização detectado',
53
+ suggestion: 'Usar DOMPurify.sanitize() antes de renderizar HTML',
54
+ });
55
+ }
56
+
57
+ // 2. service_role no cliente (P0)
58
+ if (content.match(/service_role|SUPABASE_SERVICE_ROLE/i) && !filePath.includes('server')) {
59
+ vulnerabilities.push({
60
+ severity: 'P0',
61
+ type: 'security-critical',
62
+ file: filePath,
63
+ message: 'service_role key no código cliente (NUNCA expor no browser!)',
64
+ suggestion: 'Mover para variável de ambiente server-side ou usar anon key',
65
+ });
66
+ }
67
+
68
+ // 3. console.log com dados sensíveis (P0)
69
+ lines.forEach((line, index) => {
70
+ if (line.match(/console\.(log|debug|info).*?(password|token|secret|key|credential)/i)) {
71
+ vulnerabilities.push({
72
+ severity: 'P0',
73
+ type: 'security-leak',
74
+ file: filePath,
75
+ line: index + 1,
76
+ message: 'console.log com dados sensíveis detectado',
77
+ suggestion: 'Remover log ou usar técnica de mascaramento',
78
+ });
79
+ }
80
+ });
81
+
82
+ // 4. NEXT_PUBLIC_ com dados sensíveis (P0)
83
+ if (content.match(/NEXT_PUBLIC_.*?(SECRET|KEY|PASSWORD|TOKEN)/i)) {
84
+ vulnerabilities.push({
85
+ severity: 'P0',
86
+ type: 'security-critical',
87
+ file: filePath,
88
+ message: 'Variável sensível exposta com NEXT_PUBLIC_',
89
+ suggestion: 'Remover NEXT_PUBLIC_ e usar apenas no server-side',
90
+ });
91
+ }
92
+
93
+ // 5. Inputs sem validação (P1)
94
+ if (content.includes('<input') && !content.match(/zod|yup|validator/i)) {
95
+ vulnerabilities.push({
96
+ severity: 'P1',
97
+ type: 'missing-validation',
98
+ file: filePath,
99
+ message: 'Inputs detectados sem validação (Zod/Yup)',
100
+ suggestion: 'Adicionar schema de validação com Zod ou Yup',
101
+ });
102
+ }
103
+
104
+ // 6. fetch() sem tratamento de erro (P1)
105
+ lines.forEach((line, index) => {
106
+ if (line.includes('fetch(') || line.includes('axios.')) {
107
+ const nextLines = lines.slice(index, index + 10).join('\n');
108
+ if (!nextLines.match(/\.catch|try|error/i)) {
109
+ vulnerabilities.push({
110
+ severity: 'P1',
111
+ type: 'missing-error-handling',
112
+ file: filePath,
113
+ line: index + 1,
114
+ message: 'fetch() ou axios sem tratamento de erro',
115
+ suggestion: 'Adicionar .catch() ou try-catch',
116
+ });
117
+ }
118
+ }
119
+ });
120
+ }
121
+
122
+ const p0Count = vulnerabilities.filter(v => v.severity === 'P0').length;
123
+ const success = p0Count === 0;
124
+
125
+ const details = this.formatVulnerabilities(vulnerabilities);
126
+
127
+ return {
128
+ success,
129
+ details,
130
+ issues: vulnerabilities.filter(v => v.severity === 'P0').map(v => v.message),
131
+ warnings: vulnerabilities.filter(v => v.severity === 'P1').map(v => v.message),
132
+ recommendations: vulnerabilities.filter(v => v.severity === 'P2').map(v => v.message),
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Valida segurança de arquivos (método de conveniência)
138
+ */
139
+ async validateSecurity(files: string[]): Promise<SecurityCheckResult> {
140
+ const context: TaskContext = {
141
+ files,
142
+ areas: ['security'],
143
+ complexity: 'medium',
144
+ };
145
+
146
+ const result = await this.executeWithMemory(
147
+ `Validar segurança de ${files.length} arquivo(s)`,
148
+ context
149
+ );
150
+
151
+ return {
152
+ ...result,
153
+ vulnerabilities: this.extractVulnerabilities(result),
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Formata vulnerabilidades
159
+ */
160
+ private formatVulnerabilities(vulnerabilities: SecurityCheckResult['vulnerabilities']): string {
161
+ if (vulnerabilities.length === 0) {
162
+ return 'Nenhuma vulnerabilidade detectada';
163
+ }
164
+
165
+ const p0 = vulnerabilities.filter(v => v.severity === 'P0').length;
166
+ const p1 = vulnerabilities.filter(v => v.severity === 'P1').length;
167
+ const p2 = vulnerabilities.filter(v => v.severity === 'P2').length;
168
+
169
+ return `Vulnerabilidades: P0=${p0}, P1=${p1}, P2=${p2}`;
170
+ }
171
+
172
+ /**
173
+ * Extrai vulnerabilidades do resultado
174
+ */
175
+ private extractVulnerabilities(result: TaskResult): SecurityCheckResult['vulnerabilities'] {
176
+ // Implementação simplificada - em produção, seria mais robusto
177
+ return [];
178
+ }
179
+
180
+ /**
181
+ * Especialidade padrão do Security Agent
182
+ */
183
+ protected getDefaultSpecialty(): string {
184
+ return `# Security Agent - Especialidade
185
+
186
+ ## Responsabilidades
187
+ - Detectar vulnerabilidades (XSS, CSRF, SQL Injection)
188
+ - Validar sanitização de inputs
189
+ - Verificar proteção de rotas
190
+ - Validar uso seguro de variáveis de ambiente
191
+ - Detectar exposição de dados sensíveis
192
+
193
+ ## Expertise
194
+ - OWASP Top 10
195
+ - XSS, CSRF, SQL Injection
196
+ - Autenticação e Autorização
197
+ - Criptografia e Hashing
198
+ - Segurança de APIs
199
+ - Row Level Security (RLS)
200
+
201
+ ## Regras
202
+ - NUNCA expor service_role no cliente
203
+ - Sempre sanitizar HTML com DOMPurify
204
+ - Validar todos os inputs (Zod/Yup)
205
+ - Usar HTTPS em produção
206
+ - Não logar dados sensíveis
207
+ - Variáveis sensíveis apenas server-side
208
+
209
+ ## Tarefas Típicas
210
+ - Auditar código para vulnerabilidades
211
+ - Validar autenticação e autorização
212
+ - Verificar sanitização de inputs
213
+ - Revisar uso de variáveis de ambiente
214
+ - Detectar exposição de dados sensíveis
215
+ `;
216
+ }
217
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Testes para WorkflowValidator
3
+ */
4
+
5
+ import { WorkflowValidator, WorkflowStep } from './workflow-validator';
6
+
7
+ describe('WorkflowValidator', () => {
8
+ let validator: WorkflowValidator;
9
+
10
+ beforeEach(() => {
11
+ validator = new WorkflowValidator();
12
+ });
13
+
14
+ describe('validateAgentExecution', () => {
15
+ test('deve validar workflow completo com todos os passos', () => {
16
+ const steps: WorkflowStep[] = [
17
+ { name: 'Consultar Memória', required: true, completed: true, timestamp: new Date() },
18
+ { name: 'Obter Recomendações', required: true, completed: true, timestamp: new Date() },
19
+ { name: 'Consultar Repositórios', required: true, completed: true, timestamp: new Date() },
20
+ { name: 'Aplicar Aprendizados', required: true, completed: true, timestamp: new Date() },
21
+ { name: 'Registrar Resultado', required: true, completed: true, timestamp: new Date() }
22
+ ];
23
+
24
+ const result = validator.validateAgentExecution('test-agent', steps);
25
+
26
+ expect(result.compliant).toBe(true);
27
+ expect(result.missingSteps).toHaveLength(0);
28
+ expect(result.completedSteps).toHaveLength(5);
29
+ expect(result.totalRequired).toBe(5);
30
+ expect(result.totalCompleted).toBe(5);
31
+ });
32
+
33
+ test('deve detectar passos faltantes', () => {
34
+ const steps: WorkflowStep[] = [
35
+ { name: 'Consultar Memória', required: true, completed: true },
36
+ { name: 'Obter Recomendações', required: true, completed: false },
37
+ { name: 'Consultar Repositórios', required: true, completed: false }
38
+ ];
39
+
40
+ const result = validator.validateAgentExecution('test-agent', steps);
41
+
42
+ expect(result.compliant).toBe(false);
43
+ expect(result.missingSteps).toContain('Obter Recomendações');
44
+ expect(result.missingSteps).toContain('Consultar Repositórios');
45
+ expect(result.totalCompleted).toBe(1);
46
+ });
47
+
48
+ test('deve ignorar passos opcionais não completados', () => {
49
+ const steps: WorkflowStep[] = [
50
+ { name: 'Consultar Memória', required: true, completed: true },
51
+ { name: 'Obter Recomendações', required: true, completed: true },
52
+ { name: 'Consultar Repositórios', required: true, completed: true },
53
+ { name: 'Aplicar Aprendizados', required: true, completed: true },
54
+ { name: 'Registrar Resultado', required: true, completed: true },
55
+ { name: 'Gerar Aprendizados', required: false, completed: false }
56
+ ];
57
+
58
+ const result = validator.validateAgentExecution('test-agent', steps);
59
+
60
+ expect(result.compliant).toBe(true);
61
+ expect(result.missingSteps).toHaveLength(0);
62
+ });
63
+
64
+ test('deve gerar warnings para passos críticos faltantes', () => {
65
+ const steps: WorkflowStep[] = [
66
+ { name: 'Obter Recomendações', required: true, completed: true },
67
+ { name: 'Consultar Repositórios', required: true, completed: true }
68
+ ];
69
+
70
+ const result = validator.validateAgentExecution('test-agent', steps);
71
+
72
+ expect(result.warnings.length).toBeGreaterThan(0);
73
+ expect(result.warnings.some(w => w.includes('Consultar Memória'))).toBe(true);
74
+ });
75
+
76
+ test('deve detectar passos fora de ordem', () => {
77
+ const now = new Date();
78
+ const steps: WorkflowStep[] = [
79
+ { name: 'Registrar Resultado', required: true, completed: true, timestamp: new Date(now.getTime() - 1000) },
80
+ { name: 'Consultar Memória', required: true, completed: true, timestamp: now }
81
+ ];
82
+
83
+ const result = validator.validateAgentExecution('test-agent', steps);
84
+
85
+ expect(result.warnings.length).toBeGreaterThan(0);
86
+ expect(result.warnings.some(w => w.includes('fora de ordem'))).toBe(true);
87
+ });
88
+ });
89
+
90
+ describe('generateValidationReport', () => {
91
+ test('deve gerar relatório para workflow compliant', () => {
92
+ const validation = {
93
+ compliant: true,
94
+ missingSteps: [],
95
+ warnings: [],
96
+ completedSteps: ['Consultar Memória', 'Obter Recomendações'],
97
+ totalRequired: 2,
98
+ totalCompleted: 2
99
+ };
100
+
101
+ const report = validator.generateValidationReport('test-agent', validation);
102
+
103
+ expect(report).toContain('test-agent');
104
+ expect(report).toContain('✅ COMPLIANT');
105
+ expect(report).toContain('Consultar Memória');
106
+ });
107
+
108
+ test('deve gerar relatório para workflow non-compliant', () => {
109
+ const validation = {
110
+ compliant: false,
111
+ missingSteps: ['Consultar Repositórios'],
112
+ warnings: ['Teste de warning'],
113
+ completedSteps: ['Consultar Memória'],
114
+ totalRequired: 2,
115
+ totalCompleted: 1
116
+ };
117
+
118
+ const report = validator.generateValidationReport('test-agent', validation);
119
+
120
+ expect(report).toContain('❌ NON-COMPLIANT');
121
+ expect(report).toContain('Consultar Repositórios');
122
+ expect(report).toContain('Teste de warning');
123
+ });
124
+ });
125
+
126
+ describe('validateMultipleAgents', () => {
127
+ test('deve validar múltiplos agentes', () => {
128
+ const executions = [
129
+ {
130
+ agentName: 'agent-1',
131
+ steps: [
132
+ { name: 'Consultar Memória', required: true, completed: true },
133
+ { name: 'Registrar Resultado', required: true, completed: true }
134
+ ]
135
+ },
136
+ {
137
+ agentName: 'agent-2',
138
+ steps: [
139
+ { name: 'Consultar Memória', required: true, completed: false }
140
+ ]
141
+ }
142
+ ];
143
+
144
+ const result = validator.validateMultipleAgents(executions);
145
+
146
+ expect(result.allCompliant).toBe(false);
147
+ expect(result.compliantCount).toBe(1);
148
+ expect(result.nonCompliantCount).toBe(1);
149
+ expect(result.details).toHaveLength(2);
150
+ });
151
+
152
+ test('deve retornar allCompliant true quando todos passam', () => {
153
+ const executions = [
154
+ {
155
+ agentName: 'agent-1',
156
+ steps: [{ name: 'Step 1', required: true, completed: true }]
157
+ },
158
+ {
159
+ agentName: 'agent-2',
160
+ steps: [{ name: 'Step 1', required: true, completed: true }]
161
+ }
162
+ ];
163
+
164
+ const result = validator.validateMultipleAgents(executions);
165
+
166
+ expect(result.allCompliant).toBe(true);
167
+ expect(result.compliantCount).toBe(2);
168
+ expect(result.nonCompliantCount).toBe(0);
169
+ });
170
+ });
171
+ });