@codexa/cli 8.5.0 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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
+ }