oxe-cc 1.9.1 → 1.10.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 (39) hide show
  1. package/.cursor/commands/oxe-dashboard.md +2 -2
  2. package/.cursor/commands/oxe-execute.md +2 -2
  3. package/.cursor/commands/oxe-plan.md +2 -2
  4. package/.cursor/commands/oxe-quick.md +2 -2
  5. package/.cursor/commands/oxe-spec.md +3 -3
  6. package/.github/prompts/oxe-dashboard.prompt.md +2 -2
  7. package/.github/prompts/oxe-execute.prompt.md +2 -2
  8. package/.github/prompts/oxe-plan.prompt.md +2 -2
  9. package/.github/prompts/oxe-quick.prompt.md +2 -2
  10. package/.github/prompts/oxe-spec.prompt.md +3 -3
  11. package/CHANGELOG.md +14 -0
  12. package/README.md +18 -15
  13. package/bin/lib/oxe-context-engine.cjs +2 -0
  14. package/bin/lib/oxe-operational.cjs +23 -7
  15. package/bin/lib/oxe-project-health.cjs +41 -9
  16. package/bin/lib/oxe-rationality.cjs +146 -1
  17. package/bin/lib/oxe-release.cjs +31 -2
  18. package/bin/oxe-cc.js +38 -24
  19. package/commands/oxe/dashboard.md +2 -2
  20. package/commands/oxe/execute.md +2 -2
  21. package/commands/oxe/plan.md +2 -2
  22. package/commands/oxe/quick.md +2 -2
  23. package/commands/oxe/spec.md +3 -3
  24. package/docs/RELEASE-READINESS.md +2 -0
  25. package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +9 -0
  26. package/lib/runtime/scheduler/multi-agent-coordinator.js +60 -9
  27. package/oxe/templates/REFERENCE-ANCHORS.template.md +12 -5
  28. package/oxe/templates/SPEC.template.md +10 -0
  29. package/oxe/templates/VISUAL-INPUTS.template.json +27 -0
  30. package/oxe/templates/VISUAL-INPUTS.template.md +36 -0
  31. package/oxe/workflows/execute.md +3 -0
  32. package/oxe/workflows/plan.md +13 -9
  33. package/oxe/workflows/references/workflow-runtime-contracts.json +44 -29
  34. package/oxe/workflows/spec.md +19 -8
  35. package/oxe/workflows/ui-spec.md +3 -2
  36. package/package.json +1 -1
  37. package/packages/runtime/package.json +1 -1
  38. package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +67 -9
  39. package/vscode-extension/package.json +1 -1
@@ -223,9 +223,14 @@ function summarizeReferenceAnchors(filePath, externalRefs) {
223
223
  sourceType: attrs.source_type || null,
224
224
  path: attrs.path || null,
225
225
  sourceRef: attrs.source_ref || null,
226
+ visualRef: attrs.visual_ref || null,
227
+ extractionConfidence: attrs.extraction_confidence || null,
228
+ reproducibility: attrs.reproducibility || null,
226
229
  relevance: (((match[2].match(/<relevance>([\s\S]*?)<\/relevance>/i) || [null, ''])[1]) || '').trim(),
227
230
  action: (((match[2].match(/<action>([\s\S]*?)<\/action>/i) || [null, ''])[1]) || '').trim(),
228
231
  summary: (((match[2].match(/<summary>([\s\S]*?)<\/summary>/i) || [null, ''])[1]) || '').trim(),
232
+ limitations: (((match[2].match(/<limitations>([\s\S]*?)<\/limitations>/i) || [null, ''])[1]) || '').trim(),
233
+ derivedRequirements: (((match[2].match(/<derived_requirements>([\s\S]*?)<\/derived_requirements>/i) || [null, ''])[1]) || '').trim(),
229
234
  });
230
235
  }
231
236
  if (status === 'not_applicable' && externalRefs.length) {
@@ -267,6 +272,136 @@ function summarizeReferenceAnchors(filePath, externalRefs) {
267
272
  };
268
273
  }
269
274
 
