@spec-wave/cli 0.30.0 → 0.32.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.
- package/package.json +5 -3
- package/protocol/qa-result.v1.json +62 -0
- package/protocol/qa-trail-report.v1.json +113 -0
- package/src/api/github-graphql.mjs +6 -1
- package/src/api/github-rest.mjs +21 -0
- package/src/cli.mjs +80 -5
- package/src/commands/decompose.mjs +29 -3
- package/src/commands/doctor.mjs +102 -3
- package/src/commands/implement.mjs +56 -44
- package/src/commands/merge.mjs +43 -14
- package/src/commands/order.mjs +350 -96
- package/src/commands/qa-lead.mjs +748 -0
- package/src/commands/qa-run.mjs +104 -25
- package/src/config.mjs +15 -0
- package/src/lib/artifact-publish.mjs +5 -2
- package/src/lib/board.mjs +14 -0
- package/src/lib/dependency-map.mjs +300 -0
- package/src/lib/doc-paths.mjs +4 -0
- package/src/lib/git-retry.mjs +82 -0
- package/src/lib/net-cache.mjs +142 -0
- package/src/lib/qa-exec.mjs +23 -2
- package/src/lib/qa-lead-backend.mjs +213 -0
- package/src/lib/qa-lead.mjs +627 -0
- package/src/lib/qa-report.mjs +65 -9
- package/src/lib/skill-compose.mjs +234 -0
- package/src/lib/story-graph.mjs +256 -0
- package/src/plugin/.claude-plugin/plugin.json +1 -1
- package/src/plugin/skills/merge/SKILL.md +1 -0
- package/src/plugin/skills/order/SKILL.md +21 -5
- package/src/plugin/skills/qa/SKILL.md +3 -1
- package/src/plugin/skills/qa-executor/SKILL.md +76 -0
- package/src/plugin/skills/qa-lead/SKILL.md +89 -0
- package/src/templates/skill/SKILL.md +953 -298
- package/src/templates/skill/core.md +584 -0
|
@@ -11,13 +11,28 @@ allowed-tools:
|
|
|
11
11
|
Comando **local**:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx @spec-wave/cli@latest order <feature>
|
|
15
|
-
npx @spec-wave/cli@latest order
|
|
14
|
+
npx @spec-wave/cli@latest order <feature> # uma Feature
|
|
15
|
+
npx @spec-wave/cli@latest order # o mapa de todas as Features com trabalho
|
|
16
|
+
npx @spec-wave/cli@latest order --milestone v04 # só as Features da milestone
|
|
17
|
+
npx @spec-wave/cli@latest order --json # contrato estável p/ scripts e agentes
|
|
18
|
+
npx @spec-wave/cli@latest order <feature> --sync # blocked_by da API → doc + dependency-map.json
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
| Arg | Descrição |
|
|
21
|
+
| Arg/Flag | Descrição |
|
|
19
22
|
|-----|-----------|
|
|
20
23
|
| `<feature>` | Número da issue da **Feature**, ex.: `12` ou `#12`. Posicional, **opcional**. |
|
|
24
|
+
| `--milestone <ref>` | Filtra o mapa sem argumento pelas Features da milestone (número ou título). |
|
|
25
|
+
| `--json` | Saída JSON estável (sem ANSI) — **prefira-a para consumo programático**, em vez de parsear o texto. |
|
|
26
|
+
| `--remote` | Une também o blocked_by da API (1 chamada por Story) — pega arestas criadas SÓ pela UI. |
|
|
27
|
+
| `--refresh` | Ignora o cache local e reconsulta a API. |
|
|
28
|
+
| `--sync` | Reescreve as linhas `Depende de:` do decomposition.md e regenera o `dependency-map.json` a partir do estado VIVO (body ∪ blocked_by), com commit local. |
|
|
29
|
+
|
|
30
|
+
**De onde vem a informação (e por que é barato):** as arestas saem de fontes **locais** — o
|
|
31
|
+
`docs/features/<slug>/dependency-map.json` (escrito pelo `decompose --apply`), o
|
|
32
|
+
`decomposition.md` aplicado e as linhas `Depende de:` do corpo — zero chamada por Story. A
|
|
33
|
+
Etapa vem de **um** snapshot do board, cacheado por `cache.ttlSec` (default 600s; env
|
|
34
|
+
`SPEC_WAVE_CACHE_TTL`; `0` desliga) com a idade sempre impressa. Um `blocked_by` criado só
|
|
35
|
+
pela UI não está nas fontes locais: a saída avisa, e `--remote`/`--sync` o incluem.
|
|
21
36
|
|
|
22
37
|
**Sem argumento**, o conjunto vem do **board** (não dos arquivos): todas as Features abertas fora de 🎉 Done, com as Stories de todas num **grafo só** e a Feature de cada uma ao lado. É o modo para responder "por onde os devs pegam agora" quando o trabalho está espalhado por várias Features — nesse escopo, dependência entre Features deixa de ser "externa" e entra na ordenação.
|
|
23
38
|
|
|
@@ -25,7 +40,7 @@ npx @spec-wave/cli@latest order # o mapa de todas as Features com tr
|
|
|
25
40
|
|
|
26
41
|
## O que a saída traz
|
|
27
42
|
|
|
28
|
-
- As Stories da Feature em **ordem topológica** pelas dependências —
|
|
43
|
+
- As Stories da Feature em **ordem topológica** pelas dependências — dependency-map.json ∪ decomposition.md ∪ linha `Depende de: #N` do corpo (e, com `--remote`, a relação nativa *blocked by*)
|
|
29
44
|
- A **Etapa atual** de cada Story no board
|
|
30
45
|
- Avisos de **ciclo de dependência** — essas Stories ficam **fora da ordem**; corrija as linhas `Depende de:`
|
|
31
46
|
- Avisos de **dependência fora de ordem** — Story já em 🚧 Desenvolvimento ou além dependendo de outra que não está em 🎉 Done (no modo de uma Feature, também quando a bloqueadora é de **outra** Feature e continua aberta)
|
|
@@ -38,4 +53,5 @@ npx @spec-wave/cli@latest order # o mapa de todas as Features com tr
|
|
|
38
53
|
2. Apresente a ordem ao usuário, marcando o que já está concluído e o que está pendente.
|
|
39
54
|
3. **Se houver ciclo**, isso é bloqueante para a skill **implement** no modo Feature (o comando aborta com exit 1). Ajude a quebrar o ciclo editando as linhas `Depende de:` nos corpos das Stories.
|
|
40
55
|
4. **Se houver dependência fora de ordem**, aponte o risco ao usuário antes de seguir.
|
|
41
|
-
5.
|
|
56
|
+
5. Se o usuário criou/removeu `blocked_by` **pela UI do GitHub**, rode `order <feature> --sync` para gravar isso nos artefatos — as consultas seguintes voltam a ser locais.
|
|
57
|
+
6. Com a ordem clara, siga para a skill **implement**.
|
|
@@ -71,7 +71,9 @@ Mostre ao usuário o contexto montado em `.spec-wave/qa-<n>.md` antes de rodar s
|
|
|
71
71
|
|
|
72
72
|
Alvos: `qa <feature>` roda todos os cenários das Stories ainda sem `qa-approved`; `qa <story>` só os daquela Story; `qa <bug>` o Teste de Regressão do `bug.md`; `--only <n[,m]>` filtra por número posicional.
|
|
73
73
|
|
|
74
|
-
**PROIBIDO corrigir código durante a execução.** QA não conserta: cenário reprovado vira Bug, e alterar o código no meio invalida o veredito. Se você for o executor (via `qa.command`), siga as instruções do contexto à risca — um cenário por vez, evidência bruta, `blocked` (nunca `fail`) para o que não pôde rodar.
|
|
74
|
+
**PROIBIDO corrigir código durante a execução.** QA não conserta: cenário reprovado vira Bug, e alterar o código no meio invalida o veredito. Se você for o executor (via `qa.command`), siga a skill **qa-executor** e as instruções do contexto à risca — um cenário por vez, evidência bruta, `blocked` (nunca `fail`) com o `blockedReason` do enum para o que não pôde rodar.
|
|
75
|
+
|
|
76
|
+
Para validar uma **trilha inteira** (todas as Features de um milestone, em containers paralelos), use a skill **qa-lead** — o `qa` continua sendo a unidade que ela orquestra.
|
|
75
77
|
|
|
76
78
|
## 4. Os três desfechos
|
|
77
79
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-wave-qa-executor
|
|
3
|
+
description: "Use quando você for o agente EXECUTOR de QA do spec-wave — acionado via `qa.command` com um contexto `.spec-wave/qa-<n>.md`. Executa os cenários um a um, registra evidência bruta e grava o veredito em `.spec-wave/qa-result-<n>.json`. NUNCA corrige código nem escreve no GitHub. Gatilhos: 'execute o QA descrito em', contexto de QA do spec-wave, arquivo qa-<n>.md."
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# spec-wave qa-executor — o agente que executa os cenários
|
|
11
|
+
|
|
12
|
+
Você foi acionado pelo `spec-wave qa <n>` (diretamente ou por um container do
|
|
13
|
+
`qa-lead`). Seu trabalho é **executar cenários e registrar o que observou** — o
|
|
14
|
+
veredito volta pelo **arquivo de resultados**, nunca por texto ou exit code.
|
|
15
|
+
|
|
16
|
+
## O que ler
|
|
17
|
+
|
|
18
|
+
1. O **contexto** (`.spec-wave/qa-<n>.md`, indicado no prompt): traz os cenários
|
|
19
|
+
a executar NESTA ORDEM, o setup do ambiente, o caminho do arquivo de
|
|
20
|
+
resultados e os comentários relevantes das issues.
|
|
21
|
+
2. O **plano** (`docs/features/<slug>/qa-plan.md`) e a **spec**
|
|
22
|
+
(`docs/features/<slug>/spec.md`), apontados no contexto — leia-os para
|
|
23
|
+
entender os critérios de aceite antes do primeiro cenário.
|
|
24
|
+
|
|
25
|
+
## Regras de execução (OBRIGATÓRIAS)
|
|
26
|
+
|
|
27
|
+
1. **Um cenário por vez, na ordem do contexto.** Não paralelize, não pule.
|
|
28
|
+
2. **Evidência bruta, sem paráfrase** — o comando executado, a saída relevante e
|
|
29
|
+
o código de status. A evidência de um `fail` vira o `bug.md` do Bug aberto:
|
|
30
|
+
"não funcionou" não reproduz nada; `500 — TypeError: cannot read 'id' of
|
|
31
|
+
undefined` reproduz.
|
|
32
|
+
3. **PROIBIDO corrigir código.** QA não conserta. Alterar qualquer código
|
|
33
|
+
durante a execução **invalida o veredito de todos os cenários da corrida**,
|
|
34
|
+
inclusive os que já passaram.
|
|
35
|
+
4. **PROIBIDO escrever no GitHub.** Não comente, não abra issue, não mova card —
|
|
36
|
+
isso é do comando `qa`, depois de ler seu resultado. Com o `qa-lead`, N
|
|
37
|
+
executores rodam em paralelo: dois agentes escrevendo no board é exatamente o
|
|
38
|
+
que esta regra impede.
|
|
39
|
+
5. **`blocked` nunca é `fail`.** Cenário que não pôde ser executado
|
|
40
|
+
(pré-condição ausente, serviço fora, seed que falhou, dependência não
|
|
41
|
+
entregue) é `blocked` com o `blockedReason` do enum. Marcar como `fail` cria
|
|
42
|
+
um Bug falso e custa investigação de dev.
|
|
43
|
+
|
|
44
|
+
## Como registrar o veredito
|
|
45
|
+
|
|
46
|
+
Ao terminar (ou ao abortar no meio), grave `.spec-wave/qa-result-<n>.json` — o
|
|
47
|
+
caminho exato está no contexto:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"scenarios": [
|
|
52
|
+
{ "cenario": 1, "verdict": "pass", "evidencia": "GET /pedidos → 200; 2 pedidos, ambos de A" },
|
|
53
|
+
{ "cenario": 2, "verdict": "fail", "evidencia": "500 — TypeError: cannot read 'id' of undefined" },
|
|
54
|
+
{ "cenario": 3, "verdict": "blocked", "blockedReason": "massa-de-dados",
|
|
55
|
+
"evidencia": "seed falhou: tabela `pedidos` inexistente" }
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- **Um objeto por cenário-alvo**, com o número POSICIONAL. Nenhum pode ser
|
|
61
|
+
omitido: se você abortar no meio, os cenários não alcançados entram como
|
|
62
|
+
`blocked` — resultado parcial honesto vale mais que ausência de resultado.
|
|
63
|
+
- `fail` **exige** `evidencia` não vazia.
|
|
64
|
+
- `blocked` **exige** `blockedReason`, um de: `ambiente` · `setup-falhou` ·
|
|
65
|
+
`massa-de-dados` · `dependencia-nao-entregue` · `bloqueado-por-bug` ·
|
|
66
|
+
`credencial` · `outro` (este exige `evidencia` com o motivo em texto livre).
|
|
67
|
+
- A CLI **recusa** o arquivo fora do contrato (schema em
|
|
68
|
+
`protocol/qa-result.v1.json` do pacote `@spec-wave/cli`) — e arquivo ausente é
|
|
69
|
+
falha alta: nada é aprovado nem reprovado sem ele.
|
|
70
|
+
|
|
71
|
+
## Setup do ambiente
|
|
72
|
+
|
|
73
|
+
Se o contexto trouxer uma seção de setup, rode-a **antes do primeiro cenário**.
|
|
74
|
+
Se o setup falhar, TODOS os cenários são `blocked` com `blockedReason:
|
|
75
|
+
setup-falhou` e a saída do erro como evidência — não tente "consertar o
|
|
76
|
+
ambiente" mudando código.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-wave-qa-lead
|
|
3
|
+
description: "Use para orquestrar o QA de uma TRILHA inteira (milestone) do spec-wave — preparar os planos de todas as Features (`qa-lead plan`), executar o ciclo com containers paralelos (`qa-lead run`) e consultar relatórios de ciclo (`qa-lead report`). Gatilhos: 'rodar o QA do milestone', 'QA da release', 'trilha de QA', 'relatório de QA do ciclo'."
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash(npx @spec-wave/cli@latest qa-lead *)
|
|
6
|
+
- Bash(npx @spec-wave/cli@latest qa *)
|
|
7
|
+
- Bash(npx @spec-wave/cli@latest doctor)
|
|
8
|
+
- Bash(gh issue *)
|
|
9
|
+
- Read
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# spec-wave qa-lead — QA de trilha (milestone)
|
|
13
|
+
|
|
14
|
+
O `qa` valida **uma** issue; o `qa-lead` percorre **todas as Features de um
|
|
15
|
+
milestone** (trilha = milestone, D-QAL1), em duas fases com um portão humano no
|
|
16
|
+
meio (D-QAL2). O Lead **não executa cenário, não abre Bug, não move card** —
|
|
17
|
+
toda mutação de board continua no `qa`, que roda dentro dos containers.
|
|
18
|
+
|
|
19
|
+
## Fase A — preparar os planos
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @spec-wave/cli@latest qa-lead plan <milestone> --dry-run # classifica sem aplicar nada
|
|
23
|
+
npx @spec-wave/cli@latest qa-lead plan <milestone> [--watch]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Classifica cada Feature (pronta / portão humano / em voo / sem spec-plan) e
|
|
27
|
+
aplica `spec-wave:qa` nas que precisam de plano. **PARA aqui** (D-QA4): o humano
|
|
28
|
+
revisa os `qa-plan.md` e o Action aplica `qa-ready`. `--watch` acompanha até
|
|
29
|
+
resolver (teto `qa.lead.planWaitTimeoutMin`). Exit 0 só com a trilha inteira
|
|
30
|
+
pronta.
|
|
31
|
+
|
|
32
|
+
- Feature com `critique-failed`/`needs-human` é **portão humano**: o Lead nunca
|
|
33
|
+
aplica gatilho nela — corrija o documento apontado no comentário 🔎 primeiro.
|
|
34
|
+
|
|
35
|
+
## Fase B — executar o ciclo
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @spec-wave/cli@latest qa-lead run <milestone> --dry-run # plano de despacho, zero container
|
|
39
|
+
npx @spec-wave/cli@latest qa-lead run <milestone> [--only 318,320] [--max-cycles 3]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **Portão:** toda Feature em 🧪 QA precisa de `qa-ready`, senão recusa listando
|
|
43
|
+
as pendentes. Features em etapa anterior aparecem como `fora-do-ciclo`;
|
|
44
|
+
posteriores, `ja-aprovada` — contabilizadas, sem bloquear.
|
|
45
|
+
- **Preflight global** antes de qualquer container (backend, imagem,
|
|
46
|
+
credenciais, disco). Falha → ciclo `ciclo-abortado` com relatório emitido.
|
|
47
|
+
- **Despacho:** até `qa.lead.maxParallel` containers, um ambiente isolado por
|
|
48
|
+
Feature (D-QAL3), rodando `qa <feature>`. Timeout mata o container e a
|
|
49
|
+
Feature vira `execucao-abortada` (nunca lida como verde).
|
|
50
|
+
- **Ciclos:** o N+1 só existe se um Bug fechou ou um bloqueio caiu desde o N
|
|
51
|
+
(D-QAL7); retestes usam `qa <story> --only <cenários>`. Teto de 3 ciclos.
|
|
52
|
+
|
|
53
|
+
Configuração no `.spec-wave.json` (defaults entre parênteses):
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"qa": {
|
|
58
|
+
"lead": {
|
|
59
|
+
"maxParallel": 4, "maxCycles": 3, "featureTimeoutMin": 45,
|
|
60
|
+
"pollIntervalSec": 30, "planWaitTimeoutMin": 20,
|
|
61
|
+
"container": { "image": "ghcr.io/acme/qa-runner:1.4", "env": { "NODE_ENV": "test" } }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`container.image` é **obrigatória** para a fase B. Valor vazio em
|
|
68
|
+
`container.env` significa "vem do ambiente do Lead". Backend: `docker`
|
|
69
|
+
(default) ou `sandbox` (follow-up — ainda sem API de sessão).
|
|
70
|
+
|
|
71
|
+
## Relatórios
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx @spec-wave/cli@latest qa-lead report <milestone> [--cycle <n>]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Cada ciclo grava `docs/qa/<slug-milestone>/cycle-<n>/{report.md,report.json}`
|
|
78
|
+
(schema em `protocol/qa-trail-report.v1.json`) e atualiza um **bloco delimitado**
|
|
79
|
+
na descrição do milestone — substituído a cada ciclo, preservando o resto da
|
|
80
|
+
descrição (Release Notes moram no mesmo campo).
|
|
81
|
+
|
|
82
|
+
## O que o Lead escreve (e NADA além)
|
|
83
|
+
|
|
84
|
+
1. a label de gatilho `spec-wave:qa` (fase A);
|
|
85
|
+
2. `docs/qa/<slug>/cycle-<n>/{report.md,report.json}`;
|
|
86
|
+
3. o bloco delimitado na descrição do milestone.
|
|
87
|
+
|
|
88
|
+
Etapa, `qa-approved`, Bugs e comentários de veredito são do `qa`. Se algo mais
|
|
89
|
+
precisar mudar no board, use as skills **qa** ou **move** — nunca por fora.
|