spec-first-copilot 0.5.0-beta.0 → 0.5.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +9 -3
  2. package/bin/cli.js +23 -5
  3. package/lib/init.js +2 -2
  4. package/lib/update.js +130 -0
  5. package/package.json +1 -1
  6. package/templates/.github/CHANGELOG.md +112 -0
  7. package/templates/.github/adapters/SETUP.md +314 -0
  8. package/templates/.github/adapters/confluence.md +295 -0
  9. package/templates/.github/adapters/errors.md +234 -0
  10. package/templates/.github/adapters/filesystem.md +353 -0
  11. package/templates/.github/adapters/interface.md +301 -0
  12. package/templates/.github/adapters/naming.md +241 -0
  13. package/templates/.github/adapters/registry.md +244 -0
  14. package/templates/.github/agents/backend-coder.md +215 -215
  15. package/templates/.github/agents/db-coder.md +165 -165
  16. package/templates/.github/agents/frontend-coder.md +222 -222
  17. package/templates/.github/agents/infra-coder.md +341 -341
  18. package/templates/.github/agents/reviewer.md +99 -99
  19. package/templates/.github/agents/security-reviewer.md +153 -153
  20. package/templates/.github/copilot-instructions.md +221 -194
  21. package/templates/.github/instructions/docs.instructions.md +123 -123
  22. package/templates/.github/instructions/sensitive-files.instructions.md +32 -32
  23. package/templates/.github/skills/sf-design/SKILL.md +209 -180
  24. package/templates/.github/skills/sf-dev/SKILL.md +354 -349
  25. package/templates/.github/skills/sf-feature/SKILL.md +60 -86
  26. package/templates/.github/skills/sf-load/SKILL.md +205 -0
  27. package/templates/.github/skills/sf-new-project/SKILL.md +102 -0
  28. package/templates/.github/skills/sf-plan/SKILL.md +180 -178
  29. package/templates/.github/templates/feature/PRD.template.md +256 -256
  30. package/templates/.github/templates/feature/Progresso.template.md +136 -136
  31. package/templates/.github/templates/specs/brief.template.md +47 -0
  32. package/templates/.github/templates/specs/contracts.template.md +82 -0
  33. package/templates/.github/templates/specs/scenarios.template.md +79 -0
  34. package/templates/.github/templates/specs/tasks.template.md +61 -0
  35. package/templates/sfw.config.yml.example +131 -0
  36. package/templates/.github/skills/sf-setup-projeto/SKILL.md +0 -123
  37. package/templates/.github/templates/feature/tasks.template.md +0 -115
  38. package/templates/workspace/Input/setup_projeto/.gitkeep +0 -0
  39. /package/templates/{docs → specs}/.gitkeep +0 -0
package/README.md CHANGED
@@ -77,11 +77,17 @@ MeuProjeto/
77
77
  │ ├── domain.md <- Visao de negocio + modelo de dados
78
78
  │ ├── conventions.md <- Auth, authz, LGPD, env vars, monitoramento
79
79
  │ ├── apiContracts.md <- Rotas, paginacao, erros, catalogo de endpoints
80
- └── decisions.md <- ADRs
81
- ├── workspace/ <- TEAM CONTENT (futuro wiki)
80
+ ├── decisions.md <- ADRs
81
+ │ └── specs/ <- Especs por feature (projecoes do SDD, pro agent)
82
+ │ └── {nome}/
83
+ │ ├── brief.md <- Problema/Solucao
84
+ │ ├── contracts.md <- Dados/API/Integracoes
85
+ │ ├── scenarios.md <- Fluxos/UI/CAs
86
+ │ └── tasks.md <- Tabela unica com coluna Area
87
+ ├── workspace/ <- TEAM CONTENT (futuro wiki)
82
88
  │ ├── Input/ <- Jogue seus insumos aqui
83
89
  │ │ └── setup_projeto/ <- Insumos do bootstrap
84
- │ └── Output/ <- Docs por feature (gerados)
90
+ │ └── Output/ <- Docs narrativos pro humano (PRD, TRD, SDD, Progresso)
85
91
  └── .gitignore
