agentic-qe 1.9.4 → 2.0.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 (173) hide show
  1. package/.claude/agents/qe-api-contract-validator.md +95 -1336
  2. package/.claude/agents/qe-chaos-engineer.md +152 -1211
  3. package/.claude/agents/qe-code-complexity.md +144 -707
  4. package/.claude/agents/qe-coverage-analyzer.md +147 -743
  5. package/.claude/agents/qe-deployment-readiness.md +143 -1496
  6. package/.claude/agents/qe-flaky-test-hunter.md +132 -1529
  7. package/.claude/agents/qe-fleet-commander.md +12 -12
  8. package/.claude/agents/qe-performance-tester.md +150 -886
  9. package/.claude/agents/qe-production-intelligence.md +155 -1396
  10. package/.claude/agents/qe-quality-analyzer.md +6 -6
  11. package/.claude/agents/qe-quality-gate.md +151 -648
  12. package/.claude/agents/qe-regression-risk-analyzer.md +132 -1150
  13. package/.claude/agents/qe-requirements-validator.md +149 -932
  14. package/.claude/agents/qe-security-scanner.md +157 -797
  15. package/.claude/agents/qe-test-data-architect.md +96 -1365
  16. package/.claude/agents/qe-test-executor.md +8 -8
  17. package/.claude/agents/qe-test-generator.md +145 -1540
  18. package/.claude/agents/qe-visual-tester.md +153 -1257
  19. package/.claude/agents/qx-partner.md +235 -0
  20. package/.claude/agents/subagents/qe-code-reviewer.md +40 -136
  21. package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +40 -480
  22. package/.claude/agents/subagents/qe-data-generator.md +41 -125
  23. package/.claude/agents/subagents/qe-flaky-investigator.md +55 -411
  24. package/.claude/agents/subagents/qe-integration-tester.md +53 -141
  25. package/.claude/agents/subagents/qe-performance-validator.md +54 -130
  26. package/.claude/agents/subagents/qe-security-auditor.md +56 -114
  27. package/.claude/agents/subagents/qe-test-data-architect-sub.md +57 -548
  28. package/.claude/agents/subagents/qe-test-implementer.md +58 -551
  29. package/.claude/agents/subagents/qe-test-refactorer.md +65 -722
  30. package/.claude/agents/subagents/qe-test-writer.md +63 -726
  31. package/.claude/skills/skills-manifest.json +632 -0
  32. package/.claude/skills/testability-scoring/README.md +71 -0
  33. package/.claude/skills/testability-scoring/SKILL.md +611 -0
  34. package/.claude/skills/testability-scoring/resources/templates/config.template.js +84 -0
  35. package/.claude/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
  36. package/.claude/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
  37. package/.claude/skills/testability-scoring/scripts/run-assessment.sh +70 -0
  38. package/CHANGELOG.md +62 -0
  39. package/README.md +33 -6
  40. package/dist/agents/QXPartnerAgent.d.ts +139 -0
  41. package/dist/agents/QXPartnerAgent.d.ts.map +1 -0
  42. package/dist/agents/QXPartnerAgent.js +769 -0
  43. package/dist/agents/QXPartnerAgent.js.map +1 -0
  44. package/dist/agents/index.d.ts +1 -0
  45. package/dist/agents/index.d.ts.map +1 -1
  46. package/dist/agents/index.js +82 -2
  47. package/dist/agents/index.js.map +1 -1
  48. package/dist/cli/commands/debug/agent.d.ts.map +1 -1
  49. package/dist/cli/commands/debug/agent.js +19 -6
  50. package/dist/cli/commands/debug/agent.js.map +1 -1
  51. package/dist/cli/commands/debug/health-check.js +20 -7
  52. package/dist/cli/commands/debug/health-check.js.map +1 -1
  53. package/dist/cli/commands/init-claude-md-template.d.ts +1 -0
  54. package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
  55. package/dist/cli/commands/init-claude-md-template.js +4 -3
  56. package/dist/cli/commands/init-claude-md-template.js.map +1 -1
  57. package/dist/cli/commands/workflow/cancel.d.ts.map +1 -1
  58. package/dist/cli/commands/workflow/cancel.js +4 -3
  59. package/dist/cli/commands/workflow/cancel.js.map +1 -1
  60. package/dist/cli/commands/workflow/list.d.ts.map +1 -1
  61. package/dist/cli/commands/workflow/list.js +4 -3
  62. package/dist/cli/commands/workflow/list.js.map +1 -1
  63. package/dist/cli/commands/workflow/pause.d.ts.map +1 -1
  64. package/dist/cli/commands/workflow/pause.js +4 -3
  65. package/dist/cli/commands/workflow/pause.js.map +1 -1
  66. package/dist/cli/init/claude-config.d.ts.map +1 -1
  67. package/dist/cli/init/claude-config.js +3 -8
  68. package/dist/cli/init/claude-config.js.map +1 -1
  69. package/dist/cli/init/claude-md.d.ts.map +1 -1
  70. package/dist/cli/init/claude-md.js +44 -2
  71. package/dist/cli/init/claude-md.js.map +1 -1
  72. package/dist/cli/init/database-init.js +1 -1
  73. package/dist/cli/init/index.d.ts.map +1 -1
  74. package/dist/cli/init/index.js +13 -6
  75. package/dist/cli/init/index.js.map +1 -1
  76. package/dist/cli/init/skills.d.ts.map +1 -1
  77. package/dist/cli/init/skills.js +2 -1
  78. package/dist/cli/init/skills.js.map +1 -1
  79. package/dist/core/memory/AgentDBIntegration.d.ts +24 -6
  80. package/dist/core/memory/AgentDBIntegration.d.ts.map +1 -1
  81. package/dist/core/memory/AgentDBIntegration.js +66 -10
  82. package/dist/core/memory/AgentDBIntegration.js.map +1 -1
  83. package/dist/core/memory/UnifiedMemoryCoordinator.d.ts +341 -0
  84. package/dist/core/memory/UnifiedMemoryCoordinator.d.ts.map +1 -0
  85. package/dist/core/memory/UnifiedMemoryCoordinator.js +986 -0
  86. package/dist/core/memory/UnifiedMemoryCoordinator.js.map +1 -0
  87. package/dist/core/memory/index.d.ts +5 -0
  88. package/dist/core/memory/index.d.ts.map +1 -1
  89. package/dist/core/memory/index.js +23 -1
  90. package/dist/core/memory/index.js.map +1 -1
  91. package/dist/core/optimization/SwarmOptimizer.d.ts +185 -0
  92. package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -0
  93. package/dist/core/optimization/SwarmOptimizer.js +631 -0
  94. package/dist/core/optimization/SwarmOptimizer.js.map +1 -0
  95. package/dist/core/optimization/index.d.ts +9 -0
  96. package/dist/core/optimization/index.d.ts.map +1 -0
  97. package/dist/core/optimization/index.js +25 -0
  98. package/dist/core/optimization/index.js.map +1 -0
  99. package/dist/core/optimization/types.d.ts +53 -0
  100. package/dist/core/optimization/types.d.ts.map +1 -0
  101. package/dist/core/optimization/types.js +6 -0
  102. package/dist/core/optimization/types.js.map +1 -0
  103. package/dist/core/orchestration/PriorityQueue.d.ts +54 -0
  104. package/dist/core/orchestration/PriorityQueue.d.ts.map +1 -0
  105. package/dist/core/orchestration/PriorityQueue.js +122 -0
  106. package/dist/core/orchestration/PriorityQueue.js.map +1 -0
  107. package/dist/core/orchestration/WorkflowOrchestrator.d.ts +176 -0
  108. package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -0
  109. package/dist/core/orchestration/WorkflowOrchestrator.js +813 -0
  110. package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -0
  111. package/dist/core/orchestration/index.d.ts +7 -0
  112. package/dist/core/orchestration/index.d.ts.map +1 -0
  113. package/dist/core/orchestration/index.js +11 -0
  114. package/dist/core/orchestration/index.js.map +1 -0
  115. package/dist/core/orchestration/types.d.ts +96 -0
  116. package/dist/core/orchestration/types.d.ts.map +1 -0
  117. package/dist/core/orchestration/types.js +6 -0
  118. package/dist/core/orchestration/types.js.map +1 -0
  119. package/dist/core/skills/DynamicSkillLoader.d.ts +96 -0
  120. package/dist/core/skills/DynamicSkillLoader.d.ts.map +1 -0
  121. package/dist/core/skills/DynamicSkillLoader.js +353 -0
  122. package/dist/core/skills/DynamicSkillLoader.js.map +1 -0
  123. package/dist/core/skills/types.d.ts +118 -0
  124. package/dist/core/skills/types.d.ts.map +1 -0
  125. package/dist/core/skills/types.js +7 -0
  126. package/dist/core/skills/types.js.map +1 -0
  127. package/dist/core/transport/QUICTransport.d.ts +320 -0
  128. package/dist/core/transport/QUICTransport.d.ts.map +1 -0
  129. package/dist/core/transport/QUICTransport.js +711 -0
  130. package/dist/core/transport/QUICTransport.js.map +1 -0
  131. package/dist/core/transport/index.d.ts +40 -0
  132. package/dist/core/transport/index.d.ts.map +1 -0
  133. package/dist/core/transport/index.js +46 -0
  134. package/dist/core/transport/index.js.map +1 -0
  135. package/dist/core/transport/quic-loader.d.ts +123 -0
  136. package/dist/core/transport/quic-loader.d.ts.map +1 -0
  137. package/dist/core/transport/quic-loader.js +293 -0
  138. package/dist/core/transport/quic-loader.js.map +1 -0
  139. package/dist/core/transport/quic.d.ts +154 -0
  140. package/dist/core/transport/quic.d.ts.map +1 -0
  141. package/dist/core/transport/quic.js +214 -0
  142. package/dist/core/transport/quic.js.map +1 -0
  143. package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
  144. package/dist/mcp/services/AgentRegistry.js +4 -1
  145. package/dist/mcp/services/AgentRegistry.js.map +1 -1
  146. package/dist/types/index.d.ts +2 -1
  147. package/dist/types/index.d.ts.map +1 -1
  148. package/dist/types/index.js +2 -0
  149. package/dist/types/index.js.map +1 -1
  150. package/dist/types/qx.d.ts +397 -0
  151. package/dist/types/qx.d.ts.map +1 -0
  152. package/dist/types/qx.js +71 -0
  153. package/dist/types/qx.js.map +1 -0
  154. package/dist/visualization/api/RestEndpoints.js +1 -1
  155. package/dist/visualization/api/RestEndpoints.js.map +1 -1
  156. package/dist/visualization/api/WebSocketServer.d.ts +44 -0
  157. package/dist/visualization/api/WebSocketServer.d.ts.map +1 -1
  158. package/dist/visualization/api/WebSocketServer.js +144 -23
  159. package/dist/visualization/api/WebSocketServer.js.map +1 -1
  160. package/dist/visualization/core/DataTransformer.d.ts +10 -0
  161. package/dist/visualization/core/DataTransformer.d.ts.map +1 -1
  162. package/dist/visualization/core/DataTransformer.js +60 -5
  163. package/dist/visualization/core/DataTransformer.js.map +1 -1
  164. package/dist/visualization/emit-event.d.ts +75 -0
  165. package/dist/visualization/emit-event.d.ts.map +1 -0
  166. package/dist/visualization/emit-event.js +213 -0
  167. package/dist/visualization/emit-event.js.map +1 -0
  168. package/dist/visualization/index.d.ts +1 -0
  169. package/dist/visualization/index.d.ts.map +1 -1
  170. package/dist/visualization/index.js +7 -1
  171. package/dist/visualization/index.js.map +1 -1
  172. package/docs/reference/skills.md +63 -1
  173. package/package.json +4 -4
