@spec-wave/cli 0.13.0 → 0.15.0

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.
Files changed (38) hide show
  1. package/README.md +39 -6
  2. package/bin/spec-wave.mjs +17 -1
  3. package/package.json +1 -1
  4. package/src/api/github-rest.mjs +198 -2
  5. package/src/commands/code-review.mjs +5 -8
  6. package/src/commands/decompose.mjs +412 -130
  7. package/src/commands/dev-agent.mjs +3 -2
  8. package/src/commands/doctor.mjs +239 -9
  9. package/src/commands/generate-plan.mjs +105 -30
  10. package/src/commands/generate-spec.mjs +17 -5
  11. package/src/commands/implement.mjs +39 -15
  12. package/src/commands/info.mjs +4 -3
  13. package/src/commands/issue.mjs +4 -4
  14. package/src/commands/move.mjs +162 -0
  15. package/src/commands/order.mjs +1 -12
  16. package/src/commands/qa.mjs +5 -8
  17. package/src/commands/refresh.mjs +4 -3
  18. package/src/commands/story.mjs +1 -12
  19. package/src/commands/task.mjs +1 -11
  20. package/src/commands/update.mjs +372 -71
  21. package/src/commands/validate.mjs +37 -22
  22. package/src/config.mjs +40 -1
  23. package/src/lib/board.mjs +88 -26
  24. package/src/lib/claude.mjs +315 -70
  25. package/src/lib/critique.mjs +391 -91
  26. package/src/lib/decomposition-doc.mjs +451 -0
  27. package/src/lib/implement-board.mjs +14 -1
  28. package/src/lib/pr-branch.mjs +267 -0
  29. package/src/lib/project-root.mjs +93 -0
  30. package/src/lib/templates.mjs +53 -0
  31. package/src/setup/files.mjs +3 -10
  32. package/src/templates/skill/SKILL.md +158 -30
  33. package/src/templates/workflows/code-review.yml +1 -1
  34. package/src/templates/workflows/decompose.yml +20 -6
  35. package/src/templates/workflows/generate-plan.yml +1 -1
  36. package/src/templates/workflows/generate-spec.yml +1 -1
  37. package/src/templates/workflows/qa.yml +1 -1
  38. package/src/templates/workflows/validate.yml +1 -1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: spec-wave
3
3
  description: "Use when the user wants to set up a spec-driven GitHub workflow, create a Feature issue, generate spec.md or plan.md, decompose a Feature into Stories/Tasks, write RFC documentation, or audit and fix a Pull Request. Implements the RFC-001 workflow with GitHub Projects v2, labels, and AI-powered GitHub Actions."
4
- argument-hint: "[info|setup|update|doctor|issue|feature|spec|plan|ready|decompose|order|implement|task|story|uninstall|rfc|fix-pr] [target]"
4
+ argument-hint: "[info|setup|update|doctor|issue|feature|spec|plan|ready|decompose|order|implement|task|story|move|uninstall|rfc|fix-pr] [target]"
5
5
  user-invocable: true
6
6
  allowed-tools:
7
7
  - Bash(npx @spec-wave/cli@latest *)
@@ -87,24 +87,30 @@ Essa é a sequência completa, mas **cada tipo de artefato percorre só um trech
87
87
  |----------|----------|----------|-------------|
88
88
  | **Initiative / Epic** | 📥 Backlog | — | Agrupadores. Não têm fluxo próprio; acompanham os filhos. |
89
89
  | **Feature** | 📥 Backlog | 🎯 Priorizado → 📋 Spec → 📋 Plan → ✅ Ready → 🚧 Desenvolvimento → 👀 Code Review → 🧪 QA → 📋 Homologação → 🚀 Deploy → 🎉 Done | Fica parada em **✅ Ready** esperando um dev assumir — é ali que ela aparece na fila do TL. Só avança para 👀 Code Review quando **TODAS** as suas Stories já estiverem lá. |
90
- | **Story** | **✅ Ready** (criada pelo `decompose`) | 🚧 Desenvolvimento → 👀 Code Review → 🧪 QA → 📋 Homologação → 🎉 Done | **Nunca nasce em 📥 Backlog.** |
91
- | **Task** | **✅ Ready** (criada pelo `decompose`) | 🚧 Desenvolvimento → 🎉 Done | **Não** passa por Code Review, QA nem Homologação — só `task start` e `task done`. |
90
+ | **Story** | **✅ Ready** (criada pelo `decompose-apply`) | 🚧 Desenvolvimento → 👀 Code Review → 🧪 QA → 📋 Homologação → 🎉 Done | **Nunca nasce em 📥 Backlog.** |
91
+ | **Task** | **✅ Ready** (criada pelo `decompose-apply`) | 🚧 Desenvolvimento → 🎉 Done | **Não** passa por Code Review, QA nem Homologação — só `task start` e `task done`. |
92
92
  | **RFC** | 📥 Backlog | decompõe direto em **Tasks** (que nascem em ✅ Ready) | Não usa spec/plan. |
93
93
  | **Bug** | 📥 Backlog | 🚧 Desenvolvimento → 🎉 Done | Ao aprovar, vai direto para Done (não passa por Homologação). |
94
94
  | **Spike** | 📥 Backlog | **movido só à mão pelo usuário** | Nunca avance a Etapa de um Spike por conta própria. |
95
95
 