86
92
  ```
87
93
 
package/bin/cli.js CHANGED
@@ -2,26 +2,35 @@
2
2
 
3
3
  const path = require('path');
4
4
  const { init } = require('../lib/init');
5
+ const { update } = require('../lib/update');
5
6
 
6
7
  const args = process.argv.slice(2);
7
8
  const command = args[0];
8
9
 
9
10
  function printUsage() {
10
- console.log('Usage: spec-first-copilot init --name=<project-name> [--target=<path>]');
11
+ console.log('Usage:');
12
+ console.log(' spec-first-copilot init --name=<project-name> [--target=<path>]');
13
+ console.log(' spec-first-copilot update [--target=<path>] [--force]');
11
14
  console.log('');
12
- console.log('Creates a new spec-first project configured for GitHub Copilot.');
15
+ console.log('Commands:');
16
+ console.log(' init Create a new spec-first project');
17
+ console.log(' update Update an existing project with new framework files');
18
+ console.log(' (adds missing files, updates framework files like skills/adapters/agents)');
13
19
  console.log('');
14
20
  console.log('Options:');
15
- console.log(' --name=<name> Project name (required)');
16
- console.log(' --target=<path> Target directory (defaults to ./<name>)');
21
+ console.log(' --name=<name> Project name (required for init)');
22
+ console.log(' --target=<path> Target directory (defaults to ./<name> for init, cwd for update)');
23
+ console.log(' --force Force update all files, not just framework files (use with caution)');
17
24
  }
18
25
 
19
26
  function parseArgs(args) {
20
- const parsed = {};
27
+ const parsed = { flags: [] };
21
28
  for (const arg of args) {
22
29
  const match = arg.match(/^--(\w+)=(.+)$/);
23
30
  if (match) {
24
31
  parsed[match[1]] = match[2];
32
+ } else if (arg.startsWith('--')) {
33
+ parsed.flags.push(arg.slice(2));
25
34
  }
26
35
  }
27
36
  return parsed;
@@ -43,6 +52,15 @@ if (command === 'init') {
43
52
  templatesDir,
44
53
  targetDir: opts.target || undefined,
45
54
  });
55
+ } else if (command === 'update') {
56
+ const opts = parseArgs(args.slice(1));
57
+ const templatesDir = path.join(__dirname, '..', 'templates');
58
+
59
+ update({
60
+ templatesDir,
61
+ targetDir: opts.target || undefined,
62
+ force: opts.flags.includes('force'),
63
+ });
46
64
  } else {
47
65
  printUsage();
48
66
  if (command) {
package/lib/init.js CHANGED
@@ -62,8 +62,8 @@ function init({ name, templatesDir, targetDir }) {
62
62
  console.log(`\nDone! Project "${name}" is ready.`);
63
63
  console.log('\nNext steps:');
64
64
  console.log(` 1. cd ${name}`);
65
- console.log(' 2. Add your input files to workspace/Input/setup_projeto/');
66
- console.log(' 3. Run /sf-setup-projeto to start the pipeline');
65
+ console.log(' 2. Create a folder in workspace/Input/ with your project files (e.g. workspace/Input/my_app/)');
66
+ console.log(' 3. Run /sf-new-project <folder-name> to start the pipeline');
67
67
  console.log('');
68
68
  }
69
69
 
package/lib/update.js ADDED
@@ -0,0 +1,130 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const FRAMEWORK_DIRS = [
5
+ path.join('.github', 'adapters'),
6
+ path.join('.github', 'skills'),
7
+ path.join('.github', 'agents'),
8
+ path.join('.github', 'templates'),
9
+ path.join('.github', 'instructions'),
10
+ ];
11
+
12
+ const FRAMEWORK_FILES = [
13
+ path.join('.github', 'rules.md'),
14
+ path.join('.github', 'copilot-instructions.md'),
15
+ path.join('.github', 'CHANGELOG.md'),
16
+ 'sfw.config.yml.example',
17
+ ];
18
+
19
+ function update({ templatesDir, targetDir, force }) {
20
+ const dest = targetDir || process.cwd();
21
+
22
+ if (!fs.existsSync(dest)) {
23
+ console.error(`Error: directory "${dest}" does not exist.`);
24
+ console.error('Run "spec-first-copilot init --name=<name>" first to create a project.');
25
+ process.exit(1);
26
+ }
27
+
28
+ const githubDir = path.join(dest, '.github');
29
+ if (!fs.existsSync(githubDir)) {
30
+ console.error('Error: not a spec-first project (missing .github/ directory).');
31
+ console.error('Run "spec-first-copilot init --name=<name>" first.');
32
+ process.exit(1);
33
+ }
34
+
35
+ console.log(`\nUpdating project in ${dest}\n`);
36
+
37
+ const stats = { added: [], updated: [], skipped: 0 };
38
+ syncDir(templatesDir, dest, force, stats, dest);
39
+
40
+ console.log('');
41
+ if (stats.added.length > 0) {
42
+ console.log(`Added (${stats.added.length}):`);
43
+ for (const f of stats.added) console.log(` + ${f}`);
44
+ }
45
+ if (stats.updated.length > 0) {
46
+ console.log(`Updated (${stats.updated.length}):`);
47
+ for (const f of stats.updated) console.log(` ~ ${f}`);
48
+ }
49
+ if (stats.added.length === 0 && stats.updated.length === 0) {
50
+ console.log('Already up to date — no new files to add.');
51
+ } else {
52
+ console.log(`\n${stats.added.length} added, ${stats.updated.length} updated, ${stats.skipped} unchanged`);
53
+ }
54
+ console.log('');
55
+ }
56
+
57
+ function syncDir(src, dest, force, stats, root) {
58
+ fs.mkdirSync(dest, { recursive: true });
59
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
60
+ const srcPath = path.join(src, entry.name);
61
+ const destPath = path.join(dest, entry.name);
62
+ if (entry.isDirectory()) {
63
+ syncDir(srcPath, destPath, force, stats, root);
64
+ } else {
65
+ syncFile(srcPath, destPath, force, stats, root);
66
+ }
67
+ }
68
+ }
69
+
70
+ function syncFile(src, dest, force, stats, root) {
71
+ const rel = path.relative(root, dest);
72
+ const exists = fs.existsSync(dest);
73
+
74
+ if (exists && !force) {
75
+ const isFramework = isFrameworkPath(rel);
76
+ if (!isFramework) {
77
+ stats.skipped++;
78
+ return;
79
+ }
80
+ const srcContent = fs.readFileSync(src, 'utf-8');
81
+ const destContent = fs.readFileSync(dest, 'utf-8');
82
+ if (srcContent === destContent) {
83
+ stats.skipped++;
84
+ return;
85
+ }
86
+ fs.writeFileSync(dest, srcContent, 'utf-8');
87
+ stats.updated.push(rel);
88
+ return;
89
+ }
90
+
91
+ if (exists && force) {
92
+ const srcContent = fs.readFileSync(src, 'utf-8');
93
+ const destContent = fs.readFileSync(dest, 'utf-8');
94
+ if (srcContent === destContent) {
95
+ stats.skipped++;
96
+ return;
97
+ }
98
+ fs.writeFileSync(dest, srcContent, 'utf-8');
99
+ stats.updated.push(rel);
100
+ return;
101
+ }
102
+
103
+ const textExtensions = ['.md', '.yaml', '.yml', '.json', '.js', '.ts', '.gitignore', '.gitkeep', ''];
104
+ const ext = path.extname(src).toLowerCase();
105
+ const basename = path.basename(src);
106
+ const isText = textExtensions.includes(ext) || basename.startsWith('.');
107
+
108
+ if (isText) {
109
+ const content = fs.readFileSync(src, 'utf-8');
110
+ fs.writeFileSync(dest, content, 'utf-8');
111
+ } else {
112
+ fs.copyFileSync(src, dest);
113
+ }
114
+ stats.added.push(rel);
115
+ }
116
+
117
+ function isFrameworkPath(rel) {
118
+ const normalized = rel.split(path.sep).join('/');
119
+ for (const dir of FRAMEWORK_DIRS) {
120
+ const normalizedDir = dir.split(path.sep).join('/');
121
+ if (normalized.startsWith(normalizedDir + '/')) return true;
122
+ }
123
+ for (const file of FRAMEWORK_FILES) {
124
+ const normalizedFile = file.split(path.sep).join('/');
125
+ if (normalized === normalizedFile) return true;
126
+ }
127
+ return false;
128
+ }
129
+
130
+ 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.0",
3
+ "version": "0.5.0-beta.10",
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"
@@ -0,0 +1,112 @@
1
+ # SFW Changelog — spec-first-copilot
2
+
3
+ > Este arquivo é atualizado automaticamente pelo `spec-first-copilot update`.
4
+ > O agent deve ler este arquivo quando o usuário perguntar sobre mudanças,
5
+ > funcionalidades novas, ou o que está disponível no framework.
6
+ >
7
+ > **Não editar manualmente** — será sobrescrito no próximo update.
8
+
9
+ ---
10
+
11
+ ## 0.5.0-beta.7 (2026-04-12)
12
+
13
+ ### Novo: Comando `/sf-load <nome>`
14
+ Puxa insumos do backend configurado (Confluence ou filesystem) para `workspace/Input/{nome}/`.
15
+ - Busca o scope pelo nome no backend (match exato)
16
+ - Desce recursivamente na árvore (Confluence `get_page_children` é apenas direto — `/sf-load` faz loop)
17
+ - Baixa conteúdo + attachments
18
+ - Log incremental em `.ai/sf-load-log.md` (NOVO/MODIFICADO/INALTERADO via sha256)
19
+ - Idempotente — rodar N vezes sem mudanças no backend não altera nada
20
+ - Referência: `.github/commands/sf-load.md`
21
+
22
+ ### Novo: Adapter layer (Confluence + Filesystem)
23
+ Pipeline agora é backend-agnóstico via adapters plugáveis.
24
+ - **ConfluenceAdapter** — fala com Confluence via MCP `sooperset/mcp-atlassian`
25
+ - **FilesystemAdapter** — lê/escreve direto no disco (também serve como mock pra testes)
26
+ - Configurado em `sfw.config.yml` (copiar de `sfw.config.yml.example`)
27
+ - Interface: `.github/adapters/interface.md` (7 métodos)
28
+ - Erros tipados: `.github/adapters/errors.md` (6 classes)
29
+ - Naming engine: `.github/adapters/naming.md` (placeholders `{scope}`, `{type}`)
30
+ - Registry: `.github/adapters/registry.md`
31
+ - Setup guide: `.github/adapters/SETUP.md` (passo a passo de MCP + Confluence)
32
+
33
+ ### Novo: `sfw.config.yml`
34
+ Manifesto do projeto que define de onde vêm e pra onde vão os artefatos.
35
+ - `input.adapter` — de onde puxar insumos (`confluence` ou `filesystem`)
36
+ - `output.targets[].mode` — ligar/desligar publish (`auto`, `manual`, `off`)
37
+ - `naming.output_container` — template do nome da subpasta no Output (ex: `out_{scope}`)
38
+ - `naming.output_artifact` — template do nome do artefato (ex: `{scope} - {type}`)
39
+ - Copiar `sfw.config.yml.example` e preencher. Zero segredos neste arquivo.
40
+
41
+ ### Novo: `SETUP.md` — Guia de configuração
42
+ Guia passo a passo em `.github/adapters/SETUP.md`:
43
+ - Setup Confluence: uvx, .mcp.json, token Atlassian, space key, page IDs
44
+ - Setup 100% local (filesystem, zero dependências)
45
+ - Como ligar/desligar Confluence via `mode: auto|manual|off`
46
+ - Troubleshooting: tabela com todos os gotchas conhecidos
47
+ - **IMPORTANTE**: Confluence NÃO é CLI. Acesso via MCP tools prefixadas `mcp__atlassian__confluence_*`
48
+
49
+ ### Novo: CLI `update`
50
+ ```bash
51
+ npx spec-first-copilot update # adiciona novos, atualiza framework
52
+ npx spec-first-copilot update --force # sobrescreve tudo incluindo copilot-instructions.md
53
+ ```
54
+ Atualiza projeto existente sem perder arquivos do usuário.
55
+
56
+ ### Breaking: `/sf-setup-projeto` → `/sf-new-project <nome>`
57
+ - Antes: `/sf-setup-projeto` era hardcoded pra pasta `setup_projeto`
58
+ - Agora: `/sf-new-project <nome>` recebe o nome como argumento (simétrico com `/sf-feature <nome>`)
59
+ - `/sf-new-project` gera TRD (bootstrap técnico), `/sf-feature` gera PRD (feature)
60
+ - **Não existe mais pasta mágica** — usuário nomeia livremente em `workspace/Input/`
61
+ - O antigo `setup-projeto.md` foi removido. Usar `new-project.md`
62
+
63
+ ### Breaking: `{sequence}` removido
64
+ - Antes: todo item tinha prefixo numérico `001 - ` pra unicidade no Confluence
65
+ - Agora: usuário nomeia livremente, agent segue o nome do Input
66
+ - Naming simplificado: só `{scope}` e `{type}` como placeholders
67
+ - Premissa: 1 space Confluence = 1 projeto (multi-projeto no mesmo space requer nomes únicos no Input)
68
+
69
+ ### Breaking: Output agrupado por scope
70
+ - Antes: artefatos flat no Output (ex: `001 - TRD setup_projeto`)
71
+ - Agora: subpasta por scope (ex: `out_app_barbearia/app_barbearia - TRD`)
72
+ - Container configurável via `naming.output_container` (default: `out_{scope}`)
73
+ - Artifact configurável via `naming.output_artifact` (default: `{scope} - {type}`)
74
+
75
+ ---
76
+
77
+ ## 0.5.0-beta.2 (2026-04-11)
78
+
79
+ ### Refactor: `docs/specs/` → `specs/` (top-level)
80
+ - Projeções do SDD (brief, contracts, scenarios, tasks) movidas pra raiz
81
+ - Regra: humano lê `workspace/Output/`, agent lê `specs/`
82
+
83
+ ### Refactor: 3-zone separation
84
+ - `.github/` = AI config (rules, templates, commands, agents)
85
+ - `docs/` = system knowledge (5 docs de sistema)
86
+ - `workspace/` = team content (Input/ + Output/)
87
+
88
+ ---
89
+
90
+ ## 0.4.0 (2026-04-10) — v1 stable
91
+
92
+ ### Funcionalidades base
93
+ - 9 commands: setup-projeto, feature, discovery, extract, design, plan, dev, merge-delta, session-finish
94
+ - 7 agents: backend-coder, frontend-coder, db-coder, infra-coder, doc-writer, reviewer, security-reviewer
95
+ - Templates: PRD, TRD, SDD, tasks, Progresso, context, extract-log, backlog, projetos.yaml
96
+ - Templates de estrutura: architecture, domain, conventions, apiContracts, decisions
97
+ - Pipeline: extract → design → plan → dev com checkpoints de aprovação
98
+ - Delta Specs (SDD §11) + merge-delta automático
99
+ - Security Reviewer como gate pós-dev
100
+ - Multi-repo via projetos.yaml
101
+ - Entregáveis contínuos (fases de entrega)
102
+
103
+ ---
104
+
105
+ ## Como usar este arquivo
106
+
107
+ Se o usuário perguntar:
108
+ - **"O que tem de novo?"** → ler a versão mais recente acima
109
+ - **"Como uso o /sf-load?"** → apontar pra `.github/commands/sf-load.md`
110
+ - **"Como configuro Confluence?"** → apontar pra `.github/adapters/SETUP.md`
111
+ - **"O que é adapter?"** → apontar pra `.github/adapters/interface.md`
112
+ - **"O que mudou de setup-projeto?"** → seção "Breaking" do 0.5.0-beta.7
@@ -0,0 +1,314 @@
1
+ # Adapter Setup Guide
2
+
3
+ > Guia passo a passo para configurar os adapters do SFW.
4
+ > Se o usuário pedir ajuda pra configurar, siga este guia.
5
+
6
+ ---
7
+
8
+ ## Escolha seu modo de trabalho
9
+
10
+ O SFW funciona em **3 modos**, configurados no `sfw.config.yml`:
11
+
12
+ | Modo | Input | Output | Quando usar |
13
+ |------|-------|--------|-------------|
14
+ | **Full Confluence** | `adapter: confluence` | `mode: auto` | Time usa Confluence, PM publica lá, quer artefatos lá |
15
+ | **Confluence só leitura** | `adapter: confluence` | `mode: off` | PM publica no Confluence, mas artefatos ficam só local |
16
+ | **100% local** | `adapter: filesystem` | `mode: off` | Time sem Confluence, tudo no disco |
17
+
18
+ Para mudar: edite `sfw.config.yml` e ajuste `input.adapter` e `output.targets[].mode`.
19
+
20
+ ---
21
+
22
+ ## Setup 1: Confluence (Full ou só leitura)
23
+
24
+ ### Pré-requisitos
25
+
26
+ - Python 3.10+ instalado
27
+ - Conta Atlassian com acesso ao Confluence Cloud
28
+ - Claude Code instalado
29
+
30
+ ### Passo 1 — Instalar uvx
31
+
32
+ `uvx` é o runtime que executa o MCP server do Confluence.
33
+
34
+ ```bash
35
+ # Windows (PowerShell)
36
+ pip install uv
37
+
38
+ # Mac/Linux
39
+ pip install uv
40
+ # ou
41
+ brew install uv
42
+ ```
43
+
44
+ Verificar:
45
+ ```bash
46
+ uvx --version
47
+ ```
48
+
49
+ ### Passo 2 — Gerar API Token Atlassian
50
+
51
+ 1. Acesse: https://id.atlassian.com/manage-profile/security/api-tokens
52
+ 2. Clique **Create API token**
53
+ 3. Nome: `sfw-mcp` (ou qualquer nome descritivo)
54
+ 4. Copie o token gerado — **ele só aparece uma vez**
55
+
56
+ Você vai precisar de:
57
+ - **Email**: seu email da conta Atlassian (ex: `dev@empresa.com`)
58
+ - **Token**: o token que acabou de copiar
59
+ - **URL do Confluence**: geralmente `https://sua-empresa.atlassian.net/wiki`
60
+
61
+ ### Passo 3 — Criar `.mcp.json`
62
+
63
+ Crie o arquivo `.mcp.json` na **raiz do projeto** (onde está o `sfw.config.yml`).
64
+
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "atlassian": {
69
+ "command": "uvx",
70
+ "args": ["mcp-atlassian"],
71
+ "env": {
72
+ "CONFLUENCE_URL": "https://sua-empresa.atlassian.net/wiki",
73
+ "CONFLUENCE_USERNAME": "seu-email@empresa.com",
74
+ "CONFLUENCE_API_TOKEN": "seu-token-aqui"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ **IMPORTANTE — Gotchas aprendidos na prática:**
82
+
83
+ 1. **Credenciais HARDCODED no arquivo** — `${VAR}` com variáveis de ambiente **NÃO funciona** no startup do Claude Code. Coloque os valores direto.
84
+
85
+ 2. **`.mcp.json` DEVE estar no `.gitignore`** — tem credenciais. O template do kit já inclui isso, mas verifique:
86
+ ```
87
+ # .gitignore
88
+ .mcp.json
89
+ ```
90
+
91
+ 3. **Após criar/editar `.mcp.json`, REINICIE o Claude Code** — servers MCP só são carregados no startup. Mudança no arquivo não tem efeito em sessão ativa.
92
+
93
+ 4. **Primeira execução baixa ~118 dependências** — o pacote `mcp-atlassian` é pesado. A primeira vez pode demorar 1-2 minutos. As seguintes são instantâneas.
94
+
95
+ ### Passo 4 — Descobrir seu Space Key
96
+
97
+ O Space Key é o identificador curto do espaço Confluence (ex: `ST`, `DEV`, `PROJ`).
98
+
99
+ Para encontrar:
100
+ - Abra qualquer página do seu espaço Confluence
101
+ - Olhe a URL: `https://empresa.atlassian.net/wiki/spaces/ST/pages/...`
102
+ - O `ST` é o Space Key
103
+
104
+ ### Passo 5 — Criar estrutura no Confluence
105
+
106
+ Crie manualmente no Confluence (ou peça pro PM criar):
107
+
108
+ ```
109
+ {Seu Space}
110
+ └── {Nome do Projeto} ← page raiz do projeto
111
+ ├── Input ← PM coloca insumos aqui
112
+ │ └── (scopes como pages filhas)
113
+ └── Output ← agent publica aqui (não editar manualmente)
114
+ ```
115
+
116
+ Anote os **Page IDs** de `Input` e `Output`:
117
+ - Abra a page → ... (menu) → Page information → o ID está na URL
118
+ - Ou: URL da page contém `/pages/123456/...` — o número é o Page ID
119
+
120
+ ### Passo 6 — Configurar `sfw.config.yml`
121
+
122
+ Copie o `sfw.config.yml.example` pra `sfw.config.yml` e preencha:
123
+
124
+ ```yaml
125
+ project:
126
+ name: "Meu Projeto"
127
+
128
+ naming:
129
+ output_container: "out_{scope}"
130
+ output_artifact: "{scope} - {type}"
131
+
132
+ input:
133
+ adapter: confluence
134
+ config:
135
+ space_key: "ST" # ← seu Space Key
136
+ parent_page_id: "360668" # ← Page ID da page Input
137
+ recursive: true
138
+ include_attachments: true
139
+ cache:
140
+ local_dir: "workspace/Input/"
141
+ log: ".ai/load-log.md"
142
+ incremental: true
143
+
144
+ output:
145
+ targets:
146
+ - name: confluence-mirror
147
+ adapter: confluence
148
+ config:
149
+ space_key: "ST" # ← mesmo Space Key
150
+ parent_page_id: "294931" # ← Page ID da page Output
151
+ publishes: [PRD, TRD, SDD, Progresso]
152
+ mode: auto # ← auto | manual | off
153
+ conflict_detection: version
154
+ approval_mechanism: label
155
+ approval_label: "sfw-approved"
156
+ ```
157
+
158
+ ### Passo 7 — Testar a conexão
159
+
160
+ Após reiniciar o Claude Code com o `.mcp.json` configurado, peça ao agent:
161
+
162
+ ```
163
+ Teste a conexão com o Confluence: liste as páginas filhas da page {Page ID do Input}
164
+ ```
165
+
166
+ **IMPORTANTE — Como o Confluence funciona no Claude Code:**
167
+
168
+ O Confluence **NÃO é um comando de terminal**. Não existe `confluence` como CLI.
169
+ O acesso é feito via **MCP tools** — funções que o Claude Code expõe automaticamente
170
+ quando o server MCP está configurado no `.mcp.json`.
171
+
172
+ As tools disponíveis são prefixadas com `mcp__atlassian__confluence_`:
173
+
174
+ | Tool MCP | O que faz |
175
+ |----------|-----------|
176
+ | `mcp__atlassian__confluence_get_page` | Lê conteúdo de uma page por ID |
177
+ | `mcp__atlassian__confluence_get_page_children` | Lista filhos diretos de uma page |
178
+ | `mcp__atlassian__confluence_create_page` | Cria page nova |
179
+ | `mcp__atlassian__confluence_update_page` | Atualiza conteúdo de page existente |
180
+ | `mcp__atlassian__confluence_search` | Busca por texto no space |
181
+ | `mcp__atlassian__confluence_get_labels` | Lê labels de uma page |
182
+ | `mcp__atlassian__confluence_get_attachments` | Lista attachments de uma page |
183
+ | `mcp__atlassian__confluence_download_attachment` | Baixa attachment |
184
+
185
+ O agent chama essas tools diretamente — **nunca via bash/terminal**.
186
+ Se o agent tentar rodar `confluence ...` no terminal, está errado.
187
+
188
+ **Como verificar que o MCP está funcionando:**
189
+ 1. Reinicie o Claude Code após criar/editar `.mcp.json`
190
+ 2. Peça ao agent: "Use a tool `mcp__atlassian__confluence_get_page` com page_id {ID}"
191
+ 3. Se funcionar, está conectado. Se der "tool not found", o MCP não subiu — verifique `.mcp.json`
192
+
193
+ **Nota**: `get_page_children` retorna apenas filhos **diretos** (não recursivo).
194
+ Para trazer toda a árvore, o agent faz loop: chama `get_page_children` em cada
195
+ filho que tem `hasChildren`, empilha e desce. O `/load` já faz isso automaticamente.
196
+
197
+ ---
198
+
199
+ ## Setup 2: 100% Local (sem Confluence)
200
+
201
+ Nenhuma instalação extra necessária. Não precisa de `.mcp.json`.
202
+
203
+ ### Passo 1 — Configurar `sfw.config.yml`
204
+
205
+ ```yaml
206
+ project:
207
+ name: "Meu Projeto"
208
+
209
+ naming:
210
+ output_container: "out_{scope}"
211
+ output_artifact: "{type}" # sem {scope} no nome — sem risco de colisão local
212
+
213
+ input:
214
+ adapter: filesystem
215
+ config:
216
+ root_path: "workspace/Input"
217
+ cache:
218
+ local_dir: "workspace/Input/"
219
+ log: ".ai/load-log.md"
220
+ incremental: true
221
+
222
+ output:
223
+ targets:
224
+ - name: local
225
+ adapter: filesystem
226
+ config:
227
+ root_path: "workspace/Output"
228
+ publishes: [PRD, TRD, SDD, Progresso]
229
+ mode: auto
230
+ conflict_detection: hash
231
+ approval_mechanism: none
232
+ ```
233
+
234
+ ### Passo 2 — Criar pastas de Input
235
+
236
+ ```bash
237
+ mkdir -p workspace/Input/meu_escopo
238
+ # Adicione seus arquivos de insumo na pasta
239
+ ```
240
+
241
+ Pronto. `/new-project meu_escopo` funciona direto.
242
+
243
+ ---
244
+
245
+ ## Ligar e desligar Confluence (sem mudar nada estrutural)
246
+
247
+ ### Desligar output pro Confluence (manter input)
248
+
249
+ Mude `mode` no target:
250
+
251
+ ```yaml
252
+ output:
253
+ targets:
254
+ - name: confluence-mirror
255
+ mode: off # ← era "auto", agora "off"
256
+ ```
257
+
258
+ Pipeline roda normal, artefatos ficam locais. Quando quiser religar, volte pra `auto`.
259
+
260
+ ### Desligar tudo (input + output) — virar 100% local
261
+
262
+ Mude o adapter do input:
263
+
264
+ ```yaml
265
+ input:
266
+ adapter: filesystem # ← era "confluence"
267
+ config:
268
+ root_path: "workspace/Input"
269
+ ```
270
+
271
+ E coloque `mode: off` nos targets de Confluence.
272
+
273
+ ### Adicionar Confluence depois (começou local, quer publicar)
274
+
275
+ 1. Siga os passos 1-5 do Setup Confluence
276
+ 2. Adicione o target no `sfw.config.yml`:
277
+ ```yaml
278
+ output:
279
+ targets:
280
+ - name: confluence-mirror
281
+ adapter: confluence
282
+ config:
283
+ space_key: "ST"
284
+ parent_page_id: "294931"
285
+ publishes: [PRD, TRD, SDD, Progresso]
286
+ mode: auto
287
+ ```
288
+ 3. Re-rode `/extract`, `/design`, `/plan` — os artefatos locais serão publicados
289
+
290
+ ---
291
+
292
+ ## Troubleshooting
293
+
294
+ | Problema | Solução |
295
+ |----------|---------|
296
+ | MCP server não aparece no Claude Code | Reiniciar Claude Code. MCP só carrega no startup |
297
+ | `${VAR}` não resolve no `.mcp.json` | Hardcode as credenciais direto. Variáveis de ambiente não funcionam |
298
+ | "401 Unauthorized" | Verifique email + token no `.mcp.json`. Token pode ter expirado |
299
+ | "403 Forbidden" | Usuário sem permissão no space. Pedir acesso ao admin |
300
+ | "Page not found" (404) | Page ID errado. Confirme o ID via URL da page no Confluence |
301
+ | Primeira execução demora muito | Normal — uvx baixa ~118 deps na primeira vez |
302
+ | `BadRequestException: title already exists` | Title duplicado no space (unique per space no Confluence). Renomear o scope no Input |
303
+ | Edição no `.mcp.json` não faz efeito | Reiniciar Claude Code obrigatório |
304
+ | Content no Confluence parece diferente do local | Markdown roundtrip normaliza (`#`→`===`, `-`→`*`). Normal — version number é fonte de verdade, não bytes |
305
+
306
+ ---
307
+
308
+ ## Referências
309
+
310
+ - Interface do adapter: `.github/adapters/interface.md`
311
+ - ConfluenceAdapter: `.github/adapters/confluence.md`
312
+ - FilesystemAdapter: `.github/adapters/filesystem.md`
313
+ - Erros: `.github/adapters/errors.md`
314
+ - Naming: `.github/adapters/naming.md`