275
+ function specRequiresVisualInput(specPath) {
276
+ const raw = readTextIfExists(specPath);
277
+ if (!raw) return false;
278
+ const text = raw.toLowerCase();
279
+ if (/visualinputreadiness\s*:\s*(ready|partial|blocked)/i.test(raw)) return true;
280
+ if (/<visual_inputs?\b/i.test(raw)) return true;
281
+ if (/##+\s*entradas visuais e interpreta[çc][ãa]o/i.test(raw) && !/not_applicable|não aplicável|nao aplicavel/i.test(raw)) {
282
+ return true;
283
+ }
284
+ return /\b(visual-?inputs?|visual attachment|screenshot|mockup|imagem anexada|anexo visual)\b/i.test(text);
285
+ }
286
+
287
+ function normalizeInspectionStatus(value) {
288
+ const status = String(value || '').trim().toLowerCase();
289
+ if (!status) return 'unavailable';
290
+ return status;
291
+ }
292
+
293
+ function summarizeVisualInputs(paths = {}) {
294
+ const specPath = paths.spec || null;
295
+ const jsonPath = paths.visualInputsJson || null;
296
+ const mdPath = paths.visualInputsMd || null;
297
+ const specRequires = specRequiresVisualInput(specPath);
298
+ const json = readJsonIfExists(jsonPath);
299
+ const mdExists = Boolean(readTextIfExists(mdPath));
300
+ const exists = Boolean(json.ok || mdExists);
301
+ const applicable = specRequires || exists;
302
+ /** @type {string[]} */
303
+ const criticalGaps = [];
304
+ if (!applicable) {
305
+ return {
306
+ applicable: false,
307
+ ready: true,
308
+ visualInputReadiness: 'not_applicable',
309
+ path: jsonPath,
310
+ markdownPath: mdPath,
311
+ exists,
312
+ inputCount: 0,
313
+ criticalInputCount: 0,
314
+ blockedCount: 0,
315
+ partialCount: 0,
316
+ inputs: [],
317
+ criticalGaps: [],
318
+ };
319
+ }
320
+ if (!json.ok) {
321
+ criticalGaps.push(`VISUAL-INPUTS.json inválido ou ausente${json.error ? `: ${json.error}` : ''}`);
322
+ return {
323
+ applicable: true,
324
+ ready: false,
325
+ visualInputReadiness: 'blocked',
326
+ path: jsonPath,
327
+ markdownPath: mdPath,
328
+ exists,
329
+ inputCount: 0,
330
+ criticalInputCount: 0,
331
+ blockedCount: 1,
332
+ partialCount: 0,
333
+ inputs: [],
334
+ criticalGaps,
335
+ };
336
+ }
337
+ const data = json.data && typeof json.data === 'object' ? json.data : {};
338
+ const inputs = Array.isArray(data.inputs) ? data.inputs : [];
339
+ const topReady = data.ready !== false;
340
+ let criticalInputCount = 0;
341
+ let blockedCount = 0;
342
+ let partialCount = 0;
343
+ for (const input of inputs) {
344
+ const id = String(input && (input.id || input.source_ref || input.sourceRef) || '?');
345
+ const critical = Boolean(input && input.critical === true);
346
+ const status = normalizeInspectionStatus(input && input.inspection_status);
347
+ const confidence = Number(input && input.confidence);
348
+ const summary = String(input && input.visual_summary || '').trim();
349
+ const derived = Array.isArray(input && input.derived_requirements)
350
+ ? input.derived_requirements
351
+ : [];
352
+ if (critical) criticalInputCount += 1;
353
+ if (status === 'partial') partialCount += 1;
354
+ if (critical && status !== 'inspected') {
355
+ blockedCount += 1;
356
+ criticalGaps.push(`VISUAL-INPUTS.json entrada crítica ${id} com inspection_status=${status}`);
357
+ }
358
+ if (critical && !summary) {
359
+ blockedCount += 1;
360
+ criticalGaps.push(`VISUAL-INPUTS.json entrada crítica ${id} sem visual_summary`);
361
+ }
362
+ if (critical && !derived.length) {
363
+ blockedCount += 1;
364
+ criticalGaps.push(`VISUAL-INPUTS.json entrada crítica ${id} sem derived_requirements`);
365
+ }
366
+ if (critical && Number.isFinite(confidence) && confidence < 0.75) {
367
+ partialCount += 1;
368
+ criticalGaps.push(`VISUAL-INPUTS.json entrada crítica ${id} com confidence abaixo de 0.75`);
369
+ }
370
+ }
371
+ if (data.visualInputReadiness === 'blocked') {
372
+ blockedCount += 1;
373
+ criticalGaps.push('VISUAL-INPUTS.json declara visualInputReadiness=blocked');
374
+ }
375
+ if (Array.isArray(data.critical_gaps) && data.critical_gaps.length) {
376
+ blockedCount += data.critical_gaps.length;
377
+ criticalGaps.push(...data.critical_gaps.map((gap) => `VISUAL-INPUTS.json: ${String(gap)}`));
378
+ }
379
+ if (!topReady) {
380
+ blockedCount += 1;
381
+ criticalGaps.push('VISUAL-INPUTS.json com ready=false');
382
+ }
383
+ const uniqueGaps = Array.from(new Set(criticalGaps));
384
+ const visualInputReadiness = uniqueGaps.length
385
+ ? 'blocked'
386
+ : partialCount > 0 || data.visualInputReadiness === 'partial'
387
+ ? 'partial'
388
+ : 'ready';
389
+ return {
390
+ applicable: true,
391
+ ready: visualInputReadiness !== 'blocked',
392
+ visualInputReadiness,
393
+ path: jsonPath,
394
+ markdownPath: mdPath,
395
+ exists,
396
+ inputCount: inputs.length,
397
+ criticalInputCount,
398
+ blockedCount,
399
+ partialCount,
400
+ inputs,
401
+ criticalGaps: uniqueGaps,
402
+ };
403
+ }
404
+
270
405
  function summarizeFixturePack(filePath, planTasks, implementationPack) {
271
406
  const parsed = readJsonIfExists(filePath);
272
407
  /** @type {string[]} */
@@ -350,6 +485,11 @@ function buildExecutionRationality(paths = {}) {
350
485
  const implementationPack = summarizeImplementationPack(paths.implementationPackJson || null, planTasks);
351
486
  const referenceAnchors = summarizeReferenceAnchors(paths.referenceAnchors || null, externalRefs);
352
487
  const fixturePack = summarizeFixturePack(paths.fixturePackJson || null, planTasks, implementationPack);
488
+ const visualInputs = summarizeVisualInputs({
489
+ spec: paths.spec || null,
490
+ visualInputsJson: paths.visualInputsJson || null,
491
+ visualInputsMd: paths.visualInputsMd || null,
492
+ });
353
493
  const applicable = Boolean(paths.plan && fs.existsSync(paths.plan));
354
494
  const criticalExecutionGaps = applicable
355
495
  ? Array.from(
@@ -357,6 +497,7 @@ function buildExecutionRationality(paths = {}) {
357
497
  ...implementationPack.criticalGaps,
358
498
  ...referenceAnchors.criticalGaps,
359
499
  ...fixturePack.criticalGaps,
500
+ ...visualInputs.criticalGaps,
360
501
  ])
361
502
  )
362
503
  : [];
@@ -367,13 +508,16 @@ function buildExecutionRationality(paths = {}) {
367
508
  implementationPackReady: applicable ? implementationPack.ready : false,
368
509
  referenceAnchorsReady: applicable ? referenceAnchors.ready : false,
369
510
  fixturePackReady: applicable ? fixturePack.ready : false,
511
+ visualInputReadiness: applicable ? visualInputs.visualInputReadiness : 'not_applicable',
512
+ visualInputsReady: applicable ? visualInputs.ready : true,
370
513
  executionRationalityReady: applicable
371
- ? implementationPack.ready && referenceAnchors.ready && fixturePack.ready && criticalExecutionGaps.length === 0
514
+ ? implementationPack.ready && referenceAnchors.ready && fixturePack.ready && visualInputs.ready && criticalExecutionGaps.length === 0
372
515
  : false,
373
516
  criticalExecutionGaps,
374
517
  implementationPack,
375
518
  referenceAnchors,
376
519
  fixturePack,
520
+ visualInputs,
377
521
  };
378
522
  }