96
- **Regra da Etapa:** a Etapa **só avança, nunca retrocede**. O campo **Status** (Todo / In Progress / Done) mede o progresso *dentro* da Etapa e reinicia a cada avanço. Prefira sempre os comandos da CLI (`task start|done`, `story review`) a mutações manuais no board — eles embutem essas regras.
96
+ **Regra da Etapa:** a Etapa **só avança, nunca retrocede**. O campo **Status** (Todo / In Progress / Done) mede o progresso *dentro* da Etapa e reinicia a cada avanço. Prefira sempre os comandos da CLI (`move`, `task start|done`, `story review`) a mutações manuais no board — eles embutem essas regras.
97
97
 
98
98
  Labels de gatilho:
99
99
  - `spec-wave:spec` → dispara `generate-spec.yml` → gera `spec.md` (especificação funcional, primeiro)
100
100
  - `spec-wave:plan` → dispara `generate-plan.yml` → gera `plan.md` (plano técnico, a partir da spec)
101
101
  - `spec-wave:ready` → dispara `validate.yml` → valida ambos os arquivos
102
- - `spec-wave:decompose` → dispara `decompose.yml` → gera Stories e Tasks
102
+ - `spec-wave:decompose` → dispara `decompose.yml` → gera (ou **re-critica**) o **rascunho** em `decomposition.md`. **Não cria issue nenhuma.**
103
+ - `spec-wave:decompose-apply` → dispara o mesmo workflow em modo aplicação → cria as Stories e Tasks **a partir do rascunho revisado**
103
104
 
104
105
  Labels de **estado** (gravadas pelas automações — **não** são gatilhos, não as adicione por conta própria):
105
- - `spec-wave:critique-failed` → a crítica adversarial apontou contradições **graves** nos documentos; **bloqueia** o `spec-wave:ready` até ser removida (veja *Crítica adversarial* abaixo)
106
+ - `spec-wave:decompose-ready` → o rascunho da decomposição passou pela crítica e espera **revisão humana**; aplique `spec-wave:decompose-apply` para criar as issues
107
+ - `spec-wave:critique-failed` → a crítica adversarial apontou contradições **graves**; **bloqueia** o `spec-wave:ready` até ser removida (veja *Crítica adversarial* abaixo)
108
+ - `spec-wave:needs-human` → a crítica reprovou N vezes seguidas (default 3); **para o fluxo** até uma pessoa revisar e remover a label
106
109
  - `spec-wave:decomposed` → a Feature/RFC já foi decomposta; o `decompose` pula silenciosamente enquanto ela existir (veja *Guard de idempotência* abaixo)
107
110
 
111
+ Label **modificadora** (esta você pode aplicar):
112
+ - `spec-wave:model:<apelido>` → força um modelo específico **naquela execução**, resolvido por `ai.modelAliases` no `.spec-wave.json`. Serve para reprocessar um caso difícil num modelo mais forte sem editar a configuração do repositório inteiro. Duas dessas labels na mesma issue = ambíguo, nenhuma vale.
113
+
108
114
  A etapa **🚧 Desenvolvimento** é coberta pelo comando **local** `npx @spec-wave/cli@latest implement <número>` (não é uma label/Action): lê uma **Feature** (todas as Stories pendentes, em ordem de dependência), uma Story ou uma Task e aciona o spec-kit para implementar. Veja `/spec-wave implement`.
109
115
 
110
116
  ---
@@ -174,15 +180,24 @@ Mesmas flags do `issue` (exceto `--type`, fixo em `feature`). Mantido para o flu
174
180
  |------|------|-----------|
175
181
  | `--global` | flag | Verifica a skill no escopo do usuário (padrão: projeto). |
176
182
  | `--skip-skill` / `--skip-config` / `--skip-repo` | flag | Pula a categoria correspondente. |
183
+ | `--branch [nome]` | flag/string | Envia os arquivos do repo como **Pull Request** numa branch, em **um único commit**, em vez de commitar direto na branch default. Sem valor, usa `spec-wave/update-v<versão>`. |
184
+ | `--config-in-pr` / `--no-config-in-pr` | flag | Força incluir/excluir o `.spec-wave.json` do PR (o default decide sozinho — veja abaixo). |
177
185
  | `--dry-run` | flag | Mostra o que seria atualizado sem alterar nada. |
178
186
  | `--yes` | flag | Aplica sem pedir confirmação. |
179
187
 
180
188
  > Detecta e atualiza **somente o que divergiu** da versão atual da CLI: a **skill** instalada (por agente), o **`.spec-wave.json`** local (se versão/formato divergir) e os **workflows/labels** do repo (compara com os templates empacotados). Interativo por padrão (mostra o plano e confirma). É o atalho recomendado após atualizar a CLI.
181
189
 
190
+ > **`--branch` (modo Pull Request).** Sem a flag, os arquivos do repo vão em **commits diretos na branch default** — o que falha no meio da execução em repositório com proteção de branch, deixando parte aplicada, e contorna a revisão. Com a flag, todos os arquivos vão em **um commit atômico** numa branch nova e um PR é aberto: se algo falhar antes da criação da branch, **nada** é alterado no repositório. É **idempotente** — rodar duas vezes não gera um segundo commit nem um segundo PR.
191
+ >
192
+ > Duas coisas **não** entram no PR, porque não são versionáveis: as **labels** (metadado do repositório — já valem na base, com ou sem merge) e a **skill** (arquivo em máquina local). O corpo do PR diz isso explicitamente a quem revisa.
193
+ >
194
+ > ⚠️ O modo PR exige **`pull_requests: write`** além de `contents: write` (ou o escopo `repo` num PAT classic). Sem essa permissão, a branch é criada e o PR falha — a mensagem oferece a URL de `compare` para abrir à mão.
195
+
182
196
  ### `@spec-wave/cli generate-plan` · `generate-spec` · `validate` · `decompose`
