oxe-cc 0.7.1 → 0.9.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 (156) hide show
  1. package/.cursor/commands/oxe-ask.md +34 -0
  2. package/.cursor/commands/oxe-capabilities.md +34 -0
  3. package/.cursor/commands/oxe-checkpoint.md +34 -0
  4. package/.cursor/commands/oxe-compact.md +33 -0
  5. package/.cursor/commands/oxe-dashboard.md +34 -0
  6. package/.cursor/commands/oxe-debug.md +34 -0
  7. package/.cursor/commands/oxe-discuss.md +34 -0
  8. package/.cursor/commands/oxe-execute.md +34 -0
  9. package/.cursor/commands/oxe-forensics.md +34 -0
  10. package/.cursor/commands/oxe-help.md +33 -0
  11. package/.cursor/commands/oxe-loop.md +34 -0
  12. package/.cursor/commands/oxe-milestone.md +34 -0
  13. package/.cursor/commands/oxe-next.md +33 -0
  14. package/.cursor/commands/oxe-obs.md +34 -0
  15. package/.cursor/commands/oxe-plan-agent.md +33 -0
  16. package/.cursor/commands/oxe-plan.md +34 -0
  17. package/.cursor/commands/oxe-project.md +34 -0
  18. package/.cursor/commands/oxe-quick.md +34 -0
  19. package/.cursor/commands/oxe-research.md +34 -0
  20. package/.cursor/commands/oxe-retro.md +34 -0
  21. package/.cursor/commands/oxe-review-pr.md +34 -0
  22. package/.cursor/commands/oxe-route.md +34 -0
  23. package/.cursor/commands/oxe-scan.md +34 -0
  24. package/.cursor/commands/oxe-security.md +34 -0
  25. package/.cursor/commands/oxe-session.md +34 -0
  26. package/.cursor/commands/oxe-skill.md +45 -0
  27. package/.cursor/commands/oxe-spec.md +34 -0
  28. package/.cursor/commands/oxe-ui-review.md +34 -0
  29. package/.cursor/commands/oxe-ui-spec.md +34 -0
  30. package/.cursor/commands/oxe-update.md +33 -0
  31. package/.cursor/commands/oxe-validate-gaps.md +34 -0
  32. package/.cursor/commands/oxe-verify.md +34 -0
  33. package/.cursor/commands/oxe-workstream.md +34 -0
  34. package/.cursor/commands/oxe.md +38 -2
  35. package/.github/copilot-instructions.md +8 -5
  36. package/.github/prompts/oxe-ask.prompt.md +33 -0
  37. package/.github/prompts/oxe-capabilities.prompt.md +33 -0
  38. package/.github/prompts/oxe-checkpoint.prompt.md +45 -12
  39. package/.github/prompts/oxe-compact.prompt.md +44 -11
  40. package/.github/prompts/oxe-dashboard.prompt.md +33 -0
  41. package/.github/prompts/oxe-debug.prompt.md +45 -12
  42. package/.github/prompts/oxe-discuss.prompt.md +33 -0
  43. package/.github/prompts/oxe-execute.prompt.md +45 -12
  44. package/.github/prompts/oxe-forensics.prompt.md +45 -12
  45. package/.github/prompts/oxe-help.prompt.md +42 -9
  46. package/.github/prompts/oxe-loop.prompt.md +45 -12
  47. package/.github/prompts/oxe-milestone.prompt.md +45 -12
  48. package/.github/prompts/oxe-next.prompt.md +42 -9
  49. package/.github/prompts/oxe-obs.prompt.md +45 -12
  50. package/.github/prompts/oxe-plan-agent.prompt.md +43 -10
  51. package/.github/prompts/oxe-plan.prompt.md +45 -12
  52. package/.github/prompts/oxe-project.prompt.md +45 -12
  53. package/.github/prompts/oxe-quick.prompt.md +45 -12
  54. package/.github/prompts/oxe-research.prompt.md +45 -12
  55. package/.github/prompts/oxe-retro.prompt.md +45 -12
  56. package/.github/prompts/oxe-review-pr.prompt.md +45 -12
  57. package/.github/prompts/oxe-route.prompt.md +45 -12
  58. package/.github/prompts/oxe-scan.prompt.md +45 -12
  59. package/.github/prompts/oxe-security.prompt.md +45 -12
  60. package/.github/prompts/oxe-session.prompt.md +33 -0
  61. package/.github/prompts/oxe-skill.prompt.md +45 -0
  62. package/.github/prompts/oxe-spec.prompt.md +45 -12
  63. package/.github/prompts/oxe-ui-review.prompt.md +45 -12
  64. package/.github/prompts/oxe-ui-spec.prompt.md +45 -12
  65. package/.github/prompts/oxe-update.prompt.md +44 -11
  66. package/.github/prompts/oxe-validate-gaps.prompt.md +45 -12
  67. package/.github/prompts/oxe-verify.prompt.md +45 -12
  68. package/.github/prompts/oxe-workstream.prompt.md +45 -12
  69. package/.github/prompts/oxe.prompt.md +45 -12
  70. package/AGENTS.md +6 -4
  71. package/CHANGELOG.md +45 -0
  72. package/README.md +38 -8
  73. package/bin/lib/oxe-agent-install.cjs +69 -55
  74. package/bin/lib/oxe-context-engine.cjs +866 -0
  75. package/bin/lib/oxe-dashboard.cjs +605 -588
  76. package/bin/lib/oxe-operational.cjs +105 -0
  77. package/bin/lib/oxe-plugins.cjs +115 -0
  78. package/bin/lib/oxe-project-health.cjs +1139 -666
  79. package/bin/lib/oxe-runtime-semantics.cjs +459 -0
  80. package/bin/lib/oxe-security.cjs +64 -0
  81. package/bin/oxe-cc.js +615 -46
  82. package/commands/oxe/ask.md +33 -0
  83. package/commands/oxe/capabilities.md +33 -0
  84. package/commands/oxe/checkpoint.md +49 -16
  85. package/commands/oxe/compact.md +43 -10
  86. package/commands/oxe/dashboard.md +33 -0
  87. package/commands/oxe/debug.md +49 -16
  88. package/commands/oxe/discuss.md +33 -0
  89. package/commands/oxe/execute.md +49 -16
  90. package/commands/oxe/forensics.md +49 -16
  91. package/commands/oxe/help.md +44 -11
  92. package/commands/oxe/loop.md +50 -17
  93. package/commands/oxe/milestone.md +49 -16
  94. package/commands/oxe/next.md +45 -12
  95. package/commands/oxe/obs.md +49 -16
  96. package/commands/oxe/oxe.md +49 -16
  97. package/commands/oxe/plan-agent.md +48 -15
  98. package/commands/oxe/plan.md +48 -15
  99. package/commands/oxe/project.md +49 -16
  100. package/commands/oxe/quick.md +49 -16
  101. package/commands/oxe/research.md +49 -16
  102. package/commands/oxe/retro.md +49 -16
  103. package/commands/oxe/review-pr.md +49 -16
  104. package/commands/oxe/route.md +44 -11
  105. package/commands/oxe/scan.md +49 -16
  106. package/commands/oxe/security.md +49 -16
  107. package/commands/oxe/session.md +33 -0
  108. package/commands/oxe/skill.md +49 -0
  109. package/commands/oxe/spec.md +47 -14
  110. package/commands/oxe/ui-review.md +49 -16
  111. package/commands/oxe/ui-spec.md +49 -16
  112. package/commands/oxe/update.md +49 -16
  113. package/commands/oxe/validate-gaps.md +49 -16
  114. package/commands/oxe/verify.md +48 -15
  115. package/commands/oxe/workstream.md +49 -16
  116. package/lib/sdk/index.cjs +140 -7
  117. package/lib/sdk/index.d.ts +266 -1
  118. package/oxe/templates/HYPOTHESES.template.md +33 -0
  119. package/oxe/templates/PLAN.template.md +53 -22
  120. package/oxe/templates/SESSION.template.md +2 -0
  121. package/oxe/templates/SKILL.template.md +26 -0
  122. package/oxe/templates/WORKFLOW_AUTHORING.md +18 -2
  123. package/oxe/templates/config.template.json +16 -14
  124. package/oxe/workflows/ask.md +28 -7
  125. package/oxe/workflows/capabilities.md +2 -0
  126. package/oxe/workflows/dashboard.md +12 -2
  127. package/oxe/workflows/debug.md +9 -4
  128. package/oxe/workflows/discuss.md +12 -6
  129. package/oxe/workflows/execute.md +34 -12
  130. package/oxe/workflows/forensics.md +14 -9
  131. package/oxe/workflows/help.md +20 -9
  132. package/oxe/workflows/loop.md +13 -7
  133. package/oxe/workflows/next.md +6 -4
  134. package/oxe/workflows/plan-agent.md +3 -2
  135. package/oxe/workflows/plan.md +26 -3
  136. package/oxe/workflows/quick.md +10 -3
  137. package/oxe/workflows/references/reasoning-discovery.md +28 -0
  138. package/oxe/workflows/references/reasoning-execution.md +29 -0
  139. package/oxe/workflows/references/reasoning-planning.md +32 -0
  140. package/oxe/workflows/references/reasoning-review.md +29 -0
  141. package/oxe/workflows/references/reasoning-status.md +24 -0
  142. package/oxe/workflows/references/workflow-runtime-contracts.json +879 -0
  143. package/oxe/workflows/research.md +8 -2
  144. package/oxe/workflows/retro.md +7 -2
  145. package/oxe/workflows/review-pr.md +12 -8
  146. package/oxe/workflows/route.md +16 -13
  147. package/oxe/workflows/security.md +3 -2
  148. package/oxe/workflows/session.md +44 -0
  149. package/oxe/workflows/skill.md +44 -0
  150. package/oxe/workflows/spec.md +21 -18
  151. package/oxe/workflows/ui-review.md +13 -7
  152. package/oxe/workflows/update.md +3 -1
  153. package/oxe/workflows/validate-gaps.md +12 -6
  154. package/oxe/workflows/verify-audit.md +73 -0
  155. package/oxe/workflows/verify.md +40 -16
  156. package/package.json +4 -3
