adi_dev_workflow 1.3.0 → 1.4.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/frameworks/commands/ministack/generate-tasks.md +212 -212
- package/frameworks/commands/sdd/generate-task-plan.md +4 -4
- package/frameworks/commands/sdd/generate-tech-direction.md +2 -2
- package/frameworks/commands/sdd/generate-tech-spec.md +4 -4
- package/frameworks/commands/sdd/generate-tests.md +171 -39
- package/frameworks/config/ai-framework-config.yaml +2 -2
- package/frameworks/skills/ministack-tasks-expert/SKILL.md +115 -104
- package/frameworks/skills/ministack-tech-direction-expert/SKILL.md +21 -6
- package/frameworks/skills/prompt-engineer-expert/SKILL.md +10 -7
- package/frameworks/skills/sdd-tech-direction-expert/SKILL.md +21 -6
- package/frameworks/skills/sdd-tech-spec-expert/SKILL.md +23 -7
- package/package.json +1 -1
- package/src/cli.js +27 -2
- package/src/installer.js +185 -106
- package/frameworks/agents/qa-validation-expert.md +0 -458
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.json +0 -99
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/benchmark.md +0 -64
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/response.md +0 -134
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/outputs/transcript.md +0 -68
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/with_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/response.md +0 -525
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/outputs/transcript.md +0 -30
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-1-happy-path/without_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/response.md +0 -1126
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/outputs/transcript.md +0 -131
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/with_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/response.md +0 -452
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/outputs/transcript.md +0 -78
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-2-spec-simples/without_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/response.md +0 -101
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/outputs/transcript.md +0 -133
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/with_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/response.md +0 -248
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/outputs/transcript.md +0 -49
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/eval-3-sem-user-stories/without_skill/timing.json +0 -5
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-1/review.html +0 -1325
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.json +0 -94
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/benchmark.md +0 -67
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/response.md +0 -117
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/outputs/transcript.md +0 -91
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/with_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/response.md +0 -694
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/outputs/transcript.md +0 -45
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-1-happy-path/without_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/response.md +0 -1087
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/outputs/transcript.md +0 -124
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/with_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/response.md +0 -458
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/outputs/transcript.md +0 -84
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-2-spec-simples/without_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/eval_metadata.json +0 -12
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/response.md +0 -70
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/outputs/transcript.md +0 -148
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/with_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/grading.json +0 -32
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/response.md +0 -249
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/outputs/transcript.md +0 -80
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/eval-3-sem-user-stories/without_skill/timing.json +0 -1
- package/frameworks/skills/sdd-task-plan-expert-workspace/iteration-2/review.html +0 -1325
|
@@ -20,6 +20,20 @@ Estilo: Objetivo. Contextualizado. Perguntas curtas com opções baseadas no cod
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
+
# Paths dos Artefatos
|
|
24
|
+
|
|
25
|
+
> **OBRIGATÓRIO**: Antes de salvar qualquer artefato, leia `.claude/config/ai-framework-config.yaml` seção `sdd` e use os paths ali definidos.
|
|
26
|
+
|
|
27
|
+
Paths definidos no config (para referência):
|
|
28
|
+
|
|
29
|
+
| Artefato | Path |
|
|
30
|
+
|----------|------|
|
|
31
|
+
| tech_direction | `docs/specs/{feature}/{version}/tech_direction.md` |
|
|
32
|
+
|
|
33
|
+
Substitua `{feature}` pelo nome da feature em kebab-case e `{version}` pela versão (ex: `v1`) identificados a partir do path do PRD recebido como argumento.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
23
37
|
# Regra de Acentuação
|
|
24
38
|
|
|
25
39
|
Todo artefato gerado por esta skill é um documento em português brasileiro. Todo conteúdo textual (títulos, descrições, instruções, regras, mensagens) deve usar acentuação correta do pt-BR:
|
|
@@ -188,7 +202,7 @@ Estas regras sao **absolutas** e nao podem ser violadas em nenhuma circunstancia
|
|
|
188
202
|
|
|
189
203
|
O Tech Direction e salvo **na mesma pasta** do PRD aprovado. O versionamento ja foi definido pelo PRD:
|
|
190
204
|
|
|
191
|
-
- Se o PRD esta em `docs/feature-x/v1/prd.md`, o tech_direction vai em `docs/feature-x/v1/tech_direction.md`
|
|
205
|
+
- Se o PRD esta em `docs/specs/feature-x/v1/prd.md`, o tech_direction vai em `docs/specs/feature-x/v1/tech_direction.md`
|
|
192
206
|
- **NAO crie nova versao** — use a mesma pasta do PRD fornecido como argumento
|
|
193
207
|
|
|
194
208
|
---
|
|
@@ -197,10 +211,11 @@ O Tech Direction e salvo **na mesma pasta** do PRD aprovado. O versionamento ja
|
|
|
197
211
|
|
|
198
212
|
**ANTES de apresentar o Tech Direction ao usuario**, voce DEVE:
|
|
199
213
|
|
|
200
|
-
1. **
|
|
201
|
-
2. **
|
|
202
|
-
3. **
|
|
203
|
-
4. **
|
|
214
|
+
1. **Ler o config** `.claude/config/ai-framework-config.yaml` secao `sdd.tech_direction` para obter o path
|
|
215
|
+
2. **Identificar o diretorio** do PRD fornecido (ex: `docs/specs/feature-x/v1/`)
|
|
216
|
+
3. **Remover todos os comentarios `<!-- LLM-ONLY: ... -->`** do conteudo antes de salvar
|
|
217
|
+
4. **Salvar o arquivo fisico** em: `docs/specs/[nome-feature]/[versao]/tech_direction.md` (mesmo diretorio do PRD)
|
|
218
|
+
5. **Confirmar** que o arquivo foi criado com sucesso
|
|
204
219
|
|
|
205
220
|
---
|
|
206
221
|
|
|
@@ -209,7 +224,7 @@ O Tech Direction e salvo **na mesma pasta** do PRD aprovado. O versionamento ja
|
|
|
209
224
|
Apos salvar o arquivo fisico, apresente **apenas um resumo compacto**. NAO exiba o tech_direction completo no terminal.
|
|
210
225
|
|
|
211
226
|
```
|
|
212
|
-
Arquivo salvo em: docs/[nome-feature]/
|
|
227
|
+
Arquivo salvo em: docs/specs/[nome-feature]/[versao]/tech_direction.md
|
|
213
228
|
|
|
214
229
|
## Resumo do Tech Direction
|
|
215
230
|
- **Decisoes:** [lista curta]
|
|
@@ -8,6 +8,22 @@ Responsabilidade: Transformar PRDs aprovados em especificações técnicas compl
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
# Paths dos Artefatos
|
|
12
|
+
|
|
13
|
+
> **OBRIGATÓRIO**: Antes de salvar qualquer artefato, leia `.claude/config/ai-framework-config.yaml` seção `sdd` e use os paths ali definidos.
|
|
14
|
+
|
|
15
|
+
Paths definidos no config (para referência):
|
|
16
|
+
|
|
17
|
+
| Artefato | Path |
|
|
18
|
+
|----------|------|
|
|
19
|
+
| prd (leitura) | `docs/specs/{feature}/{version}/prd.md` |
|
|
20
|
+
| tech_direction (leitura, opcional) | `docs/specs/{feature}/{version}/tech_direction.md` |
|
|
21
|
+
| spec_tech (escrita) | `docs/specs/{feature}/{version}/spec_tech.md` |
|
|
22
|
+
|
|
23
|
+
Substitua `{feature}` pelo nome da feature em kebab-case e `{version}` pela versão (ex: `v1`) identificados a partir do path do PRD recebido como argumento.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
11
27
|
# Regra de Acentuação
|
|
12
28
|
|
|
13
29
|
Todo artefato gerado por esta skill é um documento em português brasileiro. Todo conteúdo textual (títulos, descrições, instruções, regras, mensagens) deve usar acentuação correta do pt-BR:
|
|
@@ -57,7 +73,7 @@ O SPEC_TECH responde: **COMO a solução será implementada tecnicamente?**
|
|
|
57
73
|
**ANTES de definir o SPEC_TECH**, você DEVE obrigatoriamente:
|
|
58
74
|
|
|
59
75
|
### 1. Verificar Tech Direction (opcional)
|
|
60
|
-
- Buscar em: `docs/[nome-feature]/
|
|
76
|
+
- Buscar em: `docs/specs/[nome-feature]/[versão]/tech_direction.md` (onde vN é a versão mais recente)
|
|
61
77
|
- Se existir, **use como ponto de partida** para decisões técnicas
|
|
62
78
|
- O tech_direction contém decisões já tomadas, tecnologias sugeridas, padrões preferidos e restrições
|
|
63
79
|
- Você pode **complementar, ajustar ou questionar** qualquer item — não é uma ordem, é um direcionamento
|
|
@@ -107,7 +123,7 @@ O usuário pode criar um arquivo **`tech_direction.md`** na pasta da feature **a
|
|
|
107
123
|
|
|
108
124
|
### O que é
|
|
109
125
|
|
|
110
|
-
É um arquivo estruturado localizado em `docs/[nome-feature]/
|
|
126
|
+
É um arquivo estruturado localizado em `docs/specs/[nome-feature]/[versão]/tech_direction.md` com as seguintes seções:
|
|
111
127
|
|
|
112
128
|
| Seção | O que contém |
|
|
113
129
|
|-------|-------------|
|
|
@@ -124,7 +140,7 @@ O template completo está em: [tech_direction-template.md](templates/tech_direct
|
|
|
124
140
|
**ANTES de iniciar as perguntas**, você DEVE buscar o arquivo:
|
|
125
141
|
|
|
126
142
|
```
|
|
127
|
-
docs/[nome-feature]/
|
|
143
|
+
docs/specs/[nome-feature]/[versão]/tech_direction.md
|
|
128
144
|
```
|
|
129
145
|
|
|
130
146
|
- **Se existir**: use como ponto de partida para decisões técnicas
|
|
@@ -223,7 +239,7 @@ A seção 14 é preenchida pelo **comando orquestrador** (`/sdd:generate-spec-te
|
|
|
223
239
|
Após coletar todas as decisões:
|
|
224
240
|
1. Gere o SPEC_TECH completo (todas as 16 seções) usando as respostas coletadas
|
|
225
241
|
2. Preencha a seção 15 (Arquivos Envolvidos) baseado na pesquisa do codebase
|
|
226
|
-
3. **Salve o arquivo** em `docs/[nome-feature]/
|
|
242
|
+
3. **Salve o arquivo** em `docs/specs/[nome-feature]/[versão]/spec_tech.md`
|
|
227
243
|
4. Apresente ao usuário para validação final
|
|
228
244
|
|
|
229
245
|
### Regras do Processo
|
|
@@ -288,9 +304,9 @@ O template completo está em: [spec_tech_template.md](templates/spec_tech_templa
|
|
|
288
304
|
**ANTES de apresentar o SPEC_TECH ao usuário**, você DEVE:
|
|
289
305
|
|
|
290
306
|
1. **Identificar o nome da feature** a partir do PRD (kebab-case, letras minúsculas, sem espaços)
|
|
291
|
-
2. **Criar diretório** se não existir: `docs/[nome-feature]/
|
|
307
|
+
2. **Criar diretório** se não existir: `docs/specs/[nome-feature]/[versão]/`
|
|
292
308
|
3. **Remover todos os comentários `<!-- LLM-ONLY: ... -->`** do conteúdo antes de salvar — são instruções internas do template e NÃO devem aparecer no arquivo gerado
|
|
293
|
-
4. **Salvar o arquivo físico** em: `docs/[nome-feature]/
|
|
309
|
+
4. **Salvar o arquivo físico** em: `docs/specs/[nome-feature]/[versão]/spec_tech.md`
|
|
294
310
|
5. **Confirmar** que o arquivo foi criado com sucesso
|
|
295
311
|
|
|
296
312
|
---
|
|
@@ -300,7 +316,7 @@ O template completo está em: [spec_tech_template.md](templates/spec_tech_templa
|
|
|
300
316
|
Após salvar o arquivo físico:
|
|
301
317
|
|
|
302
318
|
```
|
|
303
|
-
Arquivo salvo em: docs/[nome-feature]/
|
|
319
|
+
Arquivo salvo em: docs/specs/[nome-feature]/[versão]/spec_tech.md
|
|
304
320
|
|
|
305
321
|
Essa especificação técnica está aprovada? (sim/não)
|
|
306
322
|
```
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -92,10 +92,35 @@ export async function run(argv) {
|
|
|
92
92
|
|
|
93
93
|
console.log(`\nInstalling to ${ideLabel} ...\n`);
|
|
94
94
|
|
|
95
|
-
const summary = await install({
|
|
95
|
+
const summary = await install({
|
|
96
|
+
cwd,
|
|
97
|
+
target,
|
|
98
|
+
frameworks,
|
|
99
|
+
confirmOverwrite: async (labels) => {
|
|
100
|
+
console.log(` Os seguintes ${labels.length} itens ja existem em ${ideLabel} e serao SOBRESCRITOS:\n`);
|
|
101
|
+
for (const l of labels) console.log(` - ${l}`);
|
|
102
|
+
console.log('');
|
|
103
|
+
const res = await prompts({
|
|
104
|
+
type: 'confirm',
|
|
105
|
+
name: 'ok',
|
|
106
|
+
message: 'Deseja continuar e sobrescrever?',
|
|
107
|
+
initial: true,
|
|
108
|
+
});
|
|
109
|
+
return res.ok === true;
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (summary.cancelled) {
|
|
114
|
+
console.log('\n Install cancelled.\n');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
96
117
|
|
|
97
118
|
console.log(` Done!\n`);
|
|
98
|
-
console.log(` ${summary.skills} skills + ${summary.commands} commands + ${summary.templates} templates + ${summary.agents} agents + ${summary.config} config installed
|
|
119
|
+
console.log(` ${summary.skills} skills + ${summary.commands} commands + ${summary.templates} templates + ${summary.agents} agents + ${summary.config} config installed.`);
|
|
120
|
+
if (summary.overwritten > 0) {
|
|
121
|
+
console.log(` ${summary.overwritten} item(s) sobrescritos.`);
|
|
122
|
+
}
|
|
123
|
+
console.log('');
|
|
99
124
|
|
|
100
125
|
// Usage hints
|
|
101
126
|
const hints = [];
|
package/src/installer.js
CHANGED
|
@@ -6,64 +6,176 @@ import { transformContent } from './transformer.js';
|
|
|
6
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
const FRAMEWORKS_DIR = join(__dirname, '..', 'frameworks');
|
|
8
8
|
|
|
9
|
-
const FRAMEWORK_MAP = {
|
|
10
|
-
sdd: {
|
|
11
|
-
commands: 'sdd',
|
|
12
|
-
skills: ['sdd-prd-expert', 'sdd-spec-tech-expert', 'sdd-task-plan-expert', 'sdd-qa-expert'],
|
|
13
|
-
},
|
|
14
|
-
ministack: {
|
|
15
|
-
commands: 'ministack',
|
|
16
|
-
skills: ['ministack-intent-expert', 'ministack-scope-expert', 'ministack-expert', 'ministack-qa-expert'],
|
|
17
|
-
},
|
|
18
|
-
taskcard: {
|
|
19
|
-
commands: 'taskcard',
|
|
20
|
-
skills: ['taskcard-expert', 'taskcard-qa-expert'],
|
|
21
|
-
},
|
|
22
|
-
shared: {
|
|
23
|
-
commands: null, // root-level commands
|
|
24
|
-
skills: [],
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
|
|
28
9
|
const IDE_DIRS = {
|
|
29
10
|
claude: '.claude',
|
|
30
11
|
cursor: '.cursor',
|
|
31
12
|
};
|
|
32
13
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
14
|
+
// Prefixos usados para rotear skills e commands ao framework correto.
|
|
15
|
+
// Qualquer skill sem prefixo conhecido vai para 'shared'.
|
|
16
|
+
const FRAMEWORK_PREFIXES = {
|
|
17
|
+
sdd: 'sdd',
|
|
18
|
+
ministack: 'ministack',
|
|
19
|
+
taskcard: 'taskcard',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
async function exists(path) {
|
|
23
|
+
try {
|
|
24
|
+
await stat(path);
|
|
25
|
+
return true;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function listDirs(dir) {
|
|
32
|
+
if (!(await exists(dir))) return [];
|
|
33
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
34
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function listFiles(dir) {
|
|
38
|
+
if (!(await exists(dir))) return [];
|
|
39
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
40
|
+
return entries.filter((e) => e.isFile()).map((e) => e.name);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function skillFramework(skillName) {
|
|
44
|
+
for (const [fw, prefix] of Object.entries(FRAMEWORK_PREFIXES)) {
|
|
45
|
+
if (skillName === prefix || skillName.startsWith(prefix + '-')) return fw;
|
|
46
|
+
}
|
|
47
|
+
return 'shared';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function copyFile(src, dest, target) {
|
|
51
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
52
|
+
if (src.endsWith('.md')) {
|
|
53
|
+
const content = await readFile(src, 'utf-8');
|
|
54
|
+
const transformed = transformContent(content, target);
|
|
55
|
+
await writeFile(dest, transformed, 'utf-8');
|
|
56
|
+
} else {
|
|
57
|
+
const content = await readFile(src);
|
|
58
|
+
await writeFile(dest, content);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
36
62
|
async function copyDir(src, dest, target) {
|
|
37
63
|
await mkdir(dest, { recursive: true });
|
|
38
64
|
const entries = await readdir(src, { withFileTypes: true });
|
|
39
|
-
|
|
40
65
|
for (const entry of entries) {
|
|
41
66
|
const srcPath = join(src, entry.name);
|
|
42
67
|
const destPath = join(dest, entry.name);
|
|
43
|
-
|
|
44
68
|
if (entry.isDirectory()) {
|
|
45
69
|
await copyDir(srcPath, destPath, target);
|
|
46
|
-
} else if (entry.name.endsWith('.md')) {
|
|
47
|
-
const content = await readFile(srcPath, 'utf-8');
|
|
48
|
-
const transformed = transformContent(content, target);
|
|
49
|
-
await writeFile(destPath, transformed, 'utf-8');
|
|
50
70
|
} else {
|
|
51
|
-
|
|
52
|
-
await writeFile(destPath, content);
|
|
71
|
+
await copyFile(srcPath, destPath, target);
|
|
53
72
|
}
|
|
54
73
|
}
|
|
55
74
|
}
|
|
56
75
|
|
|
76
|
+
async function countMarkdownRecursive(dir) {
|
|
77
|
+
let count = 0;
|
|
78
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const full = join(dir, entry.name);
|
|
81
|
+
if (entry.isDirectory()) count += await countMarkdownRecursive(full);
|
|
82
|
+
else if (entry.name.endsWith('.md')) count++;
|
|
83
|
+
}
|
|
84
|
+
return count;
|
|
85
|
+
}
|
|
86
|
+
|
|
57
87
|
/**
|
|
58
|
-
*
|
|
88
|
+
* Constroi o plano de instalacao varrendo frameworks/ e mapeando cada item
|
|
89
|
+
* (skill, command, agent, template, config) para seu destino no IDE.
|
|
90
|
+
* Cada item e marcado com `overwrite: true` se o destino ja existir.
|
|
59
91
|
*/
|
|
60
|
-
async function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
92
|
+
async function buildPlan({ cwd, target, frameworks }) {
|
|
93
|
+
const ideDir = join(cwd, IDE_DIRS[target]);
|
|
94
|
+
const selected = new Set(frameworks);
|
|
95
|
+
const items = [];
|
|
96
|
+
|
|
97
|
+
// Skills: detectadas automaticamente por prefixo
|
|
98
|
+
const skillNames = await listDirs(join(FRAMEWORKS_DIR, 'skills'));
|
|
99
|
+
for (const name of skillNames) {
|
|
100
|
+
const fw = skillFramework(name);
|
|
101
|
+
if (!selected.has(fw)) continue;
|
|
102
|
+
items.push({
|
|
103
|
+
category: 'skills',
|
|
104
|
+
kind: 'dir',
|
|
105
|
+
src: join(FRAMEWORKS_DIR, 'skills', name),
|
|
106
|
+
dest: join(ideDir, 'skills', name),
|
|
107
|
+
label: `skills/${name}`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Commands: subdir por framework + arquivos root-level para 'shared'
|
|
112
|
+
const commandDirs = await listDirs(join(FRAMEWORKS_DIR, 'commands'));
|
|
113
|
+
for (const name of commandDirs) {
|
|
114
|
+
if (!FRAMEWORK_PREFIXES[name] || !selected.has(name)) continue;
|
|
115
|
+
items.push({
|
|
116
|
+
category: 'commands',
|
|
117
|
+
kind: 'dir',
|
|
118
|
+
src: join(FRAMEWORKS_DIR, 'commands', name),
|
|
119
|
+
dest: join(ideDir, 'commands', name),
|
|
120
|
+
label: `commands/${name}/`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
if (selected.has('shared')) {
|
|
124
|
+
const rootCmds = await listFiles(join(FRAMEWORKS_DIR, 'commands'));
|
|
125
|
+
for (const name of rootCmds) {
|
|
126
|
+
if (!name.endsWith('.md')) continue;
|
|
127
|
+
items.push({
|
|
128
|
+
category: 'commands',
|
|
129
|
+
kind: 'file',
|
|
130
|
+
src: join(FRAMEWORKS_DIR, 'commands', name),
|
|
131
|
+
dest: join(ideDir, 'commands', name),
|
|
132
|
+
label: `commands/${name}`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Agents, templates, config: pertencem a 'shared'
|
|
138
|
+
if (selected.has('shared')) {
|
|
139
|
+
for (const name of await listFiles(join(FRAMEWORKS_DIR, 'agents'))) {
|
|
140
|
+
if (!name.endsWith('.md')) continue;
|
|
141
|
+
items.push({
|
|
142
|
+
category: 'agents',
|
|
143
|
+
kind: 'file',
|
|
144
|
+
src: join(FRAMEWORKS_DIR, 'agents', name),
|
|
145
|
+
dest: join(ideDir, 'agents', name),
|
|
146
|
+
label: `agents/${name}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
for (const name of await listFiles(join(FRAMEWORKS_DIR, 'templates'))) {
|
|
150
|
+
if (!name.endsWith('.md')) continue;
|
|
151
|
+
items.push({
|
|
152
|
+
category: 'templates',
|
|
153
|
+
kind: 'file',
|
|
154
|
+
src: join(FRAMEWORKS_DIR, 'templates', name),
|
|
155
|
+
dest: join(ideDir, 'templates', name),
|
|
156
|
+
label: `templates/${name}`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
for (const name of await listFiles(join(FRAMEWORKS_DIR, 'config'))) {
|
|
160
|
+
items.push({
|
|
161
|
+
category: 'config',
|
|
162
|
+
kind: 'file',
|
|
163
|
+
src: join(FRAMEWORKS_DIR, 'config', name),
|
|
164
|
+
dest: join(ideDir, 'config', name),
|
|
165
|
+
label: `config/${name}`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (const item of items) {
|
|
171
|
+
item.overwrite = await exists(item.dest);
|
|
66
172
|
}
|
|
173
|
+
|
|
174
|
+
return { ideDir, items };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function planInstall(options) {
|
|
178
|
+
return buildPlan(options);
|
|
67
179
|
}
|
|
68
180
|
|
|
69
181
|
/**
|
|
@@ -73,81 +185,48 @@ async function exists(path) {
|
|
|
73
185
|
* @param {string} options.cwd - Current working directory
|
|
74
186
|
* @param {'claude'|'cursor'} options.target - Target IDE
|
|
75
187
|
* @param {string[]} options.frameworks - Frameworks to install ('sdd', 'ministack', 'taskcard', 'shared')
|
|
76
|
-
* @
|
|
188
|
+
* @param {(labels: string[]) => Promise<boolean>} [options.confirmOverwrite] - Called when items will be overwritten
|
|
189
|
+
* @returns {Object} Summary of installed items (or { cancelled: true })
|
|
77
190
|
*/
|
|
78
|
-
export async function install({ cwd, target, frameworks }) {
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const skillsDir = join(ideDir, 'skills');
|
|
82
|
-
const templatesDir = join(ideDir, 'templates');
|
|
83
|
-
const agentsDir = join(ideDir, 'agents');
|
|
84
|
-
|
|
85
|
-
const summary = { commands: 0, skills: 0, templates: 0, agents: 0, config: 0 };
|
|
86
|
-
|
|
87
|
-
for (const fw of frameworks) {
|
|
88
|
-
const config = FRAMEWORK_MAP[fw];
|
|
89
|
-
if (!config) continue;
|
|
90
|
-
|
|
91
|
-
// Copy commands
|
|
92
|
-
if (fw === 'shared') {
|
|
93
|
-
// Root-level commands (generate-prompt.md, sync-tasks-to-linear.md)
|
|
94
|
-
await mkdir(commandsDir, { recursive: true });
|
|
95
|
-
const srcCmds = join(FRAMEWORKS_DIR, 'commands');
|
|
96
|
-
const entries = await readdir(srcCmds, { withFileTypes: true });
|
|
97
|
-
|
|
98
|
-
for (const entry of entries) {
|
|
99
|
-
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
100
|
-
const content = await readFile(join(srcCmds, entry.name), 'utf-8');
|
|
101
|
-
const transformed = transformContent(content, target);
|
|
102
|
-
await writeFile(join(commandsDir, entry.name), transformed, 'utf-8');
|
|
103
|
-
summary.commands++;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
191
|
+
export async function install({ cwd, target, frameworks, confirmOverwrite }) {
|
|
192
|
+
const plan = await buildPlan({ cwd, target, frameworks });
|
|
193
|
+
const overwrites = plan.items.filter((i) => i.overwrite);
|
|
106
194
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const tplEntries = await readdir(srcTemplates);
|
|
112
|
-
summary.templates += tplEntries.filter((f) => f.endsWith('.md')).length;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Shared agents
|
|
116
|
-
const srcAgents = join(FRAMEWORKS_DIR, 'agents');
|
|
117
|
-
if (await exists(srcAgents)) {
|
|
118
|
-
await copyDir(srcAgents, agentsDir, target);
|
|
119
|
-
const agentEntries = await readdir(srcAgents);
|
|
120
|
-
summary.agents += agentEntries.filter((f) => f.endsWith('.md')).length;
|
|
121
|
-
}
|
|
195
|
+
if (overwrites.length > 0 && typeof confirmOverwrite === 'function') {
|
|
196
|
+
const ok = await confirmOverwrite(overwrites.map((i) => i.label));
|
|
197
|
+
if (!ok) return { cancelled: true };
|
|
198
|
+
}
|
|
122
199
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
200
|
+
const summary = {
|
|
201
|
+
skills: 0,
|
|
202
|
+
commands: 0,
|
|
203
|
+
templates: 0,
|
|
204
|
+
agents: 0,
|
|
205
|
+
config: 0,
|
|
206
|
+
overwritten: overwrites.length,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
for (const item of plan.items) {
|
|
210
|
+
if (item.kind === 'dir') {
|
|
211
|
+
await copyDir(item.src, item.dest, target);
|
|
132
212
|
} else {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const srcCmdDir = join(FRAMEWORKS_DIR, 'commands', config.commands);
|
|
136
|
-
const destCmdDir = join(commandsDir, config.commands);
|
|
137
|
-
await copyDir(srcCmdDir, destCmdDir, target);
|
|
138
|
-
const entries = await readdir(srcCmdDir);
|
|
139
|
-
summary.commands += entries.filter((f) => f.endsWith('.md')).length;
|
|
140
|
-
}
|
|
213
|
+
await copyFile(item.src, item.dest, target);
|
|
214
|
+
}
|
|
141
215
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
216
|
+
if (item.category === 'skills') {
|
|
217
|
+
summary.skills++;
|
|
218
|
+
} else if (item.category === 'commands') {
|
|
219
|
+
if (item.kind === 'dir') {
|
|
220
|
+
summary.commands += await countMarkdownRecursive(item.src);
|
|
221
|
+
} else {
|
|
222
|
+
summary.commands++;
|
|
150
223
|
}
|
|
224
|
+
} else if (item.category === 'agents') {
|
|
225
|
+
summary.agents++;
|
|
226
|
+
} else if (item.category === 'templates') {
|
|
227
|
+
summary.templates++;
|
|
228
|
+
} else if (item.category === 'config') {
|
|
229
|
+
summary.config++;
|
|
151
230
|
}
|
|
152
231
|
}
|
|
153
232
|
|