oxe-cc 1.4.0 → 1.5.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 (142) hide show
  1. package/.cursor/commands/oxe-ask.md +4 -2
  2. package/.cursor/commands/oxe-capabilities.md +4 -2
  3. package/.cursor/commands/oxe-checkpoint.md +4 -2
  4. package/.cursor/commands/oxe-compact.md +4 -2
  5. package/.cursor/commands/oxe-dashboard.md +4 -2
  6. package/.cursor/commands/oxe-debug.md +4 -2
  7. package/.cursor/commands/oxe-discuss.md +4 -2
  8. package/.cursor/commands/oxe-execute.md +5 -3
  9. package/.cursor/commands/oxe-forensics.md +4 -2
  10. package/.cursor/commands/oxe-help.md +4 -2
  11. package/.cursor/commands/oxe-loop.md +4 -2
  12. package/.cursor/commands/oxe-milestone.md +4 -2
  13. package/.cursor/commands/oxe-next.md +4 -2
  14. package/.cursor/commands/oxe-obs.md +4 -2
  15. package/.cursor/commands/oxe-plan-agent.md +4 -2
  16. package/.cursor/commands/oxe-plan.md +4 -2
  17. package/.cursor/commands/oxe-project.md +4 -2
  18. package/.cursor/commands/oxe-quick.md +4 -2
  19. package/.cursor/commands/oxe-research.md +4 -2
  20. package/.cursor/commands/oxe-retro.md +4 -2
  21. package/.cursor/commands/oxe-review-pr.md +4 -2
  22. package/.cursor/commands/oxe-route.md +4 -2
  23. package/.cursor/commands/oxe-scan.md +4 -2
  24. package/.cursor/commands/oxe-security.md +4 -2
  25. package/.cursor/commands/oxe-session.md +5 -3
  26. package/.cursor/commands/oxe-ship.md +4 -2
  27. package/.cursor/commands/oxe-skill.md +4 -2
  28. package/.cursor/commands/oxe-spec.md +4 -2
  29. package/.cursor/commands/oxe-ui-review.md +4 -2
  30. package/.cursor/commands/oxe-ui-spec.md +4 -2
  31. package/.cursor/commands/oxe-update.md +4 -2
  32. package/.cursor/commands/oxe-validate-gaps.md +4 -2
  33. package/.cursor/commands/oxe-verify-audit.md +46 -0
  34. package/.cursor/commands/oxe-verify.md +4 -2
  35. package/.cursor/commands/oxe-workflow-authoring.md +47 -0
  36. package/.cursor/commands/oxe-workstream.md +4 -2
  37. package/.cursor/commands/oxe.md +6 -2
  38. package/.github/prompts/oxe-ask.prompt.md +4 -2
  39. package/.github/prompts/oxe-capabilities.prompt.md +4 -2
  40. package/.github/prompts/oxe-checkpoint.prompt.md +4 -2
  41. package/.github/prompts/oxe-compact.prompt.md +5 -3
  42. package/.github/prompts/oxe-dashboard.prompt.md +4 -2
  43. package/.github/prompts/oxe-debug.prompt.md +4 -2
  44. package/.github/prompts/oxe-discuss.prompt.md +6 -2
  45. package/.github/prompts/oxe-execute.prompt.md +5 -3
  46. package/.github/prompts/oxe-forensics.prompt.md +4 -2
  47. package/.github/prompts/oxe-help.prompt.md +6 -2
  48. package/.github/prompts/oxe-loop.prompt.md +4 -2
  49. package/.github/prompts/oxe-milestone.prompt.md +4 -2
  50. package/.github/prompts/oxe-next.prompt.md +6 -2
  51. package/.github/prompts/oxe-obs.prompt.md +4 -2
  52. package/.github/prompts/oxe-plan-agent.prompt.md +5 -2
  53. package/.github/prompts/oxe-plan.prompt.md +4 -2
  54. package/.github/prompts/oxe-project.prompt.md +4 -2
  55. package/.github/prompts/oxe-quick.prompt.md +4 -2
  56. package/.github/prompts/oxe-research.prompt.md +4 -2
  57. package/.github/prompts/oxe-retro.prompt.md +4 -2
  58. package/.github/prompts/oxe-review-pr.prompt.md +4 -2
  59. package/.github/prompts/oxe-route.prompt.md +4 -2
  60. package/.github/prompts/oxe-scan.prompt.md +4 -2
  61. package/.github/prompts/oxe-security.prompt.md +4 -2
  62. package/.github/prompts/oxe-session.prompt.md +5 -3
  63. package/.github/prompts/oxe-ship.prompt.md +4 -2
  64. package/.github/prompts/oxe-skill.prompt.md +4 -2
  65. package/.github/prompts/oxe-spec.prompt.md +4 -2
  66. package/.github/prompts/oxe-ui-review.prompt.md +4 -2
  67. package/.github/prompts/oxe-ui-spec.prompt.md +4 -2
  68. package/.github/prompts/oxe-update.prompt.md +4 -2
  69. package/.github/prompts/oxe-validate-gaps.prompt.md +4 -2
  70. package/.github/prompts/oxe-verify-audit.prompt.md +46 -0
  71. package/.github/prompts/oxe-verify.prompt.md +4 -2
  72. package/.github/prompts/oxe-workflow-authoring.prompt.md +47 -0
  73. package/.github/prompts/oxe-workstream.prompt.md +4 -2
  74. package/.github/prompts/oxe.prompt.md +6 -2
  75. package/.github/workflows/ci.yml +57 -20
  76. package/.github/workflows/release.yml +94 -0
  77. package/AGENTS.md +3 -1
  78. package/CHANGELOG.md +383 -342
  79. package/QUICKSTART.md +99 -0
  80. package/README.md +89 -65
  81. package/bin/lib/oxe-agent-install.cjs +127 -107
  82. package/bin/lib/oxe-install-resolve.cjs +10 -0
  83. package/bin/lib/oxe-operational.cjs +34 -28
  84. package/bin/lib/oxe-project-health.cjs +38 -6
  85. package/bin/lib/oxe-release.cjs +423 -0
  86. package/bin/lib/oxe-runtime-semantics.cjs +68 -24
  87. package/bin/oxe-cc.js +388 -55
  88. package/commands/oxe/ask.md +7 -3
  89. package/commands/oxe/capabilities.md +6 -2
  90. package/commands/oxe/checkpoint.md +5 -1
  91. package/commands/oxe/compact.md +6 -2
  92. package/commands/oxe/dashboard.md +6 -2
  93. package/commands/oxe/debug.md +6 -2
  94. package/commands/oxe/discuss.md +6 -2
  95. package/commands/oxe/execute.md +6 -2
  96. package/commands/oxe/forensics.md +6 -2
  97. package/commands/oxe/help.md +6 -2
  98. package/commands/oxe/loop.md +6 -2
  99. package/commands/oxe/milestone.md +6 -2
  100. package/commands/oxe/next.md +6 -2
  101. package/commands/oxe/obs.md +6 -2
  102. package/commands/oxe/oxe.md +6 -2
  103. package/commands/oxe/plan-agent.md +6 -2
  104. package/commands/oxe/plan.md +6 -2
  105. package/commands/oxe/project.md +6 -2
  106. package/commands/oxe/quick.md +6 -2
  107. package/commands/oxe/research.md +6 -2
  108. package/commands/oxe/retro.md +6 -2
  109. package/commands/oxe/review-pr.md +6 -2
  110. package/commands/oxe/route.md +6 -2
  111. package/commands/oxe/scan.md +6 -2
  112. package/commands/oxe/security.md +6 -2
  113. package/commands/oxe/session.md +6 -2
  114. package/commands/oxe/ship.md +6 -2
  115. package/commands/oxe/skill.md +6 -2
  116. package/commands/oxe/spec.md +6 -2
  117. package/commands/oxe/ui-review.md +6 -2
  118. package/commands/oxe/ui-spec.md +6 -2
  119. package/commands/oxe/update.md +6 -2
  120. package/commands/oxe/validate-gaps.md +6 -2
  121. package/commands/oxe/verify-audit.md +50 -0
  122. package/commands/oxe/verify.md +6 -2
  123. package/commands/oxe/workflow-authoring.md +50 -0
  124. package/commands/oxe/workstream.md +6 -2
  125. package/docs/INCIDENT-PLAYBOOK.md +181 -0
  126. package/docs/RELEASE-READINESS.md +46 -0
  127. package/docs/ROLES.md +129 -0
  128. package/docs/RUNTIME-SMOKE-MATRIX.md +128 -0
  129. package/docs/TEAM-ADOPTION.md +153 -0
  130. package/docs/WALKTHROUGH.md +241 -0
  131. package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +28 -0
  132. package/lib/runtime/scheduler/multi-agent-coordinator.js +152 -26
  133. package/lib/sdk/README.md +2 -0
  134. package/lib/sdk/index.cjs +22 -8
  135. package/lib/sdk/index.d.ts +60 -16
  136. package/oxe/templates/config.template.json +1 -0
  137. package/package.json +30 -22
  138. package/packages/runtime/package.json +1 -1
  139. package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +357 -193
  140. package/vscode-extension/oxe-agents-1.4.0.vsix +0 -0
  141. package/vscode-extension/oxe-agents-1.5.0.vsix +0 -0
  142. package/vscode-extension/package.json +1 -1