379
523
 
@@ -384,4 +528,5 @@ module.exports = {
384
528
  summarizeImplementationPack,
385
529
  summarizeReferenceAnchors,
386
530
  summarizeFixturePack,
531
+ summarizeVisualInputs,
387
532
  };
@@ -19,6 +19,17 @@ const REQUIRED_RUNTIMES = [
19
19
  'antigravity',
20
20
  ];
21
21
 
22
+ const REQUIRED_RUNTIME_REAL_SCENARIOS_1_10 = [
23
+ 'static-html-js',
24
+ 'node-cli-api',
25
+ 'brownfield-docs',
26
+ 'multi_file_mutation',
27
+ 'multi_wave_app',
28
+ 'gate_blocked_execute',
29
+ 'partial_verify_replan',
30
+ 'promotion_blocked_by_risk',
31
+ ];
32
+
22
33
  const WRAPPER_TARGETS = [
23
34
  {
24
35
  key: '.github/prompts',
@@ -275,13 +286,19 @@ function loadRuntimeSmokeReport(projectRoot) {
275
286
  && item.wrapper_drift_ok !== false
276
287
  && item.extra_checks_ok !== false
277
288
  && item.agent_checks_ok !== false
289
+ && item.copilot_manifest_ok !== false
290
+ && item.codex_discovery_ok !== false
278
291
  && item.uninstall_ok
279
292
  );
280
293
  });
281
294
  }
282
295
 
283
296
  function loadRuntimeRealReport(projectRoot) {
284
- return readReportSummary(releasePaths(projectRoot).runtimeRealReport, null, (item) => Boolean(item && item.ok));
297
+ return readReportSummary(
298
+ releasePaths(projectRoot).runtimeRealReport,
299
+ REQUIRED_RUNTIME_REAL_SCENARIOS_1_10,
300
+ (item) => Boolean(item && item.ok)
301
+ );
285
302
  }
286
303
 
