product-runner 0.5.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/README.md +165 -0
- package/common/agents/README.md +68 -0
- package/common/agents/agente-conceituacao.md +141 -0
- package/common/agents/agente-documentacao-funcional.md +107 -0
- package/common/agents/agente-gerador-spec.md +106 -0
- package/common/agents/agente-kickoff.md +121 -0
- package/common/agents/agente-prod-runner.md +107 -0
- package/common/agents/agente-review-code.md +97 -0
- package/common/agents/agente-review-llm.md +94 -0
- package/common/agents/agente-review-product.md +98 -0
- package/common/agents/agente-user-review.md +99 -0
- package/common/agents/protocolo-de-gates.md +51 -0
- package/common/claude-md.template.md +210 -0
- package/common/design-principles.md +229 -0
- package/common/lessons-learned.md +440 -0
- package/common/pipeline.md +143 -0
- package/common/spec-guide.md +327 -0
- package/common/specs/_open-issues.md +46 -0
- package/common/specs/_overview.md +75 -0
- package/dist/cli.js +187 -0
- package/dist/migrations.js +147 -0
- package/dist/scaffold.js +276 -0
- package/dist/update.js +400 -0
- package/migrations/0.3.0.md +54 -0
- package/migrations/0.4.0.md +76 -0
- package/migrations/0.5.0.md +55 -0
- package/migrations/README.md +68 -0
- package/package.json +41 -0
- package/profile-cli/README.md +54 -0
- package/profile-cli/claude-md.extension.md +102 -0
- package/profile-cli/code-patterns.md +363 -0
- package/profile-ssr/DESIGN-SYSTEM.md +795 -0
- package/profile-ssr/README.md +51 -0
- package/profile-ssr/api-patterns.md +70 -0
- package/profile-ssr/claude-md.extension.md +113 -0
- package/profile-ssr/code-patterns.md +175 -0
- package/profile-ssr/ui-patterns.md +97 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# Spec guide
|
|
2
|
+
|
|
3
|
+
Como ler, escrever e implementar specs neste projeto. Este guia é a
|
|
4
|
+
**referência de formato e critérios** da spec: o template, os critérios
|
|
5
|
+
meta, a granularidade, as regras de implementação e o review.
|
|
6
|
+
|
|
7
|
+
A **geração** das specs (cortar um incremento conceituado em N specs
|
|
8
|
+
verticais) é o [agente-gerador-spec](./agents/agente-gerador-spec.md), que consome este guia e o preenche
|
|
9
|
+
a partir dos artefatos a montante — ver [pipeline](./pipeline.md). Para mudanças
|
|
10
|
+
pequenas ou projetos sem conceituação formal, escreva a spec direto neste
|
|
11
|
+
template (o pipeline inteiro não é obrigatório — ver "Fixes vs specs").
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## O que é uma spec
|
|
16
|
+
|
|
17
|
+
Definição completa de uma mudança: contexto, dependências, entrega,
|
|
18
|
+
arquivos afetados, regras, não-objetivos e critérios binários
|
|
19
|
+
de "pronto".
|
|
20
|
+
|
|
21
|
+
Spec é **contrato**, não tutorial. Diz **O QUE** muda, não **COMO**
|
|
22
|
+
implementar linha a linha — exceto quando o "como" é parte da
|
|
23
|
+
decisão (ex: "use Object.setPrototypeOf, não factory fromPlain").
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Onde vivem
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
specs/
|
|
31
|
+
├── _overview.md ← roadmap, fases, dependências
|
|
32
|
+
├── setup/ ← infra, hardening, ferramentas
|
|
33
|
+
│ ├── 00-hardening.md
|
|
34
|
+
│ ├── 01-test-harness.md
|
|
35
|
+
│ └── ...
|
|
36
|
+
├── refactor/ ← reorganização do código existente
|
|
37
|
+
│ ├── 03-pure-logic.md
|
|
38
|
+
│ └── ...
|
|
39
|
+
└── {domínio}/ ← features novas (quando houver)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Numeração indica ordem dentro do domínio. Domínios são estáveis;
|
|
43
|
+
fases podem mudar.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Template
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
# {Domínio} — {Nome da mudança}
|
|
51
|
+
|
|
52
|
+
## Contexto
|
|
53
|
+
|
|
54
|
+
Por que esta spec existe. Problema que resolve. Link pra spec
|
|
55
|
+
anterior se depender.
|
|
56
|
+
|
|
57
|
+
## Depende de
|
|
58
|
+
|
|
59
|
+
- `{domínio}/NN-{spec anterior}` (se houver)
|
|
60
|
+
|
|
61
|
+
## Entrega
|
|
62
|
+
|
|
63
|
+
O que funciona ao final. Visão de fora — o que muda no
|
|
64
|
+
comportamento ou na estrutura.
|
|
65
|
+
|
|
66
|
+
## Entities envolvidas
|
|
67
|
+
|
|
68
|
+
Schemas, types, classes novos ou alterados. Sem código
|
|
69
|
+
completo — só assinaturas e decisões.
|
|
70
|
+
|
|
71
|
+
## Mudanças por arquivo
|
|
72
|
+
|
|
73
|
+
Arquivo a arquivo, o que muda. Aceita pseudocódigo / blocos
|
|
74
|
+
curtos quando a decisão precisa ser explícita.
|
|
75
|
+
|
|
76
|
+
## Regras de negócio
|
|
77
|
+
|
|
78
|
+
Validações, limites, edge cases. O que NÃO pode acontecer.
|
|
79
|
+
|
|
80
|
+
## Não-objetivos
|
|
81
|
+
|
|
82
|
+
O que esta spec NÃO faz, mesmo que apareça tentação. Cita
|
|
83
|
+
spec futura se for fazer depois.
|
|
84
|
+
|
|
85
|
+
## Critérios de aceite
|
|
86
|
+
|
|
87
|
+
- [ ] Cada item é binário: passa ou não passa.
|
|
88
|
+
- [ ] Verificável por comando, observação direta ou diff.
|
|
89
|
+
|
|
90
|
+
## Notas pra implementação
|
|
91
|
+
|
|
92
|
+
Guardrails específicos: ferramentas, alternativas descartadas,
|
|
93
|
+
ordem sugerida, tradeoffs.
|
|
94
|
+
|
|
95
|
+
## Decisões de implementação
|
|
96
|
+
|
|
97
|
+
(Preencher após implementação — divergências, escolhas, tentações
|
|
98
|
+
não feitas. Esta seção é OBRIGATÓRIA, não opcional.)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Critérios meta padrão
|
|
104
|
+
|
|
105
|
+
Toda spec aplica estes critérios **além** dos específicos listados
|
|
106
|
+
na própria spec. Não precisam ser repetidos em cada spec — esta
|
|
107
|
+
seção é a referência canônica. Specs referenciam por nome
|
|
108
|
+
("aplicam-se também os critérios meta padrão M1, M2, M3").
|
|
109
|
+
|
|
110
|
+
Estes critérios existem porque regras textuais em `CLAUDE.md`
|
|
111
|
+
e neste guia foram observadas como insuficientes — Claude Code
|
|
112
|
+
lê uma vez e tende a esquecer durante a sessão. Critério binário
|
|
113
|
+
em checklist vence atenção.
|
|
114
|
+
|
|
115
|
+
> **Relação com os gates.** M1-M3 são a **aplicação à etapa de spec** do
|
|
116
|
+
> mesmo princípio do [protocolo-de-gates](./agents/protocolo-de-gates.md) (fonte canônica de gate e
|
|
117
|
+
> calibragem por stakes): checklist binário vence atenção textual. O
|
|
118
|
+
> protocolo governa os gates dos estágios a montante (conceituação,
|
|
119
|
+
> doc-funcional, geração); M1-M3 governam o fechamento da implementação.
|
|
120
|
+
> Em specs de UI, aplica-se também **M4** (responsividade — detalhe em
|
|
121
|
+
> `ui-patterns.md` do perfil SSR). Specs referenciam por nome:
|
|
122
|
+
> "aplicam-se M1, M2, M3" (e M4 quando houver UI).
|
|
123
|
+
|
|
124
|
+
### M1 — Decisões de implementação preenchidas
|
|
125
|
+
|
|
126
|
+
- [ ] A seção `## Decisões de implementação` da spec contém ao
|
|
127
|
+
menos um parágrafo descrevendo: - Divergências da spec original (se houve). - Escolhas entre alternativas técnicas (qual e por quê). - Tentações de escopo NÃO executadas. - Status final (✅ / ⚠️ / ❌).
|
|
128
|
+
- [ ] Seção vazia ou só template original = critério **não** atendido.
|
|
129
|
+
|
|
130
|
+
### M2 — Decisões técnicas explicitadas durante a sessão
|
|
131
|
+
|
|
132
|
+
- [ ] Cada escolha não-óbvia entre alternativas (cast vs guard,
|
|
133
|
+
qual lib, mock vs fixture, signature, etc.) aparece num
|
|
134
|
+
thinking block ou comentário durante a sessão.
|
|
135
|
+
- [ ] Reportada no resumo final junto com a justificativa.
|
|
136
|
+
- [ ] Decisões silenciosas (escolha tomada sem rastro) violam
|
|
137
|
+
este critério.
|
|
138
|
+
|
|
139
|
+
### M3 — Release checklist explícito antes de declarar pronto
|
|
140
|
+
|
|
141
|
+
- [ ] Antes de reportar conclusão, percorrer cada critério de
|
|
142
|
+
aceite da spec e marcar ✅ / ❌ / ⚠️ explicitamente
|
|
143
|
+
(incluindo os meta).
|
|
144
|
+
- [ ] Reportar a varredura no resumo final.
|
|
145
|
+
- [ ] Smoke checks marcados como "pendente humano" exigem nota
|
|
146
|
+
curta explicando por que não foi feito automaticamente
|
|
147
|
+
(ex: precisa de credenciais reais, exige observação visual).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Princípios
|
|
152
|
+
|
|
153
|
+
### Spec é contrato, não tutorial
|
|
154
|
+
|
|
155
|
+
Regra: dizer **O QUE**, não **COMO** — exceto quando o COMO é
|
|
156
|
+
a essência da decisão.
|
|
157
|
+
|
|
158
|
+
Exemplos:
|
|
159
|
+
|
|
160
|
+
- ✅ "Validar `BINANCE_API_KEY` no boot. Se ausente, fail-fast com mensagem clara."
|
|
161
|
+
- ❌ "Linha 17, adicionar `if (!process.env.BINANCE_API_KEY) throw new Error(...)`."
|
|
162
|
+
- ✅ "Use `Object.setPrototypeOf`, não factory `fromPlain` — escolha justificada na nota X." (o COMO é parte da decisão)
|
|
163
|
+
|
|
164
|
+
### Granularidade: uma spec = uma sessão
|
|
165
|
+
|
|
166
|
+
Spec entre **80-150 linhas**. Mais curta vira fix; mais longa
|
|
167
|
+
quebra em duas.
|
|
168
|
+
|
|
169
|
+
Se ao escrever a spec ela passa de 150 linhas, sinal de que tem
|
|
170
|
+
duas mudanças disfarçadas de uma. Separar.
|
|
171
|
+
|
|
172
|
+
### Critérios binários
|
|
173
|
+
|
|
174
|
+
Cada critério de aceite é verificável por comando ou observação
|
|
175
|
+
direta. Sem "o sistema funciona corretamente".
|
|
176
|
+
|
|
177
|
+
Exemplos:
|
|
178
|
+
|
|
179
|
+
- ✅ `git grep -E '(eNls3mjIoTZ|vIE3NutkqUq6)'` retorna vazio.
|
|
180
|
+
- ✅ Rodar `npm test` retorna `Tests passed: 12`.
|
|
181
|
+
- ❌ "O bot está estável."
|
|
182
|
+
- ❌ "Erros são tratados de forma robusta."
|
|
183
|
+
|
|
184
|
+
### Escopo travado por não-objetivos
|
|
185
|
+
|
|
186
|
+
Sempre listar "Não-objetivos" antes do checklist. LLM tende a
|
|
187
|
+
fazer mais que pedido — lista de "não fazer" ancora.
|
|
188
|
+
|
|
189
|
+
Itens típicos: "Não migrar X agora", "Não tocar em Y", "Não fazer
|
|
190
|
+
fix do bug Z (vai em refactor/03)".
|
|
191
|
+
|
|
192
|
+
### Fases verticais, não horizontais
|
|
193
|
+
|
|
194
|
+
Cada spec deve entregar **valor visível de ponta a ponta** dentro
|
|
195
|
+
do seu escopo, não construir uma camada inteira pra próxima
|
|
196
|
+
spec usar.
|
|
197
|
+
|
|
198
|
+
- ❌ Horizontal: spec só de schemas, depois só de services, depois só de testes.
|
|
199
|
+
- ✅ Vertical: spec de "test harness com 1ª cobertura de WavesHistory" — entrega
|
|
200
|
+
schemas + setup + 1 teste rodando.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Workflow
|
|
205
|
+
|
|
206
|
+
Este é o **trecho de implementação** do método (spec→implementa→review).
|
|
207
|
+
Quando o projeto passa pelo pipeline completo, a "escrita da spec" é o
|
|
208
|
+
[agente-gerador-spec](./agents/agente-gerador-spec.md) cortando o incremento conceituado — ver [pipeline](./pipeline.md).
|
|
209
|
+
Em mudança pequena, a spec é escrita direto neste template.
|
|
210
|
+
|
|
211
|
+
### Quem faz o quê
|
|
212
|
+
|
|
213
|
+
| Etapa | Onde | Quem |
|
|
214
|
+
| ------------------------- | -------------------------- | ----------------------------------- |
|
|
215
|
+
| Análise, gap, decisão | Cowork (esta sessão) | LLM + você |
|
|
216
|
+
| Escrita da spec | Cowork | LLM ([agente-gerador-spec](./agents/agente-gerador-spec.md) no pipeline) + validação sua |
|
|
217
|
+
| Implementação | Claude Code (outra sessão) | LLM em sessão dedicada |
|
|
218
|
+
| Review | Cowork (volta aqui) | LLM + você |
|
|
219
|
+
| Decisões de implementação | Cowork (review preenche) | LLM + você |
|
|
220
|
+
|
|
221
|
+
### Ciclo
|
|
222
|
+
|
|
223
|
+
1. Cowork escreve spec → grava em `specs/.../NN-nome.md`.
|
|
224
|
+
2. Você abre Claude Code apontando pro repo.
|
|
225
|
+
3. Pede ao Code: "implementa `specs/.../NN-nome.md`".
|
|
226
|
+
4. Code implementa, reporta no chat.
|
|
227
|
+
5. Você traz o report de volta pra Cowork.
|
|
228
|
+
6. Cowork revisa contra critérios, preenche "Decisões de implementação".
|
|
229
|
+
7. Cowork escreve próxima spec.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Como o Claude Code lê
|
|
234
|
+
|
|
235
|
+
Ordem sugerida (ele conhece esse padrão):
|
|
236
|
+
|
|
237
|
+
1. Ler a spec INTEIRA antes de começar.
|
|
238
|
+
2. Verificar "Depende de" — se a dependência não está implementada, parar.
|
|
239
|
+
3. Ler `docs/` relevantes (referenciados na spec ou no CLAUDE.md).
|
|
240
|
+
4. Implementar mudanças por arquivo.
|
|
241
|
+
5. Rodar critérios de aceite localmente — confirmar cada um.
|
|
242
|
+
6. Reportar:
|
|
243
|
+
- Cada critério ✅ ou ❌.
|
|
244
|
+
- Decisões de implementação (escolhas + tradeoffs).
|
|
245
|
+
- Notas: o que não testou, tentações que apareceram, divergências.
|
|
246
|
+
|
|
247
|
+
### Regras operacionais durante implementação
|
|
248
|
+
|
|
249
|
+
- **3 strikes:** se uma abordagem falhou 3 vezes, parar e relatar.
|
|
250
|
+
Não entrar em loop tentando variações.
|
|
251
|
+
- **Spec vs realidade:** se a spec tem tradeoff técnico significativo
|
|
252
|
+
na implementação, parar e apresentar — spec é guia, não lei.
|
|
253
|
+
- **Menor superfície:** preferir solução que altera menos arquivos.
|
|
254
|
+
- **Não adivinhar:** se a spec não cobre, perguntar.
|
|
255
|
+
- **Verificar side-effects no top-level antes de prescrever import
|
|
256
|
+
em teste.** Ao escrever spec que importa código existente pra
|
|
257
|
+
testar, checar primeiro se o módulo de origem tem side-effects no
|
|
258
|
+
top-level (`process.exit`, `new Client(...)`, `run().catch(...)`,
|
|
259
|
+
etc.). Se tiver, **não prescrever apenas `export`** — não funciona.
|
|
260
|
+
Opções: (a) extrair função pra arquivo próprio (vira refactor,
|
|
261
|
+
amplia escopo da spec); (b) adiar teste pra spec posterior. Não há
|
|
262
|
+
solução barata via mock que valha o investimento dos 3 strikes.
|
|
263
|
+
_Lição extraída de `setup/01-test-harness` no tradeBot, onde a
|
|
264
|
+
spec assumiu que `export` em função de `index.ts` bastava._
|
|
265
|
+
|
|
266
|
+
- **Mudanças adjacentes vão pra outra spec.** Quando a implementação
|
|
267
|
+
expõe um problema que NÃO faz parte da intenção da spec atual
|
|
268
|
+
(bug em código adjacente, refactor tentador, melhoria não-pedida),
|
|
269
|
+
**não corrigir na mesma spec**. Anotar em "Decisões de
|
|
270
|
+
implementação" como achado, abrir spec separada se for relevante.
|
|
271
|
+
|
|
272
|
+
Exemplos:
|
|
273
|
+
- Spec de testes expõe que `WavesHistory.ticPrice` tem
|
|
274
|
+
comportamento esquisito num edge case → o teste reflete
|
|
275
|
+
o comportamento ATUAL (caracterização), fix vai em outra spec.
|
|
276
|
+
- Spec de refactor de service expõe um bug aritmético → anota,
|
|
277
|
+
não corrige junto.
|
|
278
|
+
- Spec de Zod expõe que um campo nullable nunca é nulo na
|
|
279
|
+
prática → anota como candidato a `.nonNullable()`, não
|
|
280
|
+
muda agora.
|
|
281
|
+
|
|
282
|
+
Razão: misturar correção com a intenção principal reduz o
|
|
283
|
+
binário "passou/falhou" da spec, esconde escopo, e confunde
|
|
284
|
+
rastreabilidade. O bug visto AGORA continua visível DEPOIS — anotar
|
|
285
|
+
é suficiente pra não se perder.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Como o review funciona
|
|
290
|
+
|
|
291
|
+
Trazer o report do Code de volta pra Cowork. A revisão:
|
|
292
|
+
|
|
293
|
+
1. Cruza critérios da spec com o estado real do código (não apenas
|
|
294
|
+
o report).
|
|
295
|
+
2. Identifica divergências silenciosas (coisas mudadas que não foram
|
|
296
|
+
reportadas).
|
|
297
|
+
3. Documenta na seção "Decisões de implementação" da spec — não
|
|
298
|
+
em mensagem solta.
|
|
299
|
+
4. Se houver fix necessário pequeno, faz inline. Se for grande,
|
|
300
|
+
abre nova spec.
|
|
301
|
+
|
|
302
|
+
A seção "Decisões de implementação" é OBRIGATÓRIA. Spec sem ela
|
|
303
|
+
preenchida = spec incompleta.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Fixes vs specs
|
|
308
|
+
|
|
309
|
+
Nem tudo precisa de spec.
|
|
310
|
+
|
|
311
|
+
| Situação | Spec? |
|
|
312
|
+
| ------------------------------------------------------ | -------------------------- |
|
|
313
|
+
| Adicionar entity, schema, service novo | Sim |
|
|
314
|
+
| Refactor estrutural (mover código entre pastas) | Sim |
|
|
315
|
+
| Mudar comportamento de cálculo / regra de trade | Sim |
|
|
316
|
+
| Bug menor (typo, parêntese errado, condição invertida) | Não |
|
|
317
|
+
| Ajuste de log / mensagem | Não |
|
|
318
|
+
| Atualização de dependência | Não (a menos que mude API) |
|
|
319
|
+
|
|
320
|
+
Regra: se altera contrato (schema, função pública, comportamento
|
|
321
|
+
observável de fora), spec. Se é correção do que já deveria funcionar,
|
|
322
|
+
fix direto.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
_Este guia é vivo. Padrões entram aqui quando aparecem na prática,
|
|
327
|
+
não por importação de "boas práticas" genéricas._
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Open issues
|
|
2
|
+
|
|
3
|
+
Achados detectados durante implementação que NÃO foram endereçados
|
|
4
|
+
na spec onde apareceram, conforme regra "mudanças adjacentes vão
|
|
5
|
+
pra outra spec" do [spec-guide](./spec-guide.md).
|
|
6
|
+
|
|
7
|
+
Cada item lista: contexto, descrição, impacto, e candidato a spec
|
|
8
|
+
onde será endereçado. Sem candidato explícito = lixo acumulando.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Template de issue novo
|
|
13
|
+
|
|
14
|
+
```markdown
|
|
15
|
+
## #N — {Título curto e descritivo}
|
|
16
|
+
|
|
17
|
+
**Detectado em:** `{spec ou contexto onde apareceu}`
|
|
18
|
+
**Arquivo(s):** `path/to/file.ts`
|
|
19
|
+
|
|
20
|
+
{Descrição do problema. Linha de código se aplicável,
|
|
21
|
+
diagnóstico do que está errado, comportamento observado.}
|
|
22
|
+
|
|
23
|
+
**Impacto em produção:** {zero / médio / alto — descrição concreta}
|
|
24
|
+
|
|
25
|
+
**Candidato a endereçamento:** `{spec planejada}` — {motivo
|
|
26
|
+
de não fazer agora}.
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Template de issue fechado
|
|
32
|
+
|
|
33
|
+
```markdown
|
|
34
|
+
## #N — {título original} ✅ FECHADA
|
|
35
|
+
|
|
36
|
+
**Fechada em:** `{spec que resolveu}`, {data} — {resumo do fix}.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
*Adicionar aqui qualquer achado durante implementação que não
|
|
42
|
+
caiba na spec atual. Cada item DEVE ter "Candidato a endereçamento"
|
|
43
|
+
explícito — sem isso, vira lixo acumulado.*
|
|
44
|
+
|
|
45
|
+
*Ao fechar issue, mantém o conteúdo anterior + adiciona linha
|
|
46
|
+
"✅ FECHADA" + spec + resumo. Histórico preservado.*
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Overview das specs
|
|
2
|
+
|
|
3
|
+
> **Template.** Mapa das specs do projeto: roadmap, dependências, estado.
|
|
4
|
+
> Gerado e mantido junto com o gerador de spec (ver [pipeline](./pipeline.md)).
|
|
5
|
+
> Substitua os `{placeholders}` pelos do projeto.
|
|
6
|
+
>
|
|
7
|
+
> **Índice derivado, não fonte.** Este mapa é conveniência e **drift-a**. O
|
|
8
|
+
> estado real de cada spec é o **conteúdo da spec** (critérios marcados,
|
|
9
|
+
> veredito de review). Não responda "qual a próxima etapa" a partir desta
|
|
10
|
+
> tabela — confirme na spec. Mesmo princípio LDoc→HDoc. Como descobrir a
|
|
11
|
+
> etapa pelo rastro: [pipeline](./pipeline.md) ("Em que estágio estou?").
|
|
12
|
+
|
|
13
|
+
## Princípio de organização
|
|
14
|
+
|
|
15
|
+
Roadmap por **corte vertical**: cada unidade entrega valor visível de
|
|
16
|
+
ponta a ponta (dados → lógica → interface), não por camada horizontal
|
|
17
|
+
(todos os models → todos os services → toda a UI).
|
|
18
|
+
|
|
19
|
+
Duas formas, conforme o projeto:
|
|
20
|
+
|
|
21
|
+
- **Por incremento de produto** — projetos que passam pelo pipeline de
|
|
22
|
+
conceituação. Cada incremento é uma fatia de valor (1+ casos de uso),
|
|
23
|
+
decomposto em N specs verticais pelo [agente-gerador-spec](./agents/agente-gerador-spec.md).
|
|
24
|
+
- **Por fase/domínio** — projetos menores, sem conceituação formal. Specs
|
|
25
|
+
agrupadas por domínio estável; numeração indica ordem.
|
|
26
|
+
|
|
27
|
+
Specs vivem em `specs/{domínio}/NN-nome.md`. Domínios são estáveis; o
|
|
28
|
+
roadmap é estável-mas-não-congelado (re-entry pode reordenar à luz do que
|
|
29
|
+
se aprende).
|
|
30
|
+
|
|
31
|
+
## Fundação (`setup/`)
|
|
32
|
+
|
|
33
|
+
| Spec | Entrega | Status |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `setup/00-{bootstrap}` | {infra base, tooling} | ⏳ pendente |
|
|
36
|
+
| `setup/01-{...}` | {...} | ⏳ pendente |
|
|
37
|
+
|
|
38
|
+
## Incremento 1 — {nome} _(ou: Fase 1 — {nome})_
|
|
39
|
+
|
|
40
|
+
**Valor:** {o que entrega de ponta a ponta}. Cobre {UCs / escopo}.
|
|
41
|
+
|
|
42
|
+
| Spec | Entrega | Depende de | Status |
|
|
43
|
+
| --- | --- | --- | --- |
|
|
44
|
+
| `{domínio}/01-{...}` | {fatia vertical com resultado visível} | `setup/...` | ⏳ pendente |
|
|
45
|
+
| `{domínio}/02-{...}` | {...} | `{domínio}/01` | ⏳ pendente |
|
|
46
|
+
| `{domínio}/03-{...}` | {fecha o ciclo mínimo} | `{domínio}/01` | ⏳ pendente |
|
|
47
|
+
|
|
48
|
+
## Incrementos/Fases seguintes (baixa resolução)
|
|
49
|
+
|
|
50
|
+
Detalhados só na vez deles (re-entry da conceituação, se aplicável).
|
|
51
|
+
|
|
52
|
+
| # | Nome | Valor | UCs |
|
|
53
|
+
| --- | --- | --- | --- |
|
|
54
|
+
| 2 | {...} | {...} | {...} |
|
|
55
|
+
| 3 | {...} | {...} | {...} |
|
|
56
|
+
|
|
57
|
+
## Grafo de dependências
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
setup/00 → setup/01 → {incremento/fase 1}
|
|
61
|
+
↘ {incremento/fase 2}
|
|
62
|
+
{incremento 1} → {o que depende dele}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Resumo das entities
|
|
66
|
+
|
|
67
|
+
| Entity | Domínio | Descrição |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| {...} | {...} | {...} |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
_Documento vivo. Atualizar ao implementar specs e ao detalhar novos
|
|
74
|
+
incrementos. Dependências são duras: spec que depende de outra não
|
|
75
|
+
implementada → parar e reportar (regra do [spec-guide](./spec-guide.md))._
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { scaffold, initProject, ENTRY_AGENT, } from "./scaffold.js";
|
|
5
|
+
import { update, renderPlan, HANDOFF_DIR } from "./update.js";
|
|
6
|
+
const HELP = `product-runner — scaffold de docs para projetos TS com AI
|
|
7
|
+
|
|
8
|
+
Uso:
|
|
9
|
+
npx product-runner init [--dir <path>] [--force]
|
|
10
|
+
npx product-runner --name <nome> --profile <cli|ssr> [opções]
|
|
11
|
+
npx product-runner update [--dir <path>] [--dry-run] [opções]
|
|
12
|
+
|
|
13
|
+
Comandos:
|
|
14
|
+
init Coloca os agentes de bootstrap (${ENTRY_AGENT} +
|
|
15
|
+
agente-kickoff.md) na raiz. Peça a uma LLM para ler
|
|
16
|
+
${ENTRY_AGENT} e seguir — ele roteia o resto.
|
|
17
|
+
update Atualiza docs/ + CLAUDE.md de um projeto existente contra
|
|
18
|
+
a versão atual dos templates (adiciona / auto-merge /
|
|
19
|
+
revisar). Usa o manifesto se houver; senão, modo legado.
|
|
20
|
+
(sem comando) Gera docs/ + CLAUDE.md (o scaffold em si).
|
|
21
|
+
|
|
22
|
+
Opções (scaffold):
|
|
23
|
+
--name <string> Nome do projeto (obrigatório). Substitui {PROJECT_NAME}.
|
|
24
|
+
--profile <cli|ssr> Perfil de templates (obrigatório).
|
|
25
|
+
--dir <path> Diretório alvo. Default: "." (atual).
|
|
26
|
+
--port <number> Porta default; substitui {PORT}. Default: 3000.
|
|
27
|
+
--force Sobrescreve arquivos existentes.
|
|
28
|
+
-h, --help Mostra esta ajuda.
|
|
29
|
+
|
|
30
|
+
Opções (update):
|
|
31
|
+
--dir <path> Diretório do projeto. Default: "." (atual).
|
|
32
|
+
--dry-run Só imprime o plano; não escreve nada.
|
|
33
|
+
--profile <cli|ssr> Perfil (obrigatório se o projeto não tiver manifesto).
|
|
34
|
+
--normalize-links Converte links dos arquivos novos pro estilo do projeto.
|
|
35
|
+
--only <glob> Limita a ação aos paths que casam (ex.: "docs/agents/**").
|
|
36
|
+
--no-format-normalize Não normaliza formatação (Prettier) antes de comparar.
|
|
37
|
+
|
|
38
|
+
Fluxo recomendado:
|
|
39
|
+
1. npx product-runner init
|
|
40
|
+
2. Peça à sua LLM: "leia ${ENTRY_AGENT} e siga as instruções".
|
|
41
|
+
|
|
42
|
+
Exemplo (scaffold direto):
|
|
43
|
+
npx product-runner --name meu-app --profile ssr --port 3000 --dir .
|
|
44
|
+
|
|
45
|
+
Exemplo (update):
|
|
46
|
+
npx product-runner update --dry-run
|
|
47
|
+
`;
|
|
48
|
+
function fail(msg) {
|
|
49
|
+
console.error(`Erro: ${msg}\n`);
|
|
50
|
+
console.error(HELP);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
async function runInit(dir, force) {
|
|
54
|
+
const targetDir = resolve(dir);
|
|
55
|
+
try {
|
|
56
|
+
const { files } = await initProject({ targetDir, force });
|
|
57
|
+
console.log(`✔ Agentes de bootstrap criados (${files.length}):`);
|
|
58
|
+
for (const f of files)
|
|
59
|
+
console.log(` ${f}`);
|
|
60
|
+
console.log("\nPróximo passo:");
|
|
61
|
+
console.log(` Abra sua LLM (Claude Code/Cowork) neste diretório e peça:`);
|
|
62
|
+
console.log(` "leia ${ENTRY_AGENT} e siga as instruções".`);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function runScaffold(values) {
|
|
69
|
+
if (!values.name)
|
|
70
|
+
fail("--name é obrigatório.");
|
|
71
|
+
if (!values.profile)
|
|
72
|
+
fail("--profile é obrigatório.");
|
|
73
|
+
if (values.profile !== "cli" && values.profile !== "ssr") {
|
|
74
|
+
fail(`--profile deve ser "cli" ou "ssr" (recebido: "${values.profile}").`);
|
|
75
|
+
}
|
|
76
|
+
const targetDir = resolve(values.dir ?? ".");
|
|
77
|
+
try {
|
|
78
|
+
const result = await scaffold({
|
|
79
|
+
name: values.name,
|
|
80
|
+
profile: values.profile,
|
|
81
|
+
targetDir,
|
|
82
|
+
port: values.port ?? "3000",
|
|
83
|
+
force: values.force ?? false,
|
|
84
|
+
});
|
|
85
|
+
console.log(`✔ docs criados em: ${result.docsPath}`);
|
|
86
|
+
console.log(`✔ CLAUDE.md criado em: ${result.claudeMdPath}`);
|
|
87
|
+
console.log("\nPróximos passos:");
|
|
88
|
+
console.log(" 1. Revise o CLAUDE.md e preencha placeholders restantes ({...}).");
|
|
89
|
+
console.log(" 2. git init (se ainda não for um repo).");
|
|
90
|
+
console.log(" 3. Escreva a primeira spec em specs/setup/00-*.md (ver docs/spec-guide.md).");
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function runUpdate(values) {
|
|
97
|
+
if (values.profile !== undefined &&
|
|
98
|
+
values.profile !== "cli" &&
|
|
99
|
+
values.profile !== "ssr") {
|
|
100
|
+
fail(`--profile deve ser "cli" ou "ssr" (recebido: "${values.profile}").`);
|
|
101
|
+
}
|
|
102
|
+
const targetDir = resolve(values.dir ?? ".");
|
|
103
|
+
const dryRun = values["dry-run"] ?? false;
|
|
104
|
+
try {
|
|
105
|
+
const result = await update({
|
|
106
|
+
targetDir,
|
|
107
|
+
profile: values.profile,
|
|
108
|
+
dryRun,
|
|
109
|
+
normalizeLinks: values["normalize-links"] ?? false,
|
|
110
|
+
only: values.only,
|
|
111
|
+
formatNormalize: !(values["no-format-normalize"] ?? false),
|
|
112
|
+
});
|
|
113
|
+
const modeNote = result.mode === "legacy"
|
|
114
|
+
? "⚠ Sem manifesto — modo legado (comparação 2-way normalizada).\n"
|
|
115
|
+
: "";
|
|
116
|
+
// Aviso crítico: normalização pedida mas Prettier ausente → REVISAR pode
|
|
117
|
+
// estar inflado só por diferença de formatação.
|
|
118
|
+
const formatNote = !(values["no-format-normalize"] ?? false) && !result.prettierFound
|
|
119
|
+
? "⚠ Prettier não encontrado em node_modules/.bin — comparei SEM normalizar\n" +
|
|
120
|
+
" formatação. Arquivos podem cair em REVISAR só por estilo (aspas, tabelas).\n" +
|
|
121
|
+
" Rode `npm install` no projeto e tente de novo, ou use --no-format-normalize\n" +
|
|
122
|
+
" pra silenciar este aviso.\n"
|
|
123
|
+
: "";
|
|
124
|
+
const header = dryRun
|
|
125
|
+
? "Plano de update — NADA será escrito.\n"
|
|
126
|
+
: "Update aplicado.\n";
|
|
127
|
+
console.log(modeNote + formatNote + header);
|
|
128
|
+
console.log(renderPlan(result));
|
|
129
|
+
const { add, automerge, review, uptodate } = result.counts;
|
|
130
|
+
const mig = result.migrations.length;
|
|
131
|
+
console.log(`\nResumo: ${mig} migration(s) · ${add} adicionar · ${automerge} auto-merge · ${review} revisar · ${uptodate} em dia.`);
|
|
132
|
+
const autoMig = result.migrations.some((m) => m.autoApply && m.ops.length);
|
|
133
|
+
const conductMig = result.migrations.filter((m) => m.body.trim().length > 0).length;
|
|
134
|
+
if (dryRun) {
|
|
135
|
+
if (autoMig) {
|
|
136
|
+
console.log("\nNota: buckets calculados ANTES das migrations; renomeações declaradas\nacima podem reclassificar itens ao aplicar.");
|
|
137
|
+
}
|
|
138
|
+
console.log("\nRode sem --dry-run pra aplicar migrations + ADICIONA + AUTO-MERGE.");
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (conductMig > 0) {
|
|
142
|
+
console.log(`\n${conductMig} migration(s) pra conduzir: veja docs/${HANDOFF_DIR}/MIGRATION-*.md.`);
|
|
143
|
+
}
|
|
144
|
+
if (review > 0) {
|
|
145
|
+
console.log(`\n${review} arquivo(s) pra revisar: veja os handoffs em docs/${HANDOFF_DIR}/.`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function main() {
|
|
154
|
+
const { values, positionals } = parseArgs({
|
|
155
|
+
options: {
|
|
156
|
+
name: { type: "string" },
|
|
157
|
+
profile: { type: "string" },
|
|
158
|
+
dir: { type: "string", default: "." },
|
|
159
|
+
port: { type: "string", default: "3000" },
|
|
160
|
+
force: { type: "boolean", default: false },
|
|
161
|
+
help: { type: "boolean", short: "h", default: false },
|
|
162
|
+
"dry-run": { type: "boolean", default: false },
|
|
163
|
+
"normalize-links": { type: "boolean", default: false },
|
|
164
|
+
only: { type: "string" },
|
|
165
|
+
"no-format-normalize": { type: "boolean", default: false },
|
|
166
|
+
},
|
|
167
|
+
allowPositionals: true,
|
|
168
|
+
});
|
|
169
|
+
if (values.help) {
|
|
170
|
+
console.log(HELP);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const command = positionals[0];
|
|
174
|
+
if (command === "init") {
|
|
175
|
+
await runInit(values.dir ?? ".", values.force ?? false);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (command === "update") {
|
|
179
|
+
await runUpdate(values);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (command !== undefined && command !== "scaffold") {
|
|
183
|
+
fail(`Comando desconhecido: "${command}". Use "init", "update" ou nenhum comando.`);
|
|
184
|
+
}
|
|
185
|
+
await runScaffold(values);
|
|
186
|
+
}
|
|
187
|
+
main();
|