oxe-cc 1.8.0 → 1.8.3

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 (44) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +1 -1
  3. package/bin/lib/oxe-manifest.cjs +20 -13
  4. package/bin/lib/oxe-operational.cjs +96 -10
  5. package/bin/lib/oxe-project-health.cjs +77 -18
  6. package/bin/lib/oxe-rationality.cjs +9 -7
  7. package/bin/oxe-cc.js +202 -39
  8. package/lib/runtime/compiler/graph-compiler.js +1 -1
  9. package/lib/runtime/executor/action-tool-map.js +4 -0
  10. package/lib/runtime/executor/built-in-tools.js +27 -0
  11. package/lib/runtime/executor/llm-task-executor.d.ts +4 -1
  12. package/lib/runtime/executor/llm-task-executor.js +41 -5
  13. package/lib/runtime/executor/node-prompt-builder.d.ts +4 -1
  14. package/lib/runtime/executor/node-prompt-builder.js +13 -2
  15. package/lib/runtime/models/failure.d.ts +1 -1
  16. package/lib/runtime/scheduler/scheduler.d.ts +5 -1
  17. package/lib/runtime/scheduler/scheduler.js +82 -14
  18. package/lib/runtime/verification/verification-compiler.js +7 -5
  19. package/lib/sdk/index.cjs +48 -44
  20. package/oxe/templates/PLAN.template.md +23 -9
  21. package/oxe/templates/SPEC.template.md +55 -22
  22. package/oxe/workflows/plan.md +18 -6
  23. package/oxe/workflows/spec.md +31 -9
  24. package/package.json +103 -100
  25. package/packages/runtime/package.json +18 -18
  26. package/packages/runtime/src/compiler/graph-compiler.ts +1 -1
  27. package/packages/runtime/src/evidence/evidence-store.ts +2 -2
  28. package/packages/runtime/src/executor/action-tool-map.ts +4 -0
  29. package/packages/runtime/src/executor/built-in-tools.ts +29 -0
  30. package/packages/runtime/src/executor/llm-task-executor.ts +46 -4
  31. package/packages/runtime/src/executor/node-prompt-builder.ts +18 -1
  32. package/packages/runtime/src/models/failure.ts +2 -0
  33. package/packages/runtime/src/scheduler/scheduler.ts +93 -15
  34. package/packages/runtime/src/verification/verification-compiler.ts +7 -5
  35. package/vscode-extension/package.json +185 -185
  36. package/vscode-extension/oxe-agents-0.9.1.vsix +0 -0
  37. package/vscode-extension/oxe-agents-0.9.2.vsix +0 -0
  38. package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
  39. package/vscode-extension/oxe-agents-1.4.0.vsix +0 -0
  40. package/vscode-extension/oxe-agents-1.5.0.vsix +0 -0
  41. package/vscode-extension/oxe-agents-1.5.1.vsix +0 -0
  42. package/vscode-extension/oxe-agents-1.6.0.vsix +0 -0
  43. package/vscode-extension/oxe-agents-1.7.0.vsix +0 -0
  44. package/vscode-extension/oxe-agents-1.8.0.vsix +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,69 @@ Todas as versões seguem [Semantic Versioning](https://semver.org/). As mudança
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.8.3] — 2026-05-04
8
+
9
+ ### Release readiness e higiene de publicação
10
+
11
+ Esta release consolida a linha `1.8.3` para publicação no npm com foco em consistência de versão, alinhamento documental e pacote distribuído mais limpo.
12
+
13
+ #### Publicação
14
+
15
+ - alinhamento da versão `1.8.3` entre manifesto raiz, runtime, extensão VS Code, README e changelog
16
+ - fechamento do gate oficial `doctor --release` para a linha atual
17
+ - preparação do pacote npm para sair sem drift entre versão publicada e documentação principal
18
+
19
+ #### Higiene do pacote
20
+
21
+ - exclusão dos arquivos `.vsix` históricos da extensão VS Code do tarball npm
22
+ - manutenção apenas do código-fonte da extensão dentro do pacote, evitando distribuir binários legados desnecessários
23
+
24
+ ## [1.8.2] — 2026-04-30
25
+
26
+ ### Fluxo inicial mais coerente e geração de `spec`/`plan` mais forte
27
+
28
+ Esta release fecha a linha de robustez do ciclo `install -> status/doctor -> /oxe -> spec -> plan -> execute -> verify` sem abrir nova superfície pública. O foco foi remover ruído operacional em projetos novos e aumentar a densidade executável dos artefatos que o OXE induz.
29
+
30
+ #### Fluxo operacional
31
+
32
+ - `install`, `status` e `doctor` passam a convergir em `/oxe` como próximo passo canônico para projetos recém-inicializados
33
+ - `doctor` e `status` deixam de tratar `IMPLEMENTATION-PACK`, `REFERENCE-ANCHORS` e `FIXTURE-PACK` como blocker primário antes de existir `PLAN.md`
34
+ - o relatório racional agora marca o estado sem plano como `não aplicável ainda`, sem contaminar o próximo passo
35
+ - instalações e desinstalações locais por runtime continuam simétricas, com inferência de artefatos locais preservada
36
+
37
+ #### Indução mais forte de SPEC e PLAN
38
+
39
+ - `SPEC.template.md` passou a exigir outcome observável, público-alvo, restrições técnicas, setup externo, conteúdo/fluxos obrigatórios e contratos esperados para o plano
40
+ - `PLAN.template.md` ganhou contrato operacional da solução, densidade operacional mínima, `symbols alvo`, `estado/fluxo coberto` e `fixture/anchor obrigatório` por tarefa
41
+ - `oxe/workflows/spec.md` agora força extração explícita de blocos de interface, conteúdo mínimo, interações, responsividade e acessibilidade em demandas de produto/app/UI
42
+ - `oxe/workflows/plan.md` agora endurece o gate de confiança `>90%` para tarefas mutáveis vagas e exige fechamento mais forte de interface, conteúdo, estado persistido, anchors e fixtures em apps/UI estáticos
43
+
44
+ #### Testes
45
+
46
+ - novo teste cobrindo o estado racional não bloqueante antes da existência de `PLAN.md`
47
+ - suíte focada de CLI/health atualizada para manter o comportamento novo estável
48
+
49
+ ## [1.8.1] — 2026-04-30
50
+
51
+ ### Hotfix — Gaps implementados no fonte TypeScript (não em arquivos compilados)
52
+
53
+ A v1.8.0 aplicou as 5 correções críticas diretamente nos arquivos `.js` compilados (`lib/runtime/`), que são sobrescritos a cada `npm run build:runtime`. Esta release porta todas as correções para o fonte TypeScript em `packages/runtime/src/`, tornando-as permanentes.
54
+
55
+ #### Correções portadas para TypeScript
56
+
57
+ - **`models/failure.ts`**: `FailureClass` agora inclui `'verify'` e `'llm'` como classes canônicas
58
+ - **`scheduler/scheduler.ts`**: `TaskResult` com campo opcional `completed_by`; `TaskExecutor.execute()` aceita `options?: { previousError? }`; `verifyNode()` importa e chama `verifyRun` da fonte TS; `executeNode()` repassa `options`; `requestGateForNode()` com warning quando manager ausente
59
+ - **`executor/built-in-tools.ts`**: `finishTask` handler + registro em `BUILT_IN_TOOLS`
60
+ - **`executor/action-tool-map.ts`**: `finish_task` injetado universalmente em `selectToolsForActions()`
61
+ - **`executor/node-prompt-builder.ts`**: parâmetro `options`, seção de retry context, instrução `finish_task`
62
+ - **`executor/llm-task-executor.ts`**: detecção de `finish_task`, `completed_by` no retorno, `turn_limit_exhausted` retorna `success: false`
63
+
64
+ #### Testes
65
+ - 542 testes passando (era 542 na v1.8.0, nenhuma regressão)
66
+ - 36 testes de gaps (gap1–gap5) todos passando contra o código compilado
67
+
68
+ ---
69
+
7
70
  ## [1.8.0] — 2026-04-29
