claude-flow-novice 2.15.6 → 2.15.8

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 (122) hide show
  1. package/.claude/cfn-extras/agents/google-sheets/google-sheets-coordinator.md +1 -1
  2. package/.claude/cfn-extras/docs/GOOGLE_SHEETS_CFN_LOOP.md +13 -11
  3. package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +39 -577
  4. package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +49 -270
  5. package/.claude/skills/cfn-loop-orchestration/src/helpers/consensus.ts +87 -0
  6. package/.claude/skills/cfn-loop-orchestration/src/helpers/deliverable-verifier.ts +103 -0
  7. package/.claude/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +115 -0
  8. package/.claude/skills/cfn-loop-orchestration/src/helpers/iteration-manager.ts +45 -0
  9. package/.claude/skills/cfn-loop-orchestration/src/helpers/parse-test-results.ts +372 -0
  10. package/.claude/skills/cfn-loop-orchestration/src/helpers/timeout-calculator.ts +41 -0
  11. package/.claude/skills/cfn-loop-orchestration/tests/consensus.test.ts +142 -0
  12. package/.claude/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +197 -0
  13. package/.claude/skills/cfn-loop-orchestration/tests/gate-check.test.ts +325 -0
  14. package/.claude/skills/cfn-loop-orchestration/tests/iteration-manager.test.ts +132 -0
  15. package/.claude/skills/cfn-loop-orchestration/tests/parse-test-results.test.ts +382 -0
  16. package/.claude/skills/cfn-loop-orchestration/tests/timeout-calculator.test.ts +118 -0
  17. package/.claude/skills/cfn-redis-coordination/coverage/clover.xml +1447 -0
  18. package/.claude/skills/cfn-redis-coordination/coverage/coverage-final.json +13 -0
  19. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/agent-logger.ts.html +1423 -0
  20. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/agent-recovery.ts.html +1447 -0
  21. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/base.css +224 -0
  22. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/block-navigation.js +87 -0
  23. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/completion-reporter.ts.html +1273 -0
  24. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/context-manager.ts.html +1066 -0
  25. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/favicon.png +0 -0
  26. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/index.html +281 -0
  27. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/mode-detector.ts.html +550 -0
  28. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/prettify.css +1 -0
  29. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/prettify.js +2 -0
  30. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/redis-client.ts.html +2047 -0
  31. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/result-collector.ts.html +1396 -0
  32. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  33. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/sorter.js +210 -0
  34. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/swarm-manager.ts.html +1567 -0
  35. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/task-analyzer.ts.html +1297 -0
  36. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/task-executor.ts.html +1354 -0
  37. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/types.ts.html +790 -0
  38. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/waiting-coordinator.ts.html +1846 -0
  39. package/.claude/skills/cfn-redis-coordination/coverage/lcov.info +2650 -0
  40. package/.claude/skills/cfn-redis-coordination/dist/task-analyzer.js +1 -1
  41. package/.claude/skills/cfn-redis-coordination/src/task-analyzer.ts +1 -1
  42. package/.claude/skills/cfn-redis-coordination/tests/coordination.test.ts +18 -9
  43. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +13 -72
  44. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +5 -65
  45. package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +465 -508
  46. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +733 -743
  47. package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +13 -79
  48. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +13 -18
  49. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +13 -18
  50. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +13 -18
  51. package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +15 -17
  52. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +15 -17
  53. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +15 -14
  54. package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +15 -17
  55. package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +15 -17
  56. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +15 -17
  57. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +23 -30
  58. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +13 -18
  59. package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +13 -18
  60. package/claude-assets/agents/cfn-dev-team/reviewers/code-reviewer.md +312 -317
  61. package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +23 -20
  62. package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +23 -20
  63. package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +23 -20
  64. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +23 -20
  65. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +15 -20
  66. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +15 -20
  67. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +718 -737
  68. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +817 -828
  69. package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +15 -20
  70. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +8 -9
  71. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +668 -684
  72. package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +15 -20
  73. package/claude-assets/agents/cfn-dev-team/testers/tester.md +248 -253
  74. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +13 -18
  75. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +13 -18
  76. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +13 -18
  77. package/claude-assets/cfn-extras/agents/google-sheets/google-sheets-coordinator.md +1 -1
  78. package/claude-assets/cfn-extras/docs/GOOGLE_SHEETS_CFN_LOOP.md +13 -11
  79. package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +39 -577
  80. package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +49 -270
  81. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/consensus.ts +87 -0
  82. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/deliverable-verifier.ts +103 -0
  83. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +115 -0
  84. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/iteration-manager.ts +45 -0
  85. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/parse-test-results.ts +372 -0
  86. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/timeout-calculator.ts +41 -0
  87. package/claude-assets/skills/cfn-loop-orchestration/tests/consensus.test.ts +142 -0
  88. package/claude-assets/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +197 -0
  89. package/claude-assets/skills/cfn-loop-orchestration/tests/gate-check.test.ts +325 -0
  90. package/claude-assets/skills/cfn-loop-orchestration/tests/iteration-manager.test.ts +132 -0
  91. package/claude-assets/skills/cfn-loop-orchestration/tests/parse-test-results.test.ts +382 -0
  92. package/claude-assets/skills/cfn-loop-orchestration/tests/timeout-calculator.test.ts +118 -0
  93. package/claude-assets/skills/cfn-redis-coordination/coverage/clover.xml +1447 -0
  94. package/claude-assets/skills/cfn-redis-coordination/coverage/coverage-final.json +13 -0
  95. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/agent-logger.ts.html +1423 -0
  96. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/agent-recovery.ts.html +1447 -0
  97. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/base.css +224 -0
  98. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/block-navigation.js +87 -0
  99. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/completion-reporter.ts.html +1273 -0
  100. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/context-manager.ts.html +1066 -0
  101. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/favicon.png +0 -0
  102. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/index.html +281 -0
  103. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/mode-detector.ts.html +550 -0
  104. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/prettify.css +1 -0
  105. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/prettify.js +2 -0
  106. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/redis-client.ts.html +2047 -0
  107. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/result-collector.ts.html +1396 -0
  108. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  109. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/sorter.js +210 -0
  110. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/swarm-manager.ts.html +1567 -0
  111. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/task-analyzer.ts.html +1297 -0
  112. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/task-executor.ts.html +1354 -0
  113. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/types.ts.html +790 -0
  114. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/waiting-coordinator.ts.html +1846 -0
  115. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov.info +2650 -0
  116. package/claude-assets/skills/cfn-redis-coordination/dist/task-analyzer.js +1 -1
  117. package/claude-assets/skills/cfn-redis-coordination/src/task-analyzer.ts +1 -1
  118. package/claude-assets/skills/cfn-redis-coordination/tests/coordination.test.ts +18 -9
  119. package/dist/agents/agent-loader.js +165 -146
  120. package/dist/agents/agent-loader.js.map +1 -1
  121. package/package.json +1 -1
  122. package/scripts/clean-agent-profiles.sh +112 -0