287
304
  function loadRecoveryFixtureReport(projectRoot) {
@@ -293,7 +310,18 @@ function loadMultiAgentSoakReport(projectRoot) {
293
310
  }
294
311
 
295
312
  function loadMultiAgentRealReport(projectRoot) {
296
- return readReportSummary(releasePaths(projectRoot).multiAgentRealReport, null, (item) => Boolean(item && item.ok));
313
+ return readReportSummary(releasePaths(projectRoot).multiAgentRealReport, null, (item) => {
314
+ if (!item || !item.ok) return false;
315
+ const records = item.report && Array.isArray(item.report.records) ? item.report.records : [];
316
+ for (const record of records) {
317
+ if (record.status !== 'merged') continue;
318
+ if (record.verify_status !== 'pass') return false;
319
+ if (!Array.isArray(record.evidence_refs) || record.evidence_refs.length === 0) return false;
320
+ if (!Array.isArray(record.applied_paths) || record.applied_paths.length === 0) return false;
321
+ if (!record.diff_summary || !Array.isArray(record.diff_summary.paths) || record.diff_summary.paths.length === 0) return false;
322
+ }
323
+ return true;
324
+ });
297
325
  }
298
326
 
299
327
  function readVersionSnapshot(projectRoot) {
@@ -506,6 +534,7 @@ function inspectReleaseReadiness(projectRoot, options = {}) {
506
534
 
507
535
  module.exports = {
508
536
  REQUIRED_RUNTIMES,
537
+ REQUIRED_RUNTIME_REAL_SCENARIOS_1_10,
509
538
  WRAPPER_TARGETS,
510
539
  releasePaths,
511
540
  collectWrapperHashes,
package/bin/oxe-cc.js CHANGED
@@ -1537,10 +1537,13 @@ function printOxeHealthDiagnostics(target, c, diagOpts = {}) {
1537
1537
  if (r.executionRationality && r.executionRationality.applicable === false) {
1538
1538
  console.log(` ${c ? dim : ''}Prontidão racional:${c ? reset : ''} não aplicável ainda (PLAN.md ausente)`);
1539
1539
  } else if (typeof r.executionRationalityReady === 'boolean') {
1540
- console.log(
1541
- ` ${c ? dim : ''}Prontidão racional:${c ? reset : ''} implementation=${r.implementationPackReady ? 'ok' : 'pendente'} | anchors=${r.referenceAnchorsReady ? 'ok' : 'pendente'} | fixtures=${r.fixturePackReady ? 'ok' : 'pendente'}`
1542
- );
1543
- }
1540
+ console.log(
1541
+ ` ${c ? dim : ''}Prontidão racional:${c ? reset : ''} implementation=${r.implementationPackReady ? 'ok' : 'pendente'} | anchors=${r.referenceAnchorsReady ? 'ok' : 'pendente'} | fixtures=${r.fixturePackReady ? 'ok' : 'pendente'}`
1542
+ );
1543
+ if (r.visualInputReadiness && r.visualInputReadiness !== 'not_applicable') {
1544
+ console.log(` ${c ? dim : ''}Entradas visuais:${c ? reset : ''} ${r.visualInputReadiness}`);
1545
+ }
1546
+ }
1544
1547
  if (r.contextQuality) {
1545
1548
  console.log(
1546
1549
  ` ${c ? dim : ''}Contexto:${c ? reset : ''} score=${r.contextQuality.primaryScore != null ? r.contextQuality.primaryScore : '—'} | workflow=${r.contextQuality.primaryWorkflow || '—'} | status=${r.contextQuality.primaryStatus || '—'}`
@@ -1744,10 +1747,13 @@ function runStatusFull(target) {
1744
1747
  console.log(` ${c ? yellow : ''} • ${w}${c ? reset : ''}`);
1745
1748
  }
1746
1749
  }
1747
- if (planExists) {
1748
- console.log(` ${c ? dim : ''} • Artefatos racionais:${c ? reset : ''} implementation=${report.implementationPackReady ? 'ok' : 'pendente'} · anchors=${report.referenceAnchorsReady ? 'ok' : 'pendente'} · fixtures=${report.fixturePackReady ? 'ok' : 'pendente'}`);
1749
- }
1750
- }
1750
+ if (planExists) {
1751
+ console.log(` ${c ? dim : ''} • Artefatos racionais:${c ? reset : ''} implementation=${report.implementationPackReady ? 'ok' : 'pendente'} · anchors=${report.referenceAnchorsReady ? 'ok' : 'pendente'} · fixtures=${report.fixturePackReady ? 'ok' : 'pendente'}`);
1752
+ if (report.visualInputReadiness && report.visualInputReadiness !== 'not_applicable') {
1753
+ console.log(` ${c ? dim : ''} • Entradas visuais:${c ? reset : ''} ${report.visualInputReadiness}`);
1754
+ }
1755
+ }
1756
+ }
1751
1757
 
1752
1758
  // Active run summary
1753
1759
  if (report.activeRun) {
@@ -1804,12 +1810,14 @@ function runStatusFull(target) {
1804
1810
  if (report.recoveryState) {
1805
1811
  console.log(` ${c ? dim : ''}Recovery:${c ? reset : ''} ${report.recoveryState.status || 'unknown'} · recoveries ${report.recoveryState.recoverCount ?? 0} · issues ${Array.isArray(report.recoveryState.issues) ? report.recoveryState.issues.length : 0}`);
1806
1812
  }
1807
- if (report.multiAgent) {
1808
- const agents = Array.isArray(report.multiAgent.agents) ? report.multiAgent.agents.length : 0;
1809
- const handoffs = Array.isArray(report.multiAgent.handoffs) ? report.multiAgent.handoffs.length : 0;
1810
- const ownership = Array.isArray(report.multiAgent.ownership) ? report.multiAgent.ownership.length : 0;
1811
- console.log(` ${c ? dim : ''}Multi-agent:${c ? reset : ''} ${report.multiAgent.enabled ? (report.multiAgent.mode || 'active') : 'disabled'} · agentes ${agents} · ownership ${ownership} · handoffs ${handoffs}`);
1812
- }
1813
+ if (report.multiAgent) {
1814
+ const agents = Array.isArray(report.multiAgent.agents) ? report.multiAgent.agents.length : 0;
1815
+ const handoffs = Array.isArray(report.multiAgent.handoffs) ? report.multiAgent.handoffs.length : 0;
1816
+ const ownership = Array.isArray(report.multiAgent.ownership) ? report.multiAgent.ownership.length : 0;
1817
+ const blockers = Array.isArray(report.multiAgent.mergeBlockers) ? report.multiAgent.mergeBlockers.length : 0;
1818
+ console.log(` ${c ? dim : ''}Multi-agent:${c ? reset : ''} ${report.multiAgent.enabled ? (report.multiAgent.mode || 'active') : 'disabled'} · agentes ${agents} · ownership ${ownership} · handoffs ${handoffs} · merge ${report.multiAgent.mergeReadiness || 'n/a'} · blockers ${blockers}`);
1819
+ if (report.multiAgent.nextAction) console.log(` ${c ? dim : ''}Multi-agent next:${c ? reset : ''} ${report.multiAgent.nextAction}`);
1820
+ }
1813
1821
  if (report.providerCatalog) {
1814
1822
  const summary = report.providerCatalog.summary || {};
1815
1823
  const pluginsCount = summary.pluginsCount ?? summary.total_plugins ?? (Array.isArray(summary.plugins) ? summary.plugins.length : 0);
@@ -1891,8 +1899,10 @@ function runStatus(target, opts = {}) {
1891
1899
  planConfidenceExecutable: report.planConfidenceExecutable,
1892
1900
  implementationPackReady: report.implementationPackReady,
1893
1901
  referenceAnchorsReady: report.referenceAnchorsReady,
1894
- fixturePackReady: report.fixturePackReady,
1895
- executionRationalityReady: report.executionRationalityReady,
1902
+ fixturePackReady: report.fixturePackReady,
1903
+ visualInputReadiness: report.visualInputReadiness,
1904
+ visualInputsReady: report.visualInputsReady,
1905
+ executionRationalityReady: report.executionRationalityReady,
1896
1906
  criticalExecutionGaps: report.criticalExecutionGaps,
1897
1907
  executionRationality: report.executionRationality,
1898
1908
  planReviewStatus: report.planReviewStatus,
@@ -4455,9 +4465,11 @@ async function runRuntime(opts) {
4455
4465
  : `${report.recoveryState.status} · issues=${recIssues} — rode ${c ? cyan : ''}runtime status --verbose${c ? reset : ''} para detalhes`;
4456
4466
  console.log(` ${c ? green : ''}Recovery:${c ? reset : ''} ${recLabel} · recoveries=${report.recoveryState.recoverCount ?? 0}`);
4457
4467
  }
4458
- if (multiAgent) {
4459
- console.log(` ${c ? green : ''}Multi-agent:${c ? reset : ''} ${multiAgent.enabled ? (multiAgent.mode || 'active') : 'disabled'} · agentes=${Array.isArray(multiAgent.agents) ? multiAgent.agents.length : 0} · ownership=${Array.isArray(multiAgent.ownership) ? multiAgent.ownership.length : 0}`);
4460
- }
4468
+ if (multiAgent) {
4469
+ const blockers = Array.isArray(multiAgent.mergeBlockers) ? multiAgent.mergeBlockers.length : 0;
4470
+ console.log(` ${c ? green : ''}Multi-agent:${c ? reset : ''} ${multiAgent.enabled ? (multiAgent.mode || 'active') : 'disabled'} · agentes=${Array.isArray(multiAgent.agents) ? multiAgent.agents.length : 0} · ownership=${Array.isArray(multiAgent.ownership) ? multiAgent.ownership.length : 0} · merge=${multiAgent.mergeReadiness || 'n/a'} · blockers=${blockers}`);
4471
+ if (multiAgent.nextAction) console.log(` ${c ? cyan : ''}Próxima ação:${c ? reset : ''} ${multiAgent.nextAction}`);
4472
+ }
4461
4473
  if (report.providerCatalog && report.providerCatalog.summary) {
4462
4474
  const summary = report.providerCatalog.summary;
4463
4475
  const pluginsCount = summary.pluginsCount ?? summary.total_plugins ?? (Array.isArray(summary.plugins) ? summary.plugins.length : 0);
@@ -4898,11 +4910,13 @@ async function runRuntime(opts) {
4898
4910
  return;
4899
4911
  }
4900
4912
  console.log(` ${c ? green : ''}Run:${c ? reset : ''} ${multiAgent.runId || '—'}`);
4901
- console.log(` ${c ? green : ''}Modo:${c ? reset : ''} ${multiAgent.enabled ? (multiAgent.mode || 'active') : 'disabled'}`);
4902
- console.log(` ${c ? green : ''}Isolamento:${c ? reset : ''} ${multiAgent.workspaceIsolationEnforced ? 'enforced' : 'shared/disabled'}`);
4903
- console.log(` ${c ? green : ''}Agentes:${c ? reset : ''} ${Array.isArray(multiAgent.agents) ? multiAgent.agents.length : 0} · ownership=${Array.isArray(multiAgent.ownership) ? multiAgent.ownership.length : 0} · handoffs=${Array.isArray(multiAgent.handoffs) ? multiAgent.handoffs.length : 0}`);
4904
- return;
4905
- }
4913
+ console.log(` ${c ? green : ''}Modo:${c ? reset : ''} ${multiAgent.enabled ? (multiAgent.mode || 'active') : 'disabled'}`);
4914
+ console.log(` ${c ? green : ''}Isolamento:${c ? reset : ''} ${multiAgent.workspaceIsolationEnforced ? 'enforced' : 'shared/disabled'}`);
4915
+ console.log(` ${c ? green : ''}Agentes:${c ? reset : ''} ${Array.isArray(multiAgent.agents) ? multiAgent.agents.length : 0} · ownership=${Array.isArray(multiAgent.ownership) ? multiAgent.ownership.length : 0} · handoffs=${Array.isArray(multiAgent.handoffs) ? multiAgent.handoffs.length : 0}`);
4916
+ console.log(` ${c ? green : ''}Merge:${c ? reset : ''} ${multiAgent.mergeReadiness || 'n/a'} · blockers=${Array.isArray(multiAgent.mergeBlockers) ? multiAgent.mergeBlockers.length : 0} · arbitration=${multiAgent.arbitrationRequired ? 'required' : 'no'}`);
4917
+ if (multiAgent.nextAction) console.log(` ${c ? cyan : ''}Próxima ação:${c ? reset : ''} ${multiAgent.nextAction}`);
4918
+ return;
4919
+ }
4906
4920
 
4907
4921
  try {
4908
4922
  const next = oxeOperational.applyRuntimeAction(opts.dir, activeSession, {
@@ -15,7 +15,7 @@ oxe_tool_profile: read_heavy
15
15
  oxe_confidence_policy: explicit
16
16
  oxe_context_tier: standard
17
17
  oxe_contract_version: 2.0.0
18
- oxe_semantics_hash: ebb4473c14e5b080
18
+ oxe_semantics_hash: 13daa3c62e0efaa4
19
19
  ---
20
20
 
21
21
  <!-- oxe-reasoning-contract:start -->
@@ -29,7 +29,7 @@ oxe_semantics_hash: ebb4473c14e5b080
29
29
  - **Política de confiança:** explícita
30
30
  - **Tier de contexto padrão:** padrão
31
31
  - **Versão do contrato:** 2.0.0
32
- - **Checksum semântico:** `ebb4473c14e5b080`
32
+ - **Checksum semântico:** `13daa3c62e0efaa4`
33
33
  - **Entrada de contexto prioritária:** `.oxe/context/packs/dashboard.md` e `.oxe/context/packs/dashboard.json`
34
34
  - **Regra pack-first:** ler o context pack primeiro; se estiver stale, incompleto ou ausente, cair para leitura direta com fallback explícito.
35
35
  - **Inspeção estruturada:** `oxe-cc context inspect --workflow dashboard --json`
@@ -22,7 +22,7 @@ oxe_tool_profile: write_bounded
22
22
  oxe_confidence_policy: explicit
23
23
  oxe_context_tier: standard
24
24
  oxe_contract_version: 2.0.0
25
- oxe_semantics_hash: 7b3446b77aef9353
25
+ oxe_semantics_hash: 0e6003de070d497f
26
26
  ---
27
27
 
28
28
  <!-- oxe-reasoning-contract:start -->
@@ -36,7 +36,7 @@ oxe_semantics_hash: 7b3446b77aef9353
36
36
  - **Política de confiança:** explícita
37
37
  - **Tier de contexto padrão:** padrão
38
38
  - **Versão do contrato:** 2.0.0
39
- - **Checksum semântico:** `7b3446b77aef9353`
39
+ - **Checksum semântico:** `0e6003de070d497f`
40
40
  - **Entrada de contexto prioritária:** `.oxe/context/packs/execute.md` e `.oxe/context/packs/execute.json`
41
41
  - **Regra pack-first:** ler o context pack primeiro; se estiver stale, incompleto ou ausente, cair para leitura direta com fallback explícito.
42
42
  - **Inspeção estruturada:** `oxe-cc context inspect --workflow execute --json`
@@ -21,7 +21,7 @@ oxe_tool_profile: mixed
21
21
  oxe_confidence_policy: rubric
22
22
  oxe_context_tier: standard
23
23
  oxe_contract_version: 2.0.0
24
- oxe_semantics_hash: 5c589398cb807029
24
+ oxe_semantics_hash: 210518babb4788d0
25
25
  ---
26
26
 
27
27
  <!-- oxe-reasoning-contract:start -->
@@ -35,7 +35,7 @@ oxe_semantics_hash: 5c589398cb807029
35
35
  - **Política de confiança:** rubrica
36
36
  - **Tier de contexto padrão:** padrão
37
37
  - **Versão do contrato:** 2.0.0
38
- - **Checksum semântico:** `5c589398cb807029`
38
+ - **Checksum semântico:** `210518babb4788d0`
39
39
  - **Entrada de contexto prioritária:** `.oxe/context/packs/plan.md` e `.oxe/context/packs/plan.json`
40
40
  - **Regra pack-first:** ler o context pack primeiro; se estiver stale, incompleto ou ausente, cair para leitura direta com fallback explícito.
41
41
  - **Inspeção estruturada:** `oxe-cc context inspect --workflow plan --json`
@@ -17,7 +17,7 @@ oxe_tool_profile: mixed
17
17
  oxe_confidence_policy: rubric
18
18
  oxe_context_tier: standard
19
19
  oxe_contract_version: 2.0.0
20
- oxe_semantics_hash: 2193373eb2691e0d
20
+ oxe_semantics_hash: ea0c06ca7b5c87bb
21
21
  ---
22
22
 
23
23
  <!-- oxe-reasoning-contract:start -->
@@ -31,7 +31,7 @@ oxe_semantics_hash: 2193373eb2691e0d
31
31
  - **Política de confiança:** rubrica
32
32
  - **Tier de contexto padrão:** padrão
33
33
  - **Versão do contrato:** 2.0.0
34
- - **Checksum semântico:** `2193373eb2691e0d`
34
+ - **Checksum semântico:** `ea0c06ca7b5c87bb`
35
35
  - **Entrada de contexto prioritária:** `.oxe/context/packs/quick.md` e `.oxe/context/packs/quick.json`
36
36
  - **Regra pack-first:** ler o context pack primeiro; se estiver stale, incompleto ou ausente, cair para leitura direta com fallback explícito.
37
37
  - **Inspeção estruturada:** `oxe-cc context inspect --workflow quick --json`
@@ -20,7 +20,7 @@ oxe_tool_profile: read_heavy
20
20
  oxe_confidence_policy: explicit
21
21
  oxe_context_tier: standard
22
22
  oxe_contract_version: 2.0.0
23
- oxe_semantics_hash: eea8766eab635c97
23
+ oxe_semantics_hash: 4ec66ac1e704fdbf
24
24
  ---
25
25
 
26
26
  <!-- oxe-reasoning-contract:start -->
@@ -34,7 +34,7 @@ oxe_semantics_hash: eea8766eab635c97
34
34
  - **Política de confiança:** explícita
35
35
  - **Tier de contexto padrão:** padrão
36
36
  - **Versão do contrato:** 2.0.0
37
- - **Checksum semântico:** `eea8766eab635c97`
37
+ - **Checksum semântico:** `4ec66ac1e704fdbf`
38
38
  - **Entrada de contexto prioritária:** `.oxe/context/packs/spec.md` e `.oxe/context/packs/spec.json`
39
39
  - **Regra pack-first:** ler o context pack primeiro; se estiver stale, incompleto ou ausente, cair para leitura direta com fallback explícito.
40
40
  - **Inspeção estruturada:** `oxe-cc context inspect --workflow spec --json`
@@ -53,4 +53,4 @@ oxe_semantics_hash: eea8766eab635c97
53
53
 
54
54
  <!-- oxe-workflow-resolution:end -->
55
55
 
56
- Usa `$ARGUMENTS` e o contexto da conversa como entrada do utilizador (texto ou `@ficheiro`).
56
+ Usa `$ARGUMENTS`, contexto da conversa e anexos como entrada do utilizador. Se houver imagem, screenshot ou mockup e o runtime suportar visão, materializar a interpretação em `VISUAL-INPUTS`; se não suportar, declarar a limitação e não inventar detalhes visuais.
@@ -35,6 +35,8 @@ Todos os artefatos abaixo devem existir em `.oxe/release/`:
35
35
  - `multi-agent-soak-report.json`
36
36
  - `multi-agent-real-report.json` para versões `>=1.9.1`
37
37
 
38
+ Na linha `>=1.10.0`, `runtime-real-report.json` deve cobrir cenários representativos além do happy path simples: multi-wave, multi-file, verify parcial, gate pendente e promoção bloqueada. O `multi-agent-real-report.json` deve provar merge com evidência, diff summary, arquivos aplicados e verify status por task; o release doctor valida esse conteúdo, não apenas a presença do arquivo.
39
+
38
40
  ## Defaults estáveis desta publicação
39
41
 
40
42
  - `execute` e `verify`: `runtime-first`
@@ -45,10 +45,19 @@ export interface WorkspaceMergeRecord {
45
45
  root_path: string | null;
46
46
  mutation_scope: string[];
47
47
  diff_paths: string[];
48
+ evidence_refs: string[];
48
49
  evidence_count: number;
49
50
  verify_status: 'pass' | 'fail' | 'partial';
50
51
  status: 'ready' | 'merged' | 'blocked' | 'skipped';
51
52
  blocker: string | null;
53
+ applied_paths: string[];
54
+ diff_summary: {
55
+ added: number;
56
+ modified: number;
57
+ missing: number;
58
+ paths: string[];
59
+ };
60
+ next_action: string | null;
52
61
  recorded_at: string;
53
62
  }
54
63
  export interface WorkspaceMergeReport {
@@ -122,7 +122,8 @@ function mutationScopeOf(node) {
122
122
  return Array.isArray(node?.mutation_scope) ? node.mutation_scope.map(String).filter(Boolean) : [];
123
123
  }
124
124
  function createMergeRecord(agent, node, lease, result) {
125
- const evidenceCount = Array.isArray(result?.evidence) ? result.evidence.length : 0;
125
+ const evidenceRefs = Array.isArray(result?.evidence) ? result.evidence.map(String).filter(Boolean) : [];
126
+ const scope = mutationScopeOf(node);
126
127
  return {
127
128
  work_item_id: node.id,
128
129
  agent_id: agent.id,
@@ -132,12 +133,31 @@ function createMergeRecord(agent, node, lease, result) {
132
133
  branch: lease.branch ?? null,
133
134
  base_commit: lease.base_commit ?? null,
134
135
  root_path: lease.root_path ?? null,
135
- mutation_scope: mutationScopeOf(node),
136
- diff_paths: mutationScopeOf(node),
137
- evidence_count: evidenceCount,
136
+ mutation_scope: scope,
137
+ diff_paths: scope,
138
+ evidence_refs: evidenceRefs,
139
+ evidence_count: evidenceRefs.length,
138
140
  verify_status: result ? (result.success ? 'pass' : 'fail') : 'partial',
139
141
  status: result ? (result.success ? 'ready' : 'blocked') : 'ready',
140
142
  blocker: result && !result.success ? `verify_failed:${result.failure_class}` : null,
143
+ applied_paths: [],
144
+ diff_summary: { added: 0, modified: 0, missing: 0, paths: scope },
145
+ next_action: result && !result.success ? 'Corrija a falha de verify/evidence antes de aplicar merge do workspace.' : null,
146
+ recorded_at: new Date().toISOString(),
147
+ };
148
+ }
149
+ function enrichMergeRecordWithResult(record, result) {
150
+ if (!result)
151
+ return record;
152
+ const evidenceRefs = Array.isArray(result.evidence) ? result.evidence.map(String).filter(Boolean) : [];
153
+ return {
154
+ ...record,
155
+ evidence_refs: evidenceRefs,
156
+ evidence_count: evidenceRefs.length,
157
+ verify_status: result.success ? 'pass' : 'fail',
158
+ status: result.success ? 'ready' : 'blocked',
159
+ blocker: result.success ? null : `verify_failed:${result.failure_class}`,
160
+ next_action: result.success ? null : 'Corrija a falha de verify/evidence antes de aplicar merge do workspace.',
141
161
  recorded_at: new Date().toISOString(),
142
162
  };
143
163
  }
@@ -179,16 +199,37 @@ function detectMutationConflicts(graph, agents, partitions) {
179
199
  function applyWorkspaceRecord(projectRoot, record) {
180
200
  if (!record.root_path || record.status !== 'ready')
181
201
  return record;
202
+ const appliedPaths = [];
203
+ const summary = { added: 0, modified: 0, missing: 0, paths: [...record.mutation_scope] };
182
204
  for (const relativePath of record.mutation_scope) {
183
205
  const source = path_1.default.join(record.root_path, relativePath);
184
206
  const target = path_1.default.join(projectRoot, relativePath);
185
207
  if (!fs_1.default.existsSync(source) || fs_1.default.statSync(source).isDirectory()) {
186
- return { ...record, status: 'blocked', blocker: `missing_output:${relativePath}` };
208
+ summary.missing += 1;
209
+ return {
210
+ ...record,
211
+ status: 'blocked',
212
+ blocker: `missing_output:${relativePath}`,
213
+ diff_summary: summary,
214
+ next_action: `Materialize o arquivo esperado ${relativePath} no worktree do agente antes do merge.`,
215
+ };
187
216
  }
217
+ if (fs_1.default.existsSync(target))
218
+ summary.modified += 1;
219
+ else
220
+ summary.added += 1;
188
221
  fs_1.default.mkdirSync(path_1.default.dirname(target), { recursive: true });
189
222
  fs_1.default.copyFileSync(source, target);
223
+ appliedPaths.push(relativePath);
190
224
  }
191
- return { ...record, status: 'merged', blocker: null };
225
+ return {
226
+ ...record,
227
+ status: 'merged',
228
+ blocker: null,
229
+ applied_paths: appliedPaths,
230
+ diff_summary: summary,
231
+ next_action: null,
232
+ };
192
233
  }
193
234
  function createTrackingWorkspaceManager(base, agent, graph, records) {
194
235
  const leases = new Map();
@@ -231,11 +272,19 @@ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeo
231
272
  };
232
273
  }
233
274
  const trackingWorkspaceManager = createTrackingWorkspaceManager(agent.workspaceManager, agent, graph, workspaceRecords);
275
+ const taskResults = new Map();
276
+ const trackingExecutor = {
277
+ execute: async (node, lease, runId, attemptNumber) => {
278
+ const result = await agent.executor.execute(node, lease, runId, attemptNumber);
279
+ taskResults.set(node.id, result);
280
+ return result;
281
+ },
282
+ };
234
283
  const ctx = {
235
284
  projectRoot: opts.projectRoot,
236
285
  sessionId: opts.sessionId,
237
286
  runId: `${opts.runId}-agent${idx}`,
238
- executor: agent.executor,
287
+ executor: trackingExecutor,
239
288
  workspaceManager: trackingWorkspaceManager,
240
289
  onEvent: opts.onEvent,
241
290
  };
@@ -243,6 +292,7 @@ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeo
243
292
  const work = scheduler.run(subGraph, ctx);
244
293
  if (!heartbeatTimeoutMs || heartbeatTimeoutMs <= 0) {
245
294
  const result = await work;
295
+ const reconciledRecords = workspaceRecords.map((record) => enrichMergeRecordWithResult(record, taskResults.get(record.work_item_id)));
246
296
  return {
247
297
  agent_id: agent.id,
248
298
  completed: result.completed,
@@ -250,7 +300,7 @@ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeo
250
300
  timed_out: false,
251
301
  assigned_task_ids: nodeIds,
252
302
  reassigned_task_ids: [],
253
- workspace_records: workspaceRecords,
303
+ workspace_records: reconciledRecords,
254
304
  cleanup: () => trackingWorkspaceManager.disposeDeferred(),
255
305
  };
256
306
  }
@@ -276,6 +326,7 @@ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeo
276
326
  };
277
327
  }
278
328
  const result = raced.result;
329
+ const reconciledRecords = workspaceRecords.map((record) => enrichMergeRecordWithResult(record, taskResults.get(record.work_item_id)));
279
330
  return {
280
331
  agent_id: agent.id,
281
332
  completed: result.completed,
@@ -283,7 +334,7 @@ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeo
283
334
  timed_out: false,
284
335
  assigned_task_ids: nodeIds,
285
336
  reassigned_task_ids: [],
286
- workspace_records: workspaceRecords,
337
+ workspace_records: reconciledRecords,
287
338
  cleanup: () => trackingWorkspaceManager.disposeDeferred(),
288
339
  };
289
340
  }