@codexa/cli 9.0.1 → 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 +25 -1
- package/workflow.ts +102 -21
package/commands/task.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { getDb } from "../db/connection";
|
|
2
|
-
import { initSchema, getPatternsForFiles, getPatternsByScope,
|
|
2
|
+
import { initSchema, getPatternsForFiles, getPatternsByScope, getRecentReasoning, claimTask } from "../db/schema";
|
|
3
3
|
import { enforceGate } from "../gates/validator";
|
|
4
4
|
import { parseSubagentReturn, formatValidationErrors } from "../protocol/subagent-protocol";
|
|
5
5
|
import { processSubagentReturn, formatProcessResult } from "../protocol/process-return";
|
|
6
6
|
import { getContextForSubagent, getMinimalContextForSubagent } from "./utils";
|
|
7
7
|
import { getUnreadKnowledgeForTask } from "./knowledge";
|
|
8
|
+
import { loadTemplate } from "../templates/loader";
|
|
9
|
+
import { TaskStateError, ValidationError, KnowledgeBlockError } from "../errors";
|
|
8
10
|
|
|
9
11
|
export function taskNext(json: boolean = false): void {
|
|
10
12
|
initSchema();
|
|
@@ -17,11 +19,9 @@ export function taskNext(json: boolean = false): void {
|
|
|
17
19
|
if (!spec) {
|
|
18
20
|
if (json) {
|
|
19
21
|
console.log(JSON.stringify({ available: [], message: "Nenhuma feature em implementacao" }));
|
|
20
|
-
|
|
21
|
-
console.error("\nNenhuma feature em fase de implementacao.");
|
|
22
|
-
console.error("Aprove o plano com: check approve\n");
|
|
22
|
+
return;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
throw new TaskStateError("Nenhuma feature em fase de implementacao.\nAprove o plano com: check approve");
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Buscar tasks pendentes cujas dependencias estao todas concluidas
|
|
@@ -119,20 +119,19 @@ export function taskStart(ids: string, json: boolean = false, fullContext: boole
|
|
|
119
119
|
const task = db.query("SELECT * FROM tasks WHERE id = ?").get(taskId) as any;
|
|
120
120
|
|
|
121
121
|
if (!task) {
|
|
122
|
-
|
|
123
|
-
process.exit(2);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (task.status !== "pending") {
|
|
127
|
-
console.error(`\nTask #${task.number} nao esta pendente (status: ${task.status}).\n`);
|
|
128
|
-
process.exit(2);
|
|
122
|
+
throw new TaskStateError(`Task #${taskId} nao encontrada.`);
|
|
129
123
|
}
|
|
130
124
|
|
|
131
125
|
// Validar dependencias para esta task especifica
|
|
132
126
|
enforceGate("task-start", { taskId });
|
|
133
127
|
|
|
134
|
-
//
|
|
135
|
-
|
|
128
|
+
// Claim atomico: UPDATE ... WHERE status = 'pending'
|
|
129
|
+
if (!claimTask(taskId)) {
|
|
130
|
+
const current = db.query("SELECT status FROM tasks WHERE id = ?").get(taskId) as any;
|
|
131
|
+
throw new TaskStateError(
|
|
132
|
+
`Task #${task.number} nao pode ser iniciada (status atual: ${current?.status || "desconhecido"}).`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
136
135
|
|
|
137
136
|
startedTasks.push(task);
|
|
138
137
|
}
|
|
@@ -233,77 +232,15 @@ export function taskStart(ids: string, json: boolean = false, fullContext: boole
|
|
|
233
232
|
// NOVO v7.4: Implementation patterns extraidos do projeto
|
|
234
233
|
implementationPatterns: formattedPatterns,
|
|
235
234
|
// Contexto para o SUBAGENT (o orquestrador deve passar isso via Task tool)
|
|
236
|
-
subagentContext:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
║ NAO descreva. NAO planeje. NAO simule. EXECUTE AGORA. ║
|
|
240
|
-
║ Se retornar sem usar Write/Edit, a task FALHA. ║
|
|
241
|
-
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
242
|
-
|
|
243
|
-
ARQUIVOS QUE VOCE DEVE CRIAR (use Write para cada um):
|
|
244
|
-
${taskFiles.map(f => ` - ${f}`).join('\n') || ' (nenhum arquivo especificado - analise o contexto)'}
|
|
245
|
-
|
|
246
|
-
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
247
|
-
║ POLLING OBRIGATORIO: Verifique blockers a cada 3 arquivos modificados ║
|
|
248
|
-
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
249
|
-
|
|
250
|
-
ANTES de criar o 4o, 7o, 10o arquivo (a cada 3), execute:
|
|
251
|
-
codexa knowledge list --severity critical --unread
|
|
252
|
-
|
|
253
|
-
Se retornar QUALQUER blocker:
|
|
254
|
-
1. PARE imediatamente
|
|
255
|
-
2. Retorne com status "blocked" e inclua o blocker encontrado
|
|
256
|
-
3. NAO continue criando arquivos apos encontrar blocker
|
|
257
|
-
|
|
258
|
-
CHECKLIST OBRIGATORIO (verifique ANTES de retornar):
|
|
259
|
-
- [ ] Usei Write ou Edit para criar/modificar arquivos?
|
|
260
|
-
- [ ] Verifiquei blockers a cada 3 arquivos?
|
|
261
|
-
- [ ] Os arquivos que vou listar em files_created EXISTEM no disco?
|
|
262
|
-
|
|
263
|
-
Se nao marcou todos os items, PARE e corrija AGORA.
|
|
264
|
-
|
|
265
|
-
CONTEXTO ON-DEMAND: Se precisar de mais contexto alem do fornecido, execute:
|
|
266
|
-
codexa context detail standards # Regras do projeto
|
|
267
|
-
codexa context detail decisions # Decisoes tomadas
|
|
268
|
-
codexa context detail patterns # Patterns de codigo
|
|
269
|
-
codexa context detail knowledge # Discoveries de outras tasks
|
|
270
|
-
NAO execute todos - apenas o que for NECESSARIO para sua task.
|
|
271
|
-
`.trim(),
|
|
235
|
+
subagentContext: loadTemplate("subagent-context", {
|
|
236
|
+
filesList: taskFiles.map(f => ` - ${f}`).join('\n') || ' (nenhum arquivo especificado - analise o contexto)',
|
|
237
|
+
}),
|
|
272
238
|
// Instrucoes de retorno para o SUBAGENT
|
|
273
|
-
subagentReturnProtocol:
|
|
274
|
-
|
|
275
|
-
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
"files_created": ["path/arquivo.ts"],
|
|
279
|
-
"files_modified": ["path/outro.ts"],
|
|
280
|
-
"reasoning": {
|
|
281
|
-
"approach": "OBRIGATORIO (min 20 chars): Como voce abordou o problema e POR QUE tomou essas decisoes",
|
|
282
|
-
"challenges": ["Desafios encontrados"],
|
|
283
|
-
"recommendations": "Sugestoes para proximas tasks"
|
|
284
|
-
},
|
|
285
|
-
"patterns_discovered": ["Pattern identificado"],
|
|
286
|
-
"decisions_made": [{"title": "...", "decision": "..."}],
|
|
287
|
-
"blockers": ["Se status != completed"],
|
|
288
|
-
"knowledge_to_broadcast": [{"category": "discovery|pattern|constraint", "content": "...", "severity": "info|warning|critical"}]
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
ATENCAO: O campo "reasoning.approach" e OBRIGATORIO para status "completed".
|
|
292
|
-
Se retornar sem ele, Gate 4.4 BLOQUEIA a finalizacao da task.
|
|
293
|
-
Descreva COMO abordou o problema, nao apenas O QUE fez.
|
|
294
|
-
|
|
295
|
-
Se NAO conseguir criar arquivos (sem permissao, sem ferramentas), retorne:
|
|
296
|
-
{
|
|
297
|
-
"status": "blocked",
|
|
298
|
-
"blockers": ["Descreva por que nao conseguiu criar os arquivos"]
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
Veja .claude/agents/PROTOCOL.md para detalhes completos.
|
|
302
|
-
${formattedPatterns.length > 0 ? `
|
|
303
|
-
PATTERNS: Voce recebeu ${formattedPatterns.length} implementation patterns extraidos do projeto.
|
|
304
|
-
Use os TEMPLATES fornecidos para criar codigo CONSISTENTE com o projeto existente.
|
|
305
|
-
` : ''}
|
|
306
|
-
`.trim(),
|
|
239
|
+
subagentReturnProtocol: loadTemplate("subagent-return-protocol", {
|
|
240
|
+
patternsNote: formattedPatterns.length > 0
|
|
241
|
+
? `\nPATTERNS: Voce recebeu ${formattedPatterns.length} implementation patterns extraidos do projeto.\nUse os TEMPLATES fornecidos para criar codigo CONSISTENTE com o projeto existente.\n`
|
|
242
|
+
: '',
|
|
243
|
+
}),
|
|
307
244
|
};
|
|
308
245
|
});
|
|
309
246
|
console.log(JSON.stringify({ started: contexts }));
|
|
@@ -325,8 +262,7 @@ export function taskDone(id: string, options: { checkpoint: string; files?: stri
|
|
|
325
262
|
const task = db.query("SELECT * FROM tasks WHERE id = ?").get(taskId) as any;
|
|
326
263
|
|
|
327
264
|
if (!task) {
|
|
328
|
-
|
|
329
|
-
process.exit(2);
|
|
265
|
+
throw new TaskStateError(`Task #${taskId} nao encontrada.`);
|
|
330
266
|
}
|
|
331
267
|
|
|
332
268
|
const spec = db.query("SELECT * FROM specs WHERE id = ?").get(task.spec_id) as any;
|
|
@@ -344,10 +280,11 @@ export function taskDone(id: string, options: { checkpoint: string; files?: stri
|
|
|
344
280
|
const parseResult = parseSubagentReturn(options.output);
|
|
345
281
|
|
|
346
282
|
if (!parseResult.success) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
283
|
+
throw new ValidationError(
|
|
284
|
+
formatValidationErrors(parseResult) +
|
|
285
|
+
"\nTask NAO pode ser completada sem retorno valido." +
|
|
286
|
+
"\nCorrija o formato do retorno do subagent e tente novamente."
|
|
287
|
+
);
|
|
351
288
|
}
|
|
352
289
|
|
|
353
290
|
subagentData = parseResult.data!;
|
|
@@ -411,14 +348,19 @@ export function taskDone(id: string, options: { checkpoint: string; files?: stri
|
|
|
411
348
|
.filter((k: any) => k.severity === 'critical' && k.task_origin !== taskId);
|
|
412
349
|
if (unackedCritical.length > 0) {
|
|
413
350
|
if (!options.force) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
351
|
+
// Task permanece em "running" (subagent output ja processado acima).
|
|
352
|
+
// Nao pode ser marcada "done" ate knowledge ser reconhecido.
|
|
353
|
+
const items = unackedCritical.map(
|
|
354
|
+
(k: any) => ` [X] ${k.content} (de Task #${k.task_origin})`
|
|
355
|
+
).join("\n");
|
|
356
|
+
|
|
357
|
+
throw new KnowledgeBlockError(
|
|
358
|
+
`BLOQUEADO: ${unackedCritical.length} knowledge(s) critico(s) nao reconhecido(s):\n${items}\n\n` +
|
|
359
|
+
`O subagent NAO verificou o polling obrigatorio.\n` +
|
|
360
|
+
`Reconheca com: knowledge ack <id>\n` +
|
|
361
|
+
`Ou force com: task done ${id} --checkpoint "..." --force --force-reason "motivo"`,
|
|
362
|
+
unackedCritical
|
|
363
|
+
);
|
|
422
364
|
} else {
|
|
423
365
|
console.log(`\n[!] AVISO: ${unackedCritical.length} knowledge(s) critico(s) ignorado(s) (--force usado)`);
|
|
424
366
|
for (const k of unackedCritical) {
|
|
@@ -494,73 +436,15 @@ export function taskDone(id: string, options: { checkpoint: string; files?: stri
|
|
|
494
436
|
[checkpoint, now, spec.id]
|
|
495
437
|
);
|
|
496
438
|
|
|
497
|
-
// Criar snapshot automatico COMPLETO
|
|
498
|
-
const allTasks = db.query("SELECT * FROM tasks WHERE spec_id = ?").all(spec.id) as any[];
|
|
499
|
-
const allDecisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
500
|
-
const allArtifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
501
|
-
const context = db.query("SELECT * FROM context WHERE spec_id = ?").get(spec.id);
|
|
502
|
-
|
|
503
|
-
const snapshotData = {
|
|
504
|
-
spec,
|
|
505
|
-
context,
|
|
506
|
-
tasks: allTasks,
|
|
507
|
-
decisions: allDecisions,
|
|
508
|
-
artifacts: allArtifacts,
|
|
509
|
-
checkpoint: options.checkpoint,
|
|
510
|
-
taskCompleted: task.number,
|
|
511
|
-
timestamp: now,
|
|
512
|
-
};
|
|
513
|
-
db.run("INSERT INTO snapshots (spec_id, data, trigger, created_at) VALUES (?, ?, 'auto', ?)", [
|
|
514
|
-
spec.id,
|
|
515
|
-
JSON.stringify(snapshotData),
|
|
516
|
-
now,
|
|
517
|
-
]);
|
|
518
|
-
|
|
519
|
-
// v8.1: Gerar session summary automaticamente
|
|
520
|
-
try {
|
|
521
|
-
const taskDecisions = allDecisions.filter((d) => d.task_ref === task.number);
|
|
522
|
-
const taskArtifacts = allArtifacts.filter((a) => a.task_ref === task.number);
|
|
523
|
-
const blockers = db.query(
|
|
524
|
-
"SELECT content FROM knowledge WHERE spec_id = ? AND task_origin = ? AND category = 'blocker'"
|
|
525
|
-
).all(spec.id, taskId) as any[];
|
|
526
|
-
const reasoning = getRecentReasoning(spec.id, 5);
|
|
527
|
-
const nextSteps: string[] = [];
|
|
528
|
-
|
|
529
|
-
// Extrair recommendations do reasoning
|
|
530
|
-
for (const r of reasoning) {
|
|
531
|
-
if (r.category === 'recommendation' && r.thought) {
|
|
532
|
-
nextSteps.push(r.thought);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Se nao completou tudo, sugerir proximo passo
|
|
537
|
-
if (doneCount.c < totalCount.c) {
|
|
538
|
-
nextSteps.push(`Continuar implementacao: ${totalCount.c - doneCount.c} tasks restantes`);
|
|
539
|
-
} else {
|
|
540
|
-
nextSteps.push("Todas tasks concluidas. Iniciar review.");
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
addSessionSummary(spec.id, {
|
|
544
|
-
startTime: task.completed_at || now, // approximation
|
|
545
|
-
endTime: now,
|
|
546
|
-
summary: `Task #${task.number} (${task.name}) concluida. ${checkpoint}`,
|
|
547
|
-
decisions: taskDecisions.map((d: any) => `${d.title}: ${d.decision}`),
|
|
548
|
-
blockers: blockers.map((b: any) => b.content),
|
|
549
|
-
nextSteps,
|
|
550
|
-
tasksCompleted: 1,
|
|
551
|
-
filesCreated: taskArtifacts.filter((a: any) => a.action === 'created').length,
|
|
552
|
-
filesModified: taskArtifacts.filter((a: any) => a.action === 'modified').length,
|
|
553
|
-
});
|
|
554
|
-
} catch (e) {
|
|
555
|
-
// Session summary e best-effort, nao deve bloquear o fluxo
|
|
556
|
-
}
|
|
557
|
-
|
|
558
439
|
console.log(`\nTask #${task.number} concluida!`);
|
|
559
440
|
console.log(`Checkpoint: ${options.checkpoint}`);
|
|
560
441
|
console.log(`Progresso: ${doneCount.c}/${totalCount.c} tasks`);
|
|
561
442
|
|
|
562
443
|
if (doneCount.c === totalCount.c) {
|
|
563
444
|
// Mostrar resumo completo da implementacao
|
|
445
|
+
const allTasks = db.query("SELECT * FROM tasks WHERE spec_id = ?").all(spec.id) as any[];
|
|
446
|
+
const allDecisions = db.query("SELECT * FROM decisions WHERE spec_id = ?").all(spec.id) as any[];
|
|
447
|
+
const allArtifacts = db.query("SELECT * FROM artifacts WHERE spec_id = ?").all(spec.id) as any[];
|
|
564
448
|
showImplementationSummary(spec.id, allTasks, allArtifacts, allDecisions);
|
|
565
449
|
} else {
|
|
566
450
|
console.log(`\nProximas tasks: task next\n`);
|