@codexa/cli 9.0.2 → 9.0.4

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
@@ -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,
@@ -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,
@@ -38,11 +40,12 @@ import {
38
40
  architectCancel,
39
41
  } from "./commands/architect";
40
42
  import { initSchema } from "./db/schema";
41
- import { getDb } from "./db/connection";
43
+ import { getDb, closeDb } from "./db/connection";
42
44
  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, GateError } 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,73 @@ 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
+
107
+ // v9.3: Exibir diagnostico e passos de recuperacao para falhas de gate
108
+ if (e instanceof GateError && e.recovery) {
109
+ console.error("\u2500".repeat(50));
110
+ console.error("DIAGNOSTICO:");
111
+ console.error(` ${e.recovery.diagnostic}\n`);
112
+ console.error("PASSOS PARA CORRIGIR:");
113
+ for (const step of e.recovery.steps) {
114
+ console.error(` \u2192 ${step}`);
115
+ }
116
+ if (e.recovery.command) {
117
+ console.error(`\nPara mais detalhes: ${e.recovery.command}`);
118
+ }
119
+ console.error();
120
+ }
121
+
122
+ closeDb();
123
+ process.exit(e.exitCode);
124
+ }
125
+ console.error(`\n[ERRO INESPERADO] ${(e as Error).message}\n`);
126
+ closeDb();
127
+ process.exit(1);
128
+ }
129
+
130
+ function wrapAction<T extends (...args: any[]) => any>(fn: T): T {
131
+ return ((...args: any[]) => {
132
+ try {
133
+ const result = fn(...args);
134
+ if (result instanceof Promise) {
135
+ return result.catch((e) => {
136
+ closeDb();
137
+ handleError(e);
138
+ });
139
+ }
140
+ return result;
141
+ } catch (e) {
142
+ closeDb();
143
+ handleError(e);
144
+ }
145
+ }) as T;
146
+ }
147
+
98
148
  const program = new Command();
99
149
 
100
150
  program
101
151
  .name("codexa")
102
152
  .description(`Codexa Workflow v${pkg.version} - Sistema de workflow para Claude Code`)
103
153
  .version(pkg.version)
104
- .hook("preAction", () => checkVersionSync());
154
+ .hook("preAction", () => {
155
+ checkVersionSync();
156
+ });
105
157
 
106
158
  // ═══════════════════════════════════════════════════════════════
107
159
  // FASE: PLAN
@@ -122,8 +174,9 @@ planCmd
122
174
  .command("show")
123
175
  .description("Mostra o plano atual")
124
176
  .option("--json", "Saida em JSON")
177
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
125
178
  .action((options) => {
126
- planShow(options.json);
179
+ planShow(options.json, options.spec);
127
180
  });
128
181
 
129
182
  planCmd
@@ -134,15 +187,17 @@ planCmd
134
187
  .option("--depends <ids>", "IDs das tasks que esta depende (ex: 1,2)")
135
188
  .option("--files <files>", "Arquivos esperados (ex: src/a.ts,src/b.ts)")
136
189
  .option("--sequential", "Marca como sequencial (nao paralelizavel)")
190
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
137
191
  .action((options) => {
138
- planTaskAdd(options);
192
+ planTaskAdd({ ...options, specId: options.spec });
139
193
  });
140
194
 
141
195
  planCmd
142
196
  .command("cancel")
143
197
  .description("Cancela a feature atual (soft-cancel, preserva historico)")
