oxe-cc 1.3.0 → 1.4.1

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 (122) 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.md +4 -2
  34. package/.cursor/commands/oxe-workstream.md +4 -2
  35. package/.cursor/commands/oxe.md +6 -2
  36. package/.github/prompts/oxe-ask.prompt.md +4 -2
  37. package/.github/prompts/oxe-capabilities.prompt.md +4 -2
  38. package/.github/prompts/oxe-checkpoint.prompt.md +4 -2
  39. package/.github/prompts/oxe-compact.prompt.md +4 -2
  40. package/.github/prompts/oxe-dashboard.prompt.md +4 -2
  41. package/.github/prompts/oxe-debug.prompt.md +4 -2
  42. package/.github/prompts/oxe-discuss.prompt.md +6 -2
  43. package/.github/prompts/oxe-execute.prompt.md +5 -3
  44. package/.github/prompts/oxe-forensics.prompt.md +4 -2
  45. package/.github/prompts/oxe-help.prompt.md +6 -2
  46. package/.github/prompts/oxe-loop.prompt.md +4 -2
  47. package/.github/prompts/oxe-milestone.prompt.md +4 -2
  48. package/.github/prompts/oxe-next.prompt.md +6 -2
  49. package/.github/prompts/oxe-obs.prompt.md +4 -2
  50. package/.github/prompts/oxe-plan-agent.prompt.md +4 -2
  51. package/.github/prompts/oxe-plan.prompt.md +4 -2
  52. package/.github/prompts/oxe-project.prompt.md +4 -2
  53. package/.github/prompts/oxe-quick.prompt.md +4 -2
  54. package/.github/prompts/oxe-research.prompt.md +4 -2
  55. package/.github/prompts/oxe-retro.prompt.md +4 -2
  56. package/.github/prompts/oxe-review-pr.prompt.md +4 -2
  57. package/.github/prompts/oxe-route.prompt.md +4 -2
  58. package/.github/prompts/oxe-scan.prompt.md +4 -2
  59. package/.github/prompts/oxe-security.prompt.md +4 -2
  60. package/.github/prompts/oxe-session.prompt.md +5 -3
  61. package/.github/prompts/oxe-ship.prompt.md +4 -2
  62. package/.github/prompts/oxe-skill.prompt.md +4 -2
  63. package/.github/prompts/oxe-spec.prompt.md +4 -2
  64. package/.github/prompts/oxe-ui-review.prompt.md +4 -2
  65. package/.github/prompts/oxe-ui-spec.prompt.md +4 -2
  66. package/.github/prompts/oxe-update.prompt.md +4 -2
  67. package/.github/prompts/oxe-validate-gaps.prompt.md +4 -2
  68. package/.github/prompts/oxe-verify.prompt.md +4 -2
  69. package/.github/prompts/oxe-workstream.prompt.md +4 -2
  70. package/.github/prompts/oxe.prompt.md +6 -2
  71. package/.github/workflows/ci.yml +56 -20
  72. package/.github/workflows/release.yml +93 -0
  73. package/AGENTS.md +5 -3
  74. package/CHANGELOG.md +388 -345
  75. package/LICENSE +21 -674
  76. package/README.md +66 -14
  77. package/bin/banner.txt +5 -5
  78. package/bin/lib/oxe-agent-install.cjs +127 -107
  79. package/bin/lib/oxe-runtime-semantics.cjs +68 -24
  80. package/bin/oxe-cc.js +393 -155
  81. package/commands/oxe/ask.md +7 -3
  82. package/commands/oxe/capabilities.md +6 -2
  83. package/commands/oxe/checkpoint.md +5 -1
  84. package/commands/oxe/compact.md +6 -2
  85. package/commands/oxe/dashboard.md +6 -2
  86. package/commands/oxe/debug.md +6 -2
  87. package/commands/oxe/discuss.md +6 -2
  88. package/commands/oxe/execute.md +6 -2
  89. package/commands/oxe/forensics.md +6 -2
  90. package/commands/oxe/help.md +6 -2
  91. package/commands/oxe/loop.md +6 -2
  92. package/commands/oxe/milestone.md +6 -2
  93. package/commands/oxe/next.md +6 -2
  94. package/commands/oxe/obs.md +6 -2
  95. package/commands/oxe/oxe.md +6 -2
  96. package/commands/oxe/plan-agent.md +6 -2
  97. package/commands/oxe/plan.md +6 -2
  98. package/commands/oxe/project.md +6 -2
  99. package/commands/oxe/quick.md +6 -2
  100. package/commands/oxe/research.md +6 -2
  101. package/commands/oxe/retro.md +6 -2
  102. package/commands/oxe/review-pr.md +6 -2
  103. package/commands/oxe/route.md +6 -2
  104. package/commands/oxe/scan.md +6 -2
  105. package/commands/oxe/security.md +6 -2
  106. package/commands/oxe/session.md +6 -2
  107. package/commands/oxe/ship.md +6 -2
  108. package/commands/oxe/skill.md +6 -2
  109. package/commands/oxe/spec.md +6 -2
  110. package/commands/oxe/ui-review.md +6 -2
  111. package/commands/oxe/ui-spec.md +6 -2
  112. package/commands/oxe/update.md +6 -2
  113. package/commands/oxe/validate-gaps.md +6 -2
  114. package/commands/oxe/verify.md +6 -2
  115. package/commands/oxe/workstream.md +6 -2
  116. package/lib/sdk/README.md +19 -7
  117. package/oxe/workflows/plan.md +51 -20
  118. package/package.json +3 -3
  119. package/packages/runtime/package.json +5 -4
  120. package/vscode-extension/LICENSE +21 -0
  121. package/vscode-extension/oxe-agents-1.4.0.vsix +0 -0
  122. package/vscode-extension/package.json +2 -2