183
197
  | Flag | Tipo | Descrição |
184
198
  |------|------|-----------|
185
199
  | `--issue-number <n>` | string (obrigatório) | Número da issue no GitHub. |
200
+ | `--apply` | flag (só `decompose`) | Cria as issues a partir do `decomposition.md` revisado. **Sem** a flag, o `decompose` apenas gera/critica o rascunho e não cria nada. |
186
201
 
187
202
  > ⚠️ Esses quatro comandos são executados pelos **GitHub Actions** (disparados por labels), **não** pela skill diretamente. Veja a *Regra fundamental*: para gerar plan/spec/decompor, adicione a **label** correspondente — não rode o comando à mão (a não ser para debug local).
188
203
  >
@@ -195,12 +210,12 @@ Mesmas flags do `issue` (exceto `--type`, fixo em `feature`). Mantido para o flu
195
210
  |----------|------|-----------|
196
211
  | `<issue>` | string (obrigatório) | Número da issue (Feature, Story ou Task), ex.: `12` ou `#12`. Argumento posicional. |
197
212
  | `--feature-dir <path>` | string | Caminho `docs/features/<slug>` para anexar `spec.md`/`plan.md` como contexto (sobrescreve a resolução automática). |
198
- | `--dry-run` | flag | Monta o contexto e imprime o comando do spec-kit **sem executar**. |
213
+ | `--dry-run` | flag | Monta o contexto e imprime o comando do spec-kit **sem executar** e **sem escrever nada no GitHub** (não move cards, não adiciona itens ao Project). |
199
214
 
200
215
  > Diferente dos quatro acima, `implement` roda **localmente** (lê `.spec-wave.json`, como `issue`), não por Action. Detecta o tipo da issue: **Feature** → lista as Stories (sub-issues), **ordena topologicamente pelas dependências** (`Depende de:` + *blocked by*), **pula** as já em 👀 Code Review+ (listadas no contexto como "não tocar") e monta **um único** contexto com todas as pendentes (cada uma com suas Tasks), acionando o spec-kit **uma vez** com `{issue}/{type}/{title}` da Feature — **ciclo de dependências entre Stories pendentes aborta o comando (exit 1)**; **Story** → coleta todas as Tasks (sub-issues) e aciona o spec-kit uma única vez; **Task** → só aquela task. Monta o contexto em `.spec-wave/implement-<n>.md` e chama o comando configurado em `specKit.command` (no `.spec-wave.json`) ou na env `SPEC_WAVE_IMPLEMENT_CMD`. Placeholders disponíveis no template: `{tasksFile} {specFile} {planFile} {issue} {type} {title}`. Se nada estiver configurado, ele apenas monta o contexto e mostra como configurar (não executa). O contexto inclui os **comentários da issue**, um **digest do código recente** e um **aviso de dependências pendentes** quando a issue depende (linha `Depende de: #N` ou relação nativa *blocked by*) de outra que ainda não foi concluída — nesse caso, confirme com o usuário antes de seguir. Inclui também instruções para o agente implementar as Tasks **sequencialmente, uma por vez** (nunca duas com Status "In Progress" ao mesmo tempo): cada Task usa o **Status** (In Progress) *dentro* da Etapa 🚧 Desenvolvimento e, **ao concluir, avança para a Etapa 🎉 Done com Status Done**. **Ao concluir toda a Story**: fazer o commit, abrir o PR e **avançar a Etapa da Story para 👀 Code Review** (Status → Todo) — as Tasks já estão em 🎉 Done. A **Feature só avança** para Code Review quando **TODAS as suas Stories** já estiverem em Code Review — enquanto houver Story pendente, a Feature fica em 🚧 Desenvolvimento. Etapa só avança (nunca volta); Status mede o progresso dentro da etapa.
201
216
 
202
217
  ### `@spec-wave/cli doctor` — preflight de auth e configuração (comando LOCAL)
203
- Sem flags. Roda um checklist de diagnóstico no repositório atual: token GitHub (e a fonte dele), escopos (`repo`, `project`, `workflow` — com degradação para checks funcionais em fine-grained PATs), conta ativa do `gh` vs. owner, `.spec-wave.json` (campos e sincronia com o Project real), acesso ao repositório, configuração de IA (provider/modelo/`ai.models`/teto de saída + secrets do Actions), **spec-kit** (`specKit.command` / env `SPEC_WAVE_IMPLEMENT_CMD` — se ausente, avisa e sugere exemplos por agente: Claude Code, opencode, Codex, Copilot CLI, Kiro CLI, Qwen Code) e presença dos workflows.
218
+ Sem flags. Roda um checklist de diagnóstico no repositório atual: token GitHub (e a fonte dele), escopos (`repo`, `project`, `workflow` — com degradação para checks funcionais em fine-grained PATs), conta ativa do `gh` vs. owner, `.spec-wave.json` (campos e sincronia com o Project real), acesso ao repositório, configuração de IA (provider/modelo/`ai.models`/escalada da crítica/apelidos de modelo/teto de saída + secrets do Actions), **higiene do board e das labels** (colunas fora do fluxo canônico, labels `spec-wave:*` descontinuadas ou ausentes), **spec-kit** (`specKit.command` / env `SPEC_WAVE_IMPLEMENT_CMD` — se ausente, avisa e sugere exemplos por agente: Claude Code, opencode, Codex, Copilot CLI, Kiro CLI, Qwen Code) e os workflows (presença + **versão da CLI fixada**, não `@latest`).
204
219
 
