@codexa/cli 8.6.0 → 8.6.9

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.
@@ -1,1072 +1,1072 @@
1
- import { getDb } from "../db/connection";
2
- import { initSchema } from "../db/schema";
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
- import { join } from "path";
5
- import {
6
- detectUniversal,
7
- detectStackLegacy,
8
- formatDetectionResult,
9
- getDetailedTechnologies,
10
- type UnifiedDetectionResult,
11
- } from "../detectors/loader";
12
-
13
- interface StackDetection {
14
- frontend?: string;
15
- backend?: string;
16
- database?: string;
17
- orm?: string;
18
- styling?: string;
19
- auth?: string;
20
- testing?: string;
21
- }
22
-
23
- interface StructureDetection {
24
- components?: string;
25
- services?: string;
26
- schema?: string;
27
- types?: string;
28
- hooks?: string;
29
- utils?: string;
30
- api?: string;
31
- }
32
-
33
- // Store last detection result for extended info
34
- let lastDetectionResult: UnifiedDetectionResult | null = null;
35
-
36
- /**
37
- * Universal stack detection using the new modular detector system.
38
- * Supports: Node.js, .NET, Python, Go, Rust, Java/Kotlin, Flutter, and more.
39
- */
40
- async function detectStack(): Promise<StackDetection> {
41
- const result = await detectStackLegacy(process.cwd());
42
- return result.stack;
43
- }
44
-
45
- /**
46
- * Structure detection using the new modular detector system.
47
- */
48
- async function detectStructure(): Promise<StructureDetection> {
49
- const result = await detectStackLegacy(process.cwd());
50
-
51
- // Map new structure keys to legacy format
52
- const structure: StructureDetection = {};
53
-
54
- if (result.structure.components) structure.components = result.structure.components;
55
- if (result.structure.services) structure.services = result.structure.services;
56
- if (result.structure.schema) structure.schema = result.structure.schema;
57
- if (result.structure.types) structure.types = result.structure.types;
58
- if (result.structure.hooks) structure.hooks = result.structure.hooks;
59
- if (result.structure.utils) structure.utils = result.structure.utils;
60
- if (result.structure.api) structure.api = result.structure.api;
61
-
62
- return structure;
63
- }
64
-
65
- /**
66
- * Full detection with all details (for extended display)
67
- */
68
- async function detectFull(): Promise<UnifiedDetectionResult> {
69
- const result = await detectUniversal(process.cwd());
70
- lastDetectionResult = result;
71
- return result;
72
- }
73
-
74
- export async function discoverStart(json: boolean = false): Promise<void> {
75
- initSchema();
76
- const db = getDb();
77
-
78
- // Verificar se ja foi descoberto
79
- const existing = db.query("SELECT * FROM project WHERE id = 'default'").get();
80
- if (existing) {
81
- console.log("\nProjeto ja foi descoberto.");
82
- console.log("Use: discover show para ver detalhes");
83
- console.log("Ou: discover reset para refazer\n");
84
- return;
85
- }
86
-
87
- console.log("\nIniciando descoberta do projeto...\n");
88
-
89
- if (!json) {
90
- console.log("[1/2] Detectando stack tecnológico (universal)...");
91
- }
92
-
93
- // Usar novo sistema de detecção universal
94
- const fullResult = await detectFull();
95
-
96
- // Converter para formato legacy para compatibilidade
97
- const stack = await detectStack();
98
- const structure = await detectStructure();
99
-
100
- if (!json) {
101
- console.log(` ✓ ${fullResult.ecosystems.length > 0 ? fullResult.ecosystems.join(", ") : "Stack"} detectado\n`);
102
- console.log("[2/2] Analisando estrutura de diretórios...");
103
- console.log(" ✓ Estrutura mapeada\n");
104
- }
105
-
106
- if (json) {
107
- console.log(JSON.stringify({
108
- stack,
109
- structure,
110
- // Extended info from new detection system
111
- extended: {
112
- primary: fullResult.primary,
113
- ecosystems: fullResult.ecosystems,
114
- technologies: getDetailedTechnologies(fullResult),
115
- configFiles: fullResult.configFiles,
116
- fullStructure: fullResult.structure,
117
- }
118
- }, null, 2));
119
- return;
120
- }
121
-
122
- // Use new formatted output
123
- console.log(formatDetectionResult(fullResult));
124
-
125
- // Show legacy structure format as well for compatibility
126
- console.log("\n" + "═".repeat(60));
127
- console.log("ESTRUTURA DETECTADA (Legacy)");
128
- console.log("═".repeat(60));
129
-
130
- if (Object.keys(structure).length === 0) {
131
- console.log("\nNenhuma estrutura padrao detectada.");
132
- } else {
133
- console.log();
134
- if (structure.components) console.log(` Componentes: ${structure.components}/`);
135
- if (structure.services) console.log(` Services: ${structure.services}/`);
136
- if (structure.schema) console.log(` Schema DB: ${structure.schema}/`);
137
- if (structure.types) console.log(` Tipos: ${structure.types}/`);
138
- if (structure.hooks) console.log(` Hooks: ${structure.hooks}/`);
139
- if (structure.utils) console.log(` Utils: ${structure.utils}/`);
140
- if (structure.api) console.log(` API: ${structure.api}/`);
141
- }
142
-
143
- console.log("\n" + "─".repeat(60));
144
- console.log("\nPara confirmar e salvar: discover confirm");
145
- console.log("Para ajustar stack: discover set-stack --frontend next --backend bun");
146
- console.log("Para ajustar estrutura: discover set-structure --components src/ui\n");
147
-
148
- // Salvar temporariamente para confirm poder usar
149
- // Include extended info for richer context
150
- db.run(
151
- `INSERT OR REPLACE INTO project (id, name, stack, discovered_at, updated_at)
152
- VALUES ('pending', 'pending', ?, datetime('now'), datetime('now'))`,
153
- [JSON.stringify({
154
- stack,
155
- structure,
156
- extended: {
157
- primary: fullResult.primary,
158
- ecosystems: fullResult.ecosystems,
159
- allTechnologies: fullResult.allTechnologies,
160
- configFiles: fullResult.configFiles,
161
- fullStructure: fullResult.structure,
162
- }
163
- })]
164
- );
165
- }
166
-
167
- export function discoverConfirm(): void {
168
- initSchema();
169
- const db = getDb();
170
-
171
- const pending = db.query("SELECT * FROM project WHERE id = 'pending'").get() as any;
172
- if (!pending) {
173
- console.error("\nNenhuma descoberta pendente.");
174
- console.error("Execute: discover start primeiro\n");
175
- process.exit(1);
176
- }
177
-
178
- const data = JSON.parse(pending.stack);
179
- const now = new Date().toISOString();
180
-
181
- // Mover de pending para default
182
- db.run("DELETE FROM project WHERE id = 'pending'");
183
- db.run(
184
- `INSERT INTO project (id, name, stack, discovered_at, updated_at)
185
- VALUES ('default', ?, ?, ?, ?)`,
186
- ["Projeto", JSON.stringify(data.stack), now, now]
187
- );
188
-
189
- // Criar standards baseados na estrutura detectada
190
- const structure = data.structure as StructureDetection;
191
-
192
- if (structure.components) {
193
- db.run(
194
- `INSERT INTO standards (category, scope, rule, examples, source, created_at)
195
- VALUES ('structure', 'frontend', ?, ?, 'detected', ?)`,
196
- [
197
- `Componentes devem estar em ${structure.components}/`,
198
- JSON.stringify([`${structure.components}/Button.tsx`]),
199
- now,
200
- ]
201
- );
202
- }
203
-
204
- if (structure.services) {
205
- db.run(
206
- `INSERT INTO standards (category, scope, rule, examples, source, created_at)
207
- VALUES ('structure', 'backend', ?, ?, 'detected', ?)`,
208
- [
209
- `Services devem estar em ${structure.services}/`,
210
- JSON.stringify([`${structure.services}/authService.ts`]),
211
- now,
212
- ]
213
- );
214
- }
215
-
216
- if (structure.schema) {
217
- db.run(
218
- `INSERT INTO standards (category, scope, rule, examples, source, created_at)
219
- VALUES ('structure', 'database', ?, ?, 'detected', ?)`,
220
- [
221
- `Schema do banco deve estar em ${structure.schema}/`,
222
- JSON.stringify([`${structure.schema}/users.ts`]),
223
- now,
224
- ]
225
- );
226
- }
227
-
228
- if (structure.types) {
229
- db.run(
230
- `INSERT INTO standards (category, scope, rule, examples, source, created_at)
231
- VALUES ('structure', 'all', ?, ?, 'detected', ?)`,
232
- [
233
- `Tipos devem estar em ${structure.types}/`,
234
- JSON.stringify([`${structure.types}/user.ts`]),
235
- now,
236
- ]
237
- );
238
- }
239
-
240
- // Standards de nomenclatura padrao
241
- db.run(
242
- `INSERT INTO standards (category, scope, rule, examples, anti_examples, source, created_at)
243
- VALUES ('naming', 'frontend', ?, ?, ?, 'detected', ?)`,
244
- [
245
- "Componentes usam PascalCase",
246
- JSON.stringify(["Button.tsx", "LoginForm.tsx"]),
247
- JSON.stringify(["button.tsx", "login-form.tsx"]),
248
- now,
249
- ]
250
- );
251
-
252
- db.run(
253
- `INSERT INTO standards (category, scope, rule, examples, anti_examples, source, created_at)
254
- VALUES ('naming', 'backend', ?, ?, ?, 'detected', ?)`,
255
- [
256
- "Services usam camelCase",
257
- JSON.stringify(["authService.ts", "userService.ts"]),
258
- JSON.stringify(["AuthService.ts", "auth-service.ts"]),
259
- now,
260
- ]
261
- );
262
-
263
- // Gerar arquivo standards.md
264
- generateStandardsMarkdown();
265
-
266
- const standardsCount = db.query("SELECT COUNT(*) as c FROM standards").get() as any;
267
-
268
- // Auto-setup: deep-explore agent
269
- ensureDeepExploreAgent();
270
-
271
- console.log("\nProjeto descoberto e configurado!");
272
- console.log(`Standards criados: ${standardsCount.c}`);
273
- console.log("\nArquivo gerado: .codexa/standards.md");
274
- console.log("\nProximo passo: /codexa:feature para iniciar uma feature\n");
275
- }
276
-
277
- export function discoverShow(json: boolean = false): void {
278
- initSchema();
279
- const db = getDb();
280
-
281
- const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
282
-
283
- if (!project) {
284
- console.error("\nProjeto nao descoberto.");
285
- console.error("Execute: discover start\n");
286
- process.exit(1);
287
- }
288
-
289
- const standards = db.query("SELECT * FROM standards ORDER BY category, scope").all() as any[];
290
- const stack = JSON.parse(project.stack);
291
-
292
- if (json) {
293
- console.log(JSON.stringify({ project, stack, standards }, null, 2));
294
- return;
295
- }
296
-
297
- console.log("\n" + "═".repeat(60));
298
- console.log("PROJETO CONFIGURADO");
299
- console.log("═".repeat(60));
300
-
301
- console.log("\nStack:");
302
- for (const [key, value] of Object.entries(stack)) {
303
- if (value) console.log(` ${key}: ${value}`);
304
- }
305
-
306
- console.log(`\nStandards (${standards.length}):`);
307
- console.log("─".repeat(60));
308
-
309
- let currentCategory = "";
310
- for (const std of standards) {
311
- if (std.category !== currentCategory) {
312
- currentCategory = std.category;
313
- console.log(`\n[${currentCategory.toUpperCase()}]`);
314
- }
315
- console.log(` (${std.scope}) ${std.rule}`);
316
- }
317
-
318
- console.log("\n" + "─".repeat(60));
319
- console.log("Arquivo: .codexa/standards.md\n");
320
- }
321
-
322
- export function discoverSetStack(options: {
323
- frontend?: string;
324
- backend?: string;
325
- database?: string;
326
- orm?: string;
327
- styling?: string;
328
- auth?: string;
329
- testing?: string;
330
- }): void {
331
- initSchema();
332
- const db = getDb();
333
-
334
- let pending = db.query("SELECT * FROM project WHERE id = 'pending'").get() as any;
335
- let data: any;
336
-
337
- if (pending) {
338
- data = JSON.parse(pending.stack);
339
- } else {
340
- data = { stack: {}, structure: {} };
341
- }
342
-
343
- // Atualizar stack com opcoes fornecidas
344
- if (options.frontend) data.stack.frontend = options.frontend;
345
- if (options.backend) data.stack.backend = options.backend;
346
- if (options.database) data.stack.database = options.database;
347
- if (options.orm) data.stack.orm = options.orm;
348
- if (options.styling) data.stack.styling = options.styling;
349
- if (options.auth) data.stack.auth = options.auth;
350
- if (options.testing) data.stack.testing = options.testing;
351
-
352
- db.run(
353
- `INSERT OR REPLACE INTO project (id, name, stack, discovered_at, updated_at)
354
- VALUES ('pending', 'pending', ?, datetime('now'), datetime('now'))`,
355
- [JSON.stringify(data)]
356
- );
357
-
358
- console.log("\nStack atualizado:");
359
- for (const [key, value] of Object.entries(data.stack)) {
360
- if (value) console.log(` ${key}: ${value}`);
361
- }
362
- console.log("\nPara confirmar: discover confirm\n");
363
- }
364
-
365
- export function discoverReset(): void {
366
- initSchema();
367
- const db = getDb();
368
-
369
- db.run("DELETE FROM project");
370
- db.run("DELETE FROM standards");
371
-
372
- console.log("\nDescoberta resetada.");
373
- console.log("Execute: discover start para refazer\n");
374
- }
375
-
376
- export async function discoverRefresh(options: { force?: boolean } = {}): Promise<void> {
377
- initSchema();
378
- const db = getDb();
379
-
380
- const currentProject = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
381
- if (!currentProject) {
382
- console.error("\nProjeto nao descoberto.");
383
- console.error("Execute: discover start primeiro\n");
384
- process.exit(1);
385
- }
386
-
387
- const currentStack = JSON.parse(currentProject.stack);
388
- const newStack = await detectStack();
389
- const newStructure = await detectStructure();
390
-
391
- // Comparar stacks
392
- const stackChanges: { key: string; from: string | undefined; to: string | undefined }[] = [];
393
- const allKeys = new Set([...Object.keys(currentStack), ...Object.keys(newStack)]);
394
-
395
- for (const key of allKeys) {
396
- const current = currentStack[key as keyof StackDetection];
397
- const detected = newStack[key as keyof StackDetection];
398
- if (current !== detected) {
399
- stackChanges.push({ key, from: current, to: detected });
400
- }
401
- }
402
-
403
- if (stackChanges.length === 0) {
404
- console.log("\n✓ Stack continua o mesmo. Nenhuma mudanca detectada.\n");
405
- return;
406
- }
407
-
408
- console.log("\n" + "═".repeat(60));
409
- console.log("MUDANCAS DETECTADAS NO STACK");
410
- console.log("═".repeat(60) + "\n");
411
-
412
- for (const change of stackChanges) {
413
- const from = change.from || "(nao definido)";
414
- const to = change.to || "(removido)";
415
- console.log(` ${change.key}: ${from} → ${to}`);
416
- }
417
-
418
- if (options.force) {
419
- // Aplicar mudanças
420
- const now = new Date().toISOString();
421
-
422
- db.run(
423
- `UPDATE project SET stack = ?, updated_at = ? WHERE id = 'default'`,
424
- [JSON.stringify(newStack), now]
425
- );
426
-
427
- // Atualizar standards de stack
428
- for (const change of stackChanges) {
429
- if (change.to) {
430
- // Adicionar ou atualizar standard de stack
431
- const existing = db.query(
432
- `SELECT id FROM standards WHERE category = 'stack' AND rule LIKE ?`
433
- ).get(`%${change.key}%`) as any;
434
-
435
- if (existing) {
436
- db.run(
437
- `UPDATE standards SET rule = ?, updated_at = ? WHERE id = ?`,
438
- [`${change.key}: ${change.to}`, now, existing.id]
439
- );
440
- } else {
441
- db.run(
442
- `INSERT INTO standards (category, scope, rule, enforcement, source, created_at)
443
- VALUES ('stack', 'all', ?, 'required', 'refresh', ?)`,
444
- [`${change.key}: ${change.to}`, now]
445
- );
446
- }
447
- }
448
- }
449
-
450
- // Regenerar standards.md
451
- generateStandardsMarkdown();
452
-
453
- console.log("\n✓ Stack atualizado com sucesso!");
454
- console.log("✓ Standards regenerados\n");
455
- } else {
456
- console.log("\n" + "─".repeat(60));
457
- console.log("Para aplicar as mudancas: discover refresh --force\n");
458
- }
459
- }
460
-
461
- function generateStandardsMarkdown(): void {
462
- const db = getDb();
463
- const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
464
- const standards = db.query("SELECT * FROM standards ORDER BY category, scope").all() as any[];
465
-
466
- if (!project) return;
467
-
468
- const stack = JSON.parse(project.stack);
469
- let md = `# Standards do Projeto
470
-
471
- > Gerado automaticamente do SQLite. Nao edite manualmente.
472
- > Para modificar, use os comandos CLI.
473
- > Gerado em: ${new Date().toISOString()}
474
-
475
- ## Stack
476
-
477
- `;
478
-
479
- for (const [key, value] of Object.entries(stack)) {
480
- if (value) md += `- **${key}:** ${value}\n`;
481
- }
482
-
483
- // Agrupar standards por categoria
484
- const byCategory: Record<string, any[]> = {};
485
- for (const std of standards) {
486
- if (!byCategory[std.category]) byCategory[std.category] = [];
487
- byCategory[std.category].push(std);
488
- }
489
-
490
- for (const [category, stds] of Object.entries(byCategory)) {
491
- md += `\n## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
492
-
493
- for (const std of stds) {
494
- const enforcement = std.enforcement === "required" ? "OBRIGATORIO" : "Recomendado";
495
- md += `### ${std.rule}\n\n`;
496
- md += `- **Escopo:** ${std.scope}\n`;
497
- md += `- **Enforcement:** ${enforcement}\n`;
498
-
499
- if (std.examples) {
500
- const examples = JSON.parse(std.examples);
501
- md += `- **Exemplos:**\n`;
502
- for (const ex of examples) {
503
- md += ` - \`${ex}\`\n`;
504
- }
505
- }
506
-
507
- if (std.anti_examples) {
508
- const antiExamples = JSON.parse(std.anti_examples);
509
- md += `- **Nao fazer:**\n`;
510
- for (const ex of antiExamples) {
511
- md += ` - ~~\`${ex}\`~~\n`;
512
- }
513
- }
514
-
515
- md += "\n";
516
- }
517
- }
518
-
519
- // Garantir que diretorio existe
520
- const mdPath = join(process.cwd(), ".codexa", "standards.md");
521
- writeFileSync(mdPath, md);
522
- }
523
-
524
- export { generateStandardsMarkdown };
525
-
526
- // ============================================================
527
- // PATTERN EXTRACTION (v7.4)
528
- // ============================================================
529
-
530
- interface PatternStructure {
531
- imports: {
532
- order: string[];
533
- common: string[];
534
- conditional: string[];
535
- };
536
- exports: {
537
- style: "named" | "default" | "both";
538
- async: boolean;
539
- };
540
- patterns: {
541
- hooks_used: string[];
542
- props_style: "interface" | "type" | "inline";
543
- error_handling: string;
544
- data_fetching: string;
545
- };
546
- conventions: {
547
- file_structure: string[];
548
- naming: {
549
- functions: string;
550
- variables: string;
551
- types: string;
552
- };
553
- };
554
- }
555
-
556
- interface AntiPattern {
557
- description: string;
558
- example: string;
559
- found_in: string[];
560
- recommendation?: string;
561
- }
562
-
563
- interface ImplementationPattern {
564
- category: string;
565
- name: string;
566
- scope: string;
567
- applies_to: string;
568
- structure: PatternStructure;
569
- template: string;
570
- examples: { path: string; relevance: number }[];
571
- anti_patterns: AntiPattern[];
572
- confidence: number;
573
- extracted_from: number;
574
- }
575
-
576
- export function discoverPatterns(options: { category?: string; json?: boolean } = {}): void {
577
- initSchema();
578
- const db = getDb();
579
-
580
- let query = "SELECT * FROM implementation_patterns";
581
- const params: string[] = [];
582
-
583
- if (options.category) {
584
- query += " WHERE category = ?";
585
- params.push(options.category);
586
- }
587
-
588
- query += " ORDER BY category, name";
589
-
590
- const patterns = db.query(query).all(...params) as any[];
591
-
592
- if (patterns.length === 0) {
593
- console.log("\nNenhum pattern extraido ainda.");
594
- console.log("Execute: discover start para extrair patterns do codigo\n");
595
- return;
596
- }
597
-
598
- if (options.json) {
599
- console.log(JSON.stringify(patterns.map(p => ({
600
- ...p,
601
- structure: JSON.parse(p.structure || "{}"),
602
- examples: JSON.parse(p.examples || "[]"),
603
- anti_patterns: JSON.parse(p.anti_patterns || "[]"),
604
- })), null, 2));
605
- return;
606
- }
607
-
608
- console.log("\n" + "═".repeat(70));
609
- console.log("IMPLEMENTATION PATTERNS EXTRAIDOS");
610
- console.log("═".repeat(70) + "\n");
611
-
612
- console.log("┌" + "─".repeat(20) + "┬" + "─".repeat(25) + "┬" + "─".repeat(10) + "┬" + "─".repeat(10) + "┐");
613
- console.log("│ Categoria │ Nome │ Arquivos │ Confianca│");
614
- console.log("├" + "─".repeat(20) + "┼" + "─".repeat(25) + "┼" + "─".repeat(10) + "┼" + "─".repeat(10) + "┤");
615
-
616
- for (const p of patterns) {
617
- const cat = p.category.padEnd(18);
618
- const name = p.name.substring(0, 23).padEnd(23);
619
- const files = String(p.extracted_from || 0).padStart(8);
620
- const conf = ((p.confidence || 0) * 100).toFixed(0).padStart(7) + "%";
621
- console.log(`│ ${cat} │ ${name} │ ${files} │ ${conf} │`);
622
- }
623
-
624
- console.log("└" + "─".repeat(20) + "┴" + "─".repeat(25) + "┴" + "─".repeat(10) + "┴" + "─".repeat(10) + "┘");
625
-
626
- // Contar anti-patterns
627
- let totalAntiPatterns = 0;
628
- for (const p of patterns) {
629
- const antiPatterns = JSON.parse(p.anti_patterns || "[]");
630
- totalAntiPatterns += antiPatterns.length;
631
- }
632
-
633
- if (totalAntiPatterns > 0) {
634
- console.log(`\n⚠ Anti-patterns identificados: ${totalAntiPatterns}`);
635
- console.log(" Use: discover patterns --show <name> para ver detalhes");
636
- }
637
-
638
- console.log("\n" + "─".repeat(70));
639
- console.log("Para ver detalhes: discover patterns --show <name>");
640
- console.log("Para exportar: discover export-patterns\n");
641
- }
642
-
643
- export function discoverPatternsShow(name: string, json: boolean = false): void {
644
- initSchema();
645
- const db = getDb();
646
-
647
- const pattern = db.query("SELECT * FROM implementation_patterns WHERE name = ?").get(name) as any;
648
-
649
- if (!pattern) {
650
- console.error(`\nPattern '${name}' nao encontrado.`);
651
- console.error("Use: discover patterns para listar todos\n");
652
- process.exit(1);
653
- }
654
-
655
- const structure = JSON.parse(pattern.structure || "{}");
656
- const examples = JSON.parse(pattern.examples || "[]");
657
- const antiPatterns = JSON.parse(pattern.anti_patterns || "[]");
658
-
659
- if (json) {
660
- console.log(JSON.stringify({
661
- ...pattern,
662
- structure,
663
- examples,
664
- anti_patterns: antiPatterns,
665
- }, null, 2));
666
- return;
667
- }
668
-
669
- console.log("\n" + "═".repeat(70));
670
- console.log(`PATTERN: ${pattern.name}`);
671
- console.log("═".repeat(70));
672
-
673
- console.log(`\nCategoria: ${pattern.category}`);
674
- console.log(`Escopo: ${pattern.scope}`);
675
- console.log(`Aplica-se a: ${pattern.applies_to}`);
676
- console.log(`Confianca: ${((pattern.confidence || 0) * 100).toFixed(0)}%`);
677
- console.log(`Extraido de: ${pattern.extracted_from} arquivos`);
678
-
679
- console.log("\n" + "─".repeat(70));
680
- console.log("ESTRUTURA");
681
- console.log("─".repeat(70));
682
-
683
- if (structure.imports) {
684
- console.log("\nImports:");
685
- console.log(` Ordem: ${structure.imports.order?.join(" → ") || "N/A"}`);
686
- console.log(` Comuns: ${structure.imports.common?.join(", ") || "N/A"}`);
687
- }
688
-
689
- if (structure.exports) {
690
- console.log("\nExports:");
691
- console.log(` Estilo: ${structure.exports.style || "N/A"}`);
692
- console.log(` Async: ${structure.exports.async ? "Sim" : "Nao"}`);
693
- }
694
-
695
- if (structure.patterns) {
696
- console.log("\nPadroes:");
697
- console.log(` Hooks: ${structure.patterns.hooks_used?.join(", ") || "N/A"}`);
698
- console.log(` Props: ${structure.patterns.props_style || "N/A"}`);
699
- console.log(` Erro: ${structure.patterns.error_handling || "N/A"}`);
700
- console.log(` Data: ${structure.patterns.data_fetching || "N/A"}`);
701
- }
702
-
703
- console.log("\n" + "─".repeat(70));
704
- console.log("TEMPLATE");
705
- console.log("─".repeat(70));
706
- console.log("\n" + pattern.template);
707
-
708
- console.log("\n" + "─".repeat(70));
709
- console.log("EXEMPLOS DE REFERENCIA");
710
- console.log("─".repeat(70));
711
-
712
- for (const ex of examples.slice(0, 5)) {
713
- const relevance = ((ex.relevance || 0) * 100).toFixed(0);
714
- console.log(` ${ex.path} (${relevance}% similar)`);
715
- }
716
-
717
- if (antiPatterns.length > 0) {
718
- console.log("\n" + "─".repeat(70));
719
- console.log("⚠ ANTI-PATTERNS IDENTIFICADOS");
720
- console.log("─".repeat(70));
721
-
722
- for (const ap of antiPatterns) {
723
- console.log(`\n ❌ ${ap.description}`);
724
- console.log(` Encontrado em: ${ap.found_in?.join(", ") || "N/A"}`);
725
- if (ap.recommendation) {
726
- console.log(` Recomendacao: ${ap.recommendation}`);
727
- }
728
- }
729
- }
730
-
731
- console.log("\n");
732
- }
733
-
734
- export function discoverPatternAdd(options: {
735
- category: string;
736
- name: string;
737
- scope: string;
738
- appliesTo: string;
739
- structure: string;
740
- template: string;
741
- examples: string;
742
- antiPatterns?: string;
743
- confidence?: number;
744
- extractedFrom?: number;
745
- }): void {
746
- initSchema();
747
- const db = getDb();
748
-
749
- // Verificar se pattern ja existe
750
- const existing = db.query("SELECT id FROM implementation_patterns WHERE name = ?").get(options.name);
751
- if (existing) {
752
- console.error(`\nPattern '${options.name}' ja existe.`);
753
- console.error("Use: discover pattern-edit para modificar\n");
754
- process.exit(1);
755
- }
756
-
757
- const now = new Date().toISOString();
758
-
759
- db.run(
760
- `INSERT INTO implementation_patterns
761
- (category, name, scope, applies_to, structure, template, examples, anti_patterns, confidence, extracted_from, created_at, updated_at)
762
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
763
- [
764
- options.category,
765
- options.name,
766
- options.scope,
767
- options.appliesTo,
768
- options.structure,
769
- options.template,
770
- options.examples,
771
- options.antiPatterns || "[]",
772
- options.confidence || 0.8,
773
- options.extractedFrom || 1,
774
- now,
775
- now,
776
- ]
777
- );
778
-
779
- // Regenerar patterns.md
780
- generatePatternsMarkdown();
781
-
782
- console.log(`\n✓ Pattern '${options.name}' adicionado com sucesso!`);
783
- console.log("Arquivo atualizado: .codexa/patterns.md\n");
784
- }
785
-
786
- export function discoverPatternEdit(name: string, options: {
787
- category?: string;
788
- scope?: string;
789
- appliesTo?: string;
790
- structure?: string;
791
- template?: string;
792
- examples?: string;
793
- antiPatterns?: string;
794
- confidence?: number;
795
- }): void {
796
- initSchema();
797
- const db = getDb();
798
-
799
- const existing = db.query("SELECT * FROM implementation_patterns WHERE name = ?").get(name) as any;
800
- if (!existing) {
801
- console.error(`\nPattern '${name}' nao encontrado.`);
802
- console.error("Use: discover patterns para listar todos\n");
803
- process.exit(1);
804
- }
805
-
806
- const updates: string[] = [];
807
- const params: any[] = [];
808
-
809
- if (options.category) {
810
- updates.push("category = ?");
811
- params.push(options.category);
812
- }
813
- if (options.scope) {
814
- updates.push("scope = ?");
815
- params.push(options.scope);
816
- }
817
- if (options.appliesTo) {
818
- updates.push("applies_to = ?");
819
- params.push(options.appliesTo);
820
- }
821
- if (options.structure) {
822
- updates.push("structure = ?");
823
- params.push(options.structure);
824
- }
825
- if (options.template) {
826
- updates.push("template = ?");
827
- params.push(options.template);
828
- }
829
- if (options.examples) {
830
- updates.push("examples = ?");
831
- params.push(options.examples);
832
- }
833
- if (options.antiPatterns) {
834
- updates.push("anti_patterns = ?");
835
- params.push(options.antiPatterns);
836
- }
837
- if (options.confidence !== undefined) {
838
- updates.push("confidence = ?");
839
- params.push(options.confidence);
840
- }
841
-
842
- if (updates.length === 0) {
843
- console.error("\nNenhuma opcao de atualizacao fornecida.\n");
844
- process.exit(1);
845
- }
846
-
847
- updates.push("updated_at = ?");
848
- params.push(new Date().toISOString());
849
- params.push(name);
850
-
851
- db.run(
852
- `UPDATE implementation_patterns SET ${updates.join(", ")} WHERE name = ?`,
853
- params
854
- );
855
-
856
- // Regenerar patterns.md
857
- generatePatternsMarkdown();
858
-
859
- console.log(`\n✓ Pattern '${name}' atualizado com sucesso!`);
860
- console.log("Arquivo atualizado: .codexa/patterns.md\n");
861
- }
862
-
863
- export function discoverPatternRemove(name: string): void {
864
- initSchema();
865
- const db = getDb();
866
-
867
- const existing = db.query("SELECT id FROM implementation_patterns WHERE name = ?").get(name);
868
- if (!existing) {
869
- console.error(`\nPattern '${name}' nao encontrado.\n`);
870
- process.exit(1);
871
- }
872
-
873
- db.run("DELETE FROM implementation_patterns WHERE name = ?", [name]);
874
-
875
- // Regenerar patterns.md
876
- generatePatternsMarkdown();
877
-
878
- console.log(`\n✓ Pattern '${name}' removido com sucesso!`);
879
- console.log("Arquivo atualizado: .codexa/patterns.md\n");
880
- }
881
-
882
- export function discoverRefreshPatterns(): void {
883
- initSchema();
884
- const db = getDb();
885
-
886
- // Verificar se projeto foi descoberto
887
- const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
888
- if (!project) {
889
- console.error("\nProjeto nao descoberto.");
890
- console.error("Execute: discover start primeiro\n");
891
- process.exit(1);
892
- }
893
-
894
- console.log("\n⚠ Refresh de patterns requer analise manual do codigo.");
895
- console.log("Use o skill /codexa:discover para extrair patterns automaticamente.");
896
- console.log("\nAlternativamente, adicione patterns manualmente:");
897
- console.log(" discover pattern-add --category component --name my-pattern ...\n");
898
- }
899
-
900
- export function generatePatternsMarkdown(): void {
901
- const db = getDb();
902
- const patterns = db.query("SELECT * FROM implementation_patterns ORDER BY category, name").all() as any[];
903
-
904
- if (patterns.length === 0) return;
905
-
906
- let md = `# Implementation Patterns
907
-
908
- > Gerado automaticamente do SQLite. Nao edite manualmente.
909
- > Para modificar, use os comandos CLI.
910
- > Gerado em: ${new Date().toISOString()}
911
-
912
- ## Resumo
913
-
914
- | Categoria | Nome | Arquivos | Confianca |
915
- |-----------|------|----------|-----------|
916
- `;
917
-
918
- for (const p of patterns) {
919
- const conf = ((p.confidence || 0) * 100).toFixed(0);
920
- md += `| ${p.category} | ${p.name} | ${p.extracted_from || 0} | ${conf}% |\n`;
921
- }
922
-
923
- // Agrupar por categoria
924
- const byCategory: Record<string, any[]> = {};
925
- for (const p of patterns) {
926
- if (!byCategory[p.category]) byCategory[p.category] = [];
927
- byCategory[p.category].push(p);
928
- }
929
-
930
- for (const [category, categoryPatterns] of Object.entries(byCategory)) {
931
- md += `\n## ${category.charAt(0).toUpperCase() + category.slice(1)}\n`;
932
-
933
- for (const p of categoryPatterns) {
934
- const structure = JSON.parse(p.structure || "{}");
935
- const examples = JSON.parse(p.examples || "[]");
936
- const antiPatterns = JSON.parse(p.anti_patterns || "[]");
937
-
938
- md += `\n### ${p.name}\n\n`;
939
- md += `- **Escopo:** ${p.scope}\n`;
940
- md += `- **Aplica-se a:** \`${p.applies_to}\`\n`;
941
- md += `- **Confianca:** ${((p.confidence || 0) * 100).toFixed(0)}%\n`;
942
- md += `- **Extraido de:** ${p.extracted_from || 0} arquivos\n`;
943
-
944
- if (structure.imports?.common?.length > 0) {
945
- md += `\n**Imports comuns:**\n`;
946
- for (const imp of structure.imports.common) {
947
- md += `- \`${imp}\`\n`;
948
- }
949
- }
950
-
951
- if (structure.patterns?.hooks_used?.length > 0) {
952
- md += `\n**Hooks utilizados:** ${structure.patterns.hooks_used.join(", ")}\n`;
953
- }
954
-
955
- md += `\n**Template:**\n\n\`\`\`typescript\n${p.template}\n\`\`\`\n`;
956
-
957
- if (examples.length > 0) {
958
- md += `\n**Exemplos de referencia:**\n`;
959
- for (const ex of examples.slice(0, 5)) {
960
- const rel = ((ex.relevance || 0) * 100).toFixed(0);
961
- md += `- \`${ex.path}\` (${rel}% similar)\n`;
962
- }
963
- }
964
-
965
- if (antiPatterns.length > 0) {
966
- md += `\n**⚠ Anti-patterns:**\n`;
967
- for (const ap of antiPatterns) {
968
- md += `- ❌ ${ap.description}\n`;
969
- if (ap.found_in?.length > 0) {
970
- md += ` - Encontrado em: ${ap.found_in.join(", ")}\n`;
971
- }
972
- if (ap.recommendation) {
973
- md += ` - Recomendacao: ${ap.recommendation}\n`;
974
- }
975
- }
976
- }
977
- }
978
- }
979
-
980
- // Garantir que diretorio existe
981
- const dir = join(process.cwd(), ".codexa");
982
- if (!existsSync(dir)) {
983
- mkdirSync(dir, { recursive: true });
984
- }
985
-
986
- const mdPath = join(dir, "patterns.md");
987
- writeFileSync(mdPath, md);
988
- }
989
-
990
- export function discoverExportPatterns(): void {
991
- generatePatternsMarkdown();
992
- console.log("\n✓ Arquivo .codexa/patterns.md regenerado!\n");
993
- }
994
-
995
- // Auto-setup: garante que o agent deep-explore existe no projeto
996
- export function ensureDeepExploreAgent(): void {
997
- const agentPath = join(process.cwd(), ".claude", "agents", "deep-explore.md");
998
-
999
- if (existsSync(agentPath)) return;
1000
-
1001
- const agentsDir = join(process.cwd(), ".claude", "agents");
1002
- if (!existsSync(agentsDir)) {
1003
- mkdirSync(agentsDir, { recursive: true });
1004
- }
1005
-
1006
- const content = `---
1007
- name: deep-explore
1008
- description: Deep codebase exploration using grepai semantic search and call graph tracing. Use this agent for understanding code architecture, finding implementations by intent, analyzing function relationships, and exploring unfamiliar code areas.
1009
- tools: Read, Grep, Glob, Bash
1010
- color: cyan
1011
- model: haiku
1012
- ---
1013
-
1014
- ## Instructions
1015
-
1016
- You are a specialized code exploration agent with access to grepai semantic search and call graph tracing.
1017
-
1018
- ### Primary Tools
1019
-
1020
- #### 1. Semantic Search: \`grepai search\`
1021
-
1022
- Use this to find code by intent and meaning:
1023
-
1024
- \`\`\`bash
1025
- # Use English queries for best results (--compact saves ~80% tokens)
1026
- grepai search "authentication flow" --json --compact
1027
- grepai search "error handling middleware" --json --compact
1028
- grepai search "database connection management" --json --compact
1029
- \`\`\`
1030
-
1031
- #### 2. Call Graph Tracing: \`grepai trace\`
1032
-
1033
- Use this to understand function relationships and code flow:
1034
-
1035
- \`\`\`bash
1036
- # Find all functions that call a symbol
1037
- grepai trace callers "HandleRequest" --json
1038
-
1039
- # Find all functions called by a symbol
1040
- grepai trace callees "ProcessOrder" --json
1041
-
1042
- # Build complete call graph
1043
- grepai trace graph "ValidateToken" --depth 3 --json
1044
- \`\`\`
1045
-
1046
- Use \`grepai trace\` when you need to:
1047
-
1048
- - Find all callers of a function
1049
- - Understand the call hierarchy
1050
- - Analyze the impact of changes to a function
1051
- - Map dependencies between components
1052
-
1053
- ### When to use standard tools
1054
-
1055
- Only fall back to Grep/Glob when:
1056
-
1057
- - You need exact text matching (variable names, imports)
1058
- - grepai is not available or returns errors
1059
- - You need file path patterns
1060
-
1061
- ### Workflow
1062
-
1063
- 1. Start with \`grepai search\` to find relevant code semantically
1064
- 2. Use \`grepai trace\` to understand function relationships and call graphs
1065
- 3. Use \`Read\` to examine promising files in detail
1066
- 4. Use Grep only for exact string searches if needed
1067
- 5. Synthesize findings into a clear summary
1068
- `;
1069
-
1070
- writeFileSync(agentPath, content);
1071
- console.log("✓ Agent deep-explore instalado em .claude/agents/deep-explore.md");
1
+ import { getDb } from "../db/connection";
2
+ import { initSchema } from "../db/schema";
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
+ import { join } from "path";
5
+ import {
6
+ detectUniversal,
7
+ detectStackLegacy,
8
+ formatDetectionResult,
9
+ getDetailedTechnologies,
10
+ type UnifiedDetectionResult,
11
+ } from "../detectors/loader";
12
+
13
+ interface StackDetection {
14
+ frontend?: string;
15
+ backend?: string;
16
+ database?: string;
17
+ orm?: string;
18
+ styling?: string;
19
+ auth?: string;
20
+ testing?: string;
21
+ }
22
+
23
+ interface StructureDetection {
24
+ components?: string;
25
+ services?: string;
26
+ schema?: string;
27
+ types?: string;
28
+ hooks?: string;
29
+ utils?: string;
30
+ api?: string;
31
+ }
32
+
33
+ // Store last detection result for extended info
34
+ let lastDetectionResult: UnifiedDetectionResult | null = null;
35
+
36
+ /**
37
+ * Universal stack detection using the new modular detector system.
38
+ * Supports: Node.js, .NET, Python, Go, Rust, Java/Kotlin, Flutter, and more.
39
+ */
40
+ async function detectStack(): Promise<StackDetection> {
41
+ const result = await detectStackLegacy(process.cwd());
42
+ return result.stack;
43
+ }
44
+
45
+ /**
46
+ * Structure detection using the new modular detector system.
47
+ */
48
+ async function detectStructure(): Promise<StructureDetection> {
49
+ const result = await detectStackLegacy(process.cwd());
50
+
51
+ // Map new structure keys to legacy format
52
+ const structure: StructureDetection = {};
53
+
54
+ if (result.structure.components) structure.components = result.structure.components;
55
+ if (result.structure.services) structure.services = result.structure.services;
56
+ if (result.structure.schema) structure.schema = result.structure.schema;
57
+ if (result.structure.types) structure.types = result.structure.types;
58
+ if (result.structure.hooks) structure.hooks = result.structure.hooks;
59
+ if (result.structure.utils) structure.utils = result.structure.utils;
60
+ if (result.structure.api) structure.api = result.structure.api;
61
+
62
+ return structure;
63
+ }
64
+
65
+ /**
66
+ * Full detection with all details (for extended display)
67
+ */
68
+ async function detectFull(): Promise<UnifiedDetectionResult> {
69
+ const result = await detectUniversal(process.cwd());
70
+ lastDetectionResult = result;
71
+ return result;
72
+ }
73
+
74
+ export async function discoverStart(json: boolean = false): Promise<void> {
75
+ initSchema();
76
+ const db = getDb();
77
+
78
+ // Verificar se ja foi descoberto
79
+ const existing = db.query("SELECT * FROM project WHERE id = 'default'").get();
80
+ if (existing) {
81
+ console.log("\nProjeto ja foi descoberto.");
82
+ console.log("Use: discover show para ver detalhes");
83
+ console.log("Ou: discover reset para refazer\n");
84
+ return;
85
+ }
86
+
87
+ console.log("\nIniciando descoberta do projeto...\n");
88
+
89
+ if (!json) {
90
+ console.log("[1/2] Detectando stack tecnológico (universal)...");
91
+ }
92
+
93
+ // Usar novo sistema de detecção universal
94
+ const fullResult = await detectFull();
95
+
96
+ // Converter para formato legacy para compatibilidade
97
+ const stack = await detectStack();
98
+ const structure = await detectStructure();
99
+
100
+ if (!json) {
101
+ console.log(` ✓ ${fullResult.ecosystems.length > 0 ? fullResult.ecosystems.join(", ") : "Stack"} detectado\n`);
102
+ console.log("[2/2] Analisando estrutura de diretórios...");
103
+ console.log(" ✓ Estrutura mapeada\n");
104
+ }
105
+
106
+ if (json) {
107
+ console.log(JSON.stringify({
108
+ stack,
109
+ structure,
110
+ // Extended info from new detection system
111
+ extended: {
112
+ primary: fullResult.primary,
113
+ ecosystems: fullResult.ecosystems,
114
+ technologies: getDetailedTechnologies(fullResult),
115
+ configFiles: fullResult.configFiles,
116
+ fullStructure: fullResult.structure,
117
+ }
118
+ }, null, 2));
119
+ return;
120
+ }
121
+
122
+ // Use new formatted output
123
+ console.log(formatDetectionResult(fullResult));
124
+
125
+ // Show legacy structure format as well for compatibility
126
+ console.log("\n" + "═".repeat(60));
127
+ console.log("ESTRUTURA DETECTADA (Legacy)");
128
+ console.log("═".repeat(60));
129
+
130
+ if (Object.keys(structure).length === 0) {
131
+ console.log("\nNenhuma estrutura padrao detectada.");
132
+ } else {
133
+ console.log();
134
+ if (structure.components) console.log(` Componentes: ${structure.components}/`);
135
+ if (structure.services) console.log(` Services: ${structure.services}/`);
136
+ if (structure.schema) console.log(` Schema DB: ${structure.schema}/`);
137
+ if (structure.types) console.log(` Tipos: ${structure.types}/`);
138
+ if (structure.hooks) console.log(` Hooks: ${structure.hooks}/`);
139
+ if (structure.utils) console.log(` Utils: ${structure.utils}/`);
140
+ if (structure.api) console.log(` API: ${structure.api}/`);
141
+ }
142
+
143
+ console.log("\n" + "─".repeat(60));
144
+ console.log("\nPara confirmar e salvar: discover confirm");
145
+ console.log("Para ajustar stack: discover set-stack --frontend next --backend bun");
146
+ console.log("Para ajustar estrutura: discover set-structure --components src/ui\n");
147
+
148
+ // Salvar temporariamente para confirm poder usar
149
+ // Include extended info for richer context
150
+ db.run(
151
+ `INSERT OR REPLACE INTO project (id, name, stack, discovered_at, updated_at)
152
+ VALUES ('pending', 'pending', ?, datetime('now'), datetime('now'))`,
153
+ [JSON.stringify({
154
+ stack,
155
+ structure,
156
+ extended: {
157
+ primary: fullResult.primary,
158
+ ecosystems: fullResult.ecosystems,
159
+ allTechnologies: fullResult.allTechnologies,
160
+ configFiles: fullResult.configFiles,
161
+ fullStructure: fullResult.structure,
162
+ }
163
+ })]
164
+ );
165
+ }
166
+
167
+ export function discoverConfirm(): void {
168
+ initSchema();
169
+ const db = getDb();
170
+
171
+ const pending = db.query("SELECT * FROM project WHERE id = 'pending'").get() as any;
172
+ if (!pending) {
173
+ console.error("\nNenhuma descoberta pendente.");
174
+ console.error("Execute: discover start primeiro\n");
175
+ process.exit(1);
176
+ }
177
+
178
+ const data = JSON.parse(pending.stack);
179
+ const now = new Date().toISOString();
180
+
181
+ // Mover de pending para default
182
+ db.run("DELETE FROM project WHERE id = 'pending'");
183
+ db.run(
184
+ `INSERT INTO project (id, name, stack, discovered_at, updated_at)
185
+ VALUES ('default', ?, ?, ?, ?)`,
186
+ ["Projeto", JSON.stringify(data.stack), now, now]
187
+ );
188
+
189
+ // Criar standards baseados na estrutura detectada
190
+ const structure = data.structure as StructureDetection;
191
+
192
+ if (structure.components) {
193
+ db.run(
194
+ `INSERT INTO standards (category, scope, rule, examples, source, created_at)
195
+ VALUES ('structure', 'frontend', ?, ?, 'detected', ?)`,
196
+ [
197
+ `Componentes devem estar em ${structure.components}/`,
198
+ JSON.stringify([`${structure.components}/Button.tsx`]),
199
+ now,
200
+ ]
201
+ );
202
+ }
203
+
204
+ if (structure.services) {
205
+ db.run(
206
+ `INSERT INTO standards (category, scope, rule, examples, source, created_at)
207
+ VALUES ('structure', 'backend', ?, ?, 'detected', ?)`,
208
+ [
209
+ `Services devem estar em ${structure.services}/`,
210
+ JSON.stringify([`${structure.services}/authService.ts`]),
211
+ now,
212
+ ]
213
+ );
214
+ }
215
+
216
+ if (structure.schema) {
217
+ db.run(
218
+ `INSERT INTO standards (category, scope, rule, examples, source, created_at)
219
+ VALUES ('structure', 'database', ?, ?, 'detected', ?)`,
220
+ [
221
+ `Schema do banco deve estar em ${structure.schema}/`,
222
+ JSON.stringify([`${structure.schema}/users.ts`]),
223
+ now,
224
+ ]
225
+ );
226
+ }
227
+
228
+ if (structure.types) {
229
+ db.run(
230
+ `INSERT INTO standards (category, scope, rule, examples, source, created_at)
231
+ VALUES ('structure', 'all', ?, ?, 'detected', ?)`,
232
+ [
233
+ `Tipos devem estar em ${structure.types}/`,
234
+ JSON.stringify([`${structure.types}/user.ts`]),
235
+ now,
236
+ ]
237
+ );
238
+ }
239
+
240
+ // Standards de nomenclatura padrao
241
+ db.run(
242
+ `INSERT INTO standards (category, scope, rule, examples, anti_examples, source, created_at)
243
+ VALUES ('naming', 'frontend', ?, ?, ?, 'detected', ?)`,
244
+ [
245
+ "Componentes usam PascalCase",
246
+ JSON.stringify(["Button.tsx", "LoginForm.tsx"]),
247
+ JSON.stringify(["button.tsx", "login-form.tsx"]),
248
+ now,
249
+ ]
250
+ );
251
+
252
+ db.run(
253
+ `INSERT INTO standards (category, scope, rule, examples, anti_examples, source, created_at)
254
+ VALUES ('naming', 'backend', ?, ?, ?, 'detected', ?)`,
255
+ [
256
+ "Services usam camelCase",
257
+ JSON.stringify(["authService.ts", "userService.ts"]),
258
+ JSON.stringify(["AuthService.ts", "auth-service.ts"]),
259
+ now,
260
+ ]
261
+ );
262
+
263
+ // Gerar arquivo standards.md
264
+ generateStandardsMarkdown();
265
+
266
+ const standardsCount = db.query("SELECT COUNT(*) as c FROM standards").get() as any;
267
+
268
+ // Auto-setup: deep-explore agent
269
+ ensureDeepExploreAgent();
270
+
271
+ console.log("\nProjeto descoberto e configurado!");
272
+ console.log(`Standards criados: ${standardsCount.c}`);
273
+ console.log("\nArquivo gerado: .codexa/standards.md");
274
+ console.log("\nProximo passo: /codexa:feature para iniciar uma feature\n");
275
+ }
276
+
277
+ export function discoverShow(json: boolean = false): void {
278
+ initSchema();
279
+ const db = getDb();
280
+
281
+ const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
282
+
283
+ if (!project) {
284
+ console.error("\nProjeto nao descoberto.");
285
+ console.error("Execute: discover start\n");
286
+ process.exit(1);
287
+ }
288
+
289
+ const standards = db.query("SELECT * FROM standards ORDER BY category, scope").all() as any[];
290
+ const stack = JSON.parse(project.stack);
291
+
292
+ if (json) {
293
+ console.log(JSON.stringify({ project, stack, standards }, null, 2));
294
+ return;
295
+ }
296
+
297
+ console.log("\n" + "═".repeat(60));
298
+ console.log("PROJETO CONFIGURADO");
299
+ console.log("═".repeat(60));
300
+
301
+ console.log("\nStack:");
302
+ for (const [key, value] of Object.entries(stack)) {
303
+ if (value) console.log(` ${key}: ${value}`);
304
+ }
305
+
306
+ console.log(`\nStandards (${standards.length}):`);
307
+ console.log("─".repeat(60));
308
+
309
+ let currentCategory = "";
310
+ for (const std of standards) {
311
+ if (std.category !== currentCategory) {
312
+ currentCategory = std.category;
313
+ console.log(`\n[${currentCategory.toUpperCase()}]`);
314
+ }
315
+ console.log(` (${std.scope}) ${std.rule}`);
316
+ }
317
+
318
+ console.log("\n" + "─".repeat(60));
319
+ console.log("Arquivo: .codexa/standards.md\n");
320
+ }
321
+
322
+ export function discoverSetStack(options: {
323
+ frontend?: string;
324
+ backend?: string;
325
+ database?: string;
326
+ orm?: string;
327
+ styling?: string;
328
+ auth?: string;
329
+ testing?: string;
330
+ }): void {
331
+ initSchema();
332
+ const db = getDb();
333
+
334
+ let pending = db.query("SELECT * FROM project WHERE id = 'pending'").get() as any;
335
+ let data: any;
336
+
337
+ if (pending) {
338
+ data = JSON.parse(pending.stack);
339
+ } else {
340
+ data = { stack: {}, structure: {} };
341
+ }
342
+
343
+ // Atualizar stack com opcoes fornecidas
344
+ if (options.frontend) data.stack.frontend = options.frontend;
345
+ if (options.backend) data.stack.backend = options.backend;
346
+ if (options.database) data.stack.database = options.database;
347
+ if (options.orm) data.stack.orm = options.orm;
348
+ if (options.styling) data.stack.styling = options.styling;
349
+ if (options.auth) data.stack.auth = options.auth;
350
+ if (options.testing) data.stack.testing = options.testing;
351
+
352
+ db.run(
353
+ `INSERT OR REPLACE INTO project (id, name, stack, discovered_at, updated_at)
354
+ VALUES ('pending', 'pending', ?, datetime('now'), datetime('now'))`,
355
+ [JSON.stringify(data)]
356
+ );
357
+
358
+ console.log("\nStack atualizado:");
359
+ for (const [key, value] of Object.entries(data.stack)) {
360
+ if (value) console.log(` ${key}: ${value}`);
361
+ }
362
+ console.log("\nPara confirmar: discover confirm\n");
363
+ }
364
+
365
+ export function discoverReset(): void {
366
+ initSchema();
367
+ const db = getDb();
368
+
369
+ db.run("DELETE FROM project");
370
+ db.run("DELETE FROM standards");
371
+
372
+ console.log("\nDescoberta resetada.");
373
+ console.log("Execute: discover start para refazer\n");
374
+ }
375
+
376
+ export async function discoverRefresh(options: { force?: boolean } = {}): Promise<void> {
377
+ initSchema();
378
+ const db = getDb();
379
+
380
+ const currentProject = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
381
+ if (!currentProject) {
382
+ console.error("\nProjeto nao descoberto.");
383
+ console.error("Execute: discover start primeiro\n");
384
+ process.exit(1);
385
+ }
386
+
387
+ const currentStack = JSON.parse(currentProject.stack);
388
+ const newStack = await detectStack();
389
+ const newStructure = await detectStructure();
390
+
391
+ // Comparar stacks
392
+ const stackChanges: { key: string; from: string | undefined; to: string | undefined }[] = [];
393
+ const allKeys = new Set([...Object.keys(currentStack), ...Object.keys(newStack)]);
394
+
395
+ for (const key of allKeys) {
396
+ const current = currentStack[key as keyof StackDetection];
397
+ const detected = newStack[key as keyof StackDetection];
398
+ if (current !== detected) {
399
+ stackChanges.push({ key, from: current, to: detected });
400
+ }
401
+ }
402
+
403
+ if (stackChanges.length === 0) {
404
+ console.log("\n✓ Stack continua o mesmo. Nenhuma mudanca detectada.\n");
405
+ return;
406
+ }
407
+
408
+ console.log("\n" + "═".repeat(60));
409
+ console.log("MUDANCAS DETECTADAS NO STACK");
410
+ console.log("═".repeat(60) + "\n");
411
+
412
+ for (const change of stackChanges) {
413
+ const from = change.from || "(nao definido)";
414
+ const to = change.to || "(removido)";
415
+ console.log(` ${change.key}: ${from} → ${to}`);
416
+ }
417
+
418
+ if (options.force) {
419
+ // Aplicar mudanças
420
+ const now = new Date().toISOString();
421
+
422
+ db.run(
423
+ `UPDATE project SET stack = ?, updated_at = ? WHERE id = 'default'`,
424
+ [JSON.stringify(newStack), now]
425
+ );
426
+
427
+ // Atualizar standards de stack
428
+ for (const change of stackChanges) {
429
+ if (change.to) {
430
+ // Adicionar ou atualizar standard de stack
431
+ const existing = db.query(
432
+ `SELECT id FROM standards WHERE category = 'stack' AND rule LIKE ?`
433
+ ).get(`%${change.key}%`) as any;
434
+
435
+ if (existing) {
436
+ db.run(
437
+ `UPDATE standards SET rule = ?, updated_at = ? WHERE id = ?`,
438
+ [`${change.key}: ${change.to}`, now, existing.id]
439
+ );
440
+ } else {
441
+ db.run(
442
+ `INSERT INTO standards (category, scope, rule, enforcement, source, created_at)
443
+ VALUES ('stack', 'all', ?, 'required', 'refresh', ?)`,
444
+ [`${change.key}: ${change.to}`, now]
445
+ );
446
+ }
447
+ }
448
+ }
449
+
450
+ // Regenerar standards.md
451
+ generateStandardsMarkdown();
452
+
453
+ console.log("\n✓ Stack atualizado com sucesso!");
454
+ console.log("✓ Standards regenerados\n");
455
+ } else {
456
+ console.log("\n" + "─".repeat(60));
457
+ console.log("Para aplicar as mudancas: discover refresh --force\n");
458
+ }
459
+ }
460
+
461
+ function generateStandardsMarkdown(): void {
462
+ const db = getDb();
463
+ const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
464
+ const standards = db.query("SELECT * FROM standards ORDER BY category, scope").all() as any[];
465
+
466
+ if (!project) return;
467
+
468
+ const stack = JSON.parse(project.stack);
469
+ let md = `# Standards do Projeto
470
+
471
+ > Gerado automaticamente do SQLite. Nao edite manualmente.
472
+ > Para modificar, use os comandos CLI.
473
+ > Gerado em: ${new Date().toISOString()}
474
+
475
+ ## Stack
476
+
477
+ `;
478
+
479
+ for (const [key, value] of Object.entries(stack)) {
480
+ if (value) md += `- **${key}:** ${value}\n`;
481
+ }
482
+
483
+ // Agrupar standards por categoria
484
+ const byCategory: Record<string, any[]> = {};
485
+ for (const std of standards) {
486
+ if (!byCategory[std.category]) byCategory[std.category] = [];
487
+ byCategory[std.category].push(std);
488
+ }
489
+
490
+ for (const [category, stds] of Object.entries(byCategory)) {
491
+ md += `\n## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
492
+
493
+ for (const std of stds) {
494
+ const enforcement = std.enforcement === "required" ? "OBRIGATORIO" : "Recomendado";
495
+ md += `### ${std.rule}\n\n`;
496
+ md += `- **Escopo:** ${std.scope}\n`;
497
+ md += `- **Enforcement:** ${enforcement}\n`;
498
+
499
+ if (std.examples) {
500
+ const examples = JSON.parse(std.examples);
501
+ md += `- **Exemplos:**\n`;
502
+ for (const ex of examples) {
503
+ md += ` - \`${ex}\`\n`;
504
+ }
505
+ }
506
+
507
+ if (std.anti_examples) {
508
+ const antiExamples = JSON.parse(std.anti_examples);
509
+ md += `- **Nao fazer:**\n`;
510
+ for (const ex of antiExamples) {
511
+ md += ` - ~~\`${ex}\`~~\n`;
512
+ }
513
+ }
514
+
515
+ md += "\n";
516
+ }
517
+ }
518
+
519
+ // Garantir que diretorio existe
520
+ const mdPath = join(process.cwd(), ".codexa", "standards.md");
521
+ writeFileSync(mdPath, md);
522
+ }
523
+
524
+ export { generateStandardsMarkdown };
525
+
526
+ // ============================================================
527
+ // PATTERN EXTRACTION (v7.4)
528
+ // ============================================================
529
+
530
+ interface PatternStructure {
531
+ imports: {
532
+ order: string[];
533
+ common: string[];
534
+ conditional: string[];
535
+ };
536
+ exports: {
537
+ style: "named" | "default" | "both";
538
+ async: boolean;
539
+ };
540
+ patterns: {
541
+ hooks_used: string[];
542
+ props_style: "interface" | "type" | "inline";
543
+ error_handling: string;
544
+ data_fetching: string;
545
+ };
546
+ conventions: {
547
+ file_structure: string[];
548
+ naming: {
549
+ functions: string;
550
+ variables: string;
551
+ types: string;
552
+ };
553
+ };
554
+ }
555
+
556
+ interface AntiPattern {
557
+ description: string;
558
+ example: string;
559
+ found_in: string[];
560
+ recommendation?: string;
561
+ }
562
+
563
+ interface ImplementationPattern {
564
+ category: string;
565
+ name: string;
566
+ scope: string;
567
+ applies_to: string;
568
+ structure: PatternStructure;
569
+ template: string;
570
+ examples: { path: string; relevance: number }[];
571
+ anti_patterns: AntiPattern[];
572
+ confidence: number;
573
+ extracted_from: number;
574
+ }
575
+
576
+ export function discoverPatterns(options: { category?: string; json?: boolean } = {}): void {
577
+ initSchema();
578
+ const db = getDb();
579
+
580
+ let query = "SELECT * FROM implementation_patterns";
581
+ const params: string[] = [];
582
+
583
+ if (options.category) {
584
+ query += " WHERE category = ?";
585
+ params.push(options.category);
586
+ }
587
+
588
+ query += " ORDER BY category, name";
589
+
590
+ const patterns = db.query(query).all(...params) as any[];
591
+
592
+ if (patterns.length === 0) {
593
+ console.log("\nNenhum pattern extraido ainda.");
594
+ console.log("Execute: discover start para extrair patterns do codigo\n");
595
+ return;
596
+ }
597
+
598
+ if (options.json) {
599
+ console.log(JSON.stringify(patterns.map(p => ({
600
+ ...p,
601
+ structure: JSON.parse(p.structure || "{}"),
602
+ examples: JSON.parse(p.examples || "[]"),
603
+ anti_patterns: JSON.parse(p.anti_patterns || "[]"),
604
+ })), null, 2));
605
+ return;
606
+ }
607
+
608
+ console.log("\n" + "═".repeat(70));
609
+ console.log("IMPLEMENTATION PATTERNS EXTRAIDOS");
610
+ console.log("═".repeat(70) + "\n");
611
+
612
+ console.log("┌" + "─".repeat(20) + "┬" + "─".repeat(25) + "┬" + "─".repeat(10) + "┬" + "─".repeat(10) + "┐");
613
+ console.log("│ Categoria │ Nome │ Arquivos │ Confianca│");
614
+ console.log("├" + "─".repeat(20) + "┼" + "─".repeat(25) + "┼" + "─".repeat(10) + "┼" + "─".repeat(10) + "┤");
615
+
616
+ for (const p of patterns) {
617
+ const cat = p.category.padEnd(18);
618
+ const name = p.name.substring(0, 23).padEnd(23);
619
+ const files = String(p.extracted_from || 0).padStart(8);
620
+ const conf = ((p.confidence || 0) * 100).toFixed(0).padStart(7) + "%";
621
+ console.log(`│ ${cat} │ ${name} │ ${files} │ ${conf} │`);
622
+ }
623
+
624
+ console.log("└" + "─".repeat(20) + "┴" + "─".repeat(25) + "┴" + "─".repeat(10) + "┴" + "─".repeat(10) + "┘");
625
+
626
+ // Contar anti-patterns
627
+ let totalAntiPatterns = 0;
628
+ for (const p of patterns) {
629
+ const antiPatterns = JSON.parse(p.anti_patterns || "[]");
630
+ totalAntiPatterns += antiPatterns.length;
631
+ }
632
+
633
+ if (totalAntiPatterns > 0) {
634
+ console.log(`\n⚠ Anti-patterns identificados: ${totalAntiPatterns}`);
635
+ console.log(" Use: discover patterns --show <name> para ver detalhes");
636
+ }
637
+
638
+ console.log("\n" + "─".repeat(70));
639
+ console.log("Para ver detalhes: discover patterns --show <name>");
640
+ console.log("Para exportar: discover export-patterns\n");
641
+ }
642
+
643
+ export function discoverPatternsShow(name: string, json: boolean = false): void {
644
+ initSchema();
645
+ const db = getDb();
646
+
647
+ const pattern = db.query("SELECT * FROM implementation_patterns WHERE name = ?").get(name) as any;
648
+
649
+ if (!pattern) {
650
+ console.error(`\nPattern '${name}' nao encontrado.`);
651
+ console.error("Use: discover patterns para listar todos\n");
652
+ process.exit(1);
653
+ }
654
+
655
+ const structure = JSON.parse(pattern.structure || "{}");
656
+ const examples = JSON.parse(pattern.examples || "[]");
657
+ const antiPatterns = JSON.parse(pattern.anti_patterns || "[]");
658
+
659
+ if (json) {
660
+ console.log(JSON.stringify({
661
+ ...pattern,
662
+ structure,
663
+ examples,
664
+ anti_patterns: antiPatterns,
665
+ }, null, 2));
666
+ return;
667
+ }
668
+
669
+ console.log("\n" + "═".repeat(70));
670
+ console.log(`PATTERN: ${pattern.name}`);
671
+ console.log("═".repeat(70));
672
+
673
+ console.log(`\nCategoria: ${pattern.category}`);
674
+ console.log(`Escopo: ${pattern.scope}`);
675
+ console.log(`Aplica-se a: ${pattern.applies_to}`);
676
+ console.log(`Confianca: ${((pattern.confidence || 0) * 100).toFixed(0)}%`);
677
+ console.log(`Extraido de: ${pattern.extracted_from} arquivos`);
678
+
679
+ console.log("\n" + "─".repeat(70));
680
+ console.log("ESTRUTURA");
681
+ console.log("─".repeat(70));
682
+
683
+ if (structure.imports) {
684
+ console.log("\nImports:");
685
+ console.log(` Ordem: ${structure.imports.order?.join(" → ") || "N/A"}`);
686
+ console.log(` Comuns: ${structure.imports.common?.join(", ") || "N/A"}`);
687
+ }
688
+
689
+ if (structure.exports) {
690
+ console.log("\nExports:");
691
+ console.log(` Estilo: ${structure.exports.style || "N/A"}`);
692
+ console.log(` Async: ${structure.exports.async ? "Sim" : "Nao"}`);
693
+ }
694
+
695
+ if (structure.patterns) {
696
+ console.log("\nPadroes:");
697
+ console.log(` Hooks: ${structure.patterns.hooks_used?.join(", ") || "N/A"}`);
698
+ console.log(` Props: ${structure.patterns.props_style || "N/A"}`);
699
+ console.log(` Erro: ${structure.patterns.error_handling || "N/A"}`);
700
+ console.log(` Data: ${structure.patterns.data_fetching || "N/A"}`);
701
+ }
702
+
703
+ console.log("\n" + "─".repeat(70));
704
+ console.log("TEMPLATE");
705
+ console.log("─".repeat(70));
706
+ console.log("\n" + pattern.template);
707
+
708
+ console.log("\n" + "─".repeat(70));
709
+ console.log("EXEMPLOS DE REFERENCIA");
710
+ console.log("─".repeat(70));
711
+
712
+ for (const ex of examples.slice(0, 5)) {
713
+ const relevance = ((ex.relevance || 0) * 100).toFixed(0);
714
+ console.log(` ${ex.path} (${relevance}% similar)`);
715
+ }
716
+
717
+ if (antiPatterns.length > 0) {
718
+ console.log("\n" + "─".repeat(70));
719
+ console.log("⚠ ANTI-PATTERNS IDENTIFICADOS");
720
+ console.log("─".repeat(70));
721
+
722
+ for (const ap of antiPatterns) {
723
+ console.log(`\n ❌ ${ap.description}`);
724
+ console.log(` Encontrado em: ${ap.found_in?.join(", ") || "N/A"}`);
725
+ if (ap.recommendation) {
726
+ console.log(` Recomendacao: ${ap.recommendation}`);
727
+ }
728
+ }
729
+ }
730
+
731
+ console.log("\n");
732
+ }
733
+
734
+ export function discoverPatternAdd(options: {
735
+ category: string;
736
+ name: string;
737
+ scope: string;
738
+ appliesTo: string;
739
+ structure: string;
740
+ template: string;
741
+ examples: string;
742
+ antiPatterns?: string;
743
+ confidence?: number;
744
+ extractedFrom?: number;
745
+ }): void {
746
+ initSchema();
747
+ const db = getDb();
748
+
749
+ // Verificar se pattern ja existe
750
+ const existing = db.query("SELECT id FROM implementation_patterns WHERE name = ?").get(options.name);
751
+ if (existing) {
752
+ console.error(`\nPattern '${options.name}' ja existe.`);
753
+ console.error("Use: discover pattern-edit para modificar\n");
754
+ process.exit(1);
755
+ }
756
+
757
+ const now = new Date().toISOString();
758
+
759
+ db.run(
760
+ `INSERT INTO implementation_patterns
761
+ (category, name, scope, applies_to, structure, template, examples, anti_patterns, confidence, extracted_from, created_at, updated_at)
762
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
763
+ [
764
+ options.category,
765
+ options.name,
766
+ options.scope,
767
+ options.appliesTo,
768
+ options.structure,
769
+ options.template,
770
+ options.examples,
771
+ options.antiPatterns || "[]",
772
+ options.confidence || 0.8,
773
+ options.extractedFrom || 1,
774
+ now,
775
+ now,
776
+ ]
777
+ );
778
+
779
+ // Regenerar patterns.md
780
+ generatePatternsMarkdown();
781
+
782
+ console.log(`\n✓ Pattern '${options.name}' adicionado com sucesso!`);
783
+ console.log("Arquivo atualizado: .codexa/patterns.md\n");
784
+ }
785
+
786
+ export function discoverPatternEdit(name: string, options: {
787
+ category?: string;
788
+ scope?: string;
789
+ appliesTo?: string;
790
+ structure?: string;
791
+ template?: string;
792
+ examples?: string;
793
+ antiPatterns?: string;
794
+ confidence?: number;
795
+ }): void {
796
+ initSchema();
797
+ const db = getDb();
798
+
799
+ const existing = db.query("SELECT * FROM implementation_patterns WHERE name = ?").get(name) as any;
800
+ if (!existing) {
801
+ console.error(`\nPattern '${name}' nao encontrado.`);
802
+ console.error("Use: discover patterns para listar todos\n");
803
+ process.exit(1);
804
+ }
805
+
806
+ const updates: string[] = [];
807
+ const params: any[] = [];
808
+
809
+ if (options.category) {
810
+ updates.push("category = ?");
811
+ params.push(options.category);
812
+ }
813
+ if (options.scope) {
814
+ updates.push("scope = ?");
815
+ params.push(options.scope);
816
+ }
817
+ if (options.appliesTo) {
818
+ updates.push("applies_to = ?");
819
+ params.push(options.appliesTo);
820
+ }
821
+ if (options.structure) {
822
+ updates.push("structure = ?");
823
+ params.push(options.structure);
824
+ }
825
+ if (options.template) {
826
+ updates.push("template = ?");
827
+ params.push(options.template);
828
+ }
829
+ if (options.examples) {
830
+ updates.push("examples = ?");
831
+ params.push(options.examples);
832
+ }
833
+ if (options.antiPatterns) {
834
+ updates.push("anti_patterns = ?");
835
+ params.push(options.antiPatterns);
836
+ }
837
+ if (options.confidence !== undefined) {
838
+ updates.push("confidence = ?");
839
+ params.push(options.confidence);
840
+ }
841
+
842
+ if (updates.length === 0) {
843
+ console.error("\nNenhuma opcao de atualizacao fornecida.\n");
844
+ process.exit(1);
845
+ }
846
+
847
+ updates.push("updated_at = ?");
848
+ params.push(new Date().toISOString());
849
+ params.push(name);
850
+
851
+ db.run(
852
+ `UPDATE implementation_patterns SET ${updates.join(", ")} WHERE name = ?`,
853
+ params
854
+ );
855
+
856
+ // Regenerar patterns.md
857
+ generatePatternsMarkdown();
858
+
859
+ console.log(`\n✓ Pattern '${name}' atualizado com sucesso!`);
860
+ console.log("Arquivo atualizado: .codexa/patterns.md\n");
861
+ }
862
+
863
+ export function discoverPatternRemove(name: string): void {
864
+ initSchema();
865
+ const db = getDb();
866
+
867
+ const existing = db.query("SELECT id FROM implementation_patterns WHERE name = ?").get(name);
868
+ if (!existing) {
869
+ console.error(`\nPattern '${name}' nao encontrado.\n`);
870
+ process.exit(1);
871
+ }
872
+
873
+ db.run("DELETE FROM implementation_patterns WHERE name = ?", [name]);
874
+
875
+ // Regenerar patterns.md
876
+ generatePatternsMarkdown();
877
+
878
+ console.log(`\n✓ Pattern '${name}' removido com sucesso!`);
879
+ console.log("Arquivo atualizado: .codexa/patterns.md\n");
880
+ }
881
+
882
+ export function discoverRefreshPatterns(): void {
883
+ initSchema();
884
+ const db = getDb();
885
+
886
+ // Verificar se projeto foi descoberto
887
+ const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
888
+ if (!project) {
889
+ console.error("\nProjeto nao descoberto.");
890
+ console.error("Execute: discover start primeiro\n");
891
+ process.exit(1);
892
+ }
893
+
894
+ console.log("\n⚠ Refresh de patterns requer analise manual do codigo.");
895
+ console.log("Use o skill /codexa:discover para extrair patterns automaticamente.");
896
+ console.log("\nAlternativamente, adicione patterns manualmente:");
897
+ console.log(" discover pattern-add --category component --name my-pattern ...\n");
898
+ }
899
+
900
+ export function generatePatternsMarkdown(): void {
901
+ const db = getDb();
902
+ const patterns = db.query("SELECT * FROM implementation_patterns ORDER BY category, name").all() as any[];
903
+
904
+ if (patterns.length === 0) return;
905
+
906
+ let md = `# Implementation Patterns
907
+
908
+ > Gerado automaticamente do SQLite. Nao edite manualmente.
909
+ > Para modificar, use os comandos CLI.
910
+ > Gerado em: ${new Date().toISOString()}
911
+
912
+ ## Resumo
913
+
914
+ | Categoria | Nome | Arquivos | Confianca |
915
+ |-----------|------|----------|-----------|
916
+ `;
917
+
918
+ for (const p of patterns) {
919
+ const conf = ((p.confidence || 0) * 100).toFixed(0);
920
+ md += `| ${p.category} | ${p.name} | ${p.extracted_from || 0} | ${conf}% |\n`;
921
+ }
922
+
923
+ // Agrupar por categoria
924
+ const byCategory: Record<string, any[]> = {};
925
+ for (const p of patterns) {
926
+ if (!byCategory[p.category]) byCategory[p.category] = [];
927
+ byCategory[p.category].push(p);
928
+ }
929
+
930
+ for (const [category, categoryPatterns] of Object.entries(byCategory)) {
931
+ md += `\n## ${category.charAt(0).toUpperCase() + category.slice(1)}\n`;
932
+
933
+ for (const p of categoryPatterns) {
934
+ const structure = JSON.parse(p.structure || "{}");
935
+ const examples = JSON.parse(p.examples || "[]");
936
+ const antiPatterns = JSON.parse(p.anti_patterns || "[]");
937
+
938
+ md += `\n### ${p.name}\n\n`;
939
+ md += `- **Escopo:** ${p.scope}\n`;
940
+ md += `- **Aplica-se a:** \`${p.applies_to}\`\n`;
941
+ md += `- **Confianca:** ${((p.confidence || 0) * 100).toFixed(0)}%\n`;
942
+ md += `- **Extraido de:** ${p.extracted_from || 0} arquivos\n`;
943
+
944
+ if (structure.imports?.common?.length > 0) {
945
+ md += `\n**Imports comuns:**\n`;
946
+ for (const imp of structure.imports.common) {
947
+ md += `- \`${imp}\`\n`;
948
+ }
949
+ }
950
+
951
+ if (structure.patterns?.hooks_used?.length > 0) {
952
+ md += `\n**Hooks utilizados:** ${structure.patterns.hooks_used.join(", ")}\n`;
953
+ }
954
+
955
+ md += `\n**Template:**\n\n\`\`\`typescript\n${p.template}\n\`\`\`\n`;
956
+
957
+ if (examples.length > 0) {
958
+ md += `\n**Exemplos de referencia:**\n`;
959
+ for (const ex of examples.slice(0, 5)) {
960
+ const rel = ((ex.relevance || 0) * 100).toFixed(0);
961
+ md += `- \`${ex.path}\` (${rel}% similar)\n`;
962
+ }
963
+ }
964
+
965
+ if (antiPatterns.length > 0) {
966
+ md += `\n**⚠ Anti-patterns:**\n`;
967
+ for (const ap of antiPatterns) {
968
+ md += `- ❌ ${ap.description}\n`;
969
+ if (ap.found_in?.length > 0) {
970
+ md += ` - Encontrado em: ${ap.found_in.join(", ")}\n`;
971
+ }
972
+ if (ap.recommendation) {
973
+ md += ` - Recomendacao: ${ap.recommendation}\n`;
974
+ }
975
+ }
976
+ }
977
+ }
978
+ }
979
+
980
+ // Garantir que diretorio existe
981
+ const dir = join(process.cwd(), ".codexa");
982
+ if (!existsSync(dir)) {
983
+ mkdirSync(dir, { recursive: true });
984
+ }
985
+
986
+ const mdPath = join(dir, "patterns.md");
987
+ writeFileSync(mdPath, md);
988
+ }
989
+
990
+ export function discoverExportPatterns(): void {
991
+ generatePatternsMarkdown();
992
+ console.log("\n✓ Arquivo .codexa/patterns.md regenerado!\n");
993
+ }
994
+
995
+ // Auto-setup: garante que o agent deep-explore existe no projeto
996
+ export function ensureDeepExploreAgent(): void {
997
+ const agentPath = join(process.cwd(), ".claude", "agents", "deep-explore.md");
998
+
999
+ if (existsSync(agentPath)) return;
1000
+
1001
+ const agentsDir = join(process.cwd(), ".claude", "agents");
1002
+ if (!existsSync(agentsDir)) {
1003
+ mkdirSync(agentsDir, { recursive: true });
1004
+ }
1005
+
1006
+ const content = `---
1007
+ name: deep-explore
1008
+ description: Deep codebase exploration using grepai semantic search and call graph tracing. Use this agent for understanding code architecture, finding implementations by intent, analyzing function relationships, and exploring unfamiliar code areas.
1009
+ tools: Read, Grep, Glob, Bash
1010
+ color: cyan
1011
+ model: haiku
1012
+ ---
1013
+
1014
+ ## Instructions
1015
+
1016
+ You are a specialized code exploration agent with access to grepai semantic search and call graph tracing.
1017
+
1018
+ ### Primary Tools
1019
+
1020
+ #### 1. Semantic Search: \`grepai search\`
1021
+
1022
+ Use this to find code by intent and meaning:
1023
+
1024
+ \`\`\`bash
1025
+ # Use English queries for best results (--compact saves ~80% tokens)
1026
+ grepai search "authentication flow" --json --compact
1027
+ grepai search "error handling middleware" --json --compact
1028
+ grepai search "database connection management" --json --compact
1029
+ \`\`\`
1030
+
1031
+ #### 2. Call Graph Tracing: \`grepai trace\`
1032
+
1033
+ Use this to understand function relationships and code flow:
1034
+
1035
+ \`\`\`bash
1036
+ # Find all functions that call a symbol
1037
+ grepai trace callers "HandleRequest" --json
1038
+
1039
+ # Find all functions called by a symbol
1040
+ grepai trace callees "ProcessOrder" --json
1041
+
1042
+ # Build complete call graph
1043
+ grepai trace graph "ValidateToken" --depth 3 --json
1044
+ \`\`\`
1045
+
1046
+ Use \`grepai trace\` when you need to:
1047
+
1048
+ - Find all callers of a function
1049
+ - Understand the call hierarchy
1050
+ - Analyze the impact of changes to a function
1051
+ - Map dependencies between components
1052
+
1053
+ ### When to use standard tools
1054
+
1055
+ Only fall back to Grep/Glob when:
1056
+
1057
+ - You need exact text matching (variable names, imports)
1058
+ - grepai is not available or returns errors
1059
+ - You need file path patterns
1060
+
1061
+ ### Workflow
1062
+
1063
+ 1. Start with \`grepai search\` to find relevant code semantically
1064
+ 2. Use \`grepai trace\` to understand function relationships and call graphs
1065
+ 3. Use \`Read\` to examine promising files in detail
1066
+ 4. Use Grep only for exact string searches if needed
1067
+ 5. Synthesize findings into a clear summary
1068
+ `;
1069
+
1070
+ writeFileSync(agentPath, content);
1071
+ console.log("✓ Agent deep-explore instalado em .claude/agents/deep-explore.md");
1072
1072
  }