spec-first-copilot 0.5.0-beta.15 → 0.5.0-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,134 +1,110 @@
|
|
|
1
|
-
# /sf-load <nome>
|
|
1
|
+
# /sf-load <nome> | --all
|
|
2
2
|
|
|
3
|
-
Puxa
|
|
4
|
-
e materializa em `workspace/Input/{nome}/` no projeto local.
|
|
3
|
+
Puxa conteúdo do backend configurado (Confluence, filesystem, etc.) e materializa localmente.
|
|
5
4
|
|
|
6
|
-
##
|
|
5
|
+
## Modos
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
| Modo | O que traz | Destino local |
|
|
8
|
+
|------|-----------|---------------|
|
|
9
|
+
| `/sf-load <nome>` | Input **e** Output do scope `{nome}` | `workspace/Input/{nome}/` + `workspace/Output/{nome}/` |
|
|
10
|
+
| `/sf-load --all` | **Tudo** — todos os scopes de Input e Output | `workspace/Input/*/` + `workspace/Output/*/` |
|
|
11
|
+
|
|
12
|
+
## Por que trazer Output também?
|
|
13
|
+
|
|
14
|
+
O Output pode já ter artefatos publicados (TRD, SDD, Progresso) por outra sessão
|
|
15
|
+
ou outro dev. Se você não traz, o pipeline pensa que não existe e tenta recriar.
|
|
16
|
+
Trazer Output garante continuidade.
|
|
10
17
|
|
|
11
18
|
## Quando usar
|
|
12
19
|
|
|
13
|
-
- **Antes de `/sf-new-project
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
|
|
17
|
-
- **Não obrigatório** se o usuário já colocou insumos direto em `workspace/Input/{nome}/`
|
|
20
|
+
- **Antes de `/sf-new-project` ou `/sf-feature`** — traz insumos frescos + artefatos existentes
|
|
21
|
+
- **Após o PM adicionar novos insumos** — re-sincroniza incrementalmente
|
|
22
|
+
- **Início de sessão num projeto existente** — `/sf-load --all` pra ter tudo atualizado
|
|
23
|
+
- **Não obrigatório** se o projeto é 100% local (sem `sfw.config.yml`)
|
|
18
24
|
|
|
19
25
|
## Pré-condições
|
|
20
26
|
|
|
21
27
|
| # | Validação | Se falhar |
|
|
22
28
|
|---|-----------|-----------|
|
|
23
|
-
| 1 | `sfw.config.yml` existe na raiz do projeto | Parar → "
|
|
24
|
-
| 2 | `sfw.config.yml` tem seção `input`
|
|
25
|
-
| 3 | Adapter
|
|
29
|
+
| 1 | `sfw.config.yml` existe na raiz do projeto | Parar → "Rode /sf-mcp confluence ou configure manualmente. Veja .github/adapters/SETUP.md" |
|
|
30
|
+
| 2 | `sfw.config.yml` tem seção `input` e `output` | Parar → "Seções input/output não encontradas no sfw.config.yml" |
|
|
31
|
+
| 3 | Adapter acessível (MCP rodando pra Confluence) | Parar → orientar setup conforme `.github/adapters/SETUP.md` |
|
|
26
32
|
|
|
27
33
|
## Execução
|
|
28
34
|
|
|
29
35
|
### 1. Carregar configuração
|
|
30
36
|
|
|
31
37
|
Ler `sfw.config.yml` e extrair:
|
|
32
|
-
- `input.adapter`
|
|
33
|
-
- `input.config` —
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
36
|
-
- `input.cache.
|
|
37
|
-
- `
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
**Para Filesystem** (`adapter: filesystem`):
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
1. Listar conteúdo de config.root_path
|
|
56
|
-
2. Buscar pasta ou arquivo com nome == {nome}
|
|
57
|
-
3. Se não encontrou → ERRO: "Scope '{nome}' não encontrado em {root_path}"
|
|
58
|
-
4. Anotar scope_path
|
|
59
|
-
```
|
|
38
|
+
- `input.adapter` + `input.config` — pra puxar Input
|
|
39
|
+
- `input.config.parent_page_id` — page-mãe do Input no backend
|
|
40
|
+
- `output.targets[0].adapter` + `output.targets[0].config` — pra puxar Output
|
|
41
|
+
- `output.targets[0].config.parent_page_id` — page-mãe do Output no backend
|
|
42
|
+
- `input.cache.local_dir` — default `workspace/Input/`
|
|
43
|
+
- `input.cache.log` — default `.ai/sf-load-log.md`
|
|
44
|
+
- `naming.output_container` — template pra nome da pasta de Output (ex: `out_{scope}`)
|
|
45
|
+
|
|
46
|
+
### 2. Determinar o que trazer
|
|
47
|
+
|
|
48
|
+
**Se `/sf-load <nome>`:**
|
|
49
|
+
- **Input**: buscar scope `{nome}` nos filhos de `input.parent_page_id`
|
|
50
|
+
- Match exato por título — se não encontrou, ERRO
|
|
51
|
+
- **Output**: buscar container `out_{nome}` (ou conforme `naming.output_container`) nos filhos de `output.parent_page_id`
|
|
52
|
+
- Se não encontrou → OK, ainda não foi publicado. Pular silenciosamente.
|
|
53
|
+
|
|
54
|
+
**Se `/sf-load --all`:**
|
|
55
|
+
- **Input**: listar TODOS os filhos de `input.parent_page_id`
|
|
56
|
+
- **Output**: listar TODOS os filhos de `output.parent_page_id`
|
|
57
|
+
- Processar cada um como se fosse `/sf-load <nome>` individual
|
|
60
58
|
|
|
61
59
|
### 3. Trazer conteúdo — RECURSIVO ATÉ O ÚLTIMO NÍVEL, FLAT LOCAL
|
|
62
60
|
|
|
63
61
|
> **3 REGRAS INVIOLÁVEIS:**
|
|
64
|
-
> 1. **Descer até o último nível** —
|
|
65
|
-
> 2. **Local é flat** — todos os arquivos
|
|
66
|
-
> 3. **Refletir 100% do externo** — tudo que existe no backend
|
|
62
|
+
> 1. **Descer até o último nível** — `get_page_children` retorna só 1 nível. O agent DEVE fazer loop recursivo.
|
|
63
|
+
> 2. **Local é flat** — todos os arquivos soltos na pasta, SEM subpastas por nível.
|
|
64
|
+
> 3. **Refletir 100% do externo** — tudo que existe no backend DEVE existir localmente.
|
|
67
65
|
|
|
68
|
-
**Para
|
|
66
|
+
**Para cada scope de Input — materializar em `workspace/Input/{nome}/`:**
|
|
69
67
|
|
|
70
68
|
```
|
|
71
69
|
function loadScope(pageId, targetDir):
|
|
72
|
-
// PASSO 1: Coletar TODAS as pages da árvore (recursivo)
|
|
73
70
|
allPages = []
|
|
74
71
|
collectAllPages(pageId, allPages)
|
|
75
72
|
|
|
76
|
-
// PASSO 2: Baixar conteúdo de CADA page como arquivo flat
|
|
77
73
|
para cada page em allPages:
|
|
78
74
|
content = mcp__atlassian__confluence_get_page(page_id=page.id, convert_to_markdown=true)
|
|
79
75
|
filename = sanitize(page.title) + ".md"
|
|
80
|
-
salvar content em {targetDir}/{filename}
|
|
81
|
-
registrar no load-log
|
|
76
|
+
salvar content em {targetDir}/{filename}
|
|
77
|
+
registrar no load-log
|
|
82
78
|
|
|
83
|
-
//
|
|
79
|
+
// Attachments de CADA page
|
|
84
80
|
para cada page em allPages:
|
|
85
81
|
attachments = mcp__atlassian__confluence_get_attachments(page_id=page.id)
|
|
86
|
-
para cada att
|
|
82
|
+
para cada att:
|
|
87
83
|
bytes = mcp__atlassian__confluence_download_attachment(page_id=page.id, filename=att.title)
|
|
88
|
-
salvar em {targetDir}/{att.title}
|
|
84
|
+
salvar em {targetDir}/{att.title}
|
|
89
85
|
registrar no load-log
|
|
90
86
|
|
|
91
87
|
function collectAllPages(pageId, result):
|
|
92
|
-
// get_page_children retorna APENAS filhos diretos — por isso o loop recursivo
|
|
93
88
|
children = mcp__atlassian__confluence_get_page_children(page_id=pageId)
|
|
94
|
-
para cada child
|
|
95
|
-
result.push(child)
|
|
96
|
-
collectAllPages(child.id, result)
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**Exemplo concreto — Confluence tem esta árvore:**
|
|
100
|
-
```
|
|
101
|
-
app_barbearia (page raiz do scope)
|
|
102
|
-
├── Requisitos funcionais
|
|
103
|
-
│ ├── Regras de negocio
|
|
104
|
-
│ │ └── Neta da pagina ← 3º nível!
|
|
105
|
-
│ └── Jornadas
|
|
106
|
-
├── Stack tecnica
|
|
107
|
-
└── attachment: diagrama.png
|
|
89
|
+
para cada child:
|
|
90
|
+
result.push(child)
|
|
91
|
+
collectAllPages(child.id, result) // recursão total
|
|
108
92
|
```
|
|
109
93
|
|
|
110
|
-
**
|
|
111
|
-
```
|
|
112
|
-
workspace/Input/app_barbearia/
|
|
113
|
-
├── app_barbearia.md ← conteúdo da page raiz
|
|
114
|
-
├── requisitos_funcionais.md ← filho
|
|
115
|
-
├── regras_de_negocio.md ← neto
|
|
116
|
-
├── neta_da_pagina.md ← bisneto (3º nível!)
|
|
117
|
-
├── jornadas.md ← filho
|
|
118
|
-
├── stack_tecnica.md ← filho
|
|
119
|
-
└── diagrama.png ← attachment
|
|
120
|
-
```
|
|
94
|
+
**Para cada scope de Output — materializar em `workspace/Output/{nome}/`:**
|
|
121
95
|
|
|
122
|
-
|
|
96
|
+
Mesmo processo, mas:
|
|
97
|
+
- Container no backend tem nome conforme `naming.output_container` (ex: `out_app_barbearia`)
|
|
98
|
+
- Artifacts dentro dele são TRD, SDD, Progresso, etc.
|
|
99
|
+
- Materializar cada um como `{tipo}.md` (ex: `TRD.md`, `sdd.md`, `Progresso.md`)
|
|
100
|
+
- Nome local do scope é extraído do container (remove prefixo `out_`)
|
|
123
101
|
|
|
124
|
-
**Para Filesystem
|
|
102
|
+
**Para Filesystem** (`adapter: filesystem`):
|
|
125
103
|
|
|
126
104
|
```
|
|
127
105
|
function loadScope(sourcePath, targetDir):
|
|
128
|
-
// Se source == targetDir → no-op
|
|
106
|
+
// Se source == targetDir → no-op
|
|
129
107
|
// Senão: copiar TODOS os arquivos recursivamente pra targetDir (flat)
|
|
130
|
-
// Subpastas do source viram arquivos flat no target
|
|
131
|
-
// Calcular sha256 de cada arquivo pra load-log
|
|
132
108
|
```
|
|
133
109
|
|
|
134
110
|
### 4. Log incremental (`.ai/sf-load-log.md`)
|
|
@@ -138,85 +114,93 @@ Formato append-only:
|
|
|
138
114
|
```markdown
|
|
139
115
|
## Load: {nome} — {ISO_DATETIME}
|
|
140
116
|
|
|
117
|
+
### Input
|
|
141
118
|
| Item ID | Title | Version | SHA256 | Local Path | Status |
|
|
142
119
|
|---------|-------|---------|--------|------------|--------|
|
|
143
120
|
| 294950 | app_barbearia | 3 | a3f5... | workspace/Input/app_barbearia/app_barbearia.md | NOVO |
|
|
144
|
-
| 491572 | Requisitos
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
|
148
|
-
|
|
149
|
-
|
|
|
121
|
+
| 491572 | Requisitos | 2 | 8b1c... | workspace/Input/app_barbearia/requisitos.md | NOVO |
|
|
122
|
+
|
|
123
|
+
### Output
|
|
124
|
+
| Item ID | Title | Version | SHA256 | Local Path | Status |
|
|
125
|
+
|---------|-------|---------|--------|------------|--------|
|
|
126
|
+
| 393238 | app_barbearia - TRD | 2 | 4d2a... | workspace/Output/app_barbearia/TRD.md | NOVO |
|
|
127
|
+
| 425998 | app_barbearia - SDD | 1 | 7f3e... | workspace/Output/app_barbearia/sdd.md | NOVO |
|
|
150
128
|
```
|
|
151
129
|
|
|
152
130
|
**Se `incremental: true`** (default):
|
|
153
|
-
-
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
131
|
+
- Comparar hash com log anterior antes de baixar
|
|
132
|
+
- `INALTERADO` = hash igual, não sobrescreve
|
|
133
|
+
- `MODIFICADO` = hash diferente, sobrescreve
|
|
134
|
+
- `NOVO` = não existia no log
|
|
135
|
+
- `REMOVIDO` = existia no log mas sumiu do backend (log only, não deleta local)
|
|
158
136
|
|
|
159
137
|
### 5. Ajustar `.gitignore` conforme o adapter
|
|
160
138
|
|
|
161
|
-
Se o adapter NÃO é `filesystem
|
|
162
|
-
- Verificar se `.gitignore` contém
|
|
163
|
-
- Se NÃO contém,
|
|
139
|
+
Se o adapter NÃO é `filesystem`:
|
|
140
|
+
- Verificar se `.gitignore` contém `# SFW: workspace ignored`
|
|
141
|
+
- Se NÃO contém, adicionar:
|
|
164
142
|
```
|
|
165
143
|
# SFW: workspace ignored (external backend detected)
|
|
166
|
-
# Content lives in the external backend (Confluence, etc.) — local is just cache
|
|
167
144
|
workspace/Output/**
|
|
168
145
|
!workspace/Output/.gitkeep
|
|
169
146
|
```
|
|
170
|
-
- Informar ao usuário: "workspace/Output/ adicionado ao .gitignore (conteúdo vive no {adapter})"
|
|
171
147
|
|
|
172
|
-
Se o adapter É `filesystem
|
|
173
|
-
- Se `.gitignore` contém o bloco `# SFW: workspace ignored`, **removê-lo**
|
|
174
|
-
- Informar ao usuário: "workspace/Output/ removido do .gitignore (modo local)"
|
|
175
|
-
|
|
176
|
-
Isso garante que:
|
|
177
|
-
- Projetos com Confluence não commitam cache local
|
|
178
|
-
- Projetos que mudam de Confluence → filesystem voltam a rastrear
|
|
179
|
-
- A lógica roda no momento certo (após configurar `sfw.config.yml`, não no `init`)
|
|
148
|
+
Se o adapter É `filesystem` e o bloco existe, removê-lo.
|
|
180
149
|
|
|
181
150
|
### 6. Informar o usuário
|
|
182
151
|
|
|
152
|
+
**Para `/sf-load <nome>`:**
|
|
183
153
|
```
|
|
184
|
-
|
|
154
|
+
Scope "{nome}" carregado:
|
|
185
155
|
|
|
186
|
-
{N} arquivos ({X novos, Y modificados, Z inalterados})
|
|
187
|
-
{M}
|
|
156
|
+
Input: {N} arquivos ({X novos, Y modificados, Z inalterados})
|
|
157
|
+
Output: {M} artefatos ({A novos, B modificados, C inalterados})
|
|
158
|
+
ou "nenhum artefato publicado ainda"
|
|
188
159
|
|
|
189
160
|
Próximo passo:
|
|
190
|
-
/sf-new-project {nome} ←
|
|
191
|
-
/sf-feature {nome} ←
|
|
161
|
+
/sf-new-project {nome} ← bootstrap técnico (gera TRD)
|
|
162
|
+
/sf-feature {nome} ← feature (gera PRD)
|
|
163
|
+
|
|
164
|
+
Log: .ai/sf-load-log.md
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Para `/sf-load --all`:**
|
|
168
|
+
```
|
|
169
|
+
Projeto sincronizado:
|
|
170
|
+
|
|
171
|
+
Input: {N} scopes, {X} arquivos total
|
|
172
|
+
Output: {M} scopes, {Y} artefatos total
|
|
173
|
+
|
|
174
|
+
Scopes encontrados:
|
|
175
|
+
- app_barbearia (Input: 5 arquivos, Output: TRD + SDD + Progresso)
|
|
176
|
+
- feat_login (Input: 3 arquivos, Output: nenhum)
|
|
177
|
+
- feat_pagamento (Input: 2 arquivos, Output: PRD)
|
|
192
178
|
|
|
193
|
-
Log
|
|
179
|
+
Log: .ai/sf-load-log.md
|
|
194
180
|
```
|
|
195
181
|
|
|
196
182
|
## Notas
|
|
197
183
|
|
|
198
|
-
- `/sf-load` é **idempotente** — rodar N vezes
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
- **Estrutura local é FLAT** — não replica hierarquia do backend. Todos os arquivos soltos na mesma pasta
|
|
208
|
-
- **Recursão é total** — desce até o último nível. Se `get_page_children` retornou filhos, DESCER em cada um
|
|
184
|
+
- `/sf-load` é **idempotente** — rodar N vezes não muda nada se backend não mudou
|
|
185
|
+
- `/sf-load` **nunca modifica o backend** — só lê
|
|
186
|
+
- `/sf-load` **nunca deleta arquivos locais** — marca REMOVIDO no log mas mantém
|
|
187
|
+
- Attachments ficam flat junto com os .md
|
|
188
|
+
- **Estrutura local é FLAT** — não replica hierarquia do backend
|
|
189
|
+
- **Recursão é total** — desce até o último nível
|
|
190
|
+
- Nomes sanitizados: espaços → `_`, caracteres especiais removidos
|
|
191
|
+
- Output que não existe no backend é pulado silenciosamente (ainda não publicado)
|
|
192
|
+
- `/sf-load --all` é útil no início de sessão pra ter tudo atualizado
|
|
209
193
|
|
|
210
194
|
## Erros
|
|
211
195
|
|
|
212
196
|
| Erro | Ação |
|
|
213
197
|
|------|------|
|
|
214
|
-
| `sfw.config.yml` não existe | Parar
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
|
198
|
+
| `sfw.config.yml` não existe | Parar → orientar /sf-mcp ou setup manual |
|
|
199
|
+
| MCP não disponível | Parar → "Reinicie o Claude Code" |
|
|
200
|
+
| Scope não encontrado no Input | Parar, listar scopes disponíveis |
|
|
201
|
+
| Auth error (401/403) | Parar → "Verifique .mcp.json" |
|
|
202
|
+
| Page sem conteúdo | OK — salvar vazio, registrar no log |
|
|
203
|
+
| Output não tem container pro scope | OK — pular, informar "nenhum artefato publicado ainda" |
|
|
220
204
|
|
|
221
205
|
## Referências
|
|
222
206
|
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
# /sf-mcp <provider>
|
|
2
2
|
|
|
3
|
-
Setup interativo de backend externo. Pergunta os dados necessários e cria todos os arquivos de configuração.
|
|
3
|
+
Setup interativo de backend externo. Pergunta os dados necessários, descobre a estrutura do projeto e cria todos os arquivos de configuração.
|
|
4
4
|
|
|
5
5
|
## Providers disponíveis
|
|
6
6
|
|
|
7
7
|
| Provider | O que faz |
|
|
8
8
|
|----------|-----------|
|
|
9
|
-
| `confluence` | Configura MCP Atlassian + `sfw.config.yml` + `.mcp.json` + `.gitignore` |
|
|
10
|
-
|
|
11
|
-
Futuros: `notion`, `jira`, `filesystem` (não precisa de MCP, só cria `sfw.config.yml`).
|
|
9
|
+
| `confluence` | Configura MCP Atlassian + descobre projeto + cria `sfw.config.yml` + `.mcp.json` + `.gitignore` |
|
|
12
10
|
|
|
13
11
|
## Uso
|
|
14
12
|
|
|
15
13
|
```
|
|
16
14
|
/sf-mcp confluence
|
|
15
|
+
/sf-mcp confluence test ← só testa conexão
|
|
17
16
|
```
|
|
18
17
|
|
|
19
18
|
---
|
|
@@ -36,9 +35,9 @@ Depois rode /sf-mcp confluence novamente.
|
|
|
36
35
|
```
|
|
37
36
|
**Parar aqui** se uvx não estiver disponível.
|
|
38
37
|
|
|
39
|
-
### Passo 2 — Coletar
|
|
38
|
+
### Passo 2 — Coletar credenciais
|
|
40
39
|
|
|
41
|
-
Perguntar
|
|
40
|
+
Perguntar uma por uma:
|
|
42
41
|
|
|
43
42
|
```
|
|
44
43
|
Configurando Confluence para o SFW.
|
|
@@ -56,71 +55,133 @@ Configurando Confluence para o SFW.
|
|
|
56
55
|
>
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
### Passo 3 — Criar `.mcp.json`
|
|
59
|
+
|
|
60
|
+
Verificar se `.mcp.json` já existe:
|
|
61
|
+
- Se existe e já tem entrada `atlassian` → perguntar se quer atualizar
|
|
62
|
+
- Se existe sem `atlassian` → adicionar entrada
|
|
63
|
+
- Se não existe → criar
|
|
60
64
|
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"atlassian": {
|
|
69
|
+
"command": "uvx",
|
|
70
|
+
"args": ["mcp-atlassian"],
|
|
71
|
+
"env": {
|
|
72
|
+
"CONFLUENCE_URL": "{url}",
|
|
73
|
+
"CONFLUENCE_USERNAME": "{email}",
|
|
74
|
+
"CONFLUENCE_API_TOKEN": "{token}"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
61
79
|
```
|
|
62
|
-
|
|
80
|
+
|
|
81
|
+
**IMPORTANTE**: Credenciais hardcoded — `${VAR}` NÃO funciona no Claude Code.
|
|
82
|
+
|
|
83
|
+
### Passo 4 — Testar conexão e descobrir projeto
|
|
84
|
+
|
|
85
|
+
Testar chamando:
|
|
86
|
+
```
|
|
87
|
+
mcp__atlassian__confluence_search(query="space.key={space_key}", limit=5)
|
|
88
|
+
```
|
|
89
|
+
ou
|
|
90
|
+
```
|
|
91
|
+
mcp__atlassian__confluence_get_page_children(page_id=<root do space>)
|
|
63
92
|
```
|
|
64
93
|
|
|
65
|
-
**Se
|
|
94
|
+
**Se MCP não disponível** (primeira vez — `.mcp.json` acabou de ser criado):
|
|
66
95
|
```
|
|
67
|
-
|
|
68
|
-
>
|
|
96
|
+
.mcp.json criado. O Claude Code precisa ser reiniciado para carregar o MCP.
|
|
69
97
|
|
|
70
|
-
|
|
71
|
-
|
|
98
|
+
1. Reinicie o Claude Code (feche e abra)
|
|
99
|
+
2. Rode /sf-mcp confluence novamente — vou continuar de onde paramos
|
|
72
100
|
```
|
|
101
|
+
**Parar aqui.**
|
|
102
|
+
|
|
103
|
+
**Se MCP funcionar** — pedir o projeto:
|
|
73
104
|
|
|
74
|
-
**Se NÃO** — informar que serão criadas:
|
|
75
105
|
```
|
|
76
|
-
|
|
77
|
-
- {project.name} (raiz)
|
|
78
|
-
├── Input
|
|
79
|
-
└── Output
|
|
106
|
+
Conexão OK!
|
|
80
107
|
|
|
81
|
-
|
|
108
|
+
5. Qual é a page raiz do seu projeto no Confluence?
|
|
109
|
+
Cole o Page ID (número na URL) ou o título exato:
|
|
82
110
|
>
|
|
83
111
|
```
|
|
84
112
|
|
|
85
|
-
|
|
86
|
-
1. `mcp__atlassian__confluence_create_page` → page raiz com título informado
|
|
87
|
-
2. `mcp__atlassian__confluence_create_page` → page "Input" como filha da raiz
|
|
88
|
-
3. `mcp__atlassian__confluence_create_page` → page "Output" como filha da raiz
|
|
89
|
-
4. Anotar os 3 Page IDs retornados
|
|
113
|
+
### Passo 5 — Mapear a árvore do projeto
|
|
90
114
|
|
|
91
|
-
|
|
115
|
+
Após receber o Page ID ou título da raiz:
|
|
92
116
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
1. Chamar `mcp__atlassian__confluence_get_page` pra confirmar que existe
|
|
118
|
+
2. Chamar `mcp__atlassian__confluence_get_page_children` na raiz
|
|
119
|
+
3. Chamar recursivamente nos filhos pra mapear a árvore completa
|
|
96
120
|
|
|
97
|
-
|
|
121
|
+
Mostrar ao usuário:
|
|
98
122
|
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
123
|
+
```
|
|
124
|
+
Projeto: "Barbearia Digital" (page_id: 65708)
|
|
125
|
+
|
|
126
|
+
Estrutura encontrada:
|
|
127
|
+
├── Requisitos (page_id: 360668)
|
|
128
|
+
│ ├── App mobile (page_id: 294950)
|
|
129
|
+
│ └── Painel admin (page_id: 131084)
|
|
130
|
+
├── Documentação técnica (page_id: 294931)
|
|
131
|
+
├── Referências (page_id: 557057)
|
|
132
|
+
└── Decisões (page_id: 425998)
|
|
113
133
|
```
|
|
114
134
|
|
|
115
|
-
### Passo
|
|
135
|
+
### Passo 6 — Identificar Input e Output
|
|
116
136
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
Perguntar ao usuário:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
Preciso saber qual pasta contém os INSUMOS (Input) e onde devo PUBLICAR os artefatos (Output).
|
|
141
|
+
|
|
142
|
+
Qual dessas é o Input (onde estão os insumos do PM/PO)?
|
|
143
|
+
1. Requisitos (360668)
|
|
144
|
+
2. Documentação técnica (294931)
|
|
145
|
+
3. Referências (557057)
|
|
146
|
+
4. Decisões (425998)
|
|
147
|
+
5. Criar nova page "Input"
|
|
148
|
+
>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Após o user escolher Input:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
Qual dessas é o Output (onde publico TRD, SDD, Progresso)?
|
|
155
|
+
1. Documentação técnica (294931)
|
|
156
|
+
2. Referências (557057)
|
|
157
|
+
3. Decisões (425998)
|
|
158
|
+
4. Criar nova page "Output"
|
|
159
|
+
>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Se o user escolher "Criar nova"** → usar `mcp__atlassian__confluence_create_page` como filha da raiz.
|
|
163
|
+
|
|
164
|
+
### Passo 7 — Sugerir mapeamento de páginas úteis (opcional)
|
|
165
|
+
|
|
166
|
+
Se a árvore tem outras pages relevantes, sugerir:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
Encontrei outras páginas que podem ser úteis durante o desenvolvimento:
|
|
170
|
+
|
|
171
|
+
- "Referências" (557057) → posso consultar durante /sf-extract e /sf-design
|
|
172
|
+
- "Decisões" (425998) → posso consultar para ADRs no /sf-design
|
|
173
|
+
|
|
174
|
+
Quer que eu mapeie essas páginas como contexto adicional? (s/n)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Se sim, registrar no `sfw.config.yml` como `context_pages`.
|
|
178
|
+
|
|
179
|
+
### Passo 8 — Criar `sfw.config.yml`
|
|
120
180
|
|
|
121
181
|
```yaml
|
|
122
182
|
project:
|
|
123
|
-
name: "{
|
|
183
|
+
name: "{título da page raiz}"
|
|
184
|
+
root_page_id: "{page_id raiz}"
|
|
124
185
|
|
|
125
186
|
naming:
|
|
126
187
|
output_container: "out_{scope}"
|
|
@@ -130,7 +191,7 @@ input:
|
|
|
130
191
|
adapter: confluence
|
|
131
192
|
config:
|
|
132
193
|
space_key: "{space_key}"
|
|
133
|
-
parent_page_id: "{
|
|
194
|
+
parent_page_id: "{page_id escolhido como Input}"
|
|
134
195
|
recursive: true
|
|
135
196
|
include_attachments: true
|
|
136
197
|
cache:
|
|
@@ -144,94 +205,88 @@ output:
|
|
|
144
205
|
adapter: confluence
|
|
145
206
|
config:
|
|
146
207
|
space_key: "{space_key}"
|
|
147
|
-
parent_page_id: "{
|
|
208
|
+
parent_page_id: "{page_id escolhido como Output}"
|
|
148
209
|
publishes: [PRD, TRD, SDD, Progresso]
|
|
149
210
|
mode: auto
|
|
150
211
|
conflict_detection: version
|
|
151
212
|
approval_mechanism: label
|
|
152
213
|
approval_label: "sfw-approved"
|
|
214
|
+
|
|
215
|
+
# Pages de contexto adicional (consultadas pelo /sf-extract e /sf-design)
|
|
216
|
+
# context_pages:
|
|
217
|
+
# - id: "557057"
|
|
218
|
+
# title: "Referências"
|
|
219
|
+
# use_in: [extract, design]
|
|
220
|
+
# - id: "425998"
|
|
221
|
+
# title: "Decisões"
|
|
222
|
+
# use_in: [design]
|
|
153
223
|
```
|
|
154
224
|
|
|
155
|
-
### Passo
|
|
225
|
+
### Passo 9 — Ajustar `.gitignore`
|
|
156
226
|
|
|
157
|
-
|
|
158
|
-
- `.mcp.json`
|
|
159
|
-
- Bloco
|
|
227
|
+
Adicionar se não existem:
|
|
228
|
+
- `.mcp.json`
|
|
229
|
+
- Bloco workspace ignored:
|
|
160
230
|
```
|
|
161
231
|
# SFW: workspace ignored (external backend detected)
|
|
162
232
|
workspace/Output/**
|
|
163
233
|
!workspace/Output/.gitkeep
|
|
164
234
|
```
|
|
165
235
|
|
|
166
|
-
### Passo
|
|
236
|
+
### Passo 10 — Resumir
|
|
167
237
|
|
|
168
238
|
```
|
|
169
|
-
|
|
170
|
-
```
|
|
239
|
+
Confluence configurado!
|
|
171
240
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
**Se funcionar**:
|
|
178
|
-
```
|
|
179
|
-
Conexão OK! Confluence configurado com sucesso.
|
|
241
|
+
Projeto: {nome} ({page_id raiz})
|
|
242
|
+
Input: {título Input} ({page_id})
|
|
243
|
+
Output: {título Output} ({page_id})
|
|
180
244
|
|
|
181
|
-
Arquivos criados:
|
|
245
|
+
Arquivos criados/atualizados:
|
|
182
246
|
.mcp.json ← credenciais (gitignored)
|
|
183
247
|
sfw.config.yml ← configuração do projeto
|
|
184
|
-
.gitignore ← atualizado
|
|
248
|
+
.gitignore ← atualizado
|
|
185
249
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
2. Rode /sf-new-project <nome-da-page> ou /sf-feature <nome-da-page>
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**Se falhar** (MCP não disponível):
|
|
192
|
-
```
|
|
193
|
-
MCP não está disponível. Isso acontece porque o Claude Code precisa
|
|
194
|
-
ser reiniciado para carregar o .mcp.json que acabamos de criar.
|
|
195
|
-
|
|
196
|
-
Arquivos foram criados com sucesso:
|
|
197
|
-
.mcp.json ← credenciais
|
|
198
|
-
sfw.config.yml ← configuração
|
|
250
|
+
O projeto tem {N} scopes no Input:
|
|
251
|
+
- {lista dos filhos do Input}
|
|
199
252
|
|
|
200
253
|
Próximo passo:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
3. Depois: /sf-new-project <nome> ou /sf-feature <nome>
|
|
254
|
+
/sf-new-project <nome-do-scope> ← bootstrap técnico
|
|
255
|
+
/sf-feature <nome-do-scope> ← nova feature
|
|
204
256
|
```
|
|
205
257
|
|
|
206
|
-
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Subcomando: `/sf-mcp confluence test`
|
|
207
261
|
|
|
208
|
-
Apenas testa a conexão sem criar arquivos:
|
|
262
|
+
Apenas testa a conexão sem criar/modificar arquivos:
|
|
209
263
|
|
|
210
264
|
1. Verificar que `.mcp.json` existe
|
|
211
265
|
2. Verificar que `sfw.config.yml` existe e tem `adapter: confluence`
|
|
212
|
-
3. Chamar `mcp__atlassian__confluence_get_page_children(page_id={
|
|
213
|
-
4. Se OK → "Conexão OK! {N}
|
|
266
|
+
3. Chamar `mcp__atlassian__confluence_get_page_children(page_id={input.parent_page_id})`
|
|
267
|
+
4. Se OK → "Conexão OK! {N} scopes encontrados em Input: {lista}"
|
|
214
268
|
5. Se falha → orientar troubleshooting (ver `.github/adapters/SETUP.md`)
|
|
215
269
|
|
|
270
|
+
---
|
|
271
|
+
|
|
216
272
|
## Notas
|
|
217
273
|
|
|
218
274
|
- `.mcp.json` é SEMPRE gitignored — contém credenciais
|
|
219
275
|
- `sfw.config.yml` é commitável — zero segredos
|
|
220
|
-
- Após criar `.mcp.json`, Claude Code PRECISA ser reiniciado
|
|
221
|
-
-
|
|
222
|
-
-
|
|
276
|
+
- Após criar `.mcp.json`, Claude Code PRECISA ser reiniciado
|
|
277
|
+
- O framework conhece o projeto INTEIRO (raiz + toda a árvore), não só Input/Output
|
|
278
|
+
- `context_pages` permite que /sf-extract e /sf-design consultem páginas extras como referência
|
|
279
|
+
- Token Atlassian pode expirar — se der 401, gerar novo e atualizar `.mcp.json`
|
|
223
280
|
|
|
224
281
|
## Erros
|
|
225
282
|
|
|
226
283
|
| Erro | Ação |
|
|
227
284
|
|------|------|
|
|
228
285
|
| uvx não instalado | Parar, instruir instalação |
|
|
229
|
-
|
|
|
230
|
-
|
|
|
231
|
-
|
|
|
232
|
-
|
|
|
233
|
-
| MCP não disponível após criar | Normal — pedir reinício do Claude Code |
|
|
234
|
-
| Create page falhou (403) | Usuário sem permissão de escrita no space |
|
|
286
|
+
| MCP não disponível | Pedir reinício do Claude Code |
|
|
287
|
+
| Page raiz não encontrada | Pedir ID/título correto |
|
|
288
|
+
| Sem permissão de escrita | Informar, pedir ao admin |
|
|
289
|
+
| Space key errado | Listar spaces disponíveis se possível |
|
|
235
290
|
|
|
236
291
|
## Referências
|
|
237
292
|
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
# ----------------------------------------------------------------------------
|
|
24
24
|
project:
|
|
25
25
|
name: "Meu Projeto"
|
|
26
|
+
# Page ID raiz do projeto no Confluence (o framework conhece o projeto inteiro)
|
|
27
|
+
# root_page_id: "65708"
|
|
26
28
|
|
|
27
29
|
# ----------------------------------------------------------------------------
|
|
28
30
|
# naming — templates de nome (aplicados pela engine em .github/adapters/naming.md)
|
|
@@ -129,3 +131,17 @@ output:
|
|
|
129
131
|
# mode: auto
|
|
130
132
|
# conflict_detection: hash
|
|
131
133
|
# approval_mechanism: none
|
|
134
|
+
|
|
135
|
+
# ----------------------------------------------------------------------------
|
|
136
|
+
# context_pages — páginas extras que o framework pode consultar (opcional)
|
|
137
|
+
# ----------------------------------------------------------------------------
|
|
138
|
+
# O /mcp descobre a árvore do projeto e sugere pages que podem ser úteis
|
|
139
|
+
# como contexto durante /extract e /design (referências, decisões, etc.)
|
|
140
|
+
#
|
|
141
|
+
# context_pages:
|
|
142
|
+
# - id: "557057"
|
|
143
|
+
# title: "Referências"
|
|
144
|
+
# use_in: [extract, design]
|
|
145
|
+
# - id: "425998"
|
|
146
|
+
# title: "Decisões"
|
|
147
|
+
# use_in: [design]
|