package/bin/oxe-cc.js CHANGED
@@ -247,24 +247,35 @@ function buildInstallSummary(opts, fullLayout) {
247
247
  /**
248
248
  * @param {UninstallOpts} u
249
249
  */
250
- function buildUninstallFooter(u) {
251
- const bullets = [];
252
- const p = u.dryRun ? '[simulação] ' : '';
253
- const rm = u.dryRun ? 'Seriam removidos' : 'Removidos';
254
- if (u.cursor) bullets.push(`${p}${rm} artefatos OXE em ~/.cursor (comandos e regras).`);
255
- if (u.copilot) {
256
- bullets.push(`${p}${rm} prompt files OXE em .github/prompts/ e o bloco OXE em .github/copilot-instructions.md.`);
257
- }
250
+ function buildUninstallFooter(u) {
251
+ const bullets = [];
252
+ const p = u.dryRun ? '[simulação] ' : '';
253
+ const rm = u.dryRun ? 'Seriam removidos' : 'Removidos';
254
+ const granularAgents = [
255
+ u.agentOpenCode ? 'OpenCode' : null,
256
+ u.agentGemini ? 'Gemini' : null,
257
+ u.agentCodex ? 'Codex' : null,
258
+ u.agentWindsurf ? 'Windsurf' : null,
259
+ u.agentAntigravity ? 'Antigravity' : null,
260
+ ].filter(Boolean);
261
+ if (u.cursor) bullets.push(`${p}${rm} artefatos OXE em ~/.cursor (comandos e regras).`);
262
+ if (u.copilot) {
263
+ bullets.push(`${p}${rm} prompt files OXE em .github/prompts/ e o bloco OXE em .github/copilot-instructions.md.`);
264
+ }
258
265
  if (u.copilotLegacyClean) {
259
266
  bullets.push(`${p}${rm} apenas o legado global do Copilot VS Code em ~/.copilot/ (prompts oxe-* e bloco OXE global).`);
260
267
  }
261
- if (u.copilotCli || u.allAgents) {
262
- bullets.push(`${p}${rm} comandos oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
263
- bullets.push(`${p}${rm} skills OXE (marcadas oxe-cc) em ~/.copilot/skills/oxe*/.`);
264
- bullets.push(
265
- `${p}${rm} extensões multi-agente marcadas oxe-cc (OpenCode, Gemini TOML, Windsurf workflows, Codex prompts/skills, Antigravity), se existirem.`
266
- );
267
- }
268
+ if (u.copilotCli) {
269
+ bullets.push(`${p}${rm} comandos oxe/oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
270
+ bullets.push(`${p}${rm} skills OXE (marcadas oxe-cc) em ~/.copilot/skills/oxe*/.`);
271
+ }
272
+ if (u.allAgents) {
273
+ bullets.push(
274
+ `${p}${rm} extensões multi-agente marcadas oxe-cc (OpenCode, Gemini TOML, Windsurf workflows, Codex prompts/skills, Antigravity), se existirem.`
275
+ );
276
+ } else if (granularAgents.length) {
277
+ bullets.push(`${p}${rm} apenas as integrações selecionadas: ${granularAgents.join(', ')}.`);
278
+ }
268
279
  if (u.ideLocal) {
269
280
  bullets.push(
270
281
  `${p}${rm} integrações OXE no repositório (.cursor, .github, .claude, .copilot, .opencode, … conforme flags).`
@@ -287,10 +298,27 @@ function buildUninstallFooter(u) {
287
298
 
288
299
  /** @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 */
289
300
 
290
- /** @param {InstallOpts} o */
291
- function anyGranularAgent(o) {
292
- return !!(o.agentOpenCode || o.agentGemini || o.agentCodex || o.agentWindsurf || o.agentAntigravity);
293
- }
301
+ /** @param {InstallOpts} o */
302
+ function anyGranularAgent(o) {
303
+ return !!(o.agentOpenCode || o.agentGemini || o.agentCodex || o.agentWindsurf || o.agentAntigravity);
304
+ }
305
+
306
+ /** @param {UninstallOpts} o */
307
+ function anyGranularUninstallAgent(o) {
308
+ return !!(o.agentOpenCode || o.agentGemini || o.agentCodex || o.agentWindsurf || o.agentAntigravity);
309
+ }
310
+
311
+ /** @param {UninstallOpts} u */
312
+ function buildAgentCleanupTargets(u) {
313
+ if (u.allAgents || !anyGranularUninstallAgent(u)) return null;
314
+ return {
315
+ opencode: Boolean(u.agentOpenCode),
316
+ gemini: Boolean(u.agentGemini),
317
+ windsurf: Boolean(u.agentWindsurf),
318
+ codex: Boolean(u.agentCodex),
319
+ antigravity: Boolean(u.agentAntigravity),
320
+ };
321
+ }
294
322
 
295
323
  /** @param {InstallOpts} o */
296
324
  function anyIdeIntegration(o) {
@@ -1834,6 +1862,39 @@ function runStatus(target, opts = {}) {
1834
1862
 
1835
1863
  printOxeHealthDiagnostics(target, c, { skipScanCompactAgeWarnings: Boolean(opts.hints) });
1836
1864
 
1865
+ // IDE readiness summary
1866
+ const ideStatusLines = [];
1867
+ const _copilotPromptsDir = path.join(target, '.github', 'prompts');
1868
+ const _copilotInstructions = path.join(target, '.github', 'copilot-instructions.md');
1869
+ ideStatusLines.push(`Copilot ${fs.existsSync(_copilotPromptsDir) || fs.existsSync(_copilotInstructions) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1870
+ ideStatusLines.push(`Cursor ${fs.existsSync(path.join(target, '.cursor', 'commands')) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1871
+ const _claudeLocal = path.join(target, 'commands', 'oxe');
1872
+ const _claudeGlobal = path.join(require('os').homedir(), '.claude', 'commands');
1873
+ ideStatusLines.push(`Claude Code ${fs.existsSync(_claudeLocal) || fs.existsSync(_claudeGlobal) ? (c ? green + '✓' + reset : '✓') : (c ? dim + '✗' + reset : '✗')}`);
1874
+ console.log(`\n ${c ? dim : ''}IDEs:${c ? reset : ''} ${ideStatusLines.join(' ')}`);
1875
+
1876
+ // Gates pending in default view
1877
+ const pendingGateCount = report.pendingGates ? (report.pendingGates.pendingCount || 0) : 0;
1878
+ const staleGateCount = report.pendingGates ? (report.pendingGates.staleGateCount || 0) : 0;
1879
+ if (pendingGateCount > 0 || staleGateCount > 0) {
1880
+ const gateMsg = [];
1881
+ if (pendingGateCount > 0) gateMsg.push(`${pendingGateCount} pendente(s)`);
1882
+ if (staleGateCount > 0) gateMsg.push(`${staleGateCount} stale`);
1883
+ console.log(` ${c ? yellow : ''}⚠ Gates:${c ? reset : ''} ${gateMsg.join(', ')} — ${c ? cyan : ''}npx oxe-cc runtime gates list --dir .${c ? reset : ''}`);
1884
+ }
1885
+
1886
+ // Explicit blockage diagnosis
1887
+ const specMissing = !fs.existsSync(path.join(target, '.oxe', 'SPEC.md'));
1888
+ const planMissing = !fs.existsSync(path.join(target, '.oxe', 'PLAN.md'));
1889
+ const verifyMissing = !fs.existsSync(path.join(target, '.oxe', 'VERIFY.md'));
1890
+ if (specMissing) {
1891
+ console.log(` ${c ? yellow : ''}⚠ Bloqueio:${c ? reset : ''} SPEC.md ausente — rode ${c ? cyan : ''}/oxe-spec${c ? reset : ''} antes de planejar`);
1892
+ } else if (planMissing) {
1893
+ console.log(` ${c ? yellow : ''}⚠ Bloqueio:${c ? reset : ''} PLAN.md ausente — rode ${c ? cyan : ''}/oxe-plan${c ? reset : ''}`);
1894
+ } else if (verifyMissing && !planMissing) {
1895
+ console.log(` ${c ? dim : ''}Obs.:${c ? reset : ''} VERIFY.md ainda não gerado — rode ${c ? cyan : ''}/oxe-verify${c ? reset : ''} após executar`);
1896
+ }
1897
+
1837
1898
  if (opts.hints) {
1838
1899
  console.log(`\n ${c ? cyan : ''}Lembretes (rotina OXE)${reset}`);
1839
1900
  if (routineHints.length) {
@@ -1979,6 +2040,72 @@ function runDoctor(target) {
1979
2040
  }
1980
2041
  }
1981
2042
 
2043
+ // IDE health gates
2044
+ console.log('');
2045
+ const ideChecks = [];
2046
+ const copilotPromptsDir = path.join(target, '.github', 'prompts');
2047
+ const copilotInstructions = path.join(target, '.github', 'copilot-instructions.md');
2048
+ const copilotReady = fs.existsSync(copilotPromptsDir) || fs.existsSync(copilotInstructions);
2049
+ ideChecks.push({ label: 'Copilot', ready: copilotReady, hint: '.github/prompts/ ou copilot-instructions.md' });
2050
+
2051
+ const cursorDir = path.join(target, '.cursor', 'commands');
2052
+ const cursorReady = fs.existsSync(cursorDir);
2053
+ ideChecks.push({ label: 'Cursor', ready: cursorReady, hint: '.cursor/commands/' });
2054
+
2055
+ const claudeLocalDir = path.join(target, 'commands', 'oxe');
2056
+ const claudeGlobalDir = path.join(require('os').homedir(), '.claude', 'commands');
2057
+ const claudeReady = fs.existsSync(claudeLocalDir) || fs.existsSync(claudeGlobalDir);
2058
+ ideChecks.push({ label: 'Claude Code', ready: claudeReady, hint: 'commands/oxe/ ou ~/.claude/commands/' });
2059
+
2060
+ for (const ide of ideChecks) {
2061
+ if (ide.ready) {
2062
+ console.log(`${c ? green : ''}OK${c ? reset : ''} ${ide.label} pronto (${ide.hint})`);
2063
+ } else {
2064
+ console.log(`${c ? dim : ''}Obs.:${c ? reset : ''} ${ide.label} não detectado — esperado ${ide.hint}`);
2065
+ }
2066
+ }
2067
+
2068
+ // Runtime compilation check
2069
+ const runtimeCompiledPath = path.join(target, 'lib', 'runtime', 'index.js');
2070
+ const runtimeDistPath = path.join(target, 'packages', 'runtime', 'dist-tests');
2071
+ const runtimeCompiled = fs.existsSync(runtimeCompiledPath) || fs.existsSync(runtimeDistPath);
2072
+ if (runtimeCompiled) {
2073
+ console.log(`${c ? green : ''}OK${c ? reset : ''} Runtime compilado detectado — modo enterprise disponível`);
2074
+ } else {
2075
+ console.log(`${c ? dim : ''}Obs.:${c ? reset : ''} Runtime não compilado — operando em modo legado (sem perda de UX)`);
2076
+ }
2077
+
2078
+ // Readiness gate summary
2079
+ const stateFilePath = path.join(target, '.oxe', 'STATE.md');
2080
+ let readinessCmd = '/oxe-scan';
2081
+ let readinessDesc = 'Nenhum STATE.md encontrado';
2082
+ if (fs.existsSync(stateFilePath)) {
2083
+ try {
2084
+ const stateContent = fs.readFileSync(stateFilePath, 'utf8');
2085
+ const phaseMatch = stateContent.match(/fase[:\s]+([a-z_]+)/i) || stateContent.match(/phase[:\s]+([a-z_]+)/i) || stateContent.match(/status[:\s]+([a-z_]+)/i);
2086
+ const phase = phaseMatch ? phaseMatch[1].toLowerCase() : 'init';
2087
+ const phaseMap = {
2088
+ init: { cmd: '/oxe-scan', desc: 'Pronto para /oxe-scan' },
2089
+ scan_complete: { cmd: '/oxe-spec', desc: 'Pronto para /oxe-spec' },
2090
+ spec_complete: { cmd: '/oxe-plan', desc: 'Pronto para /oxe-plan' },
2091
+ plan_complete: { cmd: '/oxe-execute', desc: 'Pronto para /oxe-execute' },
2092
+ execute_complete: { cmd: '/oxe-verify', desc: 'Pronto para /oxe-verify' },
2093
+ verify_complete: { cmd: 'runtime promote --target pr_draft', desc: 'Pronto para promoção' },
2094
+ };
2095
+ const next = phaseMap[phase] || { cmd: '/oxe', desc: `Fase detectada: ${phase}` };
2096
+ readinessCmd = next.cmd;
2097
+ readinessDesc = next.desc;
2098
+ } catch (_) { /* ignore */ }
2099
+ }
2100
+ const specPath = path.join(target, '.oxe', 'SPEC.md');
2101
+ const specExists = fs.existsSync(specPath);
2102
+ console.log('');
2103
+ if (specExists) {
2104
+ console.log(` ${c ? green : ''}✓ ${readinessDesc}${c ? reset : ''} — próximo: ${c ? cyan : ''}${readinessCmd}${c ? reset : ''}`);
2105
+ } else {
2106
+ console.log(` ${c ? yellow : ''}⚠ Falta SPEC — rode ${c ? cyan : ''}${readinessCmd}${c ? reset : ''}`);
2107
+ }
2108
+
1982
2109
  printOxeHealthDiagnostics(target, c);
1983
2110
  const report = oxeHealth.buildHealthReport(target);
1984
2111
  const statusColor = report.healthStatus === 'healthy' ? green : report.healthStatus === 'warning' ? yellow : red;
@@ -1986,10 +2113,12 @@ function runDoctor(target) {
1986
2113
  if (report.healthStatus === 'broken') {
1987
2114
  process.exitCode = 1;
1988
2115
  }
2116
+ const ideReadySummary = ideChecks.filter((i) => i.ready).map((i) => i.label).join(', ') || 'nenhuma IDE detectada';
1989
2117
  printSummaryAndNextSteps(c, {
1990
2118
  bullets: [
1991
2119
  `Projeto em ${target}`,
1992
2120
  `Workflows conferidos em ${wfLabel}`,
2121
+ `IDEs prontas: ${ideReadySummary}`,
1993
2122
  `Saúde lógica: ${report.healthStatus}`,
1994
2123
  ],
1995
2124
  nextSteps: [
@@ -2214,17 +2343,19 @@ ${green}Uso:${reset}
2214
2343
  npx oxe-cc uninstall [opções] [pasta-do-projeto]
2215
2344
  npx oxe-cc update [opções] [argumentos extras…]
2216
2345
 
2217
- ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
2218
- --cursor / --copilot / --copilot-cli só essa integração (omissão = todas)
2219
- --copilot-vscode alias explícito de --copilot
2220
- --copilot-legacy-clean limpa só o legado antigo do Copilot VS Code em ~/.copilot/
2221
- --all-agents também remove ficheiros multi-plataforma (com --copilot-cli implícito)
2222
- --ide-local remove integrações IDE neste repositório (.cursor, .github, .claude, .copilot, …)
2223
- --ide-only não apagar .oxe/workflows, oxe/, etc. no projeto
2224
- --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)
2226
- --dry-run
2227
- --dir <pasta> raiz do projeto (padrão: diretório atual)
2346
+ ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
2347
+ --cursor / --copilot / --copilot-cli só essa integração (omissão = todas)
2348
+ --copilot-vscode alias explícito de --copilot
2349
+ --copilot-legacy-clean limpa só o legado antigo do Copilot VS Code em ~/.copilot/
2350
+ --all-agents também remove ficheiros multi-plataforma (com --copilot-cli implícito)
2351
+ --opencode / --gemini / --codex / --windsurf / --antigravity
2352
+ remove esse agente multi-runtime
2353
+ --ide-local remove integrações IDE neste repositório (.cursor, .github, .claude, .copilot, …)
2354
+ --ide-only não apagar .oxe/workflows, oxe/, etc. no projeto
2355
+ --global-cli, -g também executa npm uninstall -g oxe-cc
2356
+ --config-dir <caminho> com exatamente uma flag IDE acima (não combina com --ide-local, --copilot nem agentes granulares)
2357
+ --dry-run
2358
+ --dir <pasta> raiz do projeto (padrão: diretório atual)
2228
2359
 
2229
2360
  ${green}update${reset} (executa npx oxe-cc@latest --force na pasta do projeto)
2230
2361
  --check só consulta npm: compara versão em execução com latest (saída 0=ok, 1=há mais nova, 2=erro; incompatível com --dry-run)
@@ -2260,7 +2391,7 @@ ${green}runtime${reset} (controle operacional explícito do ACTIVE-RUN)
2260
2391
  verify executa a suite enterprise, coleta evidência e projeta VERIFY.md
2261
2392
  project projeta markdowns derivados do estado canônico
2262
2393
  ci executa checks do runtime e persiste o resultado na run
2263
- promote promove remotamente a run ativa (pr_draft|branch_push)
2394
+ promote promove remotamente a run ativa (estável: pr_draft)
2264
2395
  recover reidrata estado canônico/journal/gates/policy da run ativa
2265
2396
  gates <list|show|resolve> fila operacional de gates pendentes e resoluções auditáveis
2266
2397
  --session <sessions/sNNN-slug> força sessão específica
@@ -2274,7 +2405,7 @@ ${green}runtime${reset} (controle operacional explícito do ACTIVE-RUN)
2274
2405
  --gate <gate_id> (gates show|resolve) gate alvo
2275
2406
  --decision <approve|reject|waive> (gates resolve) decisão aplicada
2276
2407
  --actor <id> (gates resolve) ator responsável
2277
- --target <pr_draft|branch_push> (promote) alvo remoto; padrão pr_draft
2408
+ --target <pr_draft|branch_push> (promote) alvo remoto; padrão pr_draft, branch_push é avançado
2278
2409
  --remote <nome> (promote) remote git; padrão origin
2279
2410
  --base <branch> (promote) branch/ref base; padrão main
2280
2411
  --minimum-coverage <0-100> (promote) cobertura mínima exigida; padrão 100
@@ -2617,11 +2748,11 @@ function runInstall(opts) {
2617
2748
  addTracked(copilotPromptsDirPath(opts), (n) => n.startsWith('oxe-'));
2618
2749
  trackFile(copilotWorkspaceManifestPath(opts));
2619
2750
  }
2620
- trackFile(runtimeSemanticsManifestPath(opts));
2621
- 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'));
2624
- const skRoot = path.join(cpCliHome, 'skills');
2751
+ trackFile(runtimeSemanticsManifestPath(opts));
2752
+ if (opts.copilotCli || opts.allAgents) {
2753
+ addTracked(path.join(installClaudeBase(opts), 'commands'), (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2754
+ addTracked(path.join(cpCliHome, 'commands'), (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2755
+ const skRoot = path.join(cpCliHome, 'skills');
2625
2756
  if (fs.existsSync(skRoot)) {
2626
2757
  for (const sub of fs.readdirSync(skRoot, { withFileTypes: true })) {
2627
2758
  if (!sub.isDirectory() || !/^oxe($|-)/.test(sub.name)) continue;
@@ -2636,11 +2767,11 @@ function runInstall(opts) {
2636
2767
  }
2637
2768
  }
2638
2769
  }
2639
- if (opts.agentOpenCode || opts.allAgents) {
2640
- for (const d of agentPaths.opencodeCommandDirs) {
2641
- addTracked(d, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2642
- }
2643
- }
2770
+ if (opts.agentOpenCode || opts.allAgents) {
2771
+ for (const d of agentPaths.opencodeCommandDirs) {
2772
+ addTracked(d, (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2773
+ }
2774
+ }
2644
2775
  if (opts.agentGemini || opts.allAgents) {
2645
2776
  const gCmd = agentPaths.geminiCommandsBase;
2646
2777
  trackFile(path.join(gCmd, 'oxe.toml'));
@@ -2654,12 +2785,12 @@ function runInstall(opts) {
2654
2785
  if (opts.agentWindsurf || opts.allAgents) {
2655
2786
  addTracked(agentPaths.windsurfWorkflowsDir, (n) => n === 'oxe.md' || (n.startsWith('oxe-') && n.endsWith('.md')));
2656
2787
  }
2657
- if (opts.agentCodex || opts.allAgents) {
2658
- const cxPrompts = agentPaths.codexPromptsDir;
2659
- if (fs.existsSync(cxPrompts)) {
2660
- addTracked(cxPrompts, (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2661
- }
2662
- }
2788
+ if (opts.agentCodex || opts.allAgents) {
2789
+ const cxPrompts = agentPaths.codexPromptsDir;
2790
+ if (fs.existsSync(cxPrompts)) {
2791
+ addTracked(cxPrompts, (n) => oxeAgentInstall.isOxeCommandMarkdownName(n));
2792
+ }
2793
+ }
2663
2794
  if (opts.agentAntigravity || opts.allAgents) {
2664
2795
  const root = agentPaths.antigravitySkillsRoot;
2665
2796
  if (fs.existsSync(root)) {
@@ -2702,26 +2833,26 @@ function runInstall(opts) {
2702
2833
  console.log(` ${c ? green : ''}✓${c ? reset : ''} Instalação concluída com sucesso.\n`);
2703
2834
  }
2704
2835
 
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 */
2836
+ /** @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
2837
 
2707
2838
  /**
2708
2839
  * @param {UninstallOpts} u
2709
2840
  * @param {string[]} removedPaths
2710
2841
  */
2711
- function uninstallLocalIdeFromProject(u, removedPaths) {
2712
- const proj = path.resolve(u.dir);
2713
- const track = (p) => {
2714
- if (removedPaths.indexOf(p) === -1) removedPaths.push(p);
2715
- };
2716
-
2717
- if (u.cursor) {
2718
- const cmdDir = path.join(proj, '.cursor', 'commands');
2719
- if (fs.existsSync(cmdDir)) {
2720
- for (const name of fs.readdirSync(cmdDir)) {
2721
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
2722
- const p = path.join(cmdDir, name);
2723
- unlinkQuiet(p, u);
2724
- track(p);
2842
+ function uninstallLocalIdeFromProject(u, removedPaths) {
2843
+ const proj = path.resolve(u.dir);
2844
+ const track = (p) => {
2845
+ if (removedPaths.indexOf(p) === -1) removedPaths.push(p);
2846
+ };
2847
+
2848
+ if (u.cursor) {
2849
+ const cmdDir = path.join(proj, '.cursor', 'commands');
2850
+ if (fs.existsSync(cmdDir)) {
2851
+ for (const name of fs.readdirSync(cmdDir)) {
2852
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
2853
+ const p = path.join(cmdDir, name);
2854
+ unlinkQuiet(p, u);
2855
+ track(p);
2725
2856
  }
2726
2857
  }
2727
2858
  }
@@ -2756,15 +2887,15 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2756
2887
  track(manifest);
2757
2888
  }
2758
2889
 
2759
- if (u.copilotCli || u.allAgents) {
2760
- for (const base of [path.join(proj, '.claude'), path.join(proj, '.copilot')]) {
2761
- const cmdDir = path.join(base, 'commands');
2762
- if (!fs.existsSync(cmdDir)) continue;
2763
- for (const name of fs.readdirSync(cmdDir)) {
2764
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
2765
- const p = path.join(cmdDir, name);
2766
- unlinkQuiet(p, u);
2767
- track(p);
2890
+ if (u.copilotCli || u.allAgents) {
2891
+ for (const base of [path.join(proj, '.claude'), path.join(proj, '.copilot')]) {
2892
+ const cmdDir = path.join(base, 'commands');
2893
+ if (!fs.existsSync(cmdDir)) continue;
2894
+ for (const name of fs.readdirSync(cmdDir)) {
2895
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
2896
+ const p = path.join(cmdDir, name);
2897
+ unlinkQuiet(p, u);
2898
+ track(p);
2768
2899
  }
2769
2900
  }
2770
2901
  }
@@ -2792,21 +2923,25 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2792
2923
  }
2793
2924
  }
2794
2925
 
2795
- if (u.copilotCli || u.allAgents) {
2796
- const localPaths = oxeAgentInstall.buildAgentInstallPaths(false, proj);
2797
- if (!u.dryRun) {
2798
- oxeAgentInstall.cleanupMarkedUnifiedArtifacts(u, localPaths);
2799
- } else {
2800
- console.log(`${dim}agents${reset} (dry-run) limparia marcadores oxe-cc em pastas locais do projeto (OpenCode, Gemini, …)`);
2801
- }
2802
- }
2803
-
2804
- if (u.cursor || u.copilot || u.copilotCli || u.allAgents) {
2805
- const runtimeManifest = path.join(proj, '.oxe', 'install', 'runtime-semantics.json');
2806
- unlinkQuiet(runtimeManifest, u);
2807
- track(runtimeManifest);
2808
- }
2809
- }
2926
+ if (u.allAgents || anyGranularUninstallAgent(u)) {
2927
+ const localPaths = oxeAgentInstall.buildAgentInstallPaths(false, proj);
2928
+ const cleanupTargets = buildAgentCleanupTargets(u);
2929
+ if (!u.dryRun) {
2930
+ oxeAgentInstall.cleanupMarkedUnifiedArtifacts({ dryRun: u.dryRun, targets: cleanupTargets }, localPaths);
2931
+ } else {
2932
+ const label = cleanupTargets
2933
+ ? Object.keys(cleanupTargets).filter((key) => cleanupTargets[key]).join(', ')
2934
+ : 'OpenCode, Gemini, Windsurf, Codex, Antigravity';
2935
+ console.log(`${dim}agents${reset} (dry-run) limparia marcadores oxe-cc em pastas locais do projeto (${label})`);
2936
+ }
2937
+ }
2938
+
2939
+ if (u.cursor || u.copilot || u.copilotCli || u.allAgents || anyGranularUninstallAgent(u)) {
2940
+ const runtimeManifest = path.join(proj, '.oxe', 'install', 'runtime-semantics.json');
2941
+ unlinkQuiet(runtimeManifest, u);
2942
+ track(runtimeManifest);
2943
+ }
2944
+ }
2810
2945
 
2811
2946
  /**
2812
2947
  * @param {string[]} argv
@@ -2814,16 +2949,21 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2814
2949
  */
2815
2950
  function parseUninstallArgs(argv) {
2816
2951
  /** @type {UninstallOpts} */
2817
- const out = {
2818
- help: false,
2819
- dryRun: false,
2820
- cursor: false,
2821
- copilot: false,
2822
- copilotCli: false,
2823
- allAgents: false,
2824
- globalCli: false,
2825
- ideLocal: false,
2826
- ideExplicit: false,
2952
+ const out = {
2953
+ help: false,
2954
+ dryRun: false,
2955
+ cursor: false,
2956
+ copilot: false,
2957
+ copilotCli: false,
2958
+ allAgents: false,
2959
+ agentOpenCode: false,
2960
+ agentGemini: false,
2961
+ agentCodex: false,
2962
+ agentWindsurf: false,
2963
+ agentAntigravity: false,
2964
+ globalCli: false,
2965
+ ideLocal: false,
2966
+ ideExplicit: false,
2827
2967
  noProject: false,
2828
2968
  copilotLegacyClean: false,
2829
2969
  dir: process.cwd(),
@@ -2845,15 +2985,35 @@ function parseUninstallArgs(argv) {
2845
2985
  } else if (a === '--copilot' || a === '--copilot-vscode') {
2846
2986
  out.copilot = true;
2847
2987
  out.ideExplicit = true;
2848
- } else if (a === '--copilot-cli') {
2849
- out.copilotCli = true;
2850
- out.ideExplicit = true;
2851
- } else if (a === '--copilot-legacy-clean') {
2852
- out.copilotLegacyClean = true;
2853
- } else if (a === '--all-agents') {
2854
- out.allAgents = true;
2855
- out.copilotCli = true;
2856
- out.ideExplicit = true;
2988
+ } else if (a === '--copilot-cli') {
2989
+ out.copilotCli = true;
2990
+ out.ideExplicit = true;
2991
+ } else if (a === '--opencode') {
2992
+ out.agentOpenCode = true;
2993
+ out.ideExplicit = true;
2994
+ } else if (a === '--gemini') {
2995
+ out.agentGemini = true;
2996
+ out.ideExplicit = true;
2997
+ } else if (a === '--codex') {
2998
+ out.agentCodex = true;
2999
+ out.ideExplicit = true;
3000
+ } else if (a === '--windsurf') {
3001
+ out.agentWindsurf = true;
3002
+ out.ideExplicit = true;
3003
+ } else if (a === '--antigravity') {
3004
+ out.agentAntigravity = true;
3005
+ out.ideExplicit = true;
3006
+ } else if (a === '--copilot-legacy-clean') {
3007
+ out.copilotLegacyClean = true;
3008
+ } else if (a === '--all-agents') {
3009
+ out.allAgents = true;
3010
+ out.copilotCli = true;
3011
+ out.agentOpenCode = true;
3012
+ out.agentGemini = true;
3013
+ out.agentCodex = true;
3014
+ out.agentWindsurf = true;
3015
+ out.agentAntigravity = true;
3016
+ out.ideExplicit = true;
2857
3017
  } else if (a === '--global-cli' || a === '-g') {
2858
3018
  out.globalCli = true;
2859
3019
  } else if (a === '--ide-local') out.ideLocal = true;
@@ -2867,21 +3027,24 @@ function parseUninstallArgs(argv) {
2867
3027
  }
2868
3028
  }
2869
3029
  if (rest.length) out.dir = rest[0];
2870
- if (!out.ideExplicit && !out.copilotLegacyClean) {
2871
- out.cursor = true;
2872
- out.copilot = true;
2873
- out.copilotCli = true;
2874
- } else if (out.copilotLegacyClean && !out.ideExplicit && !out.noProject) {
2875
- out.noProject = true;
2876
- }
2877
- if (!out.conflictFlags && out.explicitConfigDir) {
2878
- if (out.ideLocal) {
2879
- out.conflictFlags = '--config-dir não combina com --ide-local';
2880
- } else if (out.allAgents) {
2881
- out.conflictFlags = '--config-dir não combina com --all-agents';
2882
- } else if (out.copilot && !out.cursor && !out.copilotCli) {
2883
- out.conflictFlags =
2884
- '--config-dir não combina com --copilot porque o GitHub Copilot no VS Code usa .github/ no workspace';
3030
+ if (!out.ideExplicit && !out.copilotLegacyClean) {
3031
+ out.cursor = true;
3032
+ out.copilot = true;
3033
+ out.copilotCli = true;
3034
+ out.allAgents = true;
3035
+ } else if (out.copilotLegacyClean && !out.ideExplicit && !out.noProject) {
3036
+ out.noProject = true;
3037
+ }
3038
+ if (!out.conflictFlags && out.explicitConfigDir) {
3039
+ if (out.ideLocal) {
3040
+ out.conflictFlags = '--config-dir não combina com --ide-local';
3041
+ } else if (out.allAgents) {
3042
+ out.conflictFlags = '--config-dir não combina com --all-agents';
3043
+ } else if (anyGranularUninstallAgent(out)) {
3044
+ out.conflictFlags = '--config-dir é suportado com exatamente um entre --cursor, --copilot e --copilot-cli';
3045
+ } else if (out.copilot && !out.cursor && !out.copilotCli) {
3046
+ out.conflictFlags =
3047
+ '--config-dir não combina com --copilot porque o GitHub Copilot no VS Code usa .github/ no workspace';
2885
3048
  } else {
2886
3049
  const n = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
2887
3050
  if (n !== 1) {
@@ -2970,10 +3133,15 @@ function runUninstall(u) {
2970
3133
  help: false,
2971
3134
  version: false,
2972
3135
  cursor: u.cursor,
2973
- copilot: u.copilot,
2974
- copilotCli: u.copilotCli,
2975
- allAgents: u.allAgents,
2976
- vscode: false,
3136
+ copilot: u.copilot,
3137
+ copilotCli: u.copilotCli,
3138
+ allAgents: u.allAgents,
3139
+ agentOpenCode: u.agentOpenCode,
3140
+ agentGemini: u.agentGemini,
3141
+ agentCodex: u.agentCodex,
3142
+ agentWindsurf: u.agentWindsurf,
3143
+ agentAntigravity: u.agentAntigravity,
3144
+ vscode: false,
2977
3145
  commands: false,
2978
3146
  agents: false,
2979
3147
  force: true,
@@ -3007,16 +3175,16 @@ function runUninstall(u) {
3007
3175
 
3008
3176
  const removedPaths = [];
3009
3177
 
3010
- if (u.cursor) {
3178
+ if (u.cursor) {
3011
3179
  const base = cursorUserDir(ideOpts);
3012
3180
  const cmdDir = path.join(base, 'commands');
3013
3181
  const ruleDir = path.join(base, 'rules');
3014
3182
  if (fs.existsSync(cmdDir)) {
3015
- for (const name of fs.readdirSync(cmdDir)) {
3016
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
3017
- const p = path.join(cmdDir, name);
3018
- unlinkQuiet(p, u);
3019
- removedPaths.push(p);
3183
+ for (const name of fs.readdirSync(cmdDir)) {
3184
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
3185
+ const p = path.join(cmdDir, name);
3186
+ unlinkQuiet(p, u);
3187
+ removedPaths.push(p);
3020
3188
  }
3021
3189
  }
3022
3190
  }
@@ -3054,15 +3222,15 @@ function runUninstall(u) {
3054
3222
  cleanupLegacyCopilotVsCode(ideOpts, u, removedPaths);
3055
3223
  }
3056
3224
 
3057
- if (u.copilotCli) {
3058
- for (const base of [claudeUserDir(ideOpts), copilotUserDir(ideOpts)]) {
3059
- const cmdDir = path.join(base, 'commands');
3060
- if (!fs.existsSync(cmdDir)) continue;
3061
- for (const name of fs.readdirSync(cmdDir)) {
3062
- if (name.startsWith('oxe-') && name.endsWith('.md')) {
3063
- const p = path.join(cmdDir, name);
3064
- unlinkQuiet(p, u);
3065
- removedPaths.push(p);
3225
+ if (u.copilotCli) {
3226
+ for (const base of [claudeUserDir(ideOpts), copilotUserDir(ideOpts)]) {
3227
+ const cmdDir = path.join(base, 'commands');
3228
+ if (!fs.existsSync(cmdDir)) continue;
3229
+ for (const name of fs.readdirSync(cmdDir)) {
3230
+ if (oxeAgentInstall.isOxeCommandMarkdownName(name)) {
3231
+ const p = path.join(cmdDir, name);
3232
+ unlinkQuiet(p, u);
3233
+ removedPaths.push(p);
3066
3234
  }
3067
3235
  }
3068
3236
  }
@@ -3088,12 +3256,68 @@ function runUninstall(u) {
3088
3256
  removedPaths.push(skillFile);
3089
3257
  }
3090
3258
  }
3091
- if (u.dryRun) {
3092
- console.log(`${dim}agents${reset} (dry-run) limparia OpenCode, Gemini TOML, Windsurf, Codex, Antigravity (marcadores oxe-cc)`);
3093
- } else {
3094
- oxeAgentInstall.cleanupMarkedUnifiedArtifacts(u);
3095
- }
3096
- }
3259
+ }
3260
+
3261
+ if (u.allAgents || anyGranularUninstallAgent(u)) {
3262
+ const cleanupTargets = buildAgentCleanupTargets(u);
3263
+ if (u.dryRun) {
3264
+ const label = cleanupTargets
3265
+ ? Object.keys(cleanupTargets).filter((key) => cleanupTargets[key]).join(', ')
3266
+ : 'OpenCode, Gemini, Windsurf, Codex, Antigravity';
3267
+ console.log(`${dim}agents${reset} (dry-run) limparia ${label || 'OpenCode, Gemini, Windsurf, Codex, Antigravity'} (marcadores oxe-cc)`);
3268
+ } else {
3269
+ oxeAgentInstall.cleanupMarkedUnifiedArtifacts({ dryRun: u.dryRun, targets: cleanupTargets });
3270
+ }
3271
+ const globalAgentPaths = oxeAgentInstall.buildAgentInstallPaths(true, u.dir);
3272
+ const shouldTrack = (name) => !cleanupTargets || cleanupTargets[name] !== false;
3273
+ const pushRemoved = (filePath) => {
3274
+ if (removedPaths.indexOf(filePath) === -1) removedPaths.push(filePath);
3275
+ };
3276
+ if (shouldTrack('opencode')) {
3277
+ for (const dir of globalAgentPaths.opencodeCommandDirs) {
3278
+ if (!fs.existsSync(dir)) continue;
3279
+ for (const name of fs.readdirSync(dir)) {
3280
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3281
+ pushRemoved(path.join(dir, name));
3282
+ }
3283
+ }
3284
+ }
3285
+ if (shouldTrack('gemini')) {
3286
+ pushRemoved(path.join(globalAgentPaths.geminiCommandsBase, 'oxe.toml'));
3287
+ const geminiSub = path.join(globalAgentPaths.geminiCommandsBase, 'oxe');
3288
+ if (fs.existsSync(geminiSub)) {
3289
+ for (const name of fs.readdirSync(geminiSub)) {
3290
+ if (name.endsWith('.toml')) pushRemoved(path.join(geminiSub, name));
3291
+ }
3292
+ }
3293
+ }
3294
+ if (shouldTrack('windsurf') && fs.existsSync(globalAgentPaths.windsurfWorkflowsDir)) {
3295
+ for (const name of fs.readdirSync(globalAgentPaths.windsurfWorkflowsDir)) {
3296
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3297
+ pushRemoved(path.join(globalAgentPaths.windsurfWorkflowsDir, name));
3298
+ }
3299
+ }
3300
+ if (shouldTrack('codex')) {
3301
+ if (fs.existsSync(globalAgentPaths.codexPromptsDir)) {
3302
+ for (const name of fs.readdirSync(globalAgentPaths.codexPromptsDir)) {
3303
+ if (!oxeAgentInstall.isOxeCommandMarkdownName(name)) continue;
3304
+ pushRemoved(path.join(globalAgentPaths.codexPromptsDir, name));
3305
+ }
3306
+ }
3307
+ if (fs.existsSync(globalAgentPaths.codexAgentsSkillsRoot)) {
3308
+ for (const entry of fs.readdirSync(globalAgentPaths.codexAgentsSkillsRoot, { withFileTypes: true })) {
3309
+ if (!entry.isDirectory() || !/^oxe($|-)/.test(entry.name)) continue;
3310
+ pushRemoved(path.join(globalAgentPaths.codexAgentsSkillsRoot, entry.name, 'SKILL.md'));
3311
+ }
3312
+ }
3313
+ }
3314
+ if (shouldTrack('antigravity') && fs.existsSync(globalAgentPaths.antigravitySkillsRoot)) {
3315
+ for (const entry of fs.readdirSync(globalAgentPaths.antigravitySkillsRoot, { withFileTypes: true })) {
3316
+ if (!entry.isDirectory() || !/^oxe($|-)/.test(entry.name)) continue;
3317
+ pushRemoved(path.join(globalAgentPaths.antigravitySkillsRoot, entry.name, 'SKILL.md'));
3318
+ }
3319
+ }
3320
+ }
3097
3321
 
3098
3322
  if (u.ideLocal) {
3099
3323
  uninstallLocalIdeFromProject(u, removedPaths);
@@ -3126,7 +3350,7 @@ function runUninstall(u) {
3126
3350
  }
3127
3351
  }
3128
3352
 
3129
- if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli || u.copilotLegacyClean)) {
3353
+ if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli || u.copilotLegacyClean || anyGranularUninstallAgent(u))) {
3130
3354
  const prev = oxeManifest.loadFileManifest(home);
3131
3355
  const next = { ...prev };
3132
3356
  for (const p of removedPaths) delete next[p];
@@ -3951,15 +4175,24 @@ async function runRuntime(opts) {
3951
4175
  console.log(JSON.stringify(gates, null, 2));
3952
4176
  return;
3953
4177
  }
4178
+ const slaHours = gates.gateSlaHours || 24;
3954
4179
  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`);
4180
+ 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
4181
  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) {
4182
+ const allPending = [...gates.pending];
4183
+ for (const gate of allPending) {
3958
4184
  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` : ''}`);
4185
+ const isStale = ageHours != null && ageHours > slaHours;
4186
+ const icon = isStale ? `${c ? yellow : ''}⚠ stale (>${slaHours}h)${c ? reset : ''}` : `${c ? yellow : ''}⏳ pending${c ? reset : ''}`;
4187
+ const suggested = gate.action === 'approve' ? 'approve' : 'approve|reject|waive';
4188
+ console.log(` ${icon} ${gate.gate_id} · ${gate.scope || '—'} · ${gate.work_item_id || 'run'}${ageHours != null ? ` · ${ageHours}h aberto` : ''}`);
4189
+ console.log(` ${c ? dim : ''}ação sugerida: --decision ${suggested} · impacto: bloqueia promoção${c ? reset : ''}`);
3960
4190
  }
3961
4191
  for (const gate of gates.resolvedRecent) {
3962
- console.log(` ${green}RESOLVED${reset} ${gate.gate_id} · ${gate.scope} · ${gate.decision || '—'} · ${gate.actor || '—'}`);
4192
+ console.log(` ${c ? green : ''}✓ resolved${c ? reset : ''} ${gate.gate_id} · ${gate.scope || '—'} · ${gate.decision || '—'} · ${gate.actor || '—'}`);
4193
+ }
4194
+ if (gates.pending.length === 0 && gates.resolvedRecent.length === 0) {
4195
+ console.log(` ${c ? dim : ''}Nenhum gate pendente.${c ? reset : ''}`);
3963
4196
  }
3964
4197
  return;
3965
4198
  }
@@ -4012,11 +4245,16 @@ async function runRuntime(opts) {
4012
4245
  console.log(JSON.stringify(resolved, null, 2));
4013
4246
  return;
4014
4247
  }
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}`);
4248
+ const remaining = resolved.impact ? (resolved.impact.pendingRemaining || 0) : 0;
4249
+ const staleRemaining = resolved.impact ? (resolved.impact.staleRemaining || 0) : 0;
4250
+ const canPromote = remaining === 0 && staleRemaining === 0;
4251
+ console.log(` ${c ? green : ''}✓${c ? reset : ''} Gate ${resolved.gate.gate_id} resolvido (${resolved.gate.decision}).`);
4018
4252
  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}`);
4253
+ if (canPromote) {
4254
+ console.log(` ${c ? green : ''}✓ Run pode avançar para promoção — nenhum gate restante.${c ? reset : ''}`);
4255
+ } else {
4256
+ console.log(` ${c ? yellow : ''}⚠ Run ainda bloqueada por ${remaining} gate(s) restante(s)${staleRemaining > 0 ? ` (${staleRemaining} stale)` : ''}.${c ? reset : ''}`);
4257
+ }
4020
4258
  return;
4021
4259
  } catch (err) {
4022
4260
  console.error(`${red}${err && err.message ? err.message : 'Falha ao resolver gate.'}${reset}`);