spec-first-copilot 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 +43 -38
- package/bin/cli.js +13 -13
- package/lib/init.js +23 -20
- package/lib/update.js +12 -10
- package/package.json +1 -1
- package/templates/.github/CHANGELOG.md +460 -112
- package/templates/.github/adapters/SETUP.md +6 -6
- package/templates/.github/adapters/confluence.md +6 -6
- package/templates/.github/adapters/errors.md +6 -6
- package/templates/.github/adapters/filesystem.md +7 -7
- package/templates/.github/adapters/interface.md +8 -8
- package/templates/.github/adapters/naming.md +25 -25
- package/templates/.github/adapters/registry.md +5 -5
- package/templates/.github/agents/db-coder.md +165 -165
- package/templates/.github/agents/doc-writer.md +21 -16
- package/templates/.github/agents/infra-coder.md +341 -341
- package/templates/.github/agents/security-reviewer.md +153 -153
- package/templates/.github/copilot-instructions.md +262 -221
- package/templates/.github/instructions/docs.instructions.md +145 -123
- package/templates/.github/instructions/sensitive-files.instructions.md +32 -32
- package/templates/.github/rules.md +4 -4
- package/templates/.github/scripts/bootstrap-confluence.js +289 -0
- package/templates/.github/skills/sf-design/SKILL.md +216 -209
- package/templates/.github/skills/sf-dev/SKILL.md +351 -354
- package/templates/.github/skills/sf-discovery/SKILL.md +10 -1
- package/templates/.github/skills/sf-extract/SKILL.md +199 -234
- package/templates/.github/skills/sf-load/SKILL.md +206 -116
- package/templates/.github/skills/sf-mcp/SKILL.md +385 -0
- package/templates/.github/skills/sf-merge-docs/SKILL.md +100 -0
- package/templates/.github/skills/sf-plan/SKILL.md +128 -180
- package/templates/.github/skills/sf-publish/SKILL.md +143 -0
- package/templates/.github/skills/sf-start/SKILL.md +145 -0
- package/templates/.github/templates/estrutura/apiContracts.template.md +18 -10
- package/templates/.github/templates/estrutura/architecture.template.md +19 -9
- package/templates/.github/templates/estrutura/conventions.template.md +29 -19
- package/templates/.github/templates/estrutura/decisions.template.md +16 -8
- package/templates/.github/templates/estrutura/domain.template.md +25 -13
- package/templates/.github/templates/feature/PRD.template.md +286 -256
- package/templates/.github/templates/feature/Progresso.template.md +141 -136
- package/templates/.github/templates/feature/backlog-extraido.template.md +11 -9
- package/templates/.github/templates/feature/context.template.md +19 -13
- package/templates/.github/templates/feature/extract-log.template.md +3 -2
- package/templates/.github/templates/feature/projetos.template.yaml +29 -23
- package/templates/.github/templates/feature/sdd.template.md +365 -178
- package/templates/.github/templates/global/progresso_global.template.md +10 -10
- package/templates/.github/templates/specs/brief.template.md +20 -8
- package/templates/.github/templates/specs/contracts.template.md +92 -33
- package/templates/.github/templates/specs/scenarios.template.md +75 -37
- package/templates/.github/templates/specs/tasks.template.md +63 -61
- package/templates/_gitignore +35 -0
- package/templates/sfw.config.yml.example +20 -4
- package/templates/.github/skills/sf-feature/SKILL.md +0 -130
- package/templates/.github/skills/sf-merge-delta/SKILL.md +0 -145
- package/templates/.github/skills/sf-new-project/SKILL.md +0 -128
- package/templates/.github/templates/feature/TRD.template.md +0 -204
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Kit completo para desenvolvimento **spec-first** com [GitHub Copilot](https://gi
|
|
|
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
|
|
@@ -49,20 +49,25 @@ MeuProjeto/
|
|
|
49
49
|
├── .github/ <- AI OPERATIONAL CONFIG
|
|
50
50
|
│ ├── copilot-instructions.md <- Regras globais pro agente
|
|
51
51
|
│ ├── rules.md <- Regras de desenvolvimento
|
|
52
|
+
│ ├── CHANGELOG.md <- Historico do framework
|
|
52
53
|
│ ├── instructions/ <- Regras por contexto
|
|
53
|
-
│ ├── templates/ <-
|
|
54
|
-
│ │ ├── feature/ <- PRD,
|
|
55
|
-
│ │ ├──
|
|
54
|
+
│ ├── templates/ <- Templates do workflow
|
|
55
|
+
│ │ ├── feature/ <- PRD, SDD, context, extract-log, Progresso, backlog, projetos.yaml
|
|
56
|
+
│ │ ├── specs/ <- brief, contracts, scenarios, tasks (projecoes pro agent)
|
|
57
|
+
│ │ ├── estrutura/ <- 5 templates de sintese cross-feature
|
|
56
58
|
│ │ └── global/ <- Progresso global
|
|
57
|
-
│ ├──
|
|
58
|
-
│
|
|
59
|
-
│ │ ├── sf-
|
|
59
|
+
│ ├── adapters/ <- SourceAdapter + ConfluenceAdapter + FilesystemAdapter
|
|
60
|
+
│ ├── skills/ <- 11 skills do workflow
|
|
61
|
+
│ │ ├── sf-mcp/
|
|
62
|
+
│ │ ├── sf-load/
|
|
63
|
+
│ │ ├── sf-publish/
|
|
64
|
+
│ │ ├── sf-start/ <- entrada unica (substitui sf-new-project + sf-feature)
|
|
60
65
|
│ │ ├── sf-discovery/
|
|
61
66
|
│ │ ├── sf-extract/
|
|
62
67
|
│ │ ├── sf-design/
|
|
63
68
|
│ │ ├── sf-plan/
|
|
64
69
|
│ │ ├── sf-dev/
|
|
65
|
-
│ │ ├── sf-merge-delta
|
|
70
|
+
│ │ ├── sf-merge-docs/ <- renomeado de sf-merge-delta
|
|
66
71
|
│ │ └── sf-session-finish/
|
|
67
72
|
│ └── agents/ <- 7 agentes especializados
|
|
68
73
|
│ ├── backend-coder.md <- .NET 8 / C#
|
|
@@ -72,22 +77,23 @@ MeuProjeto/
|
|
|
72
77
|
│ ├── doc-writer.md <- Documentacao
|
|
73
78
|
│ ├── reviewer.md <- Code review
|
|
74
79
|
│ └── security-reviewer.md <- Auditoria de seguranca
|
|
75
|
-
├── docs/ <-
|
|
80
|
+
├── docs/ <- SINTESE CROSS-FEATURE (atualizada pelo /sf-merge-docs)
|
|
76
81
|
│ ├── architecture.md <- Containers, stack, ambientes, deploy
|
|
77
82
|
│ ├── domain.md <- Visao de negocio + modelo de dados
|
|
78
83
|
│ ├── conventions.md <- Auth, authz, LGPD, env vars, monitoramento
|
|
79
84
|
│ ├── apiContracts.md <- Rotas, paginacao, erros, catalogo de endpoints
|
|
80
|
-
│
|
|
81
|
-
|
|
82
|
-
│
|
|
83
|
-
│
|
|
84
|
-
│
|
|
85
|
-
│
|
|
86
|
-
│
|
|
87
|
-
├── workspace/ <- TEAM CONTENT
|
|
88
|
-
│ ├── Input/ <- Jogue seus insumos aqui
|
|
89
|
-
│ │ └──
|
|
90
|
-
│ └── Output/ <- Docs narrativos pro humano (PRD,
|
|
85
|
+
│ └── decisions.md <- ADRs (append-only)
|
|
86
|
+
├── specs/ <- AGENT CONTRACTS (projecoes do SDD pro coder)
|
|
87
|
+
│ └── {nome}/
|
|
88
|
+
│ ├── brief.md <- Problema/Solucao (SDD §1+§2+§10)
|
|
89
|
+
│ ├── contracts.md <- Sistema + Áreas tocadas (SDD §3-§7)
|
|
90
|
+
│ ├── scenarios.md <- Fluxos/UI/CAs (SDD §5.2+§8+§9)
|
|
91
|
+
│ └── tasks.md <- Tabela unica com coluna Area
|
|
92
|
+
├── workspace/ <- TEAM CONTENT
|
|
93
|
+
│ ├── Input/ <- Jogue seus insumos aqui (nome livre)
|
|
94
|
+
│ │ └── {nome}/ <- ex: app_barbearia, feat_login
|
|
95
|
+
│ └── Output/ <- Docs narrativos pro humano (PRD, SDD, Progresso)
|
|
96
|
+
├── sfw.config.yml.example <- Manifesto de adapters (input/output)
|
|
91
97
|
└── .gitignore
|
|
92
98
|
```
|
|
93
99
|
|
|
@@ -99,7 +105,8 @@ MeuProjeto/
|
|
|
99
105
|
cd MeuProjeto
|
|
100
106
|
```
|
|
101
107
|
|
|
102
|
-
2. Jogue seus insumos em `workspace/Input
|
|
108
|
+
2. Jogue seus insumos em `workspace/Input/<nome>/` — qualquer formato.
|
|
109
|
+
`<nome>` e livre: `app_barbearia`, `bootstrap`, `feat_login`, `bug_checkout`, etc.
|
|
103
110
|
- `.md`, `.txt` (descricoes, requisitos, decisoes)
|
|
104
111
|
- `.sql` (modelagem de banco)
|
|
105
112
|
- `.csv`, `.xml`, `.html` (dados, configs)
|
|
@@ -107,40 +114,38 @@ MeuProjeto/
|
|
|
107
114
|
|
|
108
115
|
3. Abra o VS Code com Copilot Chat e rode:
|
|
109
116
|
```
|
|
110
|
-
/sf-
|
|
117
|
+
/sf-start <nome>
|
|
111
118
|
```
|
|
112
119
|
|
|
113
|
-
4. O pipeline comeca. A IA
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
4. O pipeline comeca. A IA detecta automaticamente se e first-run (docs/ ausente)
|
|
121
|
+
ou feature (docs/ ja existe). Nao ha skills diferentes pra setup vs feature.
|
|
122
|
+
|
|
123
|
+
- Extrai PRD dos seus insumos (pode ser empty em scopes puro-tecnicos)
|
|
124
|
+
- Para e pede sua aprovacao
|
|
116
125
|
- Depois voce roda `/sf-design`, `/sf-plan`, `/sf-dev` na sequencia
|
|
117
126
|
|
|
118
127
|
## Pipeline completo
|
|
119
128
|
|
|
120
129
|
```
|
|
121
|
-
workspace/Input
|
|
130
|
+
workspace/Input/<nome>/ (seus arquivos)
|
|
122
131
|
|
|
|
123
132
|
v
|
|
124
|
-
/sf-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
/sf-design --> SDD + docs/ (5 arquivos)
|
|
133
|
+
/sf-start <nome> --> /sf-extract --> PRD (voce revisa e aprova)
|
|
134
|
+
|
|
|
135
|
+
v
|
|
136
|
+
/sf-design --> SDD + docs/ (first-run: cria 5 arquivos)
|
|
137
|
+
(feature: gera só §Área-X + §11 delta)
|
|
128
138
|
|
|
|
129
139
|
v
|
|
130
140
|
/sf-plan --> tasks + Progresso.md
|
|
131
141
|
|
|
|
132
142
|
v
|
|
133
143
|
/sf-dev --> codigo nos repos
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
(merge-delta automatico)
|
|
144
|
+
+ /sf-merge-docs automatico
|
|
145
|
+
(aplica §11 em docs/)
|
|
137
146
|
```
|
|
138
147
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
/sf-feature nome --> /sf-extract --> PRD --> /sf-design --> /sf-plan --> /sf-dev (inclui merge-delta)
|
|
143
|
-
```
|
|
148
|
+
Mesmo comando pra bootstrap e feature — `first_run` e derivado da ausencia/presenca de `docs/`.
|
|
144
149
|
|
|
145
150
|
## Opcoes do CLI
|
|
146
151
|
|
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-copilot init --name=<
|
|
13
|
-
console.log(' spec-first-copilot update [--target=<
|
|
11
|
+
console.log('Uso:');
|
|
12
|
+
console.log(' spec-first-copilot init --name=<nome-do-projeto> [--target=<caminho>]');
|
|
13
|
+
console.log(' spec-first-copilot 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 skills/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 VS Code:');
|
|
62
|
+
console.log(' node .github/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 Copilot → faltar dep → reiniciar VS Code".');
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(' 5. Abra o VS Code com Copilot Chat e rode:');
|
|
67
|
+
console.log(' /sf-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
|
@@ -20,37 +20,38 @@ function update({ templatesDir, targetDir, force }) {
|
|
|
20
20
|
const dest = targetDir || process.cwd();
|
|
21
21
|
|
|
22
22
|
if (!fs.existsSync(dest)) {
|
|
23
|
-
console.error(`
|
|
24
|
-
console.error('
|
|
23
|
+
console.error(`Erro: diretório "${dest}" não existe.`);
|
|
24
|
+
console.error('Rode "spec-first-copilot init --name=<nome>" primeiro pra criar o projeto.');
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const githubDir = path.join(dest, '.github');
|
|
29
29
|
if (!fs.existsSync(githubDir)) {
|
|
30
|
-
console.error('
|
|
31
|
-
console.error('
|
|
30
|
+
console.error('Erro: não é um projeto spec-first (pasta .github/ não encontrada).');
|
|
31
|
+
console.error('Rode "spec-first-copilot init --name=<nome>" primeiro.');
|
|
32
32
|
process.exit(1);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
console.log(`\
|
|
35
|
+
console.log(`\nAtualizando projeto em ${dest}\n`);
|
|
36
36
|
|
|
37
37
|
const stats = { added: [], updated: [], skipped: 0 };
|
|
38
38
|
syncDir(templatesDir, dest, force, stats, dest);
|
|
39
39
|
|
|
40
40
|
console.log('');
|
|
41
41
|
if (stats.added.length > 0) {
|
|
42
|
-
console.log(`
|
|
42
|
+
console.log(`Adicionados (${stats.added.length}):`);
|
|
43
43
|
for (const f of stats.added) console.log(` + ${f}`);
|
|
44
44
|
}
|
|
45
45
|
if (stats.updated.length > 0) {
|
|
46
|
-
console.log(`
|
|
46
|
+
console.log(`Atualizados (${stats.updated.length}):`);
|
|
47
47
|
for (const f of stats.updated) console.log(` ~ ${f}`);
|
|
48
48
|
}
|
|
49
49
|
if (stats.added.length === 0 && stats.updated.length === 0) {
|
|
50
|
-
console.log('
|
|
50
|
+
console.log('Já está atualizado — nenhum arquivo novo pra adicionar.');
|
|
51
51
|
} else {
|
|
52
|
-
console.log(`\n${stats.added.length}
|
|
52
|
+
console.log(`\n${stats.added.length} adicionado(s), ${stats.updated.length} atualizado(s), ${stats.skipped} inalterado(s)`);
|
|
53
53
|
}
|
|
54
|
+
|
|
54
55
|
console.log('');
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -58,7 +59,8 @@ function syncDir(src, dest, force, stats, root) {
|
|
|
58
59
|
fs.mkdirSync(dest, { recursive: true });
|
|
59
60
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
60
61
|
const srcPath = path.join(src, entry.name);
|
|
61
|
-
const
|
|
62
|
+
const destName = entry.name === '_gitignore' ? '.gitignore' : entry.name;
|
|
63
|
+
const destPath = path.join(dest, destName);
|
|
62
64
|
if (entry.isDirectory()) {
|
|
63
65
|
syncDir(srcPath, destPath, force, stats, root);
|
|
64
66
|
} else {
|
package/package.json
CHANGED