spec-first-copilot 0.5.0-beta.8 → 0.5.0-beta.9

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.8",
3
+ "version": "0.5.0-beta.9",
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"
@@ -58,38 +58,76 @@ Ler `sfw.config.yml` e extrair:
58
58
  4. Anotar scope_path
59
59
  ```
60
60
 
61
- ### 3. Trazer conteúdo recursivamente
61
+ ### 3. Trazer conteúdo — RECURSIVO ATÉ O ÚLTIMO NÍVEL, FLAT LOCAL
62
+
63
+ > **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
67
 
63
68
  **Para Confluence**:
64
69
 
65
70
  ```
66
- function loadScope(pageId, localDir):
67
- // Baixar conteúdo da page-mãe
68
- page = mcp__atlassian__confluence_get_page(page_id=pageId, convert_to_markdown=true)
69
- salvar page.content em {localDir}/_parent.md (ou {titulo_sanitizado}.md)
70
- registrar no load-log: pageId, title, version, sha256(content)
71
-
72
- // Baixar attachments (se include_attachments=true)
73
- attachments = mcp__atlassian__confluence_get_attachments(page_id=pageId)
74
- para cada attachment:
75
- bytes = mcp__atlassian__confluence_download_attachment(page_id=pageId, filename=attachment.title)
76
- salvar em {localDir}/attachments/{filename}
77
- registrar no load-log
78
-
79
- // Recursão nos filhos
71
+ function loadScope(pageId, targetDir):
72
+ // PASSO 1: Coletar TODAS as pages da árvore (recursivo)
73
+ allPages = []
74
+ collectAllPages(pageId, allPages)
75
+
76
+ // PASSO 2: Baixar conteúdo de CADA page como arquivo flat
77
+ para cada page em allPages:
78
+ content = mcp__atlassian__confluence_get_page(page_id=page.id, convert_to_markdown=true)
79
+ 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
82
+
83
+ // PASSO 3: Baixar attachments de CADA page (se include_attachments=true)
84
+ para cada page em allPages:
85
+ attachments = mcp__atlassian__confluence_get_attachments(page_id=page.id)
86
+ para cada att em attachments:
87
+ bytes = mcp__atlassian__confluence_download_attachment(page_id=page.id, filename=att.title)
88
+ salvar em {targetDir}/{att.title} // ← FLAT junto com os .md
89
+ registrar no load-log
90
+
91
+ function collectAllPages(pageId, result):
92
+ // get_page_children retorna APENAS filhos diretos — por isso o loop recursivo
80
93
  children = mcp__atlassian__confluence_get_page_children(page_id=pageId)
81
- para cada child:
82
- childDir = {localDir}/{sanitize(child.title)}
83
- mkdir childDir
84
- loadScope(child.id, childDir) // recursão
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
85
108
  ```
86
109
 
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
+ ```
121
+
122
+ **Nenhuma subpasta.** Não importa quantos níveis a árvore do Confluence tem — local é flat.
123
+
87
124
  **Para Filesystem**:
88
125
 
89
126
  ```
90
- function loadScope(sourcePath, localDir):
91
- // Se source == localDir → no-op (input já é local)
92
- // Senão: copiar recursivamente sourcePath localDir
127
+ function loadScope(sourcePath, targetDir):
128
+ // Se source == targetDir → no-op (input já é local)
129
+ // Senão: copiar TODOS os arquivos recursivamente pra targetDir (flat)
130
+ // Subpastas do source viram arquivos flat no target
93
131
  // Calcular sha256 de cada arquivo pra load-log
94
132
  ```
95
133
 
@@ -102,9 +140,13 @@ Formato append-only:
102
140
 
103
141
  | Item ID | Title | Version | SHA256 | Local Path | Status |
104
142
  |---------|-------|---------|--------|------------|--------|
105
- | 294950 | setup_projeto | 3 | a3f5... | workspace/Input/app_barbearia/_parent.md | NOVO |
106
- | 557057 | brief fullstack | 1 | 9fc3... | workspace/Input/app_barbearia/brief_fullstack.md | NOVO |
107
- | att:diagram.png | diagram.png | | 7d2e... | workspace/Input/app_barbearia/attachments/diagram.png | NOVO |
143
+ | 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 |
108
150
  ```
109
151
 
110
152
  **Se `incremental: true`** (default):
@@ -138,8 +180,10 @@ Log salvo em .ai/sf-load-log.md
138
180
  - O `/sf-load` **nunca modifica o backend** — só lê
139
181
  - O `/sf-load` **nunca deleta arquivos locais** — se algo sumiu do backend,
140
182
  marca como REMOVIDO no log mas mantém o arquivo local
141
- - Attachments são salvos em subpasta `attachments/` dentro do scope
183
+ - Attachments ficam flat junto com os .md (sem subpasta `attachments/`)
142
184
  - Nomes de arquivo são sanitizados: espaços → `_`, caracteres especiais removidos
185
+ - **Estrutura local é FLAT** — não replica hierarquia do backend. Todos os arquivos soltos na mesma pasta
186
+ - **Recursão é total** — desce até o último nível. Se `get_page_children` retornou filhos, DESCER em cada um
143
187
 
144
188
  ## Erros
145
189