package/bin/oxe-cc.js CHANGED
@@ -21,6 +21,9 @@ const oxeNpmVersion = require(path.join(__dirname, 'lib', 'oxe-npm-version.cjs')
21
21
  const oxeDashboard = require(path.join(__dirname, 'lib', 'oxe-dashboard.cjs'));
22
22
  const oxeOperational = require(path.join(__dirname, 'lib', 'oxe-operational.cjs'));
23
23
  const oxeAzure = require(path.join(__dirname, 'lib', 'oxe-azure.cjs'));
24
+ const oxePlugins = require(path.join(__dirname, 'lib', 'oxe-plugins.cjs'));
25
+ const oxeContext = require(path.join(__dirname, 'lib', 'oxe-context-engine.cjs'));
26
+ const oxeRuntimeSemantics = require(path.join(__dirname, 'lib', 'oxe-runtime-semantics.cjs'));
24
27
 
25
28
  /** Merge markers for ~/.copilot/copilot-instructions.md (bloco OXE). */
26
29
  const OXE_INST_BEGIN = '<!-- oxe-cc:install-begin -->';
@@ -162,7 +165,7 @@ function buildInstallSummary(opts, fullLayout) {
162
165
  }
163
166
  if (opts.copilot) {
164
167
  bullets.push(
165
- `${prefix}Copilot (VS Code): trecho OXE em ${displayPathForUser(copilotInstructionsPath(opts))} e prompts em ${displayPathForUser(copilotPromptsDirPath(opts))}`
168
+ `${prefix}Copilot (VS Code): integração workspace-first em ${displayPathForUser(copilotInstructionsPath(opts))} + ${displayPathForUser(copilotPromptsDirPath(opts))}`
166
169
  );
167
170
  }
168
171
  if (opts.copilotCli && !opts.allAgents) {
@@ -249,7 +252,12 @@ function buildUninstallFooter(u) {
249
252
  const p = u.dryRun ? '[simulação] ' : '';
250
253
  const rm = u.dryRun ? 'Seriam removidos' : 'Removidos';
251
254
  if (u.cursor) bullets.push(`${p}${rm} artefatos OXE em ~/.cursor (comandos e regras).`);
252
- if (u.copilot) bullets.push(`${p}${rm} prompts oxe-* e bloco OXE em copilot-instructions (se existissem).`);
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
+ }
258
+ if (u.copilotLegacyClean) {
259
+ bullets.push(`${p}${rm} apenas o legado global do Copilot VS Code em ~/.copilot/ (prompts oxe-* e bloco OXE global).`);
260
+ }
253
261
  if (u.copilotCli || u.allAgents) {
254
262
  bullets.push(`${p}${rm} comandos oxe-* em ~/.claude/commands e ~/.copilot/commands.`);
255
263
  bullets.push(`${p}${rm} skills OXE (marcadas oxe-cc) em ~/.copilot/skills/oxe*/.`);
@@ -356,7 +364,7 @@ function parseInstallArgs(argv) {
356
364
  out.ideLocal = true;
357
365
  out.explicitIdeScope = true;
358
366
  } else if (a === '--cursor') out.cursor = true;
359
- else if (a === '--copilot') out.copilot = true;
367
+ else if (a === '--copilot' || a === '--copilot-vscode') out.copilot = true;
360
368
  else if (a === '--copilot-cli') out.copilotCli = true;
361
369
  else if (a === '--all-agents') out.allAgents = true;
362
370
  else if (a === '--opencode') out.agentOpenCode = true;
@@ -403,7 +411,10 @@ function parseInstallArgs(argv) {
403
411
  out.conflictFlags = '--config-dir não combina com --oxe-only nem com --all-agents';
404
412
  } else {
405
413
  const ideCount = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
406
- if (ideCount !== 1) {
414
+ if (out.copilot && !out.cursor && !out.copilotCli) {
415
+ out.conflictFlags =
416
+ '--config-dir não combina com --copilot porque o GitHub Copilot no VS Code usa .github/ no workspace';
417
+ } else if (ideCount !== 1) {
407
418
  out.conflictFlags =
408
419
  '--config-dir exige exatamente um entre --cursor, --copilot e --copilot-cli (e não combina com --oxe-only)';
409
420
  }
@@ -557,24 +568,38 @@ function installClaudeBase(opts) {
557
568
  return claudeUserDir(opts);
558
569
  }
559
570
 
560
- /** Ficheiro copilot-instructions (VS Code): ~/.copilot ou .github no repo. */
571
+ /** Ficheiro copilot-instructions (VS Code): sempre no workspace (.github/). */
561
572
  function copilotInstructionsPath(opts) {
562
573
  const target = path.resolve(opts.dir);
563
- if (opts.ideLocal && opts.copilot) {
564
- return path.join(target, '.github', 'copilot-instructions.md');
565
- }
566
- return path.join(copilotUserDir(opts), 'copilot-instructions.md');
574
+ return path.join(target, '.github', 'copilot-instructions.md');
567
575
  }
568
576
 
569
- /** Pasta de prompts Copilot VS Code. */
577
+ /** Pasta de prompt files do Copilot VS Code: sempre no workspace (.github/prompts). */
570
578
  function copilotPromptsDirPath(opts) {
571
579
  const target = path.resolve(opts.dir);
572
- if (opts.ideLocal && opts.copilot) {
573
- return path.join(target, '.github', 'prompts');
574
- }
580
+ return path.join(target, '.github', 'prompts');
581
+ }
582
+
583
+ /** Artefato de auditoria da integração Copilot VS Code. */
584
+ function copilotWorkspaceManifestPath(opts) {
585
+ return path.join(path.resolve(opts.dir), '.oxe', 'install', 'copilot-vscode.json');
586
+ }
587
+
588
+ /** Artefato de auditoria da semântica multi-runtime. */
589
+ function runtimeSemanticsManifestPath(opts) {
590
+ return path.join(path.resolve(opts.dir), '.oxe', 'install', 'runtime-semantics.json');
591
+ }
592
+
593
+ /** Integração legado do Copilot VS Code em ~/.copilot/. */
594
+ function copilotLegacyPromptDir(opts) {
575
595
  return path.join(copilotUserDir(opts), 'prompts');
576
596
  }
577
597
 
598
+ /** Integração legado do Copilot VS Code em ~/.copilot/. */
599
+ function copilotLegacyInstructionsPath(opts) {
600
+ return path.join(copilotUserDir(opts), 'copilot-instructions.md');
601
+ }
602
+
578
603
  /** Layout “clássico”: pasta `oxe/` na raiz do repo. Caso contrário: só `.oxe/` (workflows em `.oxe/workflows`). */
579
604
  function useFullRepoLayout(opts) {
580
605
  return opts.installAssetsGlobal === true;
@@ -655,6 +680,114 @@ function installMergedCopilotInstructions(srcPath, destPath, opts, idePathRewrit
655
680
  fs.writeFileSync(destPath, merged, 'utf8');
656
681
  }
657
682
 
683
+ /**
684
+ * @param {InstallOpts} opts
685
+ * @param {{ layout: 'nested' | 'classic' }} info
686
+ */
687
+ function writeCopilotVsCodeManifest(opts, info) {
688
+ const promptsDir = copilotPromptsDirPath(opts);
689
+ const instructionsPath = copilotInstructionsPath(opts);
690
+ const manifestPath = copilotWorkspaceManifestPath(opts);
691
+ const promptFiles = fs.existsSync(promptsDir)
692
+ ? fs
693
+ .readdirSync(promptsDir, { withFileTypes: true })
694
+ .filter((entry) => entry.isFile() && /^oxe-.*\.prompt\.md$/i.test(entry.name))
695
+ .map((entry) => entry.name)
696
+ .sort()
697
+ : [];
698
+ const payload = {
699
+ schema_version: 1,
700
+ target: 'copilot-vscode',
701
+ synced_at: new Date().toISOString(),
702
+ oxe_version: readPkgVersion(),
703
+ layout: info.layout,
704
+ instructions_path: path.relative(path.resolve(opts.dir), instructionsPath).replace(/\\/g, '/'),
705
+ prompt_files: promptFiles,
706
+ hashes: {},
707
+ };
708
+ if (fs.existsSync(instructionsPath)) {
709
+ payload.hashes[payload.instructions_path] = oxeManifest.sha256File(instructionsPath);
710
+ }
711
+ for (const name of promptFiles) {
712
+ const rel = path.posix.join('.github', 'prompts', name);
713
+ payload.hashes[rel] = oxeManifest.sha256File(path.join(promptsDir, name));
714
+ }
715
+ ensureDir(path.dirname(manifestPath));
716
+ fs.writeFileSync(manifestPath, JSON.stringify(payload, null, 2) + '\n', 'utf8');
717
+ }
718
+
719
+ /**
720
+ * @param {InstallOpts} opts
721
+ * @param {{ layout: 'nested' | 'classic' }} info
722
+ */
723
+ function writeRuntimeSemanticsManifest(opts, info) {
724
+ const target = path.resolve(opts.dir);
725
+ const manifestPath = runtimeSemanticsManifestPath(opts);
726
+ const audit = oxeRuntimeSemantics.auditRuntimeTargets(target);
727
+ const wrappers = {};
728
+ const collectWrapper = (name, root, nameFilter) => {
729
+ if (!fs.existsSync(root)) return;
730
+ const files = oxeManifest.collectFilesRecursive(root, nameFilter);
731
+ wrappers[name] = {
732
+ path: path.relative(target, root).replace(/\\/g, '/'),
733
+ files: files
734
+ .map((filePath) => ({
735
+ path: path.relative(target, filePath).replace(/\\/g, '/'),
736
+ hash: oxeManifest.sha256File(filePath),
737
+ }))
738
+ .sort((a, b) => a.path.localeCompare(b.path)),
739
+ };
740
+ };
741
+ collectWrapper('commands', path.join(target, 'commands', 'oxe'), (name) => name.endsWith('.md'));
742
+ collectWrapper(
743
+ 'copilot_prompts',
744
+ path.join(target, '.github', 'prompts'),
745
+ (name) => (name === 'oxe.prompt.md' || name.startsWith('oxe-')) && name.endsWith('.prompt.md')
746
+ );
747
+ collectWrapper(
748
+ 'cursor_commands',
749
+ path.join(target, '.cursor', 'commands'),
750
+ (name) => (name === 'oxe.md' || name.startsWith('oxe-')) && name.endsWith('.md')
751
+ );
752
+ const payload = {
753
+ schema_version: 1,
754
+ target: 'runtime-semantics',
755
+ synced_at: new Date().toISOString(),
756
+ oxe_version: readPkgVersion(),
757
+ contract_version: oxeRuntimeSemantics.CONTRACT_VERSION,
758
+ layout: info.layout,
759
+ installed_runtimes: {
760
+ cursor: Boolean(opts.cursor),
761
+ copilot_vscode: Boolean(opts.copilot),
762
+ copilot_cli: Boolean(opts.copilotCli || opts.allAgents),
763
+ opencode: Boolean(opts.agentOpenCode || opts.allAgents),
764
+ gemini: Boolean(opts.agentGemini || opts.allAgents),
765
+ codex: Boolean(opts.agentCodex || opts.allAgents),
766
+ windsurf: Boolean(opts.agentWindsurf || opts.allAgents),
767
+ antigravity: Boolean(opts.agentAntigravity || opts.allAgents),
768
+ },
769
+ semantics_hashes: Object.fromEntries(
770
+ oxeRuntimeSemantics.getAllWorkflowContracts().map((contract) => [
771
+ contract.workflow_slug,
772
+ oxeRuntimeSemantics.computeSemanticsHash(contract.workflow_slug),
773
+ ])
774
+ ),
775
+ wrappers,
776
+ audit: {
777
+ ok: audit.ok,
778
+ warnings: audit.warnings,
779
+ mismatches: audit.mismatches.map((entry) => ({
780
+ target: entry.target,
781
+ slug: entry.slug,
782
+ file: path.relative(target, entry.file).replace(/\\/g, '/'),
783
+ issues: entry.issues,
784
+ })),
785
+ },
786
+ };
787
+ ensureDir(path.dirname(manifestPath));
788
+ fs.writeFileSync(manifestPath, JSON.stringify(payload, null, 2) + '\n', 'utf8');
789
+ }
790
+
658
791
  function canInstallPrompt() {
659
792
  return (
660
793
  process.stdin.isTTY === true &&
@@ -1024,6 +1157,10 @@ function bootstrapOxe(target, opts) {
1024
1157
  const capabilitiesDir = path.join(oxeDir, 'capabilities');
1025
1158
  const investigationsDir = path.join(oxeDir, 'investigations');
1026
1159
  const dashboardDir = path.join(oxeDir, 'dashboard');
1160
+ const contextDir = path.join(oxeDir, 'context');
1161
+ const contextPacksDir = path.join(contextDir, 'packs');
1162
+ const contextSummariesDir = path.join(contextDir, 'summaries');
1163
+ const installDir = path.join(oxeDir, 'install');
1027
1164
  const stateSrc = path.join(PKG_ROOT, 'oxe', 'templates', 'STATE.md');
1028
1165
  const stateDest = path.join(oxeDir, 'STATE.md');
1029
1166
  const configSrc = path.join(PKG_ROOT, 'oxe', 'templates', 'config.template.json');
@@ -1035,7 +1172,7 @@ function bootstrapOxe(target, opts) {
1035
1172
  }
1036
1173
 
1037
1174
  if (opts.dryRun) {
1038
- console.log(`${dim}init${reset} ${oxeDir}/ (STATE.md, config.json, codebase/, capabilities/, investigations/, dashboard/, runs/, OXE-EVENTS.ndjson, ACTIVE-RUN.json)`);
1175
+ console.log(`${dim}init${reset} ${oxeDir}/ (STATE.md, config.json, codebase/, capabilities/, investigations/, dashboard/, context/, install/, runs/, OXE-EVENTS.ndjson, ACTIVE-RUN.json)`);
1039
1176
  ensureGitignoreIgnoresOxeDir(target, { dryRun: true });
1040
1177
  return;
1041
1178
  }
@@ -1044,6 +1181,9 @@ function bootstrapOxe(target, opts) {
1044
1181
  ensureDir(capabilitiesDir);
1045
1182
  ensureDir(investigationsDir);
1046
1183
  ensureDir(dashboardDir);
1184
+ ensureDir(contextPacksDir);
1185
+ ensureDir(contextSummariesDir);
1186
+ ensureDir(installDir);
1047
1187
 
1048
1188
  if (!fs.existsSync(stateDest) || opts.force) {
1049
1189
  copyFile(stateSrc, stateDest, { dryRun: false });
@@ -1248,21 +1388,42 @@ function printOxeHealthDiagnostics(target, c, diagOpts = {}) {
1248
1388
  if (r.activeSession) {
1249
1389
  console.log(` ${c ? dim : ''}Sessão ativa:${c ? reset : ''} ${r.activeSession}`);
1250
1390
  }
1251
- if (r.planReviewStatus) {
1252
- console.log(` ${c ? dim : ''}Revisão do plano:${c ? reset : ''} ${r.planReviewStatus}`);
1253
- }
1254
- if (r.activeRun && r.activeRun.run_id) {
1255
- console.log(` ${c ? dim : ''}Run ativo:${c ? reset : ''} ${r.activeRun.run_id} (${r.activeRun.status || 'planned'})`);
1256
- }
1257
- if (r.eventsSummary) {
1258
- console.log(` ${c ? dim : ''}Tracing:${c ? reset : ''} ${r.eventsSummary.total} evento(s)`);
1259
- }
1391
+ if (r.planReviewStatus) {
1392
+ console.log(` ${c ? dim : ''}Revisão do plano:${c ? reset : ''} ${r.planReviewStatus}`);
1393
+ }
1394
+ if (r.activeRun && r.activeRun.run_id) {
1395
+ console.log(` ${c ? dim : ''}Run ativo:${c ? reset : ''} ${r.activeRun.run_id} (${r.activeRun.status || 'planned'})`);
1396
+ }
1397
+ if (r.eventsSummary) {
1398
+ console.log(` ${c ? dim : ''}Tracing:${c ? reset : ''} ${r.eventsSummary.total} evento(s)`);
1399
+ }
1260
1400
  if (r.planSelfEvaluation && r.planSelfEvaluation.hasSection) {
1261
1401
  const best = r.planSelfEvaluation.bestPlan || '—';
1262
1402
  const conf =
1263
1403
  typeof r.planSelfEvaluation.confidence === 'number' ? `${r.planSelfEvaluation.confidence}%` : '—';
1264
1404
  console.log(` ${c ? dim : ''}Plano (autoavaliação):${c ? reset : ''} melhor=${best} | confiança=${conf}`);
1265
1405
  }
1406
+ if (r.contextQuality) {
1407
+ console.log(
1408
+ ` ${c ? dim : ''}Contexto:${c ? reset : ''} score=${r.contextQuality.primaryScore != null ? r.contextQuality.primaryScore : '—'} | workflow=${r.contextQuality.primaryWorkflow || '—'} | status=${r.contextQuality.primaryStatus || '—'}`
1409
+ );
1410
+ }
1411
+ if (r.semanticsDrift) {
1412
+ console.log(` ${c ? dim : ''}Semântica multi-runtime:${c ? reset : ''} ${r.semanticsDrift.ok ? 'alinhada' : 'com drift'}`);
1413
+ }
1414
+ if (r.copilot && (r.copilot.detected || r.copilot.warnings.length)) {
1415
+ const promptSource =
1416
+ r.copilot.promptSource === 'workspace'
1417
+ ? '.github/prompts/'
1418
+ : r.copilot.promptSource === 'legacy_global'
1419
+ ? '~/.copilot/prompts/ (legado)'
1420
+ : 'ausente';
1421
+ console.log(` ${c ? dim : ''}Copilot VS Code:${c ? reset : ''} target=workspace | source=${promptSource}`);
1422
+ console.log(` ${c ? dim : ''}Copilot workspace:${c ? reset : ''} ${displayPathForUser(r.copilot.workspace.promptsDir)}`);
1423
+ if (r.copilot.legacy.detected) {
1424
+ console.log(` ${c ? dim : ''}Legado global:${c ? reset : ''} ${displayPathForUser(r.copilot.legacy.root)}`);
1425
+ }
1426
+ }
1266
1427
  if (r.azureActive && r.azure) {
1267
1428
  console.log(` ${c ? dim : ''}Azure:${c ? reset : ''} ${r.azure.authStatus && r.azure.authStatus.login_active ? 'login ativo' : 'sem login'} | subscription=${r.azure.profile && (r.azure.profile.subscription_name || r.azure.profile.subscription_id) || '—'}`);
1268
1429
  console.log(` ${c ? dim : ''}Azure inventory:${c ? reset : ''} total=${r.azure.inventorySummary ? r.azure.inventorySummary.total : 0} | pendências=${r.azure.pendingOperations || 0}`);
@@ -1328,6 +1489,15 @@ function printOxeHealthDiagnostics(target, c, diagOpts = {}) {
1328
1489
  for (const w of r.installWarn) {
1329
1490
  console.log(` ${yellow}AVISO${reset} ${w}`);
1330
1491
  }
1492
+ for (const w of r.copilotWarn) {
1493
+ console.log(` ${yellow}AVISO${reset} ${w}`);
1494
+ }
1495
+ for (const w of r.contextWarn || []) {
1496
+ console.log(` ${yellow}AVISO${reset} ${w}`);
1497
+ }
1498
+ for (const w of r.semanticsWarn || []) {
1499
+ console.log(` ${yellow}AVISO${reset} ${w}`);
1500
+ }
1331
1501
  if (r.summaryGapWarn) {
1332
1502
  console.log(` ${yellow}AVISO${reset} ${r.summaryGapWarn}`);
1333
1503
  }
@@ -1371,6 +1541,17 @@ function runStatusFull(target) {
1371
1541
  const healthColor = report.healthStatus === 'healthy' ? green : report.healthStatus === 'warning' ? yellow : red;
1372
1542
  console.log(` ${c ? green : ''}Saúde:${c ? reset : ''} ${c ? healthColor : ''}${report.healthStatus}${c ? reset : ''}`);
1373
1543
 
1544
+ if (report.copilot && (report.copilot.detected || report.copilot.warnings.length)) {
1545
+ console.log(`\n ${c ? yellow : ''}Copilot VS Code${c ? reset : ''}`);
1546
+ console.log(` ${c ? dim : ''}Target:${c ? reset : ''} workspace (.github/)`);
1547
+ console.log(` ${c ? dim : ''}Source:${c ? reset : ''} ${report.copilot.promptSource}`);
1548
+ console.log(` ${c ? dim : ''}Workspace prompts:${c ? reset : ''} ${displayPathForUser(report.copilot.workspace.promptsDir)}`);
1549
+ console.log(` ${c ? dim : ''}Legado global:${c ? reset : ''} ${report.copilot.legacy.detected ? 'detectado' : 'não'}`);
1550
+ for (const warning of report.copilotWarn.slice(0, 3)) {
1551
+ console.log(` ${c ? yellow : ''} • ${warning}${c ? reset : ''}`);
1552
+ }
1553
+ }
1554
+
1374
1555
  // Coverage matrix
1375
1556
  const specPath = activeSession && sp.spec ? sp.spec : p.spec;
1376
1557
  const planPath = activeSession && sp.plan ? sp.plan : p.plan;
@@ -1404,6 +1585,18 @@ function runStatusFull(target) {
1404
1585
  console.log(` ${c ? dim : ''}Run:${c ? reset : ''} ${ar.run_id || '—'} ${c ? dim : ''}Estado:${c ? reset : ''} ${ar.status || '—'} ${c ? dim : ''}Onda:${c ? reset : ''} ${ar.current_wave != null ? ar.current_wave : '—'}`);
1405
1586
  }
1406
1587
 
1588
+ if (report.contextQuality || report.semanticsDrift) {
1589
+ const primaryWorkflow = report.contextQuality && report.contextQuality.primaryWorkflow ? report.contextQuality.primaryWorkflow : 'dashboard';
1590
+ const primaryScore = report.contextQuality && report.contextQuality.primaryScore != null ? report.contextQuality.primaryScore : null;
1591
+ const primaryStatus = report.contextQuality && report.contextQuality.primaryStatus ? report.contextQuality.primaryStatus : '—';
1592
+ const freshness = report.packFreshness && report.packFreshness[primaryWorkflow] ? report.packFreshness[primaryWorkflow] : null;
1593
+ console.log(`\n ${c ? yellow : ''}Contexto e semântica${c ? reset : ''}`);
1594
+ console.log(` ${c ? dim : ''}Pack primário:${c ? reset : ''} ${primaryWorkflow}`);
1595
+ console.log(` ${c ? dim : ''}Qualidade:${c ? reset : ''} ${primaryScore != null ? `${primaryScore} (${primaryStatus})` : '—'}`);
1596
+ console.log(` ${c ? dim : ''}Freshness:${c ? reset : ''} ${freshness ? `${freshness.reason}${freshness.pack_age_hours != null ? ` · ${freshness.pack_age_hours}h` : ''}` : '—'}`);
1597
+ console.log(` ${c ? dim : ''}Drift semântico:${c ? reset : ''} ${report.semanticsDrift && report.semanticsDrift.ok ? 'não detectado' : 'detectado'}`);
1598
+ }
1599
+
1407
1600
  // Plan self-evaluation
1408
1601
  if (report.planSelfEvaluation) {
1409
1602
  const pse = report.planSelfEvaluation;
@@ -1437,7 +1630,7 @@ function runStatus(target, opts = {}) {
1437
1630
  if (opts.json) {
1438
1631
  /** @type {Record<string, unknown>} */
1439
1632
  const payload = {
1440
- oxeStatusSchema: 2,
1633
+ oxeStatusSchema: 3,
1441
1634
  projectRoot: path.resolve(target),
1442
1635
  nextStep: report.next.step,
1443
1636
  cursorCmd: report.next.cursorCmd,
@@ -1454,9 +1647,15 @@ function runStatus(target, opts = {}) {
1454
1647
  planReviewStatus: report.planReviewStatus,
1455
1648
  activeRun: report.activeRun,
1456
1649
  eventsSummary: report.eventsSummary,
1457
- memoryLayers: report.memoryLayers,
1458
- azureActive: report.azureActive,
1459
- azure: report.azure,
1650
+ memoryLayers: report.memoryLayers,
1651
+ azureActive: report.azureActive,
1652
+ azure: report.azure,
1653
+ copilot: report.copilot,
1654
+ contextPacks: report.contextPacks,
1655
+ contextQuality: report.contextQuality,
1656
+ semanticsDrift: report.semanticsDrift,
1657
+ packFreshness: report.packFreshness,
1658
+ activeSummaryRefs: report.activeSummaryRefs,
1460
1659
  diagnostics: {
1461
1660
  configParseError: report.configParseError,
1462
1661
  typeErrors: report.typeErrors,
@@ -1468,6 +1667,9 @@ function runStatus(target, opts = {}) {
1468
1667
  investigationWarnings: report.investigationWarn,
1469
1668
  sessionWarnings: report.sessionWarn,
1470
1669
  installWarnings: report.installWarn,
1670
+ copilotWarnings: report.copilotWarn,
1671
+ contextWarnings: report.contextWarn,
1672
+ semanticsWarnings: report.semanticsWarn,
1471
1673
  summaryGapWarning: report.summaryGapWarn,
1472
1674
  specWarnings: report.specWarn,
1473
1675
  planWarnings: report.planWarn,
@@ -1580,6 +1782,20 @@ function runDoctor(target) {
1580
1782
  }
1581
1783
  }
1582
1784
 
1785
+ // Verificar workflows sem contrato no registry de semântica
1786
+ const allContractSlugs = new Set(oxeRuntimeSemantics.getAllWorkflowContracts().map((ct) => ct.workflow_slug));
1787
+ const workflowMdFiles = fs.readdirSync(wfTgt).filter((f) => f.endsWith('.md'));
1788
+ const orphanedWorkflows = workflowMdFiles
1789
+ .map((f) => f.replace(/\.md$/, ''))
1790
+ .filter((slug) => !allContractSlugs.has(slug));
1791
+ if (orphanedWorkflows.length) {
1792
+ for (const slug of orphanedWorkflows) {
1793
+ console.log(`${yellow}AVISO${reset} Workflow sem contrato semântico no registry: ${slug}.md — adicione em workflow-runtime-contracts.json ou rode \`npx oxe-cc update\`.`);
1794
+ }
1795
+ } else {
1796
+ console.log(`${green}OK${reset} Todos os workflows têm contrato semântico registado`);
1797
+ }
1798
+
1583
1799
  const oxeState = path.join(target, '.oxe', 'STATE.md');
1584
1800
  if (fs.existsSync(oxeState)) console.log(`${green}OK${reset} .oxe/STATE.md encontrado`);
1585
1801
  else {
@@ -1727,6 +1943,7 @@ function updateForwardedInstallFlags() {
1727
1943
  return [
1728
1944
  '--cursor',
1729
1945
  '--copilot',
1946
+ '--copilot-vscode',
1730
1947
  '--copilot-cli',
1731
1948
  '--all-agents',
1732
1949
  '--opencode',
@@ -1848,6 +2065,7 @@ ${green}Uso:${reset}
1848
2065
  npx oxe-cc doctor [opções] [pasta-do-projeto]
1849
2066
  npx oxe-cc status [opções] [pasta-do-projeto]
1850
2067
  npx oxe-cc init-oxe [opções] [pasta-do-projeto]
2068
+ npx oxe-cc context <build|inspect> [opções] [pasta-do-projeto]
1851
2069
  npx oxe-cc dashboard [opções] [pasta-do-projeto]
1852
2070
  npx oxe-cc runtime <status|start|pause|resume|replay> [opções] [pasta-do-projeto]
1853
2071
  npx oxe-cc azure <status|doctor|auth|sync|find|servicebus|eventgrid|sql|operations> [opções] [pasta-do-projeto]
@@ -1857,11 +2075,13 @@ ${green}Uso:${reset}
1857
2075
 
1858
2076
  ${green}uninstall${reset} (remove OXE da pasta do usuário + pastas de workflows no repo)
1859
2077
  --cursor / --copilot / --copilot-cli só essa integração (omissão = todas)
2078
+ --copilot-vscode alias explícito de --copilot
2079
+ --copilot-legacy-clean limpa só o legado antigo do Copilot VS Code em ~/.copilot/
1860
2080
  --all-agents também remove ficheiros multi-plataforma (com --copilot-cli implícito)
1861
2081
  --ide-local remove integrações IDE neste repositório (.cursor, .github, .claude, .copilot, …)
1862
2082
  --ide-only não apagar .oxe/workflows, oxe/, etc. no projeto
1863
2083
  --global-cli, -g também executa npm uninstall -g oxe-cc
1864
- --config-dir <caminho> com exatamente uma flag IDE acima (não combina com --ide-local)
2084
+ --config-dir <caminho> com exatamente uma flag IDE acima (não combina com --ide-local nem com --copilot)
1865
2085
  --dry-run
1866
2086
  --dir <pasta> raiz do projeto (padrão: diretório atual)
1867
2087
 
@@ -1880,6 +2100,15 @@ ${green}dashboard${reset} (interface web local para revisão e aprovação do pl
1880
2100
  --dump-context imprime JSON consolidado e sai
1881
2101
  --dir <pasta> raiz do projeto (padrão: diretório atual)
1882
2102
 
2103
+ ${green}context${reset} (Context Engine V2: seleção, compressão e inspeção determinística)
2104
+ build [--workflow <slug>] gera pack(s) em .oxe/context/packs/
2105
+ inspect [--workflow <slug>] lê um pack existente ou resolve sob demanda
2106
+ --workflow <slug> workflow alvo (omissão: build=todos; inspect=dashboard)
2107
+ --tier <minimal|standard|full> tier de contexto (padrão: standard)
2108
+ --session <sessions/sNNN-slug> força sessão específica
2109
+ --json saída estruturada em JSON
2110
+ --dir <pasta> raiz do projeto (padrão: diretório atual)
2111
+
1883
2112
  ${green}runtime${reset} (controle operacional explícito do ACTIVE-RUN)
1884
2113
  status mostra o run ativo resolvido para a sessão atual
1885
2114
  start cria um novo run com tracing inicial
@@ -1936,13 +2165,14 @@ ${green}azure${reset} (provider Azure nativo via Azure CLI no Windows)
1936
2165
 
1937
2166
  ${green}Opções da instalação:${reset}
1938
2167
  --cursor Copia comandos e regras para ~/.cursor (padrão com --all)
1939
- --copilot Mescla instruções + prompts em ~/.copilot (global) ou .github/ (com --ide-local)
2168
+ --copilot Instala GitHub Copilot VS Code no workspace: .github/copilot-instructions.md + .github/prompts/
2169
+ --copilot-vscode Alias explícito de --copilot
1940
2170
  --copilot-cli Skills em ~/.copilot/skills (/oxe, /oxe-scan, …) + cópia legado em ~/.claude/commands e ~/.copilot/commands
1941
2171
  (subconjunto de --all-agents)
1942
2172
  --all-agents Cursor+Copilot + CLIs + OpenCode, Gemini (TOML), Codex, Windsurf, Antigravity
1943
2173
  --opencode / --gemini / --codex / --windsurf / --antigravity só esse agente (sem os outros)
1944
2174
  --ide-global Instalar integrações IDE nas pastas do utilizador (~/.cursor, …) — predefinido
1945
- --ide-local Instalar integrações IDE neste repositório (.cursor, .github, .copilot, …)
2175
+ --ide-local Instalar integrações IDE locais quando suportado (.cursor, .claude, .copilot CLI, …); Copilot VS Code continua em .github/
1946
2176
  --vscode Também copia .vscode/settings.json (chat.promptFiles)
1947
2177
  --all, -a Cursor + Copilot (padrão se não passar --cursor nem --copilot)
1948
2178
  --no-commands Não copia commands/oxe
@@ -1955,7 +2185,7 @@ ${green}Opções da instalação:${reset}
1955
2185
  --no-global-cli, -l Não pergunta pelo CLI global (recomendado em CI)
1956
2186
  --force, -f Sobrescreve arquivos existentes
1957
2187
  --dry-run Lista ações sem gravar
1958
- --config-dir, -c <pasta> Só com exatamente um de --cursor, --copilot, --copilot-cli (não use com --all-agents)
2188
+ --config-dir, -c <pasta> Só com exatamente um de --cursor ou --copilot-cli (não use com --copilot nem --all-agents)
1959
2189
  --no-install-config Ignora o bloco install em .oxe/config.json (só integração/layout vindos das flags ou do menu)
1960
2190
  --dir <pasta> Pasta de destino (padrão: diretório atual)
1961
2191
  -h, --help
@@ -2032,15 +2262,22 @@ function runInstall(opts) {
2032
2262
  }
2033
2263
  const ideAny = anyIdeIntegration(opts);
2034
2264
  if (ideAny) {
2035
- const scopeHint = opts.ideLocal
2036
- ? `${c ? dim : ''}pastas neste repositório (.cursor, .github, …)${c ? reset : ''}`
2037
- : `${c ? dim : ''}pastas do utilizador (${c ? yellow : ''}~/.cursor${c ? dim : ''}, ${c ? yellow : ''}~/.copilot${c ? dim : ''}, …)${c ? reset : ''}`;
2265
+ const scopeParts = [];
2266
+ if (opts.cursor) {
2267
+ scopeParts.push(opts.ideLocal ? '.cursor no repositório' : '~/.cursor');
2268
+ }
2269
+ if (opts.copilot) {
2270
+ scopeParts.push('.github/ no repositório (Copilot VS Code)');
2271
+ }
2272
+ if (opts.copilotCli || opts.allAgents) {
2273
+ scopeParts.push(opts.ideLocal ? '.copilot/.claude no repositório (CLI)' : '~/.copilot + ~/.claude (CLI)');
2274
+ }
2038
2275
  const extra = opts.allAgents
2039
2276
  ? `${c ? dim : ''} + OpenCode, Gemini, Codex, Windsurf, Antigravity${c ? reset : ''}`
2040
2277
  : anyGranularAgent(opts)
2041
2278
  ? `${c ? dim : ''} + agentes selecionados${c ? reset : ''}`
2042
2279
  : '';
2043
- console.log(` ${c ? dim : ''}Integrações IDE:${c ? reset : ''} ${scopeHint}${extra}`);
2280
+ console.log(` ${c ? dim : ''}Integrações IDE:${c ? reset : ''} ${scopeParts.join('; ')}${extra}`);
2044
2281
  }
2045
2282
 
2046
2283
  const copyOpts = { dryRun: opts.dryRun, force: opts.force };
@@ -2143,6 +2380,9 @@ function runInstall(opts) {
2143
2380
  if (fs.existsSync(prompts)) {
2144
2381
  copyDir(prompts, copilotPromptsDirPath(opts), copyOpts, idePathRewrite);
2145
2382
  }
2383
+ if (!opts.dryRun) {
2384
+ writeCopilotVsCodeManifest(opts, { layout: fullLayout ? 'classic' : 'nested' });
2385
+ }
2146
2386
  }
2147
2387
 
2148
2388
  if (opts.vscode && fullLayout) {
@@ -2176,6 +2416,10 @@ function runInstall(opts) {
2176
2416
  if (!opts.noInitOxe) bootstrapOxe(target, { dryRun: opts.dryRun, force: opts.force });
2177
2417
  else ensureGitignoreIgnoresOxeDir(target, { dryRun: opts.dryRun });
2178
2418
 
2419
+ if (!opts.dryRun) {
2420
+ writeRuntimeSemanticsManifest(opts, { layout: fullLayout ? 'classic' : 'nested' });
2421
+ }
2422
+
2179
2423
  if (!opts.dryRun && (opts.cursor || opts.copilot || opts.copilotCli || opts.allAgents || anyGranularAgent(opts))) {
2180
2424
  const nextFiles = {};
2181
2425
  const addTracked = (root, nameFilter) => {
@@ -2212,7 +2456,9 @@ function runInstall(opts) {
2212
2456
  }
2213
2457
  }
2214
2458
  addTracked(copilotPromptsDirPath(opts), (n) => n.startsWith('oxe-'));
2459
+ trackFile(copilotWorkspaceManifestPath(opts));
2215
2460
  }
2461
+ trackFile(runtimeSemanticsManifestPath(opts));
2216
2462
  if (opts.copilotCli || opts.allAgents) {
2217
2463
  addTracked(path.join(installClaudeBase(opts), 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
2218
2464
  addTracked(path.join(cpCliHome, 'commands'), (n) => n.startsWith('oxe-') && n.endsWith('.md'));
@@ -2278,10 +2524,23 @@ function runInstall(opts) {
2278
2524
  }
2279
2525
 
2280
2526
  printSummaryAndNextSteps(c, buildInstallSummary(opts, fullLayout));
2527
+ if (opts.copilot) {
2528
+ const copilotReport = oxeHealth.copilotIntegrationReport(target);
2529
+ if (copilotReport.legacy && copilotReport.legacy.detected) {
2530
+ console.log(
2531
+ ` ${yellow}Nota:${reset} legado do Copilot VS Code detectado em ${c ? cyan : ''}${displayPathForUser(
2532
+ copilotReport.legacy.root
2533
+ )}${reset}. O OXE agora usa ${c ? cyan : ''}.github/${reset} no workspace para a IDE.`
2534
+ );
2535
+ console.log(
2536
+ ` ${c ? dim : ''}Limpeza opcional:${c ? reset : ''} ${c ? cyan : ''}npx oxe-cc uninstall --copilot-legacy-clean --dir "${target}"${reset}`
2537
+ );
2538
+ }
2539
+ }
2281
2540
  console.log(` ${c ? green : ''}✓${c ? reset : ''} Instalação concluída com sucesso.\n`);
2282
2541
  }
2283
2542
 
2284
- /** @typedef {{ help: boolean, dryRun: boolean, cursor: boolean, copilot: boolean, copilotCli: boolean, allAgents: boolean, globalCli: boolean, ideLocal: boolean, ideExplicit: boolean, noProject: boolean, dir: string, explicitConfigDir: string | null, parseError: boolean, unknownFlag: string, conflictFlags: string }} UninstallOpts */
2543
+ /** @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 */
2285
2544
 
2286
2545
  /**
2287
2546
  * @param {UninstallOpts} u
@@ -2319,16 +2578,20 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2319
2578
  if (u.copilot) {
2320
2579
  const inst = path.join(proj, '.github', 'copilot-instructions.md');
2321
2580
  stripOxeFromCopilotInstructions(inst, u);
2581
+ if (fs.existsSync(inst)) track(inst);
2322
2582
  const pr = path.join(proj, '.github', 'prompts');
2323
2583
  if (fs.existsSync(pr)) {
2324
2584
  for (const name of fs.readdirSync(pr)) {
2325
- if (name.startsWith('oxe-')) {
2585
+ if (/^oxe-.*\.prompt\.md$/i.test(name)) {
2326
2586
  const p = path.join(pr, name);
2327
2587
  unlinkQuiet(p, u);
2328
2588
  track(p);
2329
2589
  }
2330
2590
  }
2331
2591
  }
2592
+ const manifest = path.join(proj, '.oxe', 'install', 'copilot-vscode.json');
2593
+ unlinkQuiet(manifest, u);
2594
+ track(manifest);
2332
2595
  }
2333
2596
 
2334
2597
  if (u.copilotCli || u.allAgents) {
@@ -2375,6 +2638,12 @@ function uninstallLocalIdeFromProject(u, removedPaths) {
2375
2638
  console.log(`${dim}agents${reset} (dry-run) limparia marcadores oxe-cc em pastas locais do projeto (OpenCode, Gemini, …)`);
2376
2639
  }
2377
2640
  }
2641
+
2642
+ if (u.cursor || u.copilot || u.copilotCli || u.allAgents) {
2643
+ const runtimeManifest = path.join(proj, '.oxe', 'install', 'runtime-semantics.json');
2644
+ unlinkQuiet(runtimeManifest, u);
2645
+ track(runtimeManifest);
2646
+ }
2378
2647
  }
2379
2648
 
2380
2649
  /**
@@ -2394,6 +2663,7 @@ function parseUninstallArgs(argv) {
2394
2663
  ideLocal: false,
2395
2664
  ideExplicit: false,
2396
2665
  noProject: false,
2666
+ copilotLegacyClean: false,
2397
2667
  dir: process.cwd(),
2398
2668
  explicitConfigDir: null,
2399
2669
  parseError: false,
@@ -2410,12 +2680,14 @@ function parseUninstallArgs(argv) {
2410
2680
  } else if (a === '--cursor') {
2411
2681
  out.cursor = true;
2412
2682
  out.ideExplicit = true;
2413
- } else if (a === '--copilot') {
2683
+ } else if (a === '--copilot' || a === '--copilot-vscode') {
2414
2684
  out.copilot = true;
2415
2685
  out.ideExplicit = true;
2416
2686
  } else if (a === '--copilot-cli') {
2417
2687
  out.copilotCli = true;
2418
2688
  out.ideExplicit = true;
2689
+ } else if (a === '--copilot-legacy-clean') {
2690
+ out.copilotLegacyClean = true;
2419
2691
  } else if (a === '--all-agents') {
2420
2692
  out.allAgents = true;
2421
2693
  out.copilotCli = true;
@@ -2433,16 +2705,21 @@ function parseUninstallArgs(argv) {
2433
2705
  }
2434
2706
  }
2435
2707
  if (rest.length) out.dir = rest[0];
2436
- if (!out.ideExplicit) {
2708
+ if (!out.ideExplicit && !out.copilotLegacyClean) {
2437
2709
  out.cursor = true;
2438
2710
  out.copilot = true;
2439
2711
  out.copilotCli = true;
2712
+ } else if (out.copilotLegacyClean && !out.ideExplicit && !out.noProject) {
2713
+ out.noProject = true;
2440
2714
  }
2441
2715
  if (!out.conflictFlags && out.explicitConfigDir) {
2442
2716
  if (out.ideLocal) {
2443
2717
  out.conflictFlags = '--config-dir não combina com --ide-local';
2444
2718
  } else if (out.allAgents) {
2445
2719
  out.conflictFlags = '--config-dir não combina com --all-agents';
2720
+ } else if (out.copilot && !out.cursor && !out.copilotCli) {
2721
+ out.conflictFlags =
2722
+ '--config-dir não combina com --copilot porque o GitHub Copilot no VS Code usa .github/ no workspace';
2446
2723
  } else {
2447
2724
  const n = [out.cursor, out.copilot, out.copilotCli].filter(Boolean).length;
2448
2725
  if (n !== 1) {
@@ -2474,6 +2751,25 @@ function stripOxeFromCopilotInstructions(destPath, opts) {
2474
2751
  fs.writeFileSync(destPath, merged ? `${merged}\n` : '\n', 'utf8');
2475
2752
  }
2476
2753
 
2754
+ /**
2755
+ * @param {InstallOpts} ideOpts
2756
+ * @param {UninstallOpts} opts
2757
+ * @param {string[]} removedPaths
2758
+ */
2759
+ function cleanupLegacyCopilotVsCode(ideOpts, opts, removedPaths) {
2760
+ const inst = copilotLegacyInstructionsPath(ideOpts);
2761
+ stripOxeFromCopilotInstructions(inst, opts);
2762
+ if (fs.existsSync(inst)) removedPaths.push(inst);
2763
+ const pr = copilotLegacyPromptDir(ideOpts);
2764
+ if (!fs.existsSync(pr)) return;
2765
+ for (const name of fs.readdirSync(pr)) {
2766
+ if (!/^oxe-.*\.prompt\.md$/i.test(name)) continue;
2767
+ const promptPath = path.join(pr, name);
2768
+ unlinkQuiet(promptPath, opts);
2769
+ removedPaths.push(promptPath);
2770
+ }
2771
+ }
2772
+
2477
2773
  /**
2478
2774
  * @param {string} filePath
2479
2775
  * @param {{ dryRun: boolean }} opts
@@ -2574,19 +2870,26 @@ function runUninstall(u) {
2574
2870
  }
2575
2871
 
2576
2872
  if (u.copilot) {
2577
- const root = copilotUserDir(ideOpts);
2578
- const inst = path.join(root, 'copilot-instructions.md');
2873
+ const inst = path.join(u.dir, '.github', 'copilot-instructions.md');
2579
2874
  stripOxeFromCopilotInstructions(inst, u);
2580
- const pr = path.join(root, 'prompts');
2875
+ if (fs.existsSync(inst)) removedPaths.push(inst);
2876
+ const pr = path.join(u.dir, '.github', 'prompts');
2581
2877
  if (fs.existsSync(pr)) {
2582
2878
  for (const name of fs.readdirSync(pr)) {
2583
- if (name.startsWith('oxe-')) {
2879
+ if (/^oxe-.*\.prompt\.md$/i.test(name)) {
2584
2880
  const p = path.join(pr, name);
2585
2881
  unlinkQuiet(p, u);
2586
2882
  removedPaths.push(p);
2587
2883
  }
2588
2884
  }
2589
2885
  }
2886
+ const manifest = copilotWorkspaceManifestPath(ideOpts);
2887
+ unlinkQuiet(manifest, u);
2888
+ removedPaths.push(manifest);
2889
+ }
2890
+
2891
+ if (u.copilotLegacyClean) {
2892
+ cleanupLegacyCopilotVsCode(ideOpts, u, removedPaths);
2590
2893
  }
2591
2894
 
2592
2895
  if (u.copilotCli) {
@@ -2661,12 +2964,12 @@ function runUninstall(u) {
2661
2964
  }
2662
2965
  }
2663
2966
 
2664
- if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli)) {
2967
+ if (!u.dryRun && (u.cursor || u.copilot || u.copilotCli || u.copilotLegacyClean)) {
2665
2968
  const prev = oxeManifest.loadFileManifest(home);
2666
2969
  const next = { ...prev };
2667
2970
  for (const p of removedPaths) delete next[p];
2668
2971
  if (u.copilot) {
2669
- const instPath = path.join(copilotUserDir(ideOpts), 'copilot-instructions.md');
2972
+ const instPath = path.join(u.dir, '.github', 'copilot-instructions.md');
2670
2973
  if (fs.existsSync(instPath)) {
2671
2974
  try {
2672
2975
  next[instPath] = oxeManifest.sha256File(instPath);
@@ -2931,6 +3234,10 @@ function parseCapabilitiesArgs(argv) {
2931
3234
  * @typedef {{ help: boolean, dir: string, port: number, noOpen: boolean, readOnly: boolean, dumpContext: boolean, activeSession: string|null, parseError: boolean, unknownFlag: string }} DashboardOpts
2932
3235
  */
2933
3236
 
3237
+ /**
3238
+ * @typedef {{ help: boolean, dir: string, action: 'build'|'inspect', workflow: string, tier: 'minimal'|'standard'|'full', activeSession: string|null, json: boolean, parseError: boolean, unknownFlag: string }} ContextOpts
3239
+ */
3240
+
2934
3241
  /**
2935
3242
  * @typedef {{ help: boolean, dir: string, action: string, activeSession: string|null, wave: number|null, task: string, mode: string, reason: string, parseError: boolean, unknownFlag: string }} RuntimeOpts
2936
3243
  */
@@ -3008,6 +3315,49 @@ function parseDashboardArgs(argv) {
3008
3315
  return out;
3009
3316
  }
3010
3317
 
3318
+ /**
3319
+ * @param {string[]} argv
3320
+ * @returns {ContextOpts}
3321
+ */
3322
+ function parseContextArgs(argv) {
3323
+ /** @type {ContextOpts} */
3324
+ const out = {
3325
+ help: false,
3326
+ dir: process.cwd(),
3327
+ action: 'build',
3328
+ workflow: '',
3329
+ tier: 'standard',
3330
+ activeSession: null,
3331
+ json: false,
3332
+ parseError: false,
3333
+ unknownFlag: '',
3334
+ };
3335
+ const positionals = [];
3336
+ for (let i = 0; i < argv.length; i += 1) {
3337
+ const a = argv[i];
3338
+ if (a === '-h' || a === '--help') out.help = true;
3339
+ else if (a === '--dir' && argv[i + 1]) out.dir = path.resolve(argv[++i]);
3340
+ else if (a === '--workflow' && argv[i + 1]) out.workflow = String(argv[++i]);
3341
+ else if (a === '--tier' && argv[i + 1]) {
3342
+ const tier = String(argv[++i]);
3343
+ out.tier = ['minimal', 'standard', 'full'].includes(tier) ? /** @type {'minimal'|'standard'|'full'} */ (tier) : 'standard';
3344
+ }
3345
+ else if (a === '--session' && argv[i + 1]) out.activeSession = String(argv[++i]).replace(/\\/g, '/');
3346
+ else if (a === '--json') out.json = true;
3347
+ else if (!a.startsWith('-')) positionals.push(a);
3348
+ else {
3349
+ out.parseError = true;
3350
+ out.unknownFlag = a;
3351
+ break;
3352
+ }
3353
+ }
3354
+ if (positionals[0] === 'build' || positionals[0] === 'inspect') {
3355
+ out.action = /** @type {'build'|'inspect'} */ (positionals[0]);
3356
+ }
3357
+ if (!out.workflow && positionals[1]) out.workflow = String(positionals[1]);
3358
+ return out;
3359
+ }
3360
+
3011
3361
  /**
3012
3362
  * @param {string[]} argv
3013
3363
  * @returns {RuntimeOpts}
@@ -3023,6 +3373,9 @@ function parseRuntimeArgs(argv) {
3023
3373
  task: '',
3024
3374
  mode: '',
3025
3375
  reason: '',
3376
+ runId: '',
3377
+ fromEventId: '',
3378
+ writeReport: false,
3026
3379
  parseError: false,
3027
3380
  unknownFlag: '',
3028
3381
  };
@@ -3036,6 +3389,9 @@ function parseRuntimeArgs(argv) {
3036
3389
  else if (a === '--task' && argv[i + 1]) out.task = String(argv[++i]);
3037
3390
  else if (a === '--mode' && argv[i + 1]) out.mode = String(argv[++i]);
3038
3391
  else if (a === '--reason' && argv[i + 1]) out.reason = String(argv[++i]);
3392
+ else if (a === '--run' && argv[i + 1]) out.runId = String(argv[++i]);
3393
+ else if (a === '--from' && argv[i + 1]) out.fromEventId = String(argv[++i]);
3394
+ else if (a === '--write') out.writeReport = true;
3039
3395
  else if (!a.startsWith('-')) positionals.push(a);
3040
3396
  else {
3041
3397
  out.parseError = true;
@@ -3138,6 +3494,114 @@ function parseAzureArgs(argv) {
3138
3494
  return out;
3139
3495
  }
3140
3496
 
3497
+ /**
3498
+ * @param {ContextOpts} opts
3499
+ */
3500
+ function runContext(opts) {
3501
+ const c = useAnsiColors();
3502
+ printSection('OXE ▸ context');
3503
+ if (!fs.existsSync(opts.dir)) {
3504
+ console.error(`${yellow}Diretório não encontrado: ${opts.dir}${reset}`);
3505
+ process.exit(1);
3506
+ }
3507
+ const statePath = oxeHealth.oxePaths(opts.dir).state;
3508
+ const stateText = fs.existsSync(statePath) ? fs.readFileSync(statePath, 'utf8') : '';
3509
+ const activeSession = opts.activeSession || oxeHealth.parseActiveSession(stateText) || null;
3510
+ const workflow = opts.workflow || '';
3511
+
3512
+ if (opts.action === 'inspect') {
3513
+ const selectedWorkflow = workflow || 'dashboard';
3514
+ let pack;
3515
+ try {
3516
+ pack = oxeContext.inspectContextPack(opts.dir, {
3517
+ workflow: selectedWorkflow,
3518
+ tier: opts.tier,
3519
+ activeSession,
3520
+ });
3521
+ } catch (err) {
3522
+ console.error(`${red}Erro ao inspecionar context pack para "${selectedWorkflow}": ${err instanceof Error ? err.message : String(err)}${reset}`);
3523
+ process.exit(1);
3524
+ }
3525
+ if (opts.json) {
3526
+ console.log(JSON.stringify(pack, null, 2));
3527
+ return;
3528
+ }
3529
+ console.log(` ${c ? green : ''}Projeto:${c ? reset : ''} ${c ? cyan : ''}${opts.dir}${c ? reset : ''}`);
3530
+ console.log(` ${c ? green : ''}Sessão:${c ? reset : ''} ${c ? cyan : ''}${activeSession || 'modo legado'}${c ? reset : ''}`);
3531
+ console.log(` ${c ? green : ''}Workflow:${c ? reset : ''} ${selectedWorkflow}`);
3532
+ console.log(` ${c ? green : ''}Tier:${c ? reset : ''} ${pack.context_tier}`);
3533
+ console.log(` ${c ? green : ''}Quality:${c ? reset : ''} ${pack.context_quality.score} (${pack.context_quality.status})`);
3534
+ if (pack.context_quality.score < 30 || pack.context_quality.status === 'critical') {
3535
+ console.log(` ${yellow}AVISO${reset} Contexto crítico — artefatos obrigatórios ausentes. Use \`oxe-cc context build --workflow ${selectedWorkflow}\` para regenerar.`);
3536
+ }
3537
+ console.log(` ${c ? green : ''}Freshness:${c ? reset : ''} ${pack.freshness.reason}${pack.freshness.pack_age_hours != null ? ` · ${pack.freshness.pack_age_hours}h` : ''}`);
3538
+ console.log(` ${c ? green : ''}Pack:${c ? reset : ''} ${pack.path || '—'}`);
3539
+ console.log(` ${c ? green : ''}Artefatos:${c ? reset : ''} ${(pack.read_order || []).join(', ') || '—'}`);
3540
+ if ((pack.gaps || []).length) {
3541
+ for (const gap of pack.gaps) {
3542
+ console.log(` ${gap.severity === 'critical' ? red : yellow}${gap.severity.toUpperCase()}${reset} ${gap.alias}: ${gap.reason}`);
3543
+ }
3544
+ }
3545
+ if ((pack.conflicts || []).length) {
3546
+ for (const conflict of pack.conflicts) {
3547
+ console.log(` ${yellow}CONFLICT${reset} ${conflict.alias}: ${conflict.reason}`);
3548
+ }
3549
+ }
3550
+ return;
3551
+ }
3552
+
3553
+ if (workflow) {
3554
+ bootstrapOxe(opts.dir, { dryRun: false, force: false });
3555
+ let pack;
3556
+ try {
3557
+ pack = oxeContext.buildContextPack(opts.dir, {
3558
+ workflow,
3559
+ tier: opts.tier,
3560
+ activeSession,
3561
+ write: true,
3562
+ });
3563
+ } catch (err) {
3564
+ console.error(`${red}Erro ao gerar context pack para "${workflow}": ${err instanceof Error ? err.message : String(err)}${reset}`);
3565
+ process.exit(1);
3566
+ }
3567
+ if (opts.json) {
3568
+ console.log(JSON.stringify(pack, null, 2));
3569
+ return;
3570
+ }
3571
+ console.log(` ${c ? green : ''}✓${c ? reset : ''} Context pack gerado para ${workflow}.`);
3572
+ console.log(` ${c ? green : ''}Quality:${c ? reset : ''} ${pack.context_quality.score} (${pack.context_quality.status})`);
3573
+ if (pack.context_quality.score < 30 || pack.context_quality.status === 'critical') {
3574
+ console.log(` ${yellow}AVISO${reset} Contexto crítico — artefatos obrigatórios ausentes. Verifique o STATE e os artefatos do workflow.`);
3575
+ }
3576
+ console.log(` ${c ? green : ''}Pack:${c ? reset : ''} ${oxeContext.resolvePackFile(opts.dir, workflow, activeSession)}`);
3577
+ return;
3578
+ }
3579
+
3580
+ bootstrapOxe(opts.dir, { dryRun: false, force: false });
3581
+ let packs;
3582
+ try {
3583
+ packs = oxeContext.buildAllContextPacks(opts.dir, {
3584
+ tier: opts.tier,
3585
+ activeSession,
3586
+ write: true,
3587
+ });
3588
+ } catch (err) {
3589
+ console.error(`${red}Erro ao gerar context packs: ${err instanceof Error ? err.message : String(err)}${reset}`);
3590
+ process.exit(1);
3591
+ }
3592
+ if (opts.json) {
3593
+ console.log(JSON.stringify(packs, null, 2));
3594
+ return;
3595
+ }
3596
+ console.log(` ${c ? green : ''}Projeto:${c ? reset : ''} ${c ? cyan : ''}${opts.dir}${c ? reset : ''}`);
3597
+ console.log(` ${c ? green : ''}Sessão:${c ? reset : ''} ${c ? cyan : ''}${activeSession || 'modo legado'}${c ? reset : ''}`);
3598
+ console.log(` ${c ? green : ''}Packs:${c ? reset : ''} ${packs.length}`);
3599
+ for (const pack of packs) {
3600
+ const qualityFlag = (pack.context_quality.score < 30 || pack.context_quality.status === 'critical') ? ` ${yellow}[CRÍTICO]${reset}` : '';
3601
+ console.log(` ${c ? dim : ''}•${c ? reset : ''} ${pack.workflow} · ${pack.context_quality.score} (${pack.context_quality.status}) · ${pack.freshness.reason}${qualityFlag}`);
3602
+ }
3603
+ }
3604
+
3141
3605
  /**
3142
3606
  * @param {DashboardOpts} opts
3143
3607
  */
@@ -3210,6 +3674,42 @@ function runRuntime(opts) {
3210
3674
  return;
3211
3675
  }
3212
3676
 
3677
+ if (opts.action === 'replay' && !opts.task) {
3678
+ const report = oxeOperational.replayEvents(opts.dir, activeSession, {
3679
+ runId: opts.runId || undefined,
3680
+ fromEventId: opts.fromEventId || undefined,
3681
+ waveId: opts.wave != null ? opts.wave : undefined,
3682
+ writeReport: opts.writeReport || false,
3683
+ });
3684
+ console.log(` ${c ? green : ''}Total eventos:${c ? reset : ''} ${report.totalEvents}`);
3685
+ console.log(` ${c ? green : ''}Duração:${c ? reset : ''} ${report.duration_ms != null ? `${(report.duration_ms / 1000).toFixed(1)}s` : '—'}`);
3686
+ console.log(` ${c ? green : ''}Ondas:${c ? reset : ''} ${report.waveIds.join(', ') || '—'}`);
3687
+ console.log(` ${c ? green : ''}Tarefas:${c ? reset : ''} ${report.taskSequence.join(', ') || '—'}`);
3688
+ console.log(` ${c ? green : ''}Falhas:${c ? reset : ''} ${report.failureEvents.length}`);
3689
+ if (report.totalEvents > 0) {
3690
+ console.log('');
3691
+ const dim = c ? '\x1b[2m' : '';
3692
+ console.log(` ${dim}# Tipo Wave Task Delta Timestamp${c ? reset : ''}`);
3693
+ for (let i = 0; i < Math.min(report.events.length, 50); i++) {
3694
+ const e = report.events[i];
3695
+ const delta = i > 0 ? `+${(e._delta_ms / 1000).toFixed(1)}s` : '—';
3696
+ const num = String(i + 1).padStart(3);
3697
+ const type = String(e.type).padEnd(22).slice(0, 22);
3698
+ const wave = String(e.wave_id || '—').padEnd(7).slice(0, 7);
3699
+ const task = String(e.task_id || '—').padEnd(7).slice(0, 7);
3700
+ const deltaStr = delta.padStart(10);
3701
+ console.log(` ${num} ${type} ${wave} ${task} ${deltaStr} ${e.timestamp}`);
3702
+ }
3703
+ if (report.events.length > 50) {
3704
+ console.log(` … (${report.events.length - 50} mais)`);
3705
+ }
3706
+ }
3707
+ if (report._reportPath) {
3708
+ console.log(`\n ${c ? green : ''}Relatório:${c ? reset : ''} ${report._reportPath}`);
3709
+ }
3710
+ return;
3711
+ }
3712
+
3213
3713
  try {
3214
3714
  const next = oxeOperational.applyRuntimeAction(opts.dir, activeSession, {
3215
3715
  action: opts.action,
@@ -3714,12 +4214,14 @@ async function main() {
3714
4214
  argv[0] === 'doctor' ||
3715
4215
  argv[0] === 'status' ||
3716
4216
  argv[0] === 'init-oxe' ||
4217
+ argv[0] === 'context' ||
3717
4218
  argv[0] === 'dashboard' ||
3718
4219
  argv[0] === 'runtime' ||
3719
4220
  argv[0] === 'azure' ||
3720
4221
  argv[0] === 'uninstall' ||
3721
4222
  argv[0] === 'update' ||
3722
4223
  argv[0] === 'capabilities' ||
4224
+ argv[0] === 'plugins' ||
3723
4225
  argv[0] === 'plan' ||
3724
4226
  argv[0] === 'verify' ||
3725
4227
  argv[0] === 'install'
@@ -3828,6 +4330,24 @@ async function main() {
3828
4330
  return;
3829
4331
  }
3830
4332
 
4333
+ if (command === 'context') {
4334
+ const contextOpts = parseContextArgs(argv);
4335
+ if (contextOpts.help) {
4336
+ printBanner();
4337
+ usage();
4338
+ process.exit(0);
4339
+ }
4340
+ if (contextOpts.parseError) {
4341
+ printBanner();
4342
+ console.error(`${red}Opção desconhecida:${reset} ${contextOpts.unknownFlag}`);
4343
+ usage();
4344
+ process.exit(1);
4345
+ }
4346
+ printBanner();
4347
+ runContext(contextOpts);
4348
+ return;
4349
+ }
4350
+
3831
4351
  if (command === 'runtime') {
3832
4352
  const runtime = parseRuntimeArgs(argv);
3833
4353
  if (runtime.help) {
@@ -3850,6 +4370,55 @@ async function main() {
3850
4370
  return;
3851
4371
  }
3852
4372
 
4373
+ if (command === 'plugins') {
4374
+ printBanner();
4375
+ // Parse --dir flag
4376
+ let pluginsDir = process.cwd();
4377
+ const pluginsArgv = argv.slice();
4378
+ for (let i = 0; i < pluginsArgv.length; i++) {
4379
+ if (pluginsArgv[i] === '--dir' && pluginsArgv[i + 1]) {
4380
+ pluginsDir = path.resolve(pluginsArgv[++i]);
4381
+ pluginsArgv.splice(i - 1, 2);
4382
+ i -= 2;
4383
+ }
4384
+ }
4385
+ const c = useAnsiColors();
4386
+ const subCmd = pluginsArgv[0] || 'list';
4387
+ const pluginTarget = pluginsArgv[1] || '';
4388
+
4389
+ if (subCmd === 'list') {
4390
+ const result = oxePlugins.loadPlugins(pluginsDir);
4391
+ console.log(`\n ${c ? green : ''}Plugins carregados:${c ? reset : ''} ${result.plugins.length}`);
4392
+ for (const p of result.plugins) {
4393
+ console.log(` • ${p.name}${p.version ? ` (${p.version})` : ''} — hooks: ${Object.keys(p.hooks).join(', ')}`);
4394
+ }
4395
+ if (result.errors.length) {
4396
+ console.log(`\n ${c ? yellow : ''}Erros:${c ? reset : ''}`);
4397
+ for (const e of result.errors) {
4398
+ console.log(` ✗ ${e.file}: ${e.error}`);
4399
+ }
4400
+ }
4401
+ } else if (subCmd === 'install' && pluginTarget) {
4402
+ const src = pluginTarget.startsWith('npm:') ? pluginTarget.slice(4) : pluginTarget;
4403
+ const ver = pluginsArgv[2] || '';
4404
+ console.log(` Instalando plugin: ${src}${ver ? `@${ver}` : ''}...`);
4405
+ const result = oxePlugins.installNpmPlugin(pluginsDir, src, ver || undefined);
4406
+ if (result.ok) {
4407
+ console.log(` ${c ? green : ''}✓${c ? reset : ''} Instalado em: ${result.path}`);
4408
+ console.log(` ${c ? dim : ''}Adicione ao .oxe/config.json: "plugins": [{ "source": "npm:${src}" }]${c ? reset : ''}`);
4409
+ } else {
4410
+ console.error(` ${c ? red : ''}✗ Falha:${c ? reset : ''} ${result.error}`);
4411
+ process.exit(1);
4412
+ }
4413
+ } else if (subCmd === 'remove' && pluginTarget) {
4414
+ console.log(` ${c ? yellow : ''}Remove "${pluginTarget}" de .oxe/config.json → plugins[] manualmente.${c ? reset : ''}`);
4415
+ console.log(` ${c ? dim : ''}Arquivos npm: rm -rf .oxe/plugins/_npm/node_modules/${pluginTarget}${c ? reset : ''}`);
4416
+ } else {
4417
+ console.log(` ${c ? yellow : ''}Uso: oxe-cc plugins list | install <npm:pkg|path> | remove <id>${c ? reset : ''}`);
4418
+ }
4419
+ return;
4420
+ }
4421
+
3853
4422
  if (command === 'azure') {
3854
4423
  const azure = parseAzureArgs(argv);
3855
4424
  if (azure.help) {
@@ -3957,7 +4526,7 @@ async function main() {
3957
4526
  printSummaryAndNextSteps(c0, {
3958
4527
  bullets: opts.dryRun
3959
4528
  ? ['[simulação] Seriam criados ou atualizados .oxe/STATE.md, .oxe/config.json, .oxe/codebase/, .oxe/ACTIVE-RUN.json e .oxe/OXE-EVENTS.ndjson']
3960
- : ['.oxe/STATE.md, .oxe/config.json, .oxe/codebase/, .oxe/ACTIVE-RUN.json e .oxe/OXE-EVENTS.ndjson (criados ou atualizados conforme --force)'],
4529
+ : ['.oxe/STATE.md, .oxe/config.json, .oxe/codebase/, .oxe/context/, .oxe/ACTIVE-RUN.json e .oxe/OXE-EVENTS.ndjson (criados ou atualizados conforme --force)'],
3961
4530
  nextSteps: [
3962
4531
  { desc: 'Validar o projeto:', cmd: 'npx oxe-cc doctor' },
3963
4532
  { desc: 'Instalar integrações IDE/CLI (se ainda não fez):', cmd: 'npx oxe-cc@latest' },