@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.
- package/commands/architect.ts +760 -760
- package/commands/check.ts +131 -131
- package/commands/clear.ts +170 -170
- package/commands/decide.ts +249 -249
- package/commands/discover.ts +1071 -1071
- package/commands/knowledge.ts +361 -361
- package/commands/patterns.ts +621 -621
- package/commands/plan.ts +376 -376
- package/commands/product.ts +626 -626
- package/commands/research.ts +754 -754
- package/commands/review.ts +463 -463
- package/commands/standards.ts +200 -200
- package/commands/task.ts +623 -623
- package/commands/utils.ts +1021 -1021
- package/db/connection.ts +32 -32
- package/db/schema.ts +719 -719
- package/detectors/README.md +109 -109
- package/detectors/dotnet.ts +357 -357
- package/detectors/flutter.ts +350 -350
- package/detectors/go.ts +324 -324
- package/detectors/index.ts +387 -387
- package/detectors/jvm.ts +433 -433
- package/detectors/loader.ts +128 -128
- package/detectors/node.ts +493 -493
- package/detectors/python.ts +423 -423
- package/detectors/rust.ts +348 -348
- package/gates/standards-validator.ts +204 -204
- package/gates/validator.ts +441 -441
- package/package.json +44 -43
- package/protocol/process-return.ts +450 -450
- package/protocol/subagent-protocol.ts +401 -401
- package/workflow.ts +783 -782
package/commands/discover.ts
CHANGED
|
@@ -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
|
}
|