claude-flow-novice 2.15.6 → 2.15.7

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 (113) hide show
  1. package/.claude/skills/cfn-loop-orchestration/helpers/gate-check.sh +39 -577
  2. package/.claude/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +49 -270
  3. package/.claude/skills/cfn-loop-orchestration/src/helpers/consensus.ts +87 -0
  4. package/.claude/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +115 -0
  5. package/.claude/skills/cfn-loop-orchestration/src/helpers/parse-test-results.ts +372 -0
  6. package/.claude/skills/cfn-loop-orchestration/tests/consensus.test.ts +142 -0
  7. package/.claude/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +199 -0
  8. package/.claude/skills/cfn-loop-orchestration/tests/gate-check.test.ts +325 -0
  9. package/.claude/skills/cfn-loop-orchestration/tests/iteration-manager.test.ts +132 -0
  10. package/.claude/skills/cfn-loop-orchestration/tests/parse-test-results.test.ts +382 -0
  11. package/.claude/skills/cfn-loop-orchestration/tests/timeout-calculator.test.ts +118 -0
  12. package/.claude/skills/cfn-redis-coordination/coverage/clover.xml +1447 -0
  13. package/.claude/skills/cfn-redis-coordination/coverage/coverage-final.json +13 -0
  14. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/agent-logger.ts.html +1423 -0
  15. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/agent-recovery.ts.html +1447 -0
  16. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/base.css +224 -0
  17. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/block-navigation.js +87 -0
  18. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/completion-reporter.ts.html +1273 -0
  19. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/context-manager.ts.html +1066 -0
  20. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/favicon.png +0 -0
  21. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/index.html +281 -0
  22. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/mode-detector.ts.html +550 -0
  23. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/prettify.css +1 -0
  24. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/prettify.js +2 -0
  25. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/redis-client.ts.html +2047 -0
  26. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/result-collector.ts.html +1396 -0
  27. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  28. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/sorter.js +210 -0
  29. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/swarm-manager.ts.html +1567 -0
  30. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/task-analyzer.ts.html +1297 -0
  31. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/task-executor.ts.html +1354 -0
  32. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/types.ts.html +790 -0
  33. package/.claude/skills/cfn-redis-coordination/coverage/lcov-report/waiting-coordinator.ts.html +1846 -0
  34. package/.claude/skills/cfn-redis-coordination/coverage/lcov.info +2650 -0
  35. package/.claude/skills/cfn-redis-coordination/dist/task-analyzer.js +1 -1
  36. package/.claude/skills/cfn-redis-coordination/src/task-analyzer.ts +1 -1
  37. package/.claude/skills/cfn-redis-coordination/tests/coordination.test.ts +18 -9
  38. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +13 -72
  39. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +5 -65
  40. package/claude-assets/agents/cfn-dev-team/coordinators/consensus-builder.md +465 -508
  41. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +733 -743
  42. package/claude-assets/agents/cfn-dev-team/coordinators/multi-sprint-coordinator.md +13 -79
  43. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +13 -18
  44. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +13 -18
  45. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +13 -18
  46. package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +15 -17
  47. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +15 -17
  48. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +15 -14
  49. package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +15 -17
  50. package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +15 -17
  51. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +15 -17
  52. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +23 -30
  53. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +13 -18
  54. package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +13 -18
  55. package/claude-assets/agents/cfn-dev-team/reviewers/code-reviewer.md +312 -317
  56. package/claude-assets/agents/cfn-dev-team/reviewers/quality/code-quality-validator.md +23 -20
  57. package/claude-assets/agents/cfn-dev-team/reviewers/quality/perf-analyzer.md +23 -20
  58. package/claude-assets/agents/cfn-dev-team/reviewers/quality/performance-benchmarker.md +23 -20
  59. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +23 -20
  60. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +15 -20
  61. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +15 -20
  62. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +718 -737
  63. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +817 -828
  64. package/claude-assets/agents/cfn-dev-team/testers/interaction-tester.md +15 -20
  65. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +8 -9
  66. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +668 -684
  67. package/claude-assets/agents/cfn-dev-team/testers/playwright-tester.md +15 -20
  68. package/claude-assets/agents/cfn-dev-team/testers/tester.md +248 -253
  69. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +13 -18
  70. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +13 -18
  71. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +13 -18
  72. package/claude-assets/skills/cfn-loop-orchestration/helpers/gate-check.sh +39 -577
  73. package/claude-assets/skills/cfn-loop-orchestration/helpers/parse-test-results.sh +49 -270
  74. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/gate-check.ts +115 -0
  75. package/claude-assets/skills/cfn-loop-orchestration/src/helpers/parse-test-results.ts +372 -0
  76. package/claude-assets/skills/cfn-loop-orchestration/tests/consensus.test.ts +142 -0
  77. package/claude-assets/skills/cfn-loop-orchestration/tests/deliverable-verifier.test.ts +199 -0
  78. package/claude-assets/skills/cfn-loop-orchestration/tests/gate-check.test.ts +325 -0
  79. package/claude-assets/skills/cfn-loop-orchestration/tests/iteration-manager.test.ts +132 -0
  80. package/claude-assets/skills/cfn-loop-orchestration/tests/parse-test-results.test.ts +382 -0
  81. package/claude-assets/skills/cfn-loop-orchestration/tests/timeout-calculator.test.ts +118 -0
  82. package/claude-assets/skills/cfn-redis-coordination/coverage/clover.xml +1447 -0
  83. package/claude-assets/skills/cfn-redis-coordination/coverage/coverage-final.json +13 -0
  84. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/agent-logger.ts.html +1423 -0
  85. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/agent-recovery.ts.html +1447 -0
  86. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/base.css +224 -0
  87. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/block-navigation.js +87 -0
  88. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/completion-reporter.ts.html +1273 -0
  89. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/context-manager.ts.html +1066 -0
  90. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/favicon.png +0 -0
  91. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/index.html +281 -0
  92. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/mode-detector.ts.html +550 -0
  93. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/prettify.css +1 -0
  94. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/prettify.js +2 -0
  95. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/redis-client.ts.html +2047 -0
  96. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/result-collector.ts.html +1396 -0
  97. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  98. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/sorter.js +210 -0
  99. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/swarm-manager.ts.html +1567 -0
  100. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/task-analyzer.ts.html +1297 -0
  101. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/task-executor.ts.html +1354 -0
  102. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/types.ts.html +790 -0
  103. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov-report/waiting-coordinator.ts.html +1846 -0
  104. package/claude-assets/skills/cfn-redis-coordination/coverage/lcov.info +2650 -0
  105. package/claude-assets/skills/cfn-redis-coordination/dist/task-analyzer.js +1 -1
  106. package/claude-assets/skills/cfn-redis-coordination/src/task-analyzer.ts +1 -1
  107. package/claude-assets/skills/cfn-redis-coordination/tests/coordination.test.ts +18 -9
  108. package/dist/agents/agent-loader.js +165 -146
  109. package/dist/agents/agent-loader.js.map +1 -1
  110. package/dist/cli/config-manager.js +91 -109
  111. package/dist/cli/config-manager.js.map +1 -1
  112. package/package.json +1 -1
  113. 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,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, ConsensusResult, ConsensusValidation } 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
