@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/review.ts
CHANGED
|
@@ -1,463 +1,463 @@
|
|
|
1
|
-
import { getDb } from "../db/connection";
|
|
2
|
-
import { initSchema, getArchitecturalAnalysisForSpec } from "../db/schema";
|
|
3
|
-
import { enforceGate } from "../gates/validator";
|
|
4
|
-
|
|
5
|
-
export function reviewStart(json: boolean = false): void {
|
|
6
|
-
initSchema();
|
|
7
|
-
enforceGate("review-start");
|
|
8
|
-
|
|
9
|
-
const db = getDb();
|
|
10
|
-
const now = new Date().toISOString();
|
|
11
|
-
|
|
12
|
-
const spec = db
|
|
13
|
-
.query("SELECT * FROM specs WHERE phase = 'implementing' ORDER BY created_at DESC LIMIT 1")
|
|
14
|
-
.get() as any;
|
|
15
|
-
|
|
16
|
-
const tasks = db
|
|
17
|
-
.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number")
|
|
18
|
-
.all(spec.id) as any[];
|
|
19
|
-
|
|
20
|
-
const artifacts = db
|
|
21
|
-
.query("SELECT * FROM artifacts WHERE spec_id = ?")
|
|
22
|
-
.all(spec.id) as any[];
|
|
23
|
-
|
|
24
|
-
const decisions = db
|
|
25
|
-
.query("SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'")
|
|
26
|
-
.all(spec.id) as any[];
|
|
27
|
-
|
|
28
|
-
// v8.4: Buscar analise arquitetural (link explicito via analysis_id ou nome)
|
|
29
|
-
const archAnalysis = getArchitecturalAnalysisForSpec(spec.name, spec.id);
|
|
30
|
-
const gateBypasses = db.query(
|
|
31
|
-
"SELECT * FROM gate_bypasses WHERE spec_id = ? ORDER BY created_at"
|
|
32
|
-
).all(spec.id) as any[];
|
|
33
|
-
|
|
34
|
-
// Analisar plano vs implementado
|
|
35
|
-
const plannedFiles = tasks.flatMap((t) => (t.files ? JSON.parse(t.files) : []));
|
|
36
|
-
const createdFiles = artifacts.map((a) => a.path);
|
|
37
|
-
|
|
38
|
-
const missingFiles = plannedFiles.filter((f: string) => !createdFiles.includes(f));
|
|
39
|
-
const extraFiles = createdFiles.filter((f) => !plannedFiles.includes(f));
|
|
40
|
-
|
|
41
|
-
const deviations: string[] = [];
|
|
42
|
-
if (missingFiles.length > 0) {
|
|
43
|
-
deviations.push(`Arquivos planejados nao criados: ${missingFiles.join(", ")}`);
|
|
44
|
-
}
|
|
45
|
-
if (extraFiles.length > 0) {
|
|
46
|
-
deviations.push(`Arquivos extras criados: ${extraFiles.join(", ")}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Criar registro de review
|
|
50
|
-
const reviewData = {
|
|
51
|
-
tasks_completed: tasks.length,
|
|
52
|
-
artifacts_created: artifacts.length,
|
|
53
|
-
decisions_made: decisions.length,
|
|
54
|
-
planned_files: plannedFiles,
|
|
55
|
-
created_files: createdFiles,
|
|
56
|
-
// v8.3: Contexto arquitetural e auditoria
|
|
57
|
-
architectural_analysis: archAnalysis ? {
|
|
58
|
-
id: archAnalysis.id,
|
|
59
|
-
name: archAnalysis.name,
|
|
60
|
-
approach: archAnalysis.approach,
|
|
61
|
-
risks: archAnalysis.risks ? JSON.parse(archAnalysis.risks) : [],
|
|
62
|
-
diagrams: archAnalysis.diagrams ? JSON.parse(archAnalysis.diagrams) : [],
|
|
63
|
-
decisions: archAnalysis.decisions ? JSON.parse(archAnalysis.decisions) : [],
|
|
64
|
-
} : null,
|
|
65
|
-
gate_bypasses: gateBypasses,
|
|
66
|
-
// v8.5: Utilities criadas nesta feature (DRY audit)
|
|
67
|
-
utilities_created: (() => {
|
|
68
|
-
try {
|
|
69
|
-
return db.query(
|
|
70
|
-
"SELECT * FROM project_utilities WHERE spec_id = ? ORDER BY file_path"
|
|
71
|
-
).all(spec.id) as any[];
|
|
72
|
-
} catch { return []; }
|
|
73
|
-
})(),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
db.run(
|
|
77
|
-
`INSERT INTO review (spec_id, planned_vs_done, deviations, status, created_at)
|
|
78
|
-
VALUES (?, ?, ?, 'pending', ?)`,
|
|
79
|
-
[
|
|
80
|
-
spec.id,
|
|
81
|
-
JSON.stringify(reviewData),
|
|
82
|
-
deviations.length > 0 ? JSON.stringify(deviations) : null,
|
|
83
|
-
now,
|
|
84
|
-
]
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
// Atualizar fase
|
|
88
|
-
db.run("UPDATE specs SET phase = 'reviewing', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
89
|
-
|
|
90
|
-
if (json) {
|
|
91
|
-
console.log(JSON.stringify({ spec, reviewData, deviations }));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
console.log(`\n${"=".repeat(60)}`);
|
|
96
|
-
console.log(`REVIEW: ${spec.name}`);
|
|
97
|
-
console.log(`${"=".repeat(60)}`);
|
|
98
|
-
|
|
99
|
-
console.log(`\nResumo da implementacao:`);
|
|
100
|
-
console.log(` Tasks concluidas: ${tasks.length}`);
|
|
101
|
-
console.log(` Artefatos criados: ${artifacts.length}`);
|
|
102
|
-
console.log(` Decisoes tomadas: ${decisions.length}`);
|
|
103
|
-
|
|
104
|
-
console.log(`\nArquivos criados:`);
|
|
105
|
-
for (const artifact of artifacts) {
|
|
106
|
-
console.log(` - ${artifact.path}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (decisions.length > 0) {
|
|
110
|
-
console.log(`\nDecisoes:`);
|
|
111
|
-
for (const dec of decisions) {
|
|
112
|
-
console.log(` ${dec.id}: ${dec.title}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (deviations.length > 0) {
|
|
117
|
-
console.log(`\nDesvios encontrados:`);
|
|
118
|
-
for (const dev of deviations) {
|
|
119
|
-
console.log(` - ${dev}`);
|
|
120
|
-
}
|
|
121
|
-
console.log(`\nResolva os desvios antes de aprovar.`);
|
|
122
|
-
} else {
|
|
123
|
-
console.log(`\nNenhum desvio encontrado.`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
console.log(`\nPara aprovar: review approve`);
|
|
127
|
-
console.log(`Para ver status: status\n`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function reviewApprove(): void {
|
|
131
|
-
initSchema();
|
|
132
|
-
enforceGate("review-approve");
|
|
133
|
-
|
|
134
|
-
const db = getDb();
|
|
135
|
-
const now = new Date().toISOString();
|
|
136
|
-
|
|
137
|
-
const spec = db
|
|
138
|
-
.query("SELECT * FROM specs WHERE phase = 'reviewing' ORDER BY created_at DESC LIMIT 1")
|
|
139
|
-
.get() as any;
|
|
140
|
-
|
|
141
|
-
if (!spec) {
|
|
142
|
-
console.error("\nNenhum review em andamento.\n");
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Atualizar review
|
|
147
|
-
db.run("UPDATE review SET status = 'passed' WHERE spec_id = ?", [spec.id]);
|
|
148
|
-
|
|
149
|
-
// Atualizar spec para completed
|
|
150
|
-
db.run("UPDATE specs SET phase = 'completed', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
151
|
-
|
|
152
|
-
// Buscar todos os dados para snapshot e relatorio
|
|
153
|
-
const tasks = db.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number").all(spec.id) as any[];
|
|
154
|
-
const decisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
155
|
-
const artifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
156
|
-
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(spec.id) as any;
|
|
157
|
-
const review = db.query("SELECT * FROM review WHERE spec_id = ?").get(spec.id) as any;
|
|
158
|
-
const knowledge = db.query("SELECT * FROM knowledge WHERE spec_id = ?").all(spec.id) as any[];
|
|
159
|
-
|
|
160
|
-
// Criar snapshot final
|
|
161
|
-
const allData = {
|
|
162
|
-
spec,
|
|
163
|
-
context,
|
|
164
|
-
tasks,
|
|
165
|
-
decisions,
|
|
166
|
-
artifacts,
|
|
167
|
-
review,
|
|
168
|
-
knowledge,
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
db.run("INSERT INTO snapshots (spec_id, data, trigger, created_at) VALUES (?, ?, 'final', ?)", [
|
|
172
|
-
spec.id,
|
|
173
|
-
JSON.stringify(allData),
|
|
174
|
-
now,
|
|
175
|
-
]);
|
|
176
|
-
|
|
177
|
-
// Mostrar relatorio final completo
|
|
178
|
-
showReviewReport(spec, tasks, artifacts, decisions, knowledge, review);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Pula o review e finaliza a feature diretamente
|
|
183
|
-
*/
|
|
184
|
-
export function reviewSkip(): void {
|
|
185
|
-
initSchema();
|
|
186
|
-
|
|
187
|
-
const db = getDb();
|
|
188
|
-
const now = new Date().toISOString();
|
|
189
|
-
|
|
190
|
-
// Buscar spec em implementacao com todas tasks concluidas
|
|
191
|
-
const spec = db
|
|
192
|
-
.query("SELECT * FROM specs WHERE phase = 'implementing' ORDER BY created_at DESC LIMIT 1")
|
|
193
|
-
.get() as any;
|
|
194
|
-
|
|
195
|
-
if (!spec) {
|
|
196
|
-
console.error("\nNenhuma feature em fase de implementacao.\n");
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Verificar se todas tasks estao done
|
|
201
|
-
const pending = db
|
|
202
|
-
.query("SELECT COUNT(*) as c FROM tasks WHERE spec_id = ? AND status != 'done'")
|
|
203
|
-
.get(spec.id) as any;
|
|
204
|
-
|
|
205
|
-
if (pending.c > 0) {
|
|
206
|
-
console.error(`\nAinda existem ${pending.c} tasks pendentes.`);
|
|
207
|
-
console.error("Complete todas as tasks antes de pular o review.\n");
|
|
208
|
-
process.exit(1);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Buscar dados
|
|
212
|
-
const tasks = db.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number").all(spec.id) as any[];
|
|
213
|
-
const decisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
214
|
-
const artifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
215
|
-
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(spec.id) as any;
|
|
216
|
-
const knowledge = db.query("SELECT * FROM knowledge WHERE spec_id = ?").all(spec.id) as any[];
|
|
217
|
-
|
|
218
|
-
// Criar registro de review como skipped
|
|
219
|
-
db.run(
|
|
220
|
-
`INSERT INTO review (spec_id, planned_vs_done, deviations, status, created_at)
|
|
221
|
-
VALUES (?, ?, NULL, 'skipped', ?)`,
|
|
222
|
-
[spec.id, JSON.stringify({ skipped: true, reason: "User chose to skip review" }), now]
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
// Atualizar spec para completed
|
|
226
|
-
db.run("UPDATE specs SET phase = 'completed', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
227
|
-
|
|
228
|
-
// Criar snapshot final
|
|
229
|
-
const review = db.query("SELECT * FROM review WHERE spec_id = ?").get(spec.id) as any;
|
|
230
|
-
const allData = {
|
|
231
|
-
spec,
|
|
232
|
-
context,
|
|
233
|
-
tasks,
|
|
234
|
-
decisions,
|
|
235
|
-
artifacts,
|
|
236
|
-
review,
|
|
237
|
-
knowledge,
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
db.run("INSERT INTO snapshots (spec_id, data, trigger, created_at) VALUES (?, ?, 'final', ?)", [
|
|
241
|
-
spec.id,
|
|
242
|
-
JSON.stringify(allData),
|
|
243
|
-
now,
|
|
244
|
-
]);
|
|
245
|
-
|
|
246
|
-
console.log(`\n${"=".repeat(60)}`);
|
|
247
|
-
console.log(`FEATURE FINALIZADA (Review Pulado)`);
|
|
248
|
-
console.log(`${"=".repeat(60)}`);
|
|
249
|
-
console.log(`\n${spec.name}`);
|
|
250
|
-
console.log(`\nResumo:`);
|
|
251
|
-
console.log(` Tasks: ${tasks.length}`);
|
|
252
|
-
console.log(` Artefatos: ${artifacts.length}`);
|
|
253
|
-
console.log(` Decisoes: ${decisions.length}`);
|
|
254
|
-
console.log(`\n⚠️ Review foi pulado pelo usuario.`);
|
|
255
|
-
console.log(`\nSpec ID: ${spec.id}`);
|
|
256
|
-
console.log(`Snapshot final criado.\n`);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Mostra relatorio completo do review
|
|
261
|
-
*/
|
|
262
|
-
function showReviewReport(
|
|
263
|
-
spec: any,
|
|
264
|
-
tasks: any[],
|
|
265
|
-
artifacts: any[],
|
|
266
|
-
decisions: any[],
|
|
267
|
-
knowledge: any[],
|
|
268
|
-
review: any
|
|
269
|
-
): void {
|
|
270
|
-
const reviewData = review.planned_vs_done ? JSON.parse(review.planned_vs_done) : {};
|
|
271
|
-
const deviations = review.deviations ? JSON.parse(review.deviations) : [];
|
|
272
|
-
|
|
273
|
-
console.log(`\n${"═".repeat(60)}`);
|
|
274
|
-
console.log(` RELATORIO FINAL DE REVIEW`);
|
|
275
|
-
console.log(`${"═".repeat(60)}`);
|
|
276
|
-
|
|
277
|
-
console.log(`\n📦 FEATURE: ${spec.name}`);
|
|
278
|
-
console.log(` Status: ✅ COMPLETA E APROVADA`);
|
|
279
|
-
console.log(` ID: ${spec.id}`);
|
|
280
|
-
|
|
281
|
-
// Resumo de execucao
|
|
282
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
283
|
-
console.log(`📊 RESUMO DA EXECUCAO`);
|
|
284
|
-
console.log(`${"─".repeat(60)}`);
|
|
285
|
-
|
|
286
|
-
// Agrupar por agente
|
|
287
|
-
const tasksByAgent: Record<string, any[]> = {};
|
|
288
|
-
for (const task of tasks) {
|
|
289
|
-
const agent = task.agent || "geral";
|
|
290
|
-
if (!tasksByAgent[agent]) {
|
|
291
|
-
tasksByAgent[agent] = [];
|
|
292
|
-
}
|
|
293
|
-
tasksByAgent[agent].push(task);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
console.log(`\n Subagentes utilizados: ${Object.keys(tasksByAgent).length}`);
|
|
297
|
-
for (const [agent, agentTasks] of Object.entries(tasksByAgent)) {
|
|
298
|
-
console.log(` • ${agent}: ${agentTasks.length} task(s)`);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
console.log(`\n Totais:`);
|
|
302
|
-
console.log(` • Tasks executadas: ${tasks.length}`);
|
|
303
|
-
console.log(` • Arquivos criados: ${artifacts.length}`);
|
|
304
|
-
console.log(` • Decisoes tomadas: ${decisions.length}`);
|
|
305
|
-
console.log(` • Knowledge items: ${knowledge.length}`);
|
|
306
|
-
|
|
307
|
-
// Tasks por agente com checkpoints
|
|
308
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
309
|
-
console.log(`📋 TRABALHO REALIZADO POR SUBAGENTE`);
|
|
310
|
-
console.log(`${"─".repeat(60)}`);
|
|
311
|
-
|
|
312
|
-
for (const [agent, agentTasks] of Object.entries(tasksByAgent)) {
|
|
313
|
-
console.log(`\n [${agent.toUpperCase()}]`);
|
|
314
|
-
for (const task of agentTasks) {
|
|
315
|
-
const status = task.status === "done" ? "✅" : "❌";
|
|
316
|
-
console.log(` ${status} #${task.number}: ${task.name}`);
|
|
317
|
-
if (task.checkpoint) {
|
|
318
|
-
// Truncar checkpoint se muito longo
|
|
319
|
-
const checkpoint = task.checkpoint.length > 80
|
|
320
|
-
? task.checkpoint.substring(0, 77) + "..."
|
|
321
|
-
: task.checkpoint;
|
|
322
|
-
console.log(` └─ ${checkpoint}`);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Artefatos criados
|
|
328
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
329
|
-
console.log(`📁 ARTEFATOS CRIADOS`);
|
|
330
|
-
console.log(`${"─".repeat(60)}`);
|
|
331
|
-
|
|
332
|
-
for (const artifact of artifacts) {
|
|
333
|
-
const task = tasks.find((t) => t.number === artifact.task_ref);
|
|
334
|
-
const agentInfo = task?.agent ? ` (${task.agent})` : "";
|
|
335
|
-
console.log(` • ${artifact.path}${agentInfo}`);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Decisoes tomadas
|
|
339
|
-
if (decisions.length > 0) {
|
|
340
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
341
|
-
console.log(`🎯 DECISOES ARQUITETADAS`);
|
|
342
|
-
console.log(`${"─".repeat(60)}`);
|
|
343
|
-
|
|
344
|
-
for (const dec of decisions) {
|
|
345
|
-
const task = tasks.find((t) => t.number === dec.task_ref);
|
|
346
|
-
const agentInfo = task?.agent ? ` [${task.agent}]` : "";
|
|
347
|
-
console.log(`\n • ${dec.title}${agentInfo}`);
|
|
348
|
-
console.log(` Decisao: ${dec.decision}`);
|
|
349
|
-
if (dec.rationale) {
|
|
350
|
-
console.log(` Motivo: ${dec.rationale}`);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Desvios encontrados
|
|
356
|
-
if (deviations.length > 0) {
|
|
357
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
358
|
-
console.log(`⚠️ DESVIOS DO PLANO ORIGINAL`);
|
|
359
|
-
console.log(`${"─".repeat(60)}`);
|
|
360
|
-
|
|
361
|
-
for (const dev of deviations) {
|
|
362
|
-
console.log(` • ${dev}`);
|
|
363
|
-
}
|
|
364
|
-
} else {
|
|
365
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
366
|
-
console.log(`✅ CONFORMIDADE COM O PLANO`);
|
|
367
|
-
console.log(`${"─".repeat(60)}`);
|
|
368
|
-
console.log(` Nenhum desvio encontrado. Implementacao seguiu o plano.`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// v8.3: Design arquitetural original
|
|
372
|
-
const reviewArch = reviewData.architectural_analysis;
|
|
373
|
-
if (reviewArch) {
|
|
374
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
375
|
-
console.log(`DESIGN ARQUITETURAL ORIGINAL`);
|
|
376
|
-
console.log(`${"─".repeat(60)}`);
|
|
377
|
-
|
|
378
|
-
console.log(`\n Analise: ${reviewArch.name} (${reviewArch.id})`);
|
|
379
|
-
|
|
380
|
-
if (reviewArch.approach) {
|
|
381
|
-
const approachPreview = reviewArch.approach.length > 200
|
|
382
|
-
? reviewArch.approach.substring(0, 200) + "..."
|
|
383
|
-
: reviewArch.approach;
|
|
384
|
-
console.log(` Abordagem: ${approachPreview}`);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (reviewArch.risks && reviewArch.risks.length > 0) {
|
|
388
|
-
console.log(`\n Riscos identificados (${reviewArch.risks.length}):`);
|
|
389
|
-
for (const risk of reviewArch.risks) {
|
|
390
|
-
console.log(` - [${risk.probability}/${risk.impact}] ${risk.description}`);
|
|
391
|
-
console.log(` Mitigacao: ${risk.mitigation}`);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (reviewArch.decisions && reviewArch.decisions.length > 0) {
|
|
396
|
-
console.log(`\n Decisoes arquiteturais (${reviewArch.decisions.length}):`);
|
|
397
|
-
for (const d of reviewArch.decisions) {
|
|
398
|
-
console.log(` - ${d.decision}: ${d.rationale || ''}`);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (reviewArch.diagrams && reviewArch.diagrams.length > 0) {
|
|
403
|
-
console.log(`\n Diagramas (${reviewArch.diagrams.length}):`);
|
|
404
|
-
for (const d of reviewArch.diagrams) {
|
|
405
|
-
console.log(` - ${d.name || d.type || 'Diagrama'} (${d.type || 'mermaid'})`);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// v8.3: Gate bypasses (auditoria)
|
|
411
|
-
const bypasses = reviewData.gate_bypasses || [];
|
|
412
|
-
if (bypasses.length > 0) {
|
|
413
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
414
|
-
console.log(`[!] GATE BYPASSES (${bypasses.length})`);
|
|
415
|
-
console.log(`${"─".repeat(60)}`);
|
|
416
|
-
|
|
417
|
-
for (const bypass of bypasses) {
|
|
418
|
-
console.log(` - Gate "${bypass.gate_name}" (Task #${bypass.task_id})`);
|
|
419
|
-
console.log(` Motivo: ${bypass.reason}`);
|
|
420
|
-
console.log(` Data: ${bypass.created_at}`);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// v8.5: Utilities criadas (DRY audit)
|
|
425
|
-
const utilitiesCreated = reviewData.utilities_created || [];
|
|
426
|
-
if (utilitiesCreated.length > 0) {
|
|
427
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
428
|
-
console.log(`UTILITIES CRIADAS (${utilitiesCreated.length})`);
|
|
429
|
-
console.log(`${"─".repeat(60)}`);
|
|
430
|
-
for (const u of utilitiesCreated) {
|
|
431
|
-
console.log(` - ${u.utility_name} [${u.utility_type}] <- ${u.file_path}`);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Alertar sobre DRY bypasses
|
|
435
|
-
const dryBypasses = (reviewData.gate_bypasses || []).filter((b: any) => b.gate_name === "dry-check");
|
|
436
|
-
if (dryBypasses.length > 0) {
|
|
437
|
-
console.log(`\n [!] ${dryBypasses.length} bypass(es) de DRY gate:`);
|
|
438
|
-
for (const b of dryBypasses) {
|
|
439
|
-
console.log(` Task #${b.task_id}: ${b.reason}`);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// Knowledge descoberto
|
|
445
|
-
const discoveries = knowledge.filter((k) => k.category === "discovery" || k.category === "pattern");
|
|
446
|
-
if (discoveries.length > 0) {
|
|
447
|
-
console.log(`\n${"─".repeat(60)}`);
|
|
448
|
-
console.log(`💡 DESCOBERTAS E PADROES`);
|
|
449
|
-
console.log(`${"─".repeat(60)}`);
|
|
450
|
-
|
|
451
|
-
for (const item of discoveries) {
|
|
452
|
-
const icon = item.severity === "critical" ? "🚨" : item.severity === "warning" ? "⚠️" : "ℹ️";
|
|
453
|
-
console.log(` ${icon} ${item.content}`);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Finalização
|
|
458
|
-
console.log(`\n${"═".repeat(60)}`);
|
|
459
|
-
console.log(` FEATURE CONCLUIDA COM SUCESSO!`);
|
|
460
|
-
console.log(`${"═".repeat(60)}`);
|
|
461
|
-
console.log(`\n Snapshot final criado para recuperacao futura.`);
|
|
462
|
-
console.log(` Use 'recover --list' para ver snapshots disponiveis.\n`);
|
|
463
|
-
}
|
|
1
|
+
import { getDb } from "../db/connection";
|
|
2
|
+
import { initSchema, getArchitecturalAnalysisForSpec } from "../db/schema";
|
|
3
|
+
import { enforceGate } from "../gates/validator";
|
|
4
|
+
|
|
5
|
+
export function reviewStart(json: boolean = false): void {
|
|
6
|
+
initSchema();
|
|
7
|
+
enforceGate("review-start");
|
|
8
|
+
|
|
9
|
+
const db = getDb();
|
|
10
|
+
const now = new Date().toISOString();
|
|
11
|
+
|
|
12
|
+
const spec = db
|
|
13
|
+
.query("SELECT * FROM specs WHERE phase = 'implementing' ORDER BY created_at DESC LIMIT 1")
|
|
14
|
+
.get() as any;
|
|
15
|
+
|
|
16
|
+
const tasks = db
|
|
17
|
+
.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number")
|
|
18
|
+
.all(spec.id) as any[];
|
|
19
|
+
|
|
20
|
+
const artifacts = db
|
|
21
|
+
.query("SELECT * FROM artifacts WHERE spec_id = ?")
|
|
22
|
+
.all(spec.id) as any[];
|
|
23
|
+
|
|
24
|
+
const decisions = db
|
|
25
|
+
.query("SELECT * FROM decisions WHERE spec_id = ? AND status = 'active'")
|
|
26
|
+
.all(spec.id) as any[];
|
|
27
|
+
|
|
28
|
+
// v8.4: Buscar analise arquitetural (link explicito via analysis_id ou nome)
|
|
29
|
+
const archAnalysis = getArchitecturalAnalysisForSpec(spec.name, spec.id);
|
|
30
|
+
const gateBypasses = db.query(
|
|
31
|
+
"SELECT * FROM gate_bypasses WHERE spec_id = ? ORDER BY created_at"
|
|
32
|
+
).all(spec.id) as any[];
|
|
33
|
+
|
|
34
|
+
// Analisar plano vs implementado
|
|
35
|
+
const plannedFiles = tasks.flatMap((t) => (t.files ? JSON.parse(t.files) : []));
|
|
36
|
+
const createdFiles = artifacts.map((a) => a.path);
|
|
37
|
+
|
|
38
|
+
const missingFiles = plannedFiles.filter((f: string) => !createdFiles.includes(f));
|
|
39
|
+
const extraFiles = createdFiles.filter((f) => !plannedFiles.includes(f));
|
|
40
|
+
|
|
41
|
+
const deviations: string[] = [];
|
|
42
|
+
if (missingFiles.length > 0) {
|
|
43
|
+
deviations.push(`Arquivos planejados nao criados: ${missingFiles.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
if (extraFiles.length > 0) {
|
|
46
|
+
deviations.push(`Arquivos extras criados: ${extraFiles.join(", ")}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Criar registro de review
|
|
50
|
+
const reviewData = {
|
|
51
|
+
tasks_completed: tasks.length,
|
|
52
|
+
artifacts_created: artifacts.length,
|
|
53
|
+
decisions_made: decisions.length,
|
|
54
|
+
planned_files: plannedFiles,
|
|
55
|
+
created_files: createdFiles,
|
|
56
|
+
// v8.3: Contexto arquitetural e auditoria
|
|
57
|
+
architectural_analysis: archAnalysis ? {
|
|
58
|
+
id: archAnalysis.id,
|
|
59
|
+
name: archAnalysis.name,
|
|
60
|
+
approach: archAnalysis.approach,
|
|
61
|
+
risks: archAnalysis.risks ? JSON.parse(archAnalysis.risks) : [],
|
|
62
|
+
diagrams: archAnalysis.diagrams ? JSON.parse(archAnalysis.diagrams) : [],
|
|
63
|
+
decisions: archAnalysis.decisions ? JSON.parse(archAnalysis.decisions) : [],
|
|
64
|
+
} : null,
|
|
65
|
+
gate_bypasses: gateBypasses,
|
|
66
|
+
// v8.5: Utilities criadas nesta feature (DRY audit)
|
|
67
|
+
utilities_created: (() => {
|
|
68
|
+
try {
|
|
69
|
+
return db.query(
|
|
70
|
+
"SELECT * FROM project_utilities WHERE spec_id = ? ORDER BY file_path"
|
|
71
|
+
).all(spec.id) as any[];
|
|
72
|
+
} catch { return []; }
|
|
73
|
+
})(),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
db.run(
|
|
77
|
+
`INSERT INTO review (spec_id, planned_vs_done, deviations, status, created_at)
|
|
78
|
+
VALUES (?, ?, ?, 'pending', ?)`,
|
|
79
|
+
[
|
|
80
|
+
spec.id,
|
|
81
|
+
JSON.stringify(reviewData),
|
|
82
|
+
deviations.length > 0 ? JSON.stringify(deviations) : null,
|
|
83
|
+
now,
|
|
84
|
+
]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// Atualizar fase
|
|
88
|
+
db.run("UPDATE specs SET phase = 'reviewing', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
89
|
+
|
|
90
|
+
if (json) {
|
|
91
|
+
console.log(JSON.stringify({ spec, reviewData, deviations }));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
96
|
+
console.log(`REVIEW: ${spec.name}`);
|
|
97
|
+
console.log(`${"=".repeat(60)}`);
|
|
98
|
+
|
|
99
|
+
console.log(`\nResumo da implementacao:`);
|
|
100
|
+
console.log(` Tasks concluidas: ${tasks.length}`);
|
|
101
|
+
console.log(` Artefatos criados: ${artifacts.length}`);
|
|
102
|
+
console.log(` Decisoes tomadas: ${decisions.length}`);
|
|
103
|
+
|
|
104
|
+
console.log(`\nArquivos criados:`);
|
|
105
|
+
for (const artifact of artifacts) {
|
|
106
|
+
console.log(` - ${artifact.path}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (decisions.length > 0) {
|
|
110
|
+
console.log(`\nDecisoes:`);
|
|
111
|
+
for (const dec of decisions) {
|
|
112
|
+
console.log(` ${dec.id}: ${dec.title}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (deviations.length > 0) {
|
|
117
|
+
console.log(`\nDesvios encontrados:`);
|
|
118
|
+
for (const dev of deviations) {
|
|
119
|
+
console.log(` - ${dev}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(`\nResolva os desvios antes de aprovar.`);
|
|
122
|
+
} else {
|
|
123
|
+
console.log(`\nNenhum desvio encontrado.`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(`\nPara aprovar: review approve`);
|
|
127
|
+
console.log(`Para ver status: status\n`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function reviewApprove(): void {
|
|
131
|
+
initSchema();
|
|
132
|
+
enforceGate("review-approve");
|
|
133
|
+
|
|
134
|
+
const db = getDb();
|
|
135
|
+
const now = new Date().toISOString();
|
|
136
|
+
|
|
137
|
+
const spec = db
|
|
138
|
+
.query("SELECT * FROM specs WHERE phase = 'reviewing' ORDER BY created_at DESC LIMIT 1")
|
|
139
|
+
.get() as any;
|
|
140
|
+
|
|
141
|
+
if (!spec) {
|
|
142
|
+
console.error("\nNenhum review em andamento.\n");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Atualizar review
|
|
147
|
+
db.run("UPDATE review SET status = 'passed' WHERE spec_id = ?", [spec.id]);
|
|
148
|
+
|
|
149
|
+
// Atualizar spec para completed
|
|
150
|
+
db.run("UPDATE specs SET phase = 'completed', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
151
|
+
|
|
152
|
+
// Buscar todos os dados para snapshot e relatorio
|
|
153
|
+
const tasks = db.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number").all(spec.id) as any[];
|
|
154
|
+
const decisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
155
|
+
const artifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
156
|
+
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(spec.id) as any;
|
|
157
|
+
const review = db.query("SELECT * FROM review WHERE spec_id = ?").get(spec.id) as any;
|
|
158
|
+
const knowledge = db.query("SELECT * FROM knowledge WHERE spec_id = ?").all(spec.id) as any[];
|
|
159
|
+
|
|
160
|
+
// Criar snapshot final
|
|
161
|
+
const allData = {
|
|
162
|
+
spec,
|
|
163
|
+
context,
|
|
164
|
+
tasks,
|
|
165
|
+
decisions,
|
|
166
|
+
artifacts,
|
|
167
|
+
review,
|
|
168
|
+
knowledge,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
db.run("INSERT INTO snapshots (spec_id, data, trigger, created_at) VALUES (?, ?, 'final', ?)", [
|
|
172
|
+
spec.id,
|
|
173
|
+
JSON.stringify(allData),
|
|
174
|
+
now,
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
// Mostrar relatorio final completo
|
|
178
|
+
showReviewReport(spec, tasks, artifacts, decisions, knowledge, review);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Pula o review e finaliza a feature diretamente
|
|
183
|
+
*/
|
|
184
|
+
export function reviewSkip(): void {
|
|
185
|
+
initSchema();
|
|
186
|
+
|
|
187
|
+
const db = getDb();
|
|
188
|
+
const now = new Date().toISOString();
|
|
189
|
+
|
|
190
|
+
// Buscar spec em implementacao com todas tasks concluidas
|
|
191
|
+
const spec = db
|
|
192
|
+
.query("SELECT * FROM specs WHERE phase = 'implementing' ORDER BY created_at DESC LIMIT 1")
|
|
193
|
+
.get() as any;
|
|
194
|
+
|
|
195
|
+
if (!spec) {
|
|
196
|
+
console.error("\nNenhuma feature em fase de implementacao.\n");
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Verificar se todas tasks estao done
|
|
201
|
+
const pending = db
|
|
202
|
+
.query("SELECT COUNT(*) as c FROM tasks WHERE spec_id = ? AND status != 'done'")
|
|
203
|
+
.get(spec.id) as any;
|
|
204
|
+
|
|
205
|
+
if (pending.c > 0) {
|
|
206
|
+
console.error(`\nAinda existem ${pending.c} tasks pendentes.`);
|
|
207
|
+
console.error("Complete todas as tasks antes de pular o review.\n");
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Buscar dados
|
|
212
|
+
const tasks = db.query("SELECT * FROM tasks WHERE spec_id = ? ORDER BY number").all(spec.id) as any[];
|
|
213
|
+
const decisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
214
|
+
const artifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
215
|
+
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(spec.id) as any;
|
|
216
|
+
const knowledge = db.query("SELECT * FROM knowledge WHERE spec_id = ?").all(spec.id) as any[];
|
|
217
|
+
|
|
218
|
+
// Criar registro de review como skipped
|
|
219
|
+
db.run(
|
|
220
|
+
`INSERT INTO review (spec_id, planned_vs_done, deviations, status, created_at)
|
|
221
|
+
VALUES (?, ?, NULL, 'skipped', ?)`,
|
|
222
|
+
[spec.id, JSON.stringify({ skipped: true, reason: "User chose to skip review" }), now]
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
// Atualizar spec para completed
|
|
226
|
+
db.run("UPDATE specs SET phase = 'completed', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
227
|
+
|
|
228
|
+
// Criar snapshot final
|
|
229
|
+
const review = db.query("SELECT * FROM review WHERE spec_id = ?").get(spec.id) as any;
|
|
230
|
+
const allData = {
|
|
231
|
+
spec,
|
|
232
|
+
context,
|
|
233
|
+
tasks,
|
|
234
|
+
decisions,
|
|
235
|
+
artifacts,
|
|
236
|
+
review,
|
|
237
|
+
knowledge,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
db.run("INSERT INTO snapshots (spec_id, data, trigger, created_at) VALUES (?, ?, 'final', ?)", [
|
|
241
|
+
spec.id,
|
|
242
|
+
JSON.stringify(allData),
|
|
243
|
+
now,
|
|
244
|
+
]);
|
|
245
|
+
|
|
246
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
247
|
+
console.log(`FEATURE FINALIZADA (Review Pulado)`);
|
|
248
|
+
console.log(`${"=".repeat(60)}`);
|
|
249
|
+
console.log(`\n${spec.name}`);
|
|
250
|
+
console.log(`\nResumo:`);
|
|
251
|
+
console.log(` Tasks: ${tasks.length}`);
|
|
252
|
+
console.log(` Artefatos: ${artifacts.length}`);
|
|
253
|
+
console.log(` Decisoes: ${decisions.length}`);
|
|
254
|
+
console.log(`\n⚠️ Review foi pulado pelo usuario.`);
|
|
255
|
+
console.log(`\nSpec ID: ${spec.id}`);
|
|
256
|
+
console.log(`Snapshot final criado.\n`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Mostra relatorio completo do review
|
|
261
|
+
*/
|
|
262
|
+
function showReviewReport(
|
|
263
|
+
spec: any,
|
|
264
|
+
tasks: any[],
|
|
265
|
+
artifacts: any[],
|
|
266
|
+
decisions: any[],
|
|
267
|
+
knowledge: any[],
|
|
268
|
+
review: any
|
|
269
|
+
): void {
|
|
270
|
+
const reviewData = review.planned_vs_done ? JSON.parse(review.planned_vs_done) : {};
|
|
271
|
+
const deviations = review.deviations ? JSON.parse(review.deviations) : [];
|
|
272
|
+
|
|
273
|
+
console.log(`\n${"═".repeat(60)}`);
|
|
274
|
+
console.log(` RELATORIO FINAL DE REVIEW`);
|
|
275
|
+
console.log(`${"═".repeat(60)}`);
|
|
276
|
+
|
|
277
|
+
console.log(`\n📦 FEATURE: ${spec.name}`);
|
|
278
|
+
console.log(` Status: ✅ COMPLETA E APROVADA`);
|
|
279
|
+
console.log(` ID: ${spec.id}`);
|
|
280
|
+
|
|
281
|
+
// Resumo de execucao
|
|
282
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
283
|
+
console.log(`📊 RESUMO DA EXECUCAO`);
|
|
284
|
+
console.log(`${"─".repeat(60)}`);
|
|
285
|
+
|
|
286
|
+
// Agrupar por agente
|
|
287
|
+
const tasksByAgent: Record<string, any[]> = {};
|
|
288
|
+
for (const task of tasks) {
|
|
289
|
+
const agent = task.agent || "geral";
|
|
290
|
+
if (!tasksByAgent[agent]) {
|
|
291
|
+
tasksByAgent[agent] = [];
|
|
292
|
+
}
|
|
293
|
+
tasksByAgent[agent].push(task);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(`\n Subagentes utilizados: ${Object.keys(tasksByAgent).length}`);
|
|
297
|
+
for (const [agent, agentTasks] of Object.entries(tasksByAgent)) {
|
|
298
|
+
console.log(` • ${agent}: ${agentTasks.length} task(s)`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
console.log(`\n Totais:`);
|
|
302
|
+
console.log(` • Tasks executadas: ${tasks.length}`);
|
|
303
|
+
console.log(` • Arquivos criados: ${artifacts.length}`);
|
|
304
|
+
console.log(` • Decisoes tomadas: ${decisions.length}`);
|
|
305
|
+
console.log(` • Knowledge items: ${knowledge.length}`);
|
|
306
|
+
|
|
307
|
+
// Tasks por agente com checkpoints
|
|
308
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
309
|
+
console.log(`📋 TRABALHO REALIZADO POR SUBAGENTE`);
|
|
310
|
+
console.log(`${"─".repeat(60)}`);
|
|
311
|
+
|
|
312
|
+
for (const [agent, agentTasks] of Object.entries(tasksByAgent)) {
|
|
313
|
+
console.log(`\n [${agent.toUpperCase()}]`);
|
|
314
|
+
for (const task of agentTasks) {
|
|
315
|
+
const status = task.status === "done" ? "✅" : "❌";
|
|
316
|
+
console.log(` ${status} #${task.number}: ${task.name}`);
|
|
317
|
+
if (task.checkpoint) {
|
|
318
|
+
// Truncar checkpoint se muito longo
|
|
319
|
+
const checkpoint = task.checkpoint.length > 80
|
|
320
|
+
? task.checkpoint.substring(0, 77) + "..."
|
|
321
|
+
: task.checkpoint;
|
|
322
|
+
console.log(` └─ ${checkpoint}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Artefatos criados
|
|
328
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
329
|
+
console.log(`📁 ARTEFATOS CRIADOS`);
|
|
330
|
+
console.log(`${"─".repeat(60)}`);
|
|
331
|
+
|
|
332
|
+
for (const artifact of artifacts) {
|
|
333
|
+
const task = tasks.find((t) => t.number === artifact.task_ref);
|
|
334
|
+
const agentInfo = task?.agent ? ` (${task.agent})` : "";
|
|
335
|
+
console.log(` • ${artifact.path}${agentInfo}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Decisoes tomadas
|
|
339
|
+
if (decisions.length > 0) {
|
|
340
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
341
|
+
console.log(`🎯 DECISOES ARQUITETADAS`);
|
|
342
|
+
console.log(`${"─".repeat(60)}`);
|
|
343
|
+
|
|
344
|
+
for (const dec of decisions) {
|
|
345
|
+
const task = tasks.find((t) => t.number === dec.task_ref);
|
|
346
|
+
const agentInfo = task?.agent ? ` [${task.agent}]` : "";
|
|
347
|
+
console.log(`\n • ${dec.title}${agentInfo}`);
|
|
348
|
+
console.log(` Decisao: ${dec.decision}`);
|
|
349
|
+
if (dec.rationale) {
|
|
350
|
+
console.log(` Motivo: ${dec.rationale}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Desvios encontrados
|
|
356
|
+
if (deviations.length > 0) {
|
|
357
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
358
|
+
console.log(`⚠️ DESVIOS DO PLANO ORIGINAL`);
|
|
359
|
+
console.log(`${"─".repeat(60)}`);
|
|
360
|
+
|
|
361
|
+
for (const dev of deviations) {
|
|
362
|
+
console.log(` • ${dev}`);
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
366
|
+
console.log(`✅ CONFORMIDADE COM O PLANO`);
|
|
367
|
+
console.log(`${"─".repeat(60)}`);
|
|
368
|
+
console.log(` Nenhum desvio encontrado. Implementacao seguiu o plano.`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// v8.3: Design arquitetural original
|
|
372
|
+
const reviewArch = reviewData.architectural_analysis;
|
|
373
|
+
if (reviewArch) {
|
|
374
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
375
|
+
console.log(`DESIGN ARQUITETURAL ORIGINAL`);
|
|
376
|
+
console.log(`${"─".repeat(60)}`);
|
|
377
|
+
|
|
378
|
+
console.log(`\n Analise: ${reviewArch.name} (${reviewArch.id})`);
|
|
379
|
+
|
|
380
|
+
if (reviewArch.approach) {
|
|
381
|
+
const approachPreview = reviewArch.approach.length > 200
|
|
382
|
+
? reviewArch.approach.substring(0, 200) + "..."
|
|
383
|
+
: reviewArch.approach;
|
|
384
|
+
console.log(` Abordagem: ${approachPreview}`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (reviewArch.risks && reviewArch.risks.length > 0) {
|
|
388
|
+
console.log(`\n Riscos identificados (${reviewArch.risks.length}):`);
|
|
389
|
+
for (const risk of reviewArch.risks) {
|
|
390
|
+
console.log(` - [${risk.probability}/${risk.impact}] ${risk.description}`);
|
|
391
|
+
console.log(` Mitigacao: ${risk.mitigation}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (reviewArch.decisions && reviewArch.decisions.length > 0) {
|
|
396
|
+
console.log(`\n Decisoes arquiteturais (${reviewArch.decisions.length}):`);
|
|
397
|
+
for (const d of reviewArch.decisions) {
|
|
398
|
+
console.log(` - ${d.decision}: ${d.rationale || ''}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (reviewArch.diagrams && reviewArch.diagrams.length > 0) {
|
|
403
|
+
console.log(`\n Diagramas (${reviewArch.diagrams.length}):`);
|
|
404
|
+
for (const d of reviewArch.diagrams) {
|
|
405
|
+
console.log(` - ${d.name || d.type || 'Diagrama'} (${d.type || 'mermaid'})`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// v8.3: Gate bypasses (auditoria)
|
|
411
|
+
const bypasses = reviewData.gate_bypasses || [];
|
|
412
|
+
if (bypasses.length > 0) {
|
|
413
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
414
|
+
console.log(`[!] GATE BYPASSES (${bypasses.length})`);
|
|
415
|
+
console.log(`${"─".repeat(60)}`);
|
|
416
|
+
|
|
417
|
+
for (const bypass of bypasses) {
|
|
418
|
+
console.log(` - Gate "${bypass.gate_name}" (Task #${bypass.task_id})`);
|
|
419
|
+
console.log(` Motivo: ${bypass.reason}`);
|
|
420
|
+
console.log(` Data: ${bypass.created_at}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// v8.5: Utilities criadas (DRY audit)
|
|
425
|
+
const utilitiesCreated = reviewData.utilities_created || [];
|
|
426
|
+
if (utilitiesCreated.length > 0) {
|
|
427
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
428
|
+
console.log(`UTILITIES CRIADAS (${utilitiesCreated.length})`);
|
|
429
|
+
console.log(`${"─".repeat(60)}`);
|
|
430
|
+
for (const u of utilitiesCreated) {
|
|
431
|
+
console.log(` - ${u.utility_name} [${u.utility_type}] <- ${u.file_path}`);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Alertar sobre DRY bypasses
|
|
435
|
+
const dryBypasses = (reviewData.gate_bypasses || []).filter((b: any) => b.gate_name === "dry-check");
|
|
436
|
+
if (dryBypasses.length > 0) {
|
|
437
|
+
console.log(`\n [!] ${dryBypasses.length} bypass(es) de DRY gate:`);
|
|
438
|
+
for (const b of dryBypasses) {
|
|
439
|
+
console.log(` Task #${b.task_id}: ${b.reason}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Knowledge descoberto
|
|
445
|
+
const discoveries = knowledge.filter((k) => k.category === "discovery" || k.category === "pattern");
|
|
446
|
+
if (discoveries.length > 0) {
|
|
447
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
448
|
+
console.log(`💡 DESCOBERTAS E PADROES`);
|
|
449
|
+
console.log(`${"─".repeat(60)}`);
|
|
450
|
+
|
|
451
|
+
for (const item of discoveries) {
|
|
452
|
+
const icon = item.severity === "critical" ? "🚨" : item.severity === "warning" ? "⚠️" : "ℹ️";
|
|
453
|
+
console.log(` ${icon} ${item.content}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Finalização
|
|
458
|
+
console.log(`\n${"═".repeat(60)}`);
|
|
459
|
+
console.log(` FEATURE CONCLUIDA COM SUCESSO!`);
|
|
460
|
+
console.log(`${"═".repeat(60)}`);
|
|
461
|
+
console.log(`\n Snapshot final criado para recuperacao futura.`);
|
|
462
|
+
console.log(` Use 'recover --list' para ver snapshots disponiveis.\n`);
|
|
463
|
+
}
|