spec-first-copilot 0.5.0-beta.13 → 0.5.0-beta.15

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/lib/update.js CHANGED
@@ -37,9 +37,6 @@ function update({ templatesDir, targetDir, force }) {
37
37
  const stats = { added: [], updated: [], skipped: 0 };
38
38
  syncDir(templatesDir, dest, force, stats, dest);
39
39
 
40
- // Auto-configure .gitignore based on sfw.config.yml (before printing results)
41
- adjustGitignore(dest, stats);
42
-
43
40
  console.log('');
44
41
  if (stats.added.length > 0) {
45
42
  console.log(`Added (${stats.added.length}):`);
@@ -132,37 +129,4 @@ function isFrameworkPath(rel) {
132
129
  return false;
133
130
  }
134
131
 
135
- const WORKSPACE_IGNORE_MARKER = '# SFW: workspace ignored (external backend detected)';
136
- const WORKSPACE_IGNORE_BLOCK = `
137
- ${WORKSPACE_IGNORE_MARKER}
138
- # Content lives in the external backend (Confluence, etc.) — local is just cache
139
- workspace/Output/**
140
- !workspace/Output/.gitkeep
141
- `;
142
-
143
- function adjustGitignore(dest, stats) {
144
- const configPath = path.join(dest, 'sfw.config.yml');
145
- const gitignorePath = path.join(dest, '.gitignore');
146
-
147
- if (!fs.existsSync(configPath) || !fs.existsSync(gitignorePath)) return;
148
-
149
- const config = fs.readFileSync(configPath, 'utf-8');
150
- const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
151
-
152
- const inputMatch = config.match(/^\s*adapter:\s*(\S+)/m);
153
- const inputAdapter = inputMatch ? inputMatch[1] : 'filesystem';
154
- const isExternal = inputAdapter !== 'filesystem';
155
-
156
- const alreadyHasBlock = gitignore.includes(WORKSPACE_IGNORE_MARKER);
157
-
158
- if (isExternal && !alreadyHasBlock) {
159
- fs.appendFileSync(gitignorePath, WORKSPACE_IGNORE_BLOCK);
160
- stats.updated.push('.gitignore (workspace ignored — external backend)');
161
- } else if (!isExternal && alreadyHasBlock) {
162
- const cleaned = gitignore.split(WORKSPACE_IGNORE_MARKER)[0].trimEnd() + '\n';
163
- fs.writeFileSync(gitignorePath, cleaned, 'utf-8');
164
- stats.updated.push('.gitignore (workspace restored — local mode)');
165
- }
166
- }
167
-
168
132
  module.exports = { update };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spec-first-copilot",
3
- "version": "0.5.0-beta.13",
3
+ "version": "0.5.0-beta.15",
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"
@@ -20,10 +20,11 @@
20
20
 
21
21
  ### 2. Validar acesso a todas skills
22
22
 
23
- Verificar que TODAS as 10 skills estão acessíveis:
23
+ Verificar que TODAS as 11 skills estão acessíveis:
24
24
 
25
25
  | Skill | Caminho |
26
26
  |-------|---------|
27
+ | `/sf-mcp` | `.github/skills/sf-mcp/SKILL.md` |
27
28
  | `/sf-load` | `.github/skills/sf-load/SKILL.md` |
28
29
  | `/sf-new-project` | `.github/skills/sf-new-project/SKILL.md` |
29
30
  | `/sf-feature` | `.github/skills/sf-feature/SKILL.md` |
@@ -96,6 +97,7 @@ Nenhum código é escrito sem especificação aprovada (SDD).
96
97
 
97
98
  | Skill | Tipo | O que faz |
98
99
  |-------|------|-----------|
100
+ | `/sf-mcp <provider>` | Setup | Configura backend externo interativamente. Cria .mcp.json + sfw.config.yml + ajusta .gitignore |
99
101
  | `/sf-load <nome>` | Utilitária | Puxa insumos do backend (Confluence/filesystem) para workspace/Input/{nome}/. Incremental |
100
102
  | `/sf-new-project <nome>` | Orquestrador | Bootstrap técnico: cria .context.md tipo TRD, chama /sf-extract, para no checkpoint |
101
103
  | `/sf-feature <nome>` | Orquestrador | Feature: cria .context.md tipo PRD, chama /sf-extract, para no checkpoint |
@@ -156,7 +156,29 @@ Formato append-only:
156
156
  - Se não existia no log → status `NOVO`
157
157
  - Arquivo que existia no log mas sumiu do backend → status `REMOVIDO` (log only, não deleta local)
158
158
 
159
- ### 5. Informar o usuário
159
+ ### 5. Ajustar `.gitignore` conforme o adapter
160
+
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`:
164
+ ```
165
+ # SFW: workspace ignored (external backend detected)
166
+ # Content lives in the external backend (Confluence, etc.) — local is just cache
167
+ workspace/Output/**
168
+ !workspace/Output/.gitkeep
169
+ ```
170
+ - Informar ao usuário: "workspace/Output/ adicionado ao .gitignore (conteúdo vive no {adapter})"
171
+
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`)
180
+
181
+ ### 6. Informar o usuário
160
182
 
161
183
  ```
162
184
  Insumos carregados em workspace/Input/{nome}/
@@ -0,0 +1,240 @@
1
+ # /sf-mcp <provider>
2
+
3
+ Setup interativo de backend externo. Pergunta os dados necessários e cria todos os arquivos de configuração.
4
+
5
+ ## Providers disponíveis
6
+
7
+ | Provider | O que faz |
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`).
12
+
13
+ ## Uso
14
+
15
+ ```
16
+ /sf-mcp confluence
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Provider: Confluence
22
+
23
+ ### Passo 1 — Verificar pré-requisitos
24
+
25
+ Verificar se `uvx` está instalado:
26
+ ```bash
27
+ uvx --version
28
+ ```
29
+
30
+ Se NÃO está instalado:
31
+ ```
32
+ uvx não encontrado. Instale com:
33
+ pip install uv
34
+
35
+ Depois rode /sf-mcp confluence novamente.
36
+ ```
37
+ **Parar aqui** se uvx não estiver disponível.
38
+
39
+ ### Passo 2 — Coletar dados do usuário
40
+
41
+ Perguntar um por um, com explicação curta:
42
+
43
+ ```
44
+ Configurando Confluence para o SFW.
45
+
46
+ 1. URL do Confluence (ex: https://sua-empresa.atlassian.net/wiki):
47
+ >
48
+
49
+ 2. Email da conta Atlassian (ex: dev@empresa.com):
50
+ >
51
+
52
+ 3. API Token (gere em https://id.atlassian.com/manage-profile/security/api-tokens):
53
+ >
54
+
55
+ 4. Space Key (as letras na URL: /wiki/spaces/XX/...):
56
+ >
57
+ ```
58
+
59
+ Após coletar os 4 dados, perguntar sobre a estrutura no Confluence:
60
+
61
+ ```
62
+ 5. Você já tem pages Input e Output criadas no Confluence? (s/n)
63
+ ```
64
+
65
+ **Se SIM** — pedir os Page IDs:
66
+ ```
67
+ Page ID da page Input (o número na URL /pages/XXXXX/...):
68
+ >
69
+
70
+ Page ID da page Output:
71
+ >
72
+ ```
73
+
74
+ **Se NÃO** — informar que serão criadas:
75
+ ```
76
+ Vou criar a estrutura no Confluence:
77
+ - {project.name} (raiz)
78
+ ├── Input
79
+ └── Output
80
+
81
+ Nome do projeto pra page raiz (ex: Meu Projeto):
82
+ >
83
+ ```
84
+
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
90
+
91
+ ### Passo 3 — Criar `.mcp.json`
92
+
93
+ Verificar se `.mcp.json` já existe:
94
+ - Se existe → perguntar se quer sobrescrever ou adicionar entrada
95
+ - Se não existe → criar
96
+
97
+ Conteúdo (credenciais hardcoded — `${VAR}` NÃO funciona no Claude Code):
98
+
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
+ }
113
+ ```
114
+
115
+ ### Passo 4 — Criar `sfw.config.yml`
116
+
117
+ Verificar se já existe:
118
+ - Se existe → perguntar se quer sobrescrever
119
+ - Se não existe → criar
120
+
121
+ ```yaml
122
+ project:
123
+ name: "{nome do projeto}"
124
+
125
+ naming:
126
+ output_container: "out_{scope}"
127
+ output_artifact: "{scope} - {type}"
128
+
129
+ input:
130
+ adapter: confluence
131
+ config:
132
+ space_key: "{space_key}"
133
+ parent_page_id: "{page_id_input}"
134
+ recursive: true
135
+ include_attachments: true
136
+ cache:
137
+ local_dir: "workspace/Input/"
138
+ log: ".ai/load-log.md"
139
+ incremental: true
140
+
141
+ output:
142
+ targets:
143
+ - name: confluence-mirror
144
+ adapter: confluence
145
+ config:
146
+ space_key: "{space_key}"
147
+ parent_page_id: "{page_id_output}"
148
+ publishes: [PRD, TRD, SDD, Progresso]
149
+ mode: auto
150
+ conflict_detection: version
151
+ approval_mechanism: label
152
+ approval_label: "sfw-approved"
153
+ ```
154
+
155
+ ### Passo 5 — Ajustar `.gitignore`
156
+
157
+ Verificar que `.gitignore` contém:
158
+ - `.mcp.json` — se não, adicionar
159
+ - Bloco `# SFW: workspace ignored` — se não, adicionar:
160
+ ```
161
+ # SFW: workspace ignored (external backend detected)
162
+ workspace/Output/**
163
+ !workspace/Output/.gitkeep
164
+ ```
165
+
166
+ ### Passo 6 — Testar conexão
167
+
168
+ ```
169
+ Testando conexão com o Confluence...
170
+ ```
171
+
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.
180
+
181
+ Arquivos criados:
182
+ .mcp.json ← credenciais (gitignored)
183
+ sfw.config.yml ← configuração do projeto
184
+ .gitignore ← atualizado (workspace ignorado)
185
+
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
199
+
200
+ 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>
204
+ ```
205
+
206
+ ### Subcomando: `/sf-mcp confluence test`
207
+
208
+ Apenas testa a conexão sem criar arquivos:
209
+
210
+ 1. Verificar que `.mcp.json` existe
211
+ 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"
214
+ 5. Se falha → orientar troubleshooting (ver `.github/adapters/SETUP.md`)
215
+
216
+ ## Notas
217
+
218
+ - `.mcp.json` é SEMPRE gitignored — contém credenciais
219
+ - `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 já 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`
223
+
224
+ ## Erros
225
+
226
+ | Erro | Ação |
227
+ |------|------|
228
+ | 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 |
235
+
236
+ ## Referências
237
+
238
+ - Setup guide completo: `.github/adapters/SETUP.md`
239
+ - Confluence adapter: `.github/adapters/confluence.md`
240
+ - Interface do adapter: `.github/adapters/interface.md`