@codexa/cli 9.0.3 → 9.0.5

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/workflow.ts CHANGED
@@ -6,7 +6,7 @@ import { checkRequest, checkApprove, checkReject } from "./commands/check";
6
6
  import { taskNext, taskStart, taskDone } from "./commands/task";
7
7
  import { decide, listDecisions } from "./commands/decide";
8
8
  import { reviewStart, reviewApprove, reviewSkip } from "./commands/review";
9
- import { addKnowledge, listKnowledge, acknowledgeKnowledge, queryGraph, resolveKnowledge } from "./commands/knowledge";
9
+ import { addKnowledge, listKnowledge, acknowledgeKnowledge, queryGraph, resolveKnowledge, compactKnowledge } from "./commands/knowledge";
10
10
  import { status, contextExport, recover, contextUpdate, contextDetail } from "./commands/utils";
11
11
  import {
12
12
  discoverStart,
@@ -40,15 +40,15 @@ import {
40
40
  architectCancel,
41
41
  } from "./commands/architect";
42
42
  import { initSchema } from "./db/schema";
43
- import { getDb } from "./db/connection";
43
+ import { getDb, closeDb } from "./db/connection";
44
44
  import { execSync } from "child_process";
45
45
  import { existsSync, readFileSync } from "fs";
46
46
  import { join } from "path";
47
47
  import pkg from "./package.json";
48
- import { CodexaError, ValidationError } from "./errors";
48
+ import { CodexaError, ValidationError, GateError } from "./errors";
49
49
 
50
50
  function checkVersionSync(): void {
51
- // 1. Check CLI vs Plugin (dev repo only)
51
+ // 1. Check CLI vs Plugin (dev repo only — igualdade estrita)
52
52
  try {
53
53
  const gitRoot = execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
54
54
  const pluginJson = join(gitRoot, "plugins", "codexa-workflow", ".claude-plugin", "plugin.json");
@@ -62,11 +62,12 @@ function checkVersionSync(): void {
62
62
  );
63
63
  }
64
64
  }
65
- } catch {
65
+ } catch (e) {
66
+ if (e instanceof CodexaError) throw e;
66
67
  // Not in dev repo — skip
67
68
  }
68
69
 
