spec-first-copilot 0.5.0-beta.9 → 0.6.0-beta.2
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/lib/init.js +8 -17
- package/lib/update.js +3 -1
- package/package.json +1 -1
- package/templates/.github/CHANGELOG.md +72 -0
- package/templates/.github/adapters/SETUP.md +4 -4
- package/templates/.github/adapters/confluence.md +2 -2
- package/templates/.github/adapters/errors.md +2 -2
- package/templates/.github/adapters/filesystem.md +4 -4
- package/templates/.github/adapters/interface.md +3 -3
- package/templates/.github/adapters/naming.md +15 -15
- package/templates/.github/adapters/registry.md +3 -3
- package/templates/.github/agents/doc-writer.md +21 -16
- 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/skills/sf-design/SKILL.md +175 -209
- package/templates/.github/skills/sf-dev/SKILL.md +351 -354
- package/templates/.github/skills/sf-discovery/SKILL.md +1 -1
- package/templates/.github/skills/sf-extract/SKILL.md +143 -234
- package/templates/.github/skills/sf-load/SKILL.md +146 -120
- package/templates/.github/skills/sf-mcp/SKILL.md +295 -0
- package/templates/.github/skills/sf-merge-docs/SKILL.md +100 -0
- package/templates/.github/skills/sf-plan/SKILL.md +104 -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 +37 -13
- package/templates/.github/templates/feature/backlog-extraido.template.md +8 -6
- package/templates/.github/templates/feature/context.template.md +17 -11
- package/templates/.github/templates/feature/extract-log.template.md +2 -1
- package/templates/.github/templates/feature/projetos.template.yaml +4 -4
- package/templates/.github/templates/feature/sdd.template.md +358 -178
- package/templates/.github/templates/global/progresso_global.template.md +2 -2
- 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/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');
|
|
@@ -47,23 +48,13 @@ function init({ name, templatesDir, targetDir }) {
|
|
|
47
48
|
copyDir(templatesDir, dest, replacements);
|
|
48
49
|
patchProjectName(dest, name);
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
execSync('git init', { cwd: dest, stdio: 'pipe' });
|
|
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.`);
|
|
51
|
+
console.log(`Done! Project "${name}" is ready.`);
|
|
63
52
|
console.log('\nNext steps:');
|
|
64
53
|
console.log(` 1. cd ${name}`);
|
|
65
54
|
console.log(' 2. Create a folder in workspace/Input/ with your project files (e.g. workspace/Input/my_app/)');
|
|
66
|
-
console.log(' 3.
|
|
55
|
+
console.log(' 3. (Optional) Copy sfw.config.yml.example to sfw.config.yml and configure your backend');
|
|
56
|
+
console.log(' 4. Open VS Code with Copilot Chat and run: /sf-start <folder-name>');
|
|
57
|
+
console.log(' Framework detects first-run automatically (creates docs/) vs feature (updates docs/).');
|
|
67
58
|
console.log('');
|
|
68
59
|
}
|
|
69
60
|
|
package/lib/update.js
CHANGED
|
@@ -51,6 +51,7 @@ function update({ templatesDir, targetDir, force }) {
|
|
|
51
51
|
} else {
|
|
52
52
|
console.log(`\n${stats.added.length} added, ${stats.updated.length} updated, ${stats.skipped} unchanged`);
|
|
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
|
@@ -8,6 +8,78 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## 0.6.0-beta.2 (2026-04-12)
|
|
12
|
+
|
|
13
|
+
### Fix: CLI `init` output
|
|
14
|
+
|
|
15
|
+
- Mensagem "Next steps" do `npx spec-first-copilot init` apontava pro `/sf-new-project` removido no v3
|
|
16
|
+
- Agora aponta pro `/sf-start <folder-name>` + nota que framework detecta first-run automaticamente
|
|
17
|
+
- sfw.config.yml.example marcado como opcional (projeto funciona 100% local)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 0.6.0-beta.1 (2026-04-12) — Redesign v3 (BREAKING)
|
|
22
|
+
|
|
23
|
+
Redesign estrutural eliminando o TRD e unificando o pipeline em uma skill única.
|
|
24
|
+
Ver `planodetarefas.md §10` (no repo SFW) pra racional completo e 9 decisões arquiteturais.
|
|
25
|
+
|
|
26
|
+
### Breaking
|
|
27
|
+
|
|
28
|
+
- **TRD eliminado** — template `TRD.template.md` removido; conteúdo técnico agora vive no SDD §Sistema (novas subseções 3.1-3.7) e é sintetizado em `docs/` cross-feature
|
|
29
|
+
- **`/sf-new-project` + `/sf-feature` → `/sf-start <nome>`** — entrada única. Detecta automaticamente:
|
|
30
|
+
- `docs/` ausente → first_run (bootstrap: popula SDD §Sistema completo + cria docs/ + projetos.yaml)
|
|
31
|
+
- `docs/` existe → feature (popula §Área-X tocadas + §11 Delta Specs)
|
|
32
|
+
- **`/sf-merge-delta` → `/sf-merge-docs`** — nome alinhado ao outcome. "Delta Specs" continua como conceito no SDD §11
|
|
33
|
+
- **PRD empty-allowed** — scopes puro-técnicos marcam `empty: true` em vez de forçar PRD vazio
|
|
34
|
+
- **SDD template reorganizado** — §Sistema (baseline técnico) + §Área-Backend/Frontend/DB/Infra gateáveis por scope
|
|
35
|
+
- **docs/ = síntese cross-feature** (não projeção) — estável, referencia SDDs quando precisa detalhe
|
|
36
|
+
- **Checklist de temas críticos FIXO** — 8 temas unificados (antes era split TRD/PRD). Analyzer consulta `docs/` antes de marcar ambiguidade
|
|
37
|
+
- **Skills: 12 → 11** — `sf-new-project`, `sf-feature`, `sf-merge-delta` removidas; `sf-start`, `sf-merge-docs` adicionadas
|
|
38
|
+
|
|
39
|
+
### Migração
|
|
40
|
+
|
|
41
|
+
Projetos em `0.5.0-beta.X` precisam:
|
|
42
|
+
|
|
43
|
+
1. Rodar `npx spec-first-copilot update` (atualiza .github/, CHANGELOG, templates)
|
|
44
|
+
2. Se tiver `.context.md` com `tipo: feature|setup` ou `documento: PRD|TRD`: migrar pra schema v3:
|
|
45
|
+
```yaml
|
|
46
|
+
first_run: true|false # true se docs/ não existia quando bootstrap rodou
|
|
47
|
+
prd_empty: false # true se TRD existia mas PRD não (raro)
|
|
48
|
+
areas_tocadas: [BACK, DB] # derivar do SDD existente
|
|
49
|
+
```
|
|
50
|
+
3. Se tiver `TRD.md` em `workspace/Output/{scope}/`: manter como referência histórica ou deletar
|
|
51
|
+
4. Rodar `/sf-merge-docs <scope>` manualmente pra features que estavam em `dev_done` (aplica §11 em `docs/`)
|
|
52
|
+
|
|
53
|
+
### Novo fluxo (v3)
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
/sf-start <nome>
|
|
57
|
+
→ /sf-load (se sfw.config.yml)
|
|
58
|
+
→ /sf-discovery (opcional)
|
|
59
|
+
→ /sf-extract → PRD.md (pode ser empty) + .extract-log.md com tech chunks
|
|
60
|
+
↓ checkpoint
|
|
61
|
+
/sf-design → SDD (§Sistema + §Área-X) + specs/{nome}/
|
|
62
|
+
→ first_run: cria docs/ + projetos.yaml
|
|
63
|
+
→ feature: §11 Delta Specs pro /sf-merge-docs
|
|
64
|
+
/sf-plan → specs/{nome}/tasks.md + Progresso.md
|
|
65
|
+
/sf-dev → código + Security Review + /sf-merge-docs automático
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Templates atualizados
|
|
69
|
+
|
|
70
|
+
- `PRD.template.md` — campo `empty` no Meta; rodapé pra caso empty
|
|
71
|
+
- `sdd.template.md` — 552 linhas, §Sistema + §Área-X gateáveis + §12 Ambiguidades com "Consultei docs/?"
|
|
72
|
+
- `context.template.md` — schema v3 (`first_run`, `prd_empty`, `areas_tocadas`)
|
|
73
|
+
- 5 templates em `estrutura/` — papel de síntese cross-feature, origem SDD §Sistema
|
|
74
|
+
- `backlog-extraido.template.md` — scope agnóstico, sugere `/sf-start <nome>` pra promover items
|
|
75
|
+
|
|
76
|
+
### Arquivos removidos
|
|
77
|
+
|
|
78
|
+
- `.github/templates/feature/TRD.template.md`
|
|
79
|
+
- `.github/skills/sf-new-project/`, `sf-feature/`, `sf-merge-delta/`
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
11
83
|
## 0.5.0-beta.7 (2026-04-12)
|
|
12
84
|
|
|
13
85
|
### Novo: Comando `/sf-load <nome>`
|
|
@@ -148,7 +148,7 @@ output:
|
|
|
148
148
|
config:
|
|
149
149
|
space_key: "ST" # ← mesmo Space Key
|
|
150
150
|
parent_page_id: "294931" # ← Page ID da page Output
|
|
151
|
-
publishes: [PRD,
|
|
151
|
+
publishes: [PRD, SDD, Progresso]
|
|
152
152
|
mode: auto # ← auto | manual | off
|
|
153
153
|
conflict_detection: version
|
|
154
154
|
approval_mechanism: label
|
|
@@ -225,7 +225,7 @@ output:
|
|
|
225
225
|
adapter: filesystem
|
|
226
226
|
config:
|
|
227
227
|
root_path: "workspace/Output"
|
|
228
|
-
publishes: [PRD,
|
|
228
|
+
publishes: [PRD, SDD, Progresso]
|
|
229
229
|
mode: auto
|
|
230
230
|
conflict_detection: hash
|
|
231
231
|
approval_mechanism: none
|
|
@@ -238,7 +238,7 @@ mkdir -p workspace/Input/meu_escopo
|
|
|
238
238
|
# Adicione seus arquivos de insumo na pasta
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
Pronto. `/
|
|
241
|
+
Pronto. `/sf-start meu_escopo` funciona direto.
|
|
242
242
|
|
|
243
243
|
---
|
|
244
244
|
|
|
@@ -282,7 +282,7 @@ E coloque `mode: off` nos targets de Confluence.
|
|
|
282
282
|
config:
|
|
283
283
|
space_key: "ST"
|
|
284
284
|
parent_page_id: "294931"
|
|
285
|
-
publishes: [PRD,
|
|
285
|
+
publishes: [PRD, SDD, Progresso]
|
|
286
286
|
mode: auto
|
|
287
287
|
```
|
|
288
288
|
3. Re-rode `/extract`, `/design`, `/plan` — os artefatos locais serão publicados
|
|
@@ -161,7 +161,7 @@ futuro, trocar. Hoje `get_page` é o caminho mais direto. Custo: ~1 request HTTP
|
|
|
161
161
|
1. Chamar tool com:
|
|
162
162
|
- `space_key: config.space_key`
|
|
163
163
|
- `parent_id: parentId`
|
|
164
|
-
- `title: title` (já vem formatado pelo naming engine — ex: `"app_barbearia -
|
|
164
|
+
- `title: title` (já vem formatado pelo naming engine — ex: `"app_barbearia - PRD"`)
|
|
165
165
|
- `content: content` (markdown — MCP converte pra storage format)
|
|
166
166
|
- `content_format: "markdown"`
|
|
167
167
|
2. Retornar:
|
|
@@ -262,7 +262,7 @@ Antes de usar este adapter, usuário precisa:
|
|
|
262
262
|
+ credenciais hardcoded (NUNCA commitar — está no `.gitignore` do kit)
|
|
263
263
|
- [ ] Token Atlassian com scope de leitura + escrita no space alvo
|
|
264
264
|
- [ ] `space_key` descoberto (ex: via `confluence_search` ou URL do Confluence)
|
|
265
|
-
- [ ] Página raiz do projeto criada (manualmente ou via `/
|
|
265
|
+
- [ ] Página raiz do projeto criada (manualmente ou via `/sf-start`)
|
|
266
266
|
- [ ] Claude Code reiniciado após qualquer mudança no `.mcp.json`
|
|
267
267
|
|
|
268
268
|
Bootstrap do kit (§9.9.P0.3) automatiza isso.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SourceAdapter — Contrato de Erros
|
|
2
2
|
|
|
3
3
|
> Classes de erro tipadas que qualquer adapter **deve** lançar em vez de
|
|
4
|
-
> `throw new Error(...)`. As skills (`/load`, `/publish`, `/
|
|
4
|
+
> `throw new Error(...)`. As skills (`/load`, `/publish`, `/sf-start`,
|
|
5
5
|
> `/extract`, `/design`, `/plan`) fazem `catch` tipado e decidem o que fazer.
|
|
6
6
|
>
|
|
7
7
|
> Arquivo é referência conceitual, não runtime. A implementação real vive no
|
|
@@ -100,7 +100,7 @@ foi deletado. Inclui: `fetchContent`, `getVersion`, `update`, `listChildren`,
|
|
|
100
100
|
- `/load`: pode ser scope removido no backend. Loga e pula (não fatal).
|
|
101
101
|
- `/publish`: se título existia no publish-log mas sumiu do backend → o caller
|
|
102
102
|
DEVE chamar `create` em vez de `update` (fallback implícito).
|
|
103
|
-
- `/
|
|
103
|
+
- `/sf-start`: se parent root não existe → fatal (config errada).
|
|
104
104
|
|
|
105
105
|
---
|
|
106
106
|
|
|
@@ -200,11 +200,11 @@ arquivos de spec/doc são pequenos (KB). Se precisar otimizar, substituir por
|
|
|
200
200
|
7. Retornar `{ itemId: <relative path>, version }`
|
|
201
201
|
|
|
202
202
|
**Convenção sobre `title`**: o caller já aplica `naming.output_artifact`
|
|
203
|
-
(ex: `"app_barbearia -
|
|
203
|
+
(ex: `"app_barbearia - PRD"`). O adapter **adiciona extensão `.md`** se o
|
|
204
204
|
title não já tiver uma — filesystem exige extensão, Confluence não. Esta é a
|
|
205
205
|
assimetria principal entre os 2 adapters.
|
|
206
206
|
|
|
207
|
-
Exemplo: `title = "app_barbearia -
|
|
207
|
+
Exemplo: `title = "app_barbearia - PRD"` → arquivo `app_barbearia - PRD.md`.
|
|
208
208
|
|
|
209
209
|
---
|
|
210
210
|
|
|
@@ -259,7 +259,7 @@ output:
|
|
|
259
259
|
adapter: filesystem
|
|
260
260
|
config:
|
|
261
261
|
root_path: "./workspace/Output"
|
|
262
|
-
publishes: [PRD,
|
|
262
|
+
publishes: [PRD, SDD, Progresso]
|
|
263
263
|
mode: auto
|
|
264
264
|
conflict_detection: hash
|
|
265
265
|
approval_mechanism: none
|
|
@@ -284,7 +284,7 @@ output:
|
|
|
284
284
|
adapter: filesystem
|
|
285
285
|
config:
|
|
286
286
|
root_path: "./tests/fixtures/barbearia/actual_output"
|
|
287
|
-
publishes: [PRD,
|
|
287
|
+
publishes: [PRD, SDD, Progresso]
|
|
288
288
|
mode: auto
|
|
289
289
|
```
|
|
290
290
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# SourceAdapter — Interface
|
|
2
2
|
|
|
3
3
|
> Contrato que **todo adapter** (Confluence, Filesystem, Notion, JIRA, …) deve
|
|
4
|
-
> implementar. As skills `/load`, `/publish`, `/
|
|
4
|
+
> implementar. As skills `/load`, `/publish`, `/sf-start` **nunca** falam com
|
|
5
5
|
> backends direto — elas falam com essa interface.
|
|
6
6
|
>
|
|
7
7
|
> Este arquivo é **especificação**, não código executável. A implementação real
|
|
@@ -42,7 +42,7 @@ interface SourceAdapter {
|
|
|
42
42
|
validateConfig(config: object): void;
|
|
43
43
|
|
|
44
44
|
// ------------------------------------------------------------------
|
|
45
|
-
// LEITURA — usado por /load e /
|
|
45
|
+
// LEITURA — usado por /load e /sf-start
|
|
46
46
|
// ------------------------------------------------------------------
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -263,7 +263,7 @@ Qualquer adapter **DEVE** garantir:
|
|
|
263
263
|
├── listChildren(output.parent_page_id) ← acha container existente por título
|
|
264
264
|
├── se container não existe:
|
|
265
265
|
│ └── create(output.parent_page_id, containerTitle, seed) → container criado
|
|
266
|
-
├── applyNaming(output_artifact, {scope, type}) ← ex: "app_barbearia -
|
|
266
|
+
├── applyNaming(output_artifact, {scope, type}) ← ex: "app_barbearia - PRD"
|
|
267
267
|
├── listChildren(container.id) ← busca artefato por título
|
|
268
268
|
├── se artefato não existe:
|
|
269
269
|
│ └── create(container.id, artifactTitle, content) → log version
|
|
@@ -15,12 +15,12 @@ Antes da decisão do adapter layer, títulos eram hardcoded em string literal
|
|
|
15
15
|
no código das skills:
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
title = `out_${scope}
|
|
18
|
+
title = `out_${scope}_PRD`; // ← hardcoded em 5 lugares
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Isso forçava:
|
|
22
22
|
1. Qualquer mudança de convenção → tocar N arquivos
|
|
23
|
-
2. Times com outra convenção (ex: `[
|
|
23
|
+
2. Times com outra convenção (ex: `[PRD] scope`) não conseguiam usar SFW
|
|
24
24
|
3. Testes precisavam mockar strings mágicas
|
|
25
25
|
|
|
26
26
|
Agora a convenção vive em **um** arquivo (`sfw.config.yml`) e é aplicada via
|
|
@@ -33,7 +33,7 @@ templating engine centralizado.
|
|
|
33
33
|
| Placeholder | O que substitui | Fonte |
|
|
34
34
|
|-------------|-----------------|-------|
|
|
35
35
|
| `{scope}` | Nome do item no Input (ex: `app_barbearia`, `feat_login`) | Argumento da skill |
|
|
36
|
-
| `{type}` | Tipo do artefato (ex: `
|
|
36
|
+
| `{type}` | Tipo do artefato (ex: `PRD`, `SDD`, `Progresso`) | Contexto da skill |
|
|
37
37
|
|
|
38
38
|
**Nenhum outro placeholder é aceito no MVP.** Expansões futuras entram por
|
|
39
39
|
proposta explícita (ex: `{phase}`, `{repo}`, `{timestamp}`).
|
|
@@ -51,17 +51,17 @@ O `sfw.config.yml` define 2 templates de output:
|
|
|
51
51
|
| Template | Onde | Exemplo |
|
|
52
52
|
|----------|------|---------|
|
|
53
53
|
| `output_container` | Subpasta/page-mãe por scope no Output | `"out_{scope}"` → `out_app_barbearia` |
|
|
54
|
-
| `output_artifact` | Nome do artefato dentro do container | `"{scope} - {type}"` → `app_barbearia -
|
|
54
|
+
| `output_artifact` | Nome do artefato dentro do container | `"{scope} - {type}"` → `app_barbearia - PRD` |
|
|
55
55
|
|
|
56
56
|
**`output_container`** é o agrupador. No Confluence vira uma page-mãe com
|
|
57
57
|
children; no filesystem vira uma pasta.
|
|
58
58
|
|
|
59
|
-
**`output_artifact`** é o item individual (
|
|
59
|
+
**`output_artifact`** é o item individual (PRD, SDD, Progresso). No
|
|
60
60
|
Confluence é title de uma child page; no filesystem é nome de arquivo
|
|
61
61
|
(adapter adiciona `.md` automaticamente).
|
|
62
62
|
|
|
63
63
|
**Por que `{scope}` no `output_artifact`?** No Confluence, titles são
|
|
64
|
-
unique per SPACE — sem `{scope}`, duas features teriam `
|
|
64
|
+
unique per SPACE — sem `{scope}`, duas features teriam `PRD` e `SDD` com
|
|
65
65
|
mesmo título e colidiria. No filesystem não colide porque vive dentro de
|
|
66
66
|
pastas diferentes, então o user pode configurar `output_artifact: "{type}"`
|
|
67
67
|
se preferir limpar redundância.
|
|
@@ -94,7 +94,7 @@ function applyNaming(template: string, vars: {
|
|
|
94
94
|
Nunca retorna a string literal `{module}` — isso vazaria inconsistência pros backends.
|
|
95
95
|
|
|
96
96
|
2. **Placeholder sem valor lança erro.**
|
|
97
|
-
Template `"{scope} - {type}"` com `vars = { type: "
|
|
97
|
+
Template `"{scope} - {type}"` com `vars = { type: "PRD" }`
|
|
98
98
|
→ `NamingTemplateError: placeholder {scope} required but not provided`.
|
|
99
99
|
|
|
100
100
|
3. **Chaves extras em `vars` são ignoradas.**
|
|
@@ -156,12 +156,12 @@ function applyNaming(template: string, vars: Record<string, string | undefined>)
|
|
|
156
156
|
| Template | vars | Resultado | OK? |
|
|
157
157
|
|----------|------|-----------|-----|
|
|
158
158
|
| `out_{scope}` | `{scope:"app_barbearia"}` | `out_app_barbearia` | ✅ |
|
|
159
|
-
| `{scope} - {type}` | `{scope:"app_barbearia", type:"
|
|
159
|
+
| `{scope} - {type}` | `{scope:"app_barbearia", type:"PRD"}` | `app_barbearia - PRD` | ✅ |
|
|
160
160
|
| `{type}` | `{type:"SDD"}` | `SDD` | ✅ (filesystem dentro de subpasta) |
|
|
161
161
|
| `[{type}] {scope}` | `{type:"PRD", scope:"feat_login"}` | `[PRD] feat_login` | ✅ |
|
|
162
162
|
| `{type}/{scope}` | `{type:"docs", scope:"arch"}` | `docs/arch` | ✅ (adapter sanitiza `/` depois) |
|
|
163
|
-
| `{scope} - {type}` | `{type:"
|
|
164
|
-
| `{type} {module}` | `{type:"
|
|
163
|
+
| `{scope} - {type}` | `{type:"PRD"}` | — | ❌ `NamingTemplateError: placeholder {scope} required` |
|
|
164
|
+
| `{type} {module}` | `{type:"PRD"}` | — | ❌ `NamingTemplateError: unknown placeholder "{module}"` |
|
|
165
165
|
| `hello world` | `{}` | `hello world` | ✅ (sem placeholders) |
|
|
166
166
|
| `out_{scope}` | `{scope:""}` | — | ❌ (string vazia é tratada como ausente) |
|
|
167
167
|
|
|
@@ -172,7 +172,7 @@ function applyNaming(template: string, vars: Record<string, string | undefined>)
|
|
|
172
172
|
| Skill / operação | Template consumido | Placeholders usados |
|
|
173
173
|
|------------------|-------------------|---------------------|
|
|
174
174
|
| `/load` busca scope no Input | Nenhum — usa o nome do item **tal qual está** no backend | — |
|
|
175
|
-
| `/extract` publica
|
|
175
|
+
| `/extract` publica PRD | `output_container` + `output_artifact` (type=PRD) | `{scope}`, `{type}` |
|
|
176
176
|
| `/design` publica SDD | `output_container` + `output_artifact` (type=SDD) | `{scope}`, `{type}` |
|
|
177
177
|
| `/plan` publica Progresso | `output_container` + `output_artifact` (type=Progresso) | `{scope}`, `{type}` |
|
|
178
178
|
| `/load` grava scope folder local | `output_container` (reuso pro path local) | `{scope}` |
|
|
@@ -194,14 +194,14 @@ naming:
|
|
|
194
194
|
output_artifact: "{scope} - {type}"
|
|
195
195
|
```
|
|
196
196
|
|
|
197
|
-
Cenário: `/
|
|
197
|
+
Cenário: `/sf-start app_barbearia` → `/extract` → `/design` → `/plan`
|
|
198
198
|
|
|
199
199
|
| Passo | Template usado | vars | Resultado |
|
|
200
200
|
|-------|---------------|------|-----------|
|
|
201
201
|
| `/load` busca item no Input | nenhum | — | Encontra page "app_barbearia" pelo nome |
|
|
202
202
|
| `/load` grava local | `output_container` | `{scope:"app_barbearia"}` | Pasta `workspace/Input/out_app_barbearia/` |
|
|
203
203
|
| `/extract` cria container no Output | `output_container` | `{scope:"app_barbearia"}` | Page/pasta `out_app_barbearia` |
|
|
204
|
-
| `/extract` publica
|
|
204
|
+
| `/extract` publica PRD | `output_artifact` | `{scope:"app_barbearia", type:"PRD"}` | `app_barbearia - PRD` (dentro do container) |
|
|
205
205
|
| `/design` publica SDD | `output_artifact` | `{scope:"app_barbearia", type:"SDD"}` | `app_barbearia - SDD` |
|
|
206
206
|
| `/plan` publica Progresso | `output_artifact` | `{scope:"app_barbearia", type:"Progresso"}` | `app_barbearia - Progresso` |
|
|
207
207
|
|
|
@@ -209,7 +209,7 @@ Resultado no Confluence:
|
|
|
209
209
|
```
|
|
210
210
|
Output (page-mãe)
|
|
211
211
|
└── out_app_barbearia (container)
|
|
212
|
-
├── app_barbearia -
|
|
212
|
+
├── app_barbearia - PRD
|
|
213
213
|
├── app_barbearia - SDD
|
|
214
214
|
└── app_barbearia - Progresso
|
|
215
215
|
```
|
|
@@ -218,7 +218,7 @@ Resultado no filesystem:
|
|
|
218
218
|
```
|
|
219
219
|
workspace/Output/
|
|
220
220
|
└── out_app_barbearia/
|
|
221
|
-
├── app_barbearia -
|
|
221
|
+
├── app_barbearia - PRD.md
|
|
222
222
|
├── app_barbearia - SDD.md
|
|
223
223
|
└── app_barbearia - Progresso.md
|
|
224
224
|
```
|
|
@@ -153,7 +153,7 @@ Quando skill chama `loadConfig("sfw.config.yml")`:
|
|
|
153
153
|
5. **Valida `naming.*`** — templates precisam ser strings não-vazias; placeholders
|
|
154
154
|
desconhecidos detectados agora (antecipa erro de runtime).
|
|
155
155
|
6. **Valida coerência inter-seções**: ex., `output.targets[i].mode: auto` exige
|
|
156
|
-
`approval_mechanism` presente quando `publishes` contém
|
|
156
|
+
`approval_mechanism` presente quando `publishes` contém PRD/SDD (artefatos
|
|
157
157
|
com gate de aprovação).
|
|
158
158
|
|
|
159
159
|
Tudo no load. Se qualquer passo falha, skill para antes de tocar backend.
|
|
@@ -178,13 +178,13 @@ output:
|
|
|
178
178
|
config:
|
|
179
179
|
space_key: ST
|
|
180
180
|
parent_page_id: "294931"
|
|
181
|
-
publishes: [PRD,
|
|
181
|
+
publishes: [PRD, SDD, Progresso]
|
|
182
182
|
mode: auto
|
|
183
183
|
- name: local-mirror
|
|
184
184
|
adapter: filesystem
|
|
185
185
|
config:
|
|
186
186
|
root_path: "./mirror"
|
|
187
|
-
publishes: [PRD,
|
|
187
|
+
publishes: [PRD, SDD, Progresso, backlog]
|
|
188
188
|
mode: auto
|
|
189
189
|
```
|
|
190
190
|
|