@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
|
@@ -27,6 +27,8 @@ export interface Reasoning {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export interface SubagentReturn {
|
|
30
|
+
// v9.1: Versao do protocolo (opcional por compatibilidade)
|
|
31
|
+
protocol_version?: string;
|
|
30
32
|
status: "completed" | "blocked" | "needs_decision";
|
|
31
33
|
summary: string;
|
|
32
34
|
files_created: string[];
|
|
@@ -58,11 +60,14 @@ const VALID_STATUSES = ["completed", "blocked", "needs_decision"];
|
|
|
58
60
|
const VALID_KNOWLEDGE_CATEGORIES = ["discovery", "decision", "blocker", "pattern", "constraint"];
|
|
59
61
|
const VALID_SEVERITIES = ["info", "warning", "critical"];
|
|
60
62
|
|
|
63
|
+
// v9.1: Versao atual do protocolo de subagentes
|
|
64
|
+
export const CURRENT_PROTOCOL_VERSION = "9.1";
|
|
65
|
+
|
|
61
66
|
/**
|
|
62
67
|
* Extrai JSON de uma string que pode conter texto misto
|
|
63
68
|
* Subagents podem retornar texto com JSON embutido
|
|
64
69
|
*/
|
|
65
|
-
function extractJsonFromText(text: string): string | null {
|
|
70
|
+
export function extractJsonFromText(text: string): string | null {
|
|
66
71
|
// Tenta encontrar JSON em bloco de codigo
|
|
67
72
|
const codeBlockMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
68
73
|
if (codeBlockMatch) {
|
|
@@ -350,6 +355,17 @@ export function parseSubagentReturn(input: string): ParseResult {
|
|
|
350
355
|
}
|
|
351
356
|
}
|
|
352
357
|
|
|
358
|
+
// v9.1: protocol_version (opcional, warn on mismatch)
|
|
359
|
+
if (parsed.protocol_version !== undefined) {
|
|
360
|
+
if (typeof parsed.protocol_version !== "string") {
|
|
361
|
+
errors.push("Campo 'protocol_version' deve ser string");
|
|
362
|
+
} else if (parsed.protocol_version !== CURRENT_PROTOCOL_VERSION) {
|
|
363
|
+
console.warn(
|
|
364
|
+
`[protocol] Versao do protocolo: esperado ${CURRENT_PROTOCOL_VERSION}, recebido ${parsed.protocol_version}`
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
353
369
|
// 5. Validacoes semanticas
|
|
354
370
|
|
|
355
371
|
// Se blocked, deve ter blockers
|
|
@@ -376,6 +392,7 @@ export function parseSubagentReturn(input: string): ParseResult {
|
|
|
376
392
|
|
|
377
393
|
// Cast para tipo correto
|
|
378
394
|
const data: SubagentReturn = {
|
|
395
|
+
protocol_version: parsed.protocol_version as string | undefined,
|
|
379
396
|
status: parsed.status as SubagentReturn["status"],
|
|
380
397
|
summary: parsed.summary as string,
|
|
381
398
|
files_created: parsed.files_created as string[],
|
|
@@ -412,6 +429,7 @@ export function formatValidationErrors(result: ParseResult): string {
|
|
|
412
429
|
output += "\n" + "─".repeat(50) + "\n";
|
|
413
430
|
output += "O retorno deve seguir o formato:\n\n";
|
|
414
431
|
output += `{
|
|
432
|
+
"protocol_version": "9.1",
|
|
415
433
|
"status": "completed | blocked | needs_decision",
|
|
416
434
|
"summary": "Resumo do que foi feito (10-500 chars)",
|
|
417
435
|
"files_created": ["path/to/file.ts"],
|
package/workflow.ts
CHANGED
|
@@ -22,12 +22,14 @@ import {
|
|
|
22
22
|
discoverPatternRemove,
|
|
23
23
|
discoverRefreshPatterns,
|
|
24
24
|
discoverExportPatterns,
|
|
25
|
+
discoverIncremental,
|
|
25
26
|
} from "./commands/discover";
|
|
26
27
|
import { clearTasks, clearShow } from "./commands/clear";
|
|
27
28
|
import { standardsList, standardsAdd, standardsEdit, standardsRemove, standardsExport } from "./commands/standards";
|
|
28
29
|
import { productGuide, productImport, productSet, productGoalAdd, productFeatureAdd, productConfirm, productShow, productReset } from "./commands/product";
|
|
29
30
|
import { researchStart, researchShow, researchFill, researchMapAgent, researchReset } from "./commands/research";
|
|
30
31
|
import { patternsExtract, patternsAnalyze } from "./commands/patterns";
|
|
32
|
+
import { syncAgents } from "./commands/sync";
|
|
31
33
|
import {
|
|
32
34
|
architectStart,
|
|
33
35
|
architectShow,
|
|
@@ -43,6 +45,7 @@ import { execSync } from "child_process";
|
|
|
43
45
|
import { existsSync, readFileSync } from "fs";
|
|
44
46
|
import { join } from "path";
|
|
45
47
|
import pkg from "./package.json";
|
|
48
|
+
import { CodexaError, ValidationError } from "./errors";
|
|
46
49
|
|
|
47
50
|
function checkVersionSync(): void {
|
|
48
51
|
// 1. Check CLI vs Plugin (dev repo only)
|
|
@@ -52,10 +55,11 @@ function checkVersionSync(): void {
|
|
|
52
55
|
if (existsSync(pluginJson)) {
|
|
53
56
|
const plugin = JSON.parse(readFileSync(pluginJson, "utf-8"));
|
|
54
57
|
if (plugin.version && plugin.version !== pkg.version) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
throw new CodexaError(
|
|
59
|
+
`✘ Versao incompativel: CLI=${pkg.version} Plugin=${plugin.version}\n` +
|
|
60
|
+
` O CLI e o plugin DEVEM ter a mesma versao.\n` +
|
|
61
|
+
` Atualize o CLI: bun add -g @codexa/cli@${plugin.version}`
|
|
62
|
+
);
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
} catch {
|
|
@@ -83,25 +87,59 @@ function checkVersionSync(): void {
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
if (project.cli_version !== pkg.version) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
throw new CodexaError(
|
|
91
|
+
`✘ Versao incompativel: CLI=${pkg.version} Projeto=${project.cli_version}\n` +
|
|
92
|
+
` O projeto foi configurado com CLI v${project.cli_version} mas voce esta usando v${pkg.version}.\n` +
|
|
93
|
+
` Opcoes:\n` +
|
|
94
|
+
` 1. Atualize o CLI: bun add -g @codexa/cli@${project.cli_version}\n` +
|
|
95
|
+
` 2. Reconfigure o projeto: codexa discover reset && codexa discover start`
|
|
96
|
+
);
|
|
92
97
|
}
|
|
93
98
|
} catch {
|
|
94
99
|
// DB not available or column doesn't exist yet — skip
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
function handleError(e: unknown): never {
|
|
104
|
+
if (e instanceof CodexaError) {
|
|
105
|
+
console.error(`\n${e.message}\n`);
|
|
106
|
+
process.exit(e.exitCode);
|
|
107
|
+
}
|
|
108
|
+
console.error(`\n[ERRO INESPERADO] ${(e as Error).message}\n`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function wrapAction<T extends (...args: any[]) => any>(fn: T): T {
|
|
113
|
+
return ((...args: any[]) => {
|
|
114
|
+
try {
|
|
115
|
+
const result = fn(...args);
|
|
116
|
+
if (result instanceof Promise) {
|
|
117
|
+
return result.catch(handleError);
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
handleError(e);
|
|
122
|
+
}
|
|
123
|
+
}) as T;
|
|
124
|
+
}
|
|
125
|
+
|
|
98
126
|
const program = new Command();
|
|
99
127
|
|
|
100
128
|
program
|
|
101
129
|
.name("codexa")
|
|
102
130
|
.description(`Codexa Workflow v${pkg.version} - Sistema de workflow para Claude Code`)
|
|
103
131
|
.version(pkg.version)
|
|
104
|
-
.hook("preAction", () =>
|
|
132
|
+
.hook("preAction", () => {
|
|
133
|
+
try {
|
|
134
|
+
checkVersionSync();
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e instanceof CodexaError) {
|
|
137
|
+
console.error(`\n${e.message}\n`);
|
|
138
|
+
process.exit(e.exitCode);
|
|
139
|
+
}
|
|
140
|
+
throw e;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
105
143
|
|
|
106
144
|
// ═══════════════════════════════════════════════════════════════
|
|
107
145
|
// FASE: PLAN
|
|
@@ -182,18 +220,18 @@ taskCmd
|
|
|
182
220
|
.command("next")
|
|
183
221
|
.description("Mostra proximas tasks disponiveis")
|
|
184
222
|
.option("--json", "Saida em JSON")
|
|
185
|
-
.action((options) => {
|
|
223
|
+
.action(wrapAction((options) => {
|
|
186
224
|
taskNext(options.json);
|
|
187
|
-
});
|
|
225
|
+
}));
|
|
188
226
|
|
|
189
227
|
taskCmd
|
|
190
228
|
.command("start <ids>")
|
|
191
229
|
.description("Inicia task(s) - pode ser multiplas separadas por virgula")
|
|
192
230
|
.option("--json", "Saida em JSON")
|
|
193
231
|
.option("--full-context", "Incluir contexto completo (modo legado)")
|
|
194
|
-
.action((ids: string, options) => {
|
|
232
|
+
.action(wrapAction((ids: string, options) => {
|
|
195
233
|
taskStart(ids, options.json, options.fullContext);
|
|
196
|
-
});
|
|
234
|
+
}));
|
|
197
235
|
|
|
198
236
|
taskCmd
|
|
199
237
|
.command("done <id>")
|
|
@@ -204,15 +242,15 @@ taskCmd
|
|
|
204
242
|
.option("--files <files>", "Arquivos criados/modificados (extraido automaticamente de --output)")
|
|
205
243
|
.option("--force", "Ignorar validacao de standards (sera registrado)")
|
|
206
244
|
.option("--force-reason <reason>", "Motivo do bypass de validacao")
|
|
207
|
-
.action((id: string, options) => {
|
|
245
|
+
.action(wrapAction((id: string, options) => {
|
|
208
246
|
// Resolver --output-file: ler conteudo do arquivo
|
|
209
247
|
if (options.outputFile && !options.output) {
|
|
210
248
|
try {
|
|
211
249
|
options.output = readFileSync(options.outputFile, "utf-8");
|
|
212
250
|
} catch (e) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
251
|
+
throw new ValidationError(
|
|
252
|
+
`[ERRO] Nao foi possivel ler arquivo: ${options.outputFile}\n ${(e as Error).message}`
|
|
253
|
+
);
|
|
216
254
|
}
|
|
217
255
|
}
|
|
218
256
|
|
|
@@ -221,17 +259,17 @@ taskCmd
|
|
|
221
259
|
try {
|
|
222
260
|
options.output = readFileSync("/dev/stdin", "utf-8");
|
|
223
261
|
} catch (e) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
262
|
+
throw new ValidationError(
|
|
263
|
+
`[ERRO] Nao foi possivel ler de stdin.\n ${(e as Error).message}`
|
|
264
|
+
);
|
|
227
265
|
}
|
|
228
266
|
}
|
|
229
267
|
|
|
230
268
|
// Checkpoint obrigatorio se nao houver --output
|
|
231
269
|
if (!options.output && !options.checkpoint) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
270
|
+
throw new ValidationError(
|
|
271
|
+
"[ERRO] Checkpoint obrigatorio.\nUse: --checkpoint 'resumo' ou --output '{json do subagent}'"
|
|
272
|
+
);
|
|
235
273
|
}
|
|
236
274
|
|
|
237
275
|
taskDone(id, {
|
|
@@ -241,7 +279,7 @@ taskCmd
|
|
|
241
279
|
forceReason: options.forceReason,
|
|
242
280
|
output: options.output,
|
|
243
281
|
});
|
|
244
|
-
});
|
|
282
|
+
}));
|
|
245
283
|
|
|
246
284
|
// ═══════════════════════════════════════════════════════════════
|
|
247
285
|
// DECISOES
|
|
@@ -317,7 +355,6 @@ knowledgeCmd
|
|
|
317
355
|
.description("Consulta o knowledge graph (relacoes entre arquivos, decisoes, patterns)")
|
|
318
356
|
.option("--file <path>", "Buscar relacoes de um arquivo")
|
|
319
357
|
.option("--decision <id>", "Buscar arquivos afetados por uma decisao")
|
|
320
|
-
.option("--contradictions", "Detectar contradicoes entre decisoes")
|
|
321
358
|
.option("--json", "Saida em JSON")
|
|
322
359
|
.action((options) => {
|
|
323
360
|
queryGraph(options);
|
|
@@ -477,6 +514,13 @@ discoverCmd
|
|
|
477
514
|
await discoverRefresh(options);
|
|
478
515
|
});
|
|
479
516
|
|
|
517
|
+
discoverCmd
|
|
518
|
+
.command("incremental")
|
|
519
|
+
.description("Atualiza discover incrementalmente (arquivos modificados desde ultimo discover)")
|
|
520
|
+
.action(async () => {
|
|
521
|
+
await discoverIncremental();
|
|
522
|
+
});
|
|
523
|
+
|
|
480
524
|
// ─────────────────────────────────────────────────────────────────
|
|
481
525
|
// PATTERNS (v7.4)
|
|
482
526
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -895,5 +939,19 @@ architectCmd
|
|
|
895
939
|
architectCancel(options);
|
|
896
940
|
});
|
|
897
941
|
|
|
942
|
+
// ═══════════════════════════════════════════════════════════════
|
|
943
|
+
// PLUGIN
|
|
944
|
+
// ═══════════════════════════════════════════════════════════════
|
|
945
|
+
|
|
946
|
+
const pluginCmd = program.command("plugin").description("Comandos de gestao do plugin");
|
|
947
|
+
|
|
948
|
+
pluginCmd
|
|
949
|
+
.command("sync-agents")
|
|
950
|
+
.description("Copia agents do plugin para .claude/agents/ do projeto (resolve limitacao de subagent_type)")
|
|
951
|
+
.option("--force", "Sobrescrever agents existentes")
|
|
952
|
+
.action((options) => {
|
|
953
|
+
syncAgents(options);
|
|
954
|
+
});
|
|
955
|
+
|
|
898
956
|
// Parse e executa
|
|
899
957
|
program.parse();
|