claude-flow-novice 2.15.8 → 2.15.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/cfn-loop-orchestration/IMPLEMENTATION_SUMMARY.md +519 -0
- package/.claude/skills/cfn-loop-orchestration/ORCHESTRATOR_IMPLEMENTATION.md +493 -0
- package/.claude/skills/cfn-loop-orchestration/ORCHESTRATOR_QUICK_START.md +499 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/consensus-ts.sh +104 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/deliverable-verifier-ts.sh +123 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/iteration-manager-ts.sh +89 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/orchestrate-ts.sh +104 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/timeout-calculator-ts.sh +47 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +2 -2
- package/.claude/skills/cfn-loop-orchestration/src/orchestrate.ts +648 -0
- package/.claude/skills/cfn-loop-orchestration/tests/orchestrate.test.ts +836 -0
- package/.claude/skills/cfn-redis-coordination/report-completion.sh +55 -10
- package/.claude/skills/cfn-redis-coordination/store-context.sh +31 -1
- package/README.md +205 -10
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +6 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +180 -229
- package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +6 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +6 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +6 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +20 -8
- package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +20 -8
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +20 -9
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +17 -7
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +3 -0
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +4 -1
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +4 -1
- package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +4 -1
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +5 -0
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +19 -9
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +20 -9
- package/claude-assets/agents/cfn-dev-team/documentation/pseudocode.md +2 -7
- package/claude-assets/agents/cfn-dev-team/reviewers/code-reviewer.md +9 -5
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +13 -6
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +13 -6
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +13 -6
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +15 -5
- package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +9 -5
- package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +8 -4
- package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +16 -13
- package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +9 -5
- package/claude-assets/agents/cfn-dev-team/testers/tester.md +9 -5
- package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +16 -9
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +16 -9
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +16 -9
- package/claude-assets/skills/cfn-loop-orchestration/IMPLEMENTATION_SUMMARY.md +519 -0
- package/claude-assets/skills/cfn-loop-orchestration/ORCHESTRATOR_IMPLEMENTATION.md +493 -0
- package/claude-assets/skills/cfn-loop-orchestration/ORCHESTRATOR_QUICK_START.md +499 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/consensus-ts.sh +104 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/deliverable-verifier-ts.sh +123 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/iteration-manager-ts.sh +89 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/orchestrate-ts.sh +104 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/timeout-calculator-ts.sh +47 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +2 -2
- package/claude-assets/skills/cfn-loop-orchestration/src/orchestrate.ts +648 -0
- package/claude-assets/skills/cfn-loop-orchestration/tests/orchestrate.test.ts +836 -0
- package/claude-assets/skills/cfn-redis-coordination/report-completion.sh +55 -10
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +31 -1
- package/dist/cli/config-manager.js +91 -109
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/coordination/coordinate.js +369 -0
- package/dist/coordination/coordinate.js.map +1 -0
- package/dist/coordination/spawn-agent.js +364 -0
- package/dist/coordination/spawn-agent.js.map +1 -0
- package/dist/coordination/types-export.js +38 -0
- package/dist/coordination/types-export.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CFN Loop Orchestrator - Complete TypeScript Implementation
|
|
3
|
+
* Orchestrates the Fail Never (CFN) Loop workflow with test-driven validation
|
|
4
|
+
* Supports MVP, Standard, and Enterprise execution modes
|
|
5
|
+
*
|
|
6
|
+
* Version: 3.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { gateCheck, GateCheckParams } from './helpers/gate-check';
|
|
10
|
+
import { collectConsensus, validateConsensus } from './helpers/consensus';
|
|
11
|
+
import { TestResult, ExecutionMode } from './types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Execution phases in the CFN Loop
|
|
15
|
+
*/
|
|
16
|
+
export type LoopPhase = 'loop3' | 'loop2' | 'product-owner' | 'complete';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Product owner decision outcomes
|
|
20
|
+
*/
|
|
21
|
+
export type ProductOwnerDecision = 'PROCEED' | 'ITERATE' | 'ABORT' | null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Orchestration configuration
|
|
25
|
+
*/
|
|
26
|
+
export interface OrchestrationConfig {
|
|
27
|
+
taskId: string;
|
|
28
|
+
mode: ExecutionMode;
|
|
29
|
+
maxIterations: number;
|
|
30
|
+
aceReflect?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Agent execution context
|
|
35
|
+
*/
|
|
36
|
+
export interface AgentExecutionContext {
|
|
37
|
+
agentId: string;
|
|
38
|
+
agentType: string;
|
|
39
|
+
loopType: 'loop3' | 'loop2';
|
|
40
|
+
iteration: number;
|
|
41
|
+
taskId: string;
|
|
42
|
+
timestamp: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Phase transition tracking
|
|
47
|
+
*/
|
|
48
|
+
export interface PhaseTransition {
|
|
49
|
+
fromPhase: LoopPhase;
|
|
50
|
+
toPhase: LoopPhase;
|
|
51
|
+
timestamp: number;
|
|
52
|
+
iteration: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Gate check result
|
|
57
|
+
*/
|
|
58
|
+
export interface GateCheckResult {
|
|
59
|
+
passed: boolean;
|
|
60
|
+
passRate: number;
|
|
61
|
+
threshold: number;
|
|
62
|
+
gap: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Consensus validation result
|
|
67
|
+
*/
|
|
68
|
+
export interface ConsensusValidationResult {
|
|
69
|
+
passed: boolean;
|
|
70
|
+
average: number;
|
|
71
|
+
threshold: number;
|
|
72
|
+
gap: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Test result aggregation
|
|
77
|
+
*/
|
|
78
|
+
export interface AggregatedTestResults {
|
|
79
|
+
totalPass: number;
|
|
80
|
+
totalFail: number;
|
|
81
|
+
totalSkip: number;
|
|
82
|
+
passRate: number;
|
|
83
|
+
agentCount: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Orchestration state tracking
|
|
88
|
+
*/
|
|
89
|
+
export interface OrchestrationState {
|
|
90
|
+
taskId: string;
|
|
91
|
+
mode: ExecutionMode;
|
|
92
|
+
iteration: number;
|
|
93
|
+
currentPhase: LoopPhase;
|
|
94
|
+
completedAgents: Set<string>;
|
|
95
|
+
failedAgents: Set<string>;
|
|
96
|
+
startTime: number;
|
|
97
|
+
lastUpdateTime: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Feedback for next iteration
|
|
102
|
+
*/
|
|
103
|
+
export interface IterationFeedback {
|
|
104
|
+
gatePassRate?: number;
|
|
105
|
+
consensusAverage?: number;
|
|
106
|
+
previousFailures?: string[];
|
|
107
|
+
reasons?: string[];
|
|
108
|
+
timestamp?: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Mode-specific configuration
|
|
113
|
+
*/
|
|
114
|
+
interface ModeThresholds {
|
|
115
|
+
gateThreshold: number;
|
|
116
|
+
consensusThreshold: number;
|
|
117
|
+
maxIterations: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const MODE_CONFIG: Record<ExecutionMode, ModeThresholds> = {
|
|
121
|
+
mvp: {
|
|
122
|
+
gateThreshold: 0.70,
|
|
123
|
+
consensusThreshold: 0.80,
|
|
124
|
+
maxIterations: 5,
|
|
125
|
+
},
|
|
126
|
+
standard: {
|
|
127
|
+
gateThreshold: 0.95,
|
|
128
|
+
consensusThreshold: 0.90,
|
|
129
|
+
maxIterations: 10,
|
|
130
|
+
},
|
|
131
|
+
enterprise: {
|
|
132
|
+
gateThreshold: 0.98,
|
|
133
|
+
consensusThreshold: 0.95,
|
|
134
|
+
maxIterations: 15,
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Main orchestrator class
|
|
140
|
+
*/
|
|
141
|
+
export class Orchestrator {
|
|
142
|
+
private config: OrchestrationConfig;
|
|
143
|
+
private state: OrchestrationState;
|
|
144
|
+
private testResults: Map<string, TestResult> = new Map();
|
|
145
|
+
private consensusScores: Map<string, number> = new Map();
|
|
146
|
+
private decision: ProductOwnerDecision = null;
|
|
147
|
+
private errors: Map<string, Error> = new Map();
|
|
148
|
+
private phaseHistory: PhaseTransition[] = [];
|
|
149
|
+
|
|
150
|
+
constructor(config: OrchestrationConfig) {
|
|
151
|
+
// Validate configuration
|
|
152
|
+
this.validateConfig(config);
|
|
153
|
+
|
|
154
|
+
this.config = config;
|
|
155
|
+
this.state = this.initializeState(config);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Validate configuration parameters
|
|
160
|
+
*/
|
|
161
|
+
private validateConfig(config: OrchestrationConfig): void {
|
|
162
|
+
if (!config.taskId || config.taskId.trim() === '') {
|
|
163
|
+
throw new Error('Task ID cannot be empty');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const validModes: ExecutionMode[] = ['mvp', 'standard', 'enterprise'];
|
|
167
|
+
if (!validModes.includes(config.mode)) {
|
|
168
|
+
throw new Error(`Invalid execution mode: ${config.mode}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!Number.isInteger(config.maxIterations) || config.maxIterations < 1) {
|
|
172
|
+
throw new Error('Max iterations must be at least 1');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (config.maxIterations > 100) {
|
|
176
|
+
throw new Error('Max iterations cannot exceed 100');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Initialize orchestration state
|
|
182
|
+
*/
|
|
183
|
+
private initializeState(config: OrchestrationConfig): OrchestrationState {
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
taskId: config.taskId,
|
|
188
|
+
mode: config.mode,
|
|
189
|
+
iteration: 0,
|
|
190
|
+
currentPhase: 'loop3',
|
|
191
|
+
completedAgents: new Set(),
|
|
192
|
+
failedAgents: new Set(),
|
|
193
|
+
startTime: now,
|
|
194
|
+
lastUpdateTime: now,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get current orchestration state
|
|
200
|
+
*/
|
|
201
|
+
public getState(): OrchestrationState {
|
|
202
|
+
return { ...this.state, completedAgents: new Set(this.state.completedAgents), failedAgents: new Set(this.state.failedAgents) };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get task ID
|
|
207
|
+
*/
|
|
208
|
+
public getTaskId(): string {
|
|
209
|
+
return this.config.taskId;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get execution mode
|
|
214
|
+
*/
|
|
215
|
+
public getMode(): ExecutionMode {
|
|
216
|
+
return this.config.mode;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get maximum iterations for mode
|
|
221
|
+
*/
|
|
222
|
+
public getMaxIterations(): number {
|
|
223
|
+
return this.config.maxIterations;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get gate threshold for current mode
|
|
228
|
+
*/
|
|
229
|
+
public getGateThreshold(): number {
|
|
230
|
+
return MODE_CONFIG[this.config.mode].gateThreshold;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get consensus threshold for current mode
|
|
235
|
+
*/
|
|
236
|
+
public getConsensusThreshold(): number {
|
|
237
|
+
return MODE_CONFIG[this.config.mode].consensusThreshold;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Transition to next phase
|
|
242
|
+
*/
|
|
243
|
+
public transitionPhase(newPhase: LoopPhase): void {
|
|
244
|
+
const transition: PhaseTransition = {
|
|
245
|
+
fromPhase: this.state.currentPhase,
|
|
246
|
+
toPhase: newPhase,
|
|
247
|
+
timestamp: Date.now(),
|
|
248
|
+
iteration: this.state.iteration,
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
this.phaseHistory.push(transition);
|
|
252
|
+
this.state.currentPhase = newPhase;
|
|
253
|
+
this.state.lastUpdateTime = Date.now();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Increment iteration counter
|
|
258
|
+
*/
|
|
259
|
+
public incrementIteration(): void {
|
|
260
|
+
this.state.iteration++;
|
|
261
|
+
this.state.lastUpdateTime = Date.now();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Check if can continue iterating
|
|
266
|
+
*/
|
|
267
|
+
public canContinueIterating(): boolean {
|
|
268
|
+
return this.state.iteration < this.config.maxIterations;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Check if orchestration should terminate
|
|
273
|
+
*/
|
|
274
|
+
public shouldTerminate(): boolean {
|
|
275
|
+
if (this.decision === 'PROCEED' || this.decision === 'ABORT') {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (this.decision === 'ITERATE' && !this.canContinueIterating()) {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Mark agent as completed
|
|
288
|
+
*/
|
|
289
|
+
public markAgentComplete(agentId: string, _loopType: 'loop3' | 'loop2'): void {
|
|
290
|
+
this.state.completedAgents.add(agentId);
|
|
291
|
+
this.state.failedAgents.delete(agentId);
|
|
292
|
+
this.state.lastUpdateTime = Date.now();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Mark agent as failed
|
|
297
|
+
*/
|
|
298
|
+
public markAgentFailed(agentId: string, _loopType: 'loop3' | 'loop2'): void {
|
|
299
|
+
this.state.failedAgents.add(agentId);
|
|
300
|
+
this.state.completedAgents.delete(agentId);
|
|
301
|
+
this.state.lastUpdateTime = Date.now();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Record execution error for agent
|
|
306
|
+
*/
|
|
307
|
+
public recordExecutionError(agentId: string, error: Error): void {
|
|
308
|
+
this.errors.set(agentId, error);
|
|
309
|
+
this.markAgentFailed(agentId, 'loop3');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Record timeout for agent
|
|
314
|
+
*/
|
|
315
|
+
public recordTimeout(agentId: string, timeoutSeconds: number): void {
|
|
316
|
+
const error = new Error(`Agent timeout after ${timeoutSeconds}s`);
|
|
317
|
+
this.recordExecutionError(agentId, error);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Record test results for agent
|
|
322
|
+
*/
|
|
323
|
+
public recordTestResult(agentId: string, result: TestResult): void {
|
|
324
|
+
this.testResults.set(agentId, result);
|
|
325
|
+
this.state.lastUpdateTime = Date.now();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get test result for agent
|
|
330
|
+
*/
|
|
331
|
+
public getTestResult(agentId: string): TestResult | undefined {
|
|
332
|
+
return this.testResults.get(agentId);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Aggregate test results across all agents
|
|
337
|
+
*/
|
|
338
|
+
public aggregateTestResults(): AggregatedTestResults {
|
|
339
|
+
let totalPass = 0;
|
|
340
|
+
let totalFail = 0;
|
|
341
|
+
let totalSkip = 0;
|
|
342
|
+
|
|
343
|
+
for (const result of this.testResults.values()) {
|
|
344
|
+
totalPass += result.pass;
|
|
345
|
+
totalFail += result.fail;
|
|
346
|
+
totalSkip += result.skip ?? 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const total = totalPass + totalFail + totalSkip;
|
|
350
|
+
const passRate = total === 0 ? 0 : totalPass / total;
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
totalPass,
|
|
354
|
+
totalFail,
|
|
355
|
+
totalSkip,
|
|
356
|
+
passRate,
|
|
357
|
+
agentCount: this.testResults.size,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Check gate (Loop 3 → Loop 2 transition)
|
|
363
|
+
*/
|
|
364
|
+
public checkGate(passRate: number): GateCheckResult {
|
|
365
|
+
const threshold = this.getGateThreshold();
|
|
366
|
+
|
|
367
|
+
const params: GateCheckParams = {
|
|
368
|
+
passRate,
|
|
369
|
+
mode: this.config.mode,
|
|
370
|
+
threshold,
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const result = gateCheck(params);
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
passed: result.passed,
|
|
377
|
+
passRate: result.passRate,
|
|
378
|
+
threshold: result.threshold,
|
|
379
|
+
gap: result.gap,
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Record consensus score from validator
|
|
385
|
+
*/
|
|
386
|
+
public recordConsensusScore(validatorId: string, score: number): void {
|
|
387
|
+
if (score < 0 || score > 1) {
|
|
388
|
+
throw new Error(`Invalid consensus score: ${score} (must be 0.0-1.0)`);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
this.consensusScores.set(validatorId, score);
|
|
392
|
+
this.state.lastUpdateTime = Date.now();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Get all consensus scores
|
|
397
|
+
*/
|
|
398
|
+
public getConsensusScores(): number[] {
|
|
399
|
+
return Array.from(this.consensusScores.values());
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get consensus average
|
|
404
|
+
*/
|
|
405
|
+
public getConsensusAverage(): number {
|
|
406
|
+
const scores = this.getConsensusScores();
|
|
407
|
+
|
|
408
|
+
if (scores.length === 0) {
|
|
409
|
+
throw new Error('No consensus scores recorded');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const sum = scores.reduce((a, b) => a + b, 0);
|
|
413
|
+
return sum / scores.length;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Validate consensus against threshold
|
|
418
|
+
*/
|
|
419
|
+
public validateConsensus(): ConsensusValidationResult {
|
|
420
|
+
const scores = this.getConsensusScores();
|
|
421
|
+
|
|
422
|
+
if (scores.length === 0) {
|
|
423
|
+
throw new Error('No consensus scores recorded');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const result = collectConsensus(scores);
|
|
427
|
+
const validation = validateConsensus({
|
|
428
|
+
average: result.average,
|
|
429
|
+
mode: this.config.mode,
|
|
430
|
+
threshold: this.getConsensusThreshold(),
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
passed: validation.passed,
|
|
435
|
+
average: validation.average,
|
|
436
|
+
threshold: validation.threshold,
|
|
437
|
+
gap: validation.gap,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Record product owner decision
|
|
443
|
+
*/
|
|
444
|
+
public recordDecision(decision: ProductOwnerDecision): void {
|
|
445
|
+
this.decision = decision;
|
|
446
|
+
this.state.lastUpdateTime = Date.now();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Get recorded decision
|
|
451
|
+
*/
|
|
452
|
+
public getDecision(): ProductOwnerDecision {
|
|
453
|
+
return this.decision;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Parse decision from agent output
|
|
458
|
+
*/
|
|
459
|
+
public parseDecisionFromOutput(output: string): ProductOwnerDecision {
|
|
460
|
+
const normalizedOutput = output.toUpperCase();
|
|
461
|
+
|
|
462
|
+
if (normalizedOutput.includes('PROCEED')) {
|
|
463
|
+
return 'PROCEED';
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (normalizedOutput.includes('ITERATE')) {
|
|
467
|
+
return 'ITERATE';
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (normalizedOutput.includes('ABORT')) {
|
|
471
|
+
return 'ABORT';
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Spawn Loop 3 (implementer) agents
|
|
479
|
+
*/
|
|
480
|
+
public async spawnLoop3Agents(agentTypes: string[]): Promise<AgentExecutionContext[]> {
|
|
481
|
+
const agents: AgentExecutionContext[] = [];
|
|
482
|
+
const now = Date.now();
|
|
483
|
+
|
|
484
|
+
agentTypes.forEach((agentType, index) => {
|
|
485
|
+
agents.push({
|
|
486
|
+
agentId: `${agentType}-${this.state.iteration + 1}-${index + 1}`,
|
|
487
|
+
agentType,
|
|
488
|
+
loopType: 'loop3',
|
|
489
|
+
iteration: this.state.iteration + 1,
|
|
490
|
+
taskId: this.config.taskId,
|
|
491
|
+
timestamp: now,
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
return agents;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Spawn Loop 2 (validator) agents
|
|
500
|
+
*/
|
|
501
|
+
public async spawnLoop2Validators(validatorTypes: string[]): Promise<AgentExecutionContext[]> {
|
|
502
|
+
const validators: AgentExecutionContext[] = [];
|
|
503
|
+
const now = Date.now();
|
|
504
|
+
|
|
505
|
+
validatorTypes.forEach((validatorType, index) => {
|
|
506
|
+
validators.push({
|
|
507
|
+
agentId: `${validatorType}-${this.state.iteration + 1}-${index + 1}`,
|
|
508
|
+
agentType: validatorType,
|
|
509
|
+
loopType: 'loop2',
|
|
510
|
+
iteration: this.state.iteration + 1,
|
|
511
|
+
taskId: this.config.taskId,
|
|
512
|
+
timestamp: now,
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
return validators;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Build agent context for spawning
|
|
521
|
+
*/
|
|
522
|
+
public buildAgentContext(
|
|
523
|
+
agentId: string,
|
|
524
|
+
loopType: 'loop3' | 'loop2',
|
|
525
|
+
iteration: number,
|
|
526
|
+
_feedback?: IterationFeedback
|
|
527
|
+
): AgentExecutionContext {
|
|
528
|
+
return {
|
|
529
|
+
agentId,
|
|
530
|
+
agentType: 'unknown',
|
|
531
|
+
loopType,
|
|
532
|
+
iteration,
|
|
533
|
+
taskId: this.config.taskId,
|
|
534
|
+
timestamp: Date.now(),
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Prepare feedback for next iteration
|
|
540
|
+
*/
|
|
541
|
+
public prepareFeedback(feedback: IterationFeedback): IterationFeedback {
|
|
542
|
+
return {
|
|
543
|
+
...feedback,
|
|
544
|
+
timestamp: Date.now(),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Get phase history
|
|
550
|
+
*/
|
|
551
|
+
public getPhaseHistory(): PhaseTransition[] {
|
|
552
|
+
return [...this.phaseHistory];
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Get execution errors
|
|
557
|
+
*/
|
|
558
|
+
public getErrors(): Map<string, Error> {
|
|
559
|
+
return new Map(this.errors);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Reset state for new iteration
|
|
564
|
+
*/
|
|
565
|
+
public resetForIteration(): void {
|
|
566
|
+
this.testResults.clear();
|
|
567
|
+
this.consensusScores.clear();
|
|
568
|
+
this.decision = null;
|
|
569
|
+
this.errors.clear();
|
|
570
|
+
this.state.completedAgents.clear();
|
|
571
|
+
this.state.failedAgents.clear();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Get orchestration summary
|
|
576
|
+
*/
|
|
577
|
+
public getSummary(): {
|
|
578
|
+
taskId: string;
|
|
579
|
+
mode: ExecutionMode;
|
|
580
|
+
iteration: number;
|
|
581
|
+
totalAgentsCompleted: number;
|
|
582
|
+
totalAgentsFailed: number;
|
|
583
|
+
decision: ProductOwnerDecision;
|
|
584
|
+
duration: number;
|
|
585
|
+
} {
|
|
586
|
+
return {
|
|
587
|
+
taskId: this.config.taskId,
|
|
588
|
+
mode: this.config.mode,
|
|
589
|
+
iteration: this.state.iteration,
|
|
590
|
+
totalAgentsCompleted: this.state.completedAgents.size,
|
|
591
|
+
totalAgentsFailed: this.state.failedAgents.size,
|
|
592
|
+
decision: this.decision,
|
|
593
|
+
duration: Date.now() - this.state.startTime,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* CLI entry point for orchestrator
|
|
600
|
+
*/
|
|
601
|
+
if (require.main === module) {
|
|
602
|
+
const args = process.argv.slice(2);
|
|
603
|
+
|
|
604
|
+
// Parse command line arguments
|
|
605
|
+
let taskId = '';
|
|
606
|
+
let mode: ExecutionMode = 'standard';
|
|
607
|
+
let maxIterations = 10;
|
|
608
|
+
|
|
609
|
+
for (let i = 0; i < args.length; i++) {
|
|
610
|
+
const arg = args[i];
|
|
611
|
+
if (!arg) continue;
|
|
612
|
+
|
|
613
|
+
switch (arg) {
|
|
614
|
+
case '--task-id': {
|
|
615
|
+
const nextArg = args[++i];
|
|
616
|
+
if (nextArg) taskId = nextArg;
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
case '--mode': {
|
|
620
|
+
const nextArg = args[++i];
|
|
621
|
+
if (nextArg) mode = nextArg as ExecutionMode;
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
case '--max-iterations': {
|
|
625
|
+
const nextArg = args[++i];
|
|
626
|
+
if (nextArg) maxIterations = parseInt(nextArg, 10);
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (!taskId) {
|
|
633
|
+
console.error('Error: --task-id is required');
|
|
634
|
+
process.exit(1);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const config: OrchestrationConfig = {
|
|
638
|
+
taskId,
|
|
639
|
+
mode,
|
|
640
|
+
maxIterations,
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const orchestrator = new Orchestrator(config);
|
|
644
|
+
console.log(JSON.stringify(orchestrator.getState(), null, 2));
|
|
645
|
+
process.exit(0);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
export default Orchestrator;
|