maestro-bundle 1.1.0 → 1.2.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.mjs +95 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maestro-bundle",
3
- "version": "1.1.0",
3
+ "version": "1.2.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
@@ -69,9 +69,9 @@ const EDITORS = {
69
69
  },
70
70
  cursor: {
71
71
  name: "Cursor",
72
- instructionsFile: null, // Cursor lê AGENTS.md + .cursor/rules/
73
- skillsDir: null,
74
- rulesDir: ".cursor/rules", // Rules como .mdc com frontmatter
72
+ instructionsFile: null, // Cursor lê AGENTS.md na raiz
73
+ skillsDir: ".cursor/skills", // Skills como SKILL.md (mesmo formato do Claude)
74
+ rulesDir: null, // Não usar rules, usar skills
75
75
  needsAgentsMd: true, // Cursor lê AGENTS.md na raiz
76
76
  },
77
77
  codex: {
@@ -116,8 +116,8 @@ function showHelp() {
116
116
  }
117
117
  console.log("");
118
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`);
119
+ console.log(` ${chalk.yellow("claude".padEnd(12))} CLAUDE.md + .claude/skills/<nome>/SKILL.md`);
120
+ console.log(` ${chalk.yellow("cursor".padEnd(12))} AGENTS.md + .cursor/skills/<nome>/SKILL.md`);
121
121
  console.log(` ${chalk.yellow("codex".padEnd(12))} AGENTS.md (tudo em um arquivo)`);
122
122
  console.log(` ${chalk.yellow("copilot".padEnd(12))} .github/copilot-instructions.md + .github/instructions/`);
123
123
  console.log(` ${chalk.yellow("windsurf".padEnd(12))} .windsurfrules (tudo em um arquivo)`);
@@ -205,21 +205,7 @@ function installForEditor(editorKey, agentsMd, skills, targetDir) {
205
205
  for (const skill of skills) {
206
206
  const content = readFileSync(join(skill.dir, "SKILL.md"), "utf-8");
207
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") {
208
+ if (editorKey === "copilot") {
223
209
  // Copilot: .instructions.md
224
210
  writeFileSync(join(rulesPath, `${skill.name}.instructions.md`), content);
225
211
 
@@ -324,38 +310,97 @@ async function main() {
324
310
  }
325
311
  spinner2.succeed(`${skills.length} skills canônicas em skills/`);
326
312
 
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");
333
-
334
- // 4. References
335
- const spinner4 = ora("Instalando references").start();
313
+ // 3. References
314
+ const spinner3 = ora("Instalando references").start();
336
315
  const refsSrc = join(bundleDir, "references");
337
316
  ensureDir(join(targetDir, "references"));
338
317
  if (existsSync(refsSrc)) {
339
318
  copyDir(refsSrc, join(targetDir, "references"));
340
319
  }
341
- spinner4.succeed("references/ pronto");
342
-
343
- // 5. GitHub Spec Kit
344
- const spinner5 = ora("Verificando GitHub Spec Kit").start();
320
+ spinner3.succeed("references/ pronto");
321
+
322
+ // 4. GitHub Spec Kit — instalar CLI + inicializar no projeto
323
+ // Mapear editor para flag --ai do specify
324
+ const aiFlags = {
325
+ claude: "claude",
326
+ cursor: "cursor",
327
+ codex: "codex",
328
+ copilot: "copilot",
329
+ windsurf: "windsurf",
330
+ };
331
+ // Usar o primeiro editor como --ai (ou claude como default)
332
+ const primaryEditor = editorsToInstall[0];
333
+ const aiFlag = aiFlags[primaryEditor] || "claude";
334
+
335
+ // 4a. Instalar specify-cli se não tiver
336
+ const spinner4 = ora("Verificando GitHub Spec Kit (specify-cli)").start();
337
+ let specifyInstalled = false;
345
338
  try {
346
339
  execSync("specify --version", { stdio: "ignore" });
347
- spinner5.succeed("Spec Kit disponível");
340
+ specifyInstalled = true;
341
+ spinner4.succeed("specify-cli já instalado");
348
342
  } catch {
349
- spinner5.info("Spec Kit não encontrado");
350
- const spinner5b = ora("Instalando GitHub Spec Kit...").start();
343
+ spinner4.info("specify-cli não encontrado");
344
+ const spinner4b = ora("Instalando specify-cli...").start();
351
345
  try {
352
346
  execSync("uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", {
353
347
  stdio: "ignore", timeout: 120000,
354
348
  });
355
- spinner5b.succeed("Spec Kit instalado");
349
+ specifyInstalled = true;
350
+ spinner4b.succeed("specify-cli instalado");
356
351
  } catch {
357
- spinner5b.warn("Instale manualmente:");
358
- console.log(chalk.dim(" uv tool install specify-cli --from git+https://github.com/github/spec-kit.git"));
352
+ try {
353
+ execSync("pip install specify-cli", { stdio: "ignore", timeout: 60000 });
354
+ specifyInstalled = true;
355
+ spinner4b.succeed("specify-cli instalado via pip");
356
+ } catch {
357
+ spinner4b.warn("Não foi possível instalar. Instale manualmente:");
358
+ console.log(chalk.dim(" uv tool install specify-cli --from git+https://github.com/github/spec-kit.git"));
359
+ }
360
+ }
361
+ }
362
+
363
+ // 4b. Rodar specify init no projeto para criar .specify/ e registrar /speckit.* commands
364
+ if (specifyInstalled) {
365
+ const spinner4c = ora(`Inicializando Spec Kit no projeto (--ai ${aiFlag})`).start();
366
+ const specifyEnv = { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" };
367
+ let specInitOk = false;
368
+ const initCmds = [
369
+ `specify init --here --ai ${aiFlag}`,
370
+ `specify init . --ai ${aiFlag}`,
371
+ `specify init --here --ai ${aiFlag} --no-git`,
372
+ ];
373
+ for (const cmd of initCmds) {
374
+ try {
375
+ execSync(cmd, { stdio: "ignore", timeout: 30000, cwd: targetDir, env: specifyEnv });
376
+ specInitOk = true;
377
+ break;
378
+ } catch { /* try next */ }
379
+ }
380
+ if (specInitOk) {
381
+ spinner4c.succeed(`Spec Kit inicializado (/speckit.* commands disponíveis)`);
382
+ } else {
383
+ spinner4c.warn("Inicialize manualmente no terminal:");
384
+ console.log(chalk.dim(` cd ${targetDir}`));
385
+ console.log(chalk.dim(` specify init --here --ai ${aiFlag}`));
386
+ }
387
+
388
+ // 4c. Copiar constitution.md do bundle para dentro do .specify/memory/
389
+ const specifyMemoryDir = join(targetDir, ".specify", "memory");
390
+ const bundleConstitution = join(bundleDir, ".spec", "constitution.md");
391
+ if (existsSync(bundleConstitution)) {
392
+ ensureDir(specifyMemoryDir);
393
+ const constitutionDest = join(specifyMemoryDir, "constitution.md");
394
+ // Append os princípios do bundle ao constitution gerado pelo specify
395
+ if (existsSync(constitutionDest)) {
396
+ const existing = readFileSync(constitutionDest, "utf-8");
397
+ const bundleContent = readFileSync(bundleConstitution, "utf-8");
398
+ writeFileSync(constitutionDest, existing + "\n\n---\n\n" + bundleContent);
399
+ } else {
400
+ cpSync(bundleConstitution, constitutionDest);
401
+ }
402
+ const spinner4d = ora("Constitution do bundle integrado ao Spec Kit").start();
403
+ spinner4d.succeed("Constitution do bundle integrado ao Spec Kit");
359
404
  }
360
405
  }
361
406
 
@@ -373,7 +418,7 @@ async function main() {
373
418
  console.log(` ${chalk.cyan(".claude/skills/")} (${skills.length} skills com SKILL.md)`);
374
419
  } else if (editorKey === "cursor") {
375
420
  console.log(` ${chalk.cyan("AGENTS.md")} (instruções gerais)`);
376
- console.log(` ${chalk.cyan(".cursor/rules/")} (${skills.length} rules .mdc)`);
421
+ console.log(` ${chalk.cyan(".cursor/skills/")} (${skills.length} skills com SKILL.md)`);
377
422
  } else if (editorKey === "codex") {
378
423
  console.log(` ${chalk.cyan("AGENTS.md")} (tudo em um arquivo)`);
379
424
  } else if (editorKey === "copilot") {
@@ -384,12 +429,17 @@ async function main() {
384
429
  }
385
430
  }
386
431
  console.log(` ${chalk.cyan("skills/")} (${skills.length} canônicas para Deep Agents)`);
387
- console.log(` ${chalk.cyan(".spec/constitution.md")} (GitHub Spec Kit SDD)`);
432
+ console.log(` ${chalk.cyan(".specify/")} (GitHub Spec Kit — /speckit.* commands)`);
433
+ console.log("");
434
+ console.log(" Comandos SDD disponíveis no editor:");
435
+ console.log(` ${chalk.cyan("/speckit.constitution")} — Definir princípios do projeto`);
436
+ console.log(` ${chalk.cyan("/speckit.specify")} — Especificar O QUE e POR QUÊ`);
437
+ console.log(` ${chalk.cyan("/speckit.plan")} — Planejar arquitetura e stack`);
438
+ console.log(` ${chalk.cyan("/speckit.tasks")} — Quebrar em tasks atômicas`);
439
+ console.log(` ${chalk.cyan("/speckit.implement")} — Executar as tasks`);
388
440
  console.log("");
389
- console.log(" Próximos passos:");
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")}`);
441
+ console.log(" Próximo passo:");
442
+ console.log(" Abra o projeto no editor AI e use " + chalk.cyan("/speckit.specify") + " para começar");
393
443
  console.log("");
394
444
  }
395
445