agentic-qe 2.7.1 → 2.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +179 -0
  2. package/README.md +2 -2
  3. package/dist/agents/CodeIntelligenceAgent.d.ts.map +1 -1
  4. package/dist/agents/CodeIntelligenceAgent.js +7 -5
  5. package/dist/agents/CodeIntelligenceAgent.js.map +1 -1
  6. package/dist/cli/commands/knowledge-graph.d.ts.map +1 -1
  7. package/dist/cli/commands/knowledge-graph.js +4 -2
  8. package/dist/cli/commands/knowledge-graph.js.map +1 -1
  9. package/dist/cli/commands/migrate/index.d.ts +14 -0
  10. package/dist/cli/commands/migrate/index.d.ts.map +1 -0
  11. package/dist/cli/commands/migrate/index.js +283 -0
  12. package/dist/cli/commands/migrate/index.js.map +1 -0
  13. package/dist/cli/formatters/KGOutputFormatter.d.ts.map +1 -1
  14. package/dist/cli/formatters/KGOutputFormatter.js +15 -6
  15. package/dist/cli/formatters/KGOutputFormatter.js.map +1 -1
  16. package/dist/cli/index.js +3 -0
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/init/database-init.d.ts.map +1 -1
  19. package/dist/cli/init/database-init.js +105 -0
  20. package/dist/cli/init/database-init.js.map +1 -1
  21. package/dist/code-intelligence/orchestrator/CodeIntelligenceOrchestrator.d.ts +9 -3
  22. package/dist/code-intelligence/orchestrator/CodeIntelligenceOrchestrator.d.ts.map +1 -1
  23. package/dist/code-intelligence/orchestrator/CodeIntelligenceOrchestrator.js +41 -3
  24. package/dist/code-intelligence/orchestrator/CodeIntelligenceOrchestrator.js.map +1 -1
  25. package/dist/code-intelligence/service/CodeIntelligenceService.js +1 -1
  26. package/dist/code-intelligence/service/CodeIntelligenceService.js.map +1 -1
  27. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  28. package/dist/learning/QLearning.d.ts +110 -2
  29. package/dist/learning/QLearning.d.ts.map +1 -1
  30. package/dist/learning/QLearning.js +218 -1
  31. package/dist/learning/QLearning.js.map +1 -1
  32. package/dist/learning/metrics/LearningMetrics.d.ts +37 -0
  33. package/dist/learning/metrics/LearningMetrics.d.ts.map +1 -1
  34. package/dist/learning/metrics/LearningMetrics.js +73 -0
  35. package/dist/learning/metrics/LearningMetrics.js.map +1 -1
  36. package/dist/mcp/handlers/fleet-init.d.ts +10 -0
  37. package/dist/mcp/handlers/fleet-init.d.ts.map +1 -1
  38. package/dist/mcp/handlers/fleet-init.js +61 -0
  39. package/dist/mcp/handlers/fleet-init.js.map +1 -1
  40. package/dist/mcp/handlers/learning/learning-store-pattern.d.ts +13 -0
  41. package/dist/mcp/handlers/learning/learning-store-pattern.d.ts.map +1 -1
  42. package/dist/mcp/handlers/learning/learning-store-pattern.js +38 -0
  43. package/dist/mcp/handlers/learning/learning-store-pattern.js.map +1 -1
  44. package/dist/mcp/handlers/phase3/Phase3DomainTools.d.ts +89 -0
  45. package/dist/mcp/handlers/phase3/Phase3DomainTools.d.ts.map +1 -1
  46. package/dist/mcp/handlers/phase3/Phase3DomainTools.js +110 -1
  47. package/dist/mcp/handlers/phase3/Phase3DomainTools.js.map +1 -1
  48. package/dist/mcp/handlers/task-orchestrate.d.ts +27 -1
  49. package/dist/mcp/handlers/task-orchestrate.d.ts.map +1 -1
  50. package/dist/mcp/handlers/task-orchestrate.js +188 -8
  51. package/dist/mcp/handlers/task-orchestrate.js.map +1 -1
  52. package/dist/mcp/server-instructions.d.ts +1 -1
  53. package/dist/mcp/server-instructions.js +1 -1
  54. package/dist/mcp/server.d.ts +6 -0
  55. package/dist/mcp/server.d.ts.map +1 -1
  56. package/dist/mcp/server.js +92 -2
  57. package/dist/mcp/server.js.map +1 -1
  58. package/dist/mcp/services/AgentRegistry.d.ts +13 -0
  59. package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
  60. package/dist/mcp/services/AgentRegistry.js +66 -0
  61. package/dist/mcp/services/AgentRegistry.js.map +1 -1
  62. package/dist/mcp/tools/qe/quality-gates/evaluate-quality-gate.d.ts +55 -0
  63. package/dist/mcp/tools/qe/quality-gates/evaluate-quality-gate.d.ts.map +1 -1
  64. package/dist/mcp/tools/qe/quality-gates/evaluate-quality-gate.js +233 -0
  65. package/dist/mcp/tools/qe/quality-gates/evaluate-quality-gate.js.map +1 -1
  66. package/dist/mcp/tools/qe/quality-gates/index.d.ts +5 -2
  67. package/dist/mcp/tools/qe/quality-gates/index.d.ts.map +1 -1
  68. package/dist/mcp/tools/qe/quality-gates/index.js +10 -1
  69. package/dist/mcp/tools/qe/quality-gates/index.js.map +1 -1
  70. package/dist/mcp/tools.d.ts +1 -0
  71. package/dist/mcp/tools.d.ts.map +1 -1
  72. package/dist/mcp/tools.js +156 -1
  73. package/dist/mcp/tools.js.map +1 -1
  74. package/dist/persistence/migrations/all-migrations.d.ts +18 -0
  75. package/dist/persistence/migrations/all-migrations.d.ts.map +1 -0
  76. package/dist/persistence/migrations/all-migrations.js +624 -0
  77. package/dist/persistence/migrations/all-migrations.js.map +1 -0
  78. package/dist/persistence/migrations/index.d.ts +110 -0
  79. package/dist/persistence/migrations/index.d.ts.map +1 -0
  80. package/dist/persistence/migrations/index.js +303 -0
  81. package/dist/persistence/migrations/index.js.map +1 -0
  82. package/dist/planning/GOAPPlanner.d.ts +170 -0
  83. package/dist/planning/GOAPPlanner.d.ts.map +1 -0
  84. package/dist/planning/GOAPPlanner.js +781 -0
  85. package/dist/planning/GOAPPlanner.js.map +1 -0
  86. package/dist/planning/PlanLearning.d.ts +184 -0
  87. package/dist/planning/PlanLearning.d.ts.map +1 -0
  88. package/dist/planning/PlanLearning.js +526 -0
  89. package/dist/planning/PlanLearning.js.map +1 -0
  90. package/dist/planning/PlanSimilarity.d.ts +148 -0
  91. package/dist/planning/PlanSimilarity.d.ts.map +1 -0
  92. package/dist/planning/PlanSimilarity.js +463 -0
  93. package/dist/planning/PlanSimilarity.js.map +1 -0
  94. package/dist/planning/WorldStateBuilder.d.ts +150 -0
  95. package/dist/planning/WorldStateBuilder.d.ts.map +1 -0
  96. package/dist/planning/WorldStateBuilder.js +267 -0
  97. package/dist/planning/WorldStateBuilder.js.map +1 -0
  98. package/dist/planning/actions/fleet-actions.d.ts +78 -0
  99. package/dist/planning/actions/fleet-actions.d.ts.map +1 -0
  100. package/dist/planning/actions/fleet-actions.js +329 -0
  101. package/dist/planning/actions/fleet-actions.js.map +1 -0
  102. package/dist/planning/actions/index.d.ts +61 -0
  103. package/dist/planning/actions/index.d.ts.map +1 -0
  104. package/dist/planning/actions/index.js +159 -0
  105. package/dist/planning/actions/index.js.map +1 -0
  106. package/dist/planning/actions/orchestration-actions.d.ts +61 -0
  107. package/dist/planning/actions/orchestration-actions.d.ts.map +1 -0
  108. package/dist/planning/actions/orchestration-actions.js +395 -0
  109. package/dist/planning/actions/orchestration-actions.js.map +1 -0
  110. package/dist/planning/actions/quality-gate-actions.d.ts +160 -0
  111. package/dist/planning/actions/quality-gate-actions.d.ts.map +1 -0
  112. package/dist/planning/actions/quality-gate-actions.js +639 -0
  113. package/dist/planning/actions/quality-gate-actions.js.map +1 -0
  114. package/dist/planning/actions/test-strategy-actions.d.ts +70 -0
  115. package/dist/planning/actions/test-strategy-actions.d.ts.map +1 -0
  116. package/dist/planning/actions/test-strategy-actions.js +278 -0
  117. package/dist/planning/actions/test-strategy-actions.js.map +1 -0
  118. package/dist/planning/execution/PlanExecutor.d.ts +223 -0
  119. package/dist/planning/execution/PlanExecutor.d.ts.map +1 -0
  120. package/dist/planning/execution/PlanExecutor.js +978 -0
  121. package/dist/planning/execution/PlanExecutor.js.map +1 -0
  122. package/dist/planning/execution/index.d.ts +12 -0
  123. package/dist/planning/execution/index.d.ts.map +1 -0
  124. package/dist/planning/execution/index.js +18 -0
  125. package/dist/planning/execution/index.js.map +1 -0
  126. package/dist/planning/goals/TaskWorkflowGoals.d.ts +67 -0
  127. package/dist/planning/goals/TaskWorkflowGoals.d.ts.map +1 -0
  128. package/dist/planning/goals/TaskWorkflowGoals.js +208 -0
  129. package/dist/planning/goals/TaskWorkflowGoals.js.map +1 -0
  130. package/dist/planning/goals/index.d.ts +10 -0
  131. package/dist/planning/goals/index.d.ts.map +1 -0
  132. package/dist/planning/goals/index.js +19 -0
  133. package/dist/planning/goals/index.js.map +1 -0
  134. package/dist/planning/index.d.ts +36 -0
  135. package/dist/planning/index.d.ts.map +1 -0
  136. package/dist/planning/index.js +187 -0
  137. package/dist/planning/index.js.map +1 -0
  138. package/dist/planning/integration/GOAPQualityGateIntegration.d.ts +235 -0
  139. package/dist/planning/integration/GOAPQualityGateIntegration.d.ts.map +1 -0
  140. package/dist/planning/integration/GOAPQualityGateIntegration.js +589 -0
  141. package/dist/planning/integration/GOAPQualityGateIntegration.js.map +1 -0
  142. package/dist/planning/integration/GOAPTaskOrchestration.d.ts +165 -0
  143. package/dist/planning/integration/GOAPTaskOrchestration.d.ts.map +1 -0
  144. package/dist/planning/integration/GOAPTaskOrchestration.js +490 -0
  145. package/dist/planning/integration/GOAPTaskOrchestration.js.map +1 -0
  146. package/dist/planning/integration/index.d.ts +14 -0
  147. package/dist/planning/integration/index.d.ts.map +1 -0
  148. package/dist/planning/integration/index.js +23 -0
  149. package/dist/planning/integration/index.js.map +1 -0
  150. package/dist/planning/types.d.ts +266 -0
  151. package/dist/planning/types.d.ts.map +1 -0
  152. package/dist/planning/types.js +63 -0
  153. package/dist/planning/types.js.map +1 -0
  154. package/dist/utils/Database.d.ts.map +1 -1
  155. package/dist/utils/Database.js +81 -2
  156. package/dist/utils/Database.js.map +1 -1
  157. package/package.json +6 -3
