spec-first-claude 0.5.0-beta.9 → 0.6.0-beta.10
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 +44 -36
- package/bin/cli.js +13 -13
- package/lib/init.js +23 -20
- package/lib/update.js +11 -10
- package/package.json +1 -1
- package/templates/.claude/CHANGELOG.md +338 -0
- package/templates/.claude/adapters/SETUP.md +4 -4
- package/templates/.claude/adapters/confluence.md +2 -2
- package/templates/.claude/adapters/errors.md +2 -2
- package/templates/.claude/adapters/filesystem.md +4 -4
- package/templates/.claude/adapters/interface.md +3 -3
- package/templates/.claude/adapters/naming.md +15 -15
- package/templates/.claude/adapters/registry.md +3 -3
- package/templates/.claude/agents/db-coder.md +165 -165
- package/templates/.claude/agents/doc-writer.md +21 -16
- package/templates/.claude/agents/security-reviewer.md +153 -153
- package/templates/.claude/commands/design.md +216 -123
- package/templates/.claude/commands/dev.md +189 -189
- package/templates/.claude/commands/discovery.md +10 -1
- package/templates/.claude/commands/extract.md +183 -71
- package/templates/.claude/commands/load.md +206 -116
- package/templates/.claude/commands/mcp.md +385 -0
- package/templates/.claude/commands/merge-docs.md +100 -0
- package/templates/.claude/commands/plan.md +128 -94
- package/templates/.claude/commands/publish.md +143 -0
- package/templates/.claude/commands/sfw-start.md +145 -0
- package/templates/.claude/rules.md +1 -1
- package/templates/.claude/scripts/bootstrap-confluence.js +289 -0
- package/templates/.claude/templates/estrutura/apiContracts.template.md +18 -10
- package/templates/.claude/templates/estrutura/architecture.template.md +19 -9
- package/templates/.claude/templates/estrutura/conventions.template.md +29 -19
- package/templates/.claude/templates/estrutura/decisions.template.md +16 -8
- package/templates/.claude/templates/estrutura/domain.template.md +25 -13
- package/templates/.claude/templates/feature/PRD.template.md +48 -18
- package/templates/.claude/templates/feature/Progresso.template.md +141 -136
- package/templates/.claude/templates/feature/backlog-extraido.template.md +8 -6
- package/templates/.claude/templates/feature/context.template.md +17 -11
- package/templates/.claude/templates/feature/extract-log.template.md +2 -1
- package/templates/.claude/templates/feature/projetos.template.yaml +29 -23
- package/templates/.claude/templates/feature/sdd.template.md +365 -178
- package/templates/.claude/templates/global/progresso_global.template.md +4 -4
- package/templates/.claude/templates/specs/brief.template.md +22 -10
- package/templates/.claude/templates/specs/contracts.template.md +94 -35
- package/templates/.claude/templates/specs/scenarios.template.md +75 -37
- package/templates/.claude/templates/specs/tasks.template.md +63 -61
- package/templates/CLAUDE.md +268 -242
- package/templates/_gitignore +35 -0
- package/templates/sfw.config.yml.example +20 -4
- package/templates/.claude/commands/feature.md +0 -60
- package/templates/.claude/commands/merge-delta.md +0 -71
- package/templates/.claude/commands/new-project.md +0 -72
- package/templates/.claude/templates/feature/TRD.template.md +0 -204
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Kit completo para desenvolvimento **spec-first** com [Claude Code](https://claud
|
|
|
6
6
|
|
|
7
7
|
Em vez de pedir pra IA "cria um CRUD de usuarios", voce fornece insumos brutos (docs, SQLs, rascunhos) e a IA:
|
|
8
8
|
|
|
9
|
-
1. **Extrai** requisitos estruturados (PRD
|
|
9
|
+
1. **Extrai** requisitos estruturados (PRD)
|
|
10
10
|
2. **Espera sua aprovacao** (checkpoint humano)
|
|
11
11
|
3. **Gera design tecnico** (SDD) — fonte unica de verdade
|
|
12
12
|
4. **Planeja tasks** com dependencias e fases
|
|
@@ -48,19 +48,24 @@ MeuProjeto/
|
|
|
48
48
|
├── .ai/memory/napkin.md <- Memoria persistente do projeto
|
|
49
49
|
├── .claude/ <- AI OPERATIONAL CONFIG
|
|
50
50
|
│ ├── rules.md <- Regras de desenvolvimento
|
|
51
|
-
│ ├──
|
|
52
|
-
│
|
|
53
|
-
│ │ ├──
|
|
51
|
+
│ ├── CHANGELOG.md <- Historico do framework
|
|
52
|
+
│ ├── templates/ <- Templates do workflow
|
|
53
|
+
│ │ ├── feature/ <- PRD, SDD, context, extract-log, Progresso, backlog, projetos.yaml
|
|
54
|
+
│ │ ├── specs/ <- brief, contracts, scenarios, tasks (projecoes pro agent)
|
|
55
|
+
│ │ ├── estrutura/ <- 5 templates de sintese cross-feature
|
|
54
56
|
│ │ └── global/ <- Progresso global
|
|
55
|
-
│ ├──
|
|
56
|
-
│
|
|
57
|
-
│ │ ├──
|
|
57
|
+
│ ├── adapters/ <- SourceAdapter + ConfluenceAdapter + FilesystemAdapter
|
|
58
|
+
│ ├── commands/ <- 11 commands do workflow
|
|
59
|
+
│ │ ├── mcp.md
|
|
60
|
+
│ │ ├── load.md
|
|
61
|
+
│ │ ├── publish.md
|
|
62
|
+
│ │ ├── sfw-start.md <- entrada unica (substitui setup-projeto + feature)
|
|
58
63
|
│ │ ├── discovery.md
|
|
59
64
|
│ │ ├── extract.md
|
|
60
65
|
│ │ ├── design.md
|
|
61
66
|
│ │ ├── plan.md
|
|
62
67
|
│ │ ├── dev.md
|
|
63
|
-
│ │ ├── merge-
|
|
68
|
+
│ │ ├── merge-docs.md <- renomeado de merge-delta
|
|
64
69
|
│ │ └── session-finish.md
|
|
65
70
|
│ └── agents/ <- 7 agentes especializados
|
|
66
71
|
│ ├── backend-coder.md <- .NET 8 / C#
|
|
@@ -70,22 +75,23 @@ MeuProjeto/
|
|
|
70
75
|
│ ├── doc-writer.md <- Documentacao
|
|
71
76
|
│ ├── reviewer.md <- Code review
|
|
72
77
|
│ └── security-reviewer.md <- Auditoria de seguranca
|
|
73
|
-
├── docs/ <-
|
|
78
|
+
├── docs/ <- SINTESE CROSS-FEATURE (atualizada pelo /merge-docs)
|
|
74
79
|
│ ├── architecture.md <- Containers, stack, ambientes, deploy
|
|
75
80
|
│ ├── domain.md <- Visao de negocio + modelo de dados
|
|
76
81
|
│ ├── conventions.md <- Auth, authz, LGPD, env vars, monitoramento
|
|
77
82
|
│ ├── apiContracts.md <- Rotas, paginacao, erros, catalogo de endpoints
|
|
78
|
-
│
|
|
79
|
-
|
|
80
|
-
│
|
|
81
|
-
│
|
|
82
|
-
│
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
├── workspace/ <- TEAM CONTENT
|
|
86
|
-
│ ├── Input/ <- Jogue seus insumos aqui
|
|
87
|
-
│ │ └──
|
|
88
|
-
│ └── Output/ <- Docs narrativos pro humano (PRD,
|
|
83
|
+
│ └── decisions.md <- ADRs (append-only)
|
|
84
|
+
├── specs/ <- AGENT CONTRACTS (projecoes do SDD pro coder)
|
|
85
|
+
│ └── {nome}/
|
|
86
|
+
│ ├── brief.md <- Problema/Solucao (SDD §1+§2+§10)
|
|
87
|
+
│ ├── contracts.md <- Sistema + Áreas tocadas (SDD §3-§7)
|
|
88
|
+
│ ├── scenarios.md <- Fluxos/UI/CAs (SDD §5.2+§8+§9)
|
|
89
|
+
│ └── tasks.md <- Tabela unica com coluna Area
|
|
90
|
+
├── workspace/ <- TEAM CONTENT
|
|
91
|
+
│ ├── Input/ <- Jogue seus insumos aqui (nome livre)
|
|
92
|
+
│ │ └── {nome}/ <- ex: app_barbearia, feat_login
|
|
93
|
+
│ └── Output/ <- Docs narrativos pro humano (PRD, SDD, Progresso)
|
|
94
|
+
├── sfw.config.yml.example <- Manifesto de adapters (input/output)
|
|
89
95
|
├── CLAUDE.md <- Regras globais pro agente
|
|
90
96
|
└── .gitignore
|
|
91
97
|
```
|
|
@@ -98,7 +104,8 @@ MeuProjeto/
|
|
|
98
104
|
cd MeuProjeto
|
|
99
105
|
```
|
|
100
106
|
|
|
101
|
-
2. Jogue seus insumos em `workspace/Input
|
|
107
|
+
2. Jogue seus insumos em `workspace/Input/<nome>/` — qualquer formato.
|
|
108
|
+
`<nome>` é livre: `app_barbearia`, `bootstrap`, `feat_login`, `bug_checkout`, etc.
|
|
102
109
|
- `.md`, `.txt` (descricoes, requisitos, decisoes)
|
|
103
110
|
- `.sql` (modelagem de banco)
|
|
104
111
|
- `.csv`, `.xml`, `.html` (dados, configs)
|
|
@@ -106,37 +113,38 @@ MeuProjeto/
|
|
|
106
113
|
|
|
107
114
|
3. Abra o Claude Code e rode:
|
|
108
115
|
```
|
|
109
|
-
/
|
|
116
|
+
/sfw-start <nome>
|
|
110
117
|
```
|
|
111
118
|
|
|
112
|
-
4. O pipeline comeca. A IA
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
4. O pipeline comeca. A IA detecta automaticamente se e first-run (docs/ ausente)
|
|
120
|
+
ou feature (docs/ ja existe). Nao ha comandos diferentes pra setup vs feature.
|
|
121
|
+
|
|
122
|
+
- Extrai PRD dos seus insumos (pode ser empty em scopes puro-tecnicos)
|
|
123
|
+
- Para e pede sua aprovacao
|
|
115
124
|
- Depois voce roda `/design`, `/plan`, `/dev` na sequencia
|
|
116
125
|
|
|
117
126
|
## Pipeline completo
|
|
118
127
|
|
|
119
128
|
```
|
|
120
|
-
workspace/Input
|
|
129
|
+
workspace/Input/<nome>/ (seus arquivos)
|
|
121
130
|
|
|
|
122
131
|
v
|
|
123
|
-
/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
/design --> SDD + docs/ (5 arquivos)
|
|
132
|
+
/sfw-start <nome> --> /extract --> PRD (voce revisa e aprova)
|
|
133
|
+
|
|
|
134
|
+
v
|
|
135
|
+
/design --> SDD + docs/ (first-run: cria 5 arquivos)
|
|
136
|
+
(feature: gera só §Área-X + §11 delta)
|
|
127
137
|
|
|
|
128
138
|
v
|
|
129
139
|
/plan --> tasks + Progresso.md
|
|
130
140
|
|
|
|
131
141
|
v
|
|
132
|
-
/dev --> codigo nos repos
|
|
142
|
+
/dev --> codigo nos repos
|
|
143
|
+
+ /merge-docs automatico
|
|
144
|
+
(aplica §11 em docs/)
|
|
133
145
|
```
|
|
134
146
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
/feature nome_da_feature --> /extract --> PRD --> /design --> /plan --> /dev (inclui merge-delta)
|
|
139
|
-
```
|
|
147
|
+
Mesmo comando pra bootstrap e feature — `first_run` e derivado da ausencia/presenca de `docs/`.
|
|
140
148
|
|
|
141
149
|
## Opcoes do CLI
|
|
142
150
|
|
package/bin/cli.js
CHANGED
|
@@ -8,19 +8,19 @@ const args = process.argv.slice(2);
|
|
|
8
8
|
const command = args[0];
|
|
9
9
|
|
|
10
10
|
function printUsage() {
|
|
11
|
-
console.log('
|
|
12
|
-
console.log(' spec-first-claude init --name=<
|
|
13
|
-
console.log(' spec-first-claude update [--target=<
|
|
11
|
+
console.log('Uso:');
|
|
12
|
+
console.log(' spec-first-claude init --name=<nome-do-projeto> [--target=<caminho>]');
|
|
13
|
+
console.log(' spec-first-claude update [--target=<caminho>] [--force]');
|
|
14
14
|
console.log('');
|
|
15
|
-
console.log('
|
|
16
|
-
console.log(' init
|
|
17
|
-
console.log(' update
|
|
18
|
-
console.log(' (
|
|
15
|
+
console.log('Comandos:');
|
|
16
|
+
console.log(' init Cria um novo projeto spec-first');
|
|
17
|
+
console.log(' update Atualiza projeto existente com arquivos novos do framework');
|
|
18
|
+
console.log(' (adiciona faltantes, atualiza commands/adapters/agents/templates)');
|
|
19
19
|
console.log('');
|
|
20
|
-
console.log('
|
|
21
|
-
console.log(' --name=<
|
|
22
|
-
console.log(' --target=<path>
|
|
23
|
-
console.log(' --force
|
|
20
|
+
console.log('Opções:');
|
|
21
|
+
console.log(' --name=<nome> Nome do projeto (obrigatório no init)');
|
|
22
|
+
console.log(' --target=<path> Diretório destino (default: ./<nome> no init, cwd no update)');
|
|
23
|
+
console.log(' --force Força atualizar TODOS arquivos, não só os do framework (cuidado)');
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function parseArgs(args) {
|
|
@@ -40,7 +40,7 @@ if (command === 'init') {
|
|
|
40
40
|
const opts = parseArgs(args.slice(1));
|
|
41
41
|
|
|
42
42
|
if (!opts.name) {
|
|
43
|
-
console.error('
|
|
43
|
+
console.error('Erro: --name é obrigatório.\n');
|
|
44
44
|
printUsage();
|
|
45
45
|
process.exit(1);
|
|
46
46
|
}
|
|
@@ -64,7 +64,7 @@ if (command === 'init') {
|
|
|
64
64
|
} else {
|
|
65
65
|
printUsage();
|
|
66
66
|
if (command) {
|
|
67
|
-
console.error(`\
|
|
67
|
+
console.error(`\nComando desconhecido: "${command}"`);
|
|
68
68
|
}
|
|
69
69
|
process.exit(command ? 1 : 0);
|
|
70
70
|
}
|
package/lib/init.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
3
|
|
|
5
4
|
const PLACEHOLDER = '{{PROJECT_NAME}}';
|
|
6
5
|
|
|
@@ -8,7 +7,9 @@ function copyDir(src, dest, replacements) {
|
|
|
8
7
|
fs.mkdirSync(dest, { recursive: true });
|
|
9
8
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
10
9
|
const srcPath = path.join(src, entry.name);
|
|
11
|
-
|
|
10
|
+
// Rename _gitignore → .gitignore (npm strips .gitignore from packages)
|
|
11
|
+
const destName = entry.name === '_gitignore' ? '.gitignore' : entry.name;
|
|
12
|
+
const destPath = path.join(dest, destName);
|
|
12
13
|
if (entry.isDirectory()) {
|
|
13
14
|
copyDir(srcPath, destPath, replacements);
|
|
14
15
|
} else {
|
|
@@ -24,7 +25,7 @@ function copyFile(src, dest, replacements) {
|
|
|
24
25
|
const textExtensions = ['.md', '.yaml', '.yml', '.json', '.js', '.ts', '.gitignore', '.gitkeep', ''];
|
|
25
26
|
const ext = path.extname(src).toLowerCase();
|
|
26
27
|
const basename = path.basename(src);
|
|
27
|
-
const isText = textExtensions.includes(ext) || basename.startsWith('.');
|
|
28
|
+
const isText = textExtensions.includes(ext) || basename.startsWith('.') || basename === '_gitignore';
|
|
28
29
|
|
|
29
30
|
if (isText) {
|
|
30
31
|
let content = fs.readFileSync(src, 'utf-8');
|
|
@@ -41,29 +42,31 @@ function init({ name, templatesDir, targetDir }) {
|
|
|
41
42
|
const dest = targetDir || path.resolve(process.cwd(), name);
|
|
42
43
|
|
|
43
44
|
const existed = fs.existsSync(dest);
|
|
44
|
-
console.log(`\n${existed ? '
|
|
45
|
+
console.log(`\n${existed ? 'Inicializando' : 'Criando'} projeto "${name}" em ${dest}\n`);
|
|
45
46
|
|
|
46
47
|
const replacements = { [PLACEHOLDER]: name };
|
|
47
48
|
copyDir(templatesDir, dest, replacements);
|
|
48
49
|
patchProjectName(dest, name);
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
execSync('git add -A', { cwd: dest, stdio: 'pipe' });
|
|
53
|
-
execSync(`git commit -m "chore: init project ${name} via spec-first-workflow"`, {
|
|
54
|
-
cwd: dest,
|
|
55
|
-
stdio: 'pipe',
|
|
56
|
-
});
|
|
57
|
-
console.log('Git initialized with initial commit.');
|
|
58
|
-
} catch {
|
|
59
|
-
console.log('Git init skipped (git not available or error).');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
console.log(`\nDone! Project "${name}" is ready.`);
|
|
63
|
-
console.log('\nNext steps:');
|
|
51
|
+
console.log(`Pronto! Projeto "${name}" criado.`);
|
|
52
|
+
console.log('\nPróximos passos:');
|
|
64
53
|
console.log(` 1. cd ${name}`);
|
|
65
|
-
console.log(' 2.
|
|
66
|
-
console.log('
|
|
54
|
+
console.log(' 2. Crie uma pasta em workspace/Input/ com os insumos do seu projeto');
|
|
55
|
+
console.log(' (ex: workspace/Input/meu_app/requisitos.md)');
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log(' 3. (Opcional) Configure o backend de input/output:');
|
|
58
|
+
console.log(' cp sfw.config.yml.example sfw.config.yml');
|
|
59
|
+
console.log(' Sem isso, o framework roda 100% local (sem Confluence/etc.)');
|
|
60
|
+
console.log('');
|
|
61
|
+
console.log(' 4. (Opcional, se vai usar Confluence) Prepare o ambiente ANTES de abrir o Claude:');
|
|
62
|
+
console.log(' node .claude/scripts/bootstrap-confluence.js');
|
|
63
|
+
console.log(' Valida uvx, coleta credenciais, gera .mcp.json e pré-cacheia o MCP.');
|
|
64
|
+
console.log(' Evita o ciclo "abrir Claude → faltar dep → reiniciar".');
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(' 5. Abra o Claude Code no diretório do projeto e rode:');
|
|
67
|
+
console.log(' /sfw-start <nome-da-pasta-em-Input>');
|
|
68
|
+
console.log(' O framework detecta first-run automaticamente (cria docs/) vs feature');
|
|
69
|
+
console.log(' (atualiza docs/ via merge).');
|
|
67
70
|
console.log('');
|
|
68
71
|
}
|
|
69
72
|
|
package/lib/update.js
CHANGED
|
@@ -18,36 +18,36 @@ function update({ templatesDir, targetDir, force }) {
|
|
|
18
18
|
const dest = targetDir || process.cwd();
|
|
19
19
|
|
|
20
20
|
if (!fs.existsSync(dest)) {
|
|
21
|
-
console.error(`
|
|
22
|
-
console.error('
|
|
21
|
+
console.error(`Erro: diretório "${dest}" não existe.`);
|
|
22
|
+
console.error('Rode "spec-first-claude init --name=<nome>" primeiro pra criar o projeto.');
|
|
23
23
|
process.exit(1);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const claudeDir = path.join(dest, '.claude');
|
|
27
27
|
if (!fs.existsSync(claudeDir)) {
|
|
28
|
-
console.error('
|
|
29
|
-
console.error('
|
|
28
|
+
console.error('Erro: não é um projeto spec-first (pasta .claude/ não encontrada).');
|
|
29
|
+
console.error('Rode "spec-first-claude init --name=<nome>" primeiro.');
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
console.log(`\
|
|
33
|
+
console.log(`\nAtualizando projeto em ${dest}\n`);
|
|
34
34
|
|
|
35
35
|
const stats = { added: [], updated: [], skipped: 0 };
|
|
36
36
|
syncDir(templatesDir, dest, force, stats, dest);
|
|
37
37
|
|
|
38
38
|
console.log('');
|
|
39
39
|
if (stats.added.length > 0) {
|
|
40
|
-
console.log(`
|
|
40
|
+
console.log(`Adicionados (${stats.added.length}):`);
|
|
41
41
|
for (const f of stats.added) console.log(` + ${f}`);
|
|
42
42
|
}
|
|
43
43
|
if (stats.updated.length > 0) {
|
|
44
|
-
console.log(`
|
|
44
|
+
console.log(`Atualizados (${stats.updated.length}):`);
|
|
45
45
|
for (const f of stats.updated) console.log(` ~ ${f}`);
|
|
46
46
|
}
|
|
47
47
|
if (stats.added.length === 0 && stats.updated.length === 0) {
|
|
48
|
-
console.log('
|
|
48
|
+
console.log('Já está atualizado — nenhum arquivo novo pra adicionar.');
|
|
49
49
|
} else {
|
|
50
|
-
console.log(`\n${stats.added.length}
|
|
50
|
+
console.log(`\n${stats.added.length} adicionado(s), ${stats.updated.length} atualizado(s), ${stats.skipped} inalterado(s)`);
|
|
51
51
|
}
|
|
52
52
|
console.log('');
|
|
53
53
|
}
|
|
@@ -56,7 +56,8 @@ function syncDir(src, dest, force, stats, root) {
|
|
|
56
56
|
fs.mkdirSync(dest, { recursive: true });
|
|
57
57
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
58
58
|
const srcPath = path.join(src, entry.name);
|
|
59
|
-
const
|
|
59
|
+
const destName = entry.name === '_gitignore' ? '.gitignore' : entry.name;
|
|
60
|
+
const destPath = path.join(dest, destName);
|
|
60
61
|
if (entry.isDirectory()) {
|
|
61
62
|
syncDir(srcPath, destPath, force, stats, root);
|
|
62
63
|
} else {
|
package/package.json
CHANGED