package/bin/oxe-cc.js CHANGED
@@ -24,6 +24,7 @@ const oxeAzure = require(path.join(__dirname, 'lib', 'oxe-azure.cjs'));
24
24
  const oxePlugins = require(path.join(__dirname, 'lib', 'oxe-plugins.cjs'));
25
25
  const oxeContext = require(path.join(__dirname, 'lib', 'oxe-context-engine.cjs'));
26
26
  const oxeRuntimeSemantics = require(path.join(__dirname, 'lib', 'oxe-runtime-semantics.cjs'));
27
+ const oxeRelease = require(path.join(__dirname, 'lib', 'oxe-release.cjs'));
27
28
 
28
29
  /** Merge markers for ~/.copilot/copilot-instructions.md (bloco OXE). */
29
30
  const OXE_INST_BEGIN = '<!-- oxe-cc:install-begin -->';
@@ -251,6 +252,13 @@ function buildUninstallFooter(u) {
251
252
  const bullets = [];
252
253
  const p = u.dryRun ? '[simulação] ' : '';
253
254
  const rm = u.dryRun ? 'Seriam removidos' : 'Removidos';
255
+ const granularAgents = [
256
+ u.agentOpenCode ? 'OpenCode' : null,
257
+ u.agentGemini ? 'Gemini' : null,
258
+ u.agentCodex ? 'Codex' : null,
259
+ u.agentWindsurf ? 'Windsurf' : null,
260
+ u.agentAntigravity ? 'Antigravity' : null,
261
+ ].filter(Boolean);
254
262
  if (u.cursor) bullets.push(`${p}${rm} artefatos OXE em ~/.cursor (comandos e regras).`);
255
263
  if (u.copilot) {
256
264
  bullets.push(`${p}${rm} prompt files OXE em .github/prompts/ e o bloco OXE em .github/copilot-instructions.md.`);
@@ -258,12 +266,16 @@ function buildUninstallFooter(u) {
258
266
  if (u.copilotLegacyClean) {
259
267
  bullets.push(`${p}${rm} apenas o legado global do Copilot VS Code em ~/.copilot/ (prompts oxe-* e bloco OXE global).`);
260
268
  }
261
- if (u.copilotCli || u.allAgents) {
262
- bullets.push(`${p}${rm} comandos oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
269
+ if (u.copilotCli) {
270
+ bullets.push(`${p}${rm} comandos oxe/oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
263
271
  bullets.push(`${p}${rm} skills OXE (marcadas oxe-cc) em ~/.copilot/skills/oxe*/.`);
272
+ }
273
+ if (u.allAgents) {
264
274
  bullets.push(
265
275
  `${p}${rm} extensões multi-agente marcadas oxe-cc (OpenCode, Gemini TOML, Windsurf workflows, Codex prompts/skills, Antigravity), se existirem.`
266
276
  );
277
+ } else if (granularAgents.length) {
278
+ bullets.push(`${p}${rm} apenas as integrações selecionadas: ${granularAgents.join(', ')}.`);
267
279
  }
268
280
  if (u.ideLocal) {
269
281
  bullets.push(
@@ -285,13 +297,30 @@ function buildUninstallFooter(u) {
285
297
  return { bullets, nextSteps, dryRun: u.dryRun };
286
298
  }
287
299
 
288
- /** @typedef {{ help: boolean, version: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, agentOpenCode: boolean, agentGemini: boolean, agentCodex: boolean, agentWindsurf: boolean, agentAntigravity: 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, ideLocal: boolean, explicitIdeScope: boolean, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string, ignoreInstallConfig: boolean }} InstallOpts */
300
+ /** @typedef {{ help: boolean, version: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, agentOpenCode: boolean, agentGemini: boolean, agentCodex: boolean, agentWindsurf: boolean, agentAntigravity: 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, ideLocal: boolean, explicitIdeScope: boolean, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string, ignoreInstallConfig: boolean, releaseDoctor: boolean, writeManifest: boolean }} InstallOpts */
289
301
 
290
302
  /** @param {InstallOpts} o */
291
303
  function anyGranularAgent(o) {
292
304
  return !!(o.agentOpenCode || o.agentGemini || o.agentCodex || o.agentWindsurf || o.agentAntigravity);
293
305
  }
294
306
 
307
+ /** @param {UninstallOpts} o */
308
+ function anyGranularUninstallAgent(o) {
309
+ return !!(o.agentOpenCode || o.agentGemini || o.agentCodex || o.agentWindsurf || o.agentAntigravity);
310
+ }
311
+
312
+ /** @param {UninstallOpts} u */
313
+ function buildAgentCleanupTargets(u) {
314
+ if (u.allAgents || !anyGranularUninstallAgent(u)) return null;
315
+ return {
316
+ opencode: Boolean(u.agentOpenCode),
317
+ gemini: Boolean(u.agentGemini),
318
+ windsurf: Boolean(u.agentWindsurf),
319
+ codex: Boolean(u.agentCodex),
320
+ antigravity: Boolean(u.agentAntigravity),
321
+ };
322
+ }
323
+
295
324
  /** @param {InstallOpts} o */
296
325
  function anyIdeIntegration(o) {
297
326
  return !!(o.cursor || o.copilot || o.copilotCli || o.allAgents || anyGranularAgent(o));
@@ -336,6 +365,8 @@ function parseInstallArgs(argv) {
336
365
  unknownFlag: '',
337
366
  conflictFlags: '',
338
367
  ignoreInstallConfig: false,
368
+ releaseDoctor: false,
369
+ writeManifest: false,
339
370
  /** Saída JSON em `status` (CI / agentes). */
340
371
  jsonOutput: false,
341
372
  /** Lembretes agregados scan/compact em `status`. */
@@ -387,6 +418,8 @@ function parseInstallArgs(argv) {
387
418
  } else if (a === '--json') out.jsonOutput = true;
388
419
  else if (a === '--hints') out.statusHints = true;
389
420
  else if (a === '--full') out.statusFull = true;
421
+ else if (a === '--release') out.releaseDoctor = true;
422
+ else if (a === '--write-manifest') out.writeManifest = true;
390
423
  else if (!a.startsWith('-')) out.restPositional.push(a);
391
424
  else {
392
425
  out.parseError = true;
@@ -429,6 +462,14 @@ function parseInstallArgs(argv) {
429
462
  out.agentWindsurf = true;
430
463
  out.agentAntigravity = true;
431
464
  }
465
+ if (!out.conflictFlags && out.oxeOnly) {
466
+ const IDE_FLAGS = ['--cursor', '--copilot', '--copilot-vscode', '--copilot-cli', '--all-agents',
467
+ '--opencode', '--gemini', '--codex', '--windsurf', '--antigravity', '--vscode'];
468
+ const conflicting = IDE_FLAGS.filter((f) => argv.includes(f));
469
+ if (conflicting.length > 0) {
470
+ out.conflictFlags = `--oxe-only não combina com flags de IDE (${conflicting.join(', ')})`;
471
+ }
472
+ }
432
473
  if (out.oxeOnly) {
433
474
  out.cursor = false;
434
475
  out.copilot = false;
@@ -749,7 +790,11 @@ function writeCopilotVsCodeManifest(opts, info) {
749
790
  const promptFiles = fs.existsSync(promptsDir)
750
791
  ? fs
751
792
  .readdirSync(promptsDir, { withFileTypes: true })
752
- .filter((entry) => entry.isFile() && /^oxe-.*\.prompt\.md$/i.test(entry.name))
793
+ .filter(
794
+ (entry) =>
795
+ entry.isFile() &&
796
+ (entry.name === 'oxe.prompt.md' || /^oxe-.*\.prompt\.md$/i.test(entry.name))
797
+ )
753
798
  .map((entry) => entry.name)
754
799
  .sort()
755
800
  : [];
@@ -1010,6 +1055,27 @@ async function promptInstallScope(opts) {
1010
1055
  }
1011
1056
  }
1012
1057
 
1058
+ /**
1059
+ * Grava a escolha resolvida de ide_scope de volta em .oxe/config.json para que
1060
+ * futuras reinstalações/updates não precisem perguntar novamente.
1061
+ * @param {InstallOpts} opts
1062
+ */
1063
+ function persistIdeScope(opts) {
1064
+ if (opts.dryRun || opts.oxeOnly) return;
1065
+ const configPath = path.join(opts.dir, '.oxe', 'config.json');
1066
+ if (!fs.existsSync(configPath)) return;
1067
+ try {
1068
+ const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
1069
+ const scope = opts.ideLocal ? 'local' : 'global';
1070
+ if (!cfg.install || typeof cfg.install !== 'object') cfg.install = {};
1071
+ if (cfg.install.ide_scope === scope) return;
1072
+ cfg.install.ide_scope = scope;
1073
+ fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2) + '\n', 'utf8');
1074
+ } catch {
1075
+ /* silêncio — não bloquear instalação por falha ao persistir config */
1076
+ }
1077
+ }
1078
+
1013
1079
  /** @param {InstallOpts} opts */
1014
1080
  async function resolveInteractiveInstall(opts) {
1015
1081
  if (!opts.ignoreInstallConfig) {
@@ -1252,7 +1318,13 @@ function bootstrapOxe(target, opts) {
1252
1318
 
1253
1319
  if (fs.existsSync(configSrc)) {
1254
1320
  if (!fs.existsSync(configDest) || opts.force) {
1255
- copyFile(configSrc, configDest, { dryRun: false });
1321
+ try {
1322
+ const cfgRaw = JSON.parse(fs.readFileSync(configSrc, 'utf8'));
1323
+ delete cfgRaw._comment;
1324
+ fs.writeFileSync(configDest, JSON.stringify(cfgRaw, null, 2) + '\n', 'utf8');
1325
+ } catch {
1326
+ copyFile(configSrc, configDest, { dryRun: false });
1327
+ }
1256
1328
  console.log(`${green}init${reset} ${configDest}`);
1257
1329
  } else {
1258
1330
  console.log(`${dim}omitido${reset} ${configDest} (já existe — use --force para substituir)`);
@@ -1834,6 +1906,39 @@ function runStatus(target, opts = {}) {
1834
1906
 
1835
1907
  printOxeHealthDiagnostics(target, c, { skipScanCompactAgeWarnings: Boolean(opts.hints) });
1836
1908
 
1909
+ // IDE readiness summary
1910
+ const ideStatusLines = [];
1911
+ const _copilotPromptsDir = path.join(target, '.github', 'prompts');
1912
+ const _copilotInstructions = path.join(target, '.github', 'copilot-instructions.md');
1913
+ ideStatusLines.push(`Copilot ${fs.existsSync(_copilotPromptsDir) || fs.existsSync(_copilotInstructions) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1914
+ ideStatusLines.push(`Cursor ${fs.existsSync(path.join(target, '.cursor', 'commands')) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1915
+ const _claudeLocal = path.join(target, 'commands', 'oxe');
1916
+ const _claudeGlobal = path.join(require('os').homedir(), '.claude', 'commands');
1917
+ ideStatusLines.push(`Claude Code ${fs.existsSync(_claudeLocal) || fs.existsSync(_claudeGlobal) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1918
+ console.log(`\n ${c ? dim : ''}IDEs:${c ? reset : ''} ${ideStatusLines.join(' ')}`);
1919
+
1920
+ // Gates pending in default view
1921
+ const pendingGateCount = report.pendingGates ? (report.pendingGates.pendingCount || 0) : 0;
1922
+ const staleGateCount = report.pendingGates ? (report.pendingGates.staleGateCount || 0) : 0;
1923
+ if (pendingGateCount > 0 || staleGateCount > 0) {
1924
+ const gateMsg = [];
1925
+ if (pendingGateCount > 0) gateMsg.push(`${pendingGateCount} pendente(s)`);
1926
+ if (staleGateCount > 0) gateMsg.push(`${staleGateCount} stale`);
1927
+ console.log(` ${c ? yellow : ''}⚠ Gates:${c ? reset : ''} ${gateMsg.join(', ')} — ${c ? cyan : ''}npx oxe-cc runtime gates list --dir .${c ? reset : ''}`);
1928
+ }
1929
+
1930
+ // Explicit blockage diagnosis
1931
+ const specMissing = !fs.existsSync(path.join(target, '.oxe', 'SPEC.md'));
1932
+ const planMissing = !fs.existsSync(path.join(target, '.oxe', 'PLAN.md'));
1933
+ const verifyMissing = !fs.existsSync(path.join(target, '.oxe', 'VERIFY.md'));
1934
+ if (specMissing) {
1935
+ console.log(` ${c ? yellow : ''}⚠ Bloqueio:${c ? reset : ''} SPEC.md ausente — rode ${c ? cyan : ''}/oxe-spec${c ? reset : ''} antes de planejar`);
1936
+ } else if (planMissing) {
1937
+ console.log(` ${c ? yellow : ''}⚠ Bloqueio:${c ? reset : ''} PLAN.md ausente — rode ${c ? cyan : ''}/oxe-plan${c ? reset : ''}`);
1938
+ } else if (verifyMissing && !planMissing) {
1939
+ console.log(` ${c ? dim : ''}Obs.:${c ? reset : ''} VERIFY.md ainda não gerado — rode ${c ? cyan : ''}/oxe-verify${c ? reset : ''} após executar`);
1940
+ }
1941
+
1837
1942
  if (opts.hints) {
1838
1943
  console.log(`\n ${c ? cyan : ''}Lembretes (rotina OXE)${reset}`);
1839
1944
  if (routineHints.length) {
@@ -1865,7 +1970,46 @@ function runStatus(target, opts = {}) {
1865
1970
  }
1866
1971
 
1867
1972
  /** @param {string} target */
1868
- function runDoctor(target) {
1973
+ function runDoctor(target, options = {}) {
1974
+ if (options.release) {
1975
+ if (!options.json) printSection('OXE ▸ doctor --release');
1976
+ const c = useAnsiColors();
1977
+ const result = oxeRelease.checkReleaseConsistency(target, {
1978
+ packageRoot: PKG_ROOT,
1979
+ writeManifest: Boolean(options.writeManifest),
1980
+ });
1981
+ if (options.json) {
1982
+ console.log(
1983
+ JSON.stringify(
1984
+ {
1985
+ status: result.ok ? 'ok' : 'blocked',
1986
+ blockers: result.blockers,
1987
+ warnings: result.warnings,
1988
+ manifestPath: result.manifestPath,
1989
+ manifest: result.manifest,
1990
+ },
1991
+ null,
1992
+ 2
1993
+ )
1994
+ );
1995
+ } else {
1996
+ console.log(` ${c ? green : ''}Projeto:${c ? reset : ''} ${c ? cyan : ''}${target}${c ? reset : ''}`);
1997
+ console.log(` ${c ? green : ''}Versão alvo:${c ? reset : ''} ${result.manifest.versions.rootPackage.version || '—'}`);
1998
+ console.log(` ${c ? green : ''}Manifest:${c ? reset : ''} ${result.manifestPath}`);
1999
+ if (result.ok) {
2000
+ console.log(` ${c ? green : ''}✓${c ? reset : ''} release readiness OK`);
2001
+ } else {
2002
+ console.log(` ${c ? red : ''}✗${c ? reset : ''} release readiness bloqueada`);
2003
+ for (const blocker of result.blockers) {
2004
+ console.log(` - ${blocker}`);
2005
+ }
2006
+ }
2007
+ for (const warning of result.warnings) {
2008
+ console.log(` ${c ? yellow : ''}!${c ? reset : ''} ${warning}`);
2009
+ }
2010
+ }
2011
+ process.exit(result.ok ? 0 : 1);
2012
+ }
1869
2013
  printSection('OXE ▸ doctor');
1870
2014
  const v = process.versions.node;
1871
2015
  const major = parseInt(v.split('.')[0], 10);
@@ -1979,6 +2123,72 @@ function runDoctor(target) {
1979
2123
  }
1980
2124
  }
1981
2125
 
2126
+ // IDE health gates
2127
+ console.log('');
2128
+ const ideChecks = [];
2129
+ const copilotPromptsDir = path.join(target, '.github', 'prompts');
2130
+ const copilotInstructions = path.join(target, '.github', 'copilot-instructions.md');
2131
+ const copilotReady = fs.existsSync(copilotPromptsDir) || fs.existsSync(copilotInstructions);
2132
+ ideChecks.push({ label: 'Copilot', ready: copilotReady, hint: '.github/prompts/ ou copilot-instructions.md' });
2133
+
2134
+ const cursorDir = path.join(target, '.cursor', 'commands');
2135
+ const cursorReady = fs.existsSync(cursorDir);
2136
+ ideChecks.push({ label: 'Cursor', ready: cursorReady, hint: '.cursor/commands/' });
2137
+
2138
+ const claudeLocalDir = path.join(target, 'commands', 'oxe');
2139
+ const claudeGlobalDir = path.join(require('os').homedir(), '.claude', 'commands');
2140
+ const claudeReady = fs.existsSync(claudeLocalDir) || fs.existsSync(claudeGlobalDir);
2141
+ ideChecks.push({ label: 'Claude Code', ready: claudeReady, hint: 'commands/oxe/ ou ~/.claude/commands/' });
2142
+
2143
+ for (const ide of ideChecks) {
2144
+ if (ide.ready) {
2145
+ console.log(`${c ? green : ''}OK${c ? reset : ''} ${ide.label} pronto (${ide.hint})`);
2146
+ } else {
2147
+ console.log(`${c ? dim : ''}Obs.:${c ? reset : ''} ${ide.label} não detectado — esperado ${ide.hint}`);
2148
+ }
2149
+ }
2150
+
2151
+ // Runtime compilation check
2152
+ const runtimeCompiledPath = path.join(target, 'lib', 'runtime', 'index.js');
2153
+ const runtimeDistPath = path.join(target, 'packages', 'runtime', 'dist-tests');
2154
+ const runtimeCompiled = fs.existsSync(runtimeCompiledPath) || fs.existsSync(runtimeDistPath);
2155
+ if (runtimeCompiled) {
2156
+ console.log(`${c ? green : ''}OK${c ? reset : ''} Runtime compilado detectado — modo enterprise disponível`);
2157
+ } else {
2158
+ console.log(`${c ? dim : ''}Obs.:${c ? reset : ''} Runtime não compilado — operando em modo legado (sem perda de UX)`);
2159
+ }
2160
+
2161
+ // Readiness gate summary
2162
+ const stateFilePath = path.join(target, '.oxe', 'STATE.md');
2163
+ let readinessCmd = '/oxe-scan';
2164
+ let readinessDesc = 'Nenhum STATE.md encontrado';
2165
+ if (fs.existsSync(stateFilePath)) {
2166
+ try {
2167
+ const stateContent = fs.readFileSync(stateFilePath, 'utf8');
2168
+ const phaseMatch = stateContent.match(/fase[:\s]+([a-z_]+)/i) || stateContent.match(/phase[:\s]+([a-z_]+)/i) || stateContent.match(/status[:\s]+([a-z_]+)/i);
2169
+ const phase = phaseMatch ? phaseMatch[1].toLowerCase() : 'init';
2170
+ const phaseMap = {
2171
+ init: { cmd: '/oxe-scan', desc: 'Pronto para /oxe-scan' },
2172
+ scan_complete: { cmd: '/oxe-spec', desc: 'Pronto para /oxe-spec' },
2173
+ spec_complete: { cmd: '/oxe-plan', desc: 'Pronto para /oxe-plan' },
2174
+ plan_complete: { cmd: '/oxe-execute', desc: 'Pronto para /oxe-execute' },
2175
+ execute_complete: { cmd: '/oxe-verify', desc: 'Pronto para /oxe-verify' },
2176
+ verify_complete: { cmd: 'runtime promote --target pr_draft', desc: 'Pronto para promoção' },
2177
+ };
2178
+ const next = phaseMap[phase] || { cmd: '/oxe', desc: `Fase detectada: ${phase}` };
2179
+ readinessCmd = next.cmd;
2180
+ readinessDesc = next.desc;
2181
+ } catch (_) { /* ignore */ }
2182
+ }
2183
+ const specPath = path.join(target, '.oxe', 'SPEC.md');
2184
+ const specExists = fs.existsSync(specPath);
2185
+ console.log('');
2186
+ if (specExists) {
2187
+ console.log(` ${c ? green : ''}✓ ${readinessDesc}${c ? reset : ''} — próximo: ${c ? cyan : ''}${readinessCmd}${c ? reset : ''}`);
2188
+ } else {
2189
+ console.log(` ${c ? yellow : ''}⚠ Falta SPEC — rode ${c ? cyan : ''}${readinessCmd}${c ? reset : ''}`);
2190
+ }
2191
+
1982
2192
  printOxeHealthDiagnostics(target, c);
1983
2193
  const report = oxeHealth.buildHealthReport(target);
1984
2194
  const statusColor = report.healthStatus === 'healthy' ? green : report.healthStatus === 'warning' ? yellow : red;
@@ -1986,10 +2196,12 @@ function runDoctor(target) {
1986
2196
  if (report.healthStatus === 'broken') {
1987
2197
  process.exitCode = 1;
1988
2198
  }
2199
+ const ideReadySummary = ideChecks.filter((i) => i.ready).map((i) => i.label).join(', ') || 'nenhuma IDE detectada';
1989
2200
  printSummaryAndNextSteps(c, {
1990
2201
  bullets: [
1991
2202
  `Projeto em ${target}`,
1992
2203
  `Workflows conferidos em ${wfLabel}`,
2204
+ `IDEs prontas: ${ideReadySummary}`,
1993
2205
  `Saúde lógica: ${report.healthStatus}`,
1994
2206
  ],
1995
2207
  nextSteps: [
@@ -2018,6 +2230,12 @@ function installGlobalCliPackage() {
2018
2230
  shell: true,
2019
2231
  env: process.env,
2020
2232
  });
2233
+ if (r.error) {
2234
+ console.log(
2235
+ `\n ${c ? yellow : ''}⚠${c ? reset : ''} npm install -g falhou (${r.error.message}). Tente manualmente: ${c ? cyan : ''}npm install -g ${spec}${c ? reset : ''}\n`
2236
+ );
2237
+ return false;
2238
+ }
2021
2239
  if (r.status === 0) {
2022
2240
  console.log(
2023
2241
  `\n ${c ? green : ''}✓${c ? reset : ''} ${c ? cyan : ''}oxe-cc${c ? reset : ''} disponível globalmente (execute ${c ? cyan : ''}oxe-cc --help${c ? reset : ''} em qualquer pasta).\n`
@@ -2199,30 +2417,37 @@ function usage() {
2199
2417
  console.log(`
2200
2418
  ${cyan}oxe-cc${reset} — instala workflows OXE (núcleo .oxe/ + integrações: Cursor, Copilot, Claude, OpenCode, Gemini, Codex, Windsurf, Antigravity, …)
2201
2419
 
2202
- ${green}Uso:${reset}
2203
- npx oxe-cc@latest [opções] [pasta-do-projeto]
2204
- npx oxe-cc@latest install [opções] [pasta-do-projeto] ${dim}(equivalente à instalação predefinida)${reset}
2205
- npx oxe-cc@latest --dir /caminho/do/projeto
2206
- npx oxe-cc doctor [opções] [pasta-do-projeto]
2207
- npx oxe-cc status [opções] [pasta-do-projeto]
2208
- npx oxe-cc init-oxe [opções] [pasta-do-projeto]
2209
- npx oxe-cc context <build|inspect> [opções] [pasta-do-projeto]
2210
- npx oxe-cc dashboard [opções] [pasta-do-projeto]
2211
- npx oxe-cc runtime <status|start|pause|resume|replay|compile|verify|project|ci|promote|recover|gates> [opções] [pasta-do-projeto]
2212
- npx oxe-cc azure <status|doctor|auth|sync|find|servicebus|eventgrid|sql|operations> [opções] [pasta-do-projeto]
2213
- npx oxe-cc capabilities <list|install|remove|update> [opções] [id]
2214
- npx oxe-cc uninstall [opções] [pasta-do-projeto]
2215
- npx oxe-cc update [opções] [argumentos extras…]
2216
-
2217
- ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
2420
+ ${green}Uso:${reset}
2421
+ npx oxe-cc@latest [opções] [pasta-do-projeto]
2422
+ npx oxe-cc@latest install [opções] [pasta-do-projeto] ${dim}(equivalente à instalação predefinida)${reset}
2423
+ npx oxe-cc@latest --dir /caminho/do/projeto
2424
+ npx oxe-cc doctor [--release] [--write-manifest] [opções] [pasta-do-projeto]
2425
+ npx oxe-cc status [opções] [pasta-do-projeto]
2426
+ npx oxe-cc init-oxe [opções] [pasta-do-projeto]
2427
+ npx oxe-cc context <build|inspect> [opções] [pasta-do-projeto]
2428
+ npx oxe-cc dashboard [opções] [pasta-do-projeto]
2429
+ npx oxe-cc runtime <status|start|pause|resume|replay|compile|verify|project|ci|promote|recover|gates|agents> [opções] [pasta-do-projeto]
2430
+ npx oxe-cc azure <status|doctor|auth|sync|find|servicebus|eventgrid|sql|operations> [opções] [pasta-do-projeto]
2431
+ npx oxe-cc capabilities <list|install|remove|update> [opções] [id]
2432
+ npx oxe-cc uninstall [opções] [pasta-do-projeto]
2433
+ npx oxe-cc update [opções] [argumentos extras…]
2434
+
2435
+ ${green}doctor${reset}
2436
+ --release valida release readiness: versões, changelog, wrappers, runtime build e relatórios obrigatórios
2437
+ --write-manifest persiste .oxe/release/release-manifest.json durante doctor --release
2438
+ --json saída estruturada para CI
2439
+
2440
+ ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
2218
2441
  --cursor / --copilot / --copilot-cli só essa integração (omissão = todas)
2219
2442
  --copilot-vscode alias explícito de --copilot
2220
2443
  --copilot-legacy-clean limpa só o legado antigo do Copilot VS Code em ~/.copilot/
2221
2444
  --all-agents também remove ficheiros multi-plataforma (com --copilot-cli implícito)
2445
+ --opencode / --gemini / --codex / --windsurf / --antigravity
2446
+ remove só esse agente multi-runtime
2222
2447
  --ide-local remove integrações IDE neste repositório (.cursor, .github, .claude, .copilot, …)
2223
2448
  --ide-only não apagar .oxe/workflows, oxe/, etc. no projeto
2224
2449
  --global-cli, -g também executa npm uninstall -g oxe-cc
2225
- --config-dir <caminho> com exatamente uma flag IDE acima (não combina com --ide-local nem com --copilot)
2450
+ --config-dir <caminho> com exatamente uma flag IDE acima (não combina com --ide-local, --copilot nem agentes granulares)
2226
2451
  --dry-run
2227
2452
  --dir <pasta> raiz do projeto (padrão: diretório atual)
2228
2453
 
@@ -2260,7 +2485,7 @@ ${green}runtime${reset} (controle operacional explícito do ACTIVE-RUN)
2260
2485
  verify executa a suite enterprise, coleta evidência e projeta VERIFY.md
2261
2486
  project projeta markdowns derivados do estado canônico
2262
2487
  ci executa checks do runtime e persiste o resultado na run
2263
- promote promove remotamente a run ativa (estável: pr_draft)
2488
+ promote promove remotamente a run ativa (estável: pr_draft)
2264
2489
  recover reidrata estado canônico/journal/gates/policy da run ativa
2265
2490
  gates <list|show|resolve> fila operacional de gates pendentes e resoluções auditáveis
2266
2491
  --session <sessions/sNNN-slug> força sessão específica
@@ -2274,7 +2499,7 @@ ${green}runtime${reset} (controle operacional explícito do ACTIVE-RUN)
2274
2499
  --gate <gate_id> (gates show|resolve) gate alvo
2275
2500
  --decision <approve|reject|waive> (gates resolve) decisão aplicada
2276
2501
  --actor <id> (gates resolve) ator responsável
2277
- --target <pr_draft|branch_push> (promote) alvo remoto; padrão pr_draft, branch_push é avançado
2502
+ --target <pr_draft|branch_push> (promote) alvo remoto; padrão pr_draft, branch_push é avançado
2278
2503
  --remote <nome> (promote) remote git; padrão origin
2279
2504
  --base <branch> (promote) branch/ref base; padrão main
2280
2505
  --minimum-coverage <0-100> (promote) cobertura mínima exigida; padrão 100
@@ -2619,8 +2844,8 @@ function runInstall(opts) {
2619
2844
  }
2620
2845
  trackFile(runtimeSemanticsManifestPath(opts));
2621
2846
  if (opts.copilotCli || opts.allAgents) {
2622
- addTracked(path.join(installClaudeBase(opts), 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2623
- addTracked(path.join(cpCliHome, 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2847
+ addTracked(path.join(installClaudeBase(opts), 'commands'), (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2848
+ addTracked(path.join(cpCliHome, 'commands'), (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2624
2849
  const skRoot = path.join(cpCliHome, 'skills');
2625
2850
  if (fs.existsSync(skRoot)) {
2626
2851
  for (const sub of fs.readdirSync(skRoot, { withFileTypes: true })) {
@@ -2638,7 +2863,7 @@ function runInstall(opts) {
2638
2863
  }
2639
2864
  if (opts.agentOpenCode || opts.allAgents) {
2640
2865
  for (const d of agentPaths.opencodeCommandDirs) {
2641
- addTracked(d, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2866
+ addTracked(d, (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2642
2867
  }
2643
2868
  }
2644
2869
  if (opts.agentGemini || opts.allAgents) {
@@ -2657,7 +2882,7 @@ function runInstall(opts) {
2657
2882
  if (opts.agentCodex || opts.allAgents) {
2658
2883
  const cxPrompts = agentPaths.codexPromptsDir;
2659
2884
  if (fs.existsSync(cxPrompts)) {
2660
- addTracked(cxPrompts, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2885
+ addTracked(cxPrompts, (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2661
2886
  }
2662
2887
  }
2663
2888
  if (opts.agentAntigravity || opts.allAgents) {
@@ -2702,7 +2927,7 @@ function runInstall(opts) {
2702
2927
  console.log(` ${c ? green : ''}✓${c ? reset : ''} Instalação concluída com sucesso.\n`);
2703
2928
  }
2704
2929
 
2705
- /** @typedef {{ help: boolean, dryRun: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, globalCli: boolean, ideLocal: boolean, ideExplicit: boolean, noProject: boolean, copilotLegacyClean: boolean, dir: string, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} UninstallOpts */
2930
+ /** @typedef {{ help: boolean, dryRun: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, agentOpenCode: boolean, agentGemini: boolean, agentCodex: boolean, agentWindsurf: boolean, agentAntigravity: boolean, globalCli: boolean, ideLocal: boolean, ideExplicit: boolean, noProject: boolean, copilotLegacyClean: boolean, dir: string, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} UninstallOpts */
2706
2931
 
2707
2932
  /**
2708
2933
  * @param {UninstallOpts} u
@@ -2718,7 +2943,7 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2718
2943
  const cmdDir = path.join(proj, '.cursor', 'commands');
2719
2944
  if (fs.existsSync(cmdDir)) {
2720
2945
  for (const name of fs.readdirSync(cmdDir)) {
2721
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
2946
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
2722
2947
  const p = path.join(cmdDir, name);
2723
2948
  unlinkQuiet(p, u);
2724
2949
  track(p);
@@ -2744,7 +2969,7 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2744
2969
  const pr = path.join(proj, '.github', 'prompts');
2745
2970
  if (fs.existsSync(pr)) {
2746
2971
  for (const name of fs.readdirSync(pr)) {
2747
- if (/^oxe-.*\.prompt\.md$/i.test(name)) {
2972
+ if (name === 'oxe.prompt.md' || /^oxe-.*\.prompt\.md$/i.test(name)) {
2748
2973
  const p = path.join(pr, name);
2749
2974
  unlinkQuiet(p, u);
2750
2975
  track(p);
@@ -2761,7 +2986,7 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2761
2986
  const cmdDir = path.join(base, 'commands');
2762
2987
  if (!fs.existsSync(cmdDir)) continue;
2763
2988
  for (const name of fs.readdirSync(cmdDir)) {
2764
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
2989
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
2765
2990
  const p = path.join(cmdDir, name);
2766
2991
  unlinkQuiet(p, u);
2767
2992
  track(p);
@@ -2792,16 +3017,20 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2792
3017
  }
2793
3018
  }
2794
3019
 
2795
- if (u.copilotCli || u.allAgents) {
3020
+ if (u.allAgents || anyGranularUninstallAgent(u)) {
2796
3021
  const localPaths = oxeAgentInstall.buildAgentInstallPaths(false, proj);
3022
+ const cleanupTargets = buildAgentCleanupTargets(u);
2797
3023
  if (!u.dryRun) {
2798
- oxeAgentInstall.cleanupMarkedUnifiedArtifacts(u, localPaths);
3024
+ oxeAgentInstall.cleanupMarkedUnifiedArtifacts({ dryRun: u.dryRun, targets: cleanupTargets }, localPaths);
2799
3025
  } else {
2800
- console.log(`${dim}agents${reset} (dry-run) limparia marcadores oxe-cc em pastas locais do projeto (OpenCode, Gemini, …)`);
3026
+ const label = cleanupTargets
3027
+ ? Object.keys(cleanupTargets).filter((key) => cleanupTargets[key]).join(', ')
3028
+ : 'OpenCode, Gemini, Windsurf, Codex, Antigravity';
3029
+ console.log(`${dim}agents${reset} (dry-run) limparia marcadores oxe-cc em pastas locais do projeto (${label})`);
2801
3030
  }
2802
3031
  }
2803
3032
 
2804
- if (u.cursor || u.copilot || u.copilotCli || u.allAgents) {
3033
+ if (u.cursor || u.copilot || u.copilotCli || u.allAgents || anyGranularUninstallAgent(u)) {
2805
3034
  const runtimeManifest = path.join(proj, '.oxe', 'install', 'runtime-semantics.json');
2806
3035
  unlinkQuiet(runtimeManifest, u);
2807
3036
  track(runtimeManifest);
@@ -2821,6 +3050,11 @@ function parseUninstallArgs(argv) {
2821
3050
  copilot: false,
2822
3051
  copilotCli: false,
2823
3052
  allAgents: false,
3053
+ agentOpenCode: false,
3054
+ agentGemini: false,
3055
+ agentCodex: false,
3056
+ agentWindsurf: false,
3057
+ agentAntigravity: false,
2824
3058
  globalCli: false,
2825
3059
  ideLocal: false,
2826
3060
  ideExplicit: false,
@@ -2848,11 +3082,31 @@ function parseUninstallArgs(argv) {
2848
3082
  } else if (a === '--copilot-cli') {
2849
3083
  out.copilotCli = true;
2850
3084
  out.ideExplicit = true;
3085
+ } else if (a === '--opencode') {
3086
+ out.agentOpenCode = true;
3087
+ out.ideExplicit = true;
3088
+ } else if (a === '--gemini') {
3089
+ out.agentGemini = true;
3090
+ out.ideExplicit = true;
3091
+ } else if (a === '--codex') {
3092
+ out.agentCodex = true;
3093
+ out.ideExplicit = true;
3094
+ } else if (a === '--windsurf') {
3095
+ out.agentWindsurf = true;
3096
+ out.ideExplicit = true;
3097
+ } else if (a === '--antigravity') {
3098
+ out.agentAntigravity = true;
3099
+ out.ideExplicit = true;
2851
3100
  } else if (a === '--copilot-legacy-clean') {
2852
3101
  out.copilotLegacyClean = true;
2853
3102
  } else if (a === '--all-agents') {
2854
3103
  out.allAgents = true;
2855
3104
  out.copilotCli = true;
3105
+ out.agentOpenCode = true;
3106
+ out.agentGemini = true;
3107
+ out.agentCodex = true;
3108
+ out.agentWindsurf = true;
3109
+ out.agentAntigravity = true;
2856
3110
  out.ideExplicit = true;
2857
3111
  } else if (a === '--global-cli' || a === '-g') {
2858
3112
  out.globalCli = true;
@@ -2871,6 +3125,7 @@ function parseUninstallArgs(argv) {
2871
3125
  out.cursor = true;
2872
3126
  out.copilot = true;
2873
3127
  out.copilotCli = true;
3128
+ out.allAgents = true;
2874
3129
  } else if (out.copilotLegacyClean && !out.ideExplicit && !out.noProject) {
2875
3130
  out.noProject = true;
2876
3131
  }
@@ -2879,6 +3134,8 @@ function parseUninstallArgs(argv) {
2879
3134
  out.conflictFlags = '--config-dir não combina com --ide-local';
2880
3135
  } else if (out.allAgents) {
2881
3136
  out.conflictFlags = '--config-dir não combina com --all-agents';
3137
+ } else if (anyGranularUninstallAgent(out)) {
3138
+ out.conflictFlags = '--config-dir só é suportado com exatamente um entre --cursor, --copilot e --copilot-cli';
2882
3139
  } else if (out.copilot && !out.cursor && !out.copilotCli) {
2883
3140
  out.conflictFlags =
2884
3141
  '--config-dir não combina com --copilot porque o GitHub Copilot no VS Code usa .github/ no workspace';
@@ -2925,7 +3182,7 @@ function cleanupLegacyCopilotVsCode(ideOpts, opts, removedPaths) {
2925
3182
  const pr = copilotLegacyPromptDir(ideOpts);
2926
3183
  if (!fs.existsSync(pr)) return;
2927
3184
  for (const name of fs.readdirSync(pr)) {
2928
- if (!/^oxe-.*\.prompt\.md$/i.test(name)) continue;
3185
+ if (name !== 'oxe.prompt.md' && !/^oxe-.*\.prompt\.md$/i.test(name)) continue;
2929
3186
  const promptPath = path.join(pr, name);
2930
3187
  unlinkQuiet(promptPath, opts);
2931
3188
  removedPaths.push(promptPath);
@@ -2973,6 +3230,11 @@ function runUninstall(u) {
2973
3230
  copilot: u.copilot,
2974
3231
  copilotCli: u.copilotCli,
2975
3232
  allAgents: u.allAgents,
3233
+ agentOpenCode: u.agentOpenCode,
3234
+ agentGemini: u.agentGemini,
3235
+ agentCodex: u.agentCodex,
3236
+ agentWindsurf: u.agentWindsurf,
3237
+ agentAntigravity: u.agentAntigravity,
2976
3238
  vscode: false,
2977
3239
  commands: false,
2978
3240
  agents: false,
@@ -3013,7 +3275,7 @@ function runUninstall(u) {
3013
3275
  const ruleDir = path.join(base, 'rules');
3014
3276
  if (fs.existsSync(cmdDir)) {
3015
3277
  for (const name of fs.readdirSync(cmdDir)) {
3016
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
3278
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
3017
3279
  const p = path.join(cmdDir, name);
3018
3280
  unlinkQuiet(p, u);
3019
3281
  removedPaths.push(p);
@@ -3038,7 +3300,7 @@ function runUninstall(u) {
3038
3300
  const pr = path.join(u.dir, '.github', 'prompts');
3039
3301
  if (fs.existsSync(pr)) {
3040
3302
  for (const name of fs.readdirSync(pr)) {
3041
- if (/^oxe-.*\.prompt\.md$/i.test(name)) {
3303
+ if (name === 'oxe.prompt.md' || /^oxe-.*\.prompt\.md$/i.test(name)) {
3042
3304
  const p = path.join(pr, name);
3043
3305
  unlinkQuiet(p, u);
3044
3306
  removedPaths.push(p);
@@ -3059,7 +3321,7 @@ function runUninstall(u) {
3059
3321
  const cmdDir = path.join(base, 'commands');
3060
3322
  if (!fs.existsSync(cmdDir)) continue;
3061
3323
  for (const name of fs.readdirSync(cmdDir)) {
3062
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
3324
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
3063
3325
  const p = path.join(cmdDir, name);
3064
3326
  unlinkQuiet(p, u);
3065
3327
  removedPaths.push(p);
@@ -3088,10 +3350,66 @@ function runUninstall(u) {
3088
3350
  removedPaths.push(skillFile);
3089
3351
  }
3090
3352
  }
3353
+ }
3354
+
3355
+ if (u.allAgents || anyGranularUninstallAgent(u)) {
3356
+ const cleanupTargets = buildAgentCleanupTargets(u);
3091
3357
  if (u.dryRun) {
3092
- console.log(`${dim}agents${reset} (dry-run) limparia OpenCode, Gemini TOML, Windsurf, Codex, Antigravity (marcadores oxe-cc)`);
3358
+ const label = cleanupTargets
3359
+ ? Object.keys(cleanupTargets).filter((key) => cleanupTargets[key]).join(', ')
3360
+ : 'OpenCode, Gemini, Windsurf, Codex, Antigravity';
3361
+ console.log(`${dim}agents${reset} (dry-run) limparia ${label || 'OpenCode, Gemini, Windsurf, Codex, Antigravity'} (marcadores oxe-cc)`);
3093
3362
  } else {
3094
- oxeAgentInstall.cleanupMarkedUnifiedArtifacts(u);
3363
+ oxeAgentInstall.cleanupMarkedUnifiedArtifacts({ dryRun: u.dryRun, targets: cleanupTargets });
3364
+ }
3365
+ const globalAgentPaths = oxeAgentInstall.buildAgentInstallPaths(true, u.dir);
3366
+ const shouldTrack = (name) => !cleanupTargets || cleanupTargets[name] !== false;
3367
+ const pushRemoved = (filePath) => {
3368
+ if (removedPaths.indexOf(filePath) === -1) removedPaths.push(filePath);
3369
+ };
3370
+ if (shouldTrack('opencode')) {
3371
+ for (const dir of globalAgentPaths.opencodeCommandDirs) {
3372
+ if (!fs.existsSync(dir)) continue;
3373
+ for (const name of fs.readdirSync(dir)) {
3374
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3375
+ pushRemoved(path.join(dir, name));
3376
+ }
3377
+ }
3378
+ }
3379
+ if (shouldTrack('gemini')) {
3380
+ pushRemoved(path.join(globalAgentPaths.geminiCommandsBase, 'oxe.toml'));
3381
+ const geminiSub = path.join(globalAgentPaths.geminiCommandsBase, 'oxe');
3382
+ if (fs.existsSync(geminiSub)) {
3383
+ for (const name of fs.readdirSync(geminiSub)) {
3384
+ if (name.endsWith('.toml')) pushRemoved(path.join(geminiSub, name));
3385
+ }
3386
+ }
3387
+ }
3388
+ if (shouldTrack('windsurf') && fs.existsSync(globalAgentPaths.windsurfWorkflowsDir)) {
3389
+ for (const name of fs.readdirSync(globalAgentPaths.windsurfWorkflowsDir)) {
3390
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3391
+ pushRemoved(path.join(globalAgentPaths.windsurfWorkflowsDir, name));
3392
+ }
3393
+ }
3394
+ if (shouldTrack('codex')) {
3395
+ if (fs.existsSync(globalAgentPaths.codexPromptsDir)) {
3396
+ for (const name of fs.readdirSync(globalAgentPaths.codexPromptsDir)) {
3397
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3398
+ pushRemoved(path.join(globalAgentPaths.codexPromptsDir, name));
3399
+ }
3400
+ }
3401
+ if (fs.existsSync(globalAgentPaths.codexAgentsSkillsRoot)) {
3402
+ for (const entry of fs.readdirSync(globalAgentPaths.codexAgentsSkillsRoot, { withFileTypes: true })) {
3403
+ if (!entry.isDirectory() || !/^oxe($|-)/.test(entry.name)) continue;
3404
+ pushRemoved(path.join(globalAgentPaths.codexAgentsSkillsRoot, entry.name, 'SKILL.md'));
3405
+ }
3406
+ }
3407
+ }
3408
+ if (shouldTrack('antigravity') && fs.existsSync(globalAgentPaths.antigravitySkillsRoot)) {
3409
+ for (const entry of fs.readdirSync(globalAgentPaths.antigravitySkillsRoot, { withFileTypes: true })) {
3410
+ if (!entry.isDirectory() || !/^oxe($|-)/.test(entry.name)) continue;
3411
+ pushRemoved(path.join(globalAgentPaths.antigravitySkillsRoot, entry.name, 'SKILL.md'));
3412
+ }
3095
3413
  }
3096
3414
  }
3097
3415
 
@@ -3126,7 +3444,7 @@ function runUninstall(u) {
3126
3444
  }
3127
3445
  }
3128
3446
 
3129
- if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli || u.copilotLegacyClean)) {
3447
+ if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli || u.copilotLegacyClean || anyGranularUninstallAgent(u))) {
3130
3448
  const prev = oxeManifest.loadFileManifest(home);
3131
3449
  const next = { ...prev };
3132
3450
  for (const p of removedPaths) delete next[p];
@@ -3333,7 +3651,7 @@ function runUpdate(u) {
3333
3651
  const r = spawnSync('npx', args, {
3334
3652
  cwd: u.dir,
3335
3653
  stdio: 'inherit',
3336
- env: { ...process.env },
3654
+ env: { ...process.env, OXE_NO_PROMPT: '1' },
3337
3655
  shell: process.platform === 'win32',
3338
3656
  });
3339
3657
  if (r.error) {
@@ -3951,15 +4269,24 @@ async function runRuntime(opts) {
3951
4269
  console.log(JSON.stringify(gates, null, 2));
3952
4270
  return;
3953
4271
  }
4272
+ const slaHours = gates.gateSlaHours || 24;
3954
4273
  console.log(` ${c ? green : ''}Run:${c ? reset : ''} ${runId || '—'}`);
3955
- console.log(` ${c ? green : ''}Gates:${c ? reset : ''} total=${gates.total} pendentes=${gates.pending.length} stale=${gates.stalePending.length} resolvidos<24h=${gates.resolvedRecent.length} SLA=${gates.gateSlaHours || 24}h`);
4274
+ console.log(` ${c ? green : ''}Gates:${c ? reset : ''} total=${gates.total} pendentes=${gates.pending.length} stale=${gates.stalePending.length} resolvidos<24h=${gates.resolvedRecent.length} SLA=${slaHours}h`);
3956
4275
  console.log(` ${c ? green : ''}Filtros:${c ? reset : ''} status=${gates.filters.status || 'all'} scope=${gates.filters.scope || '—'} task=${gates.filters.workItemId || '—'}`);
3957
- for (const gate of gates.pending) {
4276
+ const allPending = [...gates.pending];
4277
+ for (const gate of allPending) {
3958
4278
  const ageHours = gate.requested_at ? Math.max(0, Math.round((Date.now() - Date.parse(gate.requested_at)) / 36e5)) : null;
3959
- console.log(` ${yellow}PENDING${reset} ${gate.gate_id} · ${gate.scope} · ${gate.work_item_id || 'run'} · ${gate.action || '—'}${ageHours != null ? ` · age ${ageHours}h` : ''}`);
4279
+ const isStale = ageHours != null && ageHours > slaHours;
4280
+ const icon = isStale ? `${c ? yellow : ''}⚠ stale (>${slaHours}h)${c ? reset : ''}` : `${c ? yellow : ''}⏳ pending${c ? reset : ''}`;
4281
+ const suggested = gate.action === 'approve' ? 'approve' : 'approve|reject|waive';
4282
+ console.log(` ${icon} ${gate.gate_id} · ${gate.scope || '—'} · ${gate.work_item_id || 'run'}${ageHours != null ? ` · ${ageHours}h aberto` : ''}`);
4283
+ console.log(` ${c ? dim : ''}ação sugerida: --decision ${suggested} · impacto: bloqueia promoção${c ? reset : ''}`);
3960
4284
  }
3961
4285
  for (const gate of gates.resolvedRecent) {
3962
- console.log(` ${green}RESOLVED${reset} ${gate.gate_id} · ${gate.scope} · ${gate.decision || '—'} · ${gate.actor || '—'}`);
4286
+ console.log(` ${c ? green : ''}✓ resolved${c ? reset : ''} ${gate.gate_id} · ${gate.scope || '—'} · ${gate.decision || '—'} · ${gate.actor || '—'}`);
4287
+ }
4288
+ if (gates.pending.length === 0 && gates.resolvedRecent.length === 0) {
4289
+ console.log(` ${c ? dim : ''}Nenhum gate pendente.${c ? reset : ''}`);
3963
4290
  }
3964
4291
  return;
3965
4292
  }
@@ -4012,11 +4339,16 @@ async function runRuntime(opts) {
4012
4339
  console.log(JSON.stringify(resolved, null, 2));
4013
4340
  return;
4014
4341
  }
4015
- console.log(` ${c ? green : ''}✓${c ? reset : ''} Gate resolvido.`);
4016
- console.log(` ${c ? green : ''}Gate:${c ? reset : ''} ${resolved.gate.gate_id}`);
4017
- console.log(` ${c ? green : ''}Decisão:${c ? reset : ''} ${resolved.gate.decision}`);
4342
+ const remaining = resolved.impact ? (resolved.impact.pendingRemaining || 0) : 0;
4343
+ const staleRemaining = resolved.impact ? (resolved.impact.staleRemaining || 0) : 0;
4344
+ const canPromote = remaining === 0 && staleRemaining === 0;
4345
+ console.log(` ${c ? green : ''}✓${c ? reset : ''} Gate ${resolved.gate.gate_id} resolvido (${resolved.gate.decision}).`);
4018
4346
  console.log(` ${c ? green : ''}Ator:${c ? reset : ''} ${resolved.gate.actor}`);
4019
- console.log(` ${c ? green : ''}Impacto:${c ? reset : ''} pendentes=${resolved.impact.pendingRemaining} stale=${resolved.impact.staleRemaining}`);
4347
+ if (canPromote) {
4348
+ console.log(` ${c ? green : ''}✓ Run pode avançar para promoção — nenhum gate restante.${c ? reset : ''}`);
4349
+ } else {
4350
+ console.log(` ${c ? yellow : ''}⚠ Run ainda bloqueada por ${remaining} gate(s) restante(s)${staleRemaining > 0 ? ` (${staleRemaining} stale)` : ''}.${c ? reset : ''}`);
4351
+ }
4020
4352
  return;
4021
4353
  } catch (err) {
4022
4354
  console.error(`${red}${err && err.message ? err.message : 'Falha ao resolver gate.'}${reset}`);
@@ -5033,7 +5365,7 @@ async function main() {
5033
5365
  process.exit(0);
5034
5366
  }
5035
5367
 
5036
- if (!(command === 'status' && opts.jsonOutput)) {
5368
+ if (!((command === 'status' && opts.jsonOutput) || (command === 'doctor' && opts.jsonOutput))) {
5037
5369
  printBanner();
5038
5370
  }
5039
5371
 
@@ -5043,7 +5375,7 @@ async function main() {
5043
5375
  console.error(`${yellow}Diretório não encontrado: ${target}${reset}`);
5044
5376
  process.exit(1);
5045
5377
  }
5046
- runDoctor(target);
5378
+ runDoctor(target, { release: opts.releaseDoctor, json: opts.jsonOutput, writeManifest: opts.writeManifest });
5047
5379
  return;
5048
5380
  }
5049
5381
 
@@ -5086,6 +5418,7 @@ async function main() {
5086
5418
  }
5087
5419
 
5088
5420
  await resolveInteractiveInstall(opts);
5421
+ persistIdeScope(opts);
5089
5422
  runInstall(opts);
5090
5423
  await maybePromptGlobalCli(opts);
5091
5424
  }