205
220
  > Saída: `✓` ok, `✗` problema confirmado, `!` não verificável (best-effort — falha de rede nunca derruba o doctor). **Exit 1** se houver algum `✗`. **Quando rodar:** no início de uma sessão de trabalho, ou sempre que aparecer um erro estranho (ex.: **404 ao criar issues** — causa típica: token sem acesso ao repo/org, que o doctor aponta). É o primeiro passo de troubleshooting — prefira-o a depurar `gh api` na mão.
206
221
 
@@ -227,23 +242,88 @@ Sem flags. Roda um checklist de diagnóstico no repositório atual: token GitHub
227
242
 
228
243
  > Avança a Story para a Etapa **👀 Code Review** com Status **Todo** (o Status reinicia ao trocar de etapa). Mesma regra do `task`: a **Etapa nunca retrocede** — se a Story já estiver em Code Review ou adiante, o comando apenas informa a Etapa atual. Use no fim do `implement` de uma Story, em vez de mutações GraphQL manuais.
229
244
 
245
+ ### `@spec-wave/cli move <n> <etapa>` — move QUALQUER item do board (comando LOCAL)
246
+ | Flag/Arg | Tipo | Descrição |
247
+ |----------|------|-----------|
248
+ | `<n>` | string (obrigatório) | Número da issue, ex.: `8` ou `#8`. |
249
+ | `<etapa>` | string (obrigatório) | Etapa de destino, com ou sem emoji, sem acento e em qualquer caixa: `"code review"`, `"Homologação"`, `"🎉 Done"`. |
250
+ | `--status <valor>` | string | Valor do campo Status no destino: `Todo`, `In Progress` ou `Done` (default: `Todo`). |
251
+
252
+ > Serve para **Feature, Story, Task, Bug e RFC** — é o comando a usar quando `story review` e `task start|done` não cobrem o movimento desejado (ex.: mover uma **Feature** para Homologação). Embute as mesmas guardas: a **Etapa nunca retrocede** (se o item já estiver adiante, o comando informa a Etapa atual e não faz nada) e **Spike** é recusado (sua Etapa é movida à mão). Um nome de etapa ambíguo (`"p"` casa com Priorizado e Plan) é recusado listando as candidatas.
253
+ >
254
+ > **Prefira `move` a `gh api graphql` manual.** Não existe escape hatch para retroceder — isso é a regra do fluxo, não uma limitação.
255
+
230
256
  ---
231
257
 
232
- ## Crítica adversarial, idempotência e dependências (v0.7)
258
+ ## Crítica adversarial, decomposição em duas etapas e dependências
233
259
 
234
260
  ### Crítica adversarial (comentário 🔎)
235
261
 
236
- Após o `generate-plan` e **antes** da criação de issues no `decompose`, um segundo agente de IA critica os documentos procurando contradições, lacunas e riscos. O resultado vira um comentário **🔎 Crítica adversarial (spec-wave)** na issue.
262
+ Depois do `generate-plan` e **antes** de qualquer issue ser criada no `decompose`, um segundo agente de IA audita o artefato procurando contradições com a spec, o plan e o `tech_context`. O resultado vira um comentário **🔎 Crítica adversarial (spec-wave)** na issue, com cabeçalho informando a **tentativa** e o **modelo** usados.
263
+
264
+ A saída da crítica é **estruturada e validada por schema**: `severity` só aceita `grave` ou `menor`, e um payload fora do contrato **falha alto** em vez de virar um finding menor com JSON cru dentro. Se a crítica não conclui, ela **não** é registrada como aprovada.
265
+
266
+ **A remediação depende de ONDE a crítica reprovou — são superfícies diferentes:**
267
+
268
+ | Reprovou depois de | O que corrigir | Como retomar |
269
+ |--------------------|----------------|--------------|
270
+ | `generate-plan` | `plan.md` (ou a `spec.md` que o embasa) | corrija/regere → remova `spec-wave:critique-failed` → reaplique `spec-wave:ready` |
271
+ | `decompose` (rascunho) | **`decomposition.md`** — os achados citam **`Story N`** e **`Task N.M`**, que são os títulos desse arquivo | edite o arquivo e commite → remova `spec-wave:critique-failed` → reaplique `spec-wave:decompose` (ele **critica o arquivo como está**, sem regerar) |
272
+
273
+ > ⚠️ No contexto do `decompose`, os achados são sobre as **Stories propostas**, não sobre o `plan.md`. Corrigir o plan não influencia o rascunho já gravado — edite o `decomposition.md` diretamente. Foi exatamente essa confusão que fazia o ciclo não convergir.
274
+
275
+ - Findings **graves** no `decompose` → **nenhuma Story/Task é criada** e o Action **falha (exit 1)**, com a label `spec-wave:critique-failed`. Um pipeline bloqueado nunca fica verde.
276
+ - Findings **menores** não bloqueiam — trate-os como revisão de qualidade.
277
+ - **Escalada:** na tentativa 2 a crítica roda em `ai.escalationModel` (se configurado). Ao atingir `ai.maxCritiqueAttempts` (default 3), o fluxo aplica **`spec-wave:needs-human`**, comenta e **para** — sem chamar a IA de novo. Para retomar: corrija os documentos e remova **as duas** labels (`spec-wave:needs-human` e `spec-wave:critique-failed`).
278
+ - Uma crítica **limpa** remove a `spec-wave:critique-failed` automaticamente e zera o contador de tentativas.
279
+
280
+ ### Decomposição em duas etapas (`decomposition.md`)
281
+
282
+ O `decompose` **não cria issues direto**. São dois passos, com um artefato revisável no meio:
283
+
284
+ ```
285
+ spec-wave:decompose
286
+ ├─ decomposition.md ausente → gera via IA → commita → critica
287
+ └─ decomposition.md presente → critica o arquivo COMO ESTÁ (preserva suas edições)
288
+ ├─ grave → +critique-failed, comentário citando Story N / Task N.M, exit 1
289
+ └─ limpo → +decompose-ready, comentário "revise e aplique"
290
+
291
+ spec-wave:decompose-apply
292
+ └─ lê decomposition.md → cria Stories/Tasks → board → +decomposed
293
+ (sem nova crítica: aplicar a label É a aprovação humana)
294
+ ```
295
+
296
+ O arquivo fica em **`docs/features/<slug>/decomposition.md`** (Feature) ou **`docs/rfcs/<slug>/decomposition.md`** (RFC). Formato:
237
297
 
