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,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-first-copilot",
3
- "version": "0.5.0-beta.15",
3
+ "version": "0.5.0-beta.17",
4
4
  "description": "Spec-first workflow kit for GitHub Copilot — AI-driven development with specs, not guesswork",
5
5
  "bin": {
6
6
  "spec-first-copilot": "bin/cli.js"
@@ -1,134 +1,110 @@
1
- # /sf-load <nome>
1
+ # /sf-load <nome> | --all
2
2
 
3
- Puxa os insumos de um scope do backend configurado (Confluence, filesystem, etc.)
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
- ## Argumento
5
+ ## Modos
7
6
 
8
- `<nome>` = nome do item no backend de input (título da page no Confluence,
9
- nome da pasta no filesystem). Match exato — se não encontrar, para com erro.
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 <nome>` ou `/sf-feature <nome>`** para trazer
14
- insumos que o PM publicou no Confluence (ou outro backend)
15
- - **Após o PM adicionar novos insumos** (ex: `ajustes_v1` como page filha)
16
- para re-sincronizar. O log incremental detecta NOVO/MODIFICADO/INALTERADO
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 → "Copie sfw.config.yml.example para sfw.config.yml e configure. Veja .github/adapters/SETUP.md" |
24
- | 2 | `sfw.config.yml` tem seção `input` com `adapter` e `config` | Parar → "Seção input não encontrada no sfw.config.yml" |
25
- | 3 | Adapter do input está acessível (MCP rodando pra Confluence, pasta existe pra filesystem) | Parar → orientar setup conforme `.github/adapters/SETUP.md` |
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` tipo do adapter (`confluence` ou `filesystem`)
33
- - `input.config` — config específica do adapter
34
- - `input.cache.local_dir` — onde materializar (default: `workspace/Input/`)
35
- - `input.cache.log` — arquivo de log (default: `.ai/sf-load-log.md`)
36
- - `input.cache.incremental` — se compara hashes antes de sobrescrever
37
- - `naming.output_container` — template pra nomear a pasta local (usa `{scope}`)
38
-
39
- ### 2. Buscar o scope no backend
40
-
41
- **Para Confluence** (`adapter: confluence`):
42
-
43
- ```
44
- 1. Chamar mcp__atlassian__confluence_get_page_children
45
- com page_id = config.parent_page_id
46
- 2. Na lista de filhos, buscar o que tem title == {nome} (match exato)
47
- 3. Se não encontrou → ERRO: "Scope '{nome}' não encontrado no Confluence
48
- (parent_page_id: {id}). Verifique se a page existe como filha de Input."
49
- 4. Anotar scope_id = page.id
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** — se uma page tem filhas, e as filhas têm netas, TODAS devem ser trazidas. `get_page_children` retorna só 1 nível o agent DEVE fazer loop recursivo.
65
- > 2. **Local é flat** — todos os arquivos ficam soltos em `workspace/Input/{nome}/`, SEM subpastas por nível. A hierarquia do Confluence NÃO é replicada localmente.
66
- > 3. **Refletir 100% do externo** — tudo que existe no backend (pages, attachments) DEVE existir em `workspace/Input/{nome}/`. Se falta algo, o `/sf-load` está errado.
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 Confluence**:
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} // ← FLAT, sem subpastas
81
- registrar no load-log: page.id, page.title, page.version, sha256(content), filename
76
+ salvar content em {targetDir}/{filename}
77
+ registrar no load-log
82
78
 
83
- // PASSO 3: Baixar attachments de CADA page (se include_attachments=true)
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 em attachments:
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} // ← FLAT junto com os .md
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 em children:
95
- result.push(child) // adiciona o filho
96
- collectAllPages(child.id, result) // desce nos netos, bisnetos, etc.
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
- **Resultado local em `workspace/Input/app_barbearia/` — TUDO FLAT:**
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
- **Nenhuma subpasta.** Não importa quantos níveis a árvore do Confluence tem — local é flat.
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 (input já é local)
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 funcionais | 2 | 8b1c... | workspace/Input/app_barbearia/requisitos_funcionais.md | NOVO |
145
- | 491573 | Regras de negocio | 1 | 4d2a... | workspace/Input/app_barbearia/regras_de_negocio.md | NOVO |
146
- | 491574 | Neta da pagina | 1 | 7f3e... | workspace/Input/app_barbearia/neta_da_pagina.md | NOVO |
147
- | 491575 | Jornadas | 1 | 9c5b... | workspace/Input/app_barbearia/jornadas.md | NOVO |
148
- | 491576 | Stack tecnica | 1 | 2e8d... | workspace/Input/app_barbearia/stack_tecnica.md | NOVO |
149
- | att:diagrama.png | diagrama.png | | 7d2e... | workspace/Input/app_barbearia/diagrama.png | NOVO |
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
- - Antes de baixar, comparar hash atual com hash no log anterior
154
- - Se hash idêntico → status `INALTERADO`, não sobrescrever
155
- - Se hash diferente → status `MODIFICADO`, sobrescrever
156
- - Se não existia no log → status `NOVO`
157
- - Arquivo que existia no log mas sumiu do backend → status `REMOVIDO` (log only, não deleta local)
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` (ou seja, é um backend externo como Confluence):
162
- - Verificar se `.gitignore` contém o bloco `# SFW: workspace ignored`
163
- - Se NÃO contém, **adicionar** ao final do `.gitignore`:
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
- Insumos carregados em workspace/Input/{nome}/
154
+ Scope "{nome}" carregado:
185
155
 
186
- {N} arquivos ({X novos, Y modificados, Z inalterados})
187
- {M} attachments
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} ← se é bootstrap técnico (gera TRD)
191
- /sf-feature {nome} ← se é feature (gera PRD)
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 salvo em .ai/sf-load-log.md
179
+ Log: .ai/sf-load-log.md
194
180
  ```
195
181
 
196
182
  ## Notas
197
183
 
198
- - `/sf-load` é **idempotente** — rodar N vezes com mesmos insumos no backend
199
- não muda nada (hashes batem, status = INALTERADO)
200
- - Se o PM adicionar page `ajustes_v1` como filha do scope no Confluence,
201
- re-rodar `/sf-load {nome}` traz como NOVO automaticamente
202
- - O `/sf-load` **nunca modifica o backend** —
203
- - O `/sf-load` **nunca deleta arquivos locais** — se algo sumiu do backend,
204
- marca como REMOVIDO no log mas mantém o arquivo local
205
- - Attachments ficam flat junto com os .md (sem subpasta `attachments/`)
206
- - Nomes de arquivo são sanitizados: espaços `_`, caracteres especiais removidos
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, orientar setup |
215
- | Adapter não configurado | Parar, apontar pra SETUP.md |
216
- | MCP não disponível (Confluence) | Parar "Reinicie o Claude Code. MCP carrega no startup" |
217
- | Scope não encontrado no backend | Parar, listar scopes disponíveis se possível |
218
- | Auth error (401/403) | Parar "Verifique credenciais no .mcp.json" |
219
- | Page sem conteúdo | OK — salvar arquivo vazio, registrar no log |
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 dados do usuário
38
+ ### Passo 2 — Coletar credenciais
40
39
 
41
- Perguntar um por um, com explicação curta:
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
- Após coletar os 4 dados, perguntar sobre a estrutura no Confluence:
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
- 5. Você já tem pages Input e Output criadas no Confluence? (s/n)
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 SIM** — pedir os Page IDs:
94
+ **Se MCP não disponível** (primeira vez `.mcp.json` acabou de ser criado):
66
95
  ```
