oxe-cc 0.3.4 → 0.3.5

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/bin/oxe-cc.js CHANGED
@@ -14,8 +14,11 @@ const { spawnSync } = require('child_process');
14
14
  const PKG_ROOT = path.join(__dirname, '..');
15
15
  const oxeManifest = require(path.join(__dirname, 'lib', 'oxe-manifest.cjs'));
16
16
  const oxeHealth = require(path.join(__dirname, 'lib', 'oxe-project-health.cjs'));
17
+ const oxeAgentInstall = require(path.join(__dirname, 'lib', 'oxe-agent-install.cjs'));
18
+ const oxeWorkflows = require(path.join(__dirname, 'lib', 'oxe-workflows.cjs'));
19
+ const oxeInstallResolve = require(path.join(__dirname, 'lib', 'oxe-install-resolve.cjs'));
17
20
 
18
- /** GSD-style merge markers for ~/.copilot/copilot-instructions.md */
21
+ /** Merge markers for ~/.copilot/copilot-instructions.md (bloco OXE). */
19
22
  const OXE_INST_BEGIN = '<!-- oxe-cc:install-begin -->';
20
23
  const OXE_INST_END = '<!-- oxe-cc:install-end -->';
21
24
 
@@ -44,7 +47,7 @@ function useAnsiColors() {
44
47
  return process.stdout.isTTY === true;
45
48
  }
46
49
 