238
- - Findings **graves** → o Action aplica a label **`spec-wave:critique-failed`**, que **bloqueia o `spec-wave:ready`** (o `validate` falha enquanto ela existir).
239
- - **Fluxo de resolução:** (1) leia o comentário 🔎 na issue; (2) corrija `spec.md`/`plan.md` (regenere com as labels ou edite e commite); (3) remova a label: `gh issue edit <n> --remove-label "spec-wave:critique-failed"`; (4) re-aplique `spec-wave:ready` para validar de novo.
240
- - Findings leves não bloqueiam — trate-os como revisão de qualidade.
298
+ ```markdown
299
+ # Decomposição [FEATURE] Cadastro de Pedidos
300
+ <!-- spec-wave:decomposition v1 issue=360 kind=stories -->
301
+
302
+ ## Story 1 — visualizar meus pedidos
303
+
304
+ **User story:** Como cliente, quero visualizar meus pedidos, para acompanhar entregas
305
+ **Depende de:** —
306
+
307
+ Descrição complementar (contexto, critérios de aceite).
308
+
309
+ ### Task 1.1 — criar endpoint GET /pedidos
310
+
311
+ Corpo técnico.
312
+ ```
313
+
314
+ **Ao editar à mão:**
315
+ - a **posição** manda, não o número escrito — inserir uma Story no meio sem renumerar funciona;
316
+ - `**Depende de:**` usa referências **1-based** (`Story 1, Story 3`) ou `—`; apontar para si mesma ou para frente é **erro**, não filtro silencioso;
317
+ - o corpo aceita markdown livre (`## Backend`, cercas de código) — só `## Story N` e `### Task N.M` são estrutura;
318
+ - **para gerar outro rascunho do zero:** apague o arquivo e reaplique `spec-wave:decompose`.
241
319
 
242
320
  ### Guard de idempotência do decompose (`spec-wave:decomposed`)
243
321
 
244
- O evento `labeled` pode redisparar (re-add da label, retry de runner). Para não duplicar Stories/Tasks, o `decompose` **pula** quando a issue já tem a label **`spec-wave:decomposed`** ou já tem sub-issues do tipo-alvo (`[STORY]` para Feature, `[TASK]` para RFC). Ao concluir com sucesso, o Action grava a label. Os workflows ainda usam `concurrency` por issue para serializar runs simultâneos.
322
+ O evento `labeled` pode redisparar (re-add da label, retry de runner). Para não duplicar Stories/Tasks, o `decompose` **pula** quando a issue já tem a label **`spec-wave:decomposed`** ou já tem sub-issues do tipo-alvo (`[STORY]` para Feature, `[TASK]` para RFC). O Action grava a label ao **aplicar** a decomposição. Os workflows ainda usam `concurrency` por issue para serializar runs simultâneos.
323
+
324
+ A `spec-wave:decompose-ready` **não** entra nesse guard: é estado de rascunho pendente, não de decomposição feita.
245
325
 
246
- **Para forçar um re-decompose:** remova a label (`gh issue edit <n> --remove-label "spec-wave:decomposed"`), **apague/feche as sub-issues antigas** (senão a detecção por sub-issues pula de novo) e re-adicione `spec-wave:decompose`.
326
+ **Para forçar um re-decompose:** remova a label (`gh issue edit <n> --remove-label "spec-wave:decomposed"`), **apague/feche as sub-issues antigas** (senão a detecção por sub-issues pula de novo), apague o `decomposition.md` se quiser um rascunho novo, e re-adicione `spec-wave:decompose`.
247
327
 
248
328
  ### Dependências entre Stories (`Depende de: #N`)
249
329
 
@@ -266,12 +346,37 @@ Cada ação de IA (`spec`, `plan`, `decompose`, `critique`) pode usar um modelo
266
346
  "models": {
267
347
  "plan": "claude-opus-4-1",
268
348
  "critique": "claude-opus-4-1"
349
+ },
350
+ "escalationModel": "claude-opus-5",
351
+ "maxCritiqueAttempts": 3,
352
+ "modelAliases": {
353
+ "opus": "claude-opus-5",
354
+ "haiku": "claude-haiku-4-5"
269
355
  }
