@codexa/cli 9.0.30 → 9.0.32
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 +52 -87
- package/commands/check.ts +22 -23
- package/commands/clear.ts +42 -48
- package/commands/decide.ts +49 -47
- package/commands/discover.ts +81 -94
- package/commands/integration.test.ts +262 -313
- package/commands/knowledge.test.ts +56 -61
- package/commands/knowledge.ts +126 -131
- package/commands/patterns.ts +28 -43
- package/commands/plan.ts +50 -48
- package/commands/product.ts +57 -59
- package/commands/research.ts +64 -77
- package/commands/review.ts +100 -86
- package/commands/simplify.ts +24 -35
- package/commands/spec-resolver.test.ts +52 -48
- package/commands/spec-resolver.ts +21 -23
- package/commands/standards.ts +20 -27
- package/commands/sync.ts +2 -8
- package/commands/task.ts +106 -97
- package/commands/team.test.ts +22 -83
- package/commands/team.ts +62 -50
- package/commands/utils.ts +83 -81
- package/context/assembly.ts +0 -1
- package/context/generator.ts +66 -79
- package/context/sections.ts +8 -14
- package/db/connection.ts +195 -19
- package/db/schema.test.ts +304 -298
- package/db/schema.ts +302 -392
- package/db/test-helpers.ts +18 -29
- package/gates/standards-validator.test.ts +83 -86
- package/gates/standards-validator.ts +9 -41
- package/gates/validator.test.ts +13 -22
- package/gates/validator.ts +69 -107
- package/package.json +2 -1
- package/protocol/process-return.ts +41 -57
- package/simplify/prompt-builder.test.ts +44 -42
- package/simplify/prompt-builder.ts +12 -14
- package/workflow.ts +159 -174
package/commands/architect.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dbGet, dbAll, dbRun } from "../db/connection";
|
|
2
2
|
import { initSchema } from "../db/schema";
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
4
4
|
import { CodexaError } from "../errors";
|
|
@@ -48,34 +48,26 @@ interface ArchitecturalAnalysis {
|
|
|
48
48
|
description: string;
|
|
49
49
|
status: "pending" | "approved" | "implemented" | "rejected";
|
|
50
50
|
|
|
51
|
-
// Contexto
|
|
52
51
|
context: string;
|
|
53
52
|
currentArchitecture: string;
|
|
54
53
|
|
|
55
|
-
// Solucao
|
|
56
54
|
approach: string;
|
|
57
55
|
chosenAlternative: string;
|
|
58
56
|
|
|
59
|
-
// Diagramas (Mermaid)
|
|
60
57
|
diagrams: {
|
|
61
58
|
name: string;
|
|
62
59
|
type: string;
|
|
63
60
|
content: string;
|
|
64
61
|
}[];
|
|
65
62
|
|
|
66
|
-
// Baby Steps
|
|
67
63
|
babySteps: BabyStep[];
|
|
68
64
|
|
|
69
|
-
// Riscos
|
|
70
65
|
risks: Risk[];
|
|
71
66
|
|
|
72
|
-
// Alternativas
|
|
73
67
|
alternatives: Alternative[];
|
|
74
68
|
|
|
75
|
-
// Decisoes
|
|
76
69
|
decisions: ArchitecturalDecision[];
|
|
77
70
|
|
|
78
|
-
// Metadados
|
|
79
71
|
filePath?: string;
|
|
80
72
|
createdAt: string;
|
|
81
73
|
updatedAt?: string;
|
|
@@ -145,7 +137,6 @@ const HEADER_ALIASES: Record<string, string[]> = {
|
|
|
145
137
|
export function extractSection(content: string, header: string): string {
|
|
146
138
|
const sections = content.split(/^## /m);
|
|
147
139
|
|
|
148
|
-
// Tier 1: Exact startsWith (fast path)
|
|
149
140
|
for (const section of sections) {
|
|
150
141
|
if (section.startsWith(header)) {
|
|
151
142
|
const lines = section.split("\n");
|
|
@@ -153,7 +144,6 @@ export function extractSection(content: string, header: string): string {
|
|
|
153
144
|
}
|
|
154
145
|
}
|
|
155
146
|
|
|
156
|
-
// Tier 2: Case-insensitive startsWith
|
|
157
147
|
const headerLower = header.toLowerCase();
|
|
158
148
|
for (const section of sections) {
|
|
159
149
|
if (section.toLowerCase().startsWith(headerLower)) {
|
|
@@ -162,7 +152,6 @@ export function extractSection(content: string, header: string): string {
|
|
|
162
152
|
}
|
|
163
153
|
}
|
|
164
154
|
|
|
165
|
-
// Tier 3: Alias-based includes matching (case-insensitive)
|
|
166
155
|
const aliases = HEADER_ALIASES[header] || [];
|
|
167
156
|
for (const section of sections) {
|
|
168
157
|
const sectionHeader = section.split("\n")[0]?.toLowerCase().trim() || "";
|
|
@@ -182,7 +171,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
182
171
|
if (!section) return [];
|
|
183
172
|
const steps: BabyStep[] = [];
|
|
184
173
|
|
|
185
|
-
// Detect phase headers: "## Fase N:" or "## Phase N:"
|
|
186
174
|
let currentPhase = 1;
|
|
187
175
|
let hasExplicitPhases = false;
|
|
188
176
|
const phaseRegex = /^##\s+(?:Fase|Phase)\s+(\d+)/im;
|
|
@@ -190,8 +178,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
190
178
|
hasExplicitPhases = true;
|
|
191
179
|
}
|
|
192
180
|
|
|
193
|
-
// Split by phase headers first, then by step headers
|
|
194
|
-
// We process the section line-by-line to track phase context
|
|
195
181
|
const lines = section.split("\n");
|
|
196
182
|
let currentBlock = "";
|
|
197
183
|
let blockPhase = currentPhase;
|
|
@@ -199,7 +185,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
199
185
|
for (const line of lines) {
|
|
200
186
|
const phaseMatch = line.match(/^##\s+(?:Fase|Phase)\s+(\d+)/i);
|
|
201
187
|
if (phaseMatch) {
|
|
202
|
-
// Process pending block BEFORE changing phase
|
|
203
188
|
if (currentBlock.trim()) {
|
|
204
189
|
const step = parseStepBlock(currentBlock, hasExplicitPhases ? blockPhase : undefined);
|
|
205
190
|
if (step) steps.push(step);
|
|
@@ -210,7 +195,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
210
195
|
continue;
|
|
211
196
|
}
|
|
212
197
|
|
|
213
|
-
// When we hit a new step header, process the previous block
|
|
214
198
|
if (line.match(/^###\s+/) && currentBlock.trim()) {
|
|
215
199
|
const step = parseStepBlock(currentBlock, hasExplicitPhases ? blockPhase : undefined);
|
|
216
200
|
if (step) steps.push(step);
|
|
@@ -221,7 +205,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
221
205
|
}
|
|
222
206
|
}
|
|
223
207
|
|
|
224
|
-
// Process the last block
|
|
225
208
|
if (currentBlock.trim()) {
|
|
226
209
|
const step = parseStepBlock(currentBlock, hasExplicitPhases ? blockPhase : undefined);
|
|
227
210
|
if (step) steps.push(step);
|
|
@@ -231,7 +214,6 @@ export function parseBabySteps(section: string): BabyStep[] {
|
|
|
231
214
|
}
|
|
232
215
|
|
|
233
216
|
function parseStepBlock(block: string, phase?: number): BabyStep | null {
|
|
234
|
-
// Remove leading "### " prefix for matching
|
|
235
217
|
const content = block.replace(/^###\s+/, "");
|
|
236
218
|
const headerMatch = content.match(/^(?:Step\s+)?(\d+)[.:]\s*(.+)/);
|
|
237
219
|
if (!headerMatch) return null;
|
|
@@ -306,12 +288,10 @@ export function parseDecisionsTable(section: string): ArchitecturalDecision[] {
|
|
|
306
288
|
const lines = section.split("\n");
|
|
307
289
|
|
|
308
290
|
for (const line of lines) {
|
|
309
|
-
// Match table rows: | Decision | Rationale |
|
|
310
291
|
const rowMatch = line.match(/^\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|$/);
|
|
311
292
|
if (!rowMatch) continue;
|
|
312
293
|
const decision = rowMatch[1].trim();
|
|
313
294
|
const rationale = rowMatch[2].trim();
|
|
314
|
-
// Skip header and separator rows
|
|
315
295
|
if (decision === "Decisao" || decision.startsWith("---")) continue;
|
|
316
296
|
if (decision && rationale) {
|
|
317
297
|
decisions.push({ decision, rationale });
|
|
@@ -346,10 +326,6 @@ function parseAlternatives(section: string): Alternative[] {
|
|
|
346
326
|
return alternatives;
|
|
347
327
|
}
|
|
348
328
|
|
|
349
|
-
/**
|
|
350
|
-
* v8.4: Parseia um arquivo .md de analise arquitetural e extrai dados estruturados.
|
|
351
|
-
* O .md deve seguir o template padrao do codexa:architect.
|
|
352
|
-
*/
|
|
353
329
|
export function parseAnalysisMd(content: string): {
|
|
354
330
|
context: string;
|
|
355
331
|
currentArchitecture: string;
|
|
@@ -386,16 +362,15 @@ export function parseAnalysisMd(content: string): {
|
|
|
386
362
|
// COMMANDS
|
|
387
363
|
// ═══════════════════════════════════════════════════════════════
|
|
388
364
|
|
|
389
|
-
export function architectStart(description: string, options: { json?: boolean } = {}): void {
|
|
390
|
-
initSchema();
|
|
391
|
-
const db = getDb();
|
|
365
|
+
export async function architectStart(description: string, options: { json?: boolean } = {}): Promise<void> {
|
|
366
|
+
await initSchema();
|
|
392
367
|
const now = new Date().toISOString();
|
|
393
368
|
const id = generateId();
|
|
394
369
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
)
|
|
370
|
+
const pending = await dbGet<any>(
|
|
371
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
|
372
|
+
[]
|
|
373
|
+
);
|
|
399
374
|
|
|
400
375
|
if (pending) {
|
|
401
376
|
if (options.json) {
|
|
@@ -418,8 +393,7 @@ export function architectStart(description: string, options: { json?: boolean }
|
|
|
418
393
|
throw new CodexaError("Ja existe uma analise pendente. Use 'architect show' ou 'architect cancel'.");
|
|
419
394
|
}
|
|
420
395
|
|
|
421
|
-
|
|
422
|
-
db.run(
|
|
396
|
+
await dbRun(
|
|
423
397
|
`INSERT INTO architectural_analyses (id, name, description, status, created_at)
|
|
424
398
|
VALUES (?, ?, ?, 'pending', ?)`,
|
|
425
399
|
[id, description, description, now]
|
|
@@ -460,24 +434,24 @@ export function architectStart(description: string, options: { json?: boolean }
|
|
|
460
434
|
}
|
|
461
435
|
}
|
|
462
436
|
|
|
463
|
-
export function architectShow(options: { id?: string; json?: boolean } = {}): void {
|
|
464
|
-
initSchema();
|
|
465
|
-
const db = getDb();
|
|
437
|
+
export async function architectShow(options: { id?: string; json?: boolean } = {}): Promise<void> {
|
|
438
|
+
await initSchema();
|
|
466
439
|
|
|
467
440
|
let analysis: any;
|
|
468
441
|
|
|
469
442
|
if (options.id) {
|
|
470
|
-
analysis =
|
|
443
|
+
analysis = await dbGet<any>("SELECT * FROM architectural_analyses WHERE id = ?", [options.id]);
|
|
471
444
|
} else {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
)
|
|
445
|
+
analysis = await dbGet<any>(
|
|
446
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
|
447
|
+
[]
|
|
448
|
+
);
|
|
476
449
|
|
|
477
450
|
if (!analysis) {
|
|
478
|
-
analysis =
|
|
479
|
-
"SELECT * FROM architectural_analyses ORDER BY created_at DESC LIMIT 1"
|
|
480
|
-
|
|
451
|
+
analysis = await dbGet<any>(
|
|
452
|
+
"SELECT * FROM architectural_analyses ORDER BY created_at DESC LIMIT 1",
|
|
453
|
+
[]
|
|
454
|
+
);
|
|
481
455
|
}
|
|
482
456
|
}
|
|
483
457
|
|
|
@@ -491,7 +465,6 @@ export function architectShow(options: { id?: string; json?: boolean } = {}): vo
|
|
|
491
465
|
return;
|
|
492
466
|
}
|
|
493
467
|
|
|
494
|
-
// Parse JSON fields
|
|
495
468
|
const parsed: ArchitecturalAnalysis = {
|
|
496
469
|
id: analysis.id,
|
|
497
470
|
name: analysis.name,
|
|
@@ -557,9 +530,8 @@ export function architectShow(options: { id?: string; json?: boolean } = {}): vo
|
|
|
557
530
|
}
|
|
558
531
|
}
|
|
559
532
|
|
|
560
|
-
export function architectList(options: { json?: boolean; status?: string } = {}): void {
|
|
561
|
-
initSchema();
|
|
562
|
-
const db = getDb();
|
|
533
|
+
export async function architectList(options: { json?: boolean; status?: string } = {}): Promise<void> {
|
|
534
|
+
await initSchema();
|
|
563
535
|
|
|
564
536
|
let query = "SELECT id, name, status, created_at, file_path FROM architectural_analyses";
|
|
565
537
|
const params: any[] = [];
|
|
@@ -571,7 +543,7 @@ export function architectList(options: { json?: boolean; status?: string } = {})
|
|
|
571
543
|
|
|
572
544
|
query += " ORDER BY created_at DESC";
|
|
573
545
|
|
|
574
|
-
const analyses =
|
|
546
|
+
const analyses = await dbAll<any>(query, params);
|
|
575
547
|
|
|
576
548
|
if (options.json) {
|
|
577
549
|
console.log(JSON.stringify(analyses, null, 2));
|
|
@@ -601,15 +573,14 @@ export function architectList(options: { json?: boolean; status?: string } = {})
|
|
|
601
573
|
}
|
|
602
574
|
}
|
|
603
575
|
|
|
604
|
-
export function architectSave(options: { file?: string; json?: boolean }): void {
|
|
605
|
-
initSchema();
|
|
606
|
-
const db = getDb();
|
|
576
|
+
export async function architectSave(options: { file?: string; json?: boolean }): Promise<void> {
|
|
577
|
+
await initSchema();
|
|
607
578
|
const now = new Date().toISOString();
|
|
608
579
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
)
|
|
580
|
+
const analysis = await dbGet<any>(
|
|
581
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
|
582
|
+
[]
|
|
583
|
+
);
|
|
613
584
|
|
|
614
585
|
if (!analysis) {
|
|
615
586
|
if (options.json) {
|
|
@@ -620,17 +591,14 @@ export function architectSave(options: { file?: string; json?: boolean }): void
|
|
|
620
591
|
throw new CodexaError("Nenhuma analise pendente encontrada.");
|
|
621
592
|
}
|
|
622
593
|
|
|
623
|
-
// v8.4: Resolver caminho do arquivo .md
|
|
624
594
|
const dir = ensureAnalysisDir();
|
|
625
595
|
let filePath: string;
|
|
626
596
|
if (options.file) {
|
|
627
|
-
// Se path fornecido, usar como-is (aceita absoluto ou relativo)
|
|
628
597
|
filePath = options.file;
|
|
629
598
|
} else {
|
|
630
599
|
filePath = join(dir, `${analysis.id}-${analysis.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").substring(0, 30)}.md`);
|
|
631
600
|
}
|
|
632
601
|
|
|
633
|
-
// v8.4: Ler .md do disco e parsear para popular o DB
|
|
634
602
|
if (!existsSync(filePath)) {
|
|
635
603
|
if (options.json) {
|
|
636
604
|
console.log(JSON.stringify({ error: "FILE_NOT_FOUND", message: `Arquivo nao encontrado: ${filePath}` }));
|
|
@@ -644,7 +612,6 @@ export function architectSave(options: { file?: string; json?: boolean }): void
|
|
|
644
612
|
const content = readFileSync(filePath, "utf-8");
|
|
645
613
|
const parsed = parseAnalysisMd(content);
|
|
646
614
|
|
|
647
|
-
// v10.0: Validar secoes criticas antes de salvar
|
|
648
615
|
if (!parsed.babySteps || parsed.babySteps.length === 0) {
|
|
649
616
|
const msg = "Secao 'Baby Steps' esta vazia ou nao foi encontrada no .md. "
|
|
650
617
|
+ "Verifique se os headers seguem o formato '## Baby Steps' e cada step usa '### N. Nome'.";
|
|
@@ -667,7 +634,6 @@ export function architectSave(options: { file?: string; json?: boolean }): void
|
|
|
667
634
|
throw new CodexaError(msg);
|
|
668
635
|
}
|
|
669
636
|
|
|
670
|
-
// Popular DB com dados extraidos do .md
|
|
671
637
|
const updates: string[] = [];
|
|
672
638
|
const values: any[] = [];
|
|
673
639
|
|
|
@@ -710,7 +676,7 @@ export function architectSave(options: { file?: string; json?: boolean }): void
|
|
|
710
676
|
values.push(now);
|
|
711
677
|
values.push(analysis.id);
|
|
712
678
|
|
|
713
|
-
|
|
679
|
+
await dbRun(
|
|
714
680
|
`UPDATE architectural_analyses SET ${updates.join(", ")} WHERE id = ?`,
|
|
715
681
|
values
|
|
716
682
|
);
|
|
@@ -750,19 +716,19 @@ export function architectSave(options: { file?: string; json?: boolean }): void
|
|
|
750
716
|
}
|
|
751
717
|
}
|
|
752
718
|
|
|
753
|
-
export function architectApprove(options: { id?: string; json?: boolean }): void {
|
|
754
|
-
initSchema();
|
|
755
|
-
const db = getDb();
|
|
719
|
+
export async function architectApprove(options: { id?: string; json?: boolean }): Promise<void> {
|
|
720
|
+
await initSchema();
|
|
756
721
|
const now = new Date().toISOString();
|
|
757
722
|
|
|
758
723
|
let analysis: any;
|
|
759
724
|
|
|
760
725
|
if (options.id) {
|
|
761
|
-
analysis =
|
|
726
|
+
analysis = await dbGet<any>("SELECT * FROM architectural_analyses WHERE id = ?", [options.id]);
|
|
762
727
|
} else {
|
|
763
|
-
analysis =
|
|
764
|
-
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1"
|
|
765
|
-
|
|
728
|
+
analysis = await dbGet<any>(
|
|
729
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
|
730
|
+
[]
|
|
731
|
+
);
|
|
766
732
|
}
|
|
767
733
|
|
|
768
734
|
if (!analysis) {
|
|
@@ -783,7 +749,7 @@ export function architectApprove(options: { id?: string; json?: boolean }): void
|
|
|
783
749
|
throw new CodexaError(`Analise ja esta com status '${analysis.status}'.`);
|
|
784
750
|
}
|
|
785
751
|
|
|
786
|
-
|
|
752
|
+
await dbRun(
|
|
787
753
|
"UPDATE architectural_analyses SET status = 'approved', approved_at = ?, updated_at = ? WHERE id = ?",
|
|
788
754
|
[now, now, analysis.id]
|
|
789
755
|
);
|
|
@@ -802,19 +768,18 @@ export function architectApprove(options: { id?: string; json?: boolean }): void
|
|
|
802
768
|
}
|
|
803
769
|
}
|
|
804
770
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
initSchema();
|
|
808
|
-
const db = getDb();
|
|
771
|
+
export async function architectExport(options: { id?: string; json?: boolean }): Promise<void> {
|
|
772
|
+
await initSchema();
|
|
809
773
|
|
|
810
774
|
let analysis: any;
|
|
811
775
|
|
|
812
776
|
if (options.id) {
|
|
813
|
-
analysis =
|
|
777
|
+
analysis = await dbGet<any>("SELECT * FROM architectural_analyses WHERE id = ?", [options.id]);
|
|
814
778
|
} else {
|
|
815
|
-
analysis =
|
|
816
|
-
"SELECT * FROM architectural_analyses WHERE status = 'approved' ORDER BY approved_at DESC LIMIT 1"
|
|
817
|
-
|
|
779
|
+
analysis = await dbGet<any>(
|
|
780
|
+
"SELECT * FROM architectural_analyses WHERE status = 'approved' ORDER BY approved_at DESC LIMIT 1",
|
|
781
|
+
[]
|
|
782
|
+
);
|
|
818
783
|
}
|
|
819
784
|
|
|
820
785
|
if (!analysis) {
|
|
@@ -854,19 +819,19 @@ export function architectExport(options: { id?: string; json?: boolean }): void
|
|
|
854
819
|
}
|
|
855
820
|
}
|
|
856
821
|
|
|
857
|
-
export function architectCancel(options: { id?: string; json?: boolean }): void {
|
|
858
|
-
initSchema();
|
|
859
|
-
const db = getDb();
|
|
822
|
+
export async function architectCancel(options: { id?: string; json?: boolean }): Promise<void> {
|
|
823
|
+
await initSchema();
|
|
860
824
|
const now = new Date().toISOString();
|
|
861
825
|
|
|
862
826
|
let analysis: any;
|
|
863
827
|
|
|
864
828
|
if (options.id) {
|
|
865
|
-
analysis =
|
|
829
|
+
analysis = await dbGet<any>("SELECT * FROM architectural_analyses WHERE id = ?", [options.id]);
|
|
866
830
|
} else {
|
|
867
|
-
analysis =
|
|
868
|
-
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1"
|
|
869
|
-
|
|
831
|
+
analysis = await dbGet<any>(
|
|
832
|
+
"SELECT * FROM architectural_analyses WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1",
|
|
833
|
+
[]
|
|
834
|
+
);
|
|
870
835
|
}
|
|
871
836
|
|
|
872
837
|
if (!analysis) {
|
|
@@ -878,7 +843,7 @@ export function architectCancel(options: { id?: string; json?: boolean }): void
|
|
|
878
843
|
return;
|
|
879
844
|
}
|
|
880
845
|
|
|
881
|
-
|
|
846
|
+
await dbRun(
|
|
882
847
|
"UPDATE architectural_analyses SET status = 'rejected', updated_at = ? WHERE id = ?",
|
|
883
848
|
[now, analysis.id]
|
|
884
849
|
);
|
package/commands/check.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dbGet, dbAll, dbRun } from "../db/connection";
|
|
2
2
|
import { initSchema } from "../db/schema";
|
|
3
3
|
import { enforceGate } from "../gates/validator";
|
|
4
4
|
import { resolveSpec } from "./spec-resolver";
|
|
5
5
|
|
|
6
|
-
export function checkRequest(specId?: string): void {
|
|
7
|
-
initSchema();
|
|
6
|
+
export async function checkRequest(specId?: string): Promise<void> {
|
|
7
|
+
await initSchema();
|
|
8
8
|
enforceGate("check-request");
|
|
9
9
|
|
|
10
|
-
const db = getDb();
|
|
11
10
|
const spec = resolveSpec(specId, ["planning"]);
|
|
12
11
|
|
|
13
|
-
const tasks =
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const tasks = await dbAll<any>(
|
|
13
|
+
"SELECT * FROM tasks WHERE spec_id = ? ORDER BY number",
|
|
14
|
+
[spec.id]
|
|
15
|
+
);
|
|
16
16
|
|
|
17
|
-
const context =
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const context = await dbGet<any>(
|
|
18
|
+
"SELECT * FROM context WHERE spec_id = ?",
|
|
19
|
+
[spec.id]
|
|
20
|
+
);
|
|
20
21
|
|
|
21
22
|
// Atualizar fase para checking
|
|
22
|
-
|
|
23
|
+
await dbRun("UPDATE specs SET phase = 'checking', updated_at = ? WHERE id = ?", [
|
|
23
24
|
new Date().toISOString(),
|
|
24
25
|
spec.id,
|
|
25
26
|
]);
|
|
@@ -67,29 +68,28 @@ export function checkRequest(specId?: string): void {
|
|
|
67
68
|
console.log(`Para ajustar: plan task-add (adiciona mais tasks)\n`);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
export function checkApprove(specId?: string): void {
|
|
71
|
-
initSchema();
|
|
71
|
+
export async function checkApprove(specId?: string): Promise<void> {
|
|
72
|
+
await initSchema();
|
|
72
73
|
enforceGate("check-approve");
|
|
73
74
|
|
|
74
|
-
const db = getDb();
|
|
75
75
|
const now = new Date().toISOString();
|
|
76
76
|
|
|
77
77
|
const spec = resolveSpec(specId, ["checking"]);
|
|
78
78
|
|
|
79
79
|
// Atualizar para aprovado
|
|
80
|
-
|
|
80
|
+
await dbRun(
|
|
81
81
|
"UPDATE specs SET phase = 'implementing', approved_at = ?, updated_at = ? WHERE id = ?",
|
|
82
82
|
[now, now, spec.id]
|
|
83
83
|
);
|
|
84
84
|
|
|
85
85
|
// Atualizar contexto
|
|
86
|
-
|
|
86
|
+
await dbRun("UPDATE context SET current_task = 0, updated_at = ? WHERE spec_id = ?", [now, spec.id]);
|
|
87
87
|
|
|
88
|
-
const taskCount =
|
|
88
|
+
const taskCount = await dbGet<any>("SELECT COUNT(*) as c FROM tasks WHERE spec_id = ?", [spec.id]);
|
|
89
89
|
|
|
90
90
|
console.log(`\nPlano APROVADO!`);
|
|
91
91
|
console.log(`Feature: ${spec.name}`);
|
|
92
|
-
console.log(`Tasks: ${taskCount
|
|
92
|
+
console.log(`Tasks: ${taskCount?.c || 0}`);
|
|
93
93
|
console.log(`Fase: implementing`);
|
|
94
94
|
console.log(`\nProximos passos:`);
|
|
95
95
|
console.log(`1. Veja proximas tasks com: task next`);
|
|
@@ -97,19 +97,18 @@ export function checkApprove(specId?: string): void {
|
|
|
97
97
|
console.log(`3. Complete uma task com: task done <id> --checkpoint "..."\n`);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
export function checkReject(reason: string, specId?: string): void {
|
|
101
|
-
initSchema();
|
|
100
|
+
export async function checkReject(reason: string, specId?: string): Promise<void> {
|
|
101
|
+
await initSchema();
|
|
102
102
|
|
|
103
|
-
const db = getDb();
|
|
104
103
|
const now = new Date().toISOString();
|
|
105
104
|
|
|
106
105
|
const spec = resolveSpec(specId, ["checking"]);
|
|
107
106
|
|
|
108
107
|
// Voltar para planning
|
|
109
|
-
|
|
108
|
+
await dbRun("UPDATE specs SET phase = 'planning', updated_at = ? WHERE id = ?", [now, spec.id]);
|
|
110
109
|
|
|
111
110
|
// Registrar motivo no contexto
|
|
112
|
-
|
|
111
|
+
await dbRun(
|
|
113
112
|
"UPDATE context SET last_checkpoint = ?, updated_at = ? WHERE spec_id = ?",
|
|
114
113
|
[`REJEITADO: ${reason}`, now, spec.id]
|
|
115
114
|
);
|
package/commands/clear.ts
CHANGED
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dbGet, dbRun } from "../db/connection";
|
|
2
2
|
import { initSchema } from "../db/schema";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
|
-
import { join
|
|
4
|
+
import { join } from "path";
|
|
5
5
|
|
|
6
6
|
interface ClearOptions {
|
|
7
7
|
force?: boolean;
|
|
8
8
|
specId?: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
function getDbUrl(): string {
|
|
12
|
+
return process.env.CODEXA_DB_URL || "(nao configurado)";
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
/**
|
|
12
16
|
* Limpa apenas as tasks/features, mantendo configurações do projeto
|
|
13
17
|
* Esta é a ÚNICA forma de limpeza disponível (v8.0)
|
|
14
18
|
* A limpeza completa foi removida por ser muito destrutiva
|
|
15
19
|
*/
|
|
16
|
-
export function clearTasks(options: ClearOptions = {}): void {
|
|
20
|
+
export async function clearTasks(options: ClearOptions = {}): Promise<void> {
|
|
17
21
|
// Garantir que o schema existe
|
|
18
|
-
initSchema();
|
|
19
|
-
const db = getDb();
|
|
22
|
+
await initSchema();
|
|
20
23
|
|
|
21
24
|
// Contar o que existe
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
25
|
+
const specsRow = await dbGet<any>("SELECT COUNT(*) as c FROM specs", []);
|
|
26
|
+
const specsCount = specsRow?.c ?? 0;
|
|
27
|
+
const tasksRow = await dbGet<any>("SELECT COUNT(*) as c FROM tasks", []);
|
|
28
|
+
const tasksCount = tasksRow?.c ?? 0;
|
|
29
|
+
const decisionsRow = await dbGet<any>("SELECT COUNT(*) as c FROM decisions", []);
|
|
30
|
+
const decisionsCount = decisionsRow?.c ?? 0;
|
|
31
|
+
const knowledgeRow = await dbGet<any>("SELECT COUNT(*) as c FROM knowledge", []);
|
|
32
|
+
const knowledgeCount = knowledgeRow?.c ?? 0;
|
|
33
|
+
const reasoningRow = await dbGet<any>("SELECT COUNT(*) as c FROM reasoning_log", []);
|
|
34
|
+
const reasoningCount = reasoningRow?.c ?? 0;
|
|
27
35
|
|
|
28
36
|
if (specsCount === 0 && tasksCount === 0) {
|
|
29
37
|
console.log("\nNenhuma feature/task para limpar.\n");
|
|
@@ -87,7 +95,7 @@ export function clearTasks(options: ClearOptions = {}): void {
|
|
|
87
95
|
|
|
88
96
|
for (const table of tablesWithSpecId) {
|
|
89
97
|
try {
|
|
90
|
-
const result =
|
|
98
|
+
const result = await dbRun(`DELETE FROM ${table} WHERE spec_id = ?`, [options.specId]);
|
|
91
99
|
if (result.changes > 0) {
|
|
92
100
|
console.log(` Limpo: ${table} (${result.changes} registros)`);
|
|
93
101
|
}
|
|
@@ -126,7 +134,7 @@ export function clearTasks(options: ClearOptions = {}): void {
|
|
|
126
134
|
|
|
127
135
|
for (const table of tablesToClear) {
|
|
128
136
|
try {
|
|
129
|
-
const result =
|
|
137
|
+
const result = await dbRun(`DELETE FROM ${table}`);
|
|
130
138
|
console.log(` Limpo: ${table} (${result.changes} registros)`);
|
|
131
139
|
} catch (err: any) {
|
|
132
140
|
// Tabela pode não existir em bancos antigos
|
|
@@ -148,15 +156,9 @@ export function clearTasks(options: ClearOptions = {}): void {
|
|
|
148
156
|
/**
|
|
149
157
|
* Mostra o estado atual do workflow
|
|
150
158
|
*/
|
|
151
|
-
export function clearShow(): void {
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
const dbFiles = [
|
|
156
|
-
dbPath,
|
|
157
|
-
`${dbPath}-shm`,
|
|
158
|
-
`${dbPath}-wal`,
|
|
159
|
-
];
|
|
159
|
+
export async function clearShow(): Promise<void> {
|
|
160
|
+
const codexaDir = join(process.cwd(), ".codexa");
|
|
161
|
+
const dbUrl = getDbUrl();
|
|
160
162
|
|
|
161
163
|
const markdownFiles = [
|
|
162
164
|
join(codexaDir, "standards.md"),
|
|
@@ -168,11 +170,7 @@ export function clearShow(): void {
|
|
|
168
170
|
console.log("ESTADO DO WORKFLOW");
|
|
169
171
|
console.log("═".repeat(60) + "\n");
|
|
170
172
|
|
|
171
|
-
console.log(
|
|
172
|
-
for (const file of dbFiles) {
|
|
173
|
-
const status = existsSync(file) ? "existe" : "nao existe";
|
|
174
|
-
console.log(` ${file}: ${status}`);
|
|
175
|
-
}
|
|
173
|
+
console.log(`Banco de dados: ${dbUrl}`);
|
|
176
174
|
|
|
177
175
|
console.log("\nArquivos gerados:");
|
|
178
176
|
for (const file of markdownFiles) {
|
|
@@ -180,28 +178,24 @@ export function clearShow(): void {
|
|
|
180
178
|
console.log(` ${file}: ${status}`);
|
|
181
179
|
}
|
|
182
180
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
console.log(` Patterns: ${patterns}`);
|
|
202
|
-
} catch (err: any) {
|
|
203
|
-
console.log(`\n Erro ao ler estatisticas: ${err.message}`);
|
|
204
|
-
}
|
|
181
|
+
try {
|
|
182
|
+
await initSchema();
|
|
183
|
+
|
|
184
|
+
console.log("\nEstatisticas:");
|
|
185
|
+
|
|
186
|
+
const specsRow = await dbGet<any>("SELECT COUNT(*) as c FROM specs", []);
|
|
187
|
+
const tasksRow = await dbGet<any>("SELECT COUNT(*) as c FROM tasks", []);
|
|
188
|
+
const decisionsRow = await dbGet<any>("SELECT COUNT(*) as c FROM decisions", []);
|
|
189
|
+
const standardsRow = await dbGet<any>("SELECT COUNT(*) as c FROM standards", []);
|
|
190
|
+
const patternsRow = await dbGet<any>("SELECT COUNT(*) as c FROM implementation_patterns", []);
|
|
191
|
+
|
|
192
|
+
console.log(` Features: ${specsRow?.c ?? 0}`);
|
|
193
|
+
console.log(` Tasks: ${tasksRow?.c ?? 0}`);
|
|
194
|
+
console.log(` Decisions: ${decisionsRow?.c ?? 0}`);
|
|
195
|
+
console.log(` Standards: ${standardsRow?.c ?? 0}`);
|
|
196
|
+
console.log(` Patterns: ${patternsRow?.c ?? 0}`);
|
|
197
|
+
} catch (err: any) {
|
|
198
|
+
console.log(`\n Erro ao ler estatisticas: ${err.message}`);
|
|
205
199
|
}
|
|
206
200
|
|
|
207
201
|
console.log("\n" + "─".repeat(60));
|