144
- .action(() => {
145
- planCancel();
198
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
199
+ .action((options) => {
200
+ planCancel(options.spec);
146
201
  });
147
202
 
148
203
  // ═══════════════════════════════════════════════════════════════
@@ -154,22 +209,25 @@ const checkCmd = program.command("check").description("Comandos da fase CHECK");
154
209
  checkCmd
155
210
  .command("request")
156
211
  .description("Solicita aprovacao do plano")
157
- .action(() => {
158
- checkRequest();
212
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
213
+ .action((options) => {
214
+ checkRequest(options.spec);
159
215
  });
160
216
 
161
217
  checkCmd
162
218
  .command("approve")
163
219
  .description("Aprova o plano")
164
- .action(() => {
165
- checkApprove();
220
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
221
+ .action((options) => {
222
+ checkApprove(options.spec);
166
223
  });
167
224
 
168
225
  checkCmd
169
226
  .command("reject <reason>")
170
227
  .description("Rejeita o plano com motivo")
171
- .action((reason: string) => {
172
- checkReject(reason);
228
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
229
+ .action((reason: string, options) => {
230
+ checkReject(reason, options.spec);
173
231
  });
174
232
 
175
233
  // ═══════════════════════════════════════════════════════════════
@@ -182,18 +240,20 @@ taskCmd
182
240
  .command("next")
183
241
  .description("Mostra proximas tasks disponiveis")
184
242
  .option("--json", "Saida em JSON")
185
- .action((options) => {
186
- taskNext(options.json);
187
- });
243
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
244
+ .action(wrapAction((options) => {
245
+ taskNext(options.json, options.spec);
246
+ }));
188
247
 
189
248
  taskCmd
190
249
  .command("start <ids>")
191
250
  .description("Inicia task(s) - pode ser multiplas separadas por virgula")
192
251
  .option("--json", "Saida em JSON")
193
252
  .option("--full-context", "Incluir contexto completo (modo legado)")
194
- .action((ids: string, options) => {
195
- taskStart(ids, options.json, options.fullContext);
196
- });
253
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
254
+ .action(wrapAction((ids: string, options) => {
255
+ taskStart(ids, options.json, options.fullContext, options.spec);
256
+ }));
197
257
 
198
258
  taskCmd
199
259
  .command("done <id>")
@@ -204,15 +264,15 @@ taskCmd
204
264
  .option("--files <files>", "Arquivos criados/modificados (extraido automaticamente de --output)")
205
265
  .option("--force", "Ignorar validacao de standards (sera registrado)")
206
266
  .option("--force-reason <reason>", "Motivo do bypass de validacao")
207
- .action((id: string, options) => {
267
+ .action(wrapAction((id: string, options) => {
208
268
  // Resolver --output-file: ler conteudo do arquivo
209
269
  if (options.outputFile && !options.output) {
210
270
  try {
211
271
  options.output = readFileSync(options.outputFile, "utf-8");
212
272
  } 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);
273
+ throw new ValidationError(
274
+ `[ERRO] Nao foi possivel ler arquivo: ${options.outputFile}\n ${(e as Error).message}`
275
+ );
216
276
  }
217
277
  }
218
278
 
@@ -221,17 +281,17 @@ taskCmd
221
281
  try {
222
282
  options.output = readFileSync("/dev/stdin", "utf-8");
223
283
  } 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);
284
+ throw new ValidationError(
285
+ `[ERRO] Nao foi possivel ler de stdin.\n ${(e as Error).message}`
286
+ );
227
287
  }
228
288
  }
229
289
 
230
290
  // Checkpoint obrigatorio se nao houver --output
231
291
  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);
292
+ throw new ValidationError(
293
+ "[ERRO] Checkpoint obrigatorio.\nUse: --checkpoint 'resumo' ou --output '{json do subagent}'"
294
+ );
235
295
  }
236
296
 
237
297
  taskDone(id, {
@@ -241,7 +301,7 @@ taskCmd
241
301
  forceReason: options.forceReason,
242
302
  output: options.output,
243
303
  });
244
- });
304
+ }));
245
305
 
246
306
  // ═══════════════════════════════════════════════════════════════
247
307
  // DECISOES
@@ -252,16 +312,18 @@ program
252
312
  .description("Registra uma decisao")
253
313
  .option("--rationale <text>", "Justificativa da decisao")
254
314
  .option("--force", "Ignorar deteccao de conflitos")
315
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
255
316
  .action((title: string, decision: string, options) => {
256
- decide(title, decision, options);
317
+ decide(title, decision, { ...options, specId: options.spec });
257
318
  });
258
319
 
259
320
  program
260
321
  .command("decisions")
261
322
  .description("Lista decisoes")
262
323
  .option("--json", "Saida em JSON")
324
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
263
325
  .action((options) => {
264
- listDecisions(options.json);
326
+ listDecisions(options.json, options.spec);
265
327
  });
266
328
 
267
329
  // ═══════════════════════════════════════════════════════════════
@@ -277,12 +339,14 @@ knowledgeCmd
277
339
  .requiredOption("--category <cat>", "Categoria (discovery, decision, blocker, pattern, constraint)")
278
340
  .option("--severity <level>", "Severidade (info, warning, critical)", "info")
279
341
  .option("--broadcast <target>", "Destino (all ou IDs separados por virgula)", "all")
342
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
280
343
  .action((options) => {
281
344
  addKnowledge({
282
345
  content: options.content,
283
346
  category: options.category,
284
347
  severity: options.severity,
285
348
  broadcastTo: options.broadcast,
349
+ specId: options.spec,
286
350
  });
287
351
  });
288
352
 
@@ -293,23 +357,26 @@ knowledgeCmd
293
357
  .option("--category <cat>", "Filtrar por categoria")
294
358
  .option("--severity <level>", "Filtrar por severidade (critical, warning, info)")
295
359
  .option("--json", "Saida em JSON")
360
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
296
361
  .action((options) => {
297
- listKnowledge(options);
362
+ listKnowledge({ ...options, specId: options.spec });
298
363
  });
299
364
 
300
365
  knowledgeCmd
301
366
  .command("ack <id>")
302
367
  .description("Marca knowledge como lido pela task atual")
303
- .action((id: string) => {
304
- acknowledgeKnowledge(id);
368
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
369
+ .action((id: string, options) => {
370
+ acknowledgeKnowledge(id, options.spec);
305
371
  });
306
372
 
307
373
  knowledgeCmd
308
374
  .command("resolve <ids>")
309
375
  .description("Resolve/reconhece knowledge item(s) critico(s)")
310
376
  .option("--resolution <text>", "Descricao de como o blocker foi resolvido")
311
- .action((ids: string, opts: { resolution?: string }) => {
312
- resolveKnowledge(ids, opts.resolution);
377
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
378
+ .action((ids: string, opts: { resolution?: string; spec?: string }) => {
379
+ resolveKnowledge(ids, opts.resolution, opts.spec);
313
380
  });
314
381
 
315
382
  knowledgeCmd
@@ -317,10 +384,20 @@ knowledgeCmd
317
384
  .description("Consulta o knowledge graph (relacoes entre arquivos, decisoes, patterns)")
318
385
  .option("--file <path>", "Buscar relacoes de um arquivo")
319
386
  .option("--decision <id>", "Buscar arquivos afetados por uma decisao")
320
- .option("--contradictions", "Detectar contradicoes entre decisoes")
387
+ .option("--json", "Saida em JSON")
388
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
389
+ .action((options) => {
390
+ queryGraph({ ...options, specId: options.spec });
391
+ });
392
+
393
+ knowledgeCmd
394
+ .command("compact")
395
+ .description("Compacta knowledge (merge similares, arquivar antigos)")
396
+ .option("--spec <id>", "ID do spec (padrao: todos)")
397
+ .option("--dry-run", "Apenas mostrar o que seria compactado")
321
398
  .option("--json", "Saida em JSON")
322
399
  .action((options) => {
323
- queryGraph(options);
400
+ compactKnowledge({ specId: options.spec, dryRun: options.dryRun, json: options.json });
324
401
  });
325
402
 
326
403
  // ═══════════════════════════════════════════════════════════════
@@ -333,22 +410,27 @@ reviewCmd
333
410
  .command("start")
334
411
  .description("Inicia o review")
335
412
  .option("--json", "Saida em JSON")
413
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
336
414
  .action((options) => {
337
- reviewStart(options.json);
415
+ reviewStart(options.json, options.spec);
338
416
  });
339
417
 
340
418
  reviewCmd
341
419
  .command("approve")
342
420
  .description("Aprova o review e finaliza a feature")
343
- .action(() => {
344
- reviewApprove();
421
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
422
+ .option("--force", "Aprovar mesmo com score baixo (<50)")
423
+ .option("--force-reason <reason>", "Motivo para aprovacao forcada")
424
+ .action((options) => {
425
+ reviewApprove({ specId: options.spec, force: options.force, forceReason: options.forceReason });
345
426
  });
346
427
 
347
428
  reviewCmd
348
429
  .command("skip")
349
430
  .description("Pula o review e finaliza a feature diretamente")
350
- .action(() => {
351
- reviewSkip();
431
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
432
+ .action((options) => {
433
+ reviewSkip(options.spec);
352
434
  });
353
435
 
354
436
  // ═══════════════════════════════════════════════════════════════
@@ -359,8 +441,9 @@ program
359
441
  .command("status")
360
442
  .description("Mostra status atual")
361
443
  .option("--json", "Saida em JSON")
444
+ .option("--spec <id>", "ID do spec (padrao: todos ativos)")
362
445
  .action((options) => {
363
- status(options.json);
446
+ status(options.json, options.spec);
364
447
  });
365
448
 
366
449
  const contextCmd = program.command("context").description("Comandos de contexto");
@@ -369,8 +452,9 @@ contextCmd
369
452
  .command("export")
370
453
  .description("Exporta contexto para subagent")
371
454
  .option("--task <id>", "ID da task especifica")
455
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
372
456
  .action((options) => {
373
- contextExport({ ...options, json: true }); // Sempre JSON
457
+ contextExport({ ...options, json: true, specId: options.spec }); // Sempre JSON
374
458
  });
375
459
 
376
460
  contextCmd
@@ -379,16 +463,18 @@ contextCmd
379
463
  .option("--approach <text>", "Adiciona nova abordagem descoberta")
380
464
  .option("--pattern <text>", "Registra padrao identificado no codigo")
381
465
  .option("--constraint <text>", "Adiciona nova limitacao encontrada")
466
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
382
467
  .action((options) => {
383
- contextUpdate(options);
468
+ contextUpdate({ ...options, specId: options.spec });
384
469
  });
385
470
 
386
471
  contextCmd
387
472
  .command("detail <section>")
388
473
  .description("Mostra secao especifica do contexto (standards, decisions, patterns, knowledge, architecture)")
389
474
  .option("--json", "Output JSON")
390
- .action((section: string, opts: { json?: boolean }) => {
391
- contextDetail(section, opts.json);
475
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
476
+ .action((section: string, opts: { json?: boolean; spec?: string }) => {
477
+ contextDetail(section, opts.json, opts.spec);
392
478
  });
393
479
 
394
480
  // Manter compatibilidade: context sem subcomando = export
@@ -396,8 +482,9 @@ program
396
482
  .command("ctx")
397
483
  .description("Alias para context export (compatibilidade)")
398
484
  .option("--task <id>", "ID da task especifica")
485
+ .option("--spec <id>", "ID do spec (padrao: mais recente)")
399
486
  .action((options) => {
400
- contextExport({ ...options, json: true });
487
+ contextExport({ ...options, json: true, specId: options.spec });
401
488
  });
402
489
 
403
490
  program
@@ -463,7 +550,7 @@ discoverCmd
463
550
  });
464
551
 
465
552
  discoverCmd
466
- .command("reset")
553
+ .command("reset", { hidden: true })
467
554
  .description("Reseta descoberta para refazer")
468
555
  .action(() => {
469
556
  discoverReset();
@@ -477,6 +564,13 @@ discoverCmd
477
564
  await discoverRefresh(options);
478
565
  });
479
566
 
567
+ discoverCmd
568
+ .command("incremental")
569
+ .description("Atualiza discover incrementalmente (arquivos modificados desde ultimo discover)")
570
+ .action(async () => {
571
+ await discoverIncremental();
572
+ });
573
+
480
574
  // ─────────────────────────────────────────────────────────────────
481
575
  // PATTERNS (v7.4)
482
576
  // ─────────────────────────────────────────────────────────────────
@@ -524,7 +618,7 @@ discoverCmd
524
618
  });
525
619
 
526
620
  discoverCmd
527
- .command("pattern-edit <name>")
621
+ .command("pattern-edit <name>", { hidden: true })
528
622
  .description("Edita um implementation pattern")
529
623
  .option("--category <cat>", "Nova categoria")
530
624
  .option("--scope <scope>", "Novo escopo")
@@ -574,7 +668,7 @@ discoverCmd
574
668
  });
575
669
 
576
670
  discoverCmd
577
- .command("analyze-file <path>")
671
+ .command("analyze-file <path>", { hidden: true })
578
672
  .description("Analisa estrutura de um arquivo (imports, exports, convencoes)")
579
673
  .option("--json", "Saida em JSON")
580
674
  .action((path, options) => {
@@ -583,7 +677,7 @@ discoverCmd
583
677
 
584
678
  // v9.0: Analise profunda com metadata enriquecida + grepai
585
679
  discoverCmd
586
- .command("analyze-deep <files...>")
680
+ .command("analyze-deep <files...>", { hidden: true })
587
681
  .description("Analise profunda de arquivos (hooks, patterns, directives)")
588
682
  .option("--json", "Saida em JSON")
589
683
  .action((files, options) => {
@@ -593,7 +687,7 @@ discoverCmd
593
687
 
594
688
  // v9.0: Anti-patterns de gate bypasses
595
689
  discoverCmd
596
- .command("extract-anti-patterns")
690
+ .command("extract-anti-patterns", { hidden: true })
597
691
  .description("Extrai anti-patterns do historico de gate bypasses")
598
692
  .action(() => {
599
693
  const { extractAntiPatternsFromHistory } = require("./commands/patterns");
@@ -601,7 +695,7 @@ discoverCmd
601
695
  });
602
696
 
603
697
  discoverCmd
604
- .command("export-patterns")
698
+ .command("export-patterns", { hidden: true })
605
699
  .description("Regenera arquivo patterns.md")
606
700
  .action(() => {
607
701
  discoverExportPatterns();
@@ -819,11 +913,12 @@ program
819
913
  .description("Limpa tasks/features mantendo configuracoes do projeto (standards, patterns, PRD)")
820
914
  .option("--force", "Confirma a limpeza (sem isso apenas mostra o que sera removido)")
821
915
  .option("--show", "Mostra estado atual dos arquivos do workflow")
916
+ .option("--spec <id>", "Limpa apenas o spec especificado")
822
917
  .action((options) => {
823
918
  if (options.show) {
824
919
  clearShow();
825
920
  } else {
826
- clearTasks({ force: options.force });
921
+ clearTasks({ force: options.force, specId: options.spec });
827
922
  }
828
923
  });
829
924
 
@@ -895,5 +990,19 @@ architectCmd
895
990
  architectCancel(options);
896
991
  });
897
992
 
993
+ // ═══════════════════════════════════════════════════════════════
994
+ // PLUGIN
995
+ // ═══════════════════════════════════════════════════════════════
996
+
997
+ const pluginCmd = program.command("plugin").description("Comandos de gestao do plugin");
998
+
999
+ pluginCmd
1000
+ .command("sync-agents")
1001
+ .description("Copia agents do plugin para .claude/agents/ do projeto (resolve limitacao de subagent_type)")
1002
+ .option("--force", "Sobrescrever agents existentes")
1003
+ .action((options) => {
1004
+ syncAgents(options);
1005
+ });
1006
+
898
1007
  // Parse e executa
899
1008
  program.parse();