oxe-cc 1.8.3 → 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.
- package/.cursor/commands/oxe-dashboard.md +2 -2
- package/.cursor/commands/oxe-execute.md +2 -2
- package/.cursor/commands/oxe-plan.md +2 -2
- package/.cursor/commands/oxe-quick.md +2 -2
- package/.cursor/commands/oxe-spec.md +3 -3
- package/.github/prompts/oxe-dashboard.prompt.md +2 -2
- package/.github/prompts/oxe-execute.prompt.md +2 -2
- package/.github/prompts/oxe-plan.prompt.md +2 -2
- package/.github/prompts/oxe-quick.prompt.md +2 -2
- package/.github/prompts/oxe-spec.prompt.md +3 -3
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +45 -0
- package/README.md +32 -26
- package/bin/lib/oxe-context-engine.cjs +2 -0
- package/bin/lib/oxe-operational.cjs +230 -74
- package/bin/lib/oxe-project-health.cjs +43 -9
- package/bin/lib/oxe-rationality.cjs +146 -1
- package/bin/lib/oxe-release.cjs +55 -0
- package/bin/oxe-cc.js +60 -37
- package/commands/oxe/dashboard.md +2 -2
- package/commands/oxe/execute.md +2 -2
- package/commands/oxe/plan.md +2 -2
- package/commands/oxe/quick.md +2 -2
- package/commands/oxe/spec.md +3 -3
- package/docs/RELEASE-READINESS.md +8 -1
- package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +48 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.js +274 -14
- package/lib/runtime/workspace/strategies/git-worktree.js +18 -9
- package/oxe/templates/REFERENCE-ANCHORS.template.md +12 -5
- package/oxe/templates/SPEC.template.md +10 -0
- package/oxe/templates/VISUAL-INPUTS.template.json +27 -0
- package/oxe/templates/VISUAL-INPUTS.template.md +36 -0
- package/oxe/workflows/execute.md +3 -0
- package/oxe/workflows/plan.md +13 -9
- package/oxe/workflows/references/workflow-runtime-contracts.json +44 -29
- package/oxe/workflows/spec.md +19 -8
- package/oxe/workflows/ui-spec.md +3 -2
- package/package.json +6 -3
- package/packages/runtime/package.json +1 -1
- package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +379 -47
- package/packages/runtime/src/workspace/strategies/git-worktree.ts +24 -16
- package/vscode-extension/package.json +1 -1
|
@@ -722,10 +722,52 @@ async function resolveRuntimeGate(projectRoot, activeSession, options = {}) {
|
|
|
722
722
|
};
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
-
// Gap 5: route execution to MultiAgentCoordinator when plan-agents.json exists
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
725
|
+
// Gap 5: route execution to MultiAgentCoordinator when plan-agents.json exists
|
|
726
|
+
function buildRuntimeExecutePreflight(projectRoot, activeSession, runState) {
|
|
727
|
+
const health = loadProjectHealth();
|
|
728
|
+
const blockers = [];
|
|
729
|
+
const warnings = [];
|
|
730
|
+
let report = null;
|
|
731
|
+
if (health && typeof health.buildHealthReport === 'function') {
|
|
732
|
+
report = health.buildHealthReport(projectRoot);
|
|
733
|
+
if (report.planSelfEvaluation && report.planSelfEvaluation.executable === false) {
|
|
734
|
+
const confidence = report.planSelfEvaluation.confidence;
|
|
735
|
+
const threshold = report.planConfidenceThreshold || 90;
|
|
736
|
+
blockers.push(`plan_confidence:${confidence == null ? 'missing' : `${confidence}%`}<=${threshold}%`);
|
|
737
|
+
}
|
|
738
|
+
if (report.executionRationality && report.executionRationality.applicable && !report.executionRationalityReady) {
|
|
739
|
+
const gaps = Array.isArray(report.criticalExecutionGaps) ? report.criticalExecutionGaps : [];
|
|
740
|
+
blockers.push(`execution_rationality:${gaps[0] || 'not_ready'}`);
|
|
741
|
+
}
|
|
742
|
+
if (report.fallbackMode && report.fallbackMode !== 'none') {
|
|
743
|
+
warnings.push(`fallback_mode:${report.fallbackMode}`);
|
|
744
|
+
}
|
|
745
|
+
} else {
|
|
746
|
+
warnings.push('health_report_unavailable');
|
|
747
|
+
}
|
|
748
|
+
const runId = runState && runState.run_id ? runState.run_id : null;
|
|
749
|
+
const queue = readRuntimeGates(projectRoot, activeSession, { runId });
|
|
750
|
+
if (queue.pending.length > 0) {
|
|
751
|
+
blockers.push(`pending_gates:${queue.pending.length}`);
|
|
752
|
+
}
|
|
753
|
+
return {
|
|
754
|
+
ok: blockers.length === 0,
|
|
755
|
+
blockers,
|
|
756
|
+
warnings,
|
|
757
|
+
runId,
|
|
758
|
+
gateQueue: {
|
|
759
|
+
pending: queue.pending.length,
|
|
760
|
+
stale: queue.staleCount || 0,
|
|
761
|
+
},
|
|
762
|
+
confidence: report && report.planSelfEvaluation ? report.planSelfEvaluation.confidence : null,
|
|
763
|
+
confidenceThreshold: report ? report.planConfidenceThreshold || 90 : 90,
|
|
764
|
+
executionRationalityReady: report ? Boolean(report.executionRationalityReady) : false,
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
|
|
769
|
+
const runtime = loadRuntimeModule();
|
|
770
|
+
if (!runtime) throw new Error('Runtime package não está disponível. Rode npm run build:runtime.');
|
|
729
771
|
const parsers = loadSdkParsers();
|
|
730
772
|
if (!parsers) throw new Error('SDK parsers não disponíveis.');
|
|
731
773
|
|
|
@@ -745,15 +787,41 @@ async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
|
|
|
745
787
|
|
|
746
788
|
// Resolve compiled graph from run state or compile on demand
|
|
747
789
|
let current = options.runState || readRunState(projectRoot, activeSession);
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
790
|
+
if (!current || !current.compiled_graph) {
|
|
791
|
+
current = compileExecutionGraphFromArtifacts(projectRoot, activeSession, { runState: current }).run;
|
|
792
|
+
}
|
|
793
|
+
if (!current || !current.compiled_graph) {
|
|
794
|
+
throw new Error('Nenhum grafo compilado encontrado. Execute oxe-cc runtime compile primeiro.');
|
|
795
|
+
}
|
|
796
|
+
const preflight = buildRuntimeExecutePreflight(projectRoot, activeSession, current);
|
|
797
|
+
if (!preflight.ok && !options.skipPreflight) {
|
|
798
|
+
const reason = preflight.blockers[0] || 'runtime_execute_preflight_failed';
|
|
799
|
+
appendEvent(projectRoot, activeSession, {
|
|
800
|
+
type: 'WorkItemBlocked',
|
|
801
|
+
run_id: current.run_id,
|
|
802
|
+
payload: {
|
|
803
|
+
reason: 'runtime_execute_preflight_failed',
|
|
804
|
+
blockers: preflight.blockers,
|
|
805
|
+
},
|
|
806
|
+
});
|
|
807
|
+
return {
|
|
808
|
+
mode: 'preflight',
|
|
809
|
+
agentPlan: null,
|
|
810
|
+
result: {
|
|
811
|
+
run_id: current.run_id,
|
|
812
|
+
status: 'blocked',
|
|
813
|
+
completed: [],
|
|
814
|
+
failed: [],
|
|
815
|
+
blocked: ['runtime_execute_preflight'],
|
|
816
|
+
reason,
|
|
817
|
+
},
|
|
818
|
+
run: current,
|
|
819
|
+
preflight,
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
const graph = runtime.fromSerializable
|
|
823
|
+
? runtime.fromSerializable(current.compiled_graph)
|
|
824
|
+
: current.compiled_graph;
|
|
757
825
|
|
|
758
826
|
// Detect plan-agents.json (session path takes priority over root)
|
|
759
827
|
const rootAgentPlan = path.join(projectRoot, '.oxe', 'plan-agents.json');
|
|
@@ -780,35 +848,40 @@ async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
|
|
|
780
848
|
// Gap 5: multi-agent path if plan-agents.json exists
|
|
781
849
|
if (agentPlanPath) {
|
|
782
850
|
let agentPlan;
|
|
783
|
-
try {
|
|
784
|
-
agentPlan = JSON.parse(fs.readFileSync(agentPlanPath, 'utf8'));
|
|
785
|
-
} catch (err) {
|
|
786
|
-
throw new Error(`plan-agents.json inválido: ${err.message}`);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
851
|
+
try {
|
|
852
|
+
agentPlan = JSON.parse(fs.readFileSync(agentPlanPath, 'utf8'));
|
|
853
|
+
} catch (err) {
|
|
854
|
+
throw new Error(`plan-agents.json inválido: ${err.message}`);
|
|
855
|
+
}
|
|
856
|
+
const planErrors = validateMultiAgentPlan(agentPlan);
|
|
857
|
+
if (planErrors.length > 0) {
|
|
858
|
+
throw new Error(`plan-agents.json inválido: ${planErrors.join('; ')}`);
|
|
859
|
+
}
|
|
860
|
+
if (typeof runtime.MultiAgentCoordinator !== 'function') {
|
|
861
|
+
throw new Error('Runtime não exporta MultiAgentCoordinator. Verifique a versão do runtime.');
|
|
862
|
+
}
|
|
863
|
+
if (typeof runtime.GitWorktreeManager !== 'function' && !options.workspaceManager) {
|
|
864
|
+
throw new Error('Runtime não exporta GitWorktreeManager. Multi-agent real exige backend git_worktree.');
|
|
865
|
+
}
|
|
866
|
+
const agents = agentPlan.agents.map((spec) => ({
|
|
867
|
+
id: spec.id,
|
|
868
|
+
executor: options.executorFactory ? options.executorFactory(spec) : (options.executor || executor),
|
|
869
|
+
workspaceManager: options.workspaceManager || new runtime.GitWorktreeManager(projectRoot),
|
|
870
|
+
assignedTaskIds: Array.isArray(spec.tasks) ? spec.tasks : [],
|
|
871
|
+
}));
|
|
800
872
|
const coordinator = new runtime.MultiAgentCoordinator();
|
|
801
873
|
const result = await coordinator.run(graph, {
|
|
802
874
|
mode: agentPlan.mode || 'parallel',
|
|
803
875
|
agents,
|
|
804
876
|
projectRoot,
|
|
805
877
|
sessionId: activeSession || null,
|
|
806
|
-
runId: current.run_id,
|
|
807
|
-
heartbeatTimeoutMs: options.heartbeatTimeoutMs ?? 120000,
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
878
|
+
runId: current.run_id,
|
|
879
|
+
heartbeatTimeoutMs: options.heartbeatTimeoutMs ?? 120000,
|
|
880
|
+
applyWorkspaceMerges: true,
|
|
881
|
+
onEvent: ctx.onEvent,
|
|
882
|
+
});
|
|
883
|
+
return { mode: agentPlan.mode || 'parallel', agentPlan, result, run: current, preflight };
|
|
884
|
+
}
|
|
812
885
|
|
|
813
886
|
// Single-agent fallback
|
|
814
887
|
if (typeof runtime.Scheduler !== 'function') {
|
|
@@ -816,8 +889,8 @@ async function runRuntimeExecute(projectRoot, activeSession, options = {}) {
|
|
|
816
889
|
}
|
|
817
890
|
const scheduler = new runtime.Scheduler();
|
|
818
891
|
const result = await scheduler.run(graph, ctx);
|
|
819
|
-
|
|
820
|
-
}
|
|
892
|
+
return { mode: 'single', agentPlan: null, result, run: current, preflight };
|
|
893
|
+
}
|
|
821
894
|
|
|
822
895
|
function readRuntimeMultiAgentStatus(projectRoot, activeSession, options = {}) {
|
|
823
896
|
const runtime = loadRuntimeModule();
|
|
@@ -832,26 +905,49 @@ function readRuntimeMultiAgentStatus(projectRoot, activeSession, options = {}) {
|
|
|
832
905
|
workspaceIsolationEnforced: false,
|
|
833
906
|
agents: [],
|
|
834
907
|
ownership: [],
|
|
835
|
-
orphanReassignments: [],
|
|
836
|
-
handoffs: [],
|
|
837
|
-
arbitrationResults: [],
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
908
|
+
orphanReassignments: [],
|
|
909
|
+
handoffs: [],
|
|
910
|
+
arbitrationResults: [],
|
|
911
|
+
workspaceMergeReport: null,
|
|
912
|
+
worktrees: [],
|
|
913
|
+
mergeBlockers: [],
|
|
914
|
+
mergeReadiness: null,
|
|
915
|
+
arbitrationRequired: false,
|
|
916
|
+
health: 'unknown',
|
|
917
|
+
nextAction: 'Execute ou compile uma run antes de inspecionar status multi-agent.',
|
|
918
|
+
summary: null,
|
|
919
|
+
};
|
|
920
|
+
}
|
|
841
921
|
const runDir = path.join(projectRoot, '.oxe', 'runs', runId);
|
|
842
922
|
const statePath = path.join(runDir, 'multi-agent-state.json');
|
|
843
|
-
const summaryPath = path.join(runDir, 'multi-agent-summary.json');
|
|
844
|
-
const handoffsPath = path.join(runDir, 'handoffs.json');
|
|
845
|
-
const arbitrationPath = path.join(runDir, 'arbitration-results.json');
|
|
923
|
+
const summaryPath = path.join(runDir, 'multi-agent-summary.json');
|
|
924
|
+
const handoffsPath = path.join(runDir, 'handoffs.json');
|
|
925
|
+
const arbitrationPath = path.join(runDir, 'arbitration-results.json');
|
|
926
|
+
const workspaceMergePath = path.join(runDir, 'workspace-merge-report.json');
|
|
846
927
|
const state = runtime && typeof runtime.loadMultiAgentState === 'function'
|
|
847
928
|
? runtime.loadMultiAgentState(projectRoot, runId)
|
|
848
929
|
: readJsonIfExists(statePath);
|
|
849
|
-
const summary = runtime && typeof runtime.loadMultiAgentSummary === 'function'
|
|
850
|
-
? runtime.loadMultiAgentSummary(projectRoot, runId)
|
|
851
|
-
: readJsonIfExists(summaryPath);
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
930
|
+
const summary = runtime && typeof runtime.loadMultiAgentSummary === 'function'
|
|
931
|
+
? runtime.loadMultiAgentSummary(projectRoot, runId)
|
|
932
|
+
: readJsonIfExists(summaryPath);
|
|
933
|
+
const workspaceMergeReport = runtime && typeof runtime.loadWorkspaceMergeReport === 'function'
|
|
934
|
+
? runtime.loadWorkspaceMergeReport(projectRoot, runId)
|
|
935
|
+
: readJsonIfExists(workspaceMergePath);
|
|
936
|
+
const handoffs = readJsonIfExists(handoffsPath);
|
|
937
|
+
const arbitrationResults = readJsonIfExists(arbitrationPath);
|
|
938
|
+
const mergeBlockers = workspaceMergeReport && Array.isArray(workspaceMergeReport.blockers) ? workspaceMergeReport.blockers : [];
|
|
939
|
+
const mergeReadiness = workspaceMergeReport && workspaceMergeReport.merge_readiness ? workspaceMergeReport.merge_readiness : null;
|
|
940
|
+
let nextAction = null;
|
|
941
|
+
if (!state) {
|
|
942
|
+
nextAction = 'Execute runtime com plan-agents.json válido para materializar o estado multi-agent.';
|
|
943
|
+
} else if (mergeBlockers.length > 0) {
|
|
944
|
+
nextAction = 'Resolva os merge blockers do workspace antes de promover ou aplicar novos resultados.';
|
|
945
|
+
} else if (mergeReadiness === 'partial') {
|
|
946
|
+
nextAction = 'Conclua verify/evidence pós-merge ou aplique os worktrees pendentes antes de fechar a run.';
|
|
947
|
+
} else if (mergeReadiness === 'ready') {
|
|
948
|
+
nextAction = 'Multi-agent merge pronto; avance para runtime verify ou promotion conforme o ciclo.';
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
855
951
|
path: statePath,
|
|
856
952
|
enabled: Boolean(state),
|
|
857
953
|
runId,
|
|
@@ -860,11 +956,44 @@ function readRuntimeMultiAgentStatus(projectRoot, activeSession, options = {}) {
|
|
|
860
956
|
agents: state && Array.isArray(state.agent_results) ? state.agent_results : [],
|
|
861
957
|
ownership: state && Array.isArray(state.ownership) ? state.ownership : [],
|
|
862
958
|
orphanReassignments: state && Array.isArray(state.orphan_reassignments) ? state.orphan_reassignments : [],
|
|
863
|
-
handoffs: Array.isArray(handoffs) ? handoffs : [],
|
|
864
|
-
arbitrationResults: Array.isArray(arbitrationResults) ? arbitrationResults : [],
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
959
|
+
handoffs: Array.isArray(handoffs) ? handoffs : [],
|
|
960
|
+
arbitrationResults: Array.isArray(arbitrationResults) ? arbitrationResults : [],
|
|
961
|
+
workspaceMergeReport: workspaceMergeReport || null,
|
|
962
|
+
worktrees: workspaceMergeReport && Array.isArray(workspaceMergeReport.records) ? workspaceMergeReport.records : [],
|
|
963
|
+
mergeBlockers,
|
|
964
|
+
mergeReadiness,
|
|
965
|
+
arbitrationRequired: Boolean(workspaceMergeReport && workspaceMergeReport.arbitration_required),
|
|
966
|
+
health: summary && summary.health ? summary.health : (mergeBlockers.length > 0 ? 'degraded' : 'unknown'),
|
|
967
|
+
nextAction,
|
|
968
|
+
summary: summary || null,
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function validateMultiAgentPlan(agentPlan) {
|
|
973
|
+
const errors = [];
|
|
974
|
+
const allowedModes = new Set(['parallel', 'competitive', 'cooperative']);
|
|
975
|
+
const mode = agentPlan && agentPlan.mode ? String(agentPlan.mode) : 'parallel';
|
|
976
|
+
if (!allowedModes.has(mode)) errors.push(`mode inválido: ${mode}`);
|
|
977
|
+
if (!Array.isArray(agentPlan && agentPlan.agents) || agentPlan.agents.length === 0) {
|
|
978
|
+
errors.push('campo "agents" vazio ou ausente');
|
|
979
|
+
return errors;
|
|
980
|
+
}
|
|
981
|
+
const schemaVersion = Number(agentPlan.schema_version || agentPlan.schema || 0);
|
|
982
|
+
const seen = new Set();
|
|
983
|
+
for (const [idx, spec] of agentPlan.agents.entries()) {
|
|
984
|
+
const id = spec && spec.id ? String(spec.id) : '';
|
|
985
|
+
if (!id) errors.push(`agents[${idx}].id ausente`);
|
|
986
|
+
if (id && seen.has(id)) errors.push(`agent duplicado: ${id}`);
|
|
987
|
+
if (id) seen.add(id);
|
|
988
|
+
if (schemaVersion >= 3 && !spec.persona) errors.push(`${id || `agents[${idx}]`}.persona ausente`);
|
|
989
|
+
if (schemaVersion >= 3 && !spec.model_hint) errors.push(`${id || `agents[${idx}]`}.model_hint ausente`);
|
|
990
|
+
if (spec.tasks != null && !Array.isArray(spec.tasks)) errors.push(`${id || `agents[${idx}]`}.tasks deve ser array`);
|
|
991
|
+
}
|
|
992
|
+
if ((mode === 'competitive' || mode === 'cooperative') && agentPlan.agents.length < 2) {
|
|
993
|
+
errors.push(`${mode} exige pelo menos 2 agentes`);
|
|
994
|
+
}
|
|
995
|
+
return errors;
|
|
996
|
+
}
|
|
868
997
|
|
|
869
998
|
function loadRuntimeVerificationArtifacts(projectRoot, runState) {
|
|
870
999
|
const runtime = loadRuntimeModule();
|
|
@@ -890,7 +1019,7 @@ function loadRuntimeVerificationArtifacts(projectRoot, runState) {
|
|
|
890
1019
|
return { manifest, residualRisks, evidenceCoverage };
|
|
891
1020
|
}
|
|
892
1021
|
|
|
893
|
-
function countVerificationEvidenceRefs(runState, verificationArtifacts) {
|
|
1022
|
+
function countVerificationEvidenceRefs(runState, verificationArtifacts) {
|
|
894
1023
|
if (verificationArtifacts && verificationArtifacts.manifest && Array.isArray(verificationArtifacts.manifest.checks)) {
|
|
895
1024
|
return verificationArtifacts.manifest.checks.reduce((sum, check) => {
|
|
896
1025
|
return sum + (Array.isArray(check.evidence_refs) ? check.evidence_refs.length : 0);
|
|
@@ -902,7 +1031,26 @@ function countVerificationEvidenceRefs(runState, verificationArtifacts) {
|
|
|
902
1031
|
}, 0);
|
|
903
1032
|
}
|
|
904
1033
|
return 0;
|
|
905
|
-
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
function detectOrphanWorktrees(projectRoot, runId) {
|
|
1037
|
+
const workspacesDir = path.join(projectRoot, '.oxe', 'workspaces');
|
|
1038
|
+
if (!fs.existsSync(workspacesDir)) return [];
|
|
1039
|
+
const active = new Set();
|
|
1040
|
+
const mergeReport = readJsonIfExists(path.join(projectRoot, '.oxe', 'runs', runId, 'workspace-merge-report.json'));
|
|
1041
|
+
for (const record of (mergeReport && Array.isArray(mergeReport.records) ? mergeReport.records : [])) {
|
|
1042
|
+
if (record && record.workspace_id) active.add(String(record.workspace_id));
|
|
1043
|
+
}
|
|
1044
|
+
return fs.readdirSync(workspacesDir, { withFileTypes: true })
|
|
1045
|
+
.filter((entry) => entry.isDirectory())
|
|
1046
|
+
.map((entry) => entry.name)
|
|
1047
|
+
.filter((name) => !active.has(name))
|
|
1048
|
+
.map((name) => ({
|
|
1049
|
+
workspace_id: name,
|
|
1050
|
+
path: path.join(workspacesDir, name),
|
|
1051
|
+
next_action: 'inspecione o worktree órfão; depois remova com git worktree remove --force se não houver diffs úteis',
|
|
1052
|
+
}));
|
|
1053
|
+
}
|
|
906
1054
|
|
|
907
1055
|
function buildRuntimeModeStatus(runState) {
|
|
908
1056
|
if (!runState) {
|
|
@@ -1074,11 +1222,17 @@ function writeRecoverySummaryMarkdown(projectRoot, activeSession, runState, reco
|
|
|
1074
1222
|
'',
|
|
1075
1223
|
'## Work items órfãos',
|
|
1076
1224
|
'',
|
|
1077
|
-
...(Array.isArray(recoverySummary.orphan_work_items) && recoverySummary.orphan_work_items.length
|
|
1078
|
-
? recoverySummary.orphan_work_items.map((item) => `- ${item}`)
|
|
1079
|
-
: ['- Nenhum']),
|
|
1080
|
-
'',
|
|
1081
|
-
'##
|
|
1225
|
+
...(Array.isArray(recoverySummary.orphan_work_items) && recoverySummary.orphan_work_items.length
|
|
1226
|
+
? recoverySummary.orphan_work_items.map((item) => `- ${item}`)
|
|
1227
|
+
: ['- Nenhum']),
|
|
1228
|
+
'',
|
|
1229
|
+
'## Worktrees órfãos',
|
|
1230
|
+
'',
|
|
1231
|
+
...(Array.isArray(recoverySummary.orphan_worktrees) && recoverySummary.orphan_worktrees.length
|
|
1232
|
+
? recoverySummary.orphan_worktrees.map((item) => `- ${item.workspace_id} · ${item.next_action}`)
|
|
1233
|
+
: ['- Nenhum']),
|
|
1234
|
+
'',
|
|
1235
|
+
'## Tentativas incompletas',
|
|
1082
1236
|
'',
|
|
1083
1237
|
...(recoverySummary.consistency && Array.isArray(recoverySummary.consistency.incomplete_attempts) && recoverySummary.consistency.incomplete_attempts.length
|
|
1084
1238
|
? recoverySummary.consistency.incomplete_attempts.map((item) => `- ${item.work_item_id} · ${item.attempt_id || 'attempt'} · ${item.outcome || 'unknown'}`)
|
|
@@ -1441,13 +1595,14 @@ function recoverRuntimeState(projectRoot, activeSession, options = {}) {
|
|
|
1441
1595
|
journal,
|
|
1442
1596
|
verificationArtifacts
|
|
1443
1597
|
);
|
|
1444
|
-
const recoverySummary = {
|
|
1445
|
-
recovered_at: new Date().toISOString(),
|
|
1446
|
-
journal_state: journal.scheduler_state,
|
|
1447
|
-
orphan_work_items: orphanWorkItems,
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1598
|
+
const recoverySummary = {
|
|
1599
|
+
recovered_at: new Date().toISOString(),
|
|
1600
|
+
journal_state: journal.scheduler_state,
|
|
1601
|
+
orphan_work_items: orphanWorkItems,
|
|
1602
|
+
orphan_worktrees: detectOrphanWorktrees(projectRoot, current.run_id),
|
|
1603
|
+
pending_gates: readRuntimeGates(projectRoot, activeSession, { runId: current.run_id }).pending.map((gate) => gate.gate_id),
|
|
1604
|
+
consistency,
|
|
1605
|
+
};
|
|
1451
1606
|
const runDir = path.join(projectRoot, '.oxe', 'runs', current.run_id);
|
|
1452
1607
|
ensureDir(runDir);
|
|
1453
1608
|
const recoverySummaryPath = path.join(runDir, 'recovery-summary.json');
|
|
@@ -2329,8 +2484,9 @@ module.exports = {
|
|
|
2329
2484
|
buildRecoveryConsistency,
|
|
2330
2485
|
readRuntimeGates,
|
|
2331
2486
|
resolveRuntimeGate,
|
|
2332
|
-
createExecutionContext,
|
|
2333
|
-
|
|
2487
|
+
createExecutionContext,
|
|
2488
|
+
buildRuntimeExecutePreflight,
|
|
2489
|
+
runRuntimeExecute,
|
|
2334
2490
|
runRuntimeVerify,
|
|
2335
2491
|
projectRuntimeArtifacts,
|
|
2336
2492
|
runRuntimeCiChecks,
|
|
@@ -658,6 +658,8 @@ function oxePaths(target) {
|
|
|
658
658
|
referenceAnchors: path.join(oxe, 'REFERENCE-ANCHORS.md'),
|
|
659
659
|
fixturePackMd: path.join(oxe, 'FIXTURE-PACK.md'),
|
|
660
660
|
fixturePackJson: path.join(oxe, 'FIXTURE-PACK.json'),
|
|
661
|
+
visualInputsMd: path.join(oxe, 'investigations', 'visual', 'VISUAL-INPUTS.md'),
|
|
662
|
+
visualInputsJson: path.join(oxe, 'investigations', 'visual', 'VISUAL-INPUTS.json'),
|
|
661
663
|
quick: path.join(oxe, 'QUICK.md'),
|
|
662
664
|
verify: path.join(oxe, 'VERIFY.md'),
|
|
663
665
|
discuss: path.join(oxe, 'DISCUSS.md'),
|
|
@@ -700,6 +702,8 @@ function scopedOxePaths(target, activeSession) {
|
|
|
700
702
|
referenceAnchors: path.join(sessionRoot, 'plan', 'REFERENCE-ANCHORS.md'),
|
|
701
703
|
fixturePackMd: path.join(sessionRoot, 'plan', 'FIXTURE-PACK.md'),
|
|
702
704
|
fixturePackJson: path.join(sessionRoot, 'plan', 'FIXTURE-PACK.json'),
|
|
705
|
+
visualInputsMd: path.join(sessionRoot, 'research', 'investigations', 'visual', 'VISUAL-INPUTS.md'),
|
|
706
|
+
visualInputsJson: path.join(sessionRoot, 'research', 'investigations', 'visual', 'VISUAL-INPUTS.json'),
|
|
703
707
|
quick: path.join(sessionRoot, 'plan', 'QUICK.md'),
|
|
704
708
|
verify: path.join(sessionRoot, 'verification', 'VERIFY.md'),
|
|
705
709
|
summary: path.join(sessionRoot, 'verification', 'SUMMARY.md'),
|
|
@@ -741,6 +745,8 @@ function resolvedReadableOxePaths(target, activeSession) {
|
|
|
741
745
|
referenceAnchors: preferScoped('referenceAnchors'),
|
|
742
746
|
fixturePackMd: preferScoped('fixturePackMd'),
|
|
743
747
|
fixturePackJson: preferScoped('fixturePackJson'),
|
|
748
|
+
visualInputsMd: preferScoped('visualInputsMd'),
|
|
749
|
+
visualInputsJson: preferScoped('visualInputsJson'),
|
|
744
750
|
quick: preferScoped('quick'),
|
|
745
751
|
verify: preferScoped('verify'),
|
|
746
752
|
summary: preferScoped('summary'),
|
|
@@ -1317,8 +1323,8 @@ function listOxePromptFiles(dir) {
|
|
|
1317
1323
|
if (!fs.existsSync(dir)) return [];
|
|
1318
1324
|
return fs
|
|
1319
1325
|
.readdirSync(dir, { withFileTypes: true })
|
|
1320
|
-
.filter((entry) => entry.isFile() && /^oxe-.*\.prompt\.md$/i.test(entry.name))
|
|
1321
|
-
.map((entry) => path.join(dir, entry.name))
|
|
1326
|
+
.filter((entry) => entry.isFile() && (entry.name === 'oxe.prompt.md' || /^oxe-.*\.prompt\.md$/i.test(entry.name)))
|
|
1327
|
+
.map((entry) => path.join(dir, entry.name))
|
|
1322
1328
|
.sort();
|
|
1323
1329
|
}
|
|
1324
1330
|
|
|
@@ -1439,9 +1445,9 @@ function copilotIntegrationReport(target) {
|
|
|
1439
1445
|
if (legacyHasOxeBlock) {
|
|
1440
1446
|
warnings.push('Bloco OXE legado detectado em ~/.copilot/copilot-instructions.md');
|
|
1441
1447
|
}
|
|
1442
|
-
if (legacyHasOtherManagedBlocks) {
|
|
1443
|
-
warnings.push('copilot-instructions global contém blocos geridos por outro framework; isso pode contaminar respostas do Copilot');
|
|
1444
|
-
}
|
|
1448
|
+
if (legacyHasOtherManagedBlocks) {
|
|
1449
|
+
warnings.push('copilot-instructions global contém blocos geridos por outro framework; isso pode contaminar respostas do Copilot — execute `oxe-cc uninstall --copilot-legacy-clean` se quiser limpar o legado global.');
|
|
1450
|
+
}
|
|
1445
1451
|
if (!manifestRaw.ok && fs.existsSync(workspace.manifest)) {
|
|
1446
1452
|
warnings.push(`Manifesto Copilot VS Code inválido: ${manifestRaw.error}`);
|
|
1447
1453
|
} else if (!fs.existsSync(workspace.manifest) && workspacePromptFiles.length > 0) {
|
|
@@ -1856,11 +1862,14 @@ function planSelfEvaluationWarnings(planPath, threshold) {
|
|
|
1856
1862
|
* implementationPackReady: boolean,
|
|
1857
1863
|
* referenceAnchorsReady: boolean,
|
|
1858
1864
|
* fixturePackReady: boolean,
|
|
1865
|
+
* visualInputReadiness?: string,
|
|
1866
|
+
* visualInputsReady?: boolean,
|
|
1859
1867
|
* executionRationalityReady: boolean,
|
|
1860
1868
|
* criticalExecutionGaps: string[],
|
|
1861
1869
|
* implementationPack: { path?: string | null, tasks?: unknown[] } | null,
|
|
1862
1870
|
* referenceAnchors: { path?: string | null, anchors?: unknown[], missingCriticalCount?: number } | null,
|
|
1863
1871
|
* fixturePack: { path?: string | null, fixtures?: unknown[] } | null,
|
|
1872
|
+
* visualInputs?: { path?: string | null, inputCount?: number, criticalInputCount?: number } | null,
|
|
1864
1873
|
* }} summary
|
|
1865
1874
|
* @returns {string[]}
|
|
1866
1875
|
*/
|
|
@@ -1877,6 +1886,9 @@ function executionRationalityWarningsFromSummary(summary) {
|
|
|
1877
1886
|
if (!summary.fixturePackReady) {
|
|
1878
1887
|
warns.push(`FIXTURE-PACK não está pronto em ${summary.fixturePack && summary.fixturePack.path ? summary.fixturePack.path : '.oxe/FIXTURE-PACK.json'}`);
|
|
1879
1888
|
}
|
|
1889
|
+
if (summary.visualInputReadiness === 'blocked') {
|
|
1890
|
+
warns.push(`VISUAL-INPUTS bloqueado em ${summary.visualInputs && summary.visualInputs.path ? summary.visualInputs.path : '.oxe/investigations/visual/VISUAL-INPUTS.json'}`);
|
|
1891
|
+
}
|
|
1880
1892
|
if (Array.isArray(summary.criticalExecutionGaps) && summary.criticalExecutionGaps.length) {
|
|
1881
1893
|
warns.push(...summary.criticalExecutionGaps);
|
|
1882
1894
|
}
|
|
@@ -2070,8 +2082,10 @@ function suggestNextStep(target, cfg = {}) {
|
|
|
2070
2082
|
artifacts: [
|
|
2071
2083
|
'.oxe/release/release-manifest.json',
|
|
2072
2084
|
'.oxe/release/runtime-smoke-report.json',
|
|
2085
|
+
'.oxe/release/runtime-real-report.json',
|
|
2073
2086
|
'.oxe/release/recovery-fixture-report.json',
|
|
2074
2087
|
'.oxe/release/multi-agent-soak-report.json',
|
|
2088
|
+
'.oxe/release/multi-agent-real-report.json',
|
|
2075
2089
|
],
|
|
2076
2090
|
};
|
|
2077
2091
|
}
|
|
@@ -2189,6 +2203,9 @@ function suggestNextStep(target, cfg = {}) {
|
|
|
2189
2203
|
referenceAnchors: p.referenceAnchors,
|
|
2190
2204
|
fixturePackJson: p.fixturePackJson,
|
|
2191
2205
|
fixturePackMd: p.fixturePackMd,
|
|
2206
|
+
spec: p.spec,
|
|
2207
|
+
visualInputsJson: p.visualInputsJson,
|
|
2208
|
+
visualInputsMd: p.visualInputsMd,
|
|
2192
2209
|
});
|
|
2193
2210
|
if (
|
|
2194
2211
|
shouldEnforceExecutionRationalityGate(phase)
|
|
@@ -2366,6 +2383,9 @@ function buildHealthReport(target) {
|
|
|
2366
2383
|
referenceAnchors: p.referenceAnchors,
|
|
2367
2384
|
fixturePackJson: p.fixturePackJson,
|
|
2368
2385
|
fixturePackMd: p.fixturePackMd,
|
|
2386
|
+
spec: p.spec,
|
|
2387
|
+
visualInputsJson: p.visualInputsJson,
|
|
2388
|
+
visualInputsMd: p.visualInputsMd,
|
|
2369
2389
|
});
|
|
2370
2390
|
const suppressExecutionWorkspaceGates = shouldSuppressExecutionWorkspaceGates(
|
|
2371
2391
|
workspaceInfo.workspaceMode,
|
|
@@ -2518,10 +2538,22 @@ function buildHealthReport(target) {
|
|
|
2518
2538
|
contextQuality.primaryStatus = contextPacks[firstWorkflow].context_quality.status;
|
|
2519
2539
|
}
|
|
2520
2540
|
}
|
|
2521
|
-
} catch (err) {
|
|
2522
|
-
contextWarn.push(`Contexto — falha ao inspecionar context packs: ${err instanceof Error ? err.message : String(err)}`);
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2541
|
+
} catch (err) {
|
|
2542
|
+
contextWarn.push(`Contexto — falha ao inspecionar context packs: ${err instanceof Error ? err.message : String(err)}`);
|
|
2543
|
+
}
|
|
2544
|
+
if (suppressExecutionWorkspaceGates) {
|
|
2545
|
+
for (const key of Object.keys(contextPacks)) delete contextPacks[key];
|
|
2546
|
+
for (const key of Object.keys(packFreshness)) delete packFreshness[key];
|
|
2547
|
+
contextWarn.length = 0;
|
|
2548
|
+
activeSummaryRefs = { project: null, session: null, phase: null };
|
|
2549
|
+
contextQuality = {
|
|
2550
|
+
primaryWorkflow: 'release',
|
|
2551
|
+
primaryScore: null,
|
|
2552
|
+
primaryStatus: 'not_applicable',
|
|
2553
|
+
byWorkflow: {},
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
const semanticsManifest = readJsonFileSafe(base.runtimeSemanticsManifest);
|
|
2525
2557
|
const semanticsAudit = runtimeSemantics.auditRuntimeTargets(target);
|
|
2526
2558
|
/** @type {string[]} */
|
|
2527
2559
|
const semanticsWarn = [];
|
|
@@ -2624,6 +2656,8 @@ function buildHealthReport(target) {
|
|
|
2624
2656
|
implementationPackReady: executionRationality.implementationPackReady,
|
|
2625
2657
|
referenceAnchorsReady: executionRationality.referenceAnchorsReady,
|
|
2626
2658
|
fixturePackReady: executionRationality.fixturePackReady,
|
|
2659
|
+
visualInputReadiness: executionRationality.visualInputReadiness,
|
|
2660
|
+
visualInputsReady: executionRationality.visualInputsReady,
|
|
2627
2661
|
executionRationalityReady: executionRationality.executionRationalityReady,
|
|
2628
2662
|
criticalExecutionGaps: executionRationality.criticalExecutionGaps,
|
|
2629
2663
|
executionRationality,
|