270
356
  }
271
357
  }
272
358
  ```
273
359
 
274
- Edite o bloco `ai` no `.spec-wave.json` (e commite) — o `doctor` mostra o provider, o modelo e os overrides de `ai.models` resolvidos.
360
+ - `escalationModel` modelo usado a partir da **segunda** tentativa da crítica.
361
+ - `maxCritiqueAttempts` → quantas reprovas seguidas antes de exigir revisão humana (`spec-wave:needs-human`).
362
+ - `modelAliases` → apelidos para a label **`spec-wave:model:<apelido>`**.
363
+
364
+ **Precedência do modelo:** `SPEC_WAVE_MODEL` (env) → label `spec-wave:model:<apelido>` → escalada automática da crítica → `ai.models[ação]` → `ai.model` → default do provider.
365
+
366
+ Edite o bloco `ai` no `.spec-wave.json` (e commite) — o `doctor` mostra o provider, o modelo, os apelidos, a escalada e os overrides resolvidos.
367
+
368
+ ### Override de modelo numa execução (`spec-wave:model:<apelido>`)
369
+
370
+ Para reprocessar **uma issue difícil** num modelo mais forte sem editar a configuração do repositório inteiro:
371
+
372
+ ```bash
373
+ # 1. Garanta o apelido em ai.modelAliases (uma vez, commitado)
374
+ # 2. Aplique a label na issue e redispare o gatilho
375
+ gh issue edit 360 --add-label "spec-wave:model:opus"
376
+ gh issue edit 360 --add-label "spec-wave:decompose"
377
+ ```
378
+
379
+ A label vale só para as execuções daquela issue e **vence a escalada automática** (é decisão humana explícita). Apelido desconhecido é ignorado com aviso; duas labels dessas na mesma issue = ambíguo, nenhuma vale.
275
380
 
276
381
  ### Teto de saída (`ai.maxTokens`) e truncamento
277
382
 
@@ -320,12 +425,16 @@ Traz tudo para a versão atual da CLI, atualizando **só o que mudou**: a skill
320
425
  npx @spec-wave/cli@latest update --dry-run
321
426
  ```
322
427
  2. Mostre ao usuário o resumo (skill / config / arquivos do repo / labels que divergiram). Se **nada** estiver desatualizado, informe que já está tudo na versão atual e encerre.
323
- 3. Se o usuário aprovar, aplique:
428
+ 3. **Pergunte como os arquivos do repo devem sair** — e prefira o Pull Request:
324
429
  ```bash
325
- npx @spec-wave/cli@latest update --yes
430
+ npx @spec-wave/cli@latest update --yes --branch # 1 commit atômico + PR (recomendado)
431
+ npx @spec-wave/cli@latest update --yes # commits diretos na branch default
326
432
  ```
327
433
  - Escopos podem ser limitados com `--skip-skill`, `--skip-config`, `--skip-repo`.
328
- - Atualizações de **arquivos do repo** são commitadas no remoto; o **`.spec-wave.json`** é local (lembre o usuário de commitá-lo).
434
+ - **Com `--branch`:** os arquivos do repo vão em **um único commit** numa branch nova e um PR é aberto nada é escrito na branch default. Passe o link do PR ao usuário e lembre que o merge é dele. Exige `pull_requests: write` no token.
435
+ - **Sem `--branch`:** cada arquivo é um commit direto na branch default. Em repositório com **proteção de branch** isso falha no meio e deixa parte aplicada — nesses casos use `--branch`.
436
+ - **Nos dois modos**, as **labels** são aplicadas direto na base (metadado do repositório, não versionável) e a **skill** é gravada em máquina local. Nenhuma das duas entra no PR.
437
+ - **`.spec-wave.json`:** com `--branch`, ele entra no PR se o repositório **já o versiona**; se não versiona, segue apenas local e o usuário precisa commitá-lo (ou use `--config-in-pr` para passar a versioná-lo). Sem `--branch`, é sempre só local.
329
438
  4. Se a skill foi atualizada, oriente recarregar/reiniciar o agente para pegar a nova versão.
330
439
 
331
440
  ---
