@codexa/cli 9.0.6 → 9.0.7
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/context/assembly.ts +82 -0
- package/context/generator.ts +273 -0
- package/context/index.ts +19 -0
- package/context/scoring.ts +106 -0
- package/context/sections.ts +246 -0
- package/package.json +4 -2
- package/templates/loader.ts +22 -0
- package/templates/subagent-context.md +34 -0
- package/templates/subagent-return-protocol.md +29 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// v8.3: Limite maximo de contexto para subagents (16KB)
|
|
2
|
+
export const MAX_CONTEXT_SIZE = 16384;
|
|
3
|
+
|
|
4
|
+
export interface ContextSection {
|
|
5
|
+
name: string;
|
|
6
|
+
content: string;
|
|
7
|
+
priority: number; // Lower = kept during truncation
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ContextData {
|
|
11
|
+
db: any;
|
|
12
|
+
task: any;
|
|
13
|
+
spec: any;
|
|
14
|
+
context: any;
|
|
15
|
+
project: any;
|
|
16
|
+
taskFiles: string[];
|
|
17
|
+
domain: string;
|
|
18
|
+
archAnalysis: any;
|
|
19
|
+
decisions: any[];
|
|
20
|
+
allDecisions: any[];
|
|
21
|
+
relevantStandards: any[];
|
|
22
|
+
criticalKnowledge: any[];
|
|
23
|
+
truncatedCritical: number;
|
|
24
|
+
infoKnowledge: any[];
|
|
25
|
+
truncatedInfo: number;
|
|
26
|
+
productContext: any;
|
|
27
|
+
patterns: any[];
|
|
28
|
+
depReasoning: any[];
|
|
29
|
+
libContexts: any[];
|
|
30
|
+
graphDecisions: any[];
|
|
31
|
+
discoveredPatterns: any[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function assembleSections(header: string, sections: ContextSection[]): string {
|
|
35
|
+
// Sort by priority (lower = higher priority, kept during truncation)
|
|
36
|
+
const sorted = [...sections].sort((a, b) => a.priority - b.priority);
|
|
37
|
+
|
|
38
|
+
let output = header;
|
|
39
|
+
for (const section of sorted) {
|
|
40
|
+
output += section.content;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Protocolo de retorno (sempre incluido)
|
|
44
|
+
output += `
|
|
45
|
+
### RETORNO OBRIGATORIO
|
|
46
|
+
\`\`\`json
|
|
47
|
+
{"status": "completed|blocked", "summary": "...", "files_created": [], "files_modified": [], "reasoning": {"approach": "como abordou", "challenges": [], "recommendations": "para proximas tasks"}}
|
|
48
|
+
\`\`\`
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
// v8.3: Overall size cap com truncamento inteligente por secao
|
|
52
|
+
if (output.length > MAX_CONTEXT_SIZE) {
|
|
53
|
+
const parts = output.split('\n### ');
|
|
54
|
+
let trimmed = parts[0]; // Sempre manter header
|
|
55
|
+
|
|
56
|
+
for (let i = 1; i < parts.length; i++) {
|
|
57
|
+
const candidate = trimmed + '\n### ' + parts[i];
|
|
58
|
+
if (candidate.length > MAX_CONTEXT_SIZE - 200) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
trimmed = candidate;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const omittedSections = parts.length - trimmed.split('\n### ').length;
|
|
65
|
+
if (omittedSections > 0) {
|
|
66
|
+
trimmed += `\n\n[CONTEXTO TRUNCADO: ${omittedSections} secao(oes) omitida(s) por limite de ${MAX_CONTEXT_SIZE} chars. Use: context-export para contexto completo]`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
output = trimmed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// v9.3: Secoes relevantes por tipo de agente.
|
|
76
|
+
// Agentes nao listados recebem TODAS as secoes (comportamento atual).
|
|
77
|
+
export const AGENT_SECTIONS: Record<string, string[]> = {
|
|
78
|
+
"testing-unit": ["STANDARDS", "DECISOES", "ALERTAS", "PATTERNS", "UTILITIES", "HINTS"],
|
|
79
|
+
"deep-explore": ["STACK", "ARQUITETURA"],
|
|
80
|
+
"security-specialist": ["STANDARDS", "DECISOES", "ALERTAS", "STACK", "HINTS"],
|
|
81
|
+
"expert-code-reviewer": ["STANDARDS", "DECISOES", "ARQUITETURA", "UTILITIES", "ALERTAS", "HINTS"],
|
|
82
|
+
};
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { getDb } from "../db/connection";
|
|
2
|
+
import { initSchema, getPatternsForFiles, getRelatedDecisions, getArchitecturalAnalysisForSpec } from "../db/schema";
|
|
3
|
+
import { getKnowledgeForTask } from "../commands/knowledge";
|
|
4
|
+
import type { ContextSection, ContextData } from "./assembly";
|
|
5
|
+
import { assembleSections, AGENT_SECTIONS } from "./assembly";
|
|
6
|
+
import { filterRelevantDecisions, filterRelevantStandards } from "./scoring";
|
|
7
|
+
import {
|
|
8
|
+
buildProductSection,
|
|
9
|
+
buildArchitectureSection,
|
|
10
|
+
buildStandardsSection,
|
|
11
|
+
buildDecisionsSection,
|
|
12
|
+
buildReasoningSection,
|
|
13
|
+
buildAlertsSection,
|
|
14
|
+
buildDiscoveriesSection,
|
|
15
|
+
buildPatternsSection,
|
|
16
|
+
buildUtilitiesSection,
|
|
17
|
+
buildGraphSection,
|
|
18
|
+
buildStackSection,
|
|
19
|
+
buildHintsSection,
|
|
20
|
+
} from "./sections";
|
|
21
|
+
|
|
22
|
+
// v9.0: Contexto minimo para subagent (max ~2KB)
|
|
23
|
+
const MAX_MINIMAL_CONTEXT = 2048;
|
|
24
|
+
|
|
25
|
+
export function getMinimalContextForSubagent(taskId: number): string {
|
|
26
|
+
initSchema();
|
|
27
|
+
const db = getDb();
|
|
28
|
+
|
|
29
|
+
const task = db.query("SELECT * FROM tasks WHERE id = ?").get(taskId) as any;
|
|
30
|
+
if (!task) return "ERRO: Task nao encontrada";
|
|
31
|
+
|
|
32
|
+
const spec = db.query("SELECT * FROM specs WHERE id = ?").get(task.spec_id) as any;
|
|
33
|
+
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(task.spec_id) as any;
|
|
34
|
+
|
|
35
|
+
const taskFiles = task.files ? JSON.parse(task.files) : [];
|
|
36
|
+
const domain = task.agent?.split("-")[0] || "all";
|
|
37
|
+
|
|
38
|
+
// 1. Standards REQUIRED apenas (nao recommended)
|
|
39
|
+
const requiredStandards = db.query(
|
|
40
|
+
`SELECT rule FROM standards
|
|
41
|
+
WHERE enforcement = 'required' AND (scope = 'all' OR scope = ?)
|
|
42
|
+
LIMIT 10`
|
|
43
|
+
).all(domain) as any[];
|
|
44
|
+
|
|
45
|
+
// 2. Blockers CRITICAL apenas
|
|
46
|
+
const criticalBlockers = db.query(
|
|
47
|
+
`SELECT content FROM knowledge
|
|
48
|
+
WHERE spec_id = ? AND severity = 'critical'
|
|
49
|
+
ORDER BY created_at DESC LIMIT 5`
|
|
50
|
+
).all(task.spec_id) as any[];
|
|
51
|
+
|
|
52
|
+
// 3. Decisoes da task anterior (dependency direta)
|
|
53
|
+
const dependsOn = task.depends_on ? JSON.parse(task.depends_on) : [];
|
|
54
|
+
let depDecisions: any[] = [];
|
|
55
|
+
if (dependsOn.length > 0) {
|
|
56
|
+
const placeholders = dependsOn.map(() => '?').join(',');
|
|
57
|
+
const depTasks = db.query(
|
|
58
|
+
`SELECT id FROM tasks WHERE spec_id = ? AND number IN (${placeholders})`
|
|
59
|
+
).all(task.spec_id, ...dependsOn) as any[];
|
|
60
|
+
|
|
61
|
+
for (const dt of depTasks) {
|
|
62
|
+
const reasoning = db.query(
|
|
63
|
+
`SELECT thought FROM reasoning_log
|
|
64
|
+
WHERE spec_id = ? AND task_id = ? AND category = 'recommendation'
|
|
65
|
+
ORDER BY created_at DESC LIMIT 2`
|
|
66
|
+
).all(task.spec_id, dt.id) as any[];
|
|
67
|
+
depDecisions.push(...reasoning);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Montar output minimo
|
|
72
|
+
let output = `## CONTEXTO MINIMO (Task #${task.number})
|
|
73
|
+
|
|
74
|
+
**Feature:** ${spec.name}
|
|
75
|
+
**Objetivo:** ${context?.objective || "N/A"}
|
|
76
|
+
**Arquivos:** ${taskFiles.join(", ") || "Nenhum especificado"}
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
if (requiredStandards.length > 0) {
|
|
80
|
+
output += `\n**Standards (OBRIGATORIOS):**\n${requiredStandards.map((s: any) => `- ${s.rule}`).join("\n")}\n`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (criticalBlockers.length > 0) {
|
|
84
|
+
output += `\n**BLOCKERS CRITICOS:**\n${criticalBlockers.map((b: any) => `[X] ${b.content}`).join("\n")}\n`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (depDecisions.length > 0) {
|
|
88
|
+
output += `\n**Recomendacoes de tasks anteriores:**\n${depDecisions.map((d: any) => `- ${d.thought}`).join("\n")}\n`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
output += `
|
|
92
|
+
**Contexto expandido**: Se precisar de mais contexto, execute:
|
|
93
|
+
codexa context detail standards # Todos os standards
|
|
94
|
+
codexa context detail decisions # Todas as decisoes
|
|
95
|
+
codexa context detail patterns # Patterns do projeto
|
|
96
|
+
codexa context detail knowledge # Knowledge completo
|
|
97
|
+
codexa context detail architecture # Analise arquitetural
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
// Truncar se exceder limite
|
|
101
|
+
if (output.length > MAX_MINIMAL_CONTEXT) {
|
|
102
|
+
output = output.substring(0, MAX_MINIMAL_CONTEXT - 100) + "\n\n[CONTEXTO TRUNCADO - use: codexa context detail <secao>]\n";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return output;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ═══════════════════════════════════════════════════════════════
|
|
109
|
+
// CONTEXT BUILDER (v9.0 — decomposed from v8.1 monolith)
|
|
110
|
+
// ═══════════════════════════════════════════════════════════════
|
|
111
|
+
|
|
112
|
+
function fetchContextData(taskId: number): ContextData | null {
|
|
113
|
+
const db = getDb();
|
|
114
|
+
|
|
115
|
+
const task = db.query("SELECT * FROM tasks WHERE id = ?").get(taskId) as any;
|
|
116
|
+
if (!task) return null;
|
|
117
|
+
|
|
118
|
+
const spec = db.query("SELECT * FROM specs WHERE id = ?").get(task.spec_id) as any;
|
|
119
|
+
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(task.spec_id) as any;
|
|
120
|
+
const project = db.query("SELECT * FROM project WHERE id = 'default'").get() as any;
|
|
121
|
+
|
|
122
|
+
// v8.4: Analise arquitetural (link explicito via analysis_id ou nome)
|
|
123
|
+
const archAnalysis = getArchitecturalAnalysisForSpec(spec.name, task.spec_id);
|
|
124
|
+
|
|
125
|
+
// Arquivos da task para filtrar contexto relevante
|
|
126
|
+
const taskFiles = task.files ? JSON.parse(task.files) : [];
|
|
127
|
+
const domain = task.agent?.split("-")[0] || "all";
|
|
128
|
+
|
|
129
|
+
// Decisoes relevantes (max 8, priorizando as que mencionam arquivos da task)
|
|
130
|
+
const allDecisions = db
|
|
131
|
+
.query("SELECT * FROM decisions WHERE spec_id = ? AND status = 'active' ORDER BY created_at DESC")
|
|
132
|
+
.all(task.spec_id) as any[];
|
|
133
|
+
const decisions = filterRelevantDecisions(allDecisions, taskFiles, 8);
|
|
134
|
+
|
|
135
|
+
// Standards required + recommended que se aplicam aos arquivos
|
|
136
|
+
const standards = db
|
|
137
|
+
.query(
|
|
138
|
+
`SELECT * FROM standards
|
|
139
|
+
WHERE (scope = 'all' OR scope = ?)
|
|
140
|
+
ORDER BY enforcement DESC, category`
|
|
141
|
+
)
|
|
142
|
+
.all(domain) as any[];
|
|
143
|
+
const relevantStandards = filterRelevantStandards(standards, taskFiles);
|
|
144
|
+
|
|
145
|
+
// Knowledge com caps e indicadores de truncamento
|
|
146
|
+
const allKnowledge = getKnowledgeForTask(task.spec_id, taskId);
|
|
147
|
+
const allCriticalKnowledge = allKnowledge.filter((k: any) => k.severity === 'critical' || k.severity === 'warning');
|
|
148
|
+
const criticalKnowledge = allCriticalKnowledge.slice(0, 20);
|
|
149
|
+
const truncatedCritical = allCriticalKnowledge.length - criticalKnowledge.length;
|
|
150
|
+
const allInfoKnowledge = allKnowledge.filter((k: any) => k.severity === 'info');
|
|
151
|
+
const infoKnowledge = allInfoKnowledge.slice(0, 10);
|
|
152
|
+
const truncatedInfo = allInfoKnowledge.length - infoKnowledge.length;
|
|
153
|
+
|
|
154
|
+
const productContext = db.query("SELECT * FROM product_context WHERE id = 'default'").get() as any;
|
|
155
|
+
const patterns = getPatternsForFiles(taskFiles);
|
|
156
|
+
|
|
157
|
+
// v8.2: Reasoning de tasks dependentes + todas tasks completas recentes
|
|
158
|
+
const dependsOn = task.depends_on ? JSON.parse(task.depends_on) : [];
|
|
159
|
+
const depReasoning: any[] = [];
|
|
160
|
+
const seenTaskIds = new Set<number>();
|
|
161
|
+
|
|
162
|
+
if (dependsOn.length > 0) {
|
|
163
|
+
const placeholders = dependsOn.map(() => '?').join(',');
|
|
164
|
+
const depTasks = db.query(
|
|
165
|
+
`SELECT id, number FROM tasks WHERE spec_id = ? AND number IN (${placeholders})`
|
|
166
|
+
).all(task.spec_id, ...dependsOn) as any[];
|
|
167
|
+
|
|
168
|
+
for (const depTask of depTasks) {
|
|
169
|
+
seenTaskIds.add(depTask.id);
|
|
170
|
+
const reasoning = db.query(
|
|
171
|
+
`SELECT category, thought FROM reasoning_log
|
|
172
|
+
WHERE spec_id = ? AND task_id = ?
|
|
173
|
+
AND category IN ('recommendation', 'decision', 'challenge')
|
|
174
|
+
ORDER BY
|
|
175
|
+
CASE importance WHEN 'critical' THEN 1 WHEN 'high' THEN 2 ELSE 3 END,
|
|
176
|
+
created_at DESC
|
|
177
|
+
LIMIT 3`
|
|
178
|
+
).all(task.spec_id, depTask.id) as any[];
|
|
179
|
+
for (const r of reasoning) {
|
|
180
|
+
depReasoning.push({ ...r, fromTask: depTask.number });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const completedTasks = db.query(
|
|
186
|
+
`SELECT t.id, t.number FROM tasks t
|
|
187
|
+
WHERE t.spec_id = ? AND t.status = 'done' AND t.id != ?
|
|
188
|
+
ORDER BY t.completed_at DESC LIMIT 10`
|
|
189
|
+
).all(task.spec_id, taskId) as any[];
|
|
190
|
+
|
|
191
|
+
for (const ct of completedTasks) {
|
|
192
|
+
if (seenTaskIds.has(ct.id)) continue;
|
|
193
|
+
const reasoning = db.query(
|
|
194
|
+
`SELECT category, thought FROM reasoning_log
|
|
195
|
+
WHERE spec_id = ? AND task_id = ?
|
|
196
|
+
AND category IN ('recommendation', 'challenge')
|
|
197
|
+
AND importance IN ('critical', 'high')
|
|
198
|
+
ORDER BY
|
|
199
|
+
CASE importance WHEN 'critical' THEN 1 ELSE 2 END,
|
|
200
|
+
created_at DESC
|
|
201
|
+
LIMIT 2`
|
|
202
|
+
).all(task.spec_id, ct.id) as any[];
|
|
203
|
+
for (const r of reasoning) {
|
|
204
|
+
depReasoning.push({ ...r, fromTask: ct.number });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const libContexts = db.query(
|
|
209
|
+
"SELECT lib_name, version FROM lib_contexts ORDER BY lib_name LIMIT 10"
|
|
210
|
+
).all() as any[];
|
|
211
|
+
|
|
212
|
+
const graphDecisions: any[] = [];
|
|
213
|
+
for (const file of taskFiles) {
|
|
214
|
+
try {
|
|
215
|
+
const related = getRelatedDecisions(file, "file");
|
|
216
|
+
for (const d of related) {
|
|
217
|
+
if (!graphDecisions.find((gd: any) => gd.id === d.id)) {
|
|
218
|
+
graphDecisions.push(d);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} catch { /* ignore if graph empty */ }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const discoveredPatterns = context?.patterns ? JSON.parse(context.patterns) : [];
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
db, task, spec, context, project, taskFiles, domain, archAnalysis,
|
|
228
|
+
decisions, allDecisions, relevantStandards,
|
|
229
|
+
criticalKnowledge, truncatedCritical, infoKnowledge, truncatedInfo,
|
|
230
|
+
productContext, patterns, depReasoning, libContexts,
|
|
231
|
+
graphDecisions, discoveredPatterns,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ── Main Entry Point ──────────────────────────────────────────
|
|
236
|
+
|
|
237
|
+
export function getContextForSubagent(taskId: number): string {
|
|
238
|
+
initSchema();
|
|
239
|
+
|
|
240
|
+
const data = fetchContextData(taskId);
|
|
241
|
+
if (!data) return "ERRO: Task nao encontrada";
|
|
242
|
+
|
|
243
|
+
const header = `## CONTEXTO (Task #${data.task.number})
|
|
244
|
+
|
|
245
|
+
**Feature:** ${data.spec.name}
|
|
246
|
+
**Objetivo:** ${data.context?.objective || "N/A"}
|
|
247
|
+
**Arquivos:** ${data.taskFiles.join(", ") || "Nenhum especificado"}
|
|
248
|
+
`;
|
|
249
|
+
|
|
250
|
+
const allSections = [
|
|
251
|
+
buildProductSection(data),
|
|
252
|
+
buildArchitectureSection(data),
|
|
253
|
+
buildStandardsSection(data),
|
|
254
|
+
buildDecisionsSection(data),
|
|
255
|
+
buildReasoningSection(data),
|
|
256
|
+
buildAlertsSection(data),
|
|
257
|
+
buildDiscoveriesSection(data),
|
|
258
|
+
buildPatternsSection(data),
|
|
259
|
+
buildUtilitiesSection(data),
|
|
260
|
+
buildGraphSection(data),
|
|
261
|
+
buildStackSection(data),
|
|
262
|
+
buildHintsSection(data),
|
|
263
|
+
].filter((s): s is ContextSection => s !== null);
|
|
264
|
+
|
|
265
|
+
// v9.3: Filtrar secoes por tipo de agente
|
|
266
|
+
const agentType = data.task.agent || "";
|
|
267
|
+
const allowedSections = AGENT_SECTIONS[agentType];
|
|
268
|
+
const sections = allowedSections
|
|
269
|
+
? allSections.filter(s => allowedSections.includes(s.name))
|
|
270
|
+
: allSections;
|
|
271
|
+
|
|
272
|
+
return assembleSections(header, sections);
|
|
273
|
+
}
|
package/context/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Re-exports for backward compatibility
|
|
2
|
+
export { getContextForSubagent, getMinimalContextForSubagent } from "./generator";
|
|
3
|
+
export { assembleSections, MAX_CONTEXT_SIZE, AGENT_SECTIONS } from "./assembly";
|
|
4
|
+
export type { ContextSection, ContextData } from "./assembly";
|
|
5
|
+
export { filterRelevantDecisions, filterRelevantStandards } from "./scoring";
|
|
6
|
+
export {
|
|
7
|
+
buildProductSection,
|
|
8
|
+
buildArchitectureSection,
|
|
9
|
+
buildStandardsSection,
|
|
10
|
+
buildDecisionsSection,
|
|
11
|
+
buildReasoningSection,
|
|
12
|
+
buildAlertsSection,
|
|
13
|
+
buildDiscoveriesSection,
|
|
14
|
+
buildPatternsSection,
|
|
15
|
+
buildUtilitiesSection,
|
|
16
|
+
buildGraphSection,
|
|
17
|
+
buildStackSection,
|
|
18
|
+
buildHintsSection,
|
|
19
|
+
} from "./sections";
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// v8.3: Filtrar decisoes relevantes com scoring melhorado
|
|
2
|
+
export function filterRelevantDecisions(decisions: any[], taskFiles: string[], maxCount: number): any[] {
|
|
3
|
+
if (decisions.length === 0) return [];
|
|
4
|
+
if (taskFiles.length === 0) return decisions.slice(0, maxCount);
|
|
5
|
+
|
|
6
|
+
// Extrair keywords semanticas dos arquivos da task
|
|
7
|
+
const fileExtensions = new Set(taskFiles.map(f => f.split('.').pop()?.toLowerCase()).filter(Boolean));
|
|
8
|
+
const fileDirs = new Set(taskFiles.flatMap(f => f.split('/').slice(0, -1)).filter(Boolean));
|
|
9
|
+
|
|
10
|
+
// Keywords de dominio para scoring contextual
|
|
11
|
+
const domainKeywords: Record<string, string[]> = {
|
|
12
|
+
frontend: ['component', 'page', 'layout', 'css', 'style', 'ui', 'react', 'next', 'hook'],
|
|
13
|
+
backend: ['api', 'route', 'handler', 'middleware', 'server', 'endpoint', 'controller'],
|
|
14
|
+
database: ['schema', 'migration', 'query', 'table', 'index', 'sql', 'model'],
|
|
15
|
+
testing: ['test', 'spec', 'mock', 'fixture', 'assert', 'jest', 'vitest'],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const scored = decisions.map((d) => {
|
|
19
|
+
let score = 0;
|
|
20
|
+
const combined = `${d.decision || ''} ${d.title || ''} ${d.rationale || ''}`.toLowerCase();
|
|
21
|
+
|
|
22
|
+
// Arquivo exato e diretorio (+10/+5)
|
|
23
|
+
for (const file of taskFiles) {
|
|
24
|
+
const fileName = file.split("/").pop() || file;
|
|
25
|
+
const dirName = file.split("/").slice(-2, -1)[0] || "";
|
|
26
|
+
|
|
27
|
+
if (combined.includes(fileName.toLowerCase())) score += 10;
|
|
28
|
+
if (dirName && combined.includes(dirName.toLowerCase())) score += 5;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// v8.3: Extensao dos arquivos (+3)
|
|
32
|
+
for (const ext of fileExtensions) {
|
|
33
|
+
if (combined.includes(`.${ext}`)) { score += 3; break; }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// v8.3: Diretorio mencionado (+4)
|
|
37
|
+
for (const dir of fileDirs) {
|
|
38
|
+
if (combined.includes(dir.toLowerCase())) { score += 4; break; }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// v8.3: Keywords de dominio (+2)
|
|
42
|
+
const taskCombined = taskFiles.join(' ').toLowerCase();
|
|
43
|
+
for (const [, keywords] of Object.entries(domainKeywords)) {
|
|
44
|
+
for (const kw of keywords) {
|
|
45
|
+
if (combined.includes(kw) && taskCombined.includes(kw)) {
|
|
46
|
+
score += 2;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Recencia (+3/+1)
|
|
53
|
+
const age = Date.now() - new Date(d.created_at).getTime();
|
|
54
|
+
const hoursOld = age / (1000 * 60 * 60);
|
|
55
|
+
if (hoursOld < 1) score += 3;
|
|
56
|
+
else if (hoursOld < 24) score += 1;
|
|
57
|
+
|
|
58
|
+
return { ...d, _relevanceScore: score };
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return scored
|
|
62
|
+
.sort((a, b) => b._relevanceScore - a._relevanceScore)
|
|
63
|
+
.slice(0, maxCount)
|
|
64
|
+
.map(({ _relevanceScore, ...d }) => d);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// v8.0: Filtrar standards relevantes para os arquivos da task
|
|
68
|
+
export function filterRelevantStandards(standards: any[], taskFiles: string[]): any[] {
|
|
69
|
+
if (standards.length === 0) return [];
|
|
70
|
+
if (taskFiles.length === 0) return standards;
|
|
71
|
+
|
|
72
|
+
// Extrair extensoes e diretorios dos arquivos da task
|
|
73
|
+
const extensions = new Set(taskFiles.map((f) => {
|
|
74
|
+
const ext = f.split(".").pop();
|
|
75
|
+
return ext ? `.${ext}` : "";
|
|
76
|
+
}).filter(Boolean));
|
|
77
|
+
|
|
78
|
+
const directories = new Set(taskFiles.map((f) => {
|
|
79
|
+
const parts = f.split("/");
|
|
80
|
+
return parts.length > 1 ? parts.slice(0, -1).join("/") : "";
|
|
81
|
+
}).filter(Boolean));
|
|
82
|
+
|
|
83
|
+
// Filtrar standards que se aplicam
|
|
84
|
+
return standards.filter((s) => {
|
|
85
|
+
// Standards de naming sempre aplicam
|
|
86
|
+
if (s.category === "naming") return true;
|
|
87
|
+
|
|
88
|
+
// Standards de code aplicam se mencionam extensao dos arquivos
|
|
89
|
+
if (s.category === "code") {
|
|
90
|
+
for (const ext of extensions) {
|
|
91
|
+
if (s.rule?.includes(ext) || s.scope === "all") return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Standards de structure aplicam se mencionam diretorio
|
|
96
|
+
if (s.category === "structure") {
|
|
97
|
+
for (const dir of directories) {
|
|
98
|
+
if (s.rule?.includes(dir)) return true;
|
|
99
|
+
}
|
|
100
|
+
return s.scope === "all";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Outros standards: incluir se scope combina
|
|
104
|
+
return true;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { getUtilitiesForContext, getAgentHints } from "../db/schema";
|
|
2
|
+
import type { ContextSection, ContextData } from "./assembly";
|
|
3
|
+
|
|
4
|
+
// ── Section Builders ──────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export function buildProductSection(data: ContextData): ContextSection | null {
|
|
7
|
+
if (!data.productContext) return null;
|
|
8
|
+
|
|
9
|
+
let content = `
|
|
10
|
+
### PRODUTO
|
|
11
|
+
- **Problema:** ${data.productContext.problem || "N/A"}
|
|
12
|
+
- **Usuarios:** ${data.productContext.target_users || "N/A"}`;
|
|
13
|
+
if (data.productContext.constraints) {
|
|
14
|
+
try {
|
|
15
|
+
const constraints = JSON.parse(data.productContext.constraints);
|
|
16
|
+
if (constraints.length > 0) {
|
|
17
|
+
content += `\n- **Restricoes:** ${constraints.slice(0, 3).join("; ")}${constraints.length > 3 ? ` [+${constraints.length - 3} mais]` : ''}`;
|
|
18
|
+
}
|
|
19
|
+
} catch { /* ignore parse errors */ }
|
|
20
|
+
}
|
|
21
|
+
content += "\n";
|
|
22
|
+
|
|
23
|
+
return { name: "PRODUTO", content, priority: 7 };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function buildArchitectureSection(data: ContextData): ContextSection | null {
|
|
27
|
+
if (!data.archAnalysis) return null;
|
|
28
|
+
|
|
29
|
+
let content = `
|
|
30
|
+
### ARQUITETURA (${data.archAnalysis.id})`;
|
|
31
|
+
if (data.archAnalysis.approach) {
|
|
32
|
+
const approachPreview = data.archAnalysis.approach.length > 500
|
|
33
|
+
? data.archAnalysis.approach.substring(0, 500) + "..."
|
|
34
|
+
: data.archAnalysis.approach;
|
|
35
|
+
content += `\n**Abordagem:** ${approachPreview}`;
|
|
36
|
+
}
|
|
37
|
+
if (data.archAnalysis.risks) {
|
|
38
|
+
try {
|
|
39
|
+
const risks = JSON.parse(data.archAnalysis.risks);
|
|
40
|
+
if (risks.length > 0) {
|
|
41
|
+
const highRisks = risks.filter((r: any) => r.impact === 'high' || r.probability === 'high');
|
|
42
|
+
const risksToShow = highRisks.length > 0 ? highRisks.slice(0, 3) : risks.slice(0, 3);
|
|
43
|
+
content += `\n**Riscos:**`;
|
|
44
|
+
for (const r of risksToShow) {
|
|
45
|
+
content += `\n - ${r.description} (${r.probability}/${r.impact}) -> ${r.mitigation}`;
|
|
46
|
+
}
|
|
47
|
+
if (risks.length > risksToShow.length) {
|
|
48
|
+
content += `\n [+${risks.length - risksToShow.length} mais riscos]`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch { /* ignore */ }
|
|
52
|
+
}
|
|
53
|
+
if (data.archAnalysis.decisions) {
|
|
54
|
+
try {
|
|
55
|
+
const archDecisions = JSON.parse(data.archAnalysis.decisions);
|
|
56
|
+
if (archDecisions.length > 0) {
|
|
57
|
+
content += `\n**Decisoes arquiteturais:**`;
|
|
58
|
+
for (const d of archDecisions.slice(0, 5)) {
|
|
59
|
+
content += `\n - ${d.decision}: ${d.rationale || ''}`;
|
|
60
|
+
}
|
|
61
|
+
if (archDecisions.length > 5) {
|
|
62
|
+
content += `\n [+${archDecisions.length - 5} mais]`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch { /* ignore */ }
|
|
66
|
+
}
|
|
67
|
+
content += "\n";
|
|
68
|
+
|
|
69
|
+
return { name: "ARQUITETURA", content, priority: 3 };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildStandardsSection(data: ContextData): ContextSection {
|
|
73
|
+
const requiredStds = data.relevantStandards.filter((s: any) => s.enforcement === 'required');
|
|
74
|
+
const recommendedStds = data.relevantStandards.filter((s: any) => s.enforcement === 'recommended');
|
|
75
|
+
|
|
76
|
+
let content = `
|
|
77
|
+
### STANDARDS (${data.relevantStandards.length})`;
|
|
78
|
+
if (requiredStds.length > 0) {
|
|
79
|
+
content += `\n**Obrigatorios:**\n${requiredStds.map((s: any) => `- ${s.rule}`).join("\n")}`;
|
|
80
|
+
}
|
|
81
|
+
if (recommendedStds.length > 0) {
|
|
82
|
+
content += `\n**Recomendados:**\n${recommendedStds.map((s: any) => `- ${s.rule}`).join("\n")}`;
|
|
83
|
+
}
|
|
84
|
+
if (data.relevantStandards.length === 0) {
|
|
85
|
+
content += "\nNenhum standard aplicavel";
|
|
86
|
+
}
|
|
87
|
+
content += "\n";
|
|
88
|
+
|
|
89
|
+
return { name: "STANDARDS", content, priority: 1 };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function buildDecisionsSection(data: ContextData): ContextSection {
|
|
93
|
+
const truncatedDecisions = data.allDecisions.length - data.decisions.length;
|
|
94
|
+
const content = `
|
|
95
|
+
### DECISOES (${data.decisions.length}${truncatedDecisions > 0 ? ` [+${truncatedDecisions} mais - use: decisions list]` : ''})
|
|
96
|
+
${data.decisions.length > 0 ? data.decisions.map((d) => `- **${d.title}**: ${d.decision}`).join("\n") : "Nenhuma"}
|
|
97
|
+
`;
|
|
98
|
+
return { name: "DECISOES", content, priority: 4 };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function buildReasoningSection(data: ContextData): ContextSection | null {
|
|
102
|
+
if (data.depReasoning.length === 0) return null;
|
|
103
|
+
|
|
104
|
+
const content = `
|
|
105
|
+
### CONTEXTO DE TASKS ANTERIORES
|
|
106
|
+
${data.depReasoning.map((r: any) => `- [Task #${r.fromTask}/${r.category}] ${r.thought}`).join("\n")}
|
|
107
|
+
`;
|
|
108
|
+
return { name: "CONTEXTO DE TASKS ANTERIORES", content, priority: 5 };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function buildAlertsSection(data: ContextData): ContextSection | null {
|
|
112
|
+
if (data.criticalKnowledge.length === 0) return null;
|
|
113
|
+
|
|
114
|
+
const severityIcon: Record<string, string> = { warning: "!!", critical: "XX" };
|
|
115
|
+
const content = `
|
|
116
|
+
### ALERTAS (${data.criticalKnowledge.length}${data.truncatedCritical > 0 ? ` [+${data.truncatedCritical} mais - use: knowledge list --severity warning]` : ''})
|
|
117
|
+
${data.criticalKnowledge.map((k: any) => `[${severityIcon[k.severity] || "!"}] ${k.content}`).join("\n")}
|
|
118
|
+
`;
|
|
119
|
+
return { name: "ALERTAS", content, priority: 2 };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function buildDiscoveriesSection(data: ContextData): ContextSection | null {
|
|
123
|
+
if (data.infoKnowledge.length === 0) return null;
|
|
124
|
+
|
|
125
|
+
const content = `
|
|
126
|
+
### DISCOVERIES DE TASKS ANTERIORES (${data.infoKnowledge.length}${data.truncatedInfo > 0 ? ` [+${data.truncatedInfo} mais - use: knowledge list]` : ''})
|
|
127
|
+
${data.infoKnowledge.map((k: any) => `- ${k.content}`).join("\n")}
|
|
128
|
+
`;
|
|
129
|
+
return { name: "DISCOVERIES", content, priority: 8 };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function buildPatternsSection(data: ContextData): ContextSection | null {
|
|
133
|
+
let content = "";
|
|
134
|
+
|
|
135
|
+
if (data.patterns.length > 0) {
|
|
136
|
+
content += `
|
|
137
|
+
### PATTERNS DO PROJETO (${data.patterns.length})
|
|
138
|
+
${data.patterns.map((p: any) => {
|
|
139
|
+
const tmpl = p.template || "";
|
|
140
|
+
const preview = tmpl.length > 200 ? tmpl.substring(0, 200) + `... [truncado de ${tmpl.length} chars]` : tmpl;
|
|
141
|
+
return `- **${p.name}** (${p.category}): ${preview || p.description || "Sem template"}`;
|
|
142
|
+
}).join("\n")}
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (data.discoveredPatterns.length > 0) {
|
|
147
|
+
const patternsToShow = data.discoveredPatterns.slice(-10);
|
|
148
|
+
content += `
|
|
149
|
+
### PATTERNS DESCOBERTOS (${data.discoveredPatterns.length})
|
|
150
|
+
${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")}
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!content) return null;
|
|
155
|
+
return { name: "PATTERNS", content, priority: 9 };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function buildUtilitiesSection(data: ContextData): ContextSection | null {
|
|
159
|
+
try {
|
|
160
|
+
const taskDirs = [...new Set(data.taskFiles.map((f: string) => {
|
|
161
|
+
const parts = f.replace(/\\/g, "/").split("/");
|
|
162
|
+
return parts.slice(0, -1).join("/");
|
|
163
|
+
}).filter(Boolean))];
|
|
164
|
+
|
|
165
|
+
const agentScope = data.task.agent?.split("-")[0] || undefined;
|
|
166
|
+
let relevantUtilities = getUtilitiesForContext(taskDirs, undefined, 15);
|
|
167
|
+
|
|
168
|
+
if (relevantUtilities.length < 5 && agentScope) {
|
|
169
|
+
const scopeUtils = getUtilitiesForContext([], agentScope, 15);
|
|
170
|
+
const existingKeys = new Set(relevantUtilities.map((u: any) => `${u.file_path}:${u.utility_name}`));
|
|
171
|
+
for (const u of scopeUtils) {
|
|
172
|
+
if (!existingKeys.has(`${u.file_path}:${u.utility_name}`)) {
|
|
173
|
+
relevantUtilities.push(u);
|
|
174
|
+
}
|
|
175
|
+
if (relevantUtilities.length >= 15) break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (relevantUtilities.length === 0) return null;
|
|
180
|
+
|
|
181
|
+
const totalCount = (data.db.query("SELECT COUNT(*) as c FROM project_utilities").get() as any)?.c || 0;
|
|
182
|
+
const truncated = totalCount - relevantUtilities.length;
|
|
183
|
+
const content = `
|
|
184
|
+
### UTILITIES EXISTENTES (${relevantUtilities.length}${truncated > 0 ? ` [+${truncated} mais]` : ''})
|
|
185
|
+
**REGRA DRY**: Reutilize ao inves de recriar. Importe do arquivo existente.
|
|
186
|
+
${relevantUtilities.map((u: any) => {
|
|
187
|
+
const sig = u.signature ? ` ${u.signature}` : '';
|
|
188
|
+
return `- **${u.utility_name}** [${u.utility_type}]${sig} <- \`${u.file_path}\``;
|
|
189
|
+
}).join("\n")}
|
|
190
|
+
`;
|
|
191
|
+
return { name: "UTILITIES", content, priority: 8 };
|
|
192
|
+
} catch { /* tabela pode nao existir ainda */ }
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function buildGraphSection(data: ContextData): ContextSection | null {
|
|
197
|
+
let content = "";
|
|
198
|
+
|
|
199
|
+
if (data.graphDecisions.length > 0) {
|
|
200
|
+
content += `
|
|
201
|
+
### DECISOES QUE AFETAM SEUS ARQUIVOS (${data.graphDecisions.length})
|
|
202
|
+
${data.graphDecisions.map((d: any) => `- **${d.title}**: ${d.decision}`).join("\n")}
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!content) return null;
|
|
207
|
+
return { name: "GRAPH", content, priority: 6 };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function buildStackSection(data: ContextData): ContextSection | null {
|
|
211
|
+
let content = "";
|
|
212
|
+
|
|
213
|
+
if (data.project) {
|
|
214
|
+
const stack = JSON.parse(data.project.stack);
|
|
215
|
+
const allStackEntries = Object.entries(stack);
|
|
216
|
+
const mainStack = allStackEntries.slice(0, 6);
|
|
217
|
+
content += `
|
|
218
|
+
### STACK
|
|
219
|
+
${mainStack.map(([k, v]) => `${k}: ${v}`).join(" | ")}${allStackEntries.length > 6 ? ` [+${allStackEntries.length - 6} mais]` : ''}
|
|
220
|
+
`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (data.libContexts.length > 0) {
|
|
224
|
+
content += `
|
|
225
|
+
### BIBLIOTECAS
|
|
226
|
+
${data.libContexts.map((l: any) => `- ${l.lib_name}${l.version ? ` v${l.version}` : ""}`).join("\n")}
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!content) return null;
|
|
231
|
+
return { name: "STACK", content, priority: 11 };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function buildHintsSection(data: ContextData): ContextSection | null {
|
|
235
|
+
const agentType = data.task.agent;
|
|
236
|
+
if (!agentType) return null;
|
|
237
|
+
|
|
238
|
+
const hints = getAgentHints(agentType);
|
|
239
|
+
if (hints.length === 0) return null;
|
|
240
|
+
|
|
241
|
+
const content = `
|
|
242
|
+
### HISTORICO DO AGENTE (${agentType})
|
|
243
|
+
${hints.map(h => `- ${h}`).join("\n")}
|
|
244
|
+
`;
|
|
245
|
+
return { name: "HINTS", content, priority: 10 };
|
|
246
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codexa/cli",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.7",
|
|
4
4
|
"description": "Orchestrated workflow system for Claude Code - manages feature development through parallel subagents with structured phases, gates, and quality enforcement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
"workflow.ts",
|
|
11
11
|
"errors.ts",
|
|
12
12
|
"commands/",
|
|
13
|
+
"context/",
|
|
13
14
|
"db/",
|
|
14
15
|
"gates/",
|
|
15
16
|
"protocol/",
|
|
16
|
-
"detectors/"
|
|
17
|
+
"detectors/",
|
|
18
|
+
"templates/"
|
|
17
19
|
],
|
|
18
20
|
"scripts": {
|
|
19
21
|
"cli": "bun run workflow.ts",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
|
|
4
|
+
const TEMPLATES_DIR = join(dirname(import.meta.path), ".");
|
|
5
|
+
|
|
6
|
+
const templateCache = new Map<string, string>();
|
|
7
|
+
|
|
8
|
+
export function loadTemplate(name: string, vars: Record<string, string> = {}): string {
|
|
9
|
+
let content = templateCache.get(name);
|
|
10
|
+
if (!content) {
|
|
11
|
+
const filePath = join(TEMPLATES_DIR, `${name}.md`);
|
|
12
|
+
content = readFileSync(filePath, "utf-8");
|
|
13
|
+
templateCache.set(name, content);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let result = content;
|
|
17
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
18
|
+
result = result.replaceAll(`{{${key}}}`, value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return result.trim();
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
2
|
+
║ DIRETIVA CRITICA: USE Write/Edit PARA CRIAR OS ARQUIVOS ║
|
|
3
|
+
║ NAO descreva. NAO planeje. NAO simule. EXECUTE AGORA. ║
|
|
4
|
+
║ Se retornar sem usar Write/Edit, a task FALHA. ║
|
|
5
|
+
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
6
|
+
|
|
7
|
+
ARQUIVOS QUE VOCE DEVE CRIAR (use Write para cada um):
|
|
8
|
+
{{filesList}}
|
|
9
|
+
|
|
10
|
+
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
11
|
+
║ POLLING OBRIGATORIO: Verifique blockers a cada 3 arquivos modificados ║
|
|
12
|
+
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
13
|
+
|
|
14
|
+
ANTES de criar o 4o, 7o, 10o arquivo (a cada 3), execute:
|
|
15
|
+
codexa knowledge list --severity critical --unread
|
|
16
|
+
|
|
17
|
+
Se retornar QUALQUER blocker:
|
|
18
|
+
1. PARE imediatamente
|
|
19
|
+
2. Retorne com status "blocked" e inclua o blocker encontrado
|
|
20
|
+
3. NAO continue criando arquivos apos encontrar blocker
|
|
21
|
+
|
|
22
|
+
CHECKLIST OBRIGATORIO (verifique ANTES de retornar):
|
|
23
|
+
- [ ] Usei Write ou Edit para criar/modificar arquivos?
|
|
24
|
+
- [ ] Verifiquei blockers a cada 3 arquivos?
|
|
25
|
+
- [ ] Os arquivos que vou listar em files_created EXISTEM no disco?
|
|
26
|
+
|
|
27
|
+
Se nao marcou todos os items, PARE e corrija AGORA.
|
|
28
|
+
|
|
29
|
+
CONTEXTO ON-DEMAND: Se precisar de mais contexto alem do fornecido, execute:
|
|
30
|
+
codexa context detail standards # Regras do projeto
|
|
31
|
+
codexa context detail decisions # Decisoes tomadas
|
|
32
|
+
codexa context detail patterns # Patterns de codigo
|
|
33
|
+
codexa context detail knowledge # Discoveries de outras tasks
|
|
34
|
+
NAO execute todos - apenas o que for NECESSARIO para sua task.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
FORMATO DE RETORNO (apos criar os arquivos):
|
|
2
|
+
{
|
|
3
|
+
"status": "completed | blocked | needs_decision",
|
|
4
|
+
"summary": "Resumo do que foi feito (10-500 chars)",
|
|
5
|
+
"files_created": ["path/arquivo.ts"],
|
|
6
|
+
"files_modified": ["path/outro.ts"],
|
|
7
|
+
"reasoning": {
|
|
8
|
+
"approach": "OBRIGATORIO (min 20 chars): Como voce abordou o problema e POR QUE tomou essas decisoes",
|
|
9
|
+
"challenges": ["Desafios encontrados"],
|
|
10
|
+
"recommendations": "Sugestoes para proximas tasks"
|
|
11
|
+
},
|
|
12
|
+
"patterns_discovered": ["Pattern identificado"],
|
|
13
|
+
"decisions_made": [{"title": "...", "decision": "..."}],
|
|
14
|
+
"blockers": ["Se status != completed"],
|
|
15
|
+
"knowledge_to_broadcast": [{"category": "discovery|pattern|constraint", "content": "...", "severity": "info|warning|critical"}]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ATENCAO: O campo "reasoning.approach" e OBRIGATORIO para status "completed".
|
|
19
|
+
Se retornar sem ele, Gate 4.4 BLOQUEIA a finalizacao da task.
|
|
20
|
+
Descreva COMO abordou o problema, nao apenas O QUE fez.
|
|
21
|
+
|
|
22
|
+
Se NAO conseguir criar arquivos (sem permissao, sem ferramentas), retorne:
|
|
23
|
+
{
|
|
24
|
+
"status": "blocked",
|
|
25
|
+
"blockers": ["Descreva por que nao conseguiu criar os arquivos"]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Veja .claude/agents/PROTOCOL.md para detalhes completos.
|
|
29
|
+
{{patternsNote}}
|