@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.
@@ -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
- console.error(`\n✘ Versao incompativel: CLI=${pkg.version} Plugin=${plugin.version}`);
56
- console.error(` O CLI e o plugin DEVEM ter a mesma versao.`);
57
- console.error(` Atualize o CLI: bun add -g @codexa/cli@${plugin.version}\n`);
58
- process.exit(1);
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
- console.error(`\n✘ Versao incompativel: CLI=${pkg.version} Projeto=${project.cli_version}`);
87
- console.error(` O projeto foi configurado com CLI v${project.cli_version} mas voce esta usando v${pkg.version}.`);
88
- console.error(` Opcoes:`);
89
- console.error(` 1. Atualize o CLI: bun add -g @codexa/cli@${project.cli_version}`);
90
- console.error(` 2. Reconfigure o projeto: codexa discover reset && codexa discover start\n`);
91
- process.exit(1);
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", () => checkVersionSync());
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
- console.error(`\n[ERRO] Nao foi possivel ler arquivo: ${options.outputFile}`);
214
- console.error(` ${(e as Error).message}\n`);
215
- process.exit(1);
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
- console.error("\n[ERRO] Nao foi possivel ler de stdin.");
225
- console.error(` ${(e as Error).message}\n`);
226
- process.exit(1);
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
- console.error("\n[ERRO] Checkpoint obrigatorio.");
233
- console.error("Use: --checkpoint 'resumo' ou --output '{json do subagent}'\n");
234
- process.exit(1);
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();