@@ -495,28 +604,39 @@ Valida que spec.md e plan.md estão completos e a Feature pode avançar.
495
604
  ```
496
605
  2. Informe: "Validação iniciada. O workflow verificará se spec.md e plan.md contêm todas as seções obrigatórias."
497
606
  3. Se a validação falhar, o workflow comentará os problemas na issue e adicionará automaticamente `spec-wave:spec`. Informe o usuário para corrigir e tentar novamente.
498
- 4. **Se a issue tiver a label `spec-wave:critique-failed`**, a validação falha de imediato: a crítica adversarial apontou contradições graves (comentário 🔎 na issue). Siga o fluxo de resolução da seção *Crítica adversarial*: corrigir os documentos → remover a label → re-aplicar `spec-wave:ready`.
499
- 5. Se passar, oriente: "Feature validada! Mova o card para **✅ Ready** e use `/spec-wave decompose <número>` para gerar as Stories."
607
+ 4. **Se a issue tiver `spec-wave:critique-failed` ou `spec-wave:needs-human`**, a validação falha de imediato — são portões humanos: a crítica apontou contradições graves (comentário 🔎 na issue) ou esgotou as tentativas. Nesses casos a Feature **não** é devolvida para a etapa de spec; siga o fluxo da seção *Crítica adversarial* (corrigir a superfície certa → remover a label → re-aplicar `spec-wave:ready`).
608
+ 5. Se passar, oriente: "Feature validada! Mova o card para **✅ Ready** e use `/spec-wave decompose <número>` para gerar o **rascunho** das Stories (nada é criado ainda)."
500
609
 
501
610
  ---
502
611
 
503
612
  ### `/spec-wave decompose <número-da-issue>`
504
613
 
505
- Decompõe automaticamente. Aplica-se a **dois tipos**:
506
- - **Feature** → gera **Stories** (cada uma com suas **Tasks**), a partir de `spec.md` + `plan.md`.
507
- - **RFC** → gera **Tasks diretamente** (sem Stories), a partir da descrição do RFC.
614
+ Decompõe em **duas etapas**, com um rascunho revisável no meio (veja *Decomposição em duas etapas*). Aplica-se a **dois tipos**:
615
+ - **Feature** → **Stories** (cada uma com suas **Tasks**), a partir de `spec.md` + `plan.md`.
616
+ - **RFC** → **Tasks diretamente** (sem Stories), a partir da descrição do RFC.
508
617
 
509
618
  Para qualquer outro tipo (Spike, Bug, Story, Task, …) o Action **recusa** e comenta.
510
619
 
511
620
  **Passos:**
512
621
  1. Para **Feature**: confirme que está em **✅ Ready** (spec.md e plan.md validados). Para **RFC**: basta a descrição estar completa (RFC não usa spec/plan).
513
- 2. Adicione a label de decomposição:
622
+ 2. **Etapa 1 gerar o rascunho:**
514
623
  ```bash
515
624
  gh issue edit <número> --add-label "spec-wave:decompose"
516
625
  ```
517
- 3. Informe: "Decomposição iniciadaFeature gera Stories+Tasks; RFC gera Tasks."
518
- 4. Após a conclusão, as issues filhas aparecerão como comentário na issue pai, junto com o comentário 🔎 da crítica adversarial. A issue pai e as Stories/Tasks criadas entram no board na Etapa **✅ Ready** (Status Todo; a Etapa nunca retrocede — itens já adiante não são tocados). As Stories geradas trazem a linha `Depende de: #N` (+ relação *blocked by*) — use `npx @spec-wave/cli@latest order <número>` para ver a ordem de execução.
519
- 5. A issue recebe a label `spec-wave:decomposed` (guard de idempotência): rodar de novo **não** duplica as issues. Para forçar um re-decompose, siga a seção *Guard de idempotência*.
626
+ Informe: "Rascunho iniciadovai commitar `decomposition.md` e passar pela crítica. **Nenhuma issue é criada nesta etapa.**"
627
+ 3. Quando o Action terminar, leia o comentário na issue:
628
+ - **`spec-wave:decompose-ready`** o rascunho passou pela crítica. **Leia o `decomposition.md`** e mostre ao usuário o que será criado (Stories, Tasks, dependências). Ofereça editar o arquivo antes de aplicar.
629
+ - **`spec-wave:critique-failed`** → o Action **falhou (exit 1)** e nada foi criado. Os achados citam `Story N` / `Task N.M` do `decomposition.md`. **Corrija esse arquivo** (não o `plan.md`), commite e reaplique `spec-wave:decompose` — o arquivo é criticado como está, sem ser regerado.
630
+ - **`spec-wave:needs-human`** → a crítica esgotou as tentativas. Pare e envolva o usuário: as duas labels precisam sair à mão.
631
+ 4. **Etapa 2 — aplicar o rascunho aprovado** (só depois da revisão):
632
+ ```bash
633
+ gh issue edit <número> --add-label "spec-wave:decompose-apply"
634
+ ```
635
+ Aplicar essa label **é** a aprovação humana — não há nova crítica.
636
+ 5. Após a aplicação, as issues filhas aparecem como comentário na issue pai. A issue pai e as Stories/Tasks criadas entram no board na Etapa **✅ Ready** (Status Todo; a Etapa nunca retrocede — itens já adiante não são tocados). As Stories trazem a linha `Depende de: #N` (+ relação *blocked by*) — use `npx @spec-wave/cli@latest order <número>` para ver a ordem de execução.
637
+ 6. A issue recebe a label `spec-wave:decomposed` (guard de idempotência): rodar de novo **não** duplica as issues. Para forçar um re-decompose, siga a seção *Guard de idempotência*.
638
+
639
+ > **Nunca pule a etapa 1** aplicando `spec-wave:decompose-apply` direto: sem `decomposition.md` o Action falha pedindo o rascunho.
520
640
 
521
641
  ---
522
642
 
@@ -682,8 +802,16 @@ Audita um Pull Request e corrige automaticamente os problemas encontrados — se
682
802
  docs/
683
803
  features/
684
804
  <slug-da-feature>/
