spec-first-copilot 0.7.0-beta.1 → 0.7.0
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/README.md +252 -167
- package/bin/cli.js +70 -70
- package/lib/init.js +92 -92
- package/lib/update.js +132 -132
- package/package.json +1 -1
- package/templates/.ai/memory/napkin.md +68 -68
- package/templates/.github/CHANGELOG.md +560 -533
- package/templates/.github/adapters/SETUP.md +314 -314
- package/templates/.github/adapters/confluence.md +295 -295
- package/templates/.github/adapters/errors.md +234 -234
- package/templates/.github/adapters/filesystem.md +353 -353
- package/templates/.github/adapters/interface.md +301 -301
- package/templates/.github/adapters/naming.md +241 -241
- package/templates/.github/adapters/registry.md +244 -244
- package/templates/.github/agents/backend-coder.md +215 -215
- package/templates/.github/agents/db-coder.md +165 -165
- package/templates/.github/agents/doc-writer.md +66 -66
- package/templates/.github/agents/frontend-coder.md +222 -222
- package/templates/.github/agents/infra-coder.md +341 -341
- package/templates/.github/agents/reviewer.md +99 -99
- package/templates/.github/agents/security-reviewer.md +153 -153
- package/templates/.github/copilot-instructions.md +272 -272
- package/templates/.github/instructions/docs.instructions.md +147 -145
- package/templates/.github/instructions/sensitive-files.instructions.md +32 -32
- package/templates/.github/rules.md +229 -229
- package/templates/.github/scripts/bootstrap-confluence.js +289 -289
- package/templates/.github/skills/sf-design/SKILL.md +161 -161
- package/templates/.github/skills/sf-dev/SKILL.md +204 -204
- package/templates/.github/skills/sf-discovery/SKILL.md +415 -415
- package/templates/.github/skills/sf-extract/SKILL.md +225 -225
- package/templates/.github/skills/sf-load/SKILL.md +296 -296
- package/templates/.github/skills/sf-mcp/SKILL.md +386 -386
- package/templates/.github/skills/sf-merge-docs/SKILL.md +152 -152
- package/templates/.github/skills/sf-plan/SKILL.md +152 -152
- package/templates/.github/skills/sf-publish/SKILL.md +144 -144
- package/templates/.github/skills/sf-session-finish/SKILL.md +93 -93
- package/templates/.github/skills/sf-start/SKILL.md +192 -192
- package/templates/.github/templates/estrutura/apiContracts.template.md +160 -159
- package/templates/.github/templates/estrutura/architecture.template.md +169 -168
- package/templates/.github/templates/estrutura/conventions.template.md +214 -212
- package/templates/.github/templates/estrutura/decisions.template.md +107 -107
- package/templates/.github/templates/estrutura/domain.template.md +161 -160
- package/templates/.github/templates/feature/PRD.template.md +279 -279
- package/templates/.github/templates/feature/Progresso.template.md +141 -141
- package/templates/.github/templates/feature/TRD.template.md +358 -358
- package/templates/.github/templates/feature/context.template.md +89 -89
- package/templates/.github/templates/feature/extract-log.template.md +49 -49
- package/templates/.github/templates/feature/projetos.template.yaml +79 -79
- package/templates/.github/templates/global/progresso_global.template.md +59 -57
- package/templates/.github/templates/specs/brief.template.md +66 -66
- package/templates/.github/templates/specs/contracts.template.md +147 -147
- package/templates/.github/templates/specs/scenarios.template.md +125 -125
- package/templates/.github/templates/specs/tasks.template.md +65 -65
- package/templates/_gitignore +35 -35
- package/templates/sfw.config.yml.example +147 -147
|
@@ -1,244 +1,244 @@
|
|
|
1
|
-
# Adapter Registry
|
|
2
|
-
|
|
3
|
-
> Como o SFW resolve `adapter: "confluence"` no `sfw.config.yml` pra uma
|
|
4
|
-
> instância concreta de `SourceAdapter`.
|
|
5
|
-
>
|
|
6
|
-
> Este arquivo é a **especificação** do registry. A implementação real vive
|
|
7
|
-
> no bootstrap do kit (quando for codada — §9.9.P0.2+).
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Conceito
|
|
12
|
-
|
|
13
|
-
O usuário declara no manifest:
|
|
14
|
-
|
|
15
|
-
```yaml
|
|
16
|
-
input:
|
|
17
|
-
adapter: confluence
|
|
18
|
-
config:
|
|
19
|
-
space_key: ST
|
|
20
|
-
parent_page_id: "360668"
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
As skills **nunca** veem a string `"confluence"`. Elas recebem uma instância
|
|
24
|
-
que implementa `SourceAdapter` — já configurada, já validada. O registry é
|
|
25
|
-
a ponte entre os dois.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Responsabilidades do registry
|
|
30
|
-
|
|
31
|
-
1. **Descobrir adapters disponíveis** (builtin + futuros plugins)
|
|
32
|
-
2. **Resolver** a string `adapter: X` na classe correta
|
|
33
|
-
3. **Instanciar** o adapter passando o objeto `config` do manifest
|
|
34
|
-
4. **Validar** chamando `adapter.validateConfig(config)` antes de devolver
|
|
35
|
-
5. **Falhar cedo e rápido** se o adapter não existe ou config está errado
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Adapters built-in no MVP
|
|
40
|
-
|
|
41
|
-
| Chave no YAML | Classe | Arquivo de runbook | Status MVP |
|
|
42
|
-
|---------------|--------|-------------------|------------|
|
|
43
|
-
| `confluence` | `ConfluenceAdapter` | `.github/adapters/confluence.md` | P0.2 — reuso do validado em testes/barbearia |
|
|
44
|
-
| `filesystem` | `FilesystemAdapter` | `.github/adapters/filesystem.md` | P0.2 — novo, trivial |
|
|
45
|
-
|
|
46
|
-
**Apenas esses 2 no MVP.** Qualquer outro valor em `adapter:` → `ValidationError`
|
|
47
|
-
no load do manifest.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Fluxo de resolução
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
1. Skill começa (ex: /sf-load)
|
|
55
|
-
2. Carrega sfw.config.yml
|
|
56
|
-
3. Para cada seção que precisa de adapter (input, cada output.target):
|
|
57
|
-
a. Lê string `adapter: X`
|
|
58
|
-
b. Consulta registry: registry.get("X")
|
|
59
|
-
- Se X não existe → ValidationError: "unknown adapter 'X' (available: confluence, filesystem)"
|
|
60
|
-
c. Instancia: const a = new AdapterClass()
|
|
61
|
-
d. Valida config: a.validateConfig(target.config)
|
|
62
|
-
- Se inválido → ValidationError (propaga do adapter)
|
|
63
|
-
e. Armazena a instância configurada em memória pra reuso durante a skill
|
|
64
|
-
4. Usa as instâncias via interface — nunca chama .name direto no hot path
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Importante**: o registry é consultado **1 vez** por execução de skill.
|
|
68
|
-
Instâncias são cached pela duração da skill. Skills que rodam em sequência
|
|
69
|
-
(`/sf-extract` → `/sf-design`) podem re-instanciar — não há estado compartilhado
|
|
70
|
-
entre execuções (não deveria haver, por contrato).
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Contrato textual do registry
|
|
75
|
-
|
|
76
|
-
```typescript
|
|
77
|
-
interface AdapterRegistry {
|
|
78
|
-
/**
|
|
79
|
-
* Retorna a classe do adapter (não instancia).
|
|
80
|
-
* @throws ValidationError se a chave não existir
|
|
81
|
-
*/
|
|
82
|
-
get(key: string): AdapterClass;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Lista as chaves disponíveis. Usado em mensagens de erro.
|
|
86
|
-
*/
|
|
87
|
-
available(): string[];
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Registra um novo adapter. No MVP só é chamado internamente pros 2 builtin.
|
|
91
|
-
* Plugin system (P2) usaria isso pra carregar adapters externos.
|
|
92
|
-
*/
|
|
93
|
-
register(key: string, cls: AdapterClass): void;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
interface AdapterClass {
|
|
97
|
-
new(): SourceAdapter;
|
|
98
|
-
/** Chave que o adapter usa no YAML — deve bater com o que está no registry */
|
|
99
|
-
readonly adapterName: string;
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Inicialização builtin (pseudo-código)
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const registry = new AdapterRegistry();
|
|
107
|
-
registry.register("confluence", ConfluenceAdapter);
|
|
108
|
-
registry.register("filesystem", FilesystemAdapter);
|
|
109
|
-
|
|
110
|
-
// quando o manifest é carregado:
|
|
111
|
-
function resolveAdapter(section: { adapter: string; config: object }): SourceAdapter {
|
|
112
|
-
const cls = registry.get(section.adapter); // throws se não existe
|
|
113
|
-
const instance = new cls();
|
|
114
|
-
instance.validateConfig(section.config); // throws se config errada
|
|
115
|
-
return instance;
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Declaração de config requerida (contrato por adapter)
|
|
122
|
-
|
|
123
|
-
Cada adapter **documenta** (em `.github/adapters/{name}.md`) quais campos
|
|
124
|
-
são obrigatórios e quais são opcionais na seção `config`. O registry não
|
|
125
|
-
valida isso — delega pro `validateConfig` do adapter. Isso evita duplicação
|
|
126
|
-
e mantém a responsabilidade localizada.
|
|
127
|
-
|
|
128
|
-
**Exemplo — ConfluenceAdapter**:
|
|
129
|
-
| Campo | Obrigatório | Tipo | Descrição |
|
|
130
|
-
|-------|:---:|------|-----------|
|
|
131
|
-
| `space_key` | ✅ | string | ex: `"ST"` |
|
|
132
|
-
| `parent_page_id` | ✅ | string | ID numérico da page pai |
|
|
133
|
-
| `recursive` | — | boolean | default `true` |
|
|
134
|
-
| `include_attachments` | — | boolean | default `true` |
|
|
135
|
-
|
|
136
|
-
**Exemplo — FilesystemAdapter**:
|
|
137
|
-
| Campo | Obrigatório | Tipo | Descrição |
|
|
138
|
-
|-------|:---:|------|-----------|
|
|
139
|
-
| `root_path` | ✅ | string | path absoluto ou relativo ao projeto |
|
|
140
|
-
| `glob` | — | string | default `**/*.md` |
|
|
141
|
-
| `watch` | — | boolean | default `false` (watch mode é P2) |
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Ordem de validação no load do manifest
|
|
146
|
-
|
|
147
|
-
Quando skill chama `loadConfig("sfw.config.yml")`:
|
|
148
|
-
|
|
149
|
-
1. **Parse YAML.** Erro de sintaxe → `ValidationError` (nem chama registry).
|
|
150
|
-
2. **Valida shape top-level.** Presença de `project`, `naming`, `input`, `output.targets[]`.
|
|
151
|
-
3. **Resolve `input.adapter`** via registry + `validateConfig` do adapter.
|
|
152
|
-
4. **Resolve cada `output.targets[i].adapter`** via registry + `validateConfig`.
|
|
153
|
-
5. **Valida `naming.*`** — templates precisam ser strings não-vazias; placeholders
|
|
154
|
-
desconhecidos detectados agora (antecipa erro de runtime).
|
|
155
|
-
6. **Valida coerência inter-seções**: ex., `output.targets[i].mode: auto` exige
|
|
156
|
-
`approval_mechanism` presente quando `publishes` contém PRD/
|
|
157
|
-
com gate de aprovação).
|
|
158
|
-
|
|
159
|
-
Tudo no load. Se qualquer passo falha, skill para antes de tocar backend.
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
## Config de exemplo resolvida
|
|
164
|
-
|
|
165
|
-
Input YAML:
|
|
166
|
-
```yaml
|
|
167
|
-
project:
|
|
168
|
-
name: "Barbearia"
|
|
169
|
-
input:
|
|
170
|
-
adapter: confluence
|
|
171
|
-
config:
|
|
172
|
-
space_key: ST
|
|
173
|
-
parent_page_id: "360668"
|
|
174
|
-
output:
|
|
175
|
-
targets:
|
|
176
|
-
- name: confluence-mirror
|
|
177
|
-
adapter: confluence
|
|
178
|
-
config:
|
|
179
|
-
space_key: ST
|
|
180
|
-
parent_page_id: "294931"
|
|
181
|
-
publishes: [PRD, TRD, Progresso]
|
|
182
|
-
mode: auto
|
|
183
|
-
- name: local-mirror
|
|
184
|
-
adapter: filesystem
|
|
185
|
-
config:
|
|
186
|
-
root_path: "./mirror"
|
|
187
|
-
publishes: [PRD, TRD, Progresso]
|
|
188
|
-
mode: auto
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Após load:
|
|
192
|
-
```typescript
|
|
193
|
-
const manifest = {
|
|
194
|
-
project: { name: "Barbearia" },
|
|
195
|
-
input: <ConfluenceAdapter instance, configured>,
|
|
196
|
-
outputs: [
|
|
197
|
-
{ name: "confluence-mirror", adapter: <ConfluenceAdapter>, publishes: [...], mode: "auto" },
|
|
198
|
-
{ name: "local-mirror", adapter: <FilesystemAdapter>, publishes: [...], mode: "auto" },
|
|
199
|
-
],
|
|
200
|
-
};
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
Skill chama `manifest.input.listChildren(...)` e `manifest.outputs[0].adapter.update(...)`.
|
|
204
|
-
A string `"confluence"` nunca aparece fora do registry.
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## O que NÃO é responsabilidade do registry
|
|
209
|
-
|
|
210
|
-
- **Credenciais.** Adapter lê `.mcp.json` / env var direto. Registry nem vê.
|
|
211
|
-
- **Retry/backoff.** Cada adapter implementa. Registry devolve instância "crua".
|
|
212
|
-
- **Logging.** Skills logam. Adapter/registry silenciam (exceto em erro).
|
|
213
|
-
- **Connection pooling.** MVP é single-process single-skill. Se virar batch,
|
|
214
|
-
registry pode cachear. Não agora.
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Futuro (P2) — Plugin system
|
|
219
|
-
|
|
220
|
-
Quando aparecer o 3º caso real de backend não-builtin:
|
|
221
|
-
|
|
222
|
-
1. `sfw.config.yml` ganha seção `plugins:`:
|
|
223
|
-
```yaml
|
|
224
|
-
plugins:
|
|
225
|
-
- npm:@sfw/notion-adapter@1.2.0
|
|
226
|
-
- file:./local-adapters/sharepoint.js
|
|
227
|
-
```
|
|
228
|
-
2. Bootstrap do kit carrega plugins antes do manifest.
|
|
229
|
-
3. Cada plugin exporta `{ key, class }` e chama `registry.register(...)`.
|
|
230
|
-
4. Interface do adapter fica estável (breaking change vira major version).
|
|
231
|
-
|
|
232
|
-
**Decisão (2026-04-11)**: não implementar agora. Builtin resolve 95% dos casos
|
|
233
|
-
e prova que a interface está certa. Plugin system vira prioridade quando um
|
|
234
|
-
usuário real pedir.
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Referências
|
|
239
|
-
|
|
240
|
-
- Interface: `.github/adapters/interface.md`
|
|
241
|
-
- Erros: `.github/adapters/errors.md`
|
|
242
|
-
- Naming: `.github/adapters/naming.md`
|
|
243
|
-
- Manifest: `sfw.config.yml.example`
|
|
244
|
-
- Roadmap: `planodetarefas.md §9.9.P0.2` (implementação dos builtins)
|
|
1
|
+
# Adapter Registry
|
|
2
|
+
|
|
3
|
+
> Como o SFW resolve `adapter: "confluence"` no `sfw.config.yml` pra uma
|
|
4
|
+
> instância concreta de `SourceAdapter`.
|
|
5
|
+
>
|
|
6
|
+
> Este arquivo é a **especificação** do registry. A implementação real vive
|
|
7
|
+
> no bootstrap do kit (quando for codada — §9.9.P0.2+).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Conceito
|
|
12
|
+
|
|
13
|
+
O usuário declara no manifest:
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
input:
|
|
17
|
+
adapter: confluence
|
|
18
|
+
config:
|
|
19
|
+
space_key: ST
|
|
20
|
+
parent_page_id: "360668"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
As skills **nunca** veem a string `"confluence"`. Elas recebem uma instância
|
|
24
|
+
que implementa `SourceAdapter` — já configurada, já validada. O registry é
|
|
25
|
+
a ponte entre os dois.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Responsabilidades do registry
|
|
30
|
+
|
|
31
|
+
1. **Descobrir adapters disponíveis** (builtin + futuros plugins)
|
|
32
|
+
2. **Resolver** a string `adapter: X` na classe correta
|
|
33
|
+
3. **Instanciar** o adapter passando o objeto `config` do manifest
|
|
34
|
+
4. **Validar** chamando `adapter.validateConfig(config)` antes de devolver
|
|
35
|
+
5. **Falhar cedo e rápido** se o adapter não existe ou config está errado
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Adapters built-in no MVP
|
|
40
|
+
|
|
41
|
+
| Chave no YAML | Classe | Arquivo de runbook | Status MVP |
|
|
42
|
+
|---------------|--------|-------------------|------------|
|
|
43
|
+
| `confluence` | `ConfluenceAdapter` | `.github/adapters/confluence.md` | P0.2 — reuso do validado em testes/barbearia |
|
|
44
|
+
| `filesystem` | `FilesystemAdapter` | `.github/adapters/filesystem.md` | P0.2 — novo, trivial |
|
|
45
|
+
|
|
46
|
+
**Apenas esses 2 no MVP.** Qualquer outro valor em `adapter:` → `ValidationError`
|
|
47
|
+
no load do manifest.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Fluxo de resolução
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
1. Skill começa (ex: /sf-load)
|
|
55
|
+
2. Carrega sfw.config.yml
|
|
56
|
+
3. Para cada seção que precisa de adapter (input, cada output.target):
|
|
57
|
+
a. Lê string `adapter: X`
|
|
58
|
+
b. Consulta registry: registry.get("X")
|
|
59
|
+
- Se X não existe → ValidationError: "unknown adapter 'X' (available: confluence, filesystem)"
|
|
60
|
+
c. Instancia: const a = new AdapterClass()
|
|
61
|
+
d. Valida config: a.validateConfig(target.config)
|
|
62
|
+
- Se inválido → ValidationError (propaga do adapter)
|
|
63
|
+
e. Armazena a instância configurada em memória pra reuso durante a skill
|
|
64
|
+
4. Usa as instâncias via interface — nunca chama .name direto no hot path
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Importante**: o registry é consultado **1 vez** por execução de skill.
|
|
68
|
+
Instâncias são cached pela duração da skill. Skills que rodam em sequência
|
|
69
|
+
(`/sf-extract` → `/sf-design`) podem re-instanciar — não há estado compartilhado
|
|
70
|
+
entre execuções (não deveria haver, por contrato).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Contrato textual do registry
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
interface AdapterRegistry {
|
|
78
|
+
/**
|
|
79
|
+
* Retorna a classe do adapter (não instancia).
|
|
80
|
+
* @throws ValidationError se a chave não existir
|
|
81
|
+
*/
|
|
82
|
+
get(key: string): AdapterClass;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Lista as chaves disponíveis. Usado em mensagens de erro.
|
|
86
|
+
*/
|
|
87
|
+
available(): string[];
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Registra um novo adapter. No MVP só é chamado internamente pros 2 builtin.
|
|
91
|
+
* Plugin system (P2) usaria isso pra carregar adapters externos.
|
|
92
|
+
*/
|
|
93
|
+
register(key: string, cls: AdapterClass): void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface AdapterClass {
|
|
97
|
+
new(): SourceAdapter;
|
|
98
|
+
/** Chave que o adapter usa no YAML — deve bater com o que está no registry */
|
|
99
|
+
readonly adapterName: string;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Inicialização builtin (pseudo-código)
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const registry = new AdapterRegistry();
|
|
107
|
+
registry.register("confluence", ConfluenceAdapter);
|
|
108
|
+
registry.register("filesystem", FilesystemAdapter);
|
|
109
|
+
|
|
110
|
+
// quando o manifest é carregado:
|
|
111
|
+
function resolveAdapter(section: { adapter: string; config: object }): SourceAdapter {
|
|
112
|
+
const cls = registry.get(section.adapter); // throws se não existe
|
|
113
|
+
const instance = new cls();
|
|
114
|
+
instance.validateConfig(section.config); // throws se config errada
|
|
115
|
+
return instance;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Declaração de config requerida (contrato por adapter)
|
|
122
|
+
|
|
123
|
+
Cada adapter **documenta** (em `.github/adapters/{name}.md`) quais campos
|
|
124
|
+
são obrigatórios e quais são opcionais na seção `config`. O registry não
|
|
125
|
+
valida isso — delega pro `validateConfig` do adapter. Isso evita duplicação
|
|
126
|
+
e mantém a responsabilidade localizada.
|
|
127
|
+
|
|
128
|
+
**Exemplo — ConfluenceAdapter**:
|
|
129
|
+
| Campo | Obrigatório | Tipo | Descrição |
|
|
130
|
+
|-------|:---:|------|-----------|
|
|
131
|
+
| `space_key` | ✅ | string | ex: `"ST"` |
|
|
132
|
+
| `parent_page_id` | ✅ | string | ID numérico da page pai |
|
|
133
|
+
| `recursive` | — | boolean | default `true` |
|
|
134
|
+
| `include_attachments` | — | boolean | default `true` |
|
|
135
|
+
|
|
136
|
+
**Exemplo — FilesystemAdapter**:
|
|
137
|
+
| Campo | Obrigatório | Tipo | Descrição |
|
|
138
|
+
|-------|:---:|------|-----------|
|
|
139
|
+
| `root_path` | ✅ | string | path absoluto ou relativo ao projeto |
|
|
140
|
+
| `glob` | — | string | default `**/*.md` |
|
|
141
|
+
| `watch` | — | boolean | default `false` (watch mode é P2) |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Ordem de validação no load do manifest
|
|
146
|
+
|
|
147
|
+
Quando skill chama `loadConfig("sfw.config.yml")`:
|
|
148
|
+
|
|
149
|
+
1. **Parse YAML.** Erro de sintaxe → `ValidationError` (nem chama registry).
|
|
150
|
+
2. **Valida shape top-level.** Presença de `project`, `naming`, `input`, `output.targets[]`.
|
|
151
|
+
3. **Resolve `input.adapter`** via registry + `validateConfig` do adapter.
|
|
152
|
+
4. **Resolve cada `output.targets[i].adapter`** via registry + `validateConfig`.
|
|
153
|
+
5. **Valida `naming.*`** — templates precisam ser strings não-vazias; placeholders
|
|
154
|
+
desconhecidos detectados agora (antecipa erro de runtime).
|
|
155
|
+
6. **Valida coerência inter-seções**: ex., `output.targets[i].mode: auto` exige
|
|
156
|
+
`approval_mechanism` presente quando `publishes` contém PRD/TRD (artefatos
|
|
157
|
+
com gate de aprovação).
|
|
158
|
+
|
|
159
|
+
Tudo no load. Se qualquer passo falha, skill para antes de tocar backend.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Config de exemplo resolvida
|
|
164
|
+
|
|
165
|
+
Input YAML:
|
|
166
|
+
```yaml
|
|
167
|
+
project:
|
|
168
|
+
name: "Barbearia"
|
|
169
|
+
input:
|
|
170
|
+
adapter: confluence
|
|
171
|
+
config:
|
|
172
|
+
space_key: ST
|
|
173
|
+
parent_page_id: "360668"
|
|
174
|
+
output:
|
|
175
|
+
targets:
|
|
176
|
+
- name: confluence-mirror
|
|
177
|
+
adapter: confluence
|
|
178
|
+
config:
|
|
179
|
+
space_key: ST
|
|
180
|
+
parent_page_id: "294931"
|
|
181
|
+
publishes: [PRD, TRD, Progresso]
|
|
182
|
+
mode: auto
|
|
183
|
+
- name: local-mirror
|
|
184
|
+
adapter: filesystem
|
|
185
|
+
config:
|
|
186
|
+
root_path: "./mirror"
|
|
187
|
+
publishes: [PRD, TRD, Progresso]
|
|
188
|
+
mode: auto
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Após load:
|
|
192
|
+
```typescript
|
|
193
|
+
const manifest = {
|
|
194
|
+
project: { name: "Barbearia" },
|
|
195
|
+
input: <ConfluenceAdapter instance, configured>,
|
|
196
|
+
outputs: [
|
|
197
|
+
{ name: "confluence-mirror", adapter: <ConfluenceAdapter>, publishes: [...], mode: "auto" },
|
|
198
|
+
{ name: "local-mirror", adapter: <FilesystemAdapter>, publishes: [...], mode: "auto" },
|
|
199
|
+
],
|
|
200
|
+
};
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Skill chama `manifest.input.listChildren(...)` e `manifest.outputs[0].adapter.update(...)`.
|
|
204
|
+
A string `"confluence"` nunca aparece fora do registry.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## O que NÃO é responsabilidade do registry
|
|
209
|
+
|
|
210
|
+
- **Credenciais.** Adapter lê `.mcp.json` / env var direto. Registry nem vê.
|
|
211
|
+
- **Retry/backoff.** Cada adapter implementa. Registry devolve instância "crua".
|
|
212
|
+
- **Logging.** Skills logam. Adapter/registry silenciam (exceto em erro).
|
|
213
|
+
- **Connection pooling.** MVP é single-process single-skill. Se virar batch,
|
|
214
|
+
registry pode cachear. Não agora.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Futuro (P2) — Plugin system
|
|
219
|
+
|
|
220
|
+
Quando aparecer o 3º caso real de backend não-builtin:
|
|
221
|
+
|
|
222
|
+
1. `sfw.config.yml` ganha seção `plugins:`:
|
|
223
|
+
```yaml
|
|
224
|
+
plugins:
|
|
225
|
+
- npm:@sfw/notion-adapter@1.2.0
|
|
226
|
+
- file:./local-adapters/sharepoint.js
|
|
227
|
+
```
|
|
228
|
+
2. Bootstrap do kit carrega plugins antes do manifest.
|
|
229
|
+
3. Cada plugin exporta `{ key, class }` e chama `registry.register(...)`.
|
|
230
|
+
4. Interface do adapter fica estável (breaking change vira major version).
|
|
231
|
+
|
|
232
|
+
**Decisão (2026-04-11)**: não implementar agora. Builtin resolve 95% dos casos
|
|
233
|
+
e prova que a interface está certa. Plugin system vira prioridade quando um
|
|
234
|
+
usuário real pedir.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Referências
|
|
239
|
+
|
|
240
|
+
- Interface: `.github/adapters/interface.md`
|
|
241
|
+
- Erros: `.github/adapters/errors.md`
|
|
242
|
+
- Naming: `.github/adapters/naming.md`
|
|
243
|
+
- Manifest: `sfw.config.yml.example`
|
|
244
|
+
- Roadmap: `planodetarefas.md §9.9.P0.2` (implementação dos builtins)
|