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,582 @@
1
+ import { BaseAgent, TaskContext, TaskResult } from './base-agent';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import { glob } from 'glob';
5
+
6
+ // ============================================================
7
+ // 🏭 INVENTORY AGENT - ALMOXARIFADO CENTRAL DO SISTEMA
8
+ // ============================================================
9
+ // Responsável por:
10
+ // 1. Mapear TUDO no projeto (componentes, variáveis, banco, APIs)
11
+ // 2. Fornecer busca rápida para outros agentes
12
+ // 3. IMPEDIR duplicação de código
13
+ // 4. Organizar e catalogar recursos
14
+ // ============================================================
15
+
16
+ interface InventoryItem {
17
+ id: string;
18
+ name: string;
19
+ type: 'component' | 'variable' | 'table' | 'endpoint' | 'type' | 'asset' | 'function';
20
+ path: string;
21
+ line?: number;
22
+ metadata: Record<string, any>;
23
+ usedBy: string[];
24
+ createdAt: string;
25
+ lastModified: string;
26
+ }
27
+
28
+ interface Component extends InventoryItem {
29
+ type: 'component';
30
+ exports: string[];
31
+ props: string[];
32
+ dependencies: string[];
33
+ }
34
+
35
+ interface Variable extends InventoryItem {
36
+ type: 'variable';
37
+ scope: 'global' | 'local' | 'exported';
38
+ value?: string;
39
+ dataType: string;
40
+ }
41
+
42
+ interface DatabaseTable extends InventoryItem {
43
+ type: 'table';
44
+ schema: string;
45
+ columns: Array<{
46
+ name: string;
47
+ type: string;
48
+ nullable: boolean;
49
+ primaryKey?: boolean;
50
+ foreignKey?: string;
51
+ }>;
52
+ relationships: Array<{
53
+ table: string;
54
+ type: 'one-to-one' | 'one-to-many' | 'many-to-many';
55
+ foreignKey: string;
56
+ }>;
57
+ }
58
+
59
+ interface Endpoint extends InventoryItem {
60
+ type: 'endpoint';
61
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
62
+ params?: string[];
63
+ body?: Record<string, string>;
64
+ response?: string;
65
+ authentication: boolean;
66
+ }
67
+
68
+ interface InventoryQuery {
69
+ type?: InventoryItem['type'];
70
+ name?: string;
71
+ path?: string;
72
+ fuzzy?: boolean;
73
+ }
74
+
75
+ interface DuplicationCheck {
76
+ exists: boolean;
77
+ duplicates: InventoryItem[];
78
+ suggestions: string[];
79
+ }
80
+
81
+ export class InventoryAgent extends BaseAgent {
82
+ private inventory: Map<string, InventoryItem> = new Map();
83
+ private inventoryPath: string;
84
+ private projectRoot: string;
85
+
86
+ constructor(projectRoot: string, memoryBasePath: string = '.agents/memory') {
87
+ super('inventory-agent', memoryBasePath);
88
+ this.projectRoot = projectRoot;
89
+ this.inventoryPath = path.join(memoryBasePath, 'inventory-agent', 'inventory');
90
+ }
91
+
92
+ async executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult> {
93
+ try {
94
+ // Determinar ação baseada na descrição da tarefa
95
+ if (taskDescription.includes('scan') || taskDescription.includes('escanear')) {
96
+ await this.scanProject();
97
+ return {
98
+ success: true,
99
+ details: `Inventário completo: ${this.inventory.size} itens catalogados`,
100
+ recommendations: [`Total de ${this.inventory.size} itens no almoxarifado`],
101
+ };
102
+ }
103
+
104
+ if (taskDescription.includes('find') || taskDescription.includes('buscar')) {
105
+ const query = this.parseQuery(taskDescription);
106
+ const results = await this.findAll(query);
107
+ return {
108
+ success: true,
109
+ details: `Encontrados ${results.length} itens`,
110
+ recommendations: results.map((r) => `${r.type}: ${r.name} (${r.path})`),
111
+ };
112
+ }
113
+
114
+ if (taskDescription.includes('check') || taskDescription.includes('verificar')) {
115
+ const itemName = this.extractItemName(taskDescription);
116
+ const check = await this.checkDuplication(itemName, 'component');
117
+ return {
118
+ success: !check.exists,
119
+ details: check.exists
120
+ ? `Item "${itemName}" já existe`
121
+ : `Nenhuma duplicação encontrada para "${itemName}"`,
122
+ warnings: check.exists ? [`Duplicação detectada: ${itemName}`] : undefined,
123
+ recommendations: check.suggestions,
124
+ };
125
+ }
126
+
127
+ // Scan padrão
128
+ await this.scanProject();
129
+ return {
130
+ success: true,
131
+ details: `Scan completo: ${this.inventory.size} itens catalogados`,
132
+ };
133
+ } catch (error) {
134
+ return {
135
+ success: false,
136
+ details: `Erro ao executar tarefa: ${(error as Error).message}`,
137
+ issues: [(error as Error).message],
138
+ };
139
+ }
140
+ }
141
+
142
+ // ============================================================
143
+ // 🔍 MÉTODOS DE BUSCA (Para outros agentes)
144
+ // ============================================================
145
+
146
+ /**
147
+ * Busca um único item no inventário
148
+ */
149
+ async find(query: InventoryQuery): Promise<InventoryItem | null> {
150
+ const results = await this.findAll(query);
151
+ return results[0] || null;
152
+ }
153
+
154
+ /**
155
+ * Busca todos os itens que correspondem à query
156
+ */
157
+ async findAll(query: InventoryQuery): Promise<InventoryItem[]> {
158
+ await this.loadInventory();
159
+
160
+ let results = Array.from(this.inventory.values());
161
+
162
+ // Filtrar por tipo
163
+ if (query.type) {
164
+ results = results.filter((item) => item.type === query.type);
165
+ }
166
+
167
+ // Filtrar por nome
168
+ if (query.name) {
169
+ if (query.fuzzy) {
170
+ // Busca fuzzy (case-insensitive, parcial)
171
+ const searchTerm = query.name.toLowerCase();
172
+ results = results.filter((item) => item.name.toLowerCase().includes(searchTerm));
173
+ } else {
174
+ // Busca exata
175
+ results = results.filter((item) => item.name === query.name);
176
+ }
177
+ }
178
+
179
+ // Filtrar por path
180
+ if (query.path) {
181
+ results = results.filter((item) => item.path.includes(query.path!));
182
+ }
183
+
184
+ return results;
185
+ }
186
+
187
+ /**
188
+ * Busca textual em todo o inventário
189
+ */
190
+ async search(text: string): Promise<InventoryItem[]> {
191
+ await this.loadInventory();
192
+
193
+ const searchTerm = text.toLowerCase();
194
+ return Array.from(this.inventory.values()).filter(
195
+ (item) =>
196
+ item.name.toLowerCase().includes(searchTerm) ||
197
+ item.path.toLowerCase().includes(searchTerm) ||
198
+ JSON.stringify(item.metadata).toLowerCase().includes(searchTerm)
199
+ );
200
+ }
201
+
202
+ // ============================================================
203
+ // 🛡️ VERIFICAÇÃO ANTI-DUPLICAÇÃO (CRÍTICO!)
204
+ // ============================================================
205
+
206
+ /**
207
+ * Verifica se um item já existe antes de criar
208
+ * TODOS os agentes DEVEM chamar isso antes de criar algo novo!
209
+ */
210
+ async checkDuplication(name: string, type: InventoryItem['type']): Promise<DuplicationCheck> {
211
+ await this.loadInventory();
212
+
213
+ // Busca exata
214
+ const exact = await this.find({ name, type });
215
+
216
+ // Busca fuzzy (similares)
217
+ const similar = await this.findAll({ name, type, fuzzy: true });
218
+
219
+ const exists = exact !== null;
220
+ const duplicates = similar.filter((item) => item.name !== name);
221
+
222
+ const suggestions: string[] = [];
223
+
224
+ if (exists) {
225
+ suggestions.push(`⚠️ Item "${name}" já existe em: ${exact.path}`);
226
+ suggestions.push(`💡 Use o existente em vez de criar novo`);
227
+ }
228
+
229
+ if (duplicates.length > 0) {
230
+ suggestions.push(`⚠️ Encontrados ${duplicates.length} item(ns) similar(es):`);
231
+ duplicates.forEach((dup) => {
232
+ suggestions.push(` - ${dup.name} (${dup.path})`);
233
+ });
234
+ suggestions.push(`💡 Considere reutilizar um desses em vez de criar novo`);
235
+ }
236
+
237
+ if (!exists && duplicates.length === 0) {
238
+ suggestions.push(`✅ Nenhuma duplicação encontrada. Seguro criar "${name}"`);
239
+ }
240
+
241
+ return {
242
+ exists,
243
+ duplicates,
244
+ suggestions,
245
+ };
246
+ }
247
+
248
+ // ============================================================
249
+ // 📊 MÉTODOS DE SCAN
250
+ // ============================================================
251
+
252
+ /**
253
+ * Escaneia o projeto inteiro e atualiza o inventário
254
+ */
255
+ async scanProject(): Promise<void> {
256
+ console.log('🔍 [inventory-agent] Escaneando projeto...');
257
+
258
+ this.inventory.clear();
259
+
260
+ await Promise.all([
261
+ this.scanComponents(),
262
+ this.scanVariables(),
263
+ this.scanEndpoints(),
264
+ this.scanTypes(),
265
+ this.scanDatabase(),
266
+ ]);
267
+
268
+ await this.saveInventory();
269
+
270
+ console.log(`✅ [inventory-agent] Scan completo: ${this.inventory.size} itens catalogados`);
271
+ }
272
+
273
+ /**
274
+ * Escaneia componentes React/Next.js
275
+ */
276
+ private async scanComponents(): Promise<void> {
277
+ const patterns = ['**/*.tsx', '**/*.jsx', '!node_modules/**', '!.next/**', '!.agents/**'];
278
+
279
+ const files = await glob(patterns, { cwd: this.projectRoot });
280
+
281
+ for (const file of files) {
282
+ const fullPath = path.join(this.projectRoot, file);
283
+ const content = await fs.readFile(fullPath, 'utf-8');
284
+
285
+ // Detectar componentes exportados
286
+ const exportMatches = content.matchAll(/export\s+(?:default\s+)?(?:function|const|class)\s+(\w+)/g);
287
+
288
+ for (const match of exportMatches) {
289
+ const componentName = match[1];
290
+
291
+ // Extrair props
292
+ const propsMatch = content.match(new RegExp(`${componentName}.*?\\(\\s*{([^}]+)}`, 's'));
293
+ const props = propsMatch
294
+ ? propsMatch[1]
295
+ .split(',')
296
+ .map((p) => p.trim().split(':')[0].trim())
297
+ .filter(Boolean)
298
+ : [];
299
+
300
+ // Extrair imports (dependências)
301
+ const importMatches = content.matchAll(/import\s+.*?from\s+['"]([^'"]+)['"]/g);
302
+ const dependencies = Array.from(importMatches, (m) => m[1]);
303
+
304
+ const component: Component = {
305
+ id: `component:${file}:${componentName}`,
306
+ name: componentName,
307
+ type: 'component',
308
+ path: file,
309
+ exports: [componentName],
310
+ props,
311
+ dependencies,
312
+ metadata: {
313
+ isDefaultExport: content.includes(`export default ${componentName}`),
314
+ },
315
+ usedBy: [], // Será preenchido em scan futuro
316
+ createdAt: new Date().toISOString(),
317
+ lastModified: new Date().toISOString(),
318
+ };
319
+
320
+ this.inventory.set(component.id, component);
321
+ }
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Escaneia variáveis globais e exportadas
327
+ */
328
+ private async scanVariables(): Promise<void> {
329
+ const patterns = ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '!node_modules/**', '!.next/**'];
330
+
331
+ const files = await glob(patterns, { cwd: this.projectRoot });
332
+
333
+ for (const file of files) {
334
+ const fullPath = path.join(this.projectRoot, file);
335
+ const content = await fs.readFile(fullPath, 'utf-8');
336
+
337
+ // Detectar variáveis exportadas
338
+ const varMatches = content.matchAll(/export\s+const\s+(\w+)\s*[:=]\s*(.+?)(?:[;\n])/g);
339
+
340
+ for (const match of varMatches) {
341
+ const [, varName, value] = match;
342
+
343
+ const variable: Variable = {
344
+ id: `variable:${file}:${varName}`,
345
+ name: varName,
346
+ type: 'variable',
347
+ path: file,
348
+ scope: 'exported',
349
+ value: value.trim(),
350
+ dataType: this.inferType(value),
351
+ metadata: {},
352
+ usedBy: [],
353
+ createdAt: new Date().toISOString(),
354
+ lastModified: new Date().toISOString(),
355
+ };
356
+
357
+ this.inventory.set(variable.id, variable);
358
+ }
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Escaneia endpoints de API
364
+ */
365
+ private async scanEndpoints(): Promise<void> {
366
+ const patterns = ['**/api/**/*.ts', '**/api/**/*.js', '!node_modules/**'];
367
+
368
+ const files = await glob(patterns, { cwd: this.projectRoot });
369
+
370
+ for (const file of files) {
371
+ const fullPath = path.join(this.projectRoot, file);
372
+ const content = await fs.readFile(fullPath, 'utf-8');
373
+
374
+ // Detectar métodos HTTP
375
+ const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;
376
+
377
+ for (const method of methods) {
378
+ const regex = new RegExp(`export\\s+async\\s+function\\s+${method}`, 'g');
379
+ if (regex.test(content)) {
380
+ const endpoint: Endpoint = {
381
+ id: `endpoint:${file}:${method}`,
382
+ name: file.replace(/.*\/api\//, '/api/').replace(/\/route\.(ts|js)/, ''),
383
+ type: 'endpoint',
384
+ path: file,
385
+ method,
386
+ authentication: content.includes('auth') || content.includes('session'),
387
+ metadata: {},
388
+ usedBy: [],
389
+ createdAt: new Date().toISOString(),
390
+ lastModified: new Date().toISOString(),
391
+ };
392
+
393
+ this.inventory.set(endpoint.id, endpoint);
394
+ }
395
+ }
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Escaneia tipos TypeScript
401
+ */
402
+ private async scanTypes(): Promise<void> {
403
+ const patterns = ['**/types/**/*.ts', '**/*.d.ts', '!node_modules/**'];
404
+
405
+ const files = await glob(patterns, { cwd: this.projectRoot });
406
+
407
+ for (const file of files) {
408
+ const fullPath = path.join(this.projectRoot, file);
409
+ const content = await fs.readFile(fullPath, 'utf-8');
410
+
411
+ // Detectar interfaces e types
412
+ const typeMatches = content.matchAll(/(?:export\s+)?(?:interface|type)\s+(\w+)/g);
413
+
414
+ for (const match of typeMatches) {
415
+ const typeName = match[1];
416
+
417
+ const typeItem: InventoryItem = {
418
+ id: `type:${file}:${typeName}`,
419
+ name: typeName,
420
+ type: 'type',
421
+ path: file,
422
+ metadata: {
423
+ isInterface: content.includes(`interface ${typeName}`),
424
+ isType: content.includes(`type ${typeName}`),
425
+ },
426
+ usedBy: [],
427
+ createdAt: new Date().toISOString(),
428
+ lastModified: new Date().toISOString(),
429
+ };
430
+
431
+ this.inventory.set(typeItem.id, typeItem);
432
+ }
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Escaneia schema do banco de dados (Supabase/PostgreSQL)
438
+ */
439
+ private async scanDatabase(): Promise<void> {
440
+ // Procurar por arquivos de schema ou migrations
441
+ const patterns = ['**/supabase/migrations/**/*.sql', '**/prisma/schema.prisma', '!node_modules/**'];
442
+
443
+ const files = await glob(patterns, { cwd: this.projectRoot });
444
+
445
+ for (const file of files) {
446
+ const fullPath = path.join(this.projectRoot, file);
447
+ const content = await fs.readFile(fullPath, 'utf-8');
448
+
449
+ // Detectar CREATE TABLE
450
+ const tableMatches = content.matchAll(/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)\s*\(/gi);
451
+
452
+ for (const match of tableMatches) {
453
+ const tableName = match[1];
454
+
455
+ const table: DatabaseTable = {
456
+ id: `table:${tableName}`,
457
+ name: tableName,
458
+ type: 'table',
459
+ path: file,
460
+ schema: 'public',
461
+ columns: [], // Seria necessário parser SQL completo
462
+ relationships: [],
463
+ metadata: {},
464
+ usedBy: [],
465
+ createdAt: new Date().toISOString(),
466
+ lastModified: new Date().toISOString(),
467
+ };
468
+
469
+ this.inventory.set(table.id, table);
470
+ }
471
+ }
472
+ }
473
+
474
+ // ============================================================
475
+ // 💾 PERSISTÊNCIA
476
+ // ============================================================
477
+
478
+ /**
479
+ * Salva inventário em arquivos JSON
480
+ */
481
+ private async saveInventory(): Promise<void> {
482
+ await fs.mkdir(this.inventoryPath, { recursive: true });
483
+
484
+ // Agrupar por tipo
485
+ const byType = new Map<string, InventoryItem[]>();
486
+
487
+ for (const item of this.inventory.values()) {
488
+ if (!byType.has(item.type)) {
489
+ byType.set(item.type, []);
490
+ }
491
+ byType.get(item.type)!.push(item);
492
+ }
493
+
494
+ // Salvar cada tipo em arquivo separado
495
+ for (const [type, items] of byType) {
496
+ const filePath = path.join(this.inventoryPath, `${type}s.json`);
497
+ await fs.writeFile(filePath, JSON.stringify(items, null, 2));
498
+ }
499
+
500
+ // Salvar índice geral
501
+ const index = {
502
+ totalItems: this.inventory.size,
503
+ byType: Object.fromEntries(
504
+ Array.from(byType.entries()).map(([type, items]) => [type, items.length])
505
+ ),
506
+ lastUpdated: new Date().toISOString(),
507
+ };
508
+
509
+ await fs.writeFile(path.join(this.inventoryPath, 'index.json'), JSON.stringify(index, null, 2));
510
+ }
511
+
512
+ /**
513
+ * Carrega inventário dos arquivos JSON
514
+ */
515
+ private async loadInventory(): Promise<void> {
516
+ try {
517
+ const indexPath = path.join(this.inventoryPath, 'index.json');
518
+ const indexExists = await fs
519
+ .access(indexPath)
520
+ .then(() => true)
521
+ .catch(() => false);
522
+
523
+ if (!indexExists) {
524
+ // Inventário vazio, fazer scan inicial
525
+ await this.scanProject();
526
+ return;
527
+ }
528
+
529
+ this.inventory.clear();
530
+
531
+ const types = ['component', 'variable', 'table', 'endpoint', 'type'];
532
+
533
+ for (const type of types) {
534
+ const filePath = path.join(this.inventoryPath, `${type}s.json`);
535
+ const fileExists = await fs
536
+ .access(filePath)
537
+ .then(() => true)
538
+ .catch(() => false);
539
+
540
+ if (fileExists) {
541
+ const content = await fs.readFile(filePath, 'utf-8');
542
+ const items = JSON.parse(content) as InventoryItem[];
543
+
544
+ for (const item of items) {
545
+ this.inventory.set(item.id, item);
546
+ }
547
+ }
548
+ }
549
+ } catch (error) {
550
+ console.warn('[inventory-agent] Erro ao carregar inventário:', error);
551
+ }
552
+ }
553
+
554
+ // ============================================================
555
+ // 🛠️ UTILITÁRIOS
556
+ // ============================================================
557
+
558
+ private inferType(value: string): string {
559
+ if (value.startsWith("'") || value.startsWith('"') || value.startsWith('`')) return 'string';
560
+ if (value === 'true' || value === 'false') return 'boolean';
561
+ if (!isNaN(Number(value))) return 'number';
562
+ if (value.startsWith('[')) return 'array';
563
+ if (value.startsWith('{')) return 'object';
564
+ return 'unknown';
565
+ }
566
+
567
+ private parseQuery(description: string): InventoryQuery {
568
+ const query: InventoryQuery = { fuzzy: true };
569
+
570
+ if (description.includes('component')) query.type = 'component';
571
+ if (description.includes('variable')) query.type = 'variable';
572
+ if (description.includes('endpoint')) query.type = 'endpoint';
573
+ if (description.includes('table')) query.type = 'table';
574
+
575
+ return query;
576
+ }
577
+
578
+ private extractItemName(description: string): string {
579
+ const match = description.match(/["']([^"']+)["']/);
580
+ return match ? match[1] : '';
581
+ }
582
+ }