69
- // 2. Check CLI vs project's stored version (client projects)
70
+ // 2. Track CLI version in project DB (informativo, migracoes garantem compatibilidade)
70
71
  try {
71
72
  const dbPath = join(process.cwd(), ".codexa", "db", "workflow.db");
72
73
  if (!existsSync(dbPath)) return;
@@ -77,7 +78,6 @@ function checkVersionSync(): void {
77
78
  if (!project) return;
78
79
 
79
80
  if (!project.cli_version) {
80
- // Projeto existente sem versao gravada (pre-v8.7) — registrar versao atual
81
81
  db.run(
82
82
  `UPDATE project SET cli_version = ? WHERE id = 'default'`,
83
83
  [pkg.version]
@@ -87,12 +87,13 @@ function checkVersionSync(): void {
87
87
  }
88
88
 
89
89
  if (project.cli_version !== pkg.version) {
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`
90
+ console.log(
91
+ `ℹ Projeto configurado com CLI v${project.cli_version}, rodando v${pkg.version}. ` +
92
+ `Migracoes aplicadas automaticamente.`
93
+ );
94
+ db.run(
95
+ `UPDATE project SET cli_version = ? WHERE id = 'default'`,
96
+ [pkg.version]
96
97
  );
97
98
  }
98
99
  } catch {
@@ -103,9 +104,27 @@ function checkVersionSync(): void {
103
104
  function handleError(e: unknown): never {
104
105
  if (e instanceof CodexaError) {
105
106
  console.error(`\n${e.message}\n`);
107
+
108
+ // v9.3: Exibir diagnostico e passos de recuperacao para falhas de gate
109
+ if (e instanceof GateError && e.recovery) {
110
+ console.error("\u2500".repeat(50));
111
+ console.error("DIAGNOSTICO:");
112
+ console.error(` ${e.recovery.diagnostic}\n`);
113
+ console.error("PASSOS PARA CORRIGIR:");
114
+ for (const step of e.recovery.steps) {
115
+ console.error(` \u2192 ${step}`);
116
+ }
117
+ if (e.recovery.command) {
118
+ console.error(`\nPara mais detalhes: ${e.recovery.command}`);
119
+ }
120
+ console.error();
121
+ }
122
+
123
+ closeDb();
106
124
  process.exit(e.exitCode);
107
125
  }
108
126
  console.error(`\n[ERRO INESPERADO] ${(e as Error).message}\n`);
127
+ closeDb();
109
128
  process.exit(1);
110
129
  }
111
130
 
@@ -114,10 +133,14 @@ function wrapAction<T extends (...args: any[]) => any>(fn: T): T {
114
133
  try {
115
134
  const result = fn(...args);
116
135
  if (result instanceof Promise) {
117
- return result.catch(handleError);
136
+ return result.catch((e) => {
137
+ closeDb();
138
+ handleError(e);
139
+ });
118
140
  }
119
141
  return result;
120
142
  } catch (e) {
143
+ closeDb();
121
144
  handleError(e);
122
145
  }
123
146
  }) as T;
@@ -130,15 +153,7 @@ program
130
153
  .description(`Codexa Workflow v${pkg.version} - Sistema de workflow para Claude Code`)
131
154
  .version(pkg.version)
132
155
  .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
- }
156
+ checkVersionSync();
142
157
  });
143
158
 
144
159
  // ═══════════════════════════════════════════════════════════════
@@ -160,8 +175,9 @@ planCmd
160
175
  .command("show")
161
176
  .description("Mostra o plano atual")
162
177
  .option("--json", "Saida em JSON")
178
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
163
179
  .action((options) => {
164
- planShow(options.json);
180
+ planShow(options.json, options.spec);
165
181
  });
166
182
 
167
183
  planCmd
@@ -172,15 +188,17 @@ planCmd
172
188
  .option("--depends <ids>", "IDs das tasks que esta depende (ex: 1,2)")
173
189
  .option("--files <files>", "Arquivos esperados (ex: src/a.ts,src/b.ts)")
174
190
  .option("--sequential", "Marca como sequencial (nao paralelizavel)")
191
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
175
192
  .action((options) => {
176
- planTaskAdd(options);
193
+ planTaskAdd({ ...options, specId: options.spec });
177
194
  });
178
195
 
179
196
  planCmd
180
197
  .command("cancel")
181
198
  .description("Cancela a feature atual (soft-cancel, preserva historico)")
182
- .action(() => {
183
- planCancel();
199
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
200
+ .action((options) => {
201
+ planCancel(options.spec);
184
202
  });
185
203
 
186
204
  // ═══════════════════════════════════════════════════════════════
@@ -192,22 +210,25 @@ const checkCmd = program.command("check").description("Comandos da fase CHECK");
192
210
  checkCmd
193
211
  .command("request")
194
212
  .description("Solicita aprovacao do plano")
195
- .action(() => {
196
- checkRequest();
213
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
214
+ .action((options) => {
215
+ checkRequest(options.spec);
197
216
  });
198
217
 
199
218
  checkCmd
200
219
  .command("approve")
201
220
  .description("Aprova o plano")
202
- .action(() => {
203
- checkApprove();
221
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
222
+ .action((options) => {
223
+ checkApprove(options.spec);
204
224
  });
205
225
 
206
226
  checkCmd
207
227
  .command("reject <reason>")
208
228
  .description("Rejeita o plano com motivo")
209
- .action((reason: string) => {
210
- checkReject(reason);
229
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
230
+ .action((reason: string, options) => {
231
+ checkReject(reason, options.spec);
211
232
  });
212
233
 
213
234
  // ═══════════════════════════════════════════════════════════════
@@ -220,8 +241,9 @@ taskCmd
220
241
  .command("next")
221
242
  .description("Mostra proximas tasks disponiveis")
222
243
  .option("--json", "Saida em JSON")
244
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
223
245
  .action(wrapAction((options) => {
224
- taskNext(options.json);
246
+ taskNext(options.json, options.spec);
225
247
  }));
226
248
 
227
249
  taskCmd
@@ -229,8 +251,9 @@ taskCmd
229
251
  .description("Inicia task(s) - pode ser multiplas separadas por virgula")
230
252
  .option("--json", "Saida em JSON")
231
253
  .option("--full-context", "Incluir contexto completo (modo legado)")
254
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
232
255
  .action(wrapAction((ids: string, options) => {
233
- taskStart(ids, options.json, options.fullContext);
256
+ taskStart(ids, options.json, options.fullContext, options.spec);
234
257
  }));
235
258
 
236
259
  taskCmd
@@ -290,16 +313,18 @@ program
290
313
  .description("Registra uma decisao")
291
314
  .option("--rationale <text>", "Justificativa da decisao")
292
315
  .option("--force", "Ignorar deteccao de conflitos")
316
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
293
317
  .action((title: string, decision: string, options) => {
294
- decide(title, decision, options);
318
+ decide(title, decision, { ...options, specId: options.spec });
295
319
  });
296
320
 
297
321
  program
298
322
  .command("decisions")
299
323
  .description("Lista decisoes")
300
324
  .option("--json", "Saida em JSON")
325
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
301
326
  .action((options) => {
302
- listDecisions(options.json);
327
+ listDecisions(options.json, options.spec);
303
328
  });
304
329
 
305
330
  // ═══════════════════════════════════════════════════════════════
@@ -315,12 +340,14 @@ knowledgeCmd
315
340
  .requiredOption("--category <cat>", "Categoria (discovery, decision, blocker, pattern, constraint)")
316
341
  .option("--severity <level>", "Severidade (info, warning, critical)", "info")
317
342
  .option("--broadcast <target>", "Destino (all ou IDs separados por virgula)", "all")
343
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
318
344
  .action((options) => {
319
345
  addKnowledge({
320
346
  content: options.content,
321
347
  category: options.category,
322
348
  severity: options.severity,
323
349
  broadcastTo: options.broadcast,
350
+ specId: options.spec,
324
351
  });
325
352
  });
326
353
 
@@ -331,23 +358,26 @@ knowledgeCmd
331
358
  .option("--category <cat>", "Filtrar por categoria")
332
359
  .option("--severity <level>", "Filtrar por severidade (critical, warning, info)")
333
360
  .option("--json", "Saida em JSON")
361
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
334
362
  .action((options) => {
335
- listKnowledge(options);
363
+ listKnowledge({ ...options, specId: options.spec });
336
364
  });
337
365
 
338
366
  knowledgeCmd
339
367
  .command("ack <id>")
340
368
  .description("Marca knowledge como lido pela task atual")
341
- .action((id: string) => {
342
- acknowledgeKnowledge(id);
369
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
370
+ .action((id: string, options) => {
371
+ acknowledgeKnowledge(id, options.spec);
343
372
  });
344
373
 
345
374
  knowledgeCmd
346
375
  .command("resolve <ids>")
347
376
  .description("Resolve/reconhece knowledge item(s) critico(s)")
348
377
  .option("--resolution <text>", "Descricao de como o blocker foi resolvido")
349
- .action((ids: string, opts: { resolution?: string }) => {
350
- resolveKnowledge(ids, opts.resolution);
378
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
379
+ .action((ids: string, opts: { resolution?: string; spec?: string }) => {
380
+ resolveKnowledge(ids, opts.resolution, opts.spec);
351
381
  });
352
382
 
353
383
  knowledgeCmd
@@ -356,8 +386,19 @@ knowledgeCmd
356
386
  .option("--file <path>", "Buscar relacoes de um arquivo")
357
387
  .option("--decision <id>", "Buscar arquivos afetados por uma decisao")
358
388
  .option("--json", "Saida em JSON")
389
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
359
390
  .action((options) => {
360
- queryGraph(options);
391
+ queryGraph({ ...options, specId: options.spec });
392
+ });
393
+
394
+ knowledgeCmd
395
+ .command("compact")
396
+ .description("Compacta knowledge (merge similares, arquivar antigos)")
397
+ .option("--spec <id>", "ID do spec (padrao: todos)")
398
+ .option("--dry-run", "Apenas mostrar o que seria compactado")
399
+ .option("--json", "Saida em JSON")
400
+ .action((options) => {
401
+ compactKnowledge({ specId: options.spec, dryRun: options.dryRun, json: options.json });
361
402
  });
362
403
 
363
404
  // ═══════════════════════════════════════════════════════════════
@@ -370,22 +411,27 @@ reviewCmd
370
411
  .command("start")
371
412
  .description("Inicia o review")
372
413
  .option("--json", "Saida em JSON")
414
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
373
415
  .action((options) => {
374
- reviewStart(options.json);
416
+ reviewStart(options.json, options.spec);
375
417
  });
376
418
 
377
419
  reviewCmd
378
420
  .command("approve")
379
421
  .description("Aprova o review e finaliza a feature")
380
- .action(() => {
381
- reviewApprove();
422
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
423
+ .option("--force", "Aprovar mesmo com score baixo (<50)")
424
+ .option("--force-reason <reason>", "Motivo para aprovacao forcada")
425
+ .action((options) => {
426
+ reviewApprove({ specId: options.spec, force: options.force, forceReason: options.forceReason });
382
427
  });
383
428
 
384
429
  reviewCmd
385
430
  .command("skip")
386
431
  .description("Pula o review e finaliza a feature diretamente")
387
- .action(() => {
388
- reviewSkip();
432
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
433
+ .action((options) => {
434
+ reviewSkip(options.spec);
389
435
  });
390
436
 
391
437
  // ═══════════════════════════════════════════════════════════════
@@ -396,8 +442,9 @@ program
396
442
  .command("status")
397
443
  .description("Mostra status atual")
398
444
  .option("--json", "Saida em JSON")
445
+ .option("--spec <id>", "ID do spec (padrao: todos ativos)")
399
446
  .action((options) => {
400
- status(options.json);
447
+ status(options.json, options.spec);
401
448
  });
402
449
 
403
450
  const contextCmd = program.command("context").description("Comandos de contexto");
@@ -406,8 +453,9 @@ contextCmd
406
453
  .command("export")
407
454
  .description("Exporta contexto para subagent")
408
455
  .option("--task <id>", "ID da task especifica")
456
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
409
457
  .action((options) => {
410
- contextExport({ ...options, json: true }); // Sempre JSON
458
+ contextExport({ ...options, json: true, specId: options.spec }); // Sempre JSON
411
459
  });
412
460
 
413
461
  contextCmd
@@ -416,16 +464,18 @@ contextCmd
416
464
  .option("--approach <text>", "Adiciona nova abordagem descoberta")
417
465
  .option("--pattern <text>", "Registra padrao identificado no codigo")
418
466
  .option("--constraint <text>", "Adiciona nova limitacao encontrada")
467
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
419
468
  .action((options) => {
420
- contextUpdate(options);
469
+ contextUpdate({ ...options, specId: options.spec });
421
470
  });
422
471
 
423
472
  contextCmd
424
473
  .command("detail <section>")
425
474
  .description("Mostra secao especifica do contexto (standards, decisions, patterns, knowledge, architecture)")
426
475
  .option("--json", "Output JSON")
427
- .action((section: string, opts: { json?: boolean }) => {
428
- contextDetail(section, opts.json);
476
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
477
+ .action((section: string, opts: { json?: boolean; spec?: string }) => {
478
+ contextDetail(section, opts.json, opts.spec);
429
479
  });
430
480
 
431
481
  // Manter compatibilidade: context sem subcomando = export
@@ -433,8 +483,9 @@ program
433
483
  .command("ctx")
434
484
  .description("Alias para context export (compatibilidade)")
435
485
  .option("--task <id>", "ID da task especifica")
486
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
436
487
  .action((options) => {
437
- contextExport({ ...options, json: true });
488
+ contextExport({ ...options, json: true, specId: options.spec });
438
489
  });
439
490
 
440
491
  program
@@ -500,7 +551,7 @@ discoverCmd
500
551
  });
501
552
 
502
553
  discoverCmd
503
- .command("reset")
554
+ .command("reset", { hidden: true })
504
555
  .description("Reseta descoberta para refazer")
505
556
  .action(() => {
506
557
  discoverReset();
@@ -568,7 +619,7 @@ discoverCmd
568
619
  });
569
620
 
570
621
  discoverCmd
571
- .command("pattern-edit <name>")
622
+ .command("pattern-edit <name>", { hidden: true })
572
623
  .description("Edita um implementation pattern")
573
624
  .option("--category <cat>", "Nova categoria")
574
625
  .option("--scope <scope>", "Novo escopo")
@@ -618,7 +669,7 @@ discoverCmd
618
669
  });
619
670
 
620
671
  discoverCmd
621
- .command("analyze-file <path>")
672
+ .command("analyze-file <path>", { hidden: true })
622
673
  .description("Analisa estrutura de um arquivo (imports, exports, convencoes)")
623
674
  .option("--json", "Saida em JSON")
624
675
  .action((path, options) => {
@@ -627,7 +678,7 @@ discoverCmd
627
678
 
628
679
  // v9.0: Analise profunda com metadata enriquecida + grepai
629
680
  discoverCmd
630
- .command("analyze-deep <files...>")
681
+ .command("analyze-deep <files...>", { hidden: true })
631
682
  .description("Analise profunda de arquivos (hooks, patterns, directives)")
632
683
  .option("--json", "Saida em JSON")
633
684
  .action((files, options) => {
@@ -637,7 +688,7 @@ discoverCmd
637
688
 
638
689
  // v9.0: Anti-patterns de gate bypasses
639
690
  discoverCmd
640
- .command("extract-anti-patterns")
691
+ .command("extract-anti-patterns", { hidden: true })
641
692
  .description("Extrai anti-patterns do historico de gate bypasses")
642
693
  .action(() => {
643
694
  const { extractAntiPatternsFromHistory } = require("./commands/patterns");
@@ -645,7 +696,7 @@ discoverCmd
645
696
  });
646
697
 
647
698
  discoverCmd
648
- .command("export-patterns")
699
+ .command("export-patterns", { hidden: true })
649
700
  .description("Regenera arquivo patterns.md")
650
701
  .action(() => {
651
702
  discoverExportPatterns();
@@ -863,11 +914,12 @@ program
863
914
  .description("Limpa tasks/features mantendo configuracoes do projeto (standards, patterns, PRD)")
864
915
  .option("--force", "Confirma a limpeza (sem isso apenas mostra o que sera removido)")
865
916
  .option("--show", "Mostra estado atual dos arquivos do workflow")
917
+ .option("--spec <id>", "Limpa apenas o spec especificado")
866
918
  .action((options) => {
867
919
  if (options.show) {
868
920
  clearShow();
869
921
  } else {
870
- clearTasks({ force: options.force });
922
+ clearTasks({ force: options.force, specId: options.spec });
871
923
  }
872
924
  });
873
925