oxe-cc 1.4.0 → 1.5.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 (142) hide show
  1. package/.cursor/commands/oxe-ask.md +4 -2
  2. package/.cursor/commands/oxe-capabilities.md +4 -2
  3. package/.cursor/commands/oxe-checkpoint.md +4 -2
  4. package/.cursor/commands/oxe-compact.md +4 -2
  5. package/.cursor/commands/oxe-dashboard.md +4 -2
  6. package/.cursor/commands/oxe-debug.md +4 -2
  7. package/.cursor/commands/oxe-discuss.md +4 -2
  8. package/.cursor/commands/oxe-execute.md +5 -3
  9. package/.cursor/commands/oxe-forensics.md +4 -2
  10. package/.cursor/commands/oxe-help.md +4 -2
  11. package/.cursor/commands/oxe-loop.md +4 -2
  12. package/.cursor/commands/oxe-milestone.md +4 -2
  13. package/.cursor/commands/oxe-next.md +4 -2
  14. package/.cursor/commands/oxe-obs.md +4 -2
  15. package/.cursor/commands/oxe-plan-agent.md +4 -2
  16. package/.cursor/commands/oxe-plan.md +4 -2
  17. package/.cursor/commands/oxe-project.md +4 -2
  18. package/.cursor/commands/oxe-quick.md +4 -2
  19. package/.cursor/commands/oxe-research.md +4 -2
  20. package/.cursor/commands/oxe-retro.md +4 -2
  21. package/.cursor/commands/oxe-review-pr.md +4 -2
  22. package/.cursor/commands/oxe-route.md +4 -2
  23. package/.cursor/commands/oxe-scan.md +4 -2
  24. package/.cursor/commands/oxe-security.md +4 -2
  25. package/.cursor/commands/oxe-session.md +5 -3
  26. package/.cursor/commands/oxe-ship.md +4 -2
  27. package/.cursor/commands/oxe-skill.md +4 -2
  28. package/.cursor/commands/oxe-spec.md +4 -2
  29. package/.cursor/commands/oxe-ui-review.md +4 -2
  30. package/.cursor/commands/oxe-ui-spec.md +4 -2
  31. package/.cursor/commands/oxe-update.md +4 -2
  32. package/.cursor/commands/oxe-validate-gaps.md +4 -2
  33. package/.cursor/commands/oxe-verify-audit.md +46 -0
  34. package/.cursor/commands/oxe-verify.md +4 -2
  35. package/.cursor/commands/oxe-workflow-authoring.md +47 -0
  36. package/.cursor/commands/oxe-workstream.md +4 -2
  37. package/.cursor/commands/oxe.md +6 -2
  38. package/.github/prompts/oxe-ask.prompt.md +4 -2
  39. package/.github/prompts/oxe-capabilities.prompt.md +4 -2
  40. package/.github/prompts/oxe-checkpoint.prompt.md +4 -2
  41. package/.github/prompts/oxe-compact.prompt.md +5 -3
  42. package/.github/prompts/oxe-dashboard.prompt.md +4 -2
  43. package/.github/prompts/oxe-debug.prompt.md +4 -2
  44. package/.github/prompts/oxe-discuss.prompt.md +6 -2
  45. package/.github/prompts/oxe-execute.prompt.md +5 -3
  46. package/.github/prompts/oxe-forensics.prompt.md +4 -2
  47. package/.github/prompts/oxe-help.prompt.md +6 -2
  48. package/.github/prompts/oxe-loop.prompt.md +4 -2
  49. package/.github/prompts/oxe-milestone.prompt.md +4 -2
  50. package/.github/prompts/oxe-next.prompt.md +6 -2
  51. package/.github/prompts/oxe-obs.prompt.md +4 -2
  52. package/.github/prompts/oxe-plan-agent.prompt.md +5 -2
  53. package/.github/prompts/oxe-plan.prompt.md +4 -2
  54. package/.github/prompts/oxe-project.prompt.md +4 -2
  55. package/.github/prompts/oxe-quick.prompt.md +4 -2
  56. package/.github/prompts/oxe-research.prompt.md +4 -2
  57. package/.github/prompts/oxe-retro.prompt.md +4 -2
  58. package/.github/prompts/oxe-review-pr.prompt.md +4 -2
  59. package/.github/prompts/oxe-route.prompt.md +4 -2
  60. package/.github/prompts/oxe-scan.prompt.md +4 -2
  61. package/.github/prompts/oxe-security.prompt.md +4 -2
  62. package/.github/prompts/oxe-session.prompt.md +5 -3
  63. package/.github/prompts/oxe-ship.prompt.md +4 -2
  64. package/.github/prompts/oxe-skill.prompt.md +4 -2
  65. package/.github/prompts/oxe-spec.prompt.md +4 -2
  66. package/.github/prompts/oxe-ui-review.prompt.md +4 -2
  67. package/.github/prompts/oxe-ui-spec.prompt.md +4 -2
  68. package/.github/prompts/oxe-update.prompt.md +4 -2
  69. package/.github/prompts/oxe-validate-gaps.prompt.md +4 -2
  70. package/.github/prompts/oxe-verify-audit.prompt.md +46 -0
  71. package/.github/prompts/oxe-verify.prompt.md +4 -2
  72. package/.github/prompts/oxe-workflow-authoring.prompt.md +47 -0
  73. package/.github/prompts/oxe-workstream.prompt.md +4 -2
  74. package/.github/prompts/oxe.prompt.md +6 -2
  75. package/.github/workflows/ci.yml +57 -20
  76. package/.github/workflows/release.yml +94 -0
  77. package/AGENTS.md +3 -1
  78. package/CHANGELOG.md +383 -342
  79. package/QUICKSTART.md +99 -0
  80. package/README.md +89 -65
  81. package/bin/lib/oxe-agent-install.cjs +127 -107
  82. package/bin/lib/oxe-install-resolve.cjs +10 -0
  83. package/bin/lib/oxe-operational.cjs +34 -28
  84. package/bin/lib/oxe-project-health.cjs +38 -6
  85. package/bin/lib/oxe-release.cjs +423 -0
  86. package/bin/lib/oxe-runtime-semantics.cjs +68 -24
  87. package/bin/oxe-cc.js +388 -55
  88. package/commands/oxe/ask.md +7 -3
  89. package/commands/oxe/capabilities.md +6 -2
  90. package/commands/oxe/checkpoint.md +5 -1
  91. package/commands/oxe/compact.md +6 -2
  92. package/commands/oxe/dashboard.md +6 -2
  93. package/commands/oxe/debug.md +6 -2
  94. package/commands/oxe/discuss.md +6 -2
  95. package/commands/oxe/execute.md +6 -2
  96. package/commands/oxe/forensics.md +6 -2
  97. package/commands/oxe/help.md +6 -2
  98. package/commands/oxe/loop.md +6 -2
  99. package/commands/oxe/milestone.md +6 -2
  100. package/commands/oxe/next.md +6 -2
  101. package/commands/oxe/obs.md +6 -2
  102. package/commands/oxe/oxe.md +6 -2
  103. package/commands/oxe/plan-agent.md +6 -2
  104. package/commands/oxe/plan.md +6 -2
  105. package/commands/oxe/project.md +6 -2
  106. package/commands/oxe/quick.md +6 -2
  107. package/commands/oxe/research.md +6 -2
  108. package/commands/oxe/retro.md +6 -2
  109. package/commands/oxe/review-pr.md +6 -2
  110. package/commands/oxe/route.md +6 -2
  111. package/commands/oxe/scan.md +6 -2
  112. package/commands/oxe/security.md +6 -2
  113. package/commands/oxe/session.md +6 -2
  114. package/commands/oxe/ship.md +6 -2
  115. package/commands/oxe/skill.md +6 -2
  116. package/commands/oxe/spec.md +6 -2
  117. package/commands/oxe/ui-review.md +6 -2
  118. package/commands/oxe/ui-spec.md +6 -2
  119. package/commands/oxe/update.md +6 -2
  120. package/commands/oxe/validate-gaps.md +6 -2
  121. package/commands/oxe/verify-audit.md +50 -0
  122. package/commands/oxe/verify.md +6 -2
  123. package/commands/oxe/workflow-authoring.md +50 -0
  124. package/commands/oxe/workstream.md +6 -2
  125. package/docs/INCIDENT-PLAYBOOK.md +181 -0
  126. package/docs/RELEASE-READINESS.md +46 -0
  127. package/docs/ROLES.md +129 -0
  128. package/docs/RUNTIME-SMOKE-MATRIX.md +128 -0
  129. package/docs/TEAM-ADOPTION.md +153 -0
  130. package/docs/WALKTHROUGH.md +241 -0
  131. package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +28 -0
  132. package/lib/runtime/scheduler/multi-agent-coordinator.js +152 -26
  133. package/lib/sdk/README.md +2 -0
  134. package/lib/sdk/index.cjs +22 -8
  135. package/lib/sdk/index.d.ts +60 -16
  136. package/oxe/templates/config.template.json +1 -0
  137. package/package.json +30 -22
  138. package/packages/runtime/package.json +1 -1
  139. package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +357 -193
  140. package/vscode-extension/oxe-agents-1.4.0.vsix +0 -0
  141. package/vscode-extension/oxe-agents-1.5.0.vsix +0 -0
  142. package/vscode-extension/package.json +1 -1
@@ -0,0 +1,241 @@
1
+ # OXE — Walkthrough Reproduzível
2
+
3
+ > Feature: "Adicionar endpoint REST `GET /api/items` de listagem paginada"
4
+ >
5
+ > Tempo estimado: 20 minutos. Todos os comandos são reproduzíveis — copie e execute.
6
+
7
+ ---
8
+
9
+ ## Pré-requisitos
10
+
11
+ ```bash
12
+ npx oxe-cc doctor
13
+ # ✓ Node 18+
14
+ # ✓ Workflows presentes
15
+ # ✓ Estrutura base .oxe/
16
+ ```
17
+
18
+ Se algum item falhar, siga o conselho exibido antes de continuar.
19
+
20
+ ---
21
+
22
+ ## Passo 1 — Descobrir onde você está
23
+
24
+ ```
25
+ /oxe
26
+ ```
27
+
28
+ **Output esperado (projeto novo):**
29
+ ```
30
+ Estado atual: init
31
+ Próximo passo recomendado: /oxe-scan
32
+ Motivo: nenhum mapeamento de codebase encontrado em .oxe/codebase/
33
+ ```
34
+
35
+ **Artefato gerado:** nenhum (apenas diagnóstico)
36
+
37
+ ---
38
+
39
+ ## Passo 2 — Mapear o codebase
40
+
41
+ ```
42
+ /oxe-scan
43
+ ```
44
+
45
+ **Output esperado:**
46
+ ```
47
+ Scan completo.
48
+ Arquivos mapeados: 47
49
+ Módulos detectados: routes/, controllers/, services/, tests/
50
+ Artefato: .oxe/codebase/map.json
51
+ ```
52
+
53
+ **Artefato gerado:** `.oxe/codebase/map.json`
54
+
55
+ ---
56
+
57
+ ## Passo 3 — Gerar critérios de aceite
58
+
59
+ ```
60
+ /oxe-spec
61
+
62
+ > Adicionar endpoint GET /api/items com paginação (page, limit). Retornar lista de items e metadados de paginação.
63
+ ```
64
+
65
+ **Output esperado:**
66
+ ```
67
+ SPEC.md gerado.
68
+ Critérios A* (bloqueantes):
69
+ A1. GET /api/items retorna 200 com lista de items
70
+ A2. Parâmetros page e limit são aceitos e validados
71
+ A3. Resposta inclui { items: [...], total, page, limit }
72
+ A4. Testes de integração cobrem os 3 critérios acima
73
+
74
+ Critérios B (desejáveis):
75
+ B1. Cursor inválido retorna 400 com mensagem clara
76
+ B2. Documentação OpenAPI atualizada
77
+ ```
78
+
79
+ **Artefato gerado:** `.oxe/SPEC.md`
80
+
81
+ Revise os critérios. Se estiverem corretos, avance.
82
+
83
+ ---
84
+
85
+ ## Passo 4 — Planejar a implementação
86
+
87
+ ```
88
+ /oxe-plan
89
+ ```
90
+
91
+ **Output esperado:**
92
+ ```
93
+ PLAN.md gerado.
94
+ Onda 1 (obrigatória):
95
+ T1. Criar route GET /api/items em routes/items.js
96
+ T2. Implementar ItemsController.list() com paginação
97
+ T3. Implementar ItemsService.findPaginated(page, limit)
98
+ T4. Escrever testes de integração para os 3 critérios A*
99
+
100
+ Hipótese crítica: ItemsService tem acesso ao repositório de dados correto
101
+ Arquivos-alvo: routes/items.js, controllers/items.js, services/items.js, tests/items.test.js
102
+ ```
103
+
104
+ **Artefato gerado:** `.oxe/PLAN.md`
105
+
106
+ ---
107
+
108
+ ## Passo 5 — Implementar
109
+
110
+ ```
111
+ /oxe-execute
112
+ ```
113
+
114
+ O executor vai implementar T1→T4 em sequência, marcando cada tarefa concluída.
115
+
116
+ **Output esperado ao final:**
117
+ ```
118
+ Onda 1 completa.
119
+ T1 ✓ routes/items.js — route criada
120
+ T2 ✓ controllers/items.js — ItemsController.list() implementado
121
+ T3 ✓ services/items.js — ItemsService.findPaginated() implementado
122
+ T4 ✓ tests/items.test.js — 4 testes de integração passando
123
+
124
+ Estado: execute_complete
125
+ ```
126
+
127
+ **Para executar uma tarefa específica:**
128
+ ```
129
+ /oxe-execute --task T3
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Passo 6 — Verificar
135
+
136
+ ```
137
+ /oxe-verify
138
+ ```
139
+
140
+ **Output esperado:**
141
+ ```
142
+ Verificação completa.
143
+
144
+ A1 ✓ GET /api/items retorna 200 — evidência: tests/items.test.js:12
145
+ A2 ✓ Parâmetros page e limit validados — evidência: controllers/items.js:34
146
+ A3 ✓ Resposta inclui {items, total, page, limit} — evidência: controllers/items.js:41
147
+ A4 ✓ Testes cobrem A1–A3 — evidência: tests/items.test.js (4 testes)
148
+
149
+ Riscos residuais: nenhum
150
+ Estado: verify_complete
151
+ ```
152
+
153
+ **Artefato gerado:** `.oxe/VERIFY.md`
154
+
155
+ ---
156
+
157
+ ## Passo 7 — Gate de aprovação (opcional, runtime-first)
158
+
159
+ Se o projeto usa runtime gates:
160
+
161
+ ```bash
162
+ npx oxe-cc runtime gates list --dir .
163
+ ```
164
+
165
+ **Output esperado:**
166
+ ```
167
+ Gates pendentes: 1
168
+ ⏳ gate-001 tipo: verify_complete estado: pending
169
+ ação sugerida: approve
170
+ impacto: bloqueia promoção para pr_draft
171
+ ```
172
+
173
+ Para aprovar:
174
+ ```bash
175
+ npx oxe-cc runtime gates resolve --dir . --gate gate-001 --decision approve --actor "seu-nome"
176
+ ```
177
+
178
+ **Output esperado:**
179
+ ```
180
+ ✓ Gate gate-001 aprovado.
181
+ Run pode avançar para promoção — nenhum gate restante.
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Passo 8 — Promover para PR draft
187
+
188
+ ```bash
189
+ npx oxe-cc runtime promote --dir . --target pr_draft
190
+ ```
191
+
192
+ **Output esperado:**
193
+ ```
194
+ Promoção para pr_draft iniciada.
195
+ Branch: feature/items-endpoint
196
+ VERIFY.md incluído como evidência
197
+ PR draft criado: https://github.com/seu-org/repo/pull/42
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Estado final dos artefatos
203
+
204
+ ```
205
+ .oxe/
206
+ ├── STATE.md # fase: verify_complete (ou pr_draft após promote)
207
+ ├── SPEC.md # critérios A1–A4 + B1–B2
208
+ ├── PLAN.md # ondas e tarefas T1–T4
209
+ ├── VERIFY.md # evidências para cada critério A*
210
+ └── codebase/
211
+ └── map.json # mapa do projeto
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Validação rápida
217
+
218
+ ```bash
219
+ npx oxe-cc status
220
+ ```
221
+
222
+ **Output esperado:**
223
+ ```
224
+ Estado: verify_complete
225
+ Próximo passo: runtime promote --target pr_draft (ou abrir PR manualmente)
226
+ SPEC: 4 critérios A* — todos verificados
227
+ VERIFY.md: presente
228
+ Gates pendentes: 0
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Se algo der errado
234
+
235
+ | Sintoma | Comando |
236
+ |---------|---------|
237
+ | Travado em uma tarefa | `/oxe-debug` |
238
+ | Critério A* não verificado | `/oxe-verify` + revisar implementação |
239
+ | Gate stale (>24h) | Ver [`docs/INCIDENT-PLAYBOOK.md`](INCIDENT-PLAYBOOK.md) |
240
+ | Plano desatualizado | `/oxe-plan` novamente (sobrescreve PLAN.md) |
241
+ | Estado incoerente | `npx oxe-cc status --full` + `/oxe` para rediagnóstico |
@@ -17,6 +17,7 @@ export interface CoordinationOptions {
17
17
  sessionId: string | null;
18
18
  runId: string;
19
19
  onEvent?: SchedulerContext['onEvent'];
20
+ heartbeatTimeoutMs?: number;
20
21
  }
21
22
  export interface ArbitrationRecord {
22
23
  work_item_id: string;
@@ -48,12 +49,36 @@ export interface MultiAgentStatusSnapshot {
48
49
  assigned_task_ids: string[];
49
50
  completed: string[];
50
51
  failed: string[];
52
+ timed_out: boolean;
53
+ reassigned_task_ids: string[];
51
54
  }>;
52
55
  orphan_reassignments: Array<{
53
56
  from_agent_id: string;
54
57
  to_agent_id: string;
55
58
  work_item_ids: string[];
56
59
  }>;
60
+ timed_out_agents: Array<{
61
+ agent_id: string;
62
+ work_item_ids: string[];
63
+ detected_at: string;
64
+ }>;
65
+ updated_at: string;
66
+ }
67
+ export interface MultiAgentOperationalSummary {
68
+ run_id: string;
69
+ mode: CoordinationMode;
70
+ workspace_isolation_enforced: boolean;
71
+ agent_count: number;
72
+ completed_count: number;
73
+ failed_count: number;
74
+ blocked_count: number;
75
+ ownership_count: number;
76
+ handoff_count: number;
77
+ arbitration_count: number;
78
+ orphan_reassignment_count: number;
79
+ timeout_count: number;
80
+ participating_agents: string[];
81
+ health: 'healthy' | 'degraded';
57
82
  updated_at: string;
58
83
  }
59
84
  export interface CoordinationResult {
@@ -70,9 +95,12 @@ export interface CoordinationResult {
70
95
  handoffs?: CooperativeHandoff[];
71
96
  arbitration_results?: ArbitrationRecord[];
72
97
  state?: MultiAgentStatusSnapshot;
98
+ summary?: MultiAgentOperationalSummary;
73
99
  }
74
100
  export declare class MultiAgentCoordinator {
75
101
  run(graph: ExecutionGraph, opts: CoordinationOptions): Promise<CoordinationResult>;
76
102
  }
77
103
  export declare function multiAgentStatePath(projectRoot: string, runId: string): string;
104
+ export declare function multiAgentSummaryPath(projectRoot: string, runId: string): string;
78
105
  export declare function loadMultiAgentState(projectRoot: string, runId: string): MultiAgentStatusSnapshot | null;
106
+ export declare function loadMultiAgentSummary(projectRoot: string, runId: string): MultiAgentOperationalSummary | null;
@@ -5,12 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.MultiAgentCoordinator = void 0;
7
7
  exports.multiAgentStatePath = multiAgentStatePath;
8
+ exports.multiAgentSummaryPath = multiAgentSummaryPath;
8
9
  exports.loadMultiAgentState = loadMultiAgentState;
10
+ exports.loadMultiAgentSummary = loadMultiAgentSummary;
9
11
  const fs_1 = __importDefault(require("fs"));
10
12
  const path_1 = __importDefault(require("path"));
11
13
  const bus_1 = require("../events/bus");
12
14
  const scheduler_1 = require("./scheduler");
13
15
  const agent_roles_1 = require("./agent-roles");
16
+ const agent_registry_1 = require("./agent-registry");
14
17
  function ensureRunDir(projectRoot, runId) {
15
18
  const dir = path_1.default.join(projectRoot, '.oxe', 'runs', runId);
16
19
  fs_1.default.mkdirSync(dir, { recursive: true });
@@ -21,6 +24,24 @@ function persistMultiAgentArtifacts(projectRoot, runId, state, handoffs = [], ar
21
24
  fs_1.default.writeFileSync(path_1.default.join(runDir, 'multi-agent-state.json'), JSON.stringify(state, null, 2), 'utf8');
22
25
  fs_1.default.writeFileSync(path_1.default.join(runDir, 'handoffs.json'), JSON.stringify(handoffs, null, 2), 'utf8');
23
26
  fs_1.default.writeFileSync(path_1.default.join(runDir, 'arbitration-results.json'), JSON.stringify(arbitrationResults, null, 2), 'utf8');
27
+ const summary = {
28
+ run_id: state.run_id,
29
+ mode: state.mode,
30
+ workspace_isolation_enforced: state.workspace_isolation_enforced,
31
+ agent_count: state.agent_count,
32
+ completed_count: state.completed.length,
33
+ failed_count: state.failed.length,
34
+ blocked_count: state.blocked.length,
35
+ ownership_count: state.ownership.length,
36
+ handoff_count: handoffs.length,
37
+ arbitration_count: arbitrationResults.length,
38
+ orphan_reassignment_count: state.orphan_reassignments.length,
39
+ timeout_count: state.timed_out_agents.length,
40
+ participating_agents: state.agent_results.map((entry) => entry.agent_id),
41
+ health: state.timed_out_agents.length > 0 || state.failed.length > 0 ? 'degraded' : 'healthy',
42
+ updated_at: state.updated_at,
43
+ };
44
+ fs_1.default.writeFileSync(path_1.default.join(runDir, 'multi-agent-summary.json'), JSON.stringify(summary, null, 2), 'utf8');
24
45
  }
25
46
  function ensureIsolatedAgents(agents) {
26
47
  const shared = agents.filter((agent) => agent.workspaceManager.isolation_level !== 'isolated');
@@ -41,7 +62,7 @@ function buildOwnership(agents, partitions) {
41
62
  }
42
63
  return ownership;
43
64
  }
44
- function makeState(mode, runId, agents, partitions, agentResults, completed, failed, blocked, orphanReassignments) {
65
+ function makeState(mode, runId, agents, partitions, agentResults, completed, failed, blocked, orphanReassignments, timedOutAgents) {
45
66
  return {
46
67
  run_id: runId,
47
68
  mode,
@@ -60,16 +81,82 @@ function makeState(mode, runId, agents, partitions, agentResults, completed, fai
60
81
  assigned_task_ids: partitions[idx] ?? agent.assignedTaskIds ?? [],
61
82
  completed: result?.completed ?? [],
62
83
  failed: result?.failed ?? [],
84
+ timed_out: Boolean(result?.timed_out),
85
+ reassigned_task_ids: result?.reassigned_task_ids ?? [],
63
86
  };
64
87
  }),
65
88
  orphan_reassignments: orphanReassignments,
89
+ timed_out_agents: timedOutAgents,
66
90
  updated_at: new Date().toISOString(),
67
91
  };
68
92
  }
93
+ async function runGraphForAgent(graph, nodeIds, agent, idx, opts, heartbeatTimeoutMs) {
94
+ const subGraph = subGraphFor(graph, nodeIds);
95
+ if (subGraph.nodes.size === 0) {
96
+ return {
97
+ agent_id: agent.id,
98
+ completed: [],
99
+ failed: [],
100
+ timed_out: false,
101
+ assigned_task_ids: nodeIds,
102
+ reassigned_task_ids: [],
103
+ };
104
+ }
105
+ const ctx = {
106
+ projectRoot: opts.projectRoot,
107
+ sessionId: opts.sessionId,
108
+ runId: `${opts.runId}-agent${idx}`,
109
+ executor: agent.executor,
110
+ workspaceManager: agent.workspaceManager,
111
+ onEvent: opts.onEvent,
112
+ };
113
+ const scheduler = new scheduler_1.Scheduler();
114
+ const work = scheduler.run(subGraph, ctx);
115
+ if (!heartbeatTimeoutMs || heartbeatTimeoutMs <= 0) {
116
+ const result = await work;
117
+ return {
118
+ agent_id: agent.id,
119
+ completed: result.completed,
120
+ failed: result.failed,
121
+ timed_out: false,
122
+ assigned_task_ids: nodeIds,
123
+ reassigned_task_ids: [],
124
+ };
125
+ }
126
+ let timer = null;
127
+ const raced = await Promise.race([
128
+ work.then((result) => ({ type: 'result', result })),
129
+ new Promise((resolve) => {
130
+ timer = setTimeout(() => resolve({ type: 'timeout' }), heartbeatTimeoutMs);
131
+ }),
132
+ ]);
133
+ if (timer)
134
+ clearTimeout(timer);
135
+ if (raced && raced.type === 'timeout') {
136
+ return {
137
+ agent_id: agent.id,
138
+ completed: [],
139
+ failed: [],
140
+ timed_out: true,
141
+ assigned_task_ids: nodeIds,
142
+ reassigned_task_ids: [],
143
+ };
144
+ }
145
+ const result = raced.result;
146
+ return {
147
+ agent_id: agent.id,
148
+ completed: result.completed,
149
+ failed: result.failed,
150
+ timed_out: false,
151
+ assigned_task_ids: nodeIds,
152
+ reassigned_task_ids: [],
153
+ };
154
+ }
69
155
  // ─── Parallel mode ───────────────────────────────────────────────────────────
70
156
  async function runParallel(graph, opts) {
71
157
  const { agents, projectRoot, sessionId, runId } = opts;
72
158
  ensureIsolatedAgents(agents);
159
+ const heartbeatTimeoutMs = opts.heartbeatTimeoutMs ?? null;
73
160
  const partitions = agents.map((agent) => [...(agent.assignedTaskIds ?? [])]);
74
161
  if (partitions.every((partition) => partition.length === 0)) {
75
162
  const allIds = [...graph.nodes.keys()];
@@ -77,33 +164,55 @@ async function runParallel(graph, opts) {
77
164
  partitions[index % agents.length].push(id);
78
165
  });
79
166
  }
167
+ const registry = new agent_registry_1.AgentRegistry(heartbeatTimeoutMs == null ? 30000 : heartbeatTimeoutMs);
168
+ agents.forEach((agent, idx) => {
169
+ registry.register(agent.id, agent.executor, agent.workspaceManager, partitions[idx] ?? []);
170
+ });
80
171
  (0, bus_1.appendEvent)(projectRoot, sessionId, {
81
172
  type: 'RunStarted',
82
173
  run_id: runId,
83
174
  payload: { mode: 'parallel', agent_count: agents.length, isolation_level: 'isolated' },
84
175
  });
85
- const agentResults = await Promise.all(agents.map(async (agent, idx) => {
86
- const subGraph = subGraphFor(graph, partitions[idx]);
87
- if (subGraph.nodes.size === 0) {
88
- return { agent_id: agent.id, completed: [], failed: [] };
89
- }
90
- const ctx = {
91
- projectRoot,
92
- sessionId,
93
- runId: `${runId}-agent${idx}`,
94
- executor: agent.executor,
95
- workspaceManager: agent.workspaceManager,
96
- onEvent: opts.onEvent,
97
- };
98
- const scheduler = new scheduler_1.Scheduler();
99
- const result = await scheduler.run(subGraph, ctx);
100
- return { agent_id: agent.id, completed: result.completed, failed: result.failed };
176
+ const initialResults = await Promise.all(agents.map(async (agent, idx) => {
177
+ registry.beat(agent.id, partitions[idx][0] || null);
178
+ const result = await runGraphForAgent(graph, partitions[idx], agent, idx, opts, heartbeatTimeoutMs);
179
+ registry.setStatus(agent.id, result.timed_out ? 'timeout' : 'idle');
180
+ return result;
101
181
  }));
102
- const completed = agentResults.flatMap((result) => result.completed);
103
- const failed = agentResults.flatMap((result) => result.failed);
182
+ const timedOutAgents = [];
104
183
  const blocked = [];
105
184
  const orphanReassignments = [];
106
- const state = makeState('parallel', runId, agents, partitions, agentResults, completed, failed, blocked, orphanReassignments);
185
+ const agentResults = initialResults.map((entry) => ({
186
+ ...entry,
187
+ reassigned_task_ids: entry.reassigned_task_ids || [],
188
+ }));
189
+ const liveAgents = agentResults.filter((entry) => !entry.timed_out);
190
+ for (const timedOut of agentResults.filter((entry) => entry.timed_out)) {
191
+ timedOutAgents.push({
192
+ agent_id: timedOut.agent_id,
193
+ work_item_ids: timedOut.assigned_task_ids,
194
+ detected_at: new Date().toISOString(),
195
+ });
196
+ const fallback = liveAgents.find((entry) => entry.agent_id !== timedOut.agent_id);
197
+ if (!fallback || timedOut.assigned_task_ids.length === 0)
198
+ continue;
199
+ const fallbackIdx = agents.findIndex((agent) => agent.id === fallback.agent_id);
200
+ const timeoutIdx = agents.findIndex((agent) => agent.id === timedOut.agent_id);
201
+ const rerun = await runGraphForAgent(graph, timedOut.assigned_task_ids, agents[fallbackIdx], fallbackIdx, opts, null);
202
+ fallback.completed.push(...rerun.completed);
203
+ fallback.failed.push(...rerun.failed);
204
+ fallback.reassigned_task_ids.push(...timedOut.assigned_task_ids);
205
+ partitions[fallbackIdx] = [...partitions[fallbackIdx], ...timedOut.assigned_task_ids];
206
+ partitions[timeoutIdx] = [];
207
+ orphanReassignments.push({
208
+ from_agent_id: timedOut.agent_id,
209
+ to_agent_id: fallback.agent_id,
210
+ work_item_ids: timedOut.assigned_task_ids,
211
+ });
212
+ }
213
+ const completed = Array.from(new Set(agentResults.flatMap((result) => result.completed)));
214
+ const failed = Array.from(new Set(agentResults.flatMap((result) => result.failed)));
215
+ const state = makeState('parallel', runId, agents, partitions, agentResults, completed, failed, blocked, orphanReassignments, timedOutAgents);
107
216
  persistMultiAgentArtifacts(projectRoot, runId, state);
108
217
  (0, bus_1.appendEvent)(projectRoot, sessionId, {
109
218
  type: 'RunCompleted',
@@ -119,6 +228,7 @@ async function runParallel(graph, opts) {
119
228
  agent_results: agentResults,
120
229
  arbitration_results: [],
121
230
  state,
231
+ summary: loadMultiAgentSummary(projectRoot, runId) || undefined,
122
232
  };
123
233
  }
124
234
  // ─── Competitive mode ────────────────────────────────────────────────────────
@@ -154,9 +264,9 @@ async function runCompetitive(graph, opts) {
154
264
  }
155
265
  const partitions = [Array.from(graph.nodes.keys()), Array.from(graph.nodes.keys())];
156
266
  const state = makeState('competitive', runId, opts.agents, partitions, [
157
- { agent_id: agentA.id, completed, failed },
158
- { agent_id: agentB.id, completed: [], failed: [] },
159
- ], completed, failed, blocked, []);
267
+ { agent_id: agentA.id, completed, failed, timed_out: false, reassigned_task_ids: [] },
268
+ { agent_id: agentB.id, completed: [], failed: [], timed_out: false, reassigned_task_ids: [] },
269
+ ], completed, failed, blocked, [], []);
160
270
  persistMultiAgentArtifacts(projectRoot, runId, state, [], arbitrationResults);
161
271
  (0, bus_1.appendEvent)(projectRoot, sessionId, {
162
272
  type: 'RunCompleted',
@@ -175,6 +285,7 @@ async function runCompetitive(graph, opts) {
175
285
  ],
176
286
  arbitration_results: arbitrationResults,
177
287
  state,
288
+ summary: loadMultiAgentSummary(projectRoot, runId) || undefined,
178
289
  };
179
290
  }
180
291
  async function competeTwoAgents(nodeId, node, agentA, agentB, opts, arbitrationResults) {
@@ -294,9 +405,9 @@ async function runCooperative(graph, opts) {
294
405
  }
295
406
  const partitions = [Array.from(graph.nodes.keys()), Array.from(graph.nodes.keys())];
296
407
  const state = makeState('cooperative', runId, opts.agents, partitions, [
297
- { agent_id: planner.id, completed: [], failed: [] },
298
- { agent_id: executor.id, completed, failed },
299
- ], completed, failed, blocked, []);
408
+ { agent_id: planner.id, completed: [], failed: [], timed_out: false, reassigned_task_ids: [] },
409
+ { agent_id: executor.id, completed, failed, timed_out: false, reassigned_task_ids: [] },
410
+ ], completed, failed, blocked, [], []);
300
411
  persistMultiAgentArtifacts(projectRoot, runId, state, handoffs, []);
301
412
  (0, bus_1.appendEvent)(projectRoot, sessionId, {
302
413
  type: 'RunCompleted',
@@ -316,6 +427,7 @@ async function runCooperative(graph, opts) {
316
427
  handoffs,
317
428
  arbitration_results: [],
318
429
  state,
430
+ summary: loadMultiAgentSummary(projectRoot, runId) || undefined,
319
431
  };
320
432
  }
321
433
  // ─── Public API ──────────────────────────────────────────────────────────────
@@ -334,6 +446,9 @@ exports.MultiAgentCoordinator = MultiAgentCoordinator;
334
446
  function multiAgentStatePath(projectRoot, runId) {
335
447
  return path_1.default.join(projectRoot, '.oxe', 'runs', runId, 'multi-agent-state.json');
336
448
  }
449
+ function multiAgentSummaryPath(projectRoot, runId) {
450
+ return path_1.default.join(projectRoot, '.oxe', 'runs', runId, 'multi-agent-summary.json');
451
+ }
337
452
  function loadMultiAgentState(projectRoot, runId) {
338
453
  const statePath = multiAgentStatePath(projectRoot, runId);
339
454
  if (!fs_1.default.existsSync(statePath))
@@ -345,6 +460,17 @@ function loadMultiAgentState(projectRoot, runId) {
345
460
  return null;
346
461
  }
347
462
  }
463
+ function loadMultiAgentSummary(projectRoot, runId) {
464
+ const summaryPath = multiAgentSummaryPath(projectRoot, runId);
465
+ if (!fs_1.default.existsSync(summaryPath))
466
+ return null;
467
+ try {
468
+ return JSON.parse(fs_1.default.readFileSync(summaryPath, 'utf8'));
469
+ }
470
+ catch {
471
+ return null;
472
+ }
473
+ }
348
474
  // ─── Helpers ─────────────────────────────────────────────────────────────────
349
475
  function subGraphFor(graph, nodeIds) {
350
476
  const ids = new Set(nodeIds);
package/lib/sdk/README.md CHANGED
@@ -76,5 +76,7 @@ O SDK já expõe os helpers usados pela operação enterprise do OXE:
76
76
  - `operational.readRuntimeGates(...)` / `operational.resolveRuntimeGate(...)`
77
77
  - `operational.recoverRuntimeState(...)` / `operational.replayRuntimeState(...)`
78
78
  - `operational.readRuntimeMultiAgentStatus(...)` / `operational.multiAgentStatus(...)`
79
+ - `release.checkReleaseConsistency(...)` / `release.buildReleaseManifest(...)`
80
+ - `release.loadRuntimeSmokeReport(...)` / `release.loadRecoveryFixtureReport(...)` / `release.loadMultiAgentSoakReport(...)`
79
81
 
80
82
  Use esses helpers quando quiser integrar gates, verify, recovery e multi-agent a scripts de CI, automações internas ou observabilidade.
package/lib/sdk/index.cjs CHANGED
@@ -17,8 +17,9 @@ const plugins = require('../../bin/lib/oxe-plugins.cjs');
17
17
  const dashboard = require('../../bin/lib/oxe-dashboard.cjs');
18
18
  const operational = require('../../bin/lib/oxe-operational.cjs');
19
19
  const azure = require('../../bin/lib/oxe-azure.cjs');
20
- const context = require('../../bin/lib/oxe-context-engine.cjs');
21
- const runtimeSemantics = require('../../bin/lib/oxe-runtime-semantics.cjs');
20
+ const context = require('../../bin/lib/oxe-context-engine.cjs');
21
+ const runtimeSemantics = require('../../bin/lib/oxe-runtime-semantics.cjs');
22
+ const release = require('../../bin/lib/oxe-release.cjs');
22
23
 
23
24
  const PACKAGE_ROOT = path.join(__dirname, '..', '..');
24
25
 
@@ -636,12 +637,25 @@ module.exports = {
636
637
  },
637
638
 
638
639
  /** Dashboard local: contexto consolidado e persistência de revisão do plano. */
639
- dashboard: {
640
- loadDashboardContext: dashboard.loadDashboardContext,
641
- savePlanReviewStatus: dashboard.savePlanReviewStatus,
642
- addPlanReviewComment: dashboard.addPlanReviewComment,
643
- updatePlanReviewCommentStatus: dashboard.updatePlanReviewCommentStatus,
644
- },
640
+ dashboard: {
641
+ loadDashboardContext: dashboard.loadDashboardContext,
642
+ savePlanReviewStatus: dashboard.savePlanReviewStatus,
643
+ addPlanReviewComment: dashboard.addPlanReviewComment,
644
+ updatePlanReviewCommentStatus: dashboard.updatePlanReviewCommentStatus,
645
+ },
646
+
647
+ /** Release readiness: manifest, smoke matrix e checks de consistência antes de publicar. */
648
+ release: {
649
+ REQUIRED_RUNTIMES: release.REQUIRED_RUNTIMES,
650
+ WRAPPER_TARGETS: release.WRAPPER_TARGETS,
651
+ releasePaths: release.releasePaths,
652
+ collectWrapperHashes: release.collectWrapperHashes,
653
+ loadRuntimeSmokeReport: release.loadRuntimeSmokeReport,
654
+ loadRecoveryFixtureReport: release.loadRecoveryFixtureReport,
655
+ loadMultiAgentSoakReport: release.loadMultiAgentSoakReport,
656
+ buildReleaseManifest: release.buildReleaseManifest,
657
+ checkReleaseConsistency: release.checkReleaseConsistency,
658
+ },
645
659
 
646
660
  /** Runtime operacional: tracing, active run, catálogo de capabilities e memória em camadas. */
647
661
  operational: {