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.
Files changed (3) hide show
  1. package/README.md +54 -62
  2. package/package.json +1 -1
  3. 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
- Instala automaticamente:
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
- ## Bundles disponíveis
17
-
18
- ```bash
19
- npx maestro-bundle ai-agents # Python + LangChain + LangGraph + FastAPI
20
- npx maestro-bundle jhipster-monorepo # Java 21 + Spring Boot + Angular + PostgreSQL
21
- npx maestro-bundle jhipster-microservices # Java 21 + Spring Boot + Kafka + Consul + K8s
22
- npx maestro-bundle data-pipeline # Python + Pandas + Scikit-learn + MLflow
23
- npx maestro-bundle frontend-spa # React + TypeScript + Tailwind + Vite
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
- ## Uso
20
+ ## Bundles disponíveis
27
21
 
28
22
  ```bash
29
- # Instalar no diretório atual
30
- npx maestro-bundle ai-agents
31
-
32
- # Instalar em outro diretório
33
- npx maestro-bundle jhipster-monorepo ./meu-projeto
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
- Instalando: Sistema Multi-Agente com AI
45
- Destino: /home/user/meu-projeto
35
+ Bundle: Sistema Multi-Agente com AI
36
+ Editor: Claude Code, Cursor, OpenAI Codex, GitHub Copilot, Windsurf
46
37
 
47
- Estrutura criada
48
- AGENTS.md instalado na raiz
49
- 14 skills instaladas
50
- ✔ .spec/constitution.md instalado
51
- References instalados
52
- Spec Kit já disponível
53
- ✔ Spec Kit inicializado
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
- ## Resultado no projeto
50
+ ## Onde cada editor procura
70
51
 
71
52
  ```
72
53
  seu-projeto/
73
- ├── AGENTS.md # Lido por qualquer editor AI
74
- ├── .spec/
75
- │ └── constitution.md # Princípios (GitHub Spec Kit)
76
- ├── skills/
77
- ├── commit-pattern/SKILL.md # Do bundle-base
78
- ├── code-review/SKILL.md # Do bundle-base
79
- ├── rag-pipeline/SKILL.md # Do bundle escolhido
80
- ├── agent-orchestration/SKILL.md
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
- ├── references/
83
- │ └── ...
84
- └── src/
67
+ └── references/ ← Docs sob demanda
85
68
  ```
86
69
 
87
- ## Compatibilidade
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
- O `AGENTS.md` segue o padrão [agents.md](https://agents.md/) e funciona com 30+ editores AI.
80
+ ## Links
90
81
 
91
- O `.spec/` segue o padrão [GitHub Spec Kit](https://github.com/github/spec-kit) para SDD.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maestro-bundle",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Instala bundles de governança para projetos com AI agents. Um comando, tudo configurado.",
5
5
  "bin": {
6
6
  "maestro-bundle": "./src/cli.mjs"
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
- description: "Python + LangChain + LangGraph + FastAPI + pgvector",
18
+ desc: "Python + LangChain + LangGraph + FastAPI + pgvector",
16
19
  },
17
20
  "jhipster-monorepo": {
18
21
  name: "JHipster Monorepo",
19
- description: "Java 21 + Spring Boot + Angular + PostgreSQL + Liquibase",
22
+ desc: "Java 21 + Spring Boot + Angular + PostgreSQL + Liquibase",
20
23
  },
21
24
  "jhipster-microservices": {
22
25
  name: "JHipster Microservices",
23
- description: "Java 21 + Spring Boot + Angular + Kafka + Consul + K8s",
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
- description: "Python + Pandas + Scikit-learn + MLflow + Airflow",
30
+ desc: "Python + Pandas + Scikit-learn + MLflow + Airflow",
28
31
  },
29
32
  "frontend-spa": {
30
33
  name: "Frontend SPA",
31
- description: "React + TypeScript + Tailwind + Vite",
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.name}`);
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
- function countSkills(dir) {
57
- if (!existsSync(dir)) return 0;
58
- let count = 0;
59
- for (const item of readdirSync(dir, { withFileTypes: true })) {
60
- if (item.isDirectory()) {
61
- const skillFile = join(dir, item.name, "SKILL.md");
62
- if (existsSync(skillFile)) count++;
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 count;
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 === 0 || args.includes("--help") || args.includes("-h")) {
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 targetDir = resolve(args[1] || ".");
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 info = BUNDLES[bundleName];
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 do bundle "${bundleName}" não encontrados em ${bundleDir}\n`));
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(` Instalando: ${chalk.green(info.name)}`));
97
- console.log(chalk.dim(` Destino: ${targetDir}`));
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. Criar diretórios
101
- let spinner = ora("Criando estrutura").start();
102
- for (const dir of ["skills", ".spec", "references"]) {
103
- mkdirSync(join(targetDir, dir), { recursive: true });
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
- if (existsSync(baseAgentsPath)) {
114
- agentsMd += readFileSync(baseAgentsPath, "utf-8");
115
- }
116
- if (existsSync(bundleAgentsPath)) {
117
- agentsMd += "\n\n---\n\n";
118
- agentsMd += readFileSync(bundleAgentsPath, "utf-8");
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
- if (existsSync(join(bundleDir, "skills"))) {
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
- // 4. .spec/constitution.md
136
- spinner = ora("Instalando constitution (Spec Kit)").start();
137
- if (existsSync(join(bundleDir, ".spec"))) {
138
- cpSync(join(bundleDir, ".spec"), join(targetDir, ".spec"), { recursive: true });
139
- }
140
- spinner.succeed(".spec/constitution.md instalado");
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
- // 5. References
143
- spinner = ora("Instalando references").start();
144
- if (existsSync(join(bundleDir, "references"))) {
145
- cpSync(join(bundleDir, "references"), join(targetDir, "references"), { recursive: true });
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
- spinner.succeed("References instalados");
341
+ spinner4.succeed("references/ pronto");
148
342
 
149
- // 6. GitHub Spec Kit
150
- spinner = ora("Verificando GitHub Spec Kit").start();
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
- specKitInstalled = true;
155
- spinner.succeed("Spec Kit já disponível");
347
+ spinner5.succeed("Spec Kit disponível");
156
348
  } catch {
157
- spinner.info("Spec Kit não encontrado");
158
- spinner = ora("Instalando GitHub Spec Kit...").start();
349
+ spinner5.info("Spec Kit não encontrado");
350
+ const spinner5b = ora("Instalando GitHub Spec Kit...").start();
159
351
  try {
160
- execSync(
161
- "uv tool install specify-cli --from git+https://github.com/github/spec-kit.git",
162
- { stdio: "ignore", timeout: 120000 }
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
- try {
168
- execSync(
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(" Arquivos instalados:");
197
- console.log(` ${chalk.cyan("AGENTS.md")} Comportamento do agente (qualquer editor AI)`);
198
- console.log(` ${chalk.cyan(".spec/constitution.md")} Princípios do projeto (GitHub Spec Kit)`);
199
- console.log(` ${chalk.cyan(`skills/ (${skillCount} skills)`)} Capacidades do agente`);
200
- console.log(` ${chalk.cyan("references/")} Documentos de referência`);
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(` 1. Abra o projeto no seu editor AI ${chalk.dim("(Cursor, Claude Code, Copilot, etc.)")}`);
204
- console.log(" 2. O agente já conhece os padrões do projeto");
205
- console.log(` 3. Para nova demanda: ${chalk.cyan("/speckit.specify")}`);
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