67
- Page ID da page Input (o número na URL /pages/XXXXX/...):
68
- >
96
+ .mcp.json criado. O Claude Code precisa ser reiniciado para carregar o MCP.
69
97
 
70
- Page ID da page Output:
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
- Vou criar a estrutura no Confluence:
77
- - {project.name} (raiz)
78
- ├── Input
79
- └── Output
106
+ Conexão OK!
80
107
 
81
- Nome do projeto pra page raiz (ex: Meu Projeto):
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
- Então usar MCP pra criar:
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
- ### Passo 3 Criar `.mcp.json`
115
+ Após receber o Page ID ou título da raiz:
92
116
 
93
- Verificar se `.mcp.json` existe:
94
- - Se existe perguntar se quer sobrescrever ou adicionar entrada
95
- - Se não existe criar
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
- Conteúdo (credenciais hardcoded — `${VAR}` NÃO funciona no Claude Code):
121
+ Mostrar ao usuário:
98
122
 
99
- ```json
100
- {
101
- "mcpServers": {
102
- "atlassian": {
103
- "command": "uvx",
104
- "args": ["mcp-atlassian"],
105
- "env": {
106
- "CONFLUENCE_URL": "{url informada}",
107
- "CONFLUENCE_USERNAME": "{email informado}",
108
- "CONFLUENCE_API_TOKEN": "{token informado}"
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 4Criar `sfw.config.yml`
135
+ ### Passo 6Identificar Input e Output
116
136
 
117
- Verificar se já existe:
118
- - Se existe → perguntar se quer sobrescrever
119
- - Se não existe → criar
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: "{nome do projeto}"
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: "{page_id_input}"
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: "{page_id_output}"
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 5 — Ajustar `.gitignore`
225
+ ### Passo 9 — Ajustar `.gitignore`
156
226
 
157
- Verificar que `.gitignore` contém:
158
- - `.mcp.json` — se não, adicionar
159
- - Bloco `# SFW: workspace ignored` — se não, adicionar:
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 6Testar conexão
236
+ ### Passo 10Resumir
167
237
 
168
238
  ```
169
- Testando conexão com o Confluence...
170
- ```
239
+ Confluence configurado!
171
240
 
172
- Chamar:
173
- ```
174
- mcp__atlassian__confluence_get_page_children(page_id={page_id_input})
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 (workspace ignorado)
248
+ .gitignore ← atualizado
185
249
 
186
- Próximo passo:
187
- 1. Crie pages de insumo como filhas de Input no Confluence
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
- 1. Reinicie o Claude Code (feche e abra novamente)
202
- 2. Rode /sf-mcp confluence test para verificar a conexão
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
- ### Subcomando: `/sf-mcp confluence test`
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={page_id_input})`
213
- 4. Se OK → "Conexão OK! {N} pages encontradas em Input"
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 pra carregar o MCP
221
- - Se o user tem `.mcp.json` com outras entradas, o comando ADICIONA a entrada `atlassian` sem apagar as existentes
222
- - Token da Atlassian pode expirar se der 401 depois de um tempo, gerar novo token e atualizar `.mcp.json`
276
+ - Após criar `.mcp.json`, Claude Code PRECISA ser reiniciado
277
+ - O framework conhece o projeto INTEIRO (raiz + toda a árvore), não 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
- | URL inválida | Pedir novamente |
230
- | Token vazio | Pedir novamente, linkar página de geração |
231
- | Space key não encontrado | Pedir novamente, sugerir como descobrir |
232
- | Page ID inválido | Pedir novamente, sugerir como descobrir |
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]