685
- spec.md ← gerado pelo GitHub Action quando spec-wave:spec é adicionado (1º)
686
- plan.md ← gerado pelo GitHub Action quando spec-wave:plan é adicionado (2º, usa a spec)
805
+ spec.md ← gerado quando spec-wave:spec é adicionado (1º)
806
+ plan.md ← gerado quando spec-wave:plan é adicionado (2º, usa a spec)
807
+ decomposition.md ← rascunho gerado quando spec-wave:decompose é adicionado (3º).
808
+ REVISÁVEL e EDITÁVEL à mão; as issues só nascem com
809
+ spec-wave:decompose-apply
810
+ rfcs/
811
+ <slug-do-rfc>/
812
+ decomposition.md ← mesmo papel, com "## Task N" (RFC não usa spec/plan)
687
813
  ```
688
814
 
689
815
  O slug é gerado a partir do título da issue: `[FEATURE] Cadastro de Pedidos com PIX` → `cadastro-de-pedidos-com-pix`
816
+
817
+ > ⚠️ O slug vem do **título**. Renomear a Feature entre o rascunho e o apply muda o diretório e o `decomposition.md` antigo fica órfão — o apply reclama que não encontrou o rascunho.
@@ -24,7 +24,7 @@ jobs:
24
24
  node-version: '24'
25
25
 
26
26
  - name: Move Feature to Code Review
27
- run: npx @spec-wave/cli@latest code-review --pr-number ${{ github.event.pull_request.number }}
27
+ run: npx @spec-wave/cli@{{CLI_VERSION}} code-review --pr-number ${{ github.event.pull_request.number }}
28
28
  env:
29
29
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30
30
  PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
@@ -4,8 +4,9 @@ on:
4
4
  issues:
5
5
  types: [labeled]
6
6
 
7
- # O evento `labeled` pode redisparar (re-add da label, retry de runner):
8
- # o concurrency serializa runs da mesma issue e o guard de idempotência
7
+ # O evento `labeled` pode redisparar (re-add da label, retry de runner). O
8
+ # concurrency serializa runs da mesma issue inclusive um `decompose-apply`
9
+ # enfileirado atrás de um `decompose` — e o guard de idempotência
9
10
  # (label spec-wave:decomposed) descarta o run enfileirado.
10
11
  concurrency:
11
12
  group: spec-wave-decompose-${{ github.event.issue.number }}
@@ -13,23 +14,36 @@ concurrency:
13
14
 
14
15
  jobs:
15
16
  decompose:
17
+ # Duas etapas, duas labels:
18
+ # • spec-wave:decompose → grava/re-critica docs/**/decomposition.md
19
+ # • spec-wave:decompose-apply → cria as Stories/Tasks a partir do rascunho
20
+ # O `[RFC]` no título também dispara: o caminho RFC → Tasks existe na CLI
21
+ # desde sempre, mas era inalcançável porque o filtro exigia `[FEATURE]`.
16
22
  if: >
17
- github.event.label.name == 'spec-wave:decompose' &&
18
- contains(github.event.issue.title, '[FEATURE]')
23
+ (github.event.label.name == 'spec-wave:decompose' ||
24
+ github.event.label.name == 'spec-wave:decompose-apply') &&
25
+ (contains(github.event.issue.title, '[FEATURE]') ||
26
+ contains(github.event.issue.title, '[RFC]'))
19
27
  runs-on: ubuntu-latest
20
28
  permissions:
21
29
  issues: write
22
- contents: read
30
+ # A etapa de rascunho commita docs/**/decomposition.md no branch default.
31
+ contents: write
23
32
 
24
33
  steps:
25
34
  - uses: actions/checkout@v4
35
+ with:
36
+ token: ${{ secrets.GITHUB_TOKEN }}
26
37
 
27
38
  - uses: actions/setup-node@v4
28
39
  with:
29
40
  node-version: '24'
30
41
 
31
42
  - name: Decompose into Stories and Tasks
32
- run: npx @spec-wave/cli@latest decompose --issue-number ${{ github.event.issue.number }}
43
+ run: >
44
+ npx @spec-wave/cli@{{CLI_VERSION}} decompose
45
+ --issue-number ${{ github.event.issue.number }}
46
+ ${{ github.event.label.name == 'spec-wave:decompose-apply' && '--apply' || '' }}
33
47
  env:
34
48
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35
49
  PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
@@ -28,7 +28,7 @@ jobs:
28
28
  node-version: '24'
29
29
 
30
30
  - name: Generate plan.md
31
- run: npx @spec-wave/cli@latest generate-plan --issue-number ${{ github.event.issue.number }}
31
+ run: npx @spec-wave/cli@{{CLI_VERSION}} generate-plan --issue-number ${{ github.event.issue.number }}
32
32
  env:
33
33
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34
34
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -28,7 +28,7 @@ jobs:
28
28
  node-version: '24'
29
29
 
30
30
  - name: Generate spec.md
31
- run: npx @spec-wave/cli@latest generate-spec --issue-number ${{ github.event.issue.number }}
31
+ run: npx @spec-wave/cli@{{CLI_VERSION}} generate-spec --issue-number ${{ github.event.issue.number }}
32
32
  env:
33
33
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34
34
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -25,7 +25,7 @@ jobs:
25
25
  node-version: '24'
26
26
 
27
27
  - name: Move Feature to QA
28
- run: npx @spec-wave/cli@latest qa --pr-number ${{ github.event.pull_request.number }}
28
+ run: npx @spec-wave/cli@{{CLI_VERSION}} qa --pr-number ${{ github.event.pull_request.number }}
29
29
  env:
30
30
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31
31
  PROJECT_TOKEN: ${{ secrets.GH_PROJECT_TOKEN }}
@@ -26,7 +26,7 @@ jobs:
26
26
  node-version: '24'
27
27
 
28
28
  - name: Validate spec and plan
29
- run: npx @spec-wave/cli@latest validate --issue-number ${{ github.event.issue.number }}
29
+ run: npx @spec-wave/cli@{{CLI_VERSION}} validate --issue-number ${{ github.event.issue.number }}
30
30
  env:
31
31
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32
32
  GITHUB_REPOSITORY: ${{ github.repository }}