@@ -0,0 +1,978 @@
1
+ "use strict";
2
+ /**
3
+ * GOAP Plan Executor
4
+ *
5
+ * Executes remediation plans generated by GOAPQualityGateIntegration:
6
+ * - Spawns agents for each action
7
+ * - Executes actions in sequence with dependency ordering
8
+ * - Records outcomes for learning via PlanLearning integration
9
+ * - Handles failures with automatic replanning
10
+ * - Phase 6: Live agent execution with real world state updates
11
+ *
12
+ * @module planning/execution/PlanExecutor
13
+ * @version 1.2.0 - Phase 6: Live Agent Execution
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.PlanExecutor = void 0;
50
+ exports.createPlanExecutor = createPlanExecutor;
51
+ exports.executeQualityGateRemediation = executeQualityGateRemediation;
52
+ const GOAPQualityGateIntegration_1 = require("../integration/GOAPQualityGateIntegration");
53
+ const Logger_1 = require("../../utils/Logger");
54
+ const PlanLearning_1 = require("../PlanLearning");
55
+ const types_1 = require("../types");
56
+ // Lazy import to avoid circular dependencies and reduce memory in tests
57
+ let AgentRegistryModule = null;
58
+ async function getAgentRegistryModule() {
59
+ if (!AgentRegistryModule) {
60
+ AgentRegistryModule = await Promise.resolve().then(() => __importStar(require('../../mcp/services/AgentRegistry')));
61
+ }
62
+ return AgentRegistryModule;
63
+ }
64
+ const DEFAULT_CONFIG = {
65
+ maxRetries: 1,
66
+ actionTimeoutMs: 300000,
67
+ continueOnFailure: false,
68
+ maxReplanAttempts: 2,
69
+ dryRun: false
70
+ };
71
+ /**
72
+ * GOAP Plan Executor
73
+ *
74
+ * Bridges plan generation with actual agent execution.
75
+ * Implements the OODA (Observe-Orient-Decide-Act) loop for plan execution.
76
+ * Integrates with PlanLearning for continuous improvement.
77
+ */
78
+ class PlanExecutor {
79
+ constructor(db, integration, config = {}) {
80
+ this.registry = null; // AgentRegistry - lazily initialized
81
+ this.ownsRegistry = false; // Track if we created the registry
82
+ this.db = db;
83
+ this.integration = integration;
84
+ this.planLearning = new PlanLearning_1.PlanLearning(db);
85
+ this.logger = Logger_1.Logger.getInstance();
86
+ this.config = { ...DEFAULT_CONFIG, ...config };
87
+ this.currentWorldState = { ...types_1.DEFAULT_WORLD_STATE };
88
+ // Registry is lazily initialized only when needed (not in dry-run mode)
89
+ }
90
+ /**
91
+ * Get the PlanLearning instance for external access
92
+ */
93
+ getPlanLearning() {
94
+ return this.planLearning;
95
+ }
96
+ /**
97
+ * Update current world state (called by integration or externally)
98
+ */
99
+ updateWorldState(state) {
100
+ this.currentWorldState = {
101
+ ...this.currentWorldState,
102
+ ...state,
103
+ coverage: { ...this.currentWorldState.coverage, ...state.coverage },
104
+ quality: { ...this.currentWorldState.quality, ...state.quality },
105
+ fleet: { ...this.currentWorldState.fleet, ...state.fleet },
106
+ resources: { ...this.currentWorldState.resources, ...state.resources },
107
+ context: { ...this.currentWorldState.context, ...state.context }
108
+ };
109
+ }
110
+ /**
111
+ * Get current world state
112
+ */
113
+ getWorldState() {
114
+ return { ...this.currentWorldState };
115
+ }
116
+ /**
117
+ * Initialize registry only when needed for actual execution
118
+ */
119
+ async ensureRegistry() {
120
+ if (!this.registry) {
121
+ const { getAgentRegistry } = await getAgentRegistryModule();
122
+ this.registry = getAgentRegistry();
123
+ this.ownsRegistry = true;
124
+ }
125
+ return this.registry;
126
+ }
127
+ /**
128
+ * Cleanup resources - call this when done with the executor
129
+ */
130
+ async cleanup() {
131
+ // Don't cleanup singleton registry - it's shared
132
+ this.registry = null;
133
+ this.ownsRegistry = false;
134
+ }
135
+ /**
136
+ * Execute a remediation plan
137
+ *
138
+ * @param plan - The remediation plan to execute
139
+ * @param context - Quality gate context for replanning
140
+ * @param metrics - Current metrics for replanning
141
+ */
142
+ async executePlan(plan, context, metrics) {
143
+ const startTime = Date.now();
144
+ const result = {
145
+ planId: plan.planId,
146
+ success: false,
147
+ totalDurationMs: 0,
148
+ actionsExecuted: 0,
149
+ actionsSucceeded: 0,
150
+ actionsFailed: 0,
151
+ actionResults: [],
152
+ replanned: false
153
+ };
154
+ // Track executed actions for learning (Phase 5 integration)
155
+ const executedActions = [];
156
+ // Initialize world state from metrics
157
+ this.initializeWorldStateFromMetrics(metrics, context);
158
+ const initialWorldState = this.getWorldState();
159
+ this.logger.info('[PlanExecutor] Starting plan execution', {
160
+ planId: plan.planId,
161
+ actionCount: plan.actions.length,
162
+ dryRun: this.config.dryRun
163
+ });
164
+ // Update plan status to 'executing'
165
+ await this.updatePlanStatus(plan.planId, 'executing');
166
+ let replanAttempts = 0;
167
+ let currentPlan = plan;
168
+ while (replanAttempts <= this.config.maxReplanAttempts) {
169
+ try {
170
+ // Execute each action in sequence
171
+ for (const action of currentPlan.actions) {
172
+ // Capture state before action
173
+ const stateBefore = this.getWorldState();
174
+ const actionResult = await this.executeAction(action, context);
175
+ result.actionResults.push(actionResult);
176
+ result.actionsExecuted++;
177
+ // Phase 6: Capture state after action
178
+ // Use real output parsing in live mode, simulation in dry-run
179
+ let stateAfter;
180
+ if (this.config.dryRun) {
181
+ stateAfter = this.simulateActionEffects(stateBefore, action, actionResult.success);
182
+ }
183
+ else {
184
+ // Live mode: parse actual agent output for real measurements
185
+ stateAfter = this.updateWorldStateFromAgentOutput(action, actionResult.output, stateBefore);
186
+ // Fallback to simulation if no output parsed
187
+ if (JSON.stringify(stateAfter) === JSON.stringify(stateBefore)) {
188
+ stateAfter = this.simulateActionEffects(stateBefore, action, actionResult.success);
189
+ }
190
+ }
191
+ this.currentWorldState = stateAfter;
192
+ // Build ExecutedAction for learning
193
+ const executedAction = {
194
+ action: this.remediationActionToGOAPAction(action),
195
+ success: actionResult.success,
196
+ result: actionResult.output,
197
+ error: actionResult.error,
198
+ stateBefore,
199
+ stateAfter,
200
+ executionTimeMs: actionResult.durationMs,
201
+ agentId: actionResult.agentId
202
+ };
203
+ executedActions.push(executedAction);
204
+ if (actionResult.success) {
205
+ result.actionsSucceeded++;
206
+ // Record success for learning (legacy + new)
207
+ await this.integration.recordActionOutcome(action.id, true);
208
+ }
209
+ else {
210
+ result.actionsFailed++;
211
+ // Record failure for learning (legacy + new)
212
+ await this.integration.recordActionOutcome(action.id, false);
213
+ if (!this.config.continueOnFailure) {
214
+ this.logger.warn('[PlanExecutor] Action failed, attempting replan', {
215
+ actionId: action.id,
216
+ actionName: action.name,
217
+ error: actionResult.error
218
+ });
219
+ // Try to replan
220
+ replanAttempts++;
221
+ if (replanAttempts > this.config.maxReplanAttempts) {
222
+ result.error = `Max replan attempts (${this.config.maxReplanAttempts}) exceeded. Last error: ${actionResult.error}`;
223
+ break;
224
+ }
225
+ // Try alternative path first
226
+ if (currentPlan.alternativePaths.length > 0) {
227
+ const altPath = currentPlan.alternativePaths[0];
228
+ this.logger.info('[PlanExecutor] Using alternative path', {
229
+ alternativePlanId: altPath.planId,
230
+ difference: altPath.differenceFromPrimary
231
+ });
232
+ // Generate new plan from alternative
233
+ const newPlan = await this.integration.generateRemediationPlan(metrics, context);
234
+ if (newPlan) {
235
+ currentPlan = newPlan;
236
+ result.replanned = true;
237
+ result.alternativePlanUsed = altPath.planId;
238
+ continue; // Restart with new plan
239
+ }
240
+ }
241
+ // Full replan if no alternatives
242
+ const newPlan = await this.integration.generateRemediationPlan(metrics, context);
243
+ if (newPlan) {
244
+ currentPlan = newPlan;
245
+ result.replanned = true;
246
+ this.logger.info('[PlanExecutor] Replanned with new strategy', {
247
+ newPlanId: newPlan.planId
248
+ });
249
+ continue;
250
+ }
251
+ result.error = `Replanning failed after action ${action.id}`;
252
+ break;
253
+ }
254
+ }
255
+ }
256
+ // If we get here without breaking, we succeeded
257
+ if (!result.error) {
258
+ result.success = result.actionsFailed === 0;
259
+ }
260
+ break;
261
+ }
262
+ catch (error) {
263
+ result.error = error instanceof Error ? error.message : String(error);
264
+ this.logger.error('[PlanExecutor] Plan execution failed', { error: result.error });
265
+ break;
266
+ }
267
+ }
268
+ result.totalDurationMs = Date.now() - startTime;
269
+ // Update plan status
270
+ await this.updatePlanStatus(plan.planId, result.success ? 'completed' : 'failed', result.success, result.error);
271
+ // Mark plan as completed via integration
272
+ await this.integration.completePlan(plan.planId, result.success, result.error);
273
+ // Phase 5 & 6: Learn from execution and store signatures
274
+ if (executedActions.length > 0) {
275
+ try {
276
+ const goapPlan = this.remediationPlanToGOAPPlan(plan, initialWorldState);
277
+ // Learn from execution (Phase 5)
278
+ const learningOutcome = await this.planLearning.learnFromExecution(goapPlan, executedActions, result.success);
279
+ this.logger.info('[PlanExecutor] Learning from execution completed', {
280
+ planId: plan.planId,
281
+ actionsUpdated: learningOutcome.actionsUpdated,
282
+ qValueUpdates: learningOutcome.qValueUpdates
283
+ });
284
+ // Phase 6: Store plan signature for future reuse (only for successful executions)
285
+ if (result.success && !this.config.dryRun) {
286
+ try {
287
+ // Get PlanSimilarity from integration's planner
288
+ const planner = this.integration.getPlanner();
289
+ if (planner) {
290
+ planner.storePlanSignature(goapPlan, initialWorldState);
291
+ this.logger.info('[PlanExecutor] Plan signature stored for future reuse', {
292
+ planId: plan.planId,
293
+ actionCount: goapPlan.actions.length
294
+ });
295
+ }
296
+ }
297
+ catch (sigError) {
298
+ this.logger.warn('[PlanExecutor] Failed to store plan signature', {
299
+ error: sigError instanceof Error ? sigError.message : String(sigError)
300
+ });
301
+ }
302
+ }
303
+ }
304
+ catch (error) {
305
+ // Learning failure should not fail the execution
306
+ this.logger.warn('[PlanExecutor] Learning from execution failed', {
307
+ error: error instanceof Error ? error.message : String(error)
308
+ });
309
+ }
310
+ }
311
+ this.logger.info('[PlanExecutor] Plan execution completed', {
312
+ planId: plan.planId,
313
+ success: result.success,
314
+ duration: `${result.totalDurationMs}ms`,
315
+ actionsExecuted: result.actionsExecuted,
316
+ actionsSucceeded: result.actionsSucceeded,
317
+ actionsFailed: result.actionsFailed,
318
+ replanned: result.replanned
319
+ });
320
+ return result;
321
+ }
322
+ /**
323
+ * Execute a single remediation action
324
+ */
325
+ async executeAction(action, context) {
326
+ const startTime = Date.now();
327
+ const result = {
328
+ actionId: action.id,
329
+ actionName: action.name,
330
+ success: false,
331
+ durationMs: 0
332
+ };
333
+ if (this.config.dryRun) {
334
+ this.logger.info('[PlanExecutor] DRY RUN - Would execute action', {
335
+ actionId: action.id,
336
+ actionName: action.name,
337
+ agentType: action.agentType
338
+ });
339
+ result.success = true;
340
+ result.durationMs = Date.now() - startTime;
341
+ return result;
342
+ }
343
+ this.logger.info('[PlanExecutor] Executing action', {
344
+ actionId: action.id,
345
+ actionName: action.name,
346
+ agentType: action.agentType
347
+ });
348
+ try {
349
+ // Get registry only when actually executing (not in dry-run)
350
+ const registry = await this.ensureRegistry();
351
+ // Map GOAP agent type to MCP agent type
352
+ const mcpAgentType = this.mapAgentType(action.agentType);
353
+ // Spawn or get an agent of the required type
354
+ const { id: agentId } = await registry.spawnAgent(mcpAgentType, {
355
+ name: `${mcpAgentType}-${action.id}`,
356
+ description: `Spawned for action: ${action.name}`,
357
+ capabilities: this.getCapabilitiesForAction(action)
358
+ });
359
+ result.agentId = agentId;
360
+ // Create task from action
361
+ const task = this.createTaskFromAction(action, context);
362
+ // Execute with timeout
363
+ const executePromise = registry.executeTask(agentId, task);
364
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Action timeout')), this.config.actionTimeoutMs));
365
+ const output = await Promise.race([executePromise, timeoutPromise]);
366
+ result.success = true;
367
+ result.output = output;
368
+ // Terminate the agent after use (cleanup)
369
+ await registry.terminateAgent(agentId).catch((err) => this.logger.warn('[PlanExecutor] Failed to terminate agent', { agentId, error: err }));
370
+ }
371
+ catch (error) {
372
+ result.success = false;
373
+ result.error = error instanceof Error ? error.message : String(error);
374
+ this.logger.error('[PlanExecutor] Action execution failed', {
375
+ actionId: action.id,
376
+ error: result.error
377
+ });
378
+ }
379
+ result.durationMs = Date.now() - startTime;
380
+ return result;
381
+ }
382
+ /**
383
+ * Map GOAP agent type to MCP agent type
384
+ *
385
+ * GOAP actions use 'qe-*' prefixed agent types which need to be
386
+ * mapped to MCP types that AgentRegistry understands.
387
+ */
388
+ mapAgentType(goapAgentType) {
389
+ const mapping = {
390
+ // Core Testing Agents
391
+ 'qe-test-generator': 'test-generator',
392
+ 'qe-test-executor': 'test-executor',
393
+ 'qe-test-writer': 'test-generator', // Test writers use test-generator agent
394
+ 'qe-integration-tester': 'test-executor', // Integration tests use test-executor
395
+ // Coverage & Analysis Agents
396
+ 'qe-coverage-analyzer': 'coverage-analyzer',
397
+ 'qe-code-complexity': 'code-analyzer', // Maps to quality-analyzer
398
+ 'qe-code-intelligence': 'code-analyzer', // Maps to quality-analyzer
399
+ // Quality & Gate Agents
400
+ 'qe-quality-gate': 'quality-gate',
401
+ 'qe-quality-analyzer': 'code-analyzer',
402
+ // Security Agents
403
+ 'qe-security-scanner': 'security-scanner',
404
+ // Performance Agents
405
+ 'qe-performance-tester': 'performance-tester',
406
+ // Specialized Testing Agents
407
+ 'qe-flaky-test-hunter': 'flaky-test-detector',
408
+ 'qe-regression-risk-analyzer': 'regression-analyzer',
409
+ 'qe-chaos-engineer': 'chaos-engineer',
410
+ 'qe-visual-tester': 'visual-tester',
411
+ // Strategic Planning Agents
412
+ 'qe-requirements-validator': 'requirements-validator',
413
+ 'qe-deployment-readiness': 'deployment-validator',
414
+ 'qe-production-intelligence': 'production-analyzer',
415
+ // Fleet & Orchestration Agents
416
+ 'qe-fleet-commander': 'fleet-commander',
417
+ // Data & Contract Agents
418
+ 'qe-test-data-architect': 'data-generator',
419
+ 'qe-api-contract-validator': 'contract-validator',
420
+ // Quality Experience (QX) Agent
421
+ 'qe-qx-partner': 'qx-partner',
422
+ // Accessibility Agent
423
+ 'qe-accessibility-ally': 'accessibility-ally',
424
+ // Legacy/simple mappings (for backward compatibility)
425
+ 'test-generator': 'test-generator',
426
+ 'test-executor': 'test-executor',
427
+ 'coverage-analyzer': 'coverage-analyzer',
428
+ 'quality-gate': 'quality-gate',
429
+ 'performance-tester': 'performance-tester',
430
+ 'security-scanner': 'security-scanner',
431
+ 'fleet-commander': 'fleet-commander',
432
+ 'chaos-engineer': 'chaos-engineer'
433
+ };
434
+ const mcpType = mapping[goapAgentType];
435
+ if (!mcpType) {
436
+ this.logger.warn(`[PlanExecutor] Unknown GOAP agent type: ${goapAgentType}, defaulting to quality-gate`);
437
+ }
438
+ return mcpType || 'quality-gate';
439
+ }
440
+ /**
441
+ * Get capabilities for an action
442
+ */
443
+ getCapabilitiesForAction(action) {
444
+ const categoryCapabilities = {
445
+ test: ['test-execution', 'test-validation'],
446
+ coverage: ['coverage-analysis', 'gap-detection'],
447
+ security: ['vulnerability-scanning', 'security-testing'],
448
+ performance: ['load-testing', 'performance-analysis'],
449
+ analysis: ['code-analysis', 'impact-analysis'],
450
+ process: ['decision-making', 'workflow-management'],
451
+ fleet: ['agent-coordination', 'resource-management']
452
+ };
453
+ return categoryCapabilities[action.category] || ['generic-execution'];
454
+ }
455
+ /**
456
+ * Create a task from a remediation action
457
+ *
458
+ * Maps GOAP action categories to structured task payloads that
459
+ * QE agents can understand and execute properly.
460
+ */
461
+ createTaskFromAction(action, context) {
462
+ const taskId = `task-${action.id}-${Date.now()}`;
463
+ const priority = context.criticality === 'critical' ? 1 : context.criticality === 'high' ? 3 : 5;
464
+ // Build category-specific payload
465
+ const categoryPayload = this.buildCategoryPayload(action, context);
466
+ return {
467
+ id: taskId,
468
+ type: this.mapCategoryToTaskType(action.category),
469
+ taskType: this.mapCategoryToTaskType(action.category),
470
+ payload: {
471
+ ...categoryPayload,
472
+ actionId: action.id,
473
+ actionName: action.name,
474
+ description: action.description,
475
+ effects: action.effects,
476
+ projectId: context.projectId,
477
+ buildId: context.buildId,
478
+ environment: context.environment
479
+ },
480
+ priority,
481
+ description: action.description || action.name,
482
+ context: {
483
+ source: 'goap-remediation',
484
+ planAction: action.id,
485
+ goapCategory: action.category
486
+ },
487
+ requirements: this.buildRequirements(action)
488
+ };
489
+ }
490
+ /**
491
+ * Build category-specific payload for task execution
492
+ *
493
+ * Note: action.effects is string[] describing the state changes
494
+ */
495
+ buildCategoryPayload(action, context) {
496
+ const basePayload = {
497
+ actionId: action.id,
498
+ actionName: action.name
499
+ };
500
+ // Parse coverage target from effects if present
501
+ const coverageTarget = this.extractCoverageTarget(action.effects);
502
+ switch (action.category) {
503
+ case 'test':
504
+ return {
505
+ ...basePayload,
506
+ testType: this.inferTestType(action.id),
507
+ targetCoverage: coverageTarget,
508
+ runIntegration: action.id.includes('integration'),
509
+ runUnit: action.id.includes('unit') || !action.id.includes('integration')
510
+ };
511
+ case 'coverage':
512
+ return {
513
+ ...basePayload,
514
+ analysisType: 'gap-detection',
515
+ targetCoverage: coverageTarget,
516
+ includeUncovered: true
517
+ };
518
+ case 'security':
519
+ return {
520
+ ...basePayload,
521
+ scanType: this.inferSecurityScanType(action.id),
522
+ severityThreshold: action.id.includes('critical') ? 'critical' : 'high',
523
+ autoFix: action.id.includes('fix') || action.id.includes('remediate')
524
+ };
525
+ case 'performance':
526
+ return {
527
+ ...basePayload,
528
+ testType: this.inferPerformanceTestType(action.id),
529
+ durationSeconds: 60,
530
+ targetP95Ms: 200,
531
+ targetErrorRate: 0.01
532
+ };
533
+ case 'analysis':
534
+ return {
535
+ ...basePayload,
536
+ analysisDepth: 'full',
537
+ includeMetrics: true
538
+ };
539
+ case 'process':
540
+ return {
541
+ ...basePayload,
542
+ processType: 'quality-gate-evaluation',
543
+ environment: context.environment,
544
+ criticality: context.criticality
545
+ };
546
+ case 'fleet':
547
+ return {
548
+ ...basePayload,
549
+ fleetOperation: this.inferFleetOperation(action.id),
550
+ maxAgents: 10
551
+ };
552
+ default:
553
+ return basePayload;
554
+ }
555
+ }
556
+ /**
557
+ * Extract coverage target from effects array
558
+ */
559
+ extractCoverageTarget(effects) {
560
+ // Effects are strings like "coverage.line >= 80" or "Increase line coverage by 10%"
561
+ for (const effect of effects) {
562
+ const match = effect.match(/coverage.*?(\d+)/i);
563
+ if (match) {
564
+ return parseInt(match[1], 10);
565
+ }
566
+ }
567
+ return 80; // Default target
568
+ }
569
+ /**
570
+ * Map action category to task type
571
+ */
572
+ mapCategoryToTaskType(category) {
573
+ const mapping = {
574
+ test: 'test-execution',
575
+ coverage: 'coverage-analysis',
576
+ security: 'security-scan',
577
+ performance: 'performance-test',
578
+ analysis: 'code-analysis',
579
+ process: 'process-evaluation',
580
+ fleet: 'fleet-management'
581
+ };
582
+ return mapping[category] || 'generic';
583
+ }
584
+ /**
585
+ * Infer test type from action ID
586
+ */
587
+ inferTestType(actionId) {
588
+ if (actionId.includes('unit'))
589
+ return 'unit';
590
+ if (actionId.includes('integration'))
591
+ return 'integration';
592
+ if (actionId.includes('e2e'))
593
+ return 'e2e';
594
+ if (actionId.includes('smoke'))
595
+ return 'smoke';
596
+ if (actionId.includes('regression'))
597
+ return 'regression';
598
+ return 'unit';
599
+ }
600
+ /**
601
+ * Infer security scan type from action ID
602
+ */
603
+ inferSecurityScanType(actionId) {
604
+ if (actionId.includes('sast'))
605
+ return 'sast';
606
+ if (actionId.includes('dast'))
607
+ return 'dast';
608
+ if (actionId.includes('dependency'))
609
+ return 'dependency';
610
+ if (actionId.includes('vulnerability'))
611
+ return 'vulnerability';
612
+ return 'comprehensive';
613
+ }
614
+ /**
615
+ * Infer performance test type from action ID
616
+ */
617
+ inferPerformanceTestType(actionId) {
618
+ if (actionId.includes('load'))
619
+ return 'load';
620
+ if (actionId.includes('stress'))
621
+ return 'stress';
622
+ if (actionId.includes('spike'))
623
+ return 'spike';
624
+ if (actionId.includes('soak'))
625
+ return 'soak';
626
+ if (actionId.includes('baseline'))
627
+ return 'baseline';
628
+ return 'load';
629
+ }
630
+ /**
631
+ * Infer fleet operation from action ID
632
+ */
633
+ inferFleetOperation(actionId) {
634
+ if (actionId.includes('spawn'))
635
+ return 'spawn';
636
+ if (actionId.includes('terminate'))
637
+ return 'terminate';
638
+ if (actionId.includes('scale'))
639
+ return 'scale';
640
+ if (actionId.includes('optimize'))
641
+ return 'optimize';
642
+ return 'manage';
643
+ }
644
+ /**
645
+ * Build requirements for task execution
646
+ */
647
+ buildRequirements(action) {
648
+ return {
649
+ timeout: action.estimatedDuration || 300000,
650
+ retries: 1,
651
+ expectedEffects: action.effects
652
+ };
653
+ }
654
+ // ============================================================================
655
+ // Phase 6: Live Execution with Real World State Updates
656
+ // ============================================================================
657
+ /**
658
+ * Parse agent output and update world state with real measurements
659
+ * This is called in live execution mode (not dry-run)
660
+ */
661
+ updateWorldStateFromAgentOutput(action, output, stateBefore) {
662
+ const stateAfter = JSON.parse(JSON.stringify(stateBefore));
663
+ if (!output)
664
+ return stateAfter;
665
+ // Parse output based on action category
666
+ switch (action.category) {
667
+ case 'test':
668
+ this.parseTestOutput(output, stateAfter);
669
+ break;
670
+ case 'coverage':
671
+ this.parseCoverageOutput(output, stateAfter);
672
+ break;
673
+ case 'security':
674
+ this.parseSecurityOutput(output, stateAfter);
675
+ break;
676
+ case 'performance':
677
+ this.parsePerformanceOutput(output, stateAfter);
678
+ break;
679
+ case 'analysis':
680
+ this.parseAnalysisOutput(output, stateAfter);
681
+ break;
682
+ default:
683
+ // For other categories, use simulation as fallback
684
+ break;
685
+ }
686
+ return stateAfter;
687
+ }
688
+ /**
689
+ * Parse test execution output
690
+ */
691
+ parseTestOutput(output, state) {
692
+ // Look for coverage data in output
693
+ if (output.coverage) {
694
+ state.coverage.line = output.coverage.line ?? output.coverage.linePercentage ?? state.coverage.line;
695
+ state.coverage.branch = output.coverage.branch ?? output.coverage.branchPercentage ?? state.coverage.branch;
696
+ state.coverage.function = output.coverage.function ?? output.coverage.functionPercentage ?? state.coverage.function;
697
+ state.coverage.measured = true;
698
+ }
699
+ // Look for test results
700
+ if (output.testResults || output.tests) {
701
+ const results = output.testResults || output.tests;
702
+ if (results.total && results.passed !== undefined) {
703
+ state.quality.testsPassing = (results.passed / results.total) * 100;
704
+ state.quality.testsMeasured = true;
705
+ }
706
+ }
707
+ // Handle simple pass rate
708
+ if (typeof output.passRate === 'number') {
709
+ state.quality.testsPassing = output.passRate;
710
+ state.quality.testsMeasured = true;
711
+ }
712
+ }
713
+ /**
714
+ * Parse coverage analysis output
715
+ */
716
+ parseCoverageOutput(output, state) {
717
+ if (output.coverage) {
718
+ state.coverage.line = output.coverage.line ?? state.coverage.line;
719
+ state.coverage.branch = output.coverage.branch ?? state.coverage.branch;
720
+ state.coverage.function = output.coverage.function ?? state.coverage.function;
721
+ state.coverage.measured = true;
722
+ }
723
+ // Handle gaps detected
724
+ if (output.gaps && Array.isArray(output.gaps)) {
725
+ // Store gap information for future actions
726
+ this.logger.debug('[PlanExecutor] Coverage gaps detected', { gapCount: output.gaps.length });
727
+ }
728
+ }
729
+ /**
730
+ * Parse security scan output
731
+ */
732
+ parseSecurityOutput(output, state) {
733
+ if (output.securityScore !== undefined) {
734
+ state.quality.securityScore = output.securityScore;
735
+ state.quality.securityMeasured = true;
736
+ }
737
+ // Calculate from vulnerabilities
738
+ if (output.vulnerabilities || output.summary) {
739
+ const summary = output.summary || output.vulnerabilities;
740
+ const critical = summary.critical ?? 0;
741
+ const high = summary.high ?? 0;
742
+ const medium = summary.medium ?? 0;
743
+ // Score: 100 - (critical*25 + high*10 + medium*5), clamped to 0-100
744
+ state.quality.securityScore = Math.max(0, Math.min(100, 100 - (critical * 25 + high * 10 + medium * 5)));
745
+ state.quality.securityMeasured = true;
746
+ }
747
+ }
748
+ /**
749
+ * Parse performance test output
750
+ */
751
+ parsePerformanceOutput(output, state) {
752
+ if (output.performanceScore !== undefined) {
753
+ state.quality.performanceScore = output.performanceScore;
754
+ state.quality.performanceMeasured = true;
755
+ }
756
+ // Calculate from error rate and latency
757
+ if (output.errorRate !== undefined || output.p95 !== undefined) {
758
+ const errorPenalty = (output.errorRate ?? 0) * 100;
759
+ const latencyPenalty = output.p95 && output.targetP95
760
+ ? Math.max(0, (output.p95 - output.targetP95) / output.targetP95 * 50)
761
+ : 0;
762
+ state.quality.performanceScore = Math.max(0, 100 - errorPenalty - latencyPenalty);
763
+ state.quality.performanceMeasured = true;
764
+ }
765
+ }
766
+ /**
767
+ * Parse code analysis output
768
+ */
769
+ parseAnalysisOutput(output, state) {
770
+ if (output.technicalDebt !== undefined) {
771
+ state.quality.technicalDebt = output.technicalDebt;
772
+ }
773
+ if (output.complexity !== undefined) {
774
+ state.quality.complexityMeasured = true;
775
+ }
776
+ }
777
+ // ============================================================================
778
+ // Phase 5: Learning Integration Helpers
779
+ // ============================================================================
780
+ /**
781
+ * Initialize world state from quality gate metrics
782
+ */
783
+ initializeWorldStateFromMetrics(metrics, context) {
784
+ // Calculate pass rate from test results
785
+ const testResults = metrics.testResults;
786
+ const testPassRate = testResults && testResults.total
787
+ ? ((testResults.passed ?? 0) / testResults.total) * 100
788
+ : 0;
789
+ // Calculate security score (inverse of vulnerability count)
790
+ const securitySummary = metrics.security?.summary;
791
+ const securityScore = securitySummary
792
+ ? Math.max(0, 100 - ((securitySummary.critical ?? 0) * 25 + (securitySummary.high ?? 0) * 10))
793
+ : 100;
794
+ // Calculate performance score from error rate
795
+ const performanceScore = metrics.performance?.errorRate !== undefined
796
+ ? Math.max(0, 100 - metrics.performance.errorRate * 100)
797
+ : 100;
798
+ // Map criticality to risk level
799
+ const riskLevelMap = {
800
+ low: 'low',
801
+ medium: 'medium',
802
+ high: 'high',
803
+ critical: 'critical'
804
+ };
805
+ const riskLevel = riskLevelMap[context.criticality || 'medium'] || 'medium';
806
+ // Estimate change size from changed files count
807
+ const changeSize = (context.changedFiles?.length ?? 0) <= 5 ? 'small' :
808
+ (context.changedFiles?.length ?? 0) <= 20 ? 'medium' : 'large';
809
+ this.currentWorldState = {
810
+ coverage: {
811
+ line: metrics.coverage?.linePercentage ?? metrics.coverage?.overallPercentage ?? 0,
812
+ branch: metrics.coverage?.branchPercentage ?? 0,
813
+ function: metrics.coverage?.functionPercentage ?? 0,
814
+ target: 80,
815
+ measured: metrics.coverage !== undefined
816
+ },
817
+ quality: {
818
+ testsPassing: testPassRate,
819
+ securityScore,
820
+ performanceScore,
821
+ technicalDebt: metrics.codeQuality?.technicalDebtDays ?? 0,
822
+ gateStatus: 'pending',
823
+ testsMeasured: testResults !== undefined,
824
+ securityMeasured: metrics.security !== undefined,
825
+ performanceMeasured: metrics.performance !== undefined
826
+ },
827
+ fleet: {
828
+ activeAgents: 0,
829
+ availableAgents: context.availableAgents || ['test-generator', 'coverage-analyzer', 'security-scanner'],
830
+ busyAgents: [],
831
+ agentTypes: {}
832
+ },
833
+ resources: {
834
+ timeRemaining: context.timeRemaining || 3600,
835
+ memoryAvailable: 4096,
836
+ parallelSlots: 4
837
+ },
838
+ context: {
839
+ environment: context.environment || 'development',
840
+ changeSize,
841
+ riskLevel,
842
+ previousFailures: context.previousFailures || 0
843
+ }
844
+ };
845
+ }
846
+ /**
847
+ * Simulate action effects on world state
848
+ */
849
+ simulateActionEffects(stateBefore, action, success) {
850
+ const stateAfter = JSON.parse(JSON.stringify(stateBefore));
851
+ if (!success)
852
+ return stateAfter;
853
+ // Parse effects and apply them
854
+ for (const effect of action.effects) {
855
+ // Effect format examples:
856
+ // "coverage.line >= 80" -> set coverage if action category is test/coverage
857
+ // "quality.testsPassing = true" -> set tests passing
858
+ // "quality.securityMeasured = true" -> mark security as measured
859
+ if (effect.includes('coverage') && action.category === 'test') {
860
+ // Simulate coverage improvement
861
+ stateAfter.coverage.line = Math.min(100, stateBefore.coverage.line + 10);
862
+ stateAfter.coverage.branch = Math.min(100, stateBefore.coverage.branch + 5);
863
+ stateAfter.coverage.measured = true;
864
+ }
865
+ if (effect.includes('testsPassing') || action.category === 'test') {
866
+ stateAfter.quality.testsPassing = Math.min(100, stateBefore.quality.testsPassing + 5);
867
+ stateAfter.quality.testsMeasured = true;
868
+ }
869
+ if (effect.includes('security') || action.category === 'security') {
870
+ stateAfter.quality.securityScore = Math.min(100, stateBefore.quality.securityScore + 10);
871
+ stateAfter.quality.securityMeasured = true;
872
+ }
873
+ if (effect.includes('performance') || action.category === 'performance') {
874
+ stateAfter.quality.performanceScore = Math.min(100, stateBefore.quality.performanceScore + 5);
875
+ stateAfter.quality.performanceMeasured = true;
876
+ }
877
+ if (effect.includes('gateStatus')) {
878
+ stateAfter.quality.gateStatus = 'passed';
879
+ stateAfter.quality.gateEvaluated = true;
880
+ }
881
+ }
882
+ return stateAfter;
883
+ }
884
+ /**
885
+ * Convert RemediationAction to GOAPAction for learning
886
+ */
887
+ remediationActionToGOAPAction(action) {
888
+ return {
889
+ id: action.id,
890
+ name: action.name,
891
+ description: action.description,
892
+ agentType: action.agentType,
893
+ preconditions: {}, // Preconditions were already checked during planning
894
+ effects: {}, // Effects are string[] in RemediationAction
895
+ cost: 1.0 / (action.successRate || 1.0), // Higher cost for lower success rate
896
+ durationEstimate: action.estimatedDuration,
897
+ successRate: action.successRate,
898
+ category: action.category
899
+ };
900
+ }
901
+ /**
902
+ * Convert RemediationPlan to GOAPPlan for learning
903
+ */
904
+ remediationPlanToGOAPPlan(plan, initialState) {
905
+ return {
906
+ id: plan.planId,
907
+ actions: plan.actions.map(a => this.remediationActionToGOAPAction(a)),
908
+ totalCost: plan.totalCost,
909
+ estimatedDuration: plan.estimatedDuration,
910
+ goalConditions: {
911
+ 'quality.gateStatus': { eq: 'passed' }
912
+ },
913
+ initialState,
914
+ status: 'executing'
915
+ };
916
+ }
917
+ /**
918
+ * Update plan status in database
919
+ */
920
+ async updatePlanStatus(planId, status, success, failureReason) {
921
+ try {
922
+ if (status === 'executing') {
923
+ this.db.prepare(`
924
+ UPDATE goap_plans SET status = ?, started_at = CURRENT_TIMESTAMP WHERE id = ?
925
+ `).run(status, planId);
926
+ }
927
+ else {
928
+ this.db.prepare(`
929
+ UPDATE goap_plans
930
+ SET status = ?, success = ?, failure_reason = ?, completed_at = CURRENT_TIMESTAMP
931
+ WHERE id = ?
932
+ `).run(status, success ? 1 : 0, failureReason || null, planId);
933
+ }
934
+ }
935
+ catch (error) {
936
+ this.logger.warn('[PlanExecutor] Failed to update plan status', { planId, error });
937
+ }
938
+ }
939
+ }
940
+ exports.PlanExecutor = PlanExecutor;
941
+ /**
942
+ * Factory function to create a PlanExecutor
943
+ */
944
+ function createPlanExecutor(dbPath, config = {}) {
945
+ const Database = require('better-sqlite3');
946
+ const db = new Database(dbPath);
947
+ const integration = new GOAPQualityGateIntegration_1.GOAPQualityGateIntegration(db);
948
+ return {
949
+ executor: new PlanExecutor(db, integration, config),
950
+ integration
951
+ };
952
+ }
953
+ /**
954
+ * Execute a quality gate remediation with GOAP planning
955
+ *
956
+ * High-level function that:
957
+ * 1. Generates a remediation plan
958
+ * 2. Executes the plan
959
+ * 3. Records outcomes for learning
960
+ */
961
+ async function executeQualityGateRemediation(metrics, context, dbPath, targetGoal, config = {}) {
962
+ const { executor, integration } = createPlanExecutor(dbPath, config);
963
+ try {
964
+ await integration.initialize();
965
+ // Generate remediation plan
966
+ const plan = await integration.generateRemediationPlan(metrics, context, targetGoal);
967
+ if (!plan) {
968
+ Logger_1.Logger.getInstance().info('[executeQualityGateRemediation] No remediation needed - goal already satisfied');
969
+ return null;
970
+ }
971
+ // Execute the plan
972
+ return await executor.executePlan(plan, context, metrics);
973
+ }
974
+ finally {
975
+ integration.close();
976
+ }
977
+ }
978
+ //# sourceMappingURL=PlanExecutor.js.map