8
71
 
9
72
  ### Autonomous Execution — 5 Critical Gaps Resolved
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![npm](https://img.shields.io/npm/v/oxe-cc.svg?style=flat-square)](https://www.npmjs.com/package/oxe-cc)
8
8
  [![license](https://img.shields.io/npm/l/oxe-cc.svg?style=flat-square)](LICENSE)
9
9
 
10
- **Versão:** `1.8.0` · [package.json](package.json)
10
+ **Versão:** `1.8.3` · [package.json](package.json)
11
11
 
12
12
  **Framework OXE — Orchestrated eXperience Engineering**
13
13
 
@@ -51,19 +51,26 @@ function writeFileManifest(home, files, version) {
51
51
  * Before overwriting with --force, backup files that diverged from last manifest.
52
52
  * @param {string} home
53
53
  * @param {Record<string, string>} prevManifest
54
- * @param {{ dryRun: boolean, force: boolean }} opts
55
- * @param {{ yellow: string, cyan: string, dim: string, reset: string }} colors
56
- * @returns {string[]} modified paths
57
- */
58
- function backupModifiedFromManifest(home, prevManifest, opts, colors) {
59
- const { yellow, cyan, dim, reset } = colors;
60
- if (!opts.force || opts.dryRun) return [];
61
- const modified = [];
62
- for (const [absPath, oldHash] of Object.entries(prevManifest)) {
63
- if (!fs.existsSync(absPath)) continue;
64
- let now;
65
- try {
66
- now = sha256File(absPath);
54
+ * @param {{ dryRun: boolean, force: boolean }} opts
55
+ * @param {{ yellow: string, cyan: string, dim: string, reset: string }} colors
56
+ * @param {{ scopeRoots?: string[] }} [scope]
57
+ * @returns {string[]} modified paths
58
+ */
59
+ function backupModifiedFromManifest(home, prevManifest, opts, colors, scope = {}) {
60
+ const { yellow, cyan, dim, reset } = colors;
61
+ if (!opts.force || opts.dryRun) return [];
62
+ const normalizedRoots = Array.isArray(scope.scopeRoots)
63
+ ? scope.scopeRoots.map((root) => path.resolve(root))
64
+ : [];
65
+ const modified = [];
66
+ for (const [absPath, oldHash] of Object.entries(prevManifest)) {
67
+ if (normalizedRoots.length > 0 && !normalizedRoots.some((root) => absPath === root || absPath.startsWith(`${root}${path.sep}`))) {
68
+ continue;
69
+ }
70
+ if (!fs.existsSync(absPath)) continue;
71
+ let now;
72
+ try {
73
+ now = sha256File(absPath);
67
74
  } catch {
68
75
  continue;
69
76
  }
@@ -456,6 +456,61 @@ function reduceCanonicalRunState(projectRoot, activeSession, options = {}) {
456
456
  return serializeCanonicalState(reduceCanonicalRunStateLive(projectRoot, activeSession, options));
457
457
  }
458
458
 
459
+ /**
460
+ * Static-analysis lints for common pitfalls detectable before execution.
461
+ * Returns hint strings to be appended to validationErrors (shown at compile time).
462
+ */
463
+ function lintPlanForCommonPitfalls(parsedPlan, parsedSpec, projectRoot, rawSpecText = '') {
464
+ const hints = [];
465
+ const specText = (parsedSpec && parsedSpec.objective ? parsedSpec.objective : '') +
466
+ JSON.stringify(parsedSpec && parsedSpec.criteria ? parsedSpec.criteria : []) +
467
+ (rawSpecText || '');
468
+ const planTasks = parsedPlan && Array.isArray(parsedPlan.tasks) ? parsedPlan.tasks : [];
469
+
470
+ // ── Lint 1: HTML/JS SPA sem restrição de file:// ──────────────────────────
471
+ // Detects: spec mentions HTML/SPA + no files restriction, but no verify command
472
+ // checks for fetch() absence. Warns to add a fetch-detection verify.
473
+ const isHtmlApp = /html|spa|browser|page|frontend|estático|static|aplicação web|web app|web page|interface web|\.html/i.test(specText);
474
+ if (isHtmlApp) {
475
+ const hasFetchGuard = planTasks.some(t =>
476
+ t.verifyCommand && /fetch|XMLHttpRequest|file:\/\//i.test(t.verifyCommand)
477
+ );
478
+ const specMentionsServer = /servidor|server|http-server|localhost|npx serve|vite|webpack/i.test(specText);
479
+ const specMentionsFileProtocol = /file:\/\/|sem servidor|without server|no.server/i.test(specText);
480
+ if (!hasFetchGuard && !specMentionsServer && !specMentionsFileProtocol) {
481
+ hints.push(
482
+ 'HINT(html-fetch): SPEC não declara se o app precisa de servidor HTTP. ' +
483
+ 'Se abrir em file://, adicione à SPEC: "sem servidor HTTP" e um verify que detecte fetch(): ' +
484
+ '`node -e "if(require(\'fs\').readFileSync(\'app.js\',\'utf8\').includes(\'fetch(\'))throw new Error(\'fetch not allowed in file://\')"`'
485
+ );
486
+ }
487
+ }
488
+
489
+ // ── Lint 2: Verify commands que só verificam existência de função, não comportamento ──
490
+ const existenceOnlyVerify = planTasks.filter(t =>
491
+ t.verifyCommand &&
492
+ /s\.includes\(/.test(t.verifyCommand) &&
493
+ !/existsSync|readFileSync.*utf8|require\(/.test(t.verifyCommand)
494
+ );
495
+ if (existenceOnlyVerify.length > 2) {
496
+ hints.push(
497
+ `HINT(verify-depth): ${existenceOnlyVerify.length} tarefa(s) verificam apenas presença de string no código ` +
498
+ `(s.includes). Considere adicionar verificações de comportamento: executar o código, não só inspecioná-lo.`
499
+ );
500
+ }
501
+
502
+ // ── Lint 3: Tarefas sem verify command (T-level) ──────────────────────────
503
+ const noVerify = planTasks.filter(t => !t.verifyCommand && !t.done);
504
+ if (noVerify.length > 0) {
505
+ hints.push(
506
+ `HINT(no-verify): ${noVerify.length} tarefa(s) sem Comando de verificação: ${noVerify.map(t => t.id).join(', ')}. ` +
507
+ `Tarefas sem verify não serão testadas inline pelo scheduler.`
508
+ );
509
+ }
510
+
511
+ return hints;
512
+ }
513
+
459
514
  function compileExecutionGraphFromArtifacts(projectRoot, activeSession, options = {}) {
460
515
  const runtime = loadRuntimeModule();
461
516
  const parsers = loadSdkParsers();
@@ -468,12 +523,17 @@ function compileExecutionGraphFromArtifacts(projectRoot, activeSession, options
468
523
  const artifactPaths = resolveRuntimeArtifactPaths(projectRoot, activeSession);
469
524
  const specText = readTextIfExists(artifactPaths.spec);
470
525
  const planText = readTextIfExists(artifactPaths.plan);
471
- if (!specText) throw new Error(`SPEC.md ausente em ${artifactPaths.spec}`);
472
- if (!planText) throw new Error(`PLAN.md ausente em ${artifactPaths.plan}`);
526
+ if (!specText) throw new Error(`SPEC.md ausente em ${artifactPaths.spec}\n Crie .oxe/SPEC.md com /oxe-spec no seu agente, ou use o template em oxe/templates/SPEC.template.md`);
527
+ if (!planText) throw new Error(`PLAN.md ausente em ${artifactPaths.plan}\n Crie .oxe/PLAN.md com /oxe-plan no seu agente (requer SPEC.md), ou use o template em oxe/templates/PLAN.template.md`);
473
528
  const parsedSpec = parsers.parseSpec(specText);
474
529
  const parsedPlan = parsers.parsePlan(planText);
475
530
  const graph = runtime.compile(parsedPlan, parsedSpec, options.compilerOptions || {});
476
531
  const validationErrors = typeof runtime.validateGraph === 'function' ? runtime.validateGraph(graph) : [];
532
+
533
+ // Static-analysis lints: detect common patterns that cause runtime failures
534
+ const lintHints = lintPlanForCommonPitfalls(parsedPlan, parsedSpec, projectRoot, specText);
535
+ if (lintHints.length) validationErrors.push(...lintHints);
536
+
477
537
  const compiledGraph = runtime.toSerializable(graph);
478
538
  const current = options.runState || readRunState(projectRoot, activeSession) || {};
479
539
  const runId = current.run_id || makeRunId();
@@ -669,6 +729,20 @@ async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
669
729
  const parsers = loadSdkParsers();
670
730
  if (!parsers) throw new Error('SDK parsers não disponíveis.');
671
731
 
732
+ // Auto-wire LlmTaskExecutor if providerConfig is supplied
733
+ let executor = options.executor || null;
734
+ if (!executor && options.providerConfig) {
735
+ if (typeof runtime.LlmTaskExecutor !== 'function') throw new Error('Runtime não exporta LlmTaskExecutor.');
736
+ executor = new runtime.LlmTaskExecutor(options.providerConfig, null, options.onProgress || null);
737
+ }
738
+ // Auto-wire InplaceWorkspaceManager as default
739
+ let workspaceManager = options.workspaceManager || null;
740
+ if (!workspaceManager) {
741
+ if (typeof runtime.InplaceWorkspaceManager === 'function') {
742
+ workspaceManager = new runtime.InplaceWorkspaceManager(projectRoot);
743
+ }
744
+ }
745
+
672
746
  // Resolve compiled graph from run state or compile on demand
673
747
  let current = options.runState || readRunState(projectRoot, activeSession);
674
748
  if (!current || !current.compiled_graph) {
@@ -693,11 +767,14 @@ async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
693
767
  // Build ctx with GateManager (Gap 1)
694
768
  const ctx = createExecutionContext(projectRoot, activeSession, {
695
769
  runId: current.run_id,
696
- executor: options.executor || null,
697
- workspaceManager: options.workspaceManager || null,
770
+ executor,
771
+ workspaceManager,
698
772
  pluginRegistry: options.pluginRegistry || buildRuntimePluginRegistry(projectRoot),
699
773
  schedulerOptions: options.schedulerOptions || {},
700
- onEvent: (event) => appendEvent(projectRoot, activeSession, event),
774
+ onEvent: (event) => {
775
+ appendEvent(projectRoot, activeSession, event);
776
+ options.onProgress?.(event);
777
+ },
701
778
  });
702
779
 
703
780
  // Gap 5: multi-agent path if plan-agents.json exists
@@ -906,6 +983,11 @@ function buildRecoveryConsistency(projectRoot, activeSession, runState, journal,
906
983
  const runDir = runState && runState.run_id ? path.join(projectRoot, '.oxe', 'runs', runState.run_id) : null;
907
984
  const allEvents = readEvents(projectRoot, activeSession);
908
985
  const runEvents = runState && runState.run_id ? allEvents.filter((event) => event.run_id === runState.run_id) : [];
986
+ // Detect if execution has ever started (at least one attempt recorded)
987
+ const attemptCount = runState && runState.canonical_state && runState.canonical_state.summary
988
+ ? (runState.canonical_state.summary.attempt_count || 0)
989
+ : 0;
990
+ const executionStarted = attemptCount > 0;
909
991
  const issues = [];
910
992
  if (!activeRunRef || activeRunRef.run_id !== (runState && runState.run_id)) {
911
993
  issues.push('ACTIVE-RUN.json não referencia o mesmo run persistido em .oxe/runs/.');
@@ -913,10 +995,12 @@ function buildRecoveryConsistency(projectRoot, activeSession, runState, journal,
913
995
  if (!runFile || !fs.existsSync(runFile)) {
914
996
  issues.push('Arquivo canónico da run ausente em .oxe/runs/<run>.json.');
915
997
  }
916
- if (!journal) {
998
+ // Journal is only created after execution starts — skip this check pre-execution
999
+ if (!journal && executionStarted) {
917
1000
  issues.push('Journal ausente para recover/replay.');
918
1001
  }
919
- if (runEvents.length === 0) {
1002
+ // Events for this run only exist after execution — skip pre-execution
1003
+ if (runEvents.length === 0 && executionStarted) {
920
1004
  issues.push('Nenhum evento NDJSON encontrado para a run ativa.');
921
1005
  }
922
1006
  if (!runState || !runState.canonical_state) {
@@ -1146,7 +1230,7 @@ function projectRuntimeArtifacts(projectRoot, activeSession, options = {}) {
1146
1230
  const paths = resolveRuntimeArtifactPaths(projectRoot, activeSession);
1147
1231
  const op = operationalPaths(projectRoot, activeSession);
1148
1232
  const projectionRefs = {
1149
- plan_ref: path.relative(projectRoot, paths.plan).replace(/\\/g, '/'),
1233
+ plan_ref: path.relative(projectRoot, paths.plan.replace(/PLAN\.md$/, 'PLAN-STATUS.md')).replace(/\\/g, '/'),
1150
1234
  verify_ref: path.relative(projectRoot, paths.verify).replace(/\\/g, '/'),
1151
1235
  state_ref: path.relative(projectRoot, paths.state).replace(/\\/g, '/'),
1152
1236
  run_summary_ref: path.relative(projectRoot, path.join(op.executionRoot, 'RUN-SUMMARY.md')).replace(/\\/g, '/'),
@@ -1156,10 +1240,12 @@ function projectRuntimeArtifacts(projectRoot, activeSession, options = {}) {
1156
1240
  generated_at: new Date().toISOString(),
1157
1241
  };
1158
1242
  if (options.write !== false) {
1159
- ensureDirForFile(paths.plan);
1243
+ // Write plan projection to PLAN-STATUS.md — never overwrite the source PLAN.md
1244
+ const planStatusPath = paths.plan.replace(/PLAN\.md$/, 'PLAN-STATUS.md');
1245
+ ensureDirForFile(planStatusPath);
1160
1246
  ensureDirForFile(paths.verify);
1161
1247
  ensureDirForFile(paths.state);
1162
- fs.writeFileSync(paths.plan, projections.plan + '\n', 'utf8');
1248
+ fs.writeFileSync(planStatusPath, projections.plan + '\n', 'utf8');
1163
1249
  fs.writeFileSync(paths.verify, projections.verify + '\n', 'utf8');
1164
1250
  fs.writeFileSync(paths.state, projections.state + '\n', 'utf8');
1165
1251
  fs.writeFileSync(path.join(op.executionRoot, 'RUN-SUMMARY.md'), projections.runSummary + '\n', 'utf8');
@@ -839,6 +839,18 @@ function codexIntegrationPaths() {
839
839
  };
840
840
  }
841
841
 
842
+ /**
843
+ * @param {string} target
844
+ */
845
+ function codexWorkspacePaths(target) {
846
+ const root = path.resolve(target);
847
+ return {
848
+ root,
849
+ promptsDir: path.join(root, '.codex', 'prompts'),
850
+ skillsRoot: path.join(root, '.agents', 'skills'),
851
+ };
852
+ }
853
+
842
854
  /**
843
855
  * @param {string} filePath
844
856
  */
@@ -1108,11 +1120,21 @@ function summarizeRecoveryState(target, activeSession, activeRun, verificationAr
1108
1120
  };
1109
1121
  }
1110
1122
 
1111
- function summarizeEnterpriseRuntime(target, activeRun, activeSession, config) {
1112
- const pendingGates = readExecutionGates(target, activeSession);
1113
- const auditSummary = summarizeAuditTrail(target, activeRun && activeRun.run_id ? activeRun.run_id : null);
1114
- const runtimeMode = operational.buildRuntimeModeStatus(activeRun);
1115
- const providerCatalog = operational.buildRuntimeProviderCatalog(target);
1123
+ function summarizeEnterpriseRuntime(target, activeRun, activeSession, config) {
1124
+ const pendingGates = readExecutionGates(target, activeSession);
1125
+ const auditSummary = summarizeAuditTrail(target, activeRun && activeRun.run_id ? activeRun.run_id : null);
1126
+ const runtimeModeBase = operational.buildRuntimeModeStatus(activeRun);
1127
+ const providerCatalog = operational.buildRuntimeProviderCatalog(target);
1128
+ const enterprisePackageAvailable = Boolean(providerCatalog && providerCatalog.available);
1129
+ const runtimeMode = enterprisePackageAvailable && runtimeModeBase.enterprise_available === false
1130
+ ? {
1131
+ ...runtimeModeBase,
1132
+ enterprise_available: true,
1133
+ reason: runtimeModeBase.reason === 'Nenhum ACTIVE-RUN encontrado para o escopo atual.'
1134
+ ? 'Runtime enterprise disponível no pacote, mas ainda sem ACTIVE-RUN canónico neste escopo.'
1135
+ : 'Runtime enterprise disponível no pacote; a run atual ainda não materializou artefatos canónicos.',
1136
+ }
1137
+ : runtimeModeBase;
1116
1138
  if (!activeRun || !activeRun.run_id) {
1117
1139
  return {
1118
1140
  runtimeMode,
@@ -1484,9 +1506,16 @@ function copilotIntegrationReport(target) {
1484
1506
  * @param {string} target
1485
1507
  */
1486
1508
  function codexIntegrationReport(target) {
1487
- const paths = codexIntegrationPaths();
1488
- const promptFiles = listOxeCodexPromptFiles(paths.promptsDir);
1489
- const skillDirs = listOxeSkillDirs(paths.skillsRoot);
1509
+ const workspace = codexWorkspacePaths(target);
1510
+ const globalPaths = codexIntegrationPaths();
1511
+ const workspacePromptFiles = listOxeCodexPromptFiles(workspace.promptsDir);
1512
+ const workspaceSkillDirs = listOxeSkillDirs(workspace.skillsRoot);
1513
+ const globalPromptFiles = listOxeCodexPromptFiles(globalPaths.promptsDir);
1514
+ const globalSkillDirs = listOxeSkillDirs(globalPaths.skillsRoot);
1515
+ const workspaceDetected = workspacePromptFiles.length > 0 || workspaceSkillDirs.length > 0;
1516
+ const globalDetected = globalPromptFiles.length > 0 || globalSkillDirs.length > 0;
1517
+ const promptFiles = workspaceDetected ? workspacePromptFiles : globalPromptFiles;
1518
+ const skillDirs = workspaceDetected ? workspaceSkillDirs : globalSkillDirs;
1490
1519
  const promptNames = promptFiles.map((filePath) => path.basename(filePath));
1491
1520
  const skillNames = skillDirs.map((dirPath) => path.basename(dirPath));
1492
1521
  const promptPathWarnings = [];
@@ -1496,11 +1525,15 @@ function codexIntegrationReport(target) {
1496
1525
 
1497
1526
  /** @type {string[]} */
1498
1527
  const warnings = [];
1499
- const detected = promptFiles.length > 0 || skillDirs.length > 0;
1528
+ const detected = workspaceDetected || globalDetected;
1529
+ const promptSource = workspaceDetected ? 'workspace' : globalDetected ? 'global' : 'missing';
1500
1530
  const commandsReady = promptNames.includes('oxe.md');
1501
1531
  const skillsReady = skillNames.includes('oxe');
1532
+ if (!workspaceDetected && globalDetected) {
1533
+ warnings.push('Codex OXE foi encontrado apenas no ambiente global do usuário; este projeto não tem integração local instalada.');
1534
+ }
1502
1535
  if (detected && promptFiles.length === 0) {
1503
- warnings.push('Codex tem skills OXE instaladas, mas ~/.codex/prompts não contém prompts OXE; a barra / não listará /oxe.');
1536
+ warnings.push('Codex tem skills OXE instaladas, mas o diretório de prompts ativo não contém prompts OXE; a barra / não listará /oxe.');
1504
1537
  }
1505
1538
  if (promptFiles.length > 0 && !commandsReady) {
1506
1539
  warnings.push('Codex prompts OXE existem, mas o entrypoint principal oxe.md está ausente.');
@@ -1525,11 +1558,28 @@ function codexIntegrationReport(target) {
1525
1558
  detected,
1526
1559
  commandsReady,
1527
1560
  skillsReady,
1528
- root: paths.root,
1529
- promptsDir: paths.promptsDir,
1530
- skillsRoot: paths.skillsRoot,
1561
+ promptSource,
1562
+ root: workspaceDetected ? workspace.root : globalPaths.root,
1563
+ promptsDir: workspaceDetected ? workspace.promptsDir : globalPaths.promptsDir,
1564
+ skillsRoot: workspaceDetected ? workspace.skillsRoot : globalPaths.skillsRoot,
1531
1565
  promptFiles,
1532
1566
  skillDirs,
1567
+ workspace: {
1568
+ root: workspace.root,
1569
+ promptsDir: workspace.promptsDir,
1570
+ skillsRoot: workspace.skillsRoot,
1571
+ promptFiles: workspacePromptFiles,
1572
+ skillDirs: workspaceSkillDirs,
1573
+ detected: workspaceDetected,
1574
+ },
1575
+ global: {
1576
+ root: globalPaths.root,
1577
+ promptsDir: globalPaths.promptsDir,
1578
+ skillsRoot: globalPaths.skillsRoot,
1579
+ promptFiles: globalPromptFiles,
1580
+ skillDirs: globalSkillDirs,
1581
+ detected: globalDetected,
1582
+ },
1533
1583
  warnings,
1534
1584
  };
1535
1585
  }
@@ -2026,12 +2076,21 @@ function suggestNextStep(target, cfg = {}) {
2026
2076
  };
2027
2077
  }
2028
2078
 
2079
+ if (!mapsComplete && !has(p.quick) && !has(p.spec) && !has(p.plan)) {
2080
+ return {
2081
+ step: 'oxe',
2082
+ cursorCmd: '/oxe',
2083
+ reason: 'Projeto recém-inicializado e sem SPEC/PLAN — use a entrada universal para começar o fluxo e escolher o primeiro scan.',
2084
+ artifacts: ['.oxe/STATE.md', '.oxe/codebase/'],
2085
+ };
2086
+ }
2087
+
2029
2088
  if (!mapsComplete && !has(p.quick)) {
2030
- return {
2031
- step: 'scan',
2032
- cursorCmd: '/oxe-scan',
2033
- reason: 'Mapas do codebase incompletos e sem QUICK.md — atualize o contexto com scan',
2034
- artifacts: ['.oxe/codebase/'],
2089
+ return {
2090
+ step: 'scan',
2091
+ cursorCmd: '/oxe-scan',
2092
+ reason: 'Mapas do codebase incompletos e sem QUICK.md — atualize o contexto com scan',
2093
+ artifacts: ['.oxe/codebase/'],
2035
2094
  };
2036
2095
  }
2037
2096
 
@@ -350,14 +350,16 @@ function buildExecutionRationality(paths = {}) {
350
350
  const implementationPack = summarizeImplementationPack(paths.implementationPackJson || null, planTasks);
351
351
  const referenceAnchors = summarizeReferenceAnchors(paths.referenceAnchors || null, externalRefs);
352
352
  const fixturePack = summarizeFixturePack(paths.fixturePackJson || null, planTasks, implementationPack);
353
- const criticalExecutionGaps = Array.from(
354
- new Set([
355
- ...implementationPack.criticalGaps,
356
- ...referenceAnchors.criticalGaps,
357
- ...fixturePack.criticalGaps,
358
- ])
359
- );
360
353
  const applicable = Boolean(paths.plan && fs.existsSync(paths.plan));
354
+ const criticalExecutionGaps = applicable
355
+ ? Array.from(
356
+ new Set([
357
+ ...implementationPack.criticalGaps,
358
+ ...referenceAnchors.criticalGaps,
359
+ ...fixturePack.criticalGaps,
360
+ ])
361
+ )
362
+ : [];
361
363
  return {
362
364
  applicable,
363
365
  planTaskCount: planTasks.length,