@codexa/cli 9.0.2 → 9.0.3
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.test.ts +531 -0
- package/commands/architect.ts +68 -11
- package/commands/clear.ts +0 -1
- package/commands/decide.ts +28 -28
- package/commands/discover.ts +128 -3
- package/commands/knowledge.ts +2 -27
- package/commands/patterns.test.ts +169 -0
- package/commands/plan.test.ts +73 -0
- package/commands/plan.ts +4 -2
- package/commands/sync.ts +90 -0
- package/commands/task.ts +43 -159
- package/commands/utils.ts +251 -249
- package/db/schema.test.ts +333 -0
- package/db/schema.ts +160 -130
- package/gates/validator.test.ts +617 -0
- package/gates/validator.ts +42 -10
- package/package.json +3 -1
- package/protocol/process-return.ts +25 -93
- package/protocol/subagent-protocol.test.ts +936 -0
- package/protocol/subagent-protocol.ts +19 -1
- package/workflow.ts +85 -27
package/commands/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDb } from "../db/connection";
|
|
2
|
-
import { initSchema, getPatternsForFiles,
|
|
2
|
+
import { initSchema, getPatternsForFiles, getRelatedDecisions, getArchitecturalAnalysisForSpec, getUtilitiesForContext } from "../db/schema";
|
|
3
3
|
import { getKnowledgeForTask } from "./knowledge";
|
|
4
4
|
import { getLibContextsForAgent } from "./research";
|
|
5
5
|
import pkg from "../package.json";
|
|
@@ -171,35 +171,6 @@ export function status(json: boolean = false): void {
|
|
|
171
171
|
console.log(`\nDecisoes ativas: ${decisions.length}`);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
// v8.1: Mostrar ultimo session summary para continuidade
|
|
175
|
-
const lastSession = getLastSessionSummary(spec.id);
|
|
176
|
-
if (lastSession) {
|
|
177
|
-
console.log(`\nUltima sessao:`);
|
|
178
|
-
console.log(` ${lastSession.summary}`);
|
|
179
|
-
if (lastSession.next_steps) {
|
|
180
|
-
try {
|
|
181
|
-
const nextSteps = JSON.parse(lastSession.next_steps);
|
|
182
|
-
if (nextSteps.length > 0) {
|
|
183
|
-
console.log(` Proximos passos sugeridos:`);
|
|
184
|
-
for (const step of nextSteps.slice(0, 3)) {
|
|
185
|
-
console.log(` - ${step}`);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
} catch { /* ignore */ }
|
|
189
|
-
}
|
|
190
|
-
if (lastSession.blockers) {
|
|
191
|
-
try {
|
|
192
|
-
const blockers = JSON.parse(lastSession.blockers);
|
|
193
|
-
if (blockers.length > 0) {
|
|
194
|
-
console.log(` Blockers pendentes:`);
|
|
195
|
-
for (const b of blockers) {
|
|
196
|
-
console.log(` [!] ${b}`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
} catch { /* ignore */ }
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
174
|
console.log(`\n${"─".repeat(60)}`);
|
|
204
175
|
|
|
205
176
|
// Sugerir proximo passo
|
|
@@ -375,13 +346,7 @@ export function getMinimalContextForSubagent(taskId: number): string {
|
|
|
375
346
|
ORDER BY created_at DESC LIMIT 5`
|
|
376
347
|
).all(task.spec_id) as any[];
|
|
377
348
|
|
|
378
|
-
// 3.
|
|
379
|
-
let contradictions: any[] = [];
|
|
380
|
-
try {
|
|
381
|
-
contradictions = findContradictions(task.spec_id);
|
|
382
|
-
} catch { /* ignore */ }
|
|
383
|
-
|
|
384
|
-
// 4. Decisoes da task anterior (dependency direta)
|
|
349
|
+
// 3. Decisoes da task anterior (dependency direta)
|
|
385
350
|
const dependsOn = task.depends_on ? JSON.parse(task.depends_on) : [];
|
|
386
351
|
let depDecisions: any[] = [];
|
|
387
352
|
if (dependsOn.length > 0) {
|
|
@@ -416,10 +381,6 @@ export function getMinimalContextForSubagent(taskId: number): string {
|
|
|
416
381
|
output += `\n**BLOCKERS CRITICOS:**\n${criticalBlockers.map((b: any) => `[X] ${b.content}`).join("\n")}\n`;
|
|
417
382
|
}
|
|
418
383
|
|
|
419
|
-
if (contradictions.length > 0) {
|
|
420
|
-
output += `\n**CONTRADICOES:**\n${contradictions.map((c: any) => `[!] "${c.decision1}" <-> "${c.decision2}"`).join("\n")}\n`;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
384
|
if (depDecisions.length > 0) {
|
|
424
385
|
output += `\n**Recomendacoes de tasks anteriores:**\n${depDecisions.map((d: any) => `- ${d.thought}`).join("\n")}\n`;
|
|
425
386
|
}
|
|
@@ -441,17 +402,45 @@ export function getMinimalContextForSubagent(taskId: number): string {
|
|
|
441
402
|
return output;
|
|
442
403
|
}
|
|
443
404
|
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
|
|
405
|
+
// ═══════════════════════════════════════════════════════════════
|
|
406
|
+
// CONTEXT BUILDER (v9.0 — decomposed from v8.1 monolith)
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════
|
|
408
|
+
|
|
409
|
+
interface ContextSection {
|
|
410
|
+
name: string;
|
|
411
|
+
content: string;
|
|
412
|
+
priority: number; // Lower = kept during truncation
|
|
413
|
+
}
|
|
448
414
|
|
|
415
|
+
interface ContextData {
|
|
416
|
+
db: any;
|
|
417
|
+
task: any;
|
|
418
|
+
spec: any;
|
|
419
|
+
context: any;
|
|
420
|
+
project: any;
|
|
421
|
+
taskFiles: string[];
|
|
422
|
+
domain: string;
|
|
423
|
+
archAnalysis: any;
|
|
424
|
+
decisions: any[];
|
|
425
|
+
allDecisions: any[];
|
|
426
|
+
relevantStandards: any[];
|
|
427
|
+
criticalKnowledge: any[];
|
|
428
|
+
truncatedCritical: number;
|
|
429
|
+
infoKnowledge: any[];
|
|
430
|
+
truncatedInfo: number;
|
|
431
|
+
productContext: any;
|
|
432
|
+
patterns: any[];
|
|
433
|
+
depReasoning: any[];
|
|
434
|
+
libContexts: any[];
|
|
435
|
+
graphDecisions: any[];
|
|
436
|
+
discoveredPatterns: any[];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function fetchContextData(taskId: number): ContextData | null {
|
|
449
440
|
const db = getDb();
|
|
450
441
|
|
|
451
442
|
const task = db.query("SELECT * FROM tasks WHERE id = ?").get(taskId) as any;
|
|
452
|
-
if (!task)
|
|
453
|
-
return "ERRO: Task nao encontrada";
|
|
454
|
-
}
|
|
443
|
+
if (!task) return null;
|
|
455
444
|
|
|
456
445
|
const spec = db.query("SELECT * FROM specs WHERE id = ?").get(task.spec_id) as any;
|
|
457
446
|
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(task.spec_id) as any;
|
|
@@ -480,27 +469,16 @@ export function getContextForSubagent(taskId: number): string {
|
|
|
480
469
|
.all(domain) as any[];
|
|
481
470
|
const relevantStandards = filterRelevantStandards(standards, taskFiles);
|
|
482
471
|
|
|
483
|
-
//
|
|
472
|
+
// Knowledge com caps e indicadores de truncamento
|
|
484
473
|
const allKnowledge = getKnowledgeForTask(task.spec_id, taskId);
|
|
485
|
-
const
|
|
486
|
-
const recentKnowledge = allKnowledge.filter((k: any) => k.created_at > now48h);
|
|
487
|
-
const staleKnowledge = allKnowledge.filter((k: any) => k.created_at <= now48h);
|
|
488
|
-
// Conhecimento recente primeiro; stale so se critical
|
|
489
|
-
const effectiveKnowledge = [
|
|
490
|
-
...recentKnowledge,
|
|
491
|
-
...staleKnowledge.filter((k: any) => k.severity === 'critical'),
|
|
492
|
-
];
|
|
493
|
-
const allCriticalKnowledge = effectiveKnowledge.filter((k: any) => k.severity === 'critical' || k.severity === 'warning');
|
|
474
|
+
const allCriticalKnowledge = allKnowledge.filter((k: any) => k.severity === 'critical' || k.severity === 'warning');
|
|
494
475
|
const criticalKnowledge = allCriticalKnowledge.slice(0, 20);
|
|
495
476
|
const truncatedCritical = allCriticalKnowledge.length - criticalKnowledge.length;
|
|
496
|
-
const allInfoKnowledge =
|
|
477
|
+
const allInfoKnowledge = allKnowledge.filter((k: any) => k.severity === 'info');
|
|
497
478
|
const infoKnowledge = allInfoKnowledge.slice(0, 10);
|
|
498
479
|
const truncatedInfo = allInfoKnowledge.length - infoKnowledge.length;
|
|
499
480
|
|
|
500
|
-
// v8.1: Contexto de produto (resumido - problema, usuarios, restricoes)
|
|
501
481
|
const productContext = db.query("SELECT * FROM product_context WHERE id = 'default'").get() as any;
|
|
502
|
-
|
|
503
|
-
// v8.1: Patterns de implementacao matchados aos arquivos da task
|
|
504
482
|
const patterns = getPatternsForFiles(taskFiles);
|
|
505
483
|
|
|
506
484
|
// v8.2: Reasoning de tasks dependentes + todas tasks completas recentes
|
|
@@ -508,7 +486,6 @@ export function getContextForSubagent(taskId: number): string {
|
|
|
508
486
|
const depReasoning: any[] = [];
|
|
509
487
|
const seenTaskIds = new Set<number>();
|
|
510
488
|
|
|
511
|
-
// 1. Reasoning de dependencias diretas (prioridade maxima)
|
|
512
489
|
if (dependsOn.length > 0) {
|
|
513
490
|
const placeholders = dependsOn.map(() => '?').join(',');
|
|
514
491
|
const depTasks = db.query(
|
|
@@ -532,7 +509,6 @@ export function getContextForSubagent(taskId: number): string {
|
|
|
532
509
|
}
|
|
533
510
|
}
|
|
534
511
|
|
|
535
|
-
// 2. Reasoning de TODAS tasks completas (recommendations e challenges de alta importancia)
|
|
536
512
|
const completedTasks = db.query(
|
|
537
513
|
`SELECT t.id, t.number FROM tasks t
|
|
538
514
|
WHERE t.spec_id = ? AND t.status = 'done' AND t.id != ?
|
|
@@ -556,15 +532,10 @@ export function getContextForSubagent(taskId: number): string {
|
|
|
556
532
|
}
|
|
557
533
|
}
|
|
558
534
|
|
|
559
|
-
// v8.1: Lib contexts do projeto (resumido - nomes e versoes)
|
|
560
535
|
const libContexts = db.query(
|
|
561
536
|
"SELECT lib_name, version FROM lib_contexts ORDER BY lib_name LIMIT 10"
|
|
562
537
|
).all() as any[];
|
|
563
538
|
|
|
564
|
-
// v8.3: Sessoes compostas para continuidade cross-session (todas, nao so ultima)
|
|
565
|
-
const sessions = getSessionSummaries(task.spec_id, 5);
|
|
566
|
-
|
|
567
|
-
// v8.2: Knowledge graph - decisoes que afetam arquivos da task
|
|
568
539
|
const graphDecisions: any[] = [];
|
|
569
540
|
for (const file of taskFiles) {
|
|
570
541
|
try {
|
|
@@ -577,138 +548,152 @@ export function getContextForSubagent(taskId: number): string {
|
|
|
577
548
|
} catch { /* ignore if graph empty */ }
|
|
578
549
|
}
|
|
579
550
|
|
|
580
|
-
// v8.2: Deteccao de contradicoes
|
|
581
|
-
let contradictions: any[] = [];
|
|
582
|
-
try {
|
|
583
|
-
contradictions = findContradictions(task.spec_id);
|
|
584
|
-
} catch { /* ignore if no contradictions */ }
|
|
585
|
-
|
|
586
|
-
// v8.2: Patterns descobertos por subagents anteriores
|
|
587
551
|
const discoveredPatterns = context?.patterns ? JSON.parse(context.patterns) : [];
|
|
588
552
|
|
|
589
|
-
|
|
553
|
+
return {
|
|
554
|
+
db, task, spec, context, project, taskFiles, domain, archAnalysis,
|
|
555
|
+
decisions, allDecisions, relevantStandards,
|
|
556
|
+
criticalKnowledge, truncatedCritical, infoKnowledge, truncatedInfo,
|
|
557
|
+
productContext, patterns, depReasoning, libContexts,
|
|
558
|
+
graphDecisions, discoveredPatterns,
|
|
559
|
+
};
|
|
560
|
+
}
|
|
590
561
|
|
|
591
|
-
|
|
562
|
+
// ── Section Builders ──────────────────────────────────────────
|
|
592
563
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
**Arquivos:** ${taskFiles.join(", ") || "Nenhum especificado"}
|
|
596
|
-
`;
|
|
564
|
+
function buildProductSection(data: ContextData): ContextSection | null {
|
|
565
|
+
if (!data.productContext) return null;
|
|
597
566
|
|
|
598
|
-
|
|
599
|
-
if (productContext) {
|
|
600
|
-
output += `
|
|
567
|
+
let content = `
|
|
601
568
|
### PRODUTO
|
|
602
|
-
- **Problema:** ${productContext.problem || "N/A"}
|
|
603
|
-
- **Usuarios:** ${productContext.target_users || "N/A"}`;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
}
|
|
612
|
-
output += "\n";
|
|
569
|
+
- **Problema:** ${data.productContext.problem || "N/A"}
|
|
570
|
+
- **Usuarios:** ${data.productContext.target_users || "N/A"}`;
|
|
571
|
+
if (data.productContext.constraints) {
|
|
572
|
+
try {
|
|
573
|
+
const constraints = JSON.parse(data.productContext.constraints);
|
|
574
|
+
if (constraints.length > 0) {
|
|
575
|
+
content += `\n- **Restricoes:** ${constraints.slice(0, 3).join("; ")}${constraints.length > 3 ? ` [+${constraints.length - 3} mais]` : ''}`;
|
|
576
|
+
}
|
|
577
|
+
} catch { /* ignore parse errors */ }
|
|
613
578
|
}
|
|
579
|
+
content += "\n";
|
|
614
580
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
581
|
+
return { name: "PRODUTO", content, priority: 7 };
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function buildArchitectureSection(data: ContextData): ContextSection | null {
|
|
585
|
+
if (!data.archAnalysis) return null;
|
|
586
|
+
|
|
587
|
+
let content = `
|
|
588
|
+
### ARQUITETURA (${data.archAnalysis.id})`;
|
|
589
|
+
if (data.archAnalysis.approach) {
|
|
590
|
+
const approachPreview = data.archAnalysis.approach.length > 500
|
|
591
|
+
? data.archAnalysis.approach.substring(0, 500) + "..."
|
|
592
|
+
: data.archAnalysis.approach;
|
|
593
|
+
content += `\n**Abordagem:** ${approachPreview}`;
|
|
594
|
+
}
|
|
595
|
+
if (data.archAnalysis.risks) {
|
|
596
|
+
try {
|
|
597
|
+
const risks = JSON.parse(data.archAnalysis.risks);
|
|
598
|
+
if (risks.length > 0) {
|
|
599
|
+
const highRisks = risks.filter((r: any) => r.impact === 'high' || r.probability === 'high');
|
|
600
|
+
const risksToShow = highRisks.length > 0 ? highRisks.slice(0, 3) : risks.slice(0, 3);
|
|
601
|
+
content += `\n**Riscos:**`;
|
|
602
|
+
for (const r of risksToShow) {
|
|
603
|
+
content += `\n - ${r.description} (${r.probability}/${r.impact}) -> ${r.mitigation}`;
|
|
638
604
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
if (archAnalysis.decisions) {
|
|
642
|
-
try {
|
|
643
|
-
const archDecisions = JSON.parse(archAnalysis.decisions);
|
|
644
|
-
if (archDecisions.length > 0) {
|
|
645
|
-
output += `\n**Decisoes arquiteturais:**`;
|
|
646
|
-
for (const d of archDecisions.slice(0, 5)) {
|
|
647
|
-
output += `\n - ${d.decision}: ${d.rationale || ''}`;
|
|
648
|
-
}
|
|
649
|
-
if (archDecisions.length > 5) {
|
|
650
|
-
output += `\n [+${archDecisions.length - 5} mais]`;
|
|
651
|
-
}
|
|
605
|
+
if (risks.length > risksToShow.length) {
|
|
606
|
+
content += `\n [+${risks.length - risksToShow.length} mais riscos]`;
|
|
652
607
|
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
output += "\n";
|
|
608
|
+
}
|
|
609
|
+
} catch { /* ignore */ }
|
|
656
610
|
}
|
|
611
|
+
if (data.archAnalysis.decisions) {
|
|
612
|
+
try {
|
|
613
|
+
const archDecisions = JSON.parse(data.archAnalysis.decisions);
|
|
614
|
+
if (archDecisions.length > 0) {
|
|
615
|
+
content += `\n**Decisoes arquiteturais:**`;
|
|
616
|
+
for (const d of archDecisions.slice(0, 5)) {
|
|
617
|
+
content += `\n - ${d.decision}: ${d.rationale || ''}`;
|
|
618
|
+
}
|
|
619
|
+
if (archDecisions.length > 5) {
|
|
620
|
+
content += `\n [+${archDecisions.length - 5} mais]`;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
} catch { /* ignore */ }
|
|
624
|
+
}
|
|
625
|
+
content += "\n";
|
|
626
|
+
|
|
627
|
+
return { name: "ARQUITETURA", content, priority: 3 };
|
|
628
|
+
}
|
|
657
629
|
|
|
658
|
-
|
|
659
|
-
const requiredStds = relevantStandards.filter((s: any) => s.enforcement === 'required');
|
|
660
|
-
const recommendedStds = relevantStandards.filter((s: any) => s.enforcement === 'recommended');
|
|
630
|
+
function buildStandardsSection(data: ContextData): ContextSection {
|
|
631
|
+
const requiredStds = data.relevantStandards.filter((s: any) => s.enforcement === 'required');
|
|
632
|
+
const recommendedStds = data.relevantStandards.filter((s: any) => s.enforcement === 'recommended');
|
|
661
633
|
|
|
662
|
-
|
|
663
|
-
### STANDARDS (${relevantStandards.length})`;
|
|
634
|
+
let content = `
|
|
635
|
+
### STANDARDS (${data.relevantStandards.length})`;
|
|
664
636
|
if (requiredStds.length > 0) {
|
|
665
|
-
|
|
637
|
+
content += `\n**Obrigatorios:**\n${requiredStds.map((s: any) => `- ${s.rule}`).join("\n")}`;
|
|
666
638
|
}
|
|
667
639
|
if (recommendedStds.length > 0) {
|
|
668
|
-
|
|
640
|
+
content += `\n**Recomendados:**\n${recommendedStds.map((s: any) => `- ${s.rule}`).join("\n")}`;
|
|
669
641
|
}
|
|
670
|
-
if (relevantStandards.length === 0) {
|
|
671
|
-
|
|
642
|
+
if (data.relevantStandards.length === 0) {
|
|
643
|
+
content += "\nNenhum standard aplicavel";
|
|
672
644
|
}
|
|
673
|
-
|
|
645
|
+
content += "\n";
|
|
674
646
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
647
|
+
return { name: "STANDARDS", content, priority: 1 };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function buildDecisionsSection(data: ContextData): ContextSection {
|
|
651
|
+
const truncatedDecisions = data.allDecisions.length - data.decisions.length;
|
|
652
|
+
const content = `
|
|
653
|
+
### DECISOES (${data.decisions.length}${truncatedDecisions > 0 ? ` [+${truncatedDecisions} mais - use: decisions list]` : ''})
|
|
654
|
+
${data.decisions.length > 0 ? data.decisions.map((d) => `- **${d.title}**: ${d.decision}`).join("\n") : "Nenhuma"}
|
|
680
655
|
`;
|
|
656
|
+
return { name: "DECISOES", content, priority: 4 };
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function buildReasoningSection(data: ContextData): ContextSection | null {
|
|
660
|
+
if (data.depReasoning.length === 0) return null;
|
|
681
661
|
|
|
682
|
-
|
|
683
|
-
if (depReasoning.length > 0) {
|
|
684
|
-
output += `
|
|
662
|
+
const content = `
|
|
685
663
|
### CONTEXTO DE TASKS ANTERIORES
|
|
686
|
-
${depReasoning.map((r: any) => `- [Task #${r.fromTask}/${r.category}] ${r.thought}`).join("\n")}
|
|
664
|
+
${data.depReasoning.map((r: any) => `- [Task #${r.fromTask}/${r.category}] ${r.thought}`).join("\n")}
|
|
687
665
|
`;
|
|
688
|
-
}
|
|
666
|
+
return { name: "CONTEXTO DE TASKS ANTERIORES", content, priority: 5 };
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function buildAlertsSection(data: ContextData): ContextSection | null {
|
|
670
|
+
if (data.criticalKnowledge.length === 0) return null;
|
|
689
671
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
### ALERTAS (${criticalKnowledge.length}${truncatedCritical > 0 ? ` [+${truncatedCritical} mais - use: knowledge list --severity warning]` : ''})
|
|
695
|
-
${criticalKnowledge.map((k: any) => `[${severityIcon[k.severity] || "!"}] ${k.content}`).join("\n")}
|
|
672
|
+
const severityIcon: Record<string, string> = { warning: "!!", critical: "XX" };
|
|
673
|
+
const content = `
|
|
674
|
+
### ALERTAS (${data.criticalKnowledge.length}${data.truncatedCritical > 0 ? ` [+${data.truncatedCritical} mais - use: knowledge list --severity warning]` : ''})
|
|
675
|
+
${data.criticalKnowledge.map((k: any) => `[${severityIcon[k.severity] || "!"}] ${k.content}`).join("\n")}
|
|
696
676
|
`;
|
|
697
|
-
}
|
|
677
|
+
return { name: "ALERTAS", content, priority: 2 };
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function buildDiscoveriesSection(data: ContextData): ContextSection | null {
|
|
681
|
+
if (data.infoKnowledge.length === 0) return null;
|
|
698
682
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
### DISCOVERIES DE TASKS ANTERIORES (${infoKnowledge.length}${truncatedInfo > 0 ? ` [+${truncatedInfo} mais - use: knowledge list]` : ''})
|
|
703
|
-
${infoKnowledge.map((k: any) => `- ${k.content}`).join("\n")}
|
|
683
|
+
const content = `
|
|
684
|
+
### DISCOVERIES DE TASKS ANTERIORES (${data.infoKnowledge.length}${data.truncatedInfo > 0 ? ` [+${data.truncatedInfo} mais - use: knowledge list]` : ''})
|
|
685
|
+
${data.infoKnowledge.map((k: any) => `- ${k.content}`).join("\n")}
|
|
704
686
|
`;
|
|
705
|
-
}
|
|
687
|
+
return { name: "DISCOVERIES", content, priority: 8 };
|
|
688
|
+
}
|
|
706
689
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
690
|
+
function buildPatternsSection(data: ContextData): ContextSection | null {
|
|
691
|
+
let content = "";
|
|
692
|
+
|
|
693
|
+
if (data.patterns.length > 0) {
|
|
694
|
+
content += `
|
|
695
|
+
### PATTERNS DO PROJETO (${data.patterns.length})
|
|
696
|
+
${data.patterns.map((p: any) => {
|
|
712
697
|
const tmpl = p.template || "";
|
|
713
698
|
const preview = tmpl.length > 200 ? tmpl.substring(0, 200) + `... [truncado de ${tmpl.length} chars]` : tmpl;
|
|
714
699
|
return `- **${p.name}** (${p.category}): ${preview || p.description || "Sem template"}`;
|
|
@@ -716,17 +701,28 @@ ${patterns.map((p: any) => {
|
|
|
716
701
|
`;
|
|
717
702
|
}
|
|
718
703
|
|
|
719
|
-
|
|
704
|
+
if (data.discoveredPatterns.length > 0) {
|
|
705
|
+
const patternsToShow = data.discoveredPatterns.slice(-10);
|
|
706
|
+
content += `
|
|
707
|
+
### PATTERNS DESCOBERTOS (${data.discoveredPatterns.length})
|
|
708
|
+
${data.discoveredPatterns.length > 10 ? `[mostrando ultimos 10 de ${data.discoveredPatterns.length}]\n` : ''}${patternsToShow.map((p: any) => `- ${p.pattern}${p.source_task ? ` (Task #${p.source_task})` : ""}`).join("\n")}
|
|
709
|
+
`;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (!content) return null;
|
|
713
|
+
return { name: "PATTERNS", content, priority: 9 };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function buildUtilitiesSection(data: ContextData): ContextSection | null {
|
|
720
717
|
try {
|
|
721
|
-
const taskDirs = [...new Set(taskFiles.map((f: string) => {
|
|
718
|
+
const taskDirs = [...new Set(data.taskFiles.map((f: string) => {
|
|
722
719
|
const parts = f.replace(/\\/g, "/").split("/");
|
|
723
720
|
return parts.slice(0, -1).join("/");
|
|
724
721
|
}).filter(Boolean))];
|
|
725
722
|
|
|
726
|
-
const agentScope = task.agent?.split("-")[0] || undefined;
|
|
723
|
+
const agentScope = data.task.agent?.split("-")[0] || undefined;
|
|
727
724
|
let relevantUtilities = getUtilitiesForContext(taskDirs, undefined, 15);
|
|
728
725
|
|
|
729
|
-
// Se poucos resultados por diretorio, ampliar para scope do agent
|
|
730
726
|
if (relevantUtilities.length < 5 && agentScope) {
|
|
731
727
|
const scopeUtils = getUtilitiesForContext([], agentScope, 15);
|
|
732
728
|
const existingKeys = new Set(relevantUtilities.map((u: any) => `${u.file_path}:${u.utility_name}`));
|
|
@@ -738,10 +734,11 @@ ${patterns.map((p: any) => {
|
|
|
738
734
|
}
|
|
739
735
|
}
|
|
740
736
|
|
|
741
|
-
if (relevantUtilities.length
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
737
|
+
if (relevantUtilities.length === 0) return null;
|
|
738
|
+
|
|
739
|
+
const totalCount = (data.db.query("SELECT COUNT(*) as c FROM project_utilities").get() as any)?.c || 0;
|
|
740
|
+
const truncated = totalCount - relevantUtilities.length;
|
|
741
|
+
const content = `
|
|
745
742
|
### UTILITIES EXISTENTES (${relevantUtilities.length}${truncated > 0 ? ` [+${truncated} mais]` : ''})
|
|
746
743
|
**REGRA DRY**: Reutilize ao inves de recriar. Importe do arquivo existente.
|
|
747
744
|
${relevantUtilities.map((u: any) => {
|
|
@@ -749,88 +746,61 @@ ${relevantUtilities.map((u: any) => {
|
|
|
749
746
|
return `- **${u.utility_name}** [${u.utility_type}]${sig} <- \`${u.file_path}\``;
|
|
750
747
|
}).join("\n")}
|
|
751
748
|
`;
|
|
752
|
-
}
|
|
749
|
+
return { name: "UTILITIES", content, priority: 8 };
|
|
753
750
|
} catch { /* tabela pode nao existir ainda */ }
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
754
753
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
output += `
|
|
758
|
-
### HISTORICO DE SESSOES (${sessions.length})`;
|
|
759
|
-
// Sessao mais recente: detalhes completos
|
|
760
|
-
const latest = sessions[0];
|
|
761
|
-
output += `\n**Ultima:** ${latest.summary}`;
|
|
762
|
-
if (latest.next_steps) {
|
|
763
|
-
try {
|
|
764
|
-
const steps = JSON.parse(latest.next_steps);
|
|
765
|
-
if (steps.length > 0) {
|
|
766
|
-
output += `\n**Proximos passos:** ${steps.slice(0, 3).join("; ")}${steps.length > 3 ? ` [+${steps.length - 3} mais]` : ''}`;
|
|
767
|
-
}
|
|
768
|
-
} catch { /* ignore */ }
|
|
769
|
-
}
|
|
770
|
-
if (latest.blockers) {
|
|
771
|
-
try {
|
|
772
|
-
const blockers = JSON.parse(latest.blockers);
|
|
773
|
-
if (blockers.length > 0) {
|
|
774
|
-
output += `\n**Blockers:** ${blockers.join("; ")}`;
|
|
775
|
-
}
|
|
776
|
-
} catch { /* ignore */ }
|
|
777
|
-
}
|
|
778
|
-
// Sessoes anteriores: resumo de 1 linha
|
|
779
|
-
if (sessions.length > 1) {
|
|
780
|
-
output += `\n**Sessoes anteriores:**`;
|
|
781
|
-
for (const s of sessions.slice(1)) {
|
|
782
|
-
output += `\n - ${s.summary.substring(0, 100)}${s.summary.length > 100 ? '...' : ''} (${s.tasks_completed || 0} tasks)`;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
output += "\n";
|
|
786
|
-
}
|
|
754
|
+
function buildGraphSection(data: ContextData): ContextSection | null {
|
|
755
|
+
let content = "";
|
|
787
756
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
${graphDecisions.map((d: any) => `- **${d.title}**: ${d.decision}`).join("\n")}
|
|
757
|
+
if (data.graphDecisions.length > 0) {
|
|
758
|
+
content += `
|
|
759
|
+
### DECISOES QUE AFETAM SEUS ARQUIVOS (${data.graphDecisions.length})
|
|
760
|
+
${data.graphDecisions.map((d: any) => `- **${d.title}**: ${d.decision}`).join("\n")}
|
|
793
761
|
`;
|
|
794
762
|
}
|
|
795
763
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
### [!!] CONTRADICOES DETECTADAS (${contradictions.length})
|
|
800
|
-
${contradictions.map((c: any) => `- "${c.decision1}" <-> "${c.decision2}"`).join("\n")}
|
|
801
|
-
Verifique estas contradicoes antes de prosseguir.
|
|
802
|
-
`;
|
|
803
|
-
}
|
|
764
|
+
if (!content) return null;
|
|
765
|
+
return { name: "GRAPH", content, priority: 6 };
|
|
766
|
+
}
|
|
804
767
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const patternsToShow = discoveredPatterns.slice(-10);
|
|
808
|
-
output += `
|
|
809
|
-
### PATTERNS DESCOBERTOS (${discoveredPatterns.length})
|
|
810
|
-
${discoveredPatterns.length > 10 ? `[mostrando ultimos 10 de ${discoveredPatterns.length}]\n` : ''}${patternsToShow.map((p: any) => `- ${p.pattern}${p.source_task ? ` (Task #${p.source_task})` : ""}`).join("\n")}
|
|
811
|
-
`;
|
|
812
|
-
}
|
|
768
|
+
function buildStackSection(data: ContextData): ContextSection | null {
|
|
769
|
+
let content = "";
|
|
813
770
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const stack = JSON.parse(project.stack);
|
|
771
|
+
if (data.project) {
|
|
772
|
+
const stack = JSON.parse(data.project.stack);
|
|
817
773
|
const allStackEntries = Object.entries(stack);
|
|
818
774
|
const mainStack = allStackEntries.slice(0, 6);
|
|
819
|
-
|
|
775
|
+
content += `
|
|
820
776
|
### STACK
|
|
821
777
|
${mainStack.map(([k, v]) => `${k}: ${v}`).join(" | ")}${allStackEntries.length > 6 ? ` [+${allStackEntries.length - 6} mais]` : ''}
|
|
822
778
|
`;
|
|
823
779
|
}
|
|
824
780
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
output += `
|
|
781
|
+
if (data.libContexts.length > 0) {
|
|
782
|
+
content += `
|
|
828
783
|
### BIBLIOTECAS
|
|
829
|
-
${libContexts.map((l: any) => `- ${l.lib_name}${l.version ? ` v${l.version}` : ""}`).join("\n")}
|
|
784
|
+
${data.libContexts.map((l: any) => `- ${l.lib_name}${l.version ? ` v${l.version}` : ""}`).join("\n")}
|
|
830
785
|
`;
|
|
831
786
|
}
|
|
832
787
|
|
|
833
|
-
|
|
788
|
+
if (!content) return null;
|
|
789
|
+
return { name: "STACK", content, priority: 11 };
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// ── Assembly + Truncation ─────────────────────────────────────
|
|
793
|
+
|
|
794
|
+
function assembleSections(header: string, sections: ContextSection[]): string {
|
|
795
|
+
// Sort by priority (lower = higher priority, kept during truncation)
|
|
796
|
+
const sorted = [...sections].sort((a, b) => a.priority - b.priority);
|
|
797
|
+
|
|
798
|
+
let output = header;
|
|
799
|
+
for (const section of sorted) {
|
|
800
|
+
output += section.content;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Protocolo de retorno (sempre incluido)
|
|
834
804
|
output += `
|
|
835
805
|
### RETORNO OBRIGATORIO
|
|
836
806
|
\`\`\`json
|
|
@@ -840,18 +810,18 @@ ${libContexts.map((l: any) => `- ${l.lib_name}${l.version ? ` v${l.version}` : "
|
|
|
840
810
|
|
|
841
811
|
// v8.3: Overall size cap com truncamento inteligente por secao
|
|
842
812
|
if (output.length > MAX_CONTEXT_SIZE) {
|
|
843
|
-
const
|
|
844
|
-
let trimmed =
|
|
813
|
+
const parts = output.split('\n### ');
|
|
814
|
+
let trimmed = parts[0]; // Sempre manter header
|
|
845
815
|
|
|
846
|
-
for (let i = 1; i <
|
|
847
|
-
const candidate = trimmed + '\n### ' +
|
|
816
|
+
for (let i = 1; i < parts.length; i++) {
|
|
817
|
+
const candidate = trimmed + '\n### ' + parts[i];
|
|
848
818
|
if (candidate.length > MAX_CONTEXT_SIZE - 200) {
|
|
849
819
|
break;
|
|
850
820
|
}
|
|
851
821
|
trimmed = candidate;
|
|
852
822
|
}
|
|
853
823
|
|
|
854
|
-
const omittedSections =
|
|
824
|
+
const omittedSections = parts.length - trimmed.split('\n### ').length;
|
|
855
825
|
if (omittedSections > 0) {
|
|
856
826
|
trimmed += `\n\n[CONTEXTO TRUNCADO: ${omittedSections} secao(oes) omitida(s) por limite de ${MAX_CONTEXT_SIZE} chars. Use: context-export para contexto completo]`;
|
|
857
827
|
}
|
|
@@ -862,6 +832,38 @@ ${libContexts.map((l: any) => `- ${l.lib_name}${l.version ? ` v${l.version}` : "
|
|
|
862
832
|
return output;
|
|
863
833
|
}
|
|
864
834
|
|
|
835
|
+
// ── Main Entry Point ──────────────────────────────────────────
|
|
836
|
+
|
|
837
|
+
export function getContextForSubagent(taskId: number): string {
|
|
838
|
+
initSchema();
|
|
839
|
+
|
|
840
|
+
const data = fetchContextData(taskId);
|
|
841
|
+
if (!data) return "ERRO: Task nao encontrada";
|
|
842
|
+
|
|
843
|
+
const header = `## CONTEXTO (Task #${data.task.number})
|
|
844
|
+
|
|
845
|
+
**Feature:** ${data.spec.name}
|
|
846
|
+
**Objetivo:** ${data.context?.objective || "N/A"}
|
|
847
|
+
**Arquivos:** ${data.taskFiles.join(", ") || "Nenhum especificado"}
|
|
848
|
+
`;
|
|
849
|
+
|
|
850
|
+
const sections = [
|
|
851
|
+
buildProductSection(data),
|
|
852
|
+
buildArchitectureSection(data),
|
|
853
|
+
buildStandardsSection(data),
|
|
854
|
+
buildDecisionsSection(data),
|
|
855
|
+
buildReasoningSection(data),
|
|
856
|
+
buildAlertsSection(data),
|
|
857
|
+
buildDiscoveriesSection(data),
|
|
858
|
+
buildPatternsSection(data),
|
|
859
|
+
buildUtilitiesSection(data),
|
|
860
|
+
buildGraphSection(data),
|
|
861
|
+
buildStackSection(data),
|
|
862
|
+
].filter((s): s is ContextSection => s !== null);
|
|
863
|
+
|
|
864
|
+
return assembleSections(header, sections);
|
|
865
|
+
}
|
|
866
|
+
|
|
865
867
|
// v8.3: Filtrar decisoes relevantes com scoring melhorado
|
|
866
868
|
function filterRelevantDecisions(decisions: any[], taskFiles: string[], maxCount: number): any[] {
|
|
867
869
|
if (decisions.length === 0) return [];
|