@@ -0,0 +1,372 @@
1
+ /**
2
+ * Test Results Parser - TypeScript Implementation
3
+ * Parses test output from multiple testing frameworks
4
+ */
5
+
6
+ export type TestFramework = 'jest' | 'mocha' | 'pytest' | 'tap' | 'go' | 'junit' | 'unknown';
7
+
8
+ export interface TestResults {
9
+ framework: TestFramework;
10
+ total: number;
11
+ passed: number;
12
+ failed: number;
13
+ skipped: number;
14
+ passRate: number;
15
+ durationMs: number;
16
+ failedTestNames: string[];
17
+ raw: string;
18
+ }
19
+
20
+ /**
21
+ * Parse Jest test output
22
+ */
23
+ function parseJestOutput(output: string): TestResults {
24
+ let total = 0;
25
+ let passed = 0;
26
+ let failed = 0;
27
+ let skipped = 0;
28
+ let duration = 0;
29
+ const failedNames: string[] = [];
30
+
31
+ // Extract test counts from "Tests:" line
32
+ const testsLine = output.match(/^\s*Tests:.*$/m)?.[0] || '';
33
+
34
+ if (testsLine) {
35
+ const passedMatch = testsLine.match(/(\d+)\s+passed/);
36
+ const failedMatch = testsLine.match(/(\d+)\s+failed/);
37
+ const skippedMatch = testsLine.match(/(\d+)\s+skipped/);
38
+ const totalMatch = testsLine.match(/(\d+)\s+total/);
39
+
40
+ if (passedMatch?.[1]) passed = parseInt(passedMatch[1], 10);
41
+ if (failedMatch?.[1]) failed = parseInt(failedMatch[1], 10);
42
+ if (skippedMatch?.[1]) skipped = parseInt(skippedMatch[1], 10);
43
+ if (totalMatch?.[1]) total = parseInt(totalMatch[1], 10);
44
+ }
45
+
46
+ // Extract duration from "Time:" line
47
+ const timeMatch = output.match(/Time:\s+([0-9.]+)\s*s/);
48
+ if (timeMatch?.[1]) {
49
+ duration = Math.round(parseFloat(timeMatch[1]) * 1000);
50
+ }
51
+
52
+ // Extract failed test names
53
+ const failedNameMatches = output.matchAll(/●\s+(.+)/g);
54
+ for (const match of failedNameMatches) {
55
+ if (match[1]) failedNames.push(match[1].trim());
56
+ }
57
+
58
+ const passRate = total > 0 ? passed / total : 0.0;
59
+
60
+ return {
61
+ framework: 'jest',
62
+ total,
63
+ passed,
64
+ failed,
65
+ skipped,
66
+ passRate: parseFloat(passRate.toFixed(4)),
67
+ durationMs: duration,
68
+ failedTestNames: failedNames,
69
+ raw: output,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Parse Mocha test output
75
+ */
76
+ function parseMochaOutput(output: string): TestResults {
77
+ let total = 0;
78
+ let passed = 0;
79
+ let failed = 0;
80
+ let skipped = 0;
81
+ let duration = 0;
82
+ const failedNames: string[] = [];
83
+
84
+ // Extract test counts
85
+ const passedMatch = output.match(/(\d+)\s+passing/);
86
+ const failedMatch = output.match(/(\d+)\s+failing/);
87
+ const pendingMatch = output.match(/(\d+)\s+pending/);
88
+
89
+ if (passedMatch?.[1]) passed = parseInt(passedMatch[1], 10);
90
+ if (failedMatch?.[1]) failed = parseInt(failedMatch[1], 10);
91
+ if (pendingMatch?.[1]) skipped = parseInt(pendingMatch[1], 10);
92
+
93
+ total = passed + failed + skipped;
94
+
95
+ // Extract duration - can be in ms or s
96
+ const durationMsMatch = output.match(/passing\s*\((\d+)ms\)/);
97
+ const durationSMatch = output.match(/passing\s*\(([0-9.]+)s\)/);
98
+
99
+ if (durationMsMatch?.[1]) {
100
+ duration = parseInt(durationMsMatch[1], 10);
101
+ } else if (durationSMatch?.[1]) {
102
+ duration = Math.round(parseFloat(durationSMatch[1]) * 1000);
103
+ }
104
+
105
+ // Extract failed test names
106
+ const failedNameMatches = output.matchAll(/^\s*\d+\)\s*(.+):/gm);
107
+ for (const match of failedNameMatches) {
108
+ if (match[1]) failedNames.push(match[1].trim());
109
+ }
110
+
111
+ const passRate = total > 0 ? passed / total : 0.0;
112
+
113
+ return {
114
+ framework: 'mocha',
115
+ total,
116
+ passed,
117
+ failed,
118
+ skipped,
119
+ passRate: parseFloat(passRate.toFixed(4)),
120
+ durationMs: duration,
121
+ failedTestNames: failedNames,
122
+ raw: output,
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Parse Pytest test output
128
+ */
129
+ function parsePytestOutput(output: string): TestResults {
130
+ let total = 0;
131
+ let passed = 0;
132
+ let failed = 0;
133
+ let skipped = 0;
134
+ let duration = 0;
135
+ const failedNames: string[] = [];
136
+
137
+ // Extract test counts
138
+ const passedMatch = output.match(/(\d+)\s+passed/);
139
+ const failedMatch = output.match(/(\d+)\s+failed/);
140
+ const skippedMatch = output.match(/(\d+)\s+skipped/);
141
+
142
+ if (passedMatch?.[1]) passed = parseInt(passedMatch[1], 10);
143
+ if (failedMatch?.[1]) failed = parseInt(failedMatch[1], 10);
144
+ if (skippedMatch?.[1]) skipped = parseInt(skippedMatch[1], 10);
145
+
146
+ total = passed + failed + skipped;
147
+
148
+ // Extract duration
149
+ const durationMatch = output.match(/in\s+([0-9.]+)s/);
150
+ if (durationMatch?.[1]) {
151
+ duration = Math.round(parseFloat(durationMatch[1]) * 1000);
152
+ }
153
+
154
+ // Extract failed test names
155
+ const failedNameMatches = output.matchAll(/^\s*FAILED\s+([^\s]+)/gm);
156
+ for (const match of failedNameMatches) {
157
+ if (match[1]) failedNames.push(match[1].trim());
158
+ }
159
+
160
+ const passRate = total > 0 ? passed / total : 0.0;
161
+
162
+ return {
163
+ framework: 'pytest',
164
+ total,
165
+ passed,
166
+ failed,
167
+ skipped,
168
+ passRate: parseFloat(passRate.toFixed(4)),
169
+ durationMs: duration,
170
+ failedTestNames: failedNames,
171
+ raw: output,
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Parse TAP test output
177
+ */
178
+ function parseTapOutput(output: string): TestResults {
179
+ let total = 0;
180
+ let passed = 0;
181
+ let failed = 0;
182
+ let skipped = 0;
183
+ const failedNames: string[] = [];
184
+
185
+ // Extract total from plan line (e.g., "1..10")
186
+ const planMatch = output.match(/^\s*1\.\.(\d+)/m);
187
+ if (planMatch?.[1]) {
188
+ total = parseInt(planMatch[1], 10);
189
+ }
190
+
191
+ // Count ok lines (excluding SKIP)
192
+ const okMatches = output.matchAll(/^\s*ok\s+\d+/gm);
193
+ let okCount = 0;
194
+ for (const _ of okMatches) {
195
+ okCount++;
196
+ }
197
+
198
+ // Count skipped tests
199
+ const skipMatches = output.matchAll(/^\s*ok\s+\d+.*#\s*SKIP/gm);
200
+ for (const _ of skipMatches) {
201
+ skipped++;
202
+ }
203
+
204
+ passed = okCount - skipped;
205
+
206
+ // Count not ok lines
207
+ const notOkMatches = output.matchAll(/^\s*not ok\s+\d+\s+(.+)/gm);
208
+ for (const match of notOkMatches) {
209
+ failed++;
210
+ if (match[1]) failedNames.push(match[1].trim());
211
+ }
212
+
213
+ const passRate = total > 0 ? passed / total : 0.0;
214
+
215
+ return {
216
+ framework: 'tap',
217
+ total,
218
+ passed,
219
+ failed,
220
+ skipped,
221
+ passRate: parseFloat(passRate.toFixed(4)),
222
+ durationMs: 0,
223
+ failedTestNames: failedNames,
224
+ raw: output,
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Parse Go test output
230
+ */
231
+ function parseGoTestOutput(output: string): TestResults {
232
+ let total = 0;
233
+ let passed = 0;
234
+ let failed = 0;
235
+ let skipped = 0;
236
+ let duration = 0;
237
+ const failedNames: string[] = [];
238
+
239
+ // Count PASS lines
240
+ const passMatches = output.matchAll(/^\s*---\s+PASS:\s+(.+)/gm);
241
+ for (const _ of passMatches) {
242
+ passed++;
243
+ }
244
+
245
+ // Count FAIL lines
246
+ const failMatches = output.matchAll(/^\s*---\s+FAIL:\s+(.+)/gm);
247
+ for (const match of failMatches) {
248
+ failed++;
249
+ if (match[1]) failedNames.push(match[1].trim());
250
+ }
251
+
252
+ // Count SKIP lines
253
+ const skipMatches = output.matchAll(/^\s*---\s+SKIP:/gm);
254
+ for (const _ of skipMatches) {
255
+ skipped++;
256
+ }
257
+
258
+ total = passed + failed + skipped;
259
+
260
+ // Extract duration
261
+ const durationMatch = output.match(/ok\s+[^\s]+\s+([0-9.]+)s/);
262
+ if (durationMatch?.[1]) {
263
+ duration = Math.round(parseFloat(durationMatch[1]) * 1000);
264
+ }
265
+
266
+ const passRate = total > 0 ? passed / total : 0.0;
267
+
268
+ return {
269
+ framework: 'go',
270
+ total,
271
+ passed,
272
+ failed,
273
+ skipped,
274
+ passRate: parseFloat(passRate.toFixed(4)),
275
+ durationMs: duration,
276
+ failedTestNames: failedNames,
277
+ raw: output,
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Auto-detect testing framework from output
283
+ */
284
+ function autoDetectFramework(output: string): TestFramework {
285
+ // Jest
286
+ if (output.match(/Test Suites:/i) || output.match(/PASS\s+.*\.test\.(js|ts)/)) {
287
+ return 'jest';
288
+ }
289
+
290
+ // Mocha
291
+ if (output.match(/\d+\s+passing/) && output.match(/\d+\s+failing/)) {
292
+ return 'mocha';
293
+ }
294
+
295
+ // Pytest
296
+ if (output.match(/====.*passed.*====/) || output.match(/FAILED.*\.py::/)) {
297
+ return 'pytest';
298
+ }
299
+
300
+ // TAP
301
+ if (output.match(/1\.\.\d+/) || output.match(/^ok\s+\d+/m) || output.match(/^not ok\s+\d+/m)) {
302
+ return 'tap';
303
+ }
304
+
305
+ // Go
306
+ if (output.match(/---\s+PASS:/) || output.match(/---\s+FAIL:/)) {
307
+ return 'go';
308
+ }
309
+
310
+ return 'unknown';
311
+ }
312
+
313
+ /**
314
+ * Main entry point - parse test results from any framework
315
+ */
316
+ export function parseTestResults(framework: string, output: string): TestResults {
317
+ let detectedFramework: TestFramework = framework as TestFramework;
318
+
319
+ // Auto-detect if requested
320
+ if (framework === 'auto') {
321
+ detectedFramework = autoDetectFramework(output);
322
+ }
323
+
324
+ // Parse based on framework
325
+ switch (detectedFramework) {
326
+ case 'jest':
327
+ return parseJestOutput(output);
328
+ case 'mocha':
329
+ return parseMochaOutput(output);
330
+ case 'pytest':
331
+ return parsePytestOutput(output);
332
+ case 'tap':
333
+ return parseTapOutput(output);
334
+ case 'go':
335
+ return parseGoTestOutput(output);
336
+ default:
337
+ return {
338
+ framework: 'unknown',
339
+ total: 0,
340
+ passed: 0,
341
+ failed: 0,
342
+ skipped: 0,
343
+ passRate: 0.0,
344
+ durationMs: 0,
345
+ failedTestNames: [],
346
+ raw: output,
347
+ };
348
+ }
349
+ }
350
+
351
+ /**
352
+ * CLI entry point for bash wrapper
353
+ */
354
+ if (require.main === module) {
355
+ const args = process.argv.slice(2);
356
+
357
+ if (args.length < 2) {
358
+ console.error('Usage: parse-test-results.js <framework|auto> <output_file_or_string>');
359
+ process.exit(1);
360
+ }
361
+
362
+ const framework = args[0];
363
+ const input = args[1];
364
+
365
+ if (!framework || !input) {
366
+ console.error('Error: framework and input are required');
367
+ process.exit(1);
368
+ }
369
+
370
+ const result = parseTestResults(framework, input);
371
+ console.log(JSON.stringify(result, null, 2));
372
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Timeout Calculator
3
+ * Calculates mode and phase-specific timeouts for agent execution
4
+ */
5
+
6
+ export type Mode = 'mvp' | 'standard' | 'enterprise';
7
+
8
+ const BASE_TIMEOUTS: Record<Mode, number> = {
9
+ mvp: 1800, // 30 minutes
10
+ standard: 3600, // 60 minutes
11
+ enterprise: 7200 // 120 minutes
12
+ };
13
+
14
+ const PHASE_MULTIPLIERS: Record<string, number> = {
15
+ 'phase-1': 1.0, // Backend work
16
+ 'phase-2': 1.5, // React components
17
+ 'phase-3': 2.0, // Advanced components
18
+ 'phase-4': 1.0 // Testing/integration
19
+ };
20
+
21
+ /**
22
+ * Calculates timeout based on mode and optional phase
23
+ * @param params Mode and optional phase identifier
24
+ * @returns Timeout in seconds
25
+ */
26
+ export function calculateTimeout(params: {
27
+ mode: Mode;
28
+ phase?: string;
29
+ }): number {
30
+ const baseTimeout = BASE_TIMEOUTS[params.mode] || BASE_TIMEOUTS.standard;
31
+
32
+ if (!params.phase) {
33
+ return baseTimeout;
34
+ }
35
+
36
+ // Normalize phase to lowercase for case-insensitive matching
37
+ const normalizedPhase = params.phase.toLowerCase();
38
+ const multiplier = PHASE_MULTIPLIERS[normalizedPhase] || 1.0;
39
+
40
+ return Math.floor(baseTimeout * multiplier);
41
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Consensus Collection and Validation Tests
3
+ * Tests for collecting Loop 2 validator scores and checking thresholds
4
+ */
5
+
6
+ import { collectConsensus, validateConsensus } from '../src/helpers/consensus';
7
+
8
+ describe('consensus', () => {
9
+ describe('collectConsensus', () => {
10
+ it('should collect scores from multiple validators', () => {
11
+ const scores = [0.92, 0.95, 0.88];
12
+ const result = collectConsensus(scores);
13
+
14
+ expect(result.scores).toEqual(scores);
15
+ expect(result.average).toBeCloseTo(0.917, 2);
16
+ expect(result.count).toBe(3);
17
+ expect(result.min).toBe(0.88);
18
+ expect(result.max).toBe(0.95);
19
+ });
20
+
21
+ it('should handle single validator', () => {
22
+ const scores = [0.85];
23
+ const result = collectConsensus(scores);
24
+
25
+ expect(result.scores).toEqual([0.85]);
26
+ expect(result.average).toBe(0.85);
27
+ expect(result.count).toBe(1);
28
+ expect(result.min).toBe(0.85);
29
+ expect(result.max).toBe(0.85);
30
+ });
31
+
32
+ it('should reject empty scores array', () => {
33
+ expect(() => collectConsensus([])).toThrow('No consensus scores provided');
34
+ });
35
+
36
+ it('should reject invalid scores (negative)', () => {
37
+ expect(() => collectConsensus([-0.5, 0.9])).toThrow('Invalid consensus score');
38
+ });
39
+
40
+ it('should reject invalid scores (>1.0)', () => {
41
+ expect(() => collectConsensus([0.9, 1.5])).toThrow('Invalid consensus score');
42
+ });
43
+
44
+ it('should handle edge case scores (0.0 and 1.0)', () => {
45
+ const scores = [0.0, 1.0, 0.5];
46
+ const result = collectConsensus(scores);
47
+
48
+ expect(result.average).toBeCloseTo(0.5, 2);
49
+ expect(result.min).toBe(0.0);
50
+ expect(result.max).toBe(1.0);
51
+ });
52
+
53
+ it('should calculate correct average for many validators', () => {
54
+ const scores = [0.90, 0.92, 0.88, 0.95, 0.91];
55
+ const result = collectConsensus(scores);
56
+
57
+ expect(result.average).toBeCloseTo(0.912, 2);
58
+ expect(result.count).toBe(5);
59
+ });
60
+ });
61
+
62
+ describe('validateConsensus', () => {
63
+ it('should pass when average >= threshold', () => {
64
+ const result = validateConsensus({
65
+ average: 0.92,
66
+ threshold: 0.90,
67
+ mode: 'standard'
68
+ });
69
+
70
+ expect(result.passed).toBe(true);
71
+ expect(result.average).toBe(0.92);
72
+ expect(result.threshold).toBe(0.90);
73
+ expect(result.gap).toBeCloseTo(0.02, 2);
74
+ });
75
+
76
+ it('should fail when average < threshold', () => {
77
+ const result = validateConsensus({
78
+ average: 0.85,
79
+ threshold: 0.90,
80
+ mode: 'standard'
81
+ });
82
+
83
+ expect(result.passed).toBe(false);
84
+ expect(result.gap).toBeCloseTo(-0.05, 2);
85
+ });
86
+
87
+ it('should use mvp mode threshold (0.80)', () => {
88
+ const result = validateConsensus({
89
+ average: 0.82,
90
+ mode: 'mvp'
91
+ });
92
+
93
+ expect(result.passed).toBe(true);
94
+ expect(result.threshold).toBe(0.80);
95
+ expect(result.mode).toBe('mvp');
96
+ });
97
+
98
+ it('should use standard mode threshold (0.90)', () => {
99
+ const result = validateConsensus({
100
+ average: 0.89,
101
+ mode: 'standard'
102
+ });
103
+
104
+ expect(result.passed).toBe(false);
105
+ expect(result.threshold).toBe(0.90);
106
+ expect(result.mode).toBe('standard');
107
+ });
108
+
109
+ it('should use enterprise mode threshold (0.95)', () => {
110
+ const result = validateConsensus({
111
+ average: 0.94,
112
+ mode: 'enterprise'
113
+ });
114
+
115
+ expect(result.passed).toBe(false);
116
+ expect(result.threshold).toBe(0.95);
117
+ expect(result.mode).toBe('enterprise');
118
+ });
119
+
120
+ it('should allow explicit threshold override', () => {
121
+ const result = validateConsensus({
122
+ average: 0.88,
123
+ threshold: 0.85,
124
+ mode: 'standard'
125
+ });
126
+
127
+ expect(result.passed).toBe(true);
128
+ expect(result.threshold).toBe(0.85); // Uses explicit, not mode default
129
+ });
130
+
131
+ it('should handle exact threshold match', () => {
132
+ const result = validateConsensus({
133
+ average: 0.90,
134
+ threshold: 0.90,
135
+ mode: 'standard'
136
+ });
137
+
138
+ expect(result.passed).toBe(true);
139
+ expect(result.gap).toBe(0);
140
+ });
141
+ });
142
+ });