maestro-bundle 1.0.0 → 1.1.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 +54 -62
- package/package.json +1 -1
- package/src/cli.mjs +301 -114
package/README.md
CHANGED
|
@@ -1,91 +1,83 @@
|
|
|
1
1
|
# maestro-bundle
|
|
2
2
|
|
|
3
|
-
Um comando. Bundle instalado. Agente governado.
|
|
3
|
+
Um comando. Bundle instalado. Agente governado. Funciona com **qualquer editor AI**.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npx maestro-bundle ai-agents
|
|
6
|
+
npx maestro-bundle ai-agents claude
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- `AGENTS.md` na raiz (compatível com Cursor, Claude Code, Copilot, Windsurf, etc.)
|
|
11
|
-
- `skills/` com todas as skills do bundle
|
|
12
|
-
- `.spec/constitution.md` do GitHub Spec Kit
|
|
13
|
-
- `references/` com docs de referência
|
|
14
|
-
- Instala o GitHub Spec Kit se necessário
|
|
9
|
+
## Editores suportados
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
npx maestro-bundle
|
|
20
|
-
npx maestro-bundle
|
|
21
|
-
npx maestro-bundle
|
|
22
|
-
npx maestro-bundle
|
|
23
|
-
npx maestro-bundle
|
|
24
|
-
```
|
|
11
|
+
| Editor | Comando | O que instala |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **Claude Code** | `npx maestro-bundle <bundle> claude` | `CLAUDE.md` + `.claude/rules/` |
|
|
14
|
+
| **Cursor** | `npx maestro-bundle <bundle> cursor` | `.cursorrules` + `.cursor/rules/` |
|
|
15
|
+
| **OpenAI Codex** | `npx maestro-bundle <bundle> codex` | `AGENTS.md` |
|
|
16
|
+
| **GitHub Copilot** | `npx maestro-bundle <bundle> copilot` | `.github/copilot-instructions.md` + `.github/instructions/` |
|
|
17
|
+
| **Windsurf** | `npx maestro-bundle <bundle> windsurf` | `.windsurfrules` |
|
|
18
|
+
| **Todos** | `npx maestro-bundle <bundle> all` | Tudo acima de uma vez |
|
|
25
19
|
|
|
26
|
-
##
|
|
20
|
+
## Bundles disponíveis
|
|
27
21
|
|
|
28
22
|
```bash
|
|
29
|
-
#
|
|
30
|
-
npx maestro-bundle
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
npx maestro-bundle
|
|
34
|
-
|
|
35
|
-
# Ver bundles disponíveis
|
|
36
|
-
npx maestro-bundle --help
|
|
23
|
+
npx maestro-bundle ai-agents claude # Agentes AI com LangChain
|
|
24
|
+
npx maestro-bundle jhipster-monorepo cursor # JHipster monolítico
|
|
25
|
+
npx maestro-bundle jhipster-microservices all # JHipster microsserviços
|
|
26
|
+
npx maestro-bundle data-pipeline codex # Pipeline dados/ML
|
|
27
|
+
npx maestro-bundle frontend-spa copilot # React SPA
|
|
37
28
|
```
|
|
38
29
|
|
|
39
30
|
## O que acontece
|
|
40
31
|
|
|
41
32
|
```
|
|
42
|
-
$ npx maestro-bundle ai-agents
|
|
33
|
+
$ npx maestro-bundle ai-agents all
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
Bundle: Sistema Multi-Agente com AI
|
|
36
|
+
Editor: Claude Code, Cursor, OpenAI Codex, GitHub Copilot, Windsurf
|
|
46
37
|
|
|
47
|
-
✔
|
|
48
|
-
✔
|
|
49
|
-
✔
|
|
50
|
-
✔ .
|
|
51
|
-
✔
|
|
52
|
-
✔
|
|
53
|
-
✔ Spec Kit
|
|
38
|
+
✔ Claude Code: CLAUDE.md + AGENTS.md, 14 rules em .claude/rules/
|
|
39
|
+
✔ Cursor: .cursorrules, 14 rules em .cursor/rules/
|
|
40
|
+
✔ OpenAI Codex: AGENTS.md
|
|
41
|
+
✔ GitHub Copilot: .github/copilot-instructions.md, 14 rules em .github/instructions/
|
|
42
|
+
✔ Windsurf: .windsurfrules
|
|
43
|
+
✔ 14 skills canônicas
|
|
44
|
+
✔ .spec/constitution.md (GitHub Spec Kit)
|
|
45
|
+
✔ Spec Kit instalado
|
|
54
46
|
|
|
55
47
|
Pronto!
|
|
56
|
-
|
|
57
|
-
Arquivos instalados:
|
|
58
|
-
AGENTS.md Comportamento do agente (qualquer editor AI)
|
|
59
|
-
.spec/constitution.md Princípios do projeto (GitHub Spec Kit)
|
|
60
|
-
skills/ (14 skills) Capacidades do agente
|
|
61
|
-
references/ Documentos de referência
|
|
62
|
-
|
|
63
|
-
Próximos passos:
|
|
64
|
-
1. Abra o projeto no seu editor AI (Cursor, Claude Code, Copilot, etc.)
|
|
65
|
-
2. O agente já conhece os padrões do projeto
|
|
66
|
-
3. Para nova demanda: /speckit.specify
|
|
67
48
|
```
|
|
68
49
|
|
|
69
|
-
##
|
|
50
|
+
## Onde cada editor procura
|
|
70
51
|
|
|
71
52
|
```
|
|
72
53
|
seu-projeto/
|
|
73
|
-
├──
|
|
74
|
-
├── .
|
|
75
|
-
|
|
76
|
-
├──
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
54
|
+
├── CLAUDE.md ← Claude Code
|
|
55
|
+
├── AGENTS.md ← Codex, agents.md universal
|
|
56
|
+
├── .cursorrules ← Cursor
|
|
57
|
+
├── .windsurfrules ← Windsurf
|
|
58
|
+
├── .claude/rules/*.md ← Claude Code (skills como rules)
|
|
59
|
+
├── .cursor/rules/*.md ← Cursor (skills como rules)
|
|
60
|
+
├── .github/copilot-instructions.md ← Copilot
|
|
61
|
+
├── .github/instructions/*.instructions.md ← Copilot (skills)
|
|
62
|
+
├── .spec/constitution.md ← GitHub Spec Kit (SDD)
|
|
63
|
+
├── skills/ ← Canônicas (Deep Agents, referência)
|
|
64
|
+
│ ├── rag-pipeline/SKILL.md
|
|
65
|
+
│ ├── clean-architecture/SKILL.md
|
|
81
66
|
│ └── ...
|
|
82
|
-
|
|
83
|
-
│ └── ...
|
|
84
|
-
└── src/
|
|
67
|
+
└── references/ ← Docs sob demanda
|
|
85
68
|
```
|
|
86
69
|
|
|
87
|
-
##
|
|
70
|
+
## Uso avançado
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Instalar em diretório específico
|
|
74
|
+
npx maestro-bundle jhipster-monorepo cursor ./meu-projeto
|
|
75
|
+
|
|
76
|
+
# Ver bundles e editores disponíveis
|
|
77
|
+
npx maestro-bundle --help
|
|
78
|
+
```
|
|
88
79
|
|
|
89
|
-
|
|
80
|
+
## Links
|
|
90
81
|
|
|
91
|
-
|
|
82
|
+
- [AGENTS.md spec](https://agents.md/) — Padrão universal para instruções de agentes
|
|
83
|
+
- [GitHub Spec Kit](https://github.com/github/spec-kit) — SDD (Specification-Driven Development)
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -9,183 +9,353 @@ import ora from "ora";
|
|
|
9
9
|
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
|
|
12
|
+
// ============================================================
|
|
13
|
+
// BUNDLES
|
|
14
|
+
// ============================================================
|
|
12
15
|
const BUNDLES = {
|
|
13
16
|
"ai-agents": {
|
|
14
17
|
name: "Sistema Multi-Agente com AI",
|
|
15
|
-
|
|
18
|
+
desc: "Python + LangChain + LangGraph + FastAPI + pgvector",
|
|
16
19
|
},
|
|
17
20
|
"jhipster-monorepo": {
|
|
18
21
|
name: "JHipster Monorepo",
|
|
19
|
-
|
|
22
|
+
desc: "Java 21 + Spring Boot + Angular + PostgreSQL + Liquibase",
|
|
20
23
|
},
|
|
21
24
|
"jhipster-microservices": {
|
|
22
25
|
name: "JHipster Microservices",
|
|
23
|
-
|
|
26
|
+
desc: "Java 21 + Spring Boot + Angular + Kafka + Consul + K8s",
|
|
24
27
|
},
|
|
25
28
|
"data-pipeline": {
|
|
26
29
|
name: "Pipeline de Dados e ML",
|
|
27
|
-
|
|
30
|
+
desc: "Python + Pandas + Scikit-learn + MLflow + Airflow",
|
|
28
31
|
},
|
|
29
32
|
"frontend-spa": {
|
|
30
33
|
name: "Frontend SPA",
|
|
31
|
-
|
|
34
|
+
desc: "React + TypeScript + Tailwind + Vite",
|
|
32
35
|
},
|
|
33
36
|
};
|
|
34
37
|
|
|
38
|
+
// ============================================================
|
|
39
|
+
// EDITORS — paths corretos para cada editor
|
|
40
|
+
//
|
|
41
|
+
// Claude Code:
|
|
42
|
+
// Instruções: CLAUDE.md (raiz) com @AGENTS.md
|
|
43
|
+
// Skills: .claude/skills/<nome>/SKILL.md
|
|
44
|
+
// Rules: .claude/rules/<nome>.md
|
|
45
|
+
//
|
|
46
|
+
// Cursor:
|
|
47
|
+
// Instruções: .cursor/rules/ (rules .mdc ou .md)
|
|
48
|
+
// Também lê: AGENTS.md (raiz)
|
|
49
|
+
//
|
|
50
|
+
// Codex (OpenAI):
|
|
51
|
+
// Instruções: AGENTS.md (raiz)
|
|
52
|
+
// Sem pasta de skills/rules
|
|
53
|
+
//
|
|
54
|
+
// Copilot:
|
|
55
|
+
// Instruções: .github/copilot-instructions.md
|
|
56
|
+
// Rules: .github/instructions/<nome>.instructions.md
|
|
57
|
+
//
|
|
58
|
+
// Windsurf:
|
|
59
|
+
// Instruções: .windsurfrules (raiz)
|
|
60
|
+
// Sem pasta de skills/rules
|
|
61
|
+
// ============================================================
|
|
62
|
+
const EDITORS = {
|
|
63
|
+
claude: {
|
|
64
|
+
name: "Claude Code",
|
|
65
|
+
instructionsFile: "CLAUDE.md",
|
|
66
|
+
skillsDir: ".claude/skills", // Skills como SKILL.md com frontmatter
|
|
67
|
+
rulesDir: ".claude/rules", // Rules curtas (padrões gerais)
|
|
68
|
+
needsAgentsMd: true, // CLAUDE.md faz @AGENTS.md
|
|
69
|
+
},
|
|
70
|
+
cursor: {
|
|
71
|
+
name: "Cursor",
|
|
72
|
+
instructionsFile: null, // Cursor lê AGENTS.md + .cursor/rules/
|
|
73
|
+
skillsDir: null,
|
|
74
|
+
rulesDir: ".cursor/rules", // Rules como .mdc com frontmatter
|
|
75
|
+
needsAgentsMd: true, // Cursor lê AGENTS.md na raiz
|
|
76
|
+
},
|
|
77
|
+
codex: {
|
|
78
|
+
name: "OpenAI Codex",
|
|
79
|
+
instructionsFile: "AGENTS.md",
|
|
80
|
+
skillsDir: null,
|
|
81
|
+
rulesDir: null,
|
|
82
|
+
needsAgentsMd: false, // AGENTS.md É o arquivo principal
|
|
83
|
+
},
|
|
84
|
+
copilot: {
|
|
85
|
+
name: "GitHub Copilot",
|
|
86
|
+
instructionsFile: ".github/copilot-instructions.md",
|
|
87
|
+
skillsDir: null,
|
|
88
|
+
rulesDir: ".github/instructions", // .instructions.md com frontmatter
|
|
89
|
+
needsAgentsMd: false,
|
|
90
|
+
},
|
|
91
|
+
windsurf: {
|
|
92
|
+
name: "Windsurf",
|
|
93
|
+
instructionsFile: ".windsurfrules",
|
|
94
|
+
skillsDir: null,
|
|
95
|
+
rulesDir: null,
|
|
96
|
+
needsAgentsMd: false,
|
|
97
|
+
},
|
|
98
|
+
all: {
|
|
99
|
+
name: "Todos os editores",
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// ============================================================
|
|
104
|
+
// HELP
|
|
105
|
+
// ============================================================
|
|
35
106
|
function showHelp() {
|
|
36
107
|
console.log("");
|
|
37
108
|
console.log(chalk.bold(" maestro-bundle") + " — Instala bundles de governança para projetos com AI");
|
|
38
109
|
console.log("");
|
|
39
110
|
console.log(chalk.dim(" Uso:"));
|
|
40
|
-
console.log(` npx maestro-bundle ${chalk.green("<bundle>")} ${chalk.dim("[diretório]")}`);
|
|
41
|
-
console.log("");
|
|
42
|
-
console.log(chalk.dim(" Bundles disponíveis:"));
|
|
111
|
+
console.log(` npx maestro-bundle ${chalk.green("<bundle>")} ${chalk.yellow("<editor>")} ${chalk.dim("[diretório]")}`);
|
|
43
112
|
console.log("");
|
|
113
|
+
console.log(chalk.dim(" Bundles:"));
|
|
44
114
|
for (const [key, info] of Object.entries(BUNDLES)) {
|
|
45
|
-
console.log(` ${chalk.green(key.padEnd(26))} ${info.
|
|
46
|
-
console.log(` ${"".padEnd(26)} ${chalk.dim(info.description)}`);
|
|
47
|
-
console.log("");
|
|
115
|
+
console.log(` ${chalk.green(key.padEnd(26))} ${info.desc}`);
|
|
48
116
|
}
|
|
117
|
+
console.log("");
|
|
118
|
+
console.log(chalk.dim(" Editores:"));
|
|
119
|
+
console.log(` ${chalk.yellow("claude".padEnd(12))} CLAUDE.md + .claude/skills/ + .claude/rules/`);
|
|
120
|
+
console.log(` ${chalk.yellow("cursor".padEnd(12))} AGENTS.md + .cursor/rules/*.mdc`);
|
|
121
|
+
console.log(` ${chalk.yellow("codex".padEnd(12))} AGENTS.md (tudo em um arquivo)`);
|
|
122
|
+
console.log(` ${chalk.yellow("copilot".padEnd(12))} .github/copilot-instructions.md + .github/instructions/`);
|
|
123
|
+
console.log(` ${chalk.yellow("windsurf".padEnd(12))} .windsurfrules (tudo em um arquivo)`);
|
|
124
|
+
console.log(` ${chalk.yellow("all".padEnd(12))} Instala para todos os editores no mesmo repo`);
|
|
125
|
+
console.log("");
|
|
49
126
|
console.log(chalk.dim(" Exemplos:"));
|
|
50
|
-
console.log(` npx maestro-bundle ai-agents`);
|
|
51
|
-
console.log(` npx maestro-bundle jhipster-monorepo ./meu-projeto`);
|
|
52
|
-
console.log(` npx maestro-bundle frontend-spa
|
|
127
|
+
console.log(` npx maestro-bundle ai-agents claude`);
|
|
128
|
+
console.log(` npx maestro-bundle jhipster-monorepo cursor ./meu-projeto`);
|
|
129
|
+
console.log(` npx maestro-bundle frontend-spa all`);
|
|
53
130
|
console.log("");
|
|
54
131
|
}
|
|
55
132
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
133
|
+
// ============================================================
|
|
134
|
+
// UTILS
|
|
135
|
+
// ============================================================
|
|
136
|
+
function ensureDir(dir) { mkdirSync(dir, { recursive: true }); }
|
|
137
|
+
function copyDir(src, dest) { if (existsSync(src)) cpSync(src, dest, { recursive: true }); }
|
|
138
|
+
function readFile(path) { return existsSync(path) ? readFileSync(path, "utf-8") : ""; }
|
|
139
|
+
|
|
140
|
+
function getSkillDirs(templatesDir, bundleName) {
|
|
141
|
+
const baseSkills = join(templatesDir, "bundle-base", "skills");
|
|
142
|
+
const bundleSkills = join(templatesDir, `bundle-${bundleName}`, "skills");
|
|
143
|
+
return [baseSkills, bundleSkills].filter(existsSync);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function listSkills(skillDirs) {
|
|
147
|
+
const skills = [];
|
|
148
|
+
for (const dir of skillDirs) {
|
|
149
|
+
for (const item of readdirSync(dir, { withFileTypes: true })) {
|
|
150
|
+
if (item.isDirectory() && existsSync(join(dir, item.name, "SKILL.md"))) {
|
|
151
|
+
skills.push({ name: item.name, dir: join(dir, item.name) });
|
|
152
|
+
}
|
|
63
153
|
}
|
|
64
154
|
}
|
|
65
|
-
return
|
|
155
|
+
return skills;
|
|
66
156
|
}
|
|
67
157
|
|
|
158
|
+
// ============================================================
|
|
159
|
+
// INSTALL PER EDITOR
|
|
160
|
+
// ============================================================
|
|
161
|
+
function installForEditor(editorKey, agentsMd, skills, targetDir) {
|
|
162
|
+
const editor = EDITORS[editorKey];
|
|
163
|
+
const installed = [];
|
|
164
|
+
|
|
165
|
+
// --- AGENTS.md (universal) ---
|
|
166
|
+
if (editor.needsAgentsMd || editorKey === "codex") {
|
|
167
|
+
writeFileSync(join(targetDir, "AGENTS.md"), agentsMd);
|
|
168
|
+
installed.push("AGENTS.md");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// --- Arquivo de instruções principal ---
|
|
172
|
+
if (editor.instructionsFile) {
|
|
173
|
+
const filePath = join(targetDir, editor.instructionsFile);
|
|
174
|
+
ensureDir(dirname(filePath));
|
|
175
|
+
|
|
176
|
+
if (editorKey === "claude") {
|
|
177
|
+
// CLAUDE.md aponta para @AGENTS.md (sem duplicar conteúdo)
|
|
178
|
+
writeFileSync(filePath, "@AGENTS.md\n");
|
|
179
|
+
installed.push("CLAUDE.md → @AGENTS.md");
|
|
180
|
+
} else if (editorKey === "codex") {
|
|
181
|
+
// AGENTS.md já foi escrito acima
|
|
182
|
+
} else {
|
|
183
|
+
// Copilot, Windsurf: copiar conteúdo completo
|
|
184
|
+
writeFileSync(filePath, agentsMd);
|
|
185
|
+
installed.push(editor.instructionsFile);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// --- Skills (Claude Code: .claude/skills/<nome>/SKILL.md) ---
|
|
190
|
+
if (editor.skillsDir) {
|
|
191
|
+
const skillsPath = join(targetDir, editor.skillsDir);
|
|
192
|
+
ensureDir(skillsPath);
|
|
193
|
+
for (const skill of skills) {
|
|
194
|
+
const destDir = join(skillsPath, skill.name);
|
|
195
|
+
copyDir(skill.dir, destDir);
|
|
196
|
+
}
|
|
197
|
+
installed.push(`${skills.length} skills em ${editor.skillsDir}/`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// --- Rules por editor ---
|
|
201
|
+
if (editor.rulesDir) {
|
|
202
|
+
const rulesPath = join(targetDir, editor.rulesDir);
|
|
203
|
+
ensureDir(rulesPath);
|
|
204
|
+
|
|
205
|
+
for (const skill of skills) {
|
|
206
|
+
const content = readFileSync(join(skill.dir, "SKILL.md"), "utf-8");
|
|
207
|
+
|
|
208
|
+
if (editorKey === "cursor") {
|
|
209
|
+
// Cursor: .mdc com frontmatter (description + globs)
|
|
210
|
+
// Extrair frontmatter existente e converter
|
|
211
|
+
const parsed = parseFrontmatter(content);
|
|
212
|
+
const cursorContent = [
|
|
213
|
+
"---",
|
|
214
|
+
`description: "${parsed.description || skill.name}"`,
|
|
215
|
+
`alwaysApply: false`,
|
|
216
|
+
"---",
|
|
217
|
+
"",
|
|
218
|
+
parsed.body,
|
|
219
|
+
].join("\n");
|
|
220
|
+
writeFileSync(join(rulesPath, `${skill.name}.mdc`), cursorContent);
|
|
221
|
+
|
|
222
|
+
} else if (editorKey === "copilot") {
|
|
223
|
+
// Copilot: .instructions.md
|
|
224
|
+
writeFileSync(join(rulesPath, `${skill.name}.instructions.md`), content);
|
|
225
|
+
|
|
226
|
+
} else if (editorKey === "claude") {
|
|
227
|
+
// Claude rules: regras curtas derivadas do AGENTS.md
|
|
228
|
+
// Skills já vão em .claude/skills/, rules é só para padrões gerais
|
|
229
|
+
// Não duplicar skills como rules
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (editorKey !== "claude") {
|
|
234
|
+
const ruleFiles = readdirSync(rulesPath).length;
|
|
235
|
+
installed.push(`${ruleFiles} rules em ${editor.rulesDir}/`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return installed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function parseFrontmatter(content) {
|
|
243
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
244
|
+
if (!match) return { description: "", body: content };
|
|
245
|
+
|
|
246
|
+
const fm = match[1];
|
|
247
|
+
const body = match[2];
|
|
248
|
+
const descMatch = fm.match(/description:\s*(.+)/);
|
|
249
|
+
const description = descMatch ? descMatch[1].trim() : "";
|
|
250
|
+
return { description, body };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// ============================================================
|
|
254
|
+
// MAIN
|
|
255
|
+
// ============================================================
|
|
68
256
|
async function main() {
|
|
69
257
|
const args = process.argv.slice(2);
|
|
70
258
|
|
|
71
|
-
if (args.length
|
|
259
|
+
if (args.length < 2 || args.includes("--help") || args.includes("-h")) {
|
|
72
260
|
showHelp();
|
|
73
|
-
process.exit(0);
|
|
261
|
+
process.exit(args.length < 2 && !args.includes("--help") ? 1 : 0);
|
|
74
262
|
}
|
|
75
263
|
|
|
76
264
|
const bundleName = args[0];
|
|
77
|
-
const
|
|
265
|
+
const editorArg = args[1];
|
|
266
|
+
const targetDir = resolve(args[2] || ".");
|
|
78
267
|
|
|
79
268
|
if (!BUNDLES[bundleName]) {
|
|
80
269
|
console.error(chalk.red(`\n Bundle "${bundleName}" não encontrado.\n`));
|
|
81
270
|
showHelp();
|
|
82
271
|
process.exit(1);
|
|
83
272
|
}
|
|
273
|
+
if (!EDITORS[editorArg]) {
|
|
274
|
+
console.error(chalk.red(`\n Editor "${editorArg}" não encontrado.\n`));
|
|
275
|
+
showHelp();
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
84
278
|
|
|
85
|
-
const
|
|
279
|
+
const bundleInfo = BUNDLES[bundleName];
|
|
86
280
|
const templatesDir = join(__dirname, "..", "templates");
|
|
87
281
|
const baseDir = join(templatesDir, "bundle-base");
|
|
88
282
|
const bundleDir = join(templatesDir, `bundle-${bundleName}`);
|
|
89
283
|
|
|
90
284
|
if (!existsSync(bundleDir)) {
|
|
91
|
-
console.error(chalk.red(`\n Templates
|
|
285
|
+
console.error(chalk.red(`\n Templates de "${bundleName}" não encontrados.\n`));
|
|
92
286
|
process.exit(1);
|
|
93
287
|
}
|
|
94
288
|
|
|
289
|
+
// Montar AGENTS.md (base + bundle)
|
|
290
|
+
let agentsMd = readFile(join(baseDir, "AGENTS.md"));
|
|
291
|
+
const bundleAgents = readFile(join(bundleDir, "AGENTS.md"));
|
|
292
|
+
if (bundleAgents) agentsMd += "\n\n---\n\n" + bundleAgents;
|
|
293
|
+
|
|
294
|
+
// Listar skills
|
|
295
|
+
const skillDirs = getSkillDirs(templatesDir, bundleName);
|
|
296
|
+
const skills = listSkills(skillDirs);
|
|
297
|
+
|
|
298
|
+
// Editores a instalar
|
|
299
|
+
const editorsToInstall = editorArg === "all"
|
|
300
|
+
? ["claude", "cursor", "codex", "copilot", "windsurf"]
|
|
301
|
+
: [editorArg];
|
|
302
|
+
|
|
303
|
+
const editorNames = editorsToInstall.map(e => EDITORS[e].name).join(", ");
|
|
304
|
+
|
|
95
305
|
console.log("");
|
|
96
|
-
console.log(chalk.bold(`
|
|
97
|
-
console.log(chalk.
|
|
306
|
+
console.log(chalk.bold(` Bundle: ${chalk.green(bundleInfo.name)}`));
|
|
307
|
+
console.log(chalk.bold(` Editor: ${chalk.yellow(editorNames)}`));
|
|
308
|
+
console.log(chalk.dim(` Destino: ${targetDir}`));
|
|
98
309
|
console.log("");
|
|
99
310
|
|
|
100
|
-
// 1.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
311
|
+
// 1. Instalar para cada editor
|
|
312
|
+
for (const editorKey of editorsToInstall) {
|
|
313
|
+
const spinner = ora(`Instalando para ${EDITORS[editorKey].name}`).start();
|
|
314
|
+
const results = installForEditor(editorKey, agentsMd, skills, targetDir);
|
|
315
|
+
spinner.succeed(`${EDITORS[editorKey].name}: ${results.join(", ")}`);
|
|
104
316
|
}
|
|
105
|
-
spinner.succeed("Estrutura criada");
|
|
106
|
-
|
|
107
|
-
// 2. AGENTS.md (base + bundle concatenados)
|
|
108
|
-
spinner = ora("Instalando AGENTS.md").start();
|
|
109
|
-
let agentsMd = "";
|
|
110
|
-
const baseAgentsPath = join(baseDir, "AGENTS.md");
|
|
111
|
-
const bundleAgentsPath = join(bundleDir, "AGENTS.md");
|
|
112
317
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
writeFileSync(join(targetDir, "AGENTS.md"), agentsMd);
|
|
121
|
-
spinner.succeed("AGENTS.md instalado na raiz");
|
|
122
|
-
|
|
123
|
-
// 3. Skills (base + bundle)
|
|
124
|
-
spinner = ora("Instalando skills").start();
|
|
125
|
-
const skillsDir = join(targetDir, "skills");
|
|
126
|
-
if (existsSync(join(baseDir, "skills"))) {
|
|
127
|
-
cpSync(join(baseDir, "skills"), skillsDir, { recursive: true });
|
|
318
|
+
// 2. Skills canônicas (sempre, para Deep Agents e referência)
|
|
319
|
+
const spinner2 = ora("Instalando skills canônicas").start();
|
|
320
|
+
const skillsDest = join(targetDir, "skills");
|
|
321
|
+
ensureDir(skillsDest);
|
|
322
|
+
for (const skill of skills) {
|
|
323
|
+
copyDir(skill.dir, join(skillsDest, skill.name));
|
|
128
324
|
}
|
|
129
|
-
|
|
130
|
-
cpSync(join(bundleDir, "skills"), skillsDir, { recursive: true });
|
|
131
|
-
}
|
|
132
|
-
const skillCount = countSkills(skillsDir);
|
|
133
|
-
spinner.succeed(`${skillCount} skills instaladas`);
|
|
325
|
+
spinner2.succeed(`${skills.length} skills canônicas em skills/`);
|
|
134
326
|
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
327
|
+
// 3. .spec/constitution.md
|
|
328
|
+
const spinner3 = ora("Instalando Spec Kit constitution").start();
|
|
329
|
+
const specSrc = join(bundleDir, ".spec");
|
|
330
|
+
ensureDir(join(targetDir, ".spec"));
|
|
331
|
+
copyDir(specSrc, join(targetDir, ".spec"));
|
|
332
|
+
spinner3.succeed(".spec/constitution.md instalado");
|
|
141
333
|
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
334
|
+
// 4. References
|
|
335
|
+
const spinner4 = ora("Instalando references").start();
|
|
336
|
+
const refsSrc = join(bundleDir, "references");
|
|
337
|
+
ensureDir(join(targetDir, "references"));
|
|
338
|
+
if (existsSync(refsSrc)) {
|
|
339
|
+
copyDir(refsSrc, join(targetDir, "references"));
|
|
146
340
|
}
|
|
147
|
-
|
|
341
|
+
spinner4.succeed("references/ pronto");
|
|
148
342
|
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
let specKitInstalled = false;
|
|
343
|
+
// 5. GitHub Spec Kit
|
|
344
|
+
const spinner5 = ora("Verificando GitHub Spec Kit").start();
|
|
152
345
|
try {
|
|
153
346
|
execSync("specify --version", { stdio: "ignore" });
|
|
154
|
-
|
|
155
|
-
spinner.succeed("Spec Kit já disponível");
|
|
347
|
+
spinner5.succeed("Spec Kit disponível");
|
|
156
348
|
} catch {
|
|
157
|
-
|
|
158
|
-
|
|
349
|
+
spinner5.info("Spec Kit não encontrado");
|
|
350
|
+
const spinner5b = ora("Instalando GitHub Spec Kit...").start();
|
|
159
351
|
try {
|
|
160
|
-
execSync(
|
|
161
|
-
"
|
|
162
|
-
|
|
163
|
-
);
|
|
164
|
-
specKitInstalled = true;
|
|
165
|
-
spinner.succeed("Spec Kit instalado");
|
|
352
|
+
execSync("uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", {
|
|
353
|
+
stdio: "ignore", timeout: 120000,
|
|
354
|
+
});
|
|
355
|
+
spinner5b.succeed("Spec Kit instalado");
|
|
166
356
|
} catch {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
"pip install specify-cli",
|
|
170
|
-
{ stdio: "ignore", timeout: 60000 }
|
|
171
|
-
);
|
|
172
|
-
specKitInstalled = true;
|
|
173
|
-
spinner.succeed("Spec Kit instalado via pip");
|
|
174
|
-
} catch {
|
|
175
|
-
spinner.warn("Instale o Spec Kit manualmente:");
|
|
176
|
-
console.log(chalk.dim(" uv tool install specify-cli --from git+https://github.com/github/spec-kit.git"));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// 7. Inicializar Spec Kit
|
|
182
|
-
if (specKitInstalled) {
|
|
183
|
-
spinner = ora("Inicializando Spec Kit").start();
|
|
184
|
-
try {
|
|
185
|
-
execSync(`specify init "${targetDir}"`, { stdio: "ignore", timeout: 15000, cwd: targetDir });
|
|
186
|
-
spinner.succeed("Spec Kit inicializado");
|
|
187
|
-
} catch {
|
|
188
|
-
spinner.info("Execute 'specify init .' no diretório do projeto");
|
|
357
|
+
spinner5b.warn("Instale manualmente:");
|
|
358
|
+
console.log(chalk.dim(" uv tool install specify-cli --from git+https://github.com/github/spec-kit.git"));
|
|
189
359
|
}
|
|
190
360
|
}
|
|
191
361
|
|
|
@@ -193,16 +363,33 @@ async function main() {
|
|
|
193
363
|
console.log("");
|
|
194
364
|
console.log(chalk.green.bold(" Pronto!"));
|
|
195
365
|
console.log("");
|
|
196
|
-
console.log("
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
366
|
+
console.log(" Estrutura instalada:");
|
|
367
|
+
|
|
368
|
+
for (const editorKey of editorsToInstall) {
|
|
369
|
+
const e = EDITORS[editorKey];
|
|
370
|
+
console.log(` ${chalk.yellow(e.name)}:`);
|
|
371
|
+
if (editorKey === "claude") {
|
|
372
|
+
console.log(` ${chalk.cyan("CLAUDE.md")} → @AGENTS.md`);
|
|
373
|
+
console.log(` ${chalk.cyan(".claude/skills/")} (${skills.length} skills com SKILL.md)`);
|
|
374
|
+
} else if (editorKey === "cursor") {
|
|
375
|
+
console.log(` ${chalk.cyan("AGENTS.md")} (instruções gerais)`);
|
|
376
|
+
console.log(` ${chalk.cyan(".cursor/rules/")} (${skills.length} rules .mdc)`);
|
|
377
|
+
} else if (editorKey === "codex") {
|
|
378
|
+
console.log(` ${chalk.cyan("AGENTS.md")} (tudo em um arquivo)`);
|
|
379
|
+
} else if (editorKey === "copilot") {
|
|
380
|
+
console.log(` ${chalk.cyan(".github/copilot-instructions.md")}`);
|
|
381
|
+
console.log(` ${chalk.cyan(".github/instructions/")} (${skills.length} .instructions.md)`);
|
|
382
|
+
} else if (editorKey === "windsurf") {
|
|
383
|
+
console.log(` ${chalk.cyan(".windsurfrules")}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
console.log(` ${chalk.cyan("skills/")} (${skills.length} canônicas para Deep Agents)`);
|
|
387
|
+
console.log(` ${chalk.cyan(".spec/constitution.md")} (GitHub Spec Kit SDD)`);
|
|
201
388
|
console.log("");
|
|
202
389
|
console.log(" Próximos passos:");
|
|
203
|
-
console.log(
|
|
204
|
-
console.log(" 2. O agente já conhece os padrões
|
|
205
|
-
console.log(` 3.
|
|
390
|
+
console.log(" 1. Abra o projeto no seu editor AI");
|
|
391
|
+
console.log(" 2. O agente já conhece os padrões");
|
|
392
|
+
console.log(` 3. Nova demanda? ${chalk.cyan("/speckit.specify")}`);
|
|
206
393
|
console.log("");
|
|
207
394
|
}
|
|
208
395
|
|