+ });
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Deliverable Verifier Tests
3
+ * Tests for verifying expected deliverables exist (prevents "consensus on vapor")
4
+ */
5
+
6
+ import { verifyDeliverables, VerificationResult } from '../src/helpers/deliverable-verifier';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+
10
+ describe('deliverable-verifier', () => {
11
+ describe('file existence verification', () => {
12
+ it('should verify existing files', () => {
13
+ const result = verifyDeliverables({
14
+ files: ['package.json', 'tsconfig.json']
15
+ });
16
+
17
+ expect(result.verified).toBe(true);
18
+ expect(result.missing).toEqual([]);
19
+ expect(result.found).toContain('package.json');
20
+ expect(result.found).toContain('tsconfig.json');
21
+ });
22
+
23
+ it('should detect missing files', () => {
24
+ const result = verifyDeliverables({
25
+ files: ['nonexistent-file-12345.txt']
26
+ });
27
+
28
+ expect(result.verified).toBe(false);
29
+ expect(result.missing).toContain('nonexistent-file-12345.txt');
30
+ expect(result.found).toEqual([]);
31
+ });
32
+
33
+ it('should detect partial missing files', () => {
34
+ const result = verifyDeliverables({
35
+ files: ['package.json', 'nonexistent.txt', 'tsconfig.json']
36
+ });
37
+
38
+ expect(result.verified).toBe(false);
39
+ expect(result.missing).toEqual(['nonexistent.txt']);
40
+ expect(result.found).toContain('package.json');
41
+ expect(result.found).toContain('tsconfig.json');
42
+ });
43
+
44
+ it('should handle empty file list', () => {
45
+ const result = verifyDeliverables({
46
+ files: []
47
+ });
48
+
49
+ expect(result.verified).toBe(true);
50
+ expect(result.missing).toEqual([]);
51
+ expect(result.found).toEqual([]);
52
+ });
53
+ });
54
+
55
+ describe('file type validation', () => {
56
+ it('should verify TypeScript files', () => {
57
+ const result = verifyDeliverables({
58
+ files: ['src/helpers/gate-check.ts'],
59
+ expectedTypes: ['.ts']
60
+ });
61
+
62
+ expect(result.verified).toBe(true);
63
+ });
64
+
65
+ it('should verify shell script files', () => {
66
+ const result = verifyDeliverables({
67
+ files: ['helpers/consensus.sh'],
68
+ expectedTypes: ['.sh']
69
+ });
70
+
71
+ expect(result.verified).toBe(true);
72
+ });
73
+
74
+ it('should reject wrong file types', () => {
75
+ const result = verifyDeliverables({
76
+ files: ['package.json'],
77
+ expectedTypes: ['.ts']
78
+ });
79
+
80
+ expect(result.verified).toBe(false);
81
+ expect(result.typeErrors).toContain('package.json');
82
+ });
83
+
84
+ it('should allow multiple file types', () => {
85
+ const result = verifyDeliverables({
86
+ files: ['package.json', 'tsconfig.json'],
87
+ expectedTypes: ['.json', '.ts']
88
+ });
89
+
90
+ expect(result.verified).toBe(true);
91
+ });
92
+ });
93
+
94
+ describe('git change detection', () => {
95
+ it('should detect when files are created', () => {
96
+ const result = verifyDeliverables({
97
+ files: [],
98
+ requireGitChanges: true
99
+ });
100
+
101
+ // This test depends on actual git state, so we check structure
102
+ expect(result).toHaveProperty('gitChanges');
103
+ expect(typeof result.gitChanges).toBe('number');
104
+ });
105
+
106
+ it('should fail when no changes and changes required', () => {
107
+ // Mock scenario: implementation task with no files
108
+ const result = verifyDeliverables({
109
+ files: [],
110
+ requireGitChanges: true,
111
+ taskType: 'implementation'
112
+ });
113
+
114
+ // If no files specified and git has no changes, should fail for implementation
115
+ if (result.gitChanges === 0) {
116
+ expect(result.verified).toBe(false);
117
+ }
118
+ });
119
+ });
120
+
121
+ describe('task type keyword detection', () => {
122
+ it('should detect implementation keywords', () => {
123
+ const keywords = ['create', 'build', 'implement', 'add', 'generate'];
124
+
125
+ keywords.forEach(keyword => {
126
+ const result = verifyDeliverables({
127
+ files: [],
128
+ taskType: keyword,
129
+ requireGitChanges: true
130
+ });
131
+
132
+ // Should require git changes for implementation keywords
133
+ expect(result).toHaveProperty('requiresChanges');
134
+ if (result.requiresChanges) {
135
+ expect(result.gitChanges).toBeGreaterThan(-1); // Check git changes were counted
136
+ }
137
+ });
138
+ });
139
+
140
+ it('should not require changes for read-only tasks', () => {
141
+ const result = verifyDeliverables({
142
+ files: [],
143
+ taskType: 'analyze',
144
+ requireGitChanges: false
145
+ });
146
+
147
+ expect(result.verified).toBe(true);
148
+ });
149
+ });
150
+
151
+ describe('consensus on vapor prevention', () => {
152
+ it('should fail if implementation task has no deliverables', () => {
153
+ const result = verifyDeliverables({
154
+ files: [],
155
+ taskType: 'implement authentication',
156
+ requireGitChanges: true
157
+ });
158
+
159
+ // If git has changes, this should pass; otherwise fail
160
+ if (result.gitChanges === 0) {
161
+ expect(result.verified).toBe(false);
162
+ expect(result.reason).toContain('vapor');
163
+ }
164
+ });
165
+
166
+ it('should pass if implementation task has deliverables', () => {
167
+ const result = verifyDeliverables({
168
+ files: ['package.json'], // Existing file as proxy
169
+ taskType: 'implement feature'
170
+ });
171
+
172
+ expect(result.verified).toBe(true);
173
+ });
174
+ });
175
+
176
+ describe('verification reporting', () => {
177
+ it('should provide detailed results', () => {
178
+ const result = verifyDeliverables({
179
+ files: ['package.json', 'missing.txt']
180
+ });
181
+
182
+ expect(result).toHaveProperty('verified');
183
+ expect(result).toHaveProperty('files');
184
+ expect(result).toHaveProperty('missing');
185
+ expect(result).toHaveProperty('found');
186
+ expect(result.files).toEqual(['package.json', 'missing.txt']);
187
+ });
188
+
189
+ it('should track all requested files', () => {
190
+ const requestedFiles = ['file1.ts', 'file2.ts', 'file3.ts'];
191
+ const result = verifyDeliverables({
192
+ files: requestedFiles
193
+ });
194
+
195
+ expect(result.files).toEqual(requestedFiles);
196
+ expect(result.found.length + result.missing.length).toBe(requestedFiles.length);
197
+ });
198
+ });
199
+ });