47
- /** Section header (GSD-inspired). */
50
+ /** Section header (CLI). */
48
51
  function printSection(title) {
49
52
  const c = useAnsiColors();
50
53
  if (!c) {
@@ -98,7 +101,7 @@ function displayPathForUser(absPath) {
98
101
  }
99
102
 
100
103
  /**
101
- * Rodapé estilo GSD: o que foi afetado + próximos comandos (pt-BR).
104
+ * Rodapé: o que foi afetado + próximos comandos (pt-BR).
102
105
  * @param {boolean} c
103
106
  * @param {{ bullets: string[], nextSteps: { desc: string, cmd: string }[], dryRun?: boolean }} block
104
107
  */
@@ -157,9 +160,14 @@ function buildInstallSummary(opts, fullLayout, cursorBase, copilotRoot, claudeBa
157
160
  `${prefix}Copilot (VS Code): trecho OXE em ${displayPathForUser(path.join(copilotRoot, 'copilot-instructions.md'))} e prompts em ${displayPathForUser(path.join(copilotRoot, 'prompts'))}`
158
161
  );
159
162
  }
160
- if (opts.copilotCli) {
163
+ if (opts.copilotCli && !opts.allAgents) {
161
164
  bullets.push(
162
- `${prefix}CLI: mesmos comandos em ${displayPathForUser(path.join(claudeBase, 'commands'))} e em ${displayPathForUser(path.join(copilotRoot, 'commands'))}`
165
+ `${prefix}CLI: skills Copilot em ${displayPathForUser(path.join(copilotRoot, 'skills'))} (/oxe, /oxe-scan, …); cópia legado em ${displayPathForUser(path.join(claudeBase, 'commands'))} e ${displayPathForUser(path.join(copilotRoot, 'commands'))}`
166
+ );
167
+ }
168
+ if (opts.allAgents) {
169
+ bullets.push(
170
+ `${prefix}Multi-agente (vários homes): OpenCode ${displayPathForUser(path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'opencode', 'commands'))} + ${displayPathForUser(path.join(os.homedir(), '.opencode', 'commands'))}; Gemini ${displayPathForUser(path.join(os.homedir(), '.gemini', 'commands'))} (/oxe, /oxe:scan); Codex ${displayPathForUser(path.join(os.homedir(), '.agents', 'skills'))} + ${displayPathForUser(path.join(os.homedir(), '.codex', 'prompts'))}; Windsurf ${displayPathForUser(path.join(os.homedir(), '.codeium', 'windsurf', 'global_workflows'))}; Antigravity ${displayPathForUser(path.join(os.homedir(), '.gemini', 'antigravity', 'skills'))}; + Claude/Copilot/Copilot skills como em --copilot-cli`
163
171
  );
164
172
  }
165
173
 
@@ -176,7 +184,7 @@ function buildInstallSummary(opts, fullLayout, cursorBase, copilotRoot, claudeBa
176
184
  const agentHint = [];
177
185
  if (opts.cursor) agentHint.push('Cursor');
178
186
  if (opts.copilot) agentHint.push('Copilot no VS Code');
179
- if (opts.copilotCli) agentHint.push('Copilot CLI / Claude');
187
+ if (opts.copilotCli || opts.allAgents) agentHint.push('CLIs / multi-agente');
180
188
  if (agentHint.length) {
181
189
  nextSteps.push({
182
190
  desc: `Mapear o código no agente (${agentHint.join(', ')}):`,
@@ -194,6 +202,19 @@ function buildInstallSummary(opts, fullLayout, cursorBase, copilotRoot, claudeBa
194
202
  });
195
203
  }
196
204
 
205
+ if (opts.copilotCli || opts.allAgents) {
206
+ nextSteps.push({
207
+ desc: 'No Copilot CLI: após instalar, rode /skills reload (ou reinicie o copilot) e use /oxe ou /oxe-scan:',
208
+ cmd: '/skills list',
209
+ });
210
+ }
211
+ if (opts.allAgents) {
212
+ nextSteps.push({
213
+ desc: 'No Gemini CLI: recarregar comandos personalizados (/oxe, /oxe:scan, …):',
214
+ cmd: '/commands reload',
215
+ });
216
+ }
217
+
197
218
  nextSteps.push({
198
219
  desc: 'Atualizar OXE depois (mesmo repositório):',
199
220
  cmd: 'npx oxe-cc@latest --force ou npx oxe-cc update',
@@ -211,7 +232,13 @@ function buildUninstallFooter(u) {
211
232
  const rm = u.dryRun ? 'Seriam removidos' : 'Removidos';
212
233
  if (u.cursor) bullets.push(`${p}${rm} artefatos OXE em ~/.cursor (comandos e regras).`);
213
234
  if (u.copilot) bullets.push(`${p}${rm} prompts oxe-* e bloco OXE em copilot-instructions (se existissem).`);
214
- if (u.copilotCli) bullets.push(`${p}${rm} comandos oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
235
+ if (u.copilotCli || u.allAgents) {
236
+ bullets.push(`${p}${rm} comandos oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
237
+ bullets.push(`${p}${rm} skills OXE (marcadas oxe-cc) em ~/.copilot/skills/oxe*/.`);
238
+ bullets.push(
239
+ `${p}${rm} extensões multi-agente marcadas oxe-cc (OpenCode, Gemini TOML, Windsurf workflows, Codex prompts/skills, Antigravity), se existirem.`
240
+ );
241
+ }
215
242
  if (!u.noProject) {
216
243
  bullets.push(
217
244
  `${p}${u.dryRun ? 'Seriam removidas' : 'Removidas'} no repositório: .oxe/workflows, .oxe/templates, oxe/ e commands/oxe (o que existir).`
@@ -226,7 +253,7 @@ function buildUninstallFooter(u) {
226
253
  return { bullets, nextSteps, dryRun: u.dryRun };
227
254
  }
228
255
 
229
- /** @typedef {{ help: boolean, version: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, vscode: boolean, commands: boolean, agents: boolean, force: boolean, dryRun: boolean, dir: string, all: boolean, noInitOxe: boolean, oxeOnly: boolean, globalCli: boolean, noGlobalCli: boolean, installAssetsGlobal: boolean, explicitScope: boolean, integrationsUnset: boolean, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} InstallOpts */
256
+ /** @typedef {{ help: boolean, version: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, vscode: boolean, commands: boolean, agents: boolean, force: boolean, dryRun: boolean, dir: string, all: boolean, noInitOxe: boolean, oxeOnly: boolean, globalCli: boolean, noGlobalCli: boolean, installAssetsGlobal: boolean, explicitScope: boolean, integrationsUnset: boolean, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string, ignoreInstallConfig: boolean }} InstallOpts */
230
257
 
231
258
  /**
232
259
  * @param {string[]} argv
@@ -240,6 +267,7 @@ function parseInstallArgs(argv) {
240
267
  cursor: false,
241
268
  copilot: false,
242
269
  copilotCli: false,
270
+ allAgents: false,
243
271
  vscode: false,
244
272
  commands: true,
245
273
  agents: true,
@@ -258,12 +286,14 @@ function parseInstallArgs(argv) {
258
286
  parseError: false,
259
287
  unknownFlag: '',
260
288
  conflictFlags: '',
289
+ ignoreInstallConfig: false,
261
290
  restPositional: [],
262
291
  };
263
292
  for (let i = 0; i < argv.length; i++) {
264
293
  const a = argv[i];
265
294
  if (a === '-h' || a === '--help') out.help = true;
266
295
  else if (a === '-v' || a === '--version') out.version = true;
296
+ else if (a === '--no-install-config') out.ignoreInstallConfig = true;
267
297
  else if ((a === '--config-dir' || a === '-c') && argv[i + 1]) {
268
298
  out.explicitConfigDir = path.resolve(expandTilde(argv[++i]));
269
299
  } else if (a === '--global') {
@@ -275,6 +305,7 @@ function parseInstallArgs(argv) {
275
305
  } else if (a === '--cursor') out.cursor = true;
276
306
  else if (a === '--copilot') out.copilot = true;
277
307
  else if (a === '--copilot-cli') out.copilotCli = true;
308
+ else if (a === '--all-agents') out.allAgents = true;
278
309
  else if (a === '--vscode') out.vscode = true;
279
310
  else if (a === '--no-commands') out.commands = false;
280
311
  else if (a === '--no-agents') out.agents = false;
@@ -301,16 +332,25 @@ function parseInstallArgs(argv) {
301
332
  out.conflictFlags = 'Não use --global e --local ao mesmo tempo';
302
333
  }
303
334
  if (!out.conflictFlags && out.explicitConfigDir) {
304
- const ideCount = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
305
- if (out.oxeOnly || ideCount !== 1) {
306
- out.conflictFlags =
307
- '--config-dir exige exatamente um entre --cursor, --copilot e --copilot-cli (e não combina com --oxe-only)';
335
+ if (out.oxeOnly || out.allAgents) {
336
+ out.conflictFlags = '--config-dir não combina com --oxe-only nem com --all-agents';
337
+ } else {
338
+ const ideCount = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
339
+ if (ideCount !== 1) {
340
+ out.conflictFlags =
341
+ '--config-dir exige exatamente um entre --cursor, --copilot e --copilot-cli (e não combina com --oxe-only)';
342
+ }
308
343
  }
309
344
  }
345
+ if (out.allAgents && !out.oxeOnly) {
346
+ out.cursor = true;
347
+ out.copilot = true;
348
+ }
310
349
  if (out.oxeOnly) {
311
350
  out.cursor = false;
312
351
  out.copilot = false;
313
352
  out.copilotCli = false;
353
+ out.allAgents = false;
314
354
  out.vscode = false;
315
355
  out.commands = false;
316
356
  out.agents = false;
@@ -369,7 +409,7 @@ function expandTilde(filePath) {
369
409
  return filePath;
370
410
  }
371
411
 
372
- /** GSD-style: Windows-native Node on WSL breaks paths — abort with guidance. */
412
+ /** Windows-native Node on WSL breaks paths — abort with guidance. */
373
413
  function assertNotWslWindowsNode() {
374
414
  if (process.platform !== 'win32') return;
375
415
  let isWsl = false;
@@ -402,6 +442,7 @@ function cursorUserDir(opts) {
402
442
  function copilotUserDir(opts) {
403
443
  if (opts.explicitConfigDir && opts.copilot) return path.resolve(expandTilde(opts.explicitConfigDir));
404
444
  if (process.env.COPILOT_CONFIG_DIR) return expandTilde(process.env.COPILOT_CONFIG_DIR);
445
+ if (process.env.COPILOT_HOME) return expandTilde(process.env.COPILOT_HOME);
405
446
  return path.join(os.homedir(), '.copilot');
406
447
  }
407
448
 
@@ -419,9 +460,25 @@ function useFullRepoLayout(opts) {
419
460
 
420
461
  /** @param {string} content */
421
462
  function adjustWorkflowPathsForNestedLayout(content) {
422
- return content
423
- .replace(/\boxe\/workflows\//g, '.oxe/workflows/')
424
- .replace(/\boxe\/templates\//g, '.oxe/templates/');
463
+ return oxeAgentInstall.adjustWorkflowPathsForNestedLayout(content);
464
+ }
465
+
466
+ /**
467
+ * Skills Copilot CLI (~/.copilot/skills/).
468
+ * @param {string} cCmdSrc
469
+ * @param {string} copilotHome
470
+ * @param {{ dryRun: boolean, force: boolean }} opts
471
+ * @param {boolean} pathRewriteNested
472
+ */
473
+ function installOxeCopilotCliSkills(cCmdSrc, copilotHome, opts, pathRewriteNested) {
474
+ oxeAgentInstall.installSkillTreeFromCursorCommands(
475
+ cCmdSrc,
476
+ path.join(copilotHome, 'skills'),
477
+ opts,
478
+ pathRewriteNested,
479
+ (d) => console.log(`${dim}omitido${reset} ${d} (já existe — use --force para substituir)`),
480
+ (msg) => console.log(`${dim}skill${reset} ${msg}`)
481
+ );
425
482
  }
426
483
 
427
484
  function isTextAssetForPathRewrite(fileName) {
@@ -437,7 +494,7 @@ function escapeForRegExp(s) {
437
494
  }
438
495
 
439
496
  /**
440
- * GSD-style merge into copilot-instructions.md (user-level).
497
+ * Merge into copilot-instructions.md (user-level).
441
498
  * @param {string} srcPath
442
499
  * @param {string} destPath
443
500
  * @param {{ dryRun: boolean, force: boolean }} opts
@@ -485,7 +542,21 @@ function canInstallPrompt() {
485
542
  );
486
543
  }
487
544
 
488
- /** @returns {Promise<{ cursor: boolean, copilot: boolean, copilotCli: boolean, vscode: boolean, commands: boolean, agents: boolean }>} */
545
+ /**
546
+ * Aplica `install` de `.oxe/config.json` quando a CLI não fixou integrações/layout (flags prevalecem).
547
+ * @param {InstallOpts} opts
548
+ * @param {string} targetDir
549
+ */
550
+ function applyInstallFromOxeConfig(opts, targetDir) {
551
+ const { options, warnings } = oxeInstallResolve.resolveInstallOptionsFromConfig(targetDir, opts);
552
+ Object.assign(opts, options);
553
+ const c = useAnsiColors();
554
+ for (const w of warnings) {
555
+ console.log(` ${c ? yellow : ''}AVISO${c ? reset : ''} .oxe/config.json: ${w}`);
556
+ }
557
+ }
558
+
559
+ /** @returns {Promise<{ cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, vscode: boolean, commands: boolean, agents: boolean }>} */
489
560
  async function promptIntegrationProfile() {
490
561
  const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
491
562
  const c = useAnsiColors();
@@ -494,24 +565,28 @@ async function promptIntegrationProfile() {
494
565
  ${c ? cyan : ''}1${c ? reset : ''}) ${c ? dim : ''}Cursor + GitHub Copilot${c ? reset : ''} ${c ? dim : ''}(recomendado)${c ? reset : ''}
495
566
  ${c ? cyan : ''}2${c ? reset : ''}) ${c ? dim : ''}Só Cursor${c ? reset : ''}
496
567
  ${c ? cyan : ''}3${c ? reset : ''}) ${c ? dim : ''}Só Copilot${c ? reset : ''} ${c ? dim : ''}(VS Code)${c ? reset : ''}
497
- ${c ? cyan : ''}4${c ? reset : ''}) ${c ? dim : ''}Cursor + Copilot + comandos na CLI${c ? reset : ''} ${c ? dim : ''}(~/.claude e ~/.copilot)${c ? reset : ''}
568
+ ${c ? cyan : ''}4${c ? reset : ''}) ${c ? dim : ''}Cursor + Copilot + CLIs${c ? reset : ''} ${c ? dim : ''}(~/.claude, ~/.copilot, skills Copilot)${c ? reset : ''}
498
569
  ${c ? cyan : ''}5${c ? reset : ''}) ${c ? dim : ''}Só o núcleo${c ? reset : ''} ${c ? dim : ''}(apenas .oxe/ com workflows, sem IDE)${c ? reset : ''}
570
+ ${c ? cyan : ''}6${c ? reset : ''}) ${c ? dim : ''}Tudo + multi-agente${c ? reset : ''} ${c ? dim : ''}— opção 4 + OpenCode, Gemini, Codex, Windsurf, Antigravity${c ? reset : ''}
499
571
  `);
500
572
  const answer = await rl.question(` ${c ? cyan : ''}Escolha${c ? reset : ''} ${c ? dim : ''}[1]${c ? reset : ''}: `);
501
573
  const choice = (answer || '1').trim();
502
574
  if (choice === '5') {
503
- return { cursor: false, copilot: false, copilotCli: false, vscode: false, commands: false, agents: false };
575
+ return { cursor: false, copilot: false, copilotCli: false, allAgents: false, vscode: false, commands: false, agents: false };
504
576
  }
505
577
  if (choice === '2') {
506
- return { cursor: true, copilot: false, copilotCli: false, vscode: false, commands: true, agents: true };
578
+ return { cursor: true, copilot: false, copilotCli: false, allAgents: false, vscode: false, commands: true, agents: true };
507
579
  }
508
580
  if (choice === '3') {
509
- return { cursor: false, copilot: true, copilotCli: false, vscode: false, commands: true, agents: true };
581
+ return { cursor: false, copilot: true, copilotCli: false, allAgents: false, vscode: false, commands: true, agents: true };
510
582
  }
511
583
  if (choice === '4') {
512
- return { cursor: true, copilot: true, copilotCli: true, vscode: false, commands: true, agents: true };
584
+ return { cursor: true, copilot: true, copilotCli: true, allAgents: false, vscode: false, commands: true, agents: true };
585
+ }
586
+ if (choice === '6') {
587
+ return { cursor: true, copilot: true, copilotCli: true, allAgents: true, vscode: false, commands: true, agents: true };
513
588
  }
514
- return { cursor: true, copilot: true, copilotCli: false, vscode: false, commands: true, agents: true };
589
+ return { cursor: true, copilot: true, copilotCli: false, allAgents: false, vscode: false, commands: true, agents: true };
515
590
  } finally {
516
591
  rl.close();
517
592
  }
@@ -519,7 +594,7 @@ async function promptIntegrationProfile() {
519
594
 
520
595
  /** @param {InstallOpts} opts */
521
596
  async function promptInstallScope(opts) {
522
- const hasIde = opts.cursor || opts.copilot || opts.copilotCli;
597
+ const hasIde = opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents;
523
598
  if (!hasIde) return;
524
599
  const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
525
600
  const c = useAnsiColors();
@@ -540,13 +615,18 @@ async function promptInstallScope(opts) {
540
615
 
541
616
  /** @param {InstallOpts} opts */
542
617
  async function resolveInteractiveInstall(opts) {
618
+ if (!opts.ignoreInstallConfig) {
619
+ applyInstallFromOxeConfig(opts, opts.dir);
620
+ }
621
+
543
622
  if (opts.dryRun) {
544
623
  if (opts.integrationsUnset) {
545
624
  opts.cursor = true;
546
625
  opts.copilot = true;
626
+ opts.allAgents = false;
547
627
  opts.integrationsUnset = false;
548
628
  }
549
- if (!opts.explicitScope && (opts.cursor || opts.copilot || opts.copilotCli)) {
629
+ if (!opts.explicitScope && (opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents)) {
550
630
  opts.installAssetsGlobal = false;
551
631
  }
552
632
  return;
@@ -562,15 +642,16 @@ async function resolveInteractiveInstall(opts) {
562
642
  } else {
563
643
  opts.cursor = true;
564
644
  opts.copilot = true;
645
+ opts.allAgents = false;
565
646
  opts.integrationsUnset = false;
566
647
  const c = useAnsiColors();
567
648
  console.log(
568
- `\n ${c ? yellow : ''}Terminal não interativo${c ? reset : ''} — layout mínimo: só ${c ? cyan : ''}.oxe/${c ? reset : ''}; integrações em ~/.cursor e ~/.copilot. Para ${c ? cyan : ''}oxe/${c ? reset : ''} na raiz use ${c ? cyan : ''}--global${c ? reset : ''}. Outras flags: ${c ? cyan : ''}--cursor${c ? reset : ''}, ${c ? cyan : ''}--copilot${c ? reset : ''}, ${c ? cyan : ''}--oxe-only${c ? reset : ''}, ${c ? cyan : ''}OXE_NO_PROMPT=1${c ? reset : ''}.\n`
649
+ `\n ${c ? yellow : ''}Terminal não interativo${c ? reset : ''} — layout mínimo: só ${c ? cyan : ''}.oxe/${c ? reset : ''}; integrações em ~/.cursor e ~/.copilot. Para ${c ? cyan : ''}oxe/${c ? reset : ''} na raiz use ${c ? cyan : ''}--global${c ? reset : ''}. Outras flags: ${c ? cyan : ''}--cursor${c ? reset : ''}, ${c ? cyan : ''}--copilot${c ? reset : ''}, ${c ? cyan : ''}--all-agents${c ? reset : ''}, ${c ? cyan : ''}--oxe-only${c ? reset : ''}, ${c ? cyan : ''}OXE_NO_PROMPT=1${c ? reset : ''}.\n`
569
650
  );
570
651
  }
571
652
  }
572
653
 
573
- const hasIde = opts.cursor || opts.copilot || opts.copilotCli;
654
+ const hasIde = opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents;
574
655
  if (hasIde && !opts.explicitScope) {
575
656
  if (can) await promptInstallScope(opts);
576
657
  else {
@@ -696,15 +777,6 @@ function bootstrapOxe(target, opts) {
696
777
  }
697
778
  }
698
779
 
699
- /** @param {string} targetProject */
700
- function resolveWorkflowsDir(targetProject) {
701
- const nested = path.join(targetProject, '.oxe', 'workflows');
702
- const root = path.join(targetProject, 'oxe', 'workflows');
703
- if (fs.existsSync(nested)) return nested;
704
- if (fs.existsSync(root)) return root;
705
- return null;
706
- }
707
-
708
780
  /**
709
781
  * Doctor / status: config estendida, fase STATE, scan antigo, SUMMARY, SPEC/PLAN.
710
782
  * @param {string} target
@@ -773,7 +845,7 @@ function runStatus(target) {
773
845
  const c = useAnsiColors();
774
846
  console.log(` ${c ? green : ''}Projeto:${c ? reset : ''} ${c ? cyan : ''}${target}${c ? reset : ''}`);
775
847
 
776
- const wfTgt = resolveWorkflowsDir(target);
848
+ const wfTgt = oxeWorkflows.resolveWorkflowsDir(target);
777
849
  if (!wfTgt) {
778
850
  console.log(` ${yellow}AVISO${reset} Workflows OXE não encontrados — ${cyan}npx oxe-cc@latest${reset}`);
779
851
  }
@@ -815,7 +887,7 @@ function runDoctor(target) {
815
887
  console.log(`${green}OK${reset} Node.js`);
816
888
 
817
889
  const wfPkg = path.join(PKG_ROOT, 'oxe', 'workflows');
818
- const wfTgt = resolveWorkflowsDir(target);
890
+ const wfTgt = oxeWorkflows.resolveWorkflowsDir(target);
819
891
  if (!fs.existsSync(wfPkg)) {
820
892
  console.log(`${red}FALHA${reset} Workflows do pacote npm ausentes: ${wfPkg}`);
821
893
  process.exit(1);
@@ -851,6 +923,13 @@ function runDoctor(target) {
851
923
  const wfLabel = wfTgt.includes(`${path.sep}.oxe${path.sep}`) ? '.oxe/workflows' : 'oxe/workflows';
852
924
  console.log(`${green}OK${reset} ${wfLabel} contém os ${expected.length} arquivos esperados do pacote`);
853
925
 
926
+ const shape = oxeWorkflows.validateWorkflowShapes(wfTgt);
927
+ if (shape.warnings.length) {
928
+ for (const w of shape.warnings) {
929
+ console.log(`${yellow}Obs. (workflow):${reset} ${w.message}`);
930
+ }
931
+ }
932
+
854
933
  const oxeState = path.join(target, '.oxe', 'STATE.md');
855
934
  if (fs.existsSync(oxeState)) console.log(`${green}OK${reset} .oxe/STATE.md encontrado`);
856
935
  else {
@@ -941,7 +1020,7 @@ function installGlobalCliPackage() {
941
1020
  }
942
1021
 
943
1022
  /**
944
- * After copying OXE into the project: optionally install the CLI globally (like GSD’s “where to install” choice).
1023
+ * After copying OXE into the project: optionally install the CLI globally (pergunta interativa ou flags).
945
1024
  * @param {InstallOpts} opts
946
1025
  * @returns {Promise<void>}
947
1026
  */
@@ -1004,6 +1083,7 @@ ${cyan}oxe-cc${reset} — instala workflows OXE (Cursor + GitHub Copilot) no pro
1004
1083
 
1005
1084
  ${green}Uso:${reset}
1006
1085
  npx oxe-cc@latest [opções] [pasta-do-projeto]
1086
+ npx oxe-cc@latest install [opções] [pasta-do-projeto] ${dim}(equivalente à instalação predefinida)${reset}
1007
1087
  npx oxe-cc@latest --dir /caminho/do/projeto
1008
1088
  npx oxe-cc doctor [opções] [pasta-do-projeto]
1009
1089
  npx oxe-cc status [opções] [pasta-do-projeto]
@@ -1013,8 +1093,9 @@ ${green}Uso:${reset}
1013
1093
 
1014
1094
  ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
1015
1095
  --cursor / --copilot / --copilot-cli só essa integração (omissão = todas)
1096
+ --all-agents também remove ficheiros multi-plataforma (com --copilot-cli implícito)
1016
1097
  --ide-only não apagar .oxe/workflows, oxe/, etc. no projeto
1017
- --config-dir <caminho> com exatamente uma flag IDE acima (estilo GSD)
1098
+ --config-dir <caminho> com exatamente uma flag IDE acima
1018
1099
  --dry-run
1019
1100
  --dir <pasta> raiz do projeto (padrão: diretório atual)
1020
1101
 
@@ -1026,7 +1107,9 @@ ${green}update${reset} (executa npx oxe-cc@latest --force na pasta do projeto)
1026
1107
  ${green}Opções da instalação:${reset}
1027
1108
  --cursor Copia comandos e regras para ~/.cursor (padrão com --all)
1028
1109
  --copilot Mescla instruções + prompts em ~/.copilot (não fica .github/ no repo)
1029
- --copilot-cli Copia comandos para ~/.claude/commands e ~/.copilot/commands (CLI — experimental)
1110
+ --copilot-cli Skills em ~/.copilot/skills (/oxe, /oxe-scan, …) + cópia legado em ~/.claude/commands e ~/.copilot/commands
1111
+ (subconjunto de --all-agents)
1112
+ --all-agents Opção 6 no menu: Cursor+Copilot + CLIs + OpenCode, Gemini (TOML), Codex, Windsurf, Antigravity
1030
1113
  --vscode Também copia .vscode/settings.json (chat.promptFiles)
1031
1114
  --all, -a Cursor + Copilot (padrão se não passar --cursor nem --copilot)
1032
1115
  --no-commands Não copia commands/oxe
@@ -1039,7 +1122,8 @@ ${green}Opções da instalação:${reset}
1039
1122
  --no-global-cli, -l Não pergunta pelo CLI global (recomendado em CI)
1040
1123
  --force, -f Sobrescreve arquivos existentes
1041
1124
  --dry-run Lista ações sem gravar
1042
- --config-dir, -c <pasta> Só com exatamente um de --cursor, --copilot, --copilot-cli
1125
+ --config-dir, -c <pasta> Só com exatamente um de --cursor, --copilot, --copilot-cli (não use com --all-agents)
1126
+ --no-install-config Ignora o bloco install em .oxe/config.json (só integração/layout vindos das flags ou do menu)
1043
1127
  --dir <pasta> Pasta de destino (padrão: diretório atual)
1044
1128
  -h, --help
1045
1129
  -v, --version
@@ -1058,6 +1142,7 @@ ${green}Exemplos:${reset}
1058
1142
  npx oxe-cc@latest ./meu-app
1059
1143
  npx oxe-cc@latest --cursor --dry-run
1060
1144
  npx oxe-cc@latest --copilot --copilot-cli
1145
+ npx oxe-cc@latest --all-agents
1061
1146
  npx oxe-cc doctor
1062
1147
  npx oxe-cc init-oxe --dir ./meu-app
1063
1148
  npx oxe-cc uninstall --dir .
@@ -1093,10 +1178,10 @@ function runInstall(opts) {
1093
1178
  ` ${c ? dim : ''}Layout repo:${c ? reset : ''} ${c ? yellow : ''}só .oxe/${c ? reset : ''} ${c ? dim : ''}(${c ? cyan : ''}.oxe/workflows${c ? dim : ''})${c ? reset : ''}`
1094
1179
  );
1095
1180
  }
1096
- const ideAny = opts.cursor || opts.copilot || opts.copilotCli;
1181
+ const ideAny = opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents;
1097
1182
  if (ideAny) {
1098
1183
  console.log(
1099
- ` ${c ? dim : ''}Integrações IDE:${c ? reset : ''} ${c ? yellow : ''}~/.cursor${c ? reset : ''}, ${c ? yellow : ''}~/.copilot${c ? reset : ''}, ${c ? yellow : ''}~/.claude${c ? reset : ''} ${c ? dim : ''}(conforme opções)${c ? reset : ''}`
1184
+ ` ${c ? dim : ''}Integrações IDE:${c ? reset : ''} ${c ? yellow : ''}~/.cursor${c ? reset : ''}, ${c ? yellow : ''}~/.copilot${c ? reset : ''}, ${c ? yellow : ''}~/.claude${c ? reset : ''}${opts.allAgents ? `${c ? dim : ''}, OpenCode, Gemini, Codex, Windsurf, Antigravity${c ? reset : ''}` : ''} ${c ? dim : ''}(conforme opções)${c ? reset : ''}`
1100
1185
  );
1101
1186
  }
1102
1187
 
@@ -1118,18 +1203,53 @@ function runInstall(opts) {
1118
1203
  if (fs.existsSync(cRules)) copyDir(cRules, path.join(cursorBase, 'rules'), copyOpts, idePathRewrite);
1119
1204
  }
1120
1205
 
1121
- if (opts.copilotCli) {
1206
+ const doAgentClis = opts.copilotCli || opts.allAgents;
1207
+ if (doAgentClis) {
1122
1208
  const cCmd = path.join(PKG_ROOT, '.cursor', 'commands');
1123
1209
  const clDest = path.join(claudeUserDir(opts), 'commands');
1124
- const cpCmdDest = path.join(copilotUserDir(opts), 'commands');
1210
+ const cpHome = copilotUserDir(opts);
1211
+ const cpCmdDest = path.join(cpHome, 'commands');
1212
+ const cpSkills = path.join(cpHome, 'skills');
1125
1213
  if (fs.existsSync(cCmd)) {
1126
1214
  console.log(
1127
- ` ${c ? green : ''}cli${c ? reset : ''} ${c ? dim : ''}comandos:${c ? reset : ''} ${c ? cyan : ''}${clDest}${c ? reset : ''} ${c ? dim : ''}+${c ? reset : ''} ${c ? cyan : ''}${cpCmdDest}${c ? reset : ''} ${c ? dim : ''}(~/.claude + ~/.copilot)${c ? reset : ''}`
1215
+ ` ${c ? green : ''}cli${c ? reset : ''} ${c ? dim : ''}Claude/Copilot: skills em${c ? reset : ''} ${c ? cyan : ''}${cpSkills}${c ? reset : ''} ${c ? dim : ''}(/oxe, /oxe-scan, …); comandos .md:${c ? reset : ''} ${c ? cyan : ''}${clDest}${c ? reset : ''} ${c ? dim : ''}+${c ? reset : ''} ${c ? cyan : ''}${cpCmdDest}${c ? reset : ''}`
1128
1216
  );
1217
+ installOxeCopilotCliSkills(cCmd, cpHome, copyOpts, idePathRewrite);
1129
1218
  copyDir(cCmd, clDest, copyOpts, idePathRewrite);
1130
1219
  copyDir(cCmd, cpCmdDest, copyOpts, idePathRewrite);
1131
1220
  } else {
1132
- console.warn(`${yellow}aviso:${reset} pasta ausente ${cCmd} — ignorando --copilot-cli`);
1221
+ console.warn(`${yellow}aviso:${reset} pasta ausente ${cCmd} — ignorando comandos CLI`);
1222
+ }
1223
+ }
1224
+
1225
+ if (opts.allAgents) {
1226
+ const cCmd = path.join(PKG_ROOT, '.cursor', 'commands');
1227
+ if (fs.existsSync(cCmd)) {
1228
+ const logO = (d) => console.log(`${dim}omitido${reset} ${d} (já existe — use --force)`);
1229
+ const logW = (msg) => console.log(`${dim}agents${reset} ${msg}`);
1230
+ console.log(
1231
+ ` ${c ? green : ''}agents${c ? reset : ''} ${c ? dim : ''}OpenCode, Gemini (TOML), Windsurf, Codex (prompts + skills), Antigravity${c ? reset : ''}`
1232
+ );
1233
+ oxeAgentInstall.installOpenCodeCommands(cCmd, copyOpts, idePathRewrite, logO, logW);
1234
+ oxeAgentInstall.installGeminiTomlCommands(cCmd, copyOpts, idePathRewrite, logO, logW);
1235
+ oxeAgentInstall.installWindsurfGlobalWorkflows(cCmd, copyOpts, idePathRewrite, logO, logW);
1236
+ oxeAgentInstall.installCodexPrompts(cCmd, copyOpts, idePathRewrite, logO, logW);
1237
+ oxeAgentInstall.installSkillTreeFromCursorCommands(
1238
+ cCmd,
1239
+ oxeAgentInstall.antigravitySkillsRoot(),
1240
+ copyOpts,
1241
+ idePathRewrite,
1242
+ logO,
1243
+ logW
1244
+ );
1245
+ oxeAgentInstall.installSkillTreeFromCursorCommands(
1246
+ cCmd,
1247
+ oxeAgentInstall.codexAgentsSkillsRoot(),
1248
+ copyOpts,
1249
+ idePathRewrite,
1250
+ logO,
1251
+ logW
1252
+ );
1133
1253
  }
1134
1254
  }
1135
1255
 
@@ -1177,7 +1297,7 @@ function runInstall(opts) {
1177
1297
 
1178
1298
  if (!opts.noInitOxe) bootstrapOxe(target, { dryRun: opts.dryRun, force: opts.force });
1179
1299
 
1180
- if (!opts.dryRun && (opts.cursor || opts.copilot || opts.copilotCli)) {
1300
+ if (!opts.dryRun && (opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents)) {
1181
1301
  const nextFiles = {};
1182
1302
  const addTracked = (root, nameFilter) => {
1183
1303
  if (!fs.existsSync(root)) return;
@@ -1190,6 +1310,14 @@ function runInstall(opts) {
1190
1310
  }
1191
1311
  }
1192
1312
  };
1313
+ const trackFile = (f) => {
1314
+ if (!fs.existsSync(f)) return;
1315
+ try {
1316
+ nextFiles[f] = oxeManifest.sha256File(f);
1317
+ } catch {
1318
+ /* skip */
1319
+ }
1320
+ };
1193
1321
  if (opts.cursor) {
1194
1322
  addTracked(path.join(cursorBase, 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
1195
1323
  addTracked(path.join(cursorBase, 'rules'), (n) => n.includes('oxe') && (n.endsWith('.mdc') || n.endsWith('.md')));
@@ -1205,9 +1333,49 @@ function runInstall(opts) {
1205
1333
  }
1206
1334
  addTracked(path.join(copilotRoot, 'prompts'), (n) => n.startsWith('oxe-'));
1207
1335
  }
1208
- if (opts.copilotCli) {
1336
+ if (opts.copilotCli || opts.allAgents) {
1209
1337
  addTracked(path.join(claudeUserDir(opts), 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
1210
1338
  addTracked(path.join(copilotRoot, 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
1339
+ const skRoot = path.join(copilotRoot, 'skills');
1340
+ if (fs.existsSync(skRoot)) {
1341
+ for (const sub of fs.readdirSync(skRoot, { withFileTypes: true })) {
1342
+ if (!sub.isDirectory() || !/^oxe($|-)/.test(sub.name)) continue;
1343
+ const sm = path.join(skRoot, sub.name, 'SKILL.md');
1344
+ if (fs.existsSync(sm)) {
1345
+ try {
1346
+ nextFiles[sm] = oxeManifest.sha256File(sm);
1347
+ } catch {
1348
+ /* skip */
1349
+ }
1350
+ }
1351
+ }
1352
+ }
1353
+ }
1354
+ if (opts.allAgents) {
1355
+ for (const d of oxeAgentInstall.opencodeCommandDirs()) {
1356
+ addTracked(d, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
1357
+ }
1358
+ const gCmd = path.join(oxeAgentInstall.geminiUserDir(), 'commands');
1359
+ trackFile(path.join(gCmd, 'oxe.toml'));
1360
+ const oxeGem = path.join(gCmd, 'oxe');
1361
+ if (fs.existsSync(oxeGem)) {
1362
+ for (const n of fs.readdirSync(oxeGem)) {
1363
+ if (n.endsWith('.toml')) trackFile(path.join(oxeGem, n));
1364
+ }
1365
+ }
1366
+ addTracked(oxeAgentInstall.windsurfGlobalWorkflowsDir(), (n) => (n === 'oxe.md' || (n.startsWith('oxe-') && n.endsWith('.md'))));
1367
+ const cxPrompts = oxeAgentInstall.codexPromptsDir();
1368
+ if (fs.existsSync(cxPrompts)) {
1369
+ addTracked(cxPrompts, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
1370
+ }
1371
+ for (const rootFn of [oxeAgentInstall.antigravitySkillsRoot, oxeAgentInstall.codexAgentsSkillsRoot]) {
1372
+ const root = rootFn();
1373
+ if (!fs.existsSync(root)) continue;
1374
+ for (const sub of fs.readdirSync(root, { withFileTypes: true })) {
1375
+ if (!sub.isDirectory() || !/^oxe($|-)/.test(sub.name)) continue;
1376
+ trackFile(path.join(root, sub.name, 'SKILL.md'));
1377
+ }
1378
+ }
1211
1379
  }
1212
1380
  const mergedManifest = { ...prevManifest, ...nextFiles };
1213
1381
  oxeManifest.writeFileManifest(home, mergedManifest, readPkgVersion());
@@ -1220,7 +1388,7 @@ function runInstall(opts) {
1220
1388
  console.log(` ${c ? green : ''}✓${c ? reset : ''} Instalação concluída com sucesso.\n`);
1221
1389
  }
1222
1390
 
1223
- /** @typedef {{ help: boolean, dryRun: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, ideExplicit: boolean, noProject: boolean, dir: string, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} UninstallOpts */
1391
+ /** @typedef {{ help: boolean, dryRun: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, ideExplicit: boolean, noProject: boolean, dir: string, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} UninstallOpts */
1224
1392
 
1225
1393
  /**
1226
1394
  * @param {string[]} argv
@@ -1234,6 +1402,7 @@ function parseUninstallArgs(argv) {
1234
1402
  cursor: false,
1235
1403
  copilot: false,
1236
1404
  copilotCli: false,
1405
+ allAgents: false,
1237
1406
  ideExplicit: false,
1238
1407
  noProject: false,
1239
1408
  dir: process.cwd(),
@@ -1258,6 +1427,10 @@ function parseUninstallArgs(argv) {
1258
1427
  } else if (a === '--copilot-cli') {
1259
1428
  out.copilotCli = true;
1260
1429
  out.ideExplicit = true;
1430
+ } else if (a === '--all-agents') {
1431
+ out.allAgents = true;
1432
+ out.copilotCli = true;
1433
+ out.ideExplicit = true;
1261
1434
  } else if (a === '--ide-only') out.noProject = true;
1262
1435
  else if (a === '--dir' && argv[i + 1]) out.dir = path.resolve(argv[++i]);
1263
1436
  else if (!a.startsWith('-')) rest.push(path.resolve(a));
@@ -1274,10 +1447,14 @@ function parseUninstallArgs(argv) {
1274
1447
  out.copilotCli = true;
1275
1448
  }
1276
1449
  if (!out.conflictFlags && out.explicitConfigDir) {
1277
- const n = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
1278
- if (n !== 1) {
1279
- out.conflictFlags =
1280
- '--config-dir exige exatamente um entre --cursor, --copilot e --copilot-cli';
1450
+ if (out.allAgents) {
1451
+ out.conflictFlags = '--config-dir não combina com --all-agents';
1452
+ } else {
1453
+ const n = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
1454
+ if (n !== 1) {
1455
+ out.conflictFlags =
1456
+ '--config-dir exige exatamente um entre --cursor, --copilot e --copilot-cli';
1457
+ }
1281
1458
  }
1282
1459
  }
1283
1460
  return out;
@@ -1343,6 +1520,7 @@ function runUninstall(u) {
1343
1520
  cursor: u.cursor,
1344
1521
  copilot: u.copilot,
1345
1522
  copilotCli: u.copilotCli,
1523
+ allAgents: u.allAgents,
1346
1524
  vscode: false,
1347
1525
  commands: false,
1348
1526
  agents: false,
@@ -1421,6 +1599,33 @@ function runUninstall(u) {
1421
1599
  }
1422
1600
  }
1423
1601
  }
1602
+ const skillsRoot = path.join(copilotUserDir(ideOpts), 'skills');
1603
+ if (fs.existsSync(skillsRoot)) {
1604
+ for (const ent of fs.readdirSync(skillsRoot, { withFileTypes: true })) {
1605
+ if (!ent.isDirectory() || !/^oxe($|-)/.test(ent.name)) continue;
1606
+ const skillFile = path.join(skillsRoot, ent.name, 'SKILL.md');
1607
+ if (!fs.existsSync(skillFile)) continue;
1608
+ let txt = '';
1609
+ try {
1610
+ txt = fs.readFileSync(skillFile, 'utf8');
1611
+ } catch {
1612
+ continue;
1613
+ }
1614
+ if (!txt.includes('<!-- oxe-cc managed -->')) continue;
1615
+ const dir = path.join(skillsRoot, ent.name);
1616
+ if (u.dryRun) {
1617
+ console.log(`${dim}rm -r${reset} ${dir}`);
1618
+ } else {
1619
+ fs.rmSync(dir, { recursive: true, force: true });
1620
+ }
1621
+ removedPaths.push(skillFile);
1622
+ }
1623
+ }
1624
+ if (u.dryRun) {
1625
+ console.log(`${dim}agents${reset} (dry-run) limparia OpenCode, Gemini TOML, Windsurf, Codex, Antigravity (marcadores oxe-cc)`);
1626
+ } else {
1627
+ oxeAgentInstall.cleanupMarkedUnifiedArtifacts(u);
1628
+ }
1424
1629
  }
1425
1630
 
1426
1631
  if (!u.noProject) {
@@ -1568,7 +1773,8 @@ async function main() {
1568
1773
  argv[0] === 'status' ||
1569
1774
  argv[0] === 'init-oxe' ||
1570
1775
  argv[0] === 'uninstall' ||
1571
- argv[0] === 'update'
1776
+ argv[0] === 'update' ||
1777
+ argv[0] === 'install'
1572
1778
  ) {
1573
1779
  command = argv[0];
1574
1780
  argv.shift();
@@ -1668,7 +1874,6 @@ async function main() {
1668
1874
  console.error(`${yellow}Diretório não encontrado: ${target}${reset}`);
1669
1875
  process.exit(1);
1670
1876
  }
1671
- printBanner();
1672
1877
  runStatus(target);
1673
1878
  return;
1674
1879
  }