@@ -0,0 +1,813 @@
1
+ "use strict";
2
+ /**
3
+ * WorkflowOrchestrator - Adaptive workflow execution for QE agent swarms
4
+ *
5
+ * Features:
6
+ * - Adaptive strategy selection (parallel/sequential/hybrid)
7
+ * - Priority-based task queue with dependency resolution
8
+ * - Workflow checkpointing for recovery
9
+ * - Integration with SwarmOptimizer and FleetManager
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.WorkflowOrchestrator = void 0;
13
+ const Logger_1 = require("../../utils/Logger");
14
+ const PriorityQueue_1 = require("./PriorityQueue");
15
+ class WorkflowOrchestrator {
16
+ constructor(memoryStore, eventBus, optimizer) {
17
+ this.isShutdown = false;
18
+ // Priority mapping for tasks
19
+ this.PRIORITY_VALUES = {
20
+ critical: 100,
21
+ high: 75,
22
+ medium: 50,
23
+ low: 25
24
+ };
25
+ this.logger = Logger_1.Logger.getInstance();
26
+ this.memoryStore = memoryStore;
27
+ this.eventBus = eventBus;
28
+ this.optimizer = optimizer;
29
+ this.workflows = new Map();
30
+ this.executions = new Map();
31
+ this.taskQueue = new PriorityQueue_1.PriorityQueue();
32
+ }
33
+ /**
34
+ * Initialize the orchestrator
35
+ */
36
+ async initialize() {
37
+ this.logger.info('Initializing WorkflowOrchestrator');
38
+ // Load workflows from memory
39
+ await this.loadWorkflowsFromMemory();
40
+ // Subscribe to events
41
+ this.eventBus.subscribe('workflow:step:completed', this.handleStepCompleted.bind(this));
42
+ this.eventBus.subscribe('workflow:step:failed', this.handleStepFailed.bind(this));
43
+ this.eventBus.subscribe('agent:available', this.handleAgentAvailable.bind(this));
44
+ this.logger.info('WorkflowOrchestrator initialized successfully');
45
+ }
46
+ // ============= WORKFLOW MANAGEMENT =============
47
+ /**
48
+ * Register a new workflow
49
+ */
50
+ registerWorkflow(workflow) {
51
+ this.logger.info(`Registering workflow: ${workflow.id} - ${workflow.name}`);
52
+ // Validate workflow
53
+ this.validateWorkflow(workflow);
54
+ this.workflows.set(workflow.id, workflow);
55
+ // Persist to memory
56
+ this.memoryStore.store(`workflows:registry:${workflow.id}`, workflow, { partition: 'workflows', ttl: 2592000 } // 30 days
57
+ ).catch(err => this.logger.error('Failed to persist workflow:', err));
58
+ this.eventBus.emitAsync('workflow:registered', { workflowId: workflow.id });
59
+ }
60
+ /**
61
+ * Get a workflow by ID
62
+ */
63
+ getWorkflow(id) {
64
+ return this.workflows.get(id);
65
+ }
66
+ /**
67
+ * List all registered workflows
68
+ */
69
+ listWorkflows() {
70
+ return Array.from(this.workflows.values());
71
+ }
72
+ // ============= EXECUTION =============
73
+ /**
74
+ * Execute a workflow
75
+ */
76
+ async executeWorkflow(workflowId, inputs = {}) {
77
+ this.logger.info(`Executing workflow: ${workflowId}`);
78
+ const workflow = this.workflows.get(workflowId);
79
+ if (!workflow) {
80
+ throw new Error(`Workflow not found: ${workflowId}`);
81
+ }
82
+ // Create execution
83
+ const execution = {
84
+ id: this.generateExecutionId(),
85
+ workflowId,
86
+ status: 'running',
87
+ startedAt: new Date(),
88
+ completedSteps: [],
89
+ failedSteps: [],
90
+ results: new Map(),
91
+ metrics: {
92
+ totalDuration: 0,
93
+ stepDurations: new Map(),
94
+ retryCount: 0,
95
+ parallelization: 0
96
+ }
97
+ };
98
+ this.executions.set(execution.id, execution);
99
+ // Emit start event
100
+ await this.eventBus.emitAsync('workflow:started', {
101
+ executionId: execution.id,
102
+ workflowId
103
+ });
104
+ try {
105
+ // Create execution context
106
+ const context = {
107
+ executionId: execution.id,
108
+ workflowId,
109
+ inputs,
110
+ stepResults: new Map(),
111
+ startTime: Date.now()
112
+ };
113
+ // Resolve dependencies and create execution plan
114
+ const plan = this.resolveDependencies(workflow.steps);
115
+ // Select execution strategy
116
+ const strategy = workflow.strategy === 'adaptive'
117
+ ? await this.selectStrategy(workflow, plan)
118
+ : workflow.strategy;
119
+ this.logger.info(`Using ${strategy} execution strategy`);
120
+ // Execute based on strategy
121
+ let results;
122
+ if (strategy === 'parallel') {
123
+ results = await this.executeParallel(workflow.steps, context);
124
+ }
125
+ else if (strategy === 'sequential') {
126
+ results = await this.executeSequential(workflow.steps, context);
127
+ }
128
+ else {
129
+ // Hybrid: execute phases in sequence, steps within phases in parallel
130
+ results = await this.executeHybrid(plan, context);
131
+ }
132
+ // Update execution with results
133
+ execution.status = 'completed';
134
+ execution.completedAt = new Date();
135
+ execution.results = results;
136
+ execution.metrics.totalDuration = Date.now() - context.startTime;
137
+ // Calculate parallelization metric
138
+ const totalStepTime = Array.from(results.values())
139
+ .reduce((sum, r) => sum + r.duration, 0);
140
+ execution.metrics.parallelization = totalStepTime / execution.metrics.totalDuration;
141
+ // Emit completion event
142
+ await this.eventBus.emitAsync('workflow:completed', {
143
+ executionId: execution.id,
144
+ workflowId,
145
+ duration: execution.metrics.totalDuration
146
+ });
147
+ this.logger.info(`Workflow ${workflowId} completed in ${execution.metrics.totalDuration}ms`);
148
+ }
149
+ catch (error) {
150
+ execution.status = 'failed';
151
+ execution.completedAt = new Date();
152
+ await this.eventBus.emitAsync('workflow:failed', {
153
+ executionId: execution.id,
154
+ workflowId,
155
+ error: error instanceof Error ? error.message : String(error)
156
+ });
157
+ this.logger.error(`Workflow ${workflowId} failed:`, error);
158
+ }
159
+ finally {
160
+ // Persist execution
161
+ await this.persistExecution(execution);
162
+ }
163
+ return execution;
164
+ }
165
+ /**
166
+ * Pause a running execution
167
+ */
168
+ async pauseExecution(executionId) {
169
+ const execution = this.executions.get(executionId);
170
+ if (!execution) {
171
+ throw new Error(`Execution not found: ${executionId}`);
172
+ }
173
+ if (execution.status !== 'running') {
174
+ throw new Error(`Cannot pause execution in ${execution.status} state`);
175
+ }
176
+ // Create checkpoint
177
+ const checkpoint = await this.createCheckpoint(executionId);
178
+ execution.checkpoint = checkpoint;
179
+ execution.status = 'paused';
180
+ await this.eventBus.emitAsync('workflow:paused', { executionId });
181
+ await this.persistExecution(execution);
182
+ this.logger.info(`Execution ${executionId} paused`);
183
+ }
184
+ /**
185
+ * Resume a paused execution
186
+ */
187
+ async resumeExecution(executionId) {
188
+ const execution = this.executions.get(executionId);
189
+ if (!execution) {
190
+ throw new Error(`Execution not found: ${executionId}`);
191
+ }
192
+ if (execution.status !== 'paused') {
193
+ throw new Error(`Cannot resume execution in ${execution.status} state`);
194
+ }
195
+ if (!execution.checkpoint) {
196
+ throw new Error(`No checkpoint found for execution ${executionId}`);
197
+ }
198
+ execution.status = 'running';
199
+ await this.eventBus.emitAsync('workflow:resumed', { executionId });
200
+ this.logger.info(`Execution ${executionId} resumed`);
201
+ // Continue execution from checkpoint
202
+ // This would be implemented based on specific requirements
203
+ }
204
+ /**
205
+ * Cancel a running or paused execution
206
+ */
207
+ async cancelExecution(executionId) {
208
+ const execution = this.executions.get(executionId);
209
+ if (!execution) {
210
+ throw new Error(`Execution not found: ${executionId}`);
211
+ }
212
+ if (execution.status === 'completed' || execution.status === 'failed') {
213
+ throw new Error(`Cannot cancel execution in ${execution.status} state`);
214
+ }
215
+ execution.status = 'failed';
216
+ execution.completedAt = new Date();
217
+ await this.eventBus.emitAsync('workflow:cancelled', { executionId });
218
+ await this.persistExecution(execution);
219
+ this.logger.info(`Execution ${executionId} cancelled`);
220
+ }
221
+ // ============= STRATEGY SELECTION =============
222
+ /**
223
+ * Select optimal execution strategy based on workflow characteristics
224
+ */
225
+ async selectStrategy(workflow, plan) {
226
+ const workload = this.analyzeWorkloadCharacteristics(workflow.steps);
227
+ // Decision logic:
228
+ // - High parallelizability + low interdependencies → parallel
229
+ // - Low parallelizability or high interdependencies → sequential
230
+ // - Mixed characteristics → hybrid
231
+ if (workload.parallelizability > 0.7 && workload.interdependencies < 0.3) {
232
+ return 'parallel';
233
+ }
234
+ if (workload.parallelizability < 0.3 || workload.interdependencies > 0.7) {
235
+ return 'sequential';
236
+ }
237
+ return 'hybrid';
238
+ }
239
+ /**
240
+ * Analyze workload characteristics
241
+ */
242
+ analyzeWorkloadCharacteristics(steps) {
243
+ const totalSteps = steps.length;
244
+ // Calculate average complexity (based on timeout as proxy)
245
+ const avgComplexity = steps.reduce((sum, s) => sum + (s.timeout / 60000), 0) / totalSteps;
246
+ // Calculate parallelizability (steps with no dependencies)
247
+ const parallelSteps = steps.filter(s => s.dependencies.length === 0).length;
248
+ const parallelizability = parallelSteps / totalSteps;
249
+ // Calculate interdependencies
250
+ const totalDependencies = steps.reduce((sum, s) => sum + s.dependencies.length, 0);
251
+ const interdependencies = totalDependencies / (totalSteps * totalSteps);
252
+ // Estimate resource intensity from timeout and priority
253
+ const criticalSteps = steps.filter(s => s.priority === 'critical').length;
254
+ const resourceIntensity = (criticalSteps / totalSteps + avgComplexity) / 2;
255
+ return {
256
+ stepCount: totalSteps,
257
+ averageComplexity: Math.min(1, avgComplexity / 10), // normalize to 0-1
258
+ parallelizability,
259
+ resourceIntensity: Math.min(1, resourceIntensity),
260
+ interdependencies: Math.min(1, interdependencies)
261
+ };
262
+ }
263
+ // ============= DEPENDENCY RESOLUTION =============
264
+ /**
265
+ * Resolve dependencies and create execution plan
266
+ */
267
+ resolveDependencies(steps) {
268
+ // Check for cycles
269
+ if (this.detectCycles(steps)) {
270
+ throw new Error('Workflow contains circular dependencies');
271
+ }
272
+ // Perform topological sort
273
+ const sortedStepIds = this.topologicalSort(steps);
274
+ // Group steps into phases (steps that can run in parallel)
275
+ const phases = this.groupIntoPhases(steps, sortedStepIds);
276
+ // Calculate critical path (longest dependency chain)
277
+ const criticalPath = this.calculateCriticalPath(steps);
278
+ // Estimate total duration based on critical path
279
+ const estimatedDuration = criticalPath
280
+ .map(stepId => steps.find(s => s.id === stepId))
281
+ .filter(s => s !== undefined)
282
+ .reduce((sum, step) => sum + step.timeout, 0);
283
+ return {
284
+ phases,
285
+ criticalPath,
286
+ estimatedDuration
287
+ };
288
+ }
289
+ /**
290
+ * Topological sort using Kahn's algorithm
291
+ */
292
+ topologicalSort(steps) {
293
+ const sorted = [];
294
+ const inDegree = new Map();
295
+ const adjList = new Map();
296
+ // Build adjacency list and in-degree map
297
+ for (const step of steps) {
298
+ inDegree.set(step.id, step.dependencies.length);
299
+ adjList.set(step.id, []);
300
+ }
301
+ for (const step of steps) {
302
+ for (const dep of step.dependencies) {
303
+ const neighbors = adjList.get(dep) || [];
304
+ neighbors.push(step.id);
305
+ adjList.set(dep, neighbors);
306
+ }
307
+ }
308
+ // Find all steps with no dependencies
309
+ const queue = [];
310
+ for (const [stepId, degree] of inDegree.entries()) {
311
+ if (degree === 0) {
312
+ queue.push(stepId);
313
+ }
314
+ }
315
+ // Process queue
316
+ while (queue.length > 0) {
317
+ const stepId = queue.shift();
318
+ sorted.push(stepId);
319
+ const neighbors = adjList.get(stepId) || [];
320
+ for (const neighbor of neighbors) {
321
+ const degree = inDegree.get(neighbor) - 1;
322
+ inDegree.set(neighbor, degree);
323
+ if (degree === 0) {
324
+ queue.push(neighbor);
325
+ }
326
+ }
327
+ }
328
+ return sorted;
329
+ }
330
+ /**
331
+ * Detect circular dependencies using DFS
332
+ */
333
+ detectCycles(steps) {
334
+ const visited = new Set();
335
+ const recursionStack = new Set();
336
+ const hasCycle = (stepId) => {
337
+ visited.add(stepId);
338
+ recursionStack.add(stepId);
339
+ const step = steps.find(s => s.id === stepId);
340
+ if (!step)
341
+ return false;
342
+ for (const dep of step.dependencies) {
343
+ if (!visited.has(dep)) {
344
+ if (hasCycle(dep)) {
345
+ return true;
346
+ }
347
+ }
348
+ else if (recursionStack.has(dep)) {
349
+ return true;
350
+ }
351
+ }
352
+ recursionStack.delete(stepId);
353
+ return false;
354
+ };
355
+ for (const step of steps) {
356
+ if (!visited.has(step.id)) {
357
+ if (hasCycle(step.id)) {
358
+ return true;
359
+ }
360
+ }
361
+ }
362
+ return false;
363
+ }
364
+ /**
365
+ * Group steps into parallel execution phases
366
+ */
367
+ groupIntoPhases(steps, sortedStepIds) {
368
+ const phases = [];
369
+ const processedSteps = new Set();
370
+ let phaseId = 0;
371
+ while (processedSteps.size < steps.length) {
372
+ // Find steps whose dependencies are all processed
373
+ const readySteps = steps.filter(step => {
374
+ if (processedSteps.has(step.id))
375
+ return false;
376
+ return step.dependencies.every(dep => processedSteps.has(dep));
377
+ });
378
+ if (readySteps.length === 0)
379
+ break;
380
+ phases.push({
381
+ id: `phase-${phaseId++}`,
382
+ steps: readySteps,
383
+ isParallel: readySteps.length > 1,
384
+ dependencies: readySteps.flatMap(s => s.dependencies).filter(d => !processedSteps.has(d))
385
+ });
386
+ readySteps.forEach(step => processedSteps.add(step.id));
387
+ }
388
+ return phases;
389
+ }
390
+ /**
391
+ * Calculate critical path (longest dependency chain)
392
+ */
393
+ calculateCriticalPath(steps) {
394
+ const memo = new Map();
395
+ const findLongestPath = (stepId) => {
396
+ if (memo.has(stepId)) {
397
+ return memo.get(stepId);
398
+ }
399
+ const step = steps.find(s => s.id === stepId);
400
+ if (!step || step.dependencies.length === 0) {
401
+ memo.set(stepId, [stepId]);
402
+ return [stepId];
403
+ }
404
+ let longestPath = [];
405
+ for (const dep of step.dependencies) {
406
+ const path = findLongestPath(dep);
407
+ if (path.length > longestPath.length) {
408
+ longestPath = path;
409
+ }
410
+ }
411
+ const result = [...longestPath, stepId];
412
+ memo.set(stepId, result);
413
+ return result;
414
+ };
415
+ // Find longest path among all terminal steps
416
+ const terminalSteps = steps.filter(step => !steps.some(s => s.dependencies.includes(step.id)));
417
+ let criticalPath = [];
418
+ for (const step of terminalSteps) {
419
+ const path = findLongestPath(step.id);
420
+ if (path.length > criticalPath.length) {
421
+ criticalPath = path;
422
+ }
423
+ }
424
+ return criticalPath;
425
+ }
426
+ // ============= STEP EXECUTION =============
427
+ /**
428
+ * Execute a single step
429
+ */
430
+ async executeStep(step, context) {
431
+ const startTime = Date.now();
432
+ let retryCount = 0;
433
+ let lastError;
434
+ this.logger.debug(`Executing step: ${step.id} - ${step.name}`);
435
+ // Emit start event
436
+ await this.eventBus.emitAsync('workflow:step:started', {
437
+ executionId: context.executionId,
438
+ stepId: step.id
439
+ });
440
+ while (retryCount <= step.retries) {
441
+ try {
442
+ // Resolve inputs from previous step results
443
+ const resolvedInputs = this.resolveStepInputs(step, context);
444
+ // Execute step with timeout
445
+ const output = await this.executeStepWithTimeout(step, resolvedInputs, context);
446
+ const duration = Date.now() - startTime;
447
+ const result = {
448
+ stepId: step.id,
449
+ status: 'success',
450
+ output,
451
+ duration,
452
+ retryCount
453
+ };
454
+ // Update execution
455
+ const execution = this.executions.get(context.executionId);
456
+ if (execution) {
457
+ execution.completedSteps.push(step.id);
458
+ execution.metrics.stepDurations.set(step.id, duration);
459
+ }
460
+ // Emit success event
461
+ await this.eventBus.emitAsync('workflow:step:completed', {
462
+ executionId: context.executionId,
463
+ stepId: step.id,
464
+ duration
465
+ });
466
+ return result;
467
+ }
468
+ catch (error) {
469
+ lastError = error instanceof Error ? error : new Error(String(error));
470
+ retryCount++;
471
+ if (retryCount <= step.retries) {
472
+ this.logger.warn(`Step ${step.id} failed, retrying (${retryCount}/${step.retries})`);
473
+ await this.delay(1000 * retryCount); // Exponential backoff
474
+ }
475
+ }
476
+ }
477
+ // All retries exhausted
478
+ const duration = Date.now() - startTime;
479
+ const result = {
480
+ stepId: step.id,
481
+ status: 'failed',
482
+ output: null,
483
+ error: lastError,
484
+ duration,
485
+ retryCount: retryCount - 1
486
+ };
487
+ // Update execution
488
+ const execution = this.executions.get(context.executionId);
489
+ if (execution) {
490
+ execution.failedSteps.push(step.id);
491
+ execution.metrics.retryCount += retryCount - 1;
492
+ }
493
+ // Emit failure event
494
+ await this.eventBus.emitAsync('workflow:step:failed', {
495
+ executionId: context.executionId,
496
+ stepId: step.id,
497
+ error: lastError?.message
498
+ });
499
+ return result;
500
+ }
501
+ /**
502
+ * Execute step with timeout
503
+ */
504
+ async executeStepWithTimeout(step, inputs, context) {
505
+ return new Promise((resolve, reject) => {
506
+ const timer = setTimeout(() => {
507
+ reject(new Error(`Step ${step.id} timed out after ${step.timeout}ms`));
508
+ }, step.timeout);
509
+ // Simulate step execution (in real implementation, this would call agent)
510
+ this.executeStepAction(step, inputs, context)
511
+ .then(result => {
512
+ clearTimeout(timer);
513
+ resolve(result);
514
+ })
515
+ .catch(error => {
516
+ clearTimeout(timer);
517
+ reject(error);
518
+ });
519
+ });
520
+ }
521
+ /**
522
+ * Execute step action (placeholder for agent invocation)
523
+ */
524
+ async executeStepAction(step, inputs, context) {
525
+ // In real implementation, this would:
526
+ // 1. Allocate agent using optimizer
527
+ // 2. Invoke agent with step action and inputs
528
+ // 3. Return agent's output
529
+ this.logger.debug(`Executing action: ${step.action} with inputs:`, inputs);
530
+ // Placeholder: return mock result
531
+ return {
532
+ stepId: step.id,
533
+ agentType: step.agentType,
534
+ action: step.action,
535
+ inputs,
536
+ timestamp: Date.now()
537
+ };
538
+ }
539
+ /**
540
+ * Resolve step inputs from previous results
541
+ */
542
+ resolveStepInputs(step, context) {
543
+ const resolved = { ...step.inputs };
544
+ // Replace references to previous step outputs
545
+ for (const [key, value] of Object.entries(resolved)) {
546
+ if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
547
+ const ref = value.slice(2, -1);
548
+ const [stepId, outputKey] = ref.split('.');
549
+ const stepResult = context.stepResults.get(stepId);
550
+ if (stepResult && stepResult.output) {
551
+ resolved[key] = outputKey
552
+ ? stepResult.output[outputKey]
553
+ : stepResult.output;
554
+ }
555
+ }
556
+ }
557
+ return resolved;
558
+ }
559
+ /**
560
+ * Execute steps in parallel
561
+ */
562
+ async executeParallel(steps, context) {
563
+ this.logger.info(`Executing ${steps.length} steps in parallel`);
564
+ const results = new Map();
565
+ // Execute all steps concurrently
566
+ const promises = steps.map(step => this.executeStep(step, context));
567
+ const stepResults = await Promise.allSettled(promises);
568
+ // Collect results
569
+ for (let i = 0; i < steps.length; i++) {
570
+ const step = steps[i];
571
+ const result = stepResults[i];
572
+ if (result.status === 'fulfilled') {
573
+ results.set(step.id, result.value);
574
+ context.stepResults.set(step.id, result.value);
575
+ }
576
+ else {
577
+ results.set(step.id, {
578
+ stepId: step.id,
579
+ status: 'failed',
580
+ output: null,
581
+ error: result.reason,
582
+ duration: 0,
583
+ retryCount: 0
584
+ });
585
+ }
586
+ }
587
+ return results;
588
+ }
589
+ /**
590
+ * Execute steps sequentially
591
+ */
592
+ async executeSequential(steps, context) {
593
+ this.logger.info(`Executing ${steps.length} steps sequentially`);
594
+ const results = new Map();
595
+ for (const step of steps) {
596
+ const result = await this.executeStep(step, context);
597
+ results.set(step.id, result);
598
+ context.stepResults.set(step.id, result);
599
+ // Stop on failure if step is critical
600
+ if (result.status === 'failed' && step.priority === 'critical') {
601
+ throw new Error(`Critical step ${step.id} failed`);
602
+ }
603
+ }
604
+ return results;
605
+ }
606
+ /**
607
+ * Execute in hybrid mode (phases sequential, steps within phase parallel)
608
+ */
609
+ async executeHybrid(plan, context) {
610
+ this.logger.info(`Executing ${plan.phases.length} phases in hybrid mode`);
611
+ const results = new Map();
612
+ for (const phase of plan.phases) {
613
+ this.logger.debug(`Executing phase ${phase.id} with ${phase.steps.length} steps`);
614
+ if (phase.isParallel) {
615
+ const phaseResults = await this.executeParallel(phase.steps, context);
616
+ phaseResults.forEach((result, stepId) => results.set(stepId, result));
617
+ }
618
+ else {
619
+ const phaseResults = await this.executeSequential(phase.steps, context);
620
+ phaseResults.forEach((result, stepId) => results.set(stepId, result));
621
+ }
622
+ }
623
+ return results;
624
+ }
625
+ // ============= CHECKPOINTING =============
626
+ /**
627
+ * Create a checkpoint for an execution
628
+ */
629
+ async createCheckpoint(executionId) {
630
+ const execution = this.executions.get(executionId);
631
+ if (!execution) {
632
+ throw new Error(`Execution not found: ${executionId}`);
633
+ }
634
+ const checkpoint = {
635
+ executionId,
636
+ timestamp: new Date(),
637
+ completedSteps: [...execution.completedSteps],
638
+ stepResults: new Map(execution.results),
639
+ state: {
640
+ status: execution.status,
641
+ currentStep: execution.currentStep
642
+ }
643
+ };
644
+ // Persist checkpoint
645
+ await this.memoryStore.store(`workflows:checkpoints:${executionId}:${Date.now()}`, this.serializeCheckpoint(checkpoint), { partition: 'workflows', ttl: 604800 } // 7 days
646
+ );
647
+ this.logger.info(`Created checkpoint for execution ${executionId}`);
648
+ return checkpoint;
649
+ }
650
+ /**
651
+ * Restore execution from checkpoint
652
+ */
653
+ async restoreFromCheckpoint(checkpoint) {
654
+ this.logger.info(`Restoring execution from checkpoint: ${checkpoint.executionId}`);
655
+ const execution = this.executions.get(checkpoint.executionId);
656
+ if (!execution) {
657
+ throw new Error(`Execution not found: ${checkpoint.executionId}`);
658
+ }
659
+ execution.completedSteps = [...checkpoint.completedSteps];
660
+ execution.results = new Map(checkpoint.stepResults);
661
+ execution.checkpoint = checkpoint;
662
+ execution.status = checkpoint.state.status;
663
+ return execution;
664
+ }
665
+ // ============= QUEUE MANAGEMENT =============
666
+ /**
667
+ * Enqueue a task with priority
668
+ */
669
+ enqueueTask(task) {
670
+ this.taskQueue.enqueue(task, task.priority);
671
+ }
672
+ /**
673
+ * Dequeue highest priority task
674
+ */
675
+ dequeueTask() {
676
+ return this.taskQueue.dequeue();
677
+ }
678
+ // ============= METRICS =============
679
+ /**
680
+ * Get execution metrics
681
+ */
682
+ getExecutionMetrics(executionId) {
683
+ const execution = this.executions.get(executionId);
684
+ if (!execution) {
685
+ throw new Error(`Execution not found: ${executionId}`);
686
+ }
687
+ return execution.metrics;
688
+ }
689
+ /**
690
+ * Get execution by ID
691
+ */
692
+ getExecution(executionId) {
693
+ return this.executions.get(executionId);
694
+ }
695
+ /**
696
+ * List all executions
697
+ */
698
+ listExecutions() {
699
+ return Array.from(this.executions.values());
700
+ }
701
+ // ============= HELPERS =============
702
+ /**
703
+ * Validate workflow structure
704
+ */
705
+ validateWorkflow(workflow) {
706
+ if (!workflow.id || !workflow.name) {
707
+ throw new Error('Workflow must have id and name');
708
+ }
709
+ if (!workflow.steps || workflow.steps.length === 0) {
710
+ throw new Error('Workflow must have at least one step');
711
+ }
712
+ // Validate step dependencies exist
713
+ const stepIds = new Set(workflow.steps.map(s => s.id));
714
+ for (const step of workflow.steps) {
715
+ for (const dep of step.dependencies) {
716
+ if (!stepIds.has(dep)) {
717
+ throw new Error(`Step ${step.id} depends on non-existent step: ${dep}`);
718
+ }
719
+ }
720
+ }
721
+ }
722
+ /**
723
+ * Generate unique execution ID
724
+ */
725
+ generateExecutionId() {
726
+ return `exec-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
727
+ }
728
+ /**
729
+ * Serialize checkpoint for storage
730
+ */
731
+ serializeCheckpoint(checkpoint) {
732
+ return {
733
+ ...checkpoint,
734
+ stepResults: Array.from(checkpoint.stepResults.entries())
735
+ };
736
+ }
737
+ /**
738
+ * Persist execution to memory
739
+ */
740
+ async persistExecution(execution) {
741
+ const serialized = {
742
+ ...execution,
743
+ results: Array.from(execution.results.entries()),
744
+ metrics: {
745
+ ...execution.metrics,
746
+ stepDurations: Array.from(execution.metrics.stepDurations.entries())
747
+ }
748
+ };
749
+ await this.memoryStore.store(`workflows:executions:${execution.id}`, serialized, { partition: 'workflows', ttl: 604800 } // 7 days
750
+ );
751
+ }
752
+ /**
753
+ * Load workflows from memory
754
+ */
755
+ async loadWorkflowsFromMemory() {
756
+ try {
757
+ const entries = await this.memoryStore.query('workflows:registry:%', {
758
+ partition: 'workflows'
759
+ });
760
+ for (const entry of entries) {
761
+ const workflow = entry.value;
762
+ this.workflows.set(workflow.id, workflow);
763
+ }
764
+ this.logger.info(`Loaded ${this.workflows.size} workflows from memory`);
765
+ }
766
+ catch (error) {
767
+ this.logger.warn('Failed to load workflows from memory:', error);
768
+ }
769
+ }
770
+ /**
771
+ * Delay helper
772
+ */
773
+ delay(ms) {
774
+ return new Promise(resolve => setTimeout(resolve, ms));
775
+ }
776
+ /**
777
+ * Event handlers
778
+ */
779
+ async handleStepCompleted(data) {
780
+ this.logger.debug(`Step completed: ${data.stepId}`);
781
+ }
782
+ async handleStepFailed(data) {
783
+ this.logger.error(`Step failed: ${data.stepId} - ${data.error}`);
784
+ }
785
+ async handleAgentAvailable(data) {
786
+ // Process queued tasks when agent becomes available
787
+ if (!this.taskQueue.isEmpty()) {
788
+ const task = this.dequeueTask();
789
+ if (task) {
790
+ this.logger.debug(`Assigning queued task ${task.id} to available agent`);
791
+ }
792
+ }
793
+ }
794
+ // ============= CLEANUP =============
795
+ /**
796
+ * Shutdown orchestrator
797
+ */
798
+ async shutdown() {
799
+ this.logger.info('Shutting down WorkflowOrchestrator');
800
+ this.isShutdown = true;
801
+ // Cancel all running executions
802
+ for (const execution of this.executions.values()) {
803
+ if (execution.status === 'running' || execution.status === 'paused') {
804
+ await this.cancelExecution(execution.id);
805
+ }
806
+ }
807
+ // Clear queue
808
+ this.taskQueue.clear();
809
+ this.logger.info('WorkflowOrchestrator shutdown complete');
810
+ }
811
+ }
812
+ exports.WorkflowOrchestrator = WorkflowOrchestrator;
813
+ //# sourceMappingURL=WorkflowOrchestrator.js.map