qa360 1.4.5 → 2.0.1

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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ai.d.ts +41 -0
  3. package/dist/commands/ai.js +499 -0
  4. package/dist/commands/ask.js +12 -12
  5. package/dist/commands/coverage.d.ts +8 -0
  6. package/dist/commands/coverage.js +252 -0
  7. package/dist/commands/explain.d.ts +27 -0
  8. package/dist/commands/explain.js +630 -0
  9. package/dist/commands/flakiness.d.ts +73 -0
  10. package/dist/commands/flakiness.js +435 -0
  11. package/dist/commands/generate.d.ts +66 -0
  12. package/dist/commands/generate.js +438 -0
  13. package/dist/commands/init.d.ts +56 -9
  14. package/dist/commands/init.js +217 -10
  15. package/dist/commands/monitor.d.ts +27 -0
  16. package/dist/commands/monitor.js +225 -0
  17. package/dist/commands/ollama.d.ts +40 -0
  18. package/dist/commands/ollama.js +301 -0
  19. package/dist/commands/pack.d.ts +37 -9
  20. package/dist/commands/pack.js +240 -141
  21. package/dist/commands/regression.d.ts +8 -0
  22. package/dist/commands/regression.js +340 -0
  23. package/dist/commands/repair.d.ts +26 -0
  24. package/dist/commands/repair.js +307 -0
  25. package/dist/commands/retry.d.ts +43 -0
  26. package/dist/commands/retry.js +275 -0
  27. package/dist/commands/run.d.ts +8 -3
  28. package/dist/commands/run.js +45 -31
  29. package/dist/commands/slo.d.ts +8 -0
  30. package/dist/commands/slo.js +327 -0
  31. package/dist/core/adapters/playwright-native-api.d.ts +183 -0
  32. package/dist/core/adapters/playwright-native-api.js +461 -0
  33. package/dist/core/adapters/playwright-ui.d.ts +7 -0
  34. package/dist/core/adapters/playwright-ui.js +29 -1
  35. package/dist/core/ai/anthropic-provider.d.ts +50 -0
  36. package/dist/core/ai/anthropic-provider.js +211 -0
  37. package/dist/core/ai/deepseek-provider.d.ts +81 -0
  38. package/dist/core/ai/deepseek-provider.js +254 -0
  39. package/dist/core/ai/index.d.ts +60 -0
  40. package/dist/core/ai/index.js +18 -0
  41. package/dist/core/ai/llm-client.d.ts +45 -0
  42. package/dist/core/ai/llm-client.js +7 -0
  43. package/dist/core/ai/mock-provider.d.ts +49 -0
  44. package/dist/core/ai/mock-provider.js +121 -0
  45. package/dist/core/ai/ollama-provider.d.ts +78 -0
  46. package/dist/core/ai/ollama-provider.js +192 -0
  47. package/dist/core/ai/openai-provider.d.ts +48 -0
  48. package/dist/core/ai/openai-provider.js +188 -0
  49. package/dist/core/ai/provider-factory.d.ts +160 -0
  50. package/dist/core/ai/provider-factory.js +269 -0
  51. package/dist/core/auth/api-key-provider.d.ts +16 -0
  52. package/dist/core/auth/api-key-provider.js +63 -0
  53. package/dist/core/auth/aws-iam-provider.d.ts +35 -0
  54. package/dist/core/auth/aws-iam-provider.js +177 -0
  55. package/dist/core/auth/azure-ad-provider.d.ts +15 -0
  56. package/dist/core/auth/azure-ad-provider.js +99 -0
  57. package/dist/core/auth/basic-auth-provider.d.ts +26 -0
  58. package/dist/core/auth/basic-auth-provider.js +111 -0
  59. package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
  60. package/dist/core/auth/gcp-adc-provider.js +126 -0
  61. package/dist/core/auth/index.d.ts +238 -0
  62. package/dist/core/auth/index.js +82 -0
  63. package/dist/core/auth/jwt-provider.d.ts +19 -0
  64. package/dist/core/auth/jwt-provider.js +160 -0
  65. package/dist/core/auth/manager.d.ts +84 -0
  66. package/dist/core/auth/manager.js +230 -0
  67. package/dist/core/auth/oauth2-provider.d.ts +17 -0
  68. package/dist/core/auth/oauth2-provider.js +114 -0
  69. package/dist/core/auth/totp-provider.d.ts +31 -0
  70. package/dist/core/auth/totp-provider.js +134 -0
  71. package/dist/core/auth/ui-login-provider.d.ts +26 -0
  72. package/dist/core/auth/ui-login-provider.js +198 -0
  73. package/dist/core/cache/index.d.ts +7 -0
  74. package/dist/core/cache/index.js +6 -0
  75. package/dist/core/cache/lru-cache.d.ts +203 -0
  76. package/dist/core/cache/lru-cache.js +397 -0
  77. package/dist/core/coverage/analyzer.d.ts +101 -0
  78. package/dist/core/coverage/analyzer.js +415 -0
  79. package/dist/core/coverage/collector.d.ts +74 -0
  80. package/dist/core/coverage/collector.js +459 -0
  81. package/dist/core/coverage/config.d.ts +37 -0
  82. package/dist/core/coverage/config.js +156 -0
  83. package/dist/core/coverage/index.d.ts +11 -0
  84. package/dist/core/coverage/index.js +15 -0
  85. package/dist/core/coverage/types.d.ts +267 -0
  86. package/dist/core/coverage/types.js +6 -0
  87. package/dist/core/coverage/vault.d.ts +95 -0
  88. package/dist/core/coverage/vault.js +405 -0
  89. package/dist/core/dashboard/assets.d.ts +6 -0
  90. package/dist/core/dashboard/assets.js +690 -0
  91. package/dist/core/dashboard/index.d.ts +6 -0
  92. package/dist/core/dashboard/index.js +5 -0
  93. package/dist/core/dashboard/server.d.ts +72 -0
  94. package/dist/core/dashboard/server.js +354 -0
  95. package/dist/core/dashboard/types.d.ts +70 -0
  96. package/dist/core/dashboard/types.js +5 -0
  97. package/dist/core/discoverer/index.d.ts +115 -0
  98. package/dist/core/discoverer/index.js +250 -0
  99. package/dist/core/flakiness/index.d.ts +228 -0
  100. package/dist/core/flakiness/index.js +384 -0
  101. package/dist/core/generation/code-formatter.d.ts +111 -0
  102. package/dist/core/generation/code-formatter.js +307 -0
  103. package/dist/core/generation/code-generator.d.ts +144 -0
  104. package/dist/core/generation/code-generator.js +293 -0
  105. package/dist/core/generation/generator.d.ts +40 -0
  106. package/dist/core/generation/generator.js +76 -0
  107. package/dist/core/generation/index.d.ts +30 -0
  108. package/dist/core/generation/index.js +28 -0
  109. package/dist/core/generation/pack-generator.d.ts +107 -0
  110. package/dist/core/generation/pack-generator.js +416 -0
  111. package/dist/core/generation/prompt-builder.d.ts +132 -0
  112. package/dist/core/generation/prompt-builder.js +672 -0
  113. package/dist/core/generation/source-analyzer.d.ts +213 -0
  114. package/dist/core/generation/source-analyzer.js +657 -0
  115. package/dist/core/generation/test-optimizer.d.ts +117 -0
  116. package/dist/core/generation/test-optimizer.js +328 -0
  117. package/dist/core/generation/types.d.ts +214 -0
  118. package/dist/core/generation/types.js +4 -0
  119. package/dist/core/index.d.ts +23 -1
  120. package/dist/core/index.js +39 -0
  121. package/dist/core/pack/validator.js +31 -1
  122. package/dist/core/pack-v2/index.d.ts +9 -0
  123. package/dist/core/pack-v2/index.js +8 -0
  124. package/dist/core/pack-v2/loader.d.ts +62 -0
  125. package/dist/core/pack-v2/loader.js +231 -0
  126. package/dist/core/pack-v2/migrator.d.ts +56 -0
  127. package/dist/core/pack-v2/migrator.js +455 -0
  128. package/dist/core/pack-v2/validator.d.ts +61 -0
  129. package/dist/core/pack-v2/validator.js +577 -0
  130. package/dist/core/regression/detector.d.ts +107 -0
  131. package/dist/core/regression/detector.js +497 -0
  132. package/dist/core/regression/index.d.ts +9 -0
  133. package/dist/core/regression/index.js +11 -0
  134. package/dist/core/regression/trend-analyzer.d.ts +102 -0
  135. package/dist/core/regression/trend-analyzer.js +345 -0
  136. package/dist/core/regression/types.d.ts +222 -0
  137. package/dist/core/regression/types.js +7 -0
  138. package/dist/core/regression/vault.d.ts +87 -0
  139. package/dist/core/regression/vault.js +289 -0
  140. package/dist/core/repair/engine/fixer.d.ts +24 -0
  141. package/dist/core/repair/engine/fixer.js +226 -0
  142. package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
  143. package/dist/core/repair/engine/suggestion-engine.js +187 -0
  144. package/dist/core/repair/index.d.ts +10 -0
  145. package/dist/core/repair/index.js +13 -0
  146. package/dist/core/repair/repairer.d.ts +90 -0
  147. package/dist/core/repair/repairer.js +284 -0
  148. package/dist/core/repair/types.d.ts +91 -0
  149. package/dist/core/repair/types.js +6 -0
  150. package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
  151. package/dist/core/repair/utils/error-analyzer.js +264 -0
  152. package/dist/core/retry/flakiness-integration.d.ts +60 -0
  153. package/dist/core/retry/flakiness-integration.js +228 -0
  154. package/dist/core/retry/index.d.ts +14 -0
  155. package/dist/core/retry/index.js +16 -0
  156. package/dist/core/retry/retry-engine.d.ts +80 -0
  157. package/dist/core/retry/retry-engine.js +296 -0
  158. package/dist/core/retry/types.d.ts +178 -0
  159. package/dist/core/retry/types.js +52 -0
  160. package/dist/core/retry/vault.d.ts +77 -0
  161. package/dist/core/retry/vault.js +304 -0
  162. package/dist/core/runner/e2e-helpers.d.ts +102 -0
  163. package/dist/core/runner/e2e-helpers.js +153 -0
  164. package/dist/core/runner/phase3-runner.d.ts +101 -2
  165. package/dist/core/runner/phase3-runner.js +559 -24
  166. package/dist/core/self-healing/assertion-healer.d.ts +97 -0
  167. package/dist/core/self-healing/assertion-healer.js +371 -0
  168. package/dist/core/self-healing/engine.d.ts +122 -0
  169. package/dist/core/self-healing/engine.js +538 -0
  170. package/dist/core/self-healing/index.d.ts +10 -0
  171. package/dist/core/self-healing/index.js +11 -0
  172. package/dist/core/self-healing/selector-healer.d.ts +103 -0
  173. package/dist/core/self-healing/selector-healer.js +372 -0
  174. package/dist/core/self-healing/types.d.ts +152 -0
  175. package/dist/core/self-healing/types.js +6 -0
  176. package/dist/core/slo/config.d.ts +107 -0
  177. package/dist/core/slo/config.js +360 -0
  178. package/dist/core/slo/index.d.ts +11 -0
  179. package/dist/core/slo/index.js +15 -0
  180. package/dist/core/slo/sli-calculator.d.ts +92 -0
  181. package/dist/core/slo/sli-calculator.js +364 -0
  182. package/dist/core/slo/slo-tracker.d.ts +148 -0
  183. package/dist/core/slo/slo-tracker.js +379 -0
  184. package/dist/core/slo/types.d.ts +281 -0
  185. package/dist/core/slo/types.js +7 -0
  186. package/dist/core/slo/vault.d.ts +102 -0
  187. package/dist/core/slo/vault.js +427 -0
  188. package/dist/core/tui/index.d.ts +7 -0
  189. package/dist/core/tui/index.js +6 -0
  190. package/dist/core/tui/monitor.d.ts +92 -0
  191. package/dist/core/tui/monitor.js +271 -0
  192. package/dist/core/tui/renderer.d.ts +33 -0
  193. package/dist/core/tui/renderer.js +218 -0
  194. package/dist/core/tui/types.d.ts +63 -0
  195. package/dist/core/tui/types.js +5 -0
  196. package/dist/core/types/pack-v2.d.ts +425 -0
  197. package/dist/core/types/pack-v2.js +8 -0
  198. package/dist/core/vault/index.d.ts +116 -0
  199. package/dist/core/vault/index.js +400 -5
  200. package/dist/core/watch/index.d.ts +7 -0
  201. package/dist/core/watch/index.js +6 -0
  202. package/dist/core/watch/watch-mode.d.ts +213 -0
  203. package/dist/core/watch/watch-mode.js +389 -0
  204. package/dist/index.js +68 -68
  205. package/dist/utils/config.d.ts +5 -0
  206. package/dist/utils/config.js +136 -0
  207. package/package.json +5 -1
  208. package/dist/core/adapters/playwright-api.d.ts +0 -82
  209. package/dist/core/adapters/playwright-api.js +0 -264
@@ -0,0 +1,252 @@
1
+ /**
2
+ * QA360 Coverage Command
3
+ *
4
+ * CLI command for coverage analytics and reporting.
5
+ */
6
+ import { Command } from 'commander';
7
+ import { existsSync } from 'fs';
8
+ import { CoverageCollector, CoverageAnalyzer, parseCoverageThreshold, formatCoverageThreshold } from '../core/index.js';
9
+ export const coverageCommand = new Command('coverage');
10
+ coverageCommand.description('Coverage analytics and reporting');
11
+ // Show coverage for a specific file or run
12
+ coverageCommand
13
+ .command('show')
14
+ .description('Show coverage metrics')
15
+ .option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
16
+ .option('-r, --run <id>', 'Run ID to fetch from vault')
17
+ .option('--json', 'Output as JSON')
18
+ .option('--verbose', 'Show detailed file-by-file coverage')
19
+ .action(async (options) => {
20
+ if (!options.file && !options.run) {
21
+ console.error('Error: Please specify --file or --run');
22
+ process.exit(1);
23
+ }
24
+ const collector = new CoverageCollector();
25
+ const analyzer = new CoverageAnalyzer();
26
+ let result;
27
+ if (options.file) {
28
+ if (!existsSync(options.file)) {
29
+ console.error(`Error: File not found: ${options.file}`);
30
+ process.exit(1);
31
+ }
32
+ result = await collector.collectFromFile(options.file);
33
+ if (!result) {
34
+ console.error('Error: Could not parse coverage file');
35
+ process.exit(1);
36
+ }
37
+ }
38
+ else if (options.run) {
39
+ // TODO: Fetch from vault when vault integration is complete
40
+ console.error('Error: Vault fetch not yet implemented');
41
+ process.exit(1);
42
+ }
43
+ if (!result)
44
+ return;
45
+ if (options.json) {
46
+ console.log(JSON.stringify(result, null, 2));
47
+ return;
48
+ }
49
+ // Print summary
50
+ console.log('\nšŸ“Š Coverage Report\n');
51
+ console.log(`Line Coverage: ${analyzer.formatCoverage(result.metrics.lineCoverage)}`);
52
+ console.log(`Branch Coverage: ${analyzer.formatCoverage(result.metrics.branchCoverage)}`);
53
+ console.log(`Function Coverage: ${analyzer.formatCoverage(result.metrics.functionCoverage)}`);
54
+ console.log(`Statement Coverage: ${analyzer.formatCoverage(result.metrics.statementCoverage)}`);
55
+ console.log(`\nFiles: ${result.metrics.filesWithCoverage}/${result.metrics.totalFiles}`);
56
+ if (options.verbose) {
57
+ console.log('\nšŸ“ File Coverage:\n');
58
+ const files = Object.entries(result.files)
59
+ .sort((a, b) => a[1].lineCoverage - b[1].lineCoverage);
60
+ for (const [path, file] of files) {
61
+ const status = file.lineCoverage >= 80 ? 'āœ“' : file.lineCoverage >= 60 ? '⚠' : 'āœ—';
62
+ console.log(` ${status} ${path}`);
63
+ console.log(` Lines: ${file.coveredLines}/${file.totalLines} (${file.lineCoverage.toFixed(1)}%)`);
64
+ console.log(` Branches: ${file.coveredBranches}/${file.totalBranches} (${file.branchCoverage.toFixed(1)}%)`);
65
+ console.log(` Functions: ${file.coveredFunctions}/${file.totalFunctions} (${file.functionCoverage.toFixed(1)}%)`);
66
+ if (file.uncoveredLines.length > 0 && file.uncoveredLines.length <= 10) {
67
+ console.log(` Uncovered: ${file.uncoveredLines.join(', ')}`);
68
+ }
69
+ else if (file.uncoveredLines.length > 10) {
70
+ console.log(` Uncovered: ${file.uncoveredLines.slice(0, 10).join(', ')} ... (${file.uncoveredLines.length} total)`);
71
+ }
72
+ console.log('');
73
+ }
74
+ }
75
+ });
76
+ // Analyze coverage and find gaps
77
+ coverageCommand
78
+ .command('analyze')
79
+ .description('Analyze coverage and find gaps')
80
+ .option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
81
+ .option('-t, --threshold <value>', 'Coverage threshold (default: 80)', '80')
82
+ .option('--json', 'Output as JSON')
83
+ .action(async (options) => {
84
+ if (!options.file) {
85
+ console.error('Error: Please specify --file');
86
+ process.exit(1);
87
+ }
88
+ if (!existsSync(options.file)) {
89
+ console.error(`Error: File not found: ${options.file}`);
90
+ process.exit(1);
91
+ }
92
+ const collector = new CoverageCollector();
93
+ const analyzer = new CoverageAnalyzer();
94
+ const result = await collector.collectFromFile(options.file);
95
+ if (!result) {
96
+ console.error('Error: Could not parse coverage file');
97
+ process.exit(1);
98
+ }
99
+ const threshold = parseCoverageThreshold(options.threshold);
100
+ const report = analyzer.analyze(result, threshold);
101
+ if (options.json) {
102
+ console.log(JSON.stringify(report, null, 2));
103
+ return;
104
+ }
105
+ console.log('\nšŸ“Š Coverage Analysis\n');
106
+ console.log(`Overall Coverage: ${report.metrics.lineCoverage.toFixed(1)}%`);
107
+ console.log(`Thresholds Met: ${report.thresholdsMet ? 'āœ“ Yes' : 'āœ— No'}`);
108
+ console.log(`Files Meeting Threshold: ${report.metrics.filesMeetingThreshold}/${report.metrics.totalFiles}`);
109
+ if (report.gaps.length > 0) {
110
+ console.log('\nšŸ”“ Coverage Gaps (files below threshold):\n');
111
+ for (const gap of report.gaps) {
112
+ const icon = gap.priority === 'high' ? 'šŸ”“' : gap.priority === 'medium' ? '🟔' : '🟢';
113
+ console.log(` ${icon} ${gap.path}`);
114
+ console.log(` Current: ${gap.currentCoverage.toFixed(1)}% | Target: ${gap.targetCoverage}% | Gap: ${gap.gap.toFixed(1)}%`);
115
+ console.log(` Effort: ${gap.effort} | Uncovered: ${gap.uncoveredCount} lines`);
116
+ if (gap.suggestions.length > 0) {
117
+ console.log(` Suggestions:`);
118
+ for (const suggestion of gap.suggestions) {
119
+ console.log(` - ${suggestion}`);
120
+ }
121
+ }
122
+ console.log('');
123
+ }
124
+ }
125
+ else {
126
+ console.log('\nāœ“ All files meet the coverage threshold!\n');
127
+ }
128
+ });
129
+ // Compare two coverage files
130
+ coverageCommand
131
+ .command('diff')
132
+ .description('Compare two coverage files')
133
+ .option('-b, --base <path>', 'Base coverage file')
134
+ .option('-c, --compare <path>', 'Comparison coverage file')
135
+ .option('--json', 'Output as JSON')
136
+ .action(async (options) => {
137
+ if (!options.base || !options.compare) {
138
+ console.error('Error: Please specify both --base and --compare');
139
+ process.exit(1);
140
+ }
141
+ if (!existsSync(options.base)) {
142
+ console.error(`Error: Base file not found: ${options.base}`);
143
+ process.exit(1);
144
+ }
145
+ if (!existsSync(options.compare)) {
146
+ console.error(`Error: Compare file not found: ${options.compare}`);
147
+ process.exit(1);
148
+ }
149
+ const collector = new CoverageCollector();
150
+ const analyzer = new CoverageAnalyzer();
151
+ const baseResult = await collector.collectFromFile(options.base);
152
+ const compareResult = await collector.collectFromFile(options.compare);
153
+ if (!baseResult || !compareResult) {
154
+ console.error('Error: Could not parse coverage files');
155
+ process.exit(1);
156
+ }
157
+ const comparison = analyzer.compare(baseResult, compareResult);
158
+ if (options.json) {
159
+ console.log(JSON.stringify(comparison, null, 2));
160
+ return;
161
+ }
162
+ console.log('\nšŸ“Š Coverage Comparison\n');
163
+ console.log(`Overall Change: ${comparison.overallChange >= 0 ? '+' : ''}${comparison.overallChange.toFixed(1)}%`);
164
+ if (comparison.improved.length > 0) {
165
+ console.log('\nāœ… Improved Files:\n');
166
+ for (const file of comparison.improved.slice(0, 10)) {
167
+ console.log(` ${file.path}`);
168
+ console.log(` ${file.before.toFixed(1)}% → ${file.after.toFixed(1)}% (+${file.delta.toFixed(1)}%)`);
169
+ }
170
+ }
171
+ if (comparison.regressed.length > 0) {
172
+ console.log('\nāš ļø Regressed Files:\n');
173
+ for (const file of comparison.regressed.slice(0, 10)) {
174
+ console.log(` ${file.path}`);
175
+ console.log(` ${file.before.toFixed(1)}% → ${file.after.toFixed(1)}% (${file.delta.toFixed(1)}%)`);
176
+ }
177
+ }
178
+ if (comparison.newFiles.length > 0) {
179
+ console.log('\nšŸ†• New Files:\n');
180
+ for (const file of comparison.newFiles.slice(0, 10)) {
181
+ console.log(` ${file}`);
182
+ }
183
+ }
184
+ if (comparison.removedFiles.length > 0) {
185
+ console.log('\nšŸ—‘ļø Removed Files:\n');
186
+ for (const file of comparison.removedFiles.slice(0, 10)) {
187
+ console.log(` ${file}`);
188
+ }
189
+ }
190
+ console.log('');
191
+ });
192
+ // List coverage files in project
193
+ coverageCommand
194
+ .command('list')
195
+ .description('List available coverage files in the project')
196
+ .action(() => {
197
+ const coveragePaths = [
198
+ 'coverage/coverage-final.json',
199
+ 'coverage/lcov.info',
200
+ 'coverage/lcov-report/index.html',
201
+ '.nyc_output/out.json',
202
+ 'coverage/istanbul.json'
203
+ ];
204
+ console.log('\nšŸ“‚ Coverage Files:\n');
205
+ for (const path of coveragePaths) {
206
+ const exists = existsSync(path);
207
+ const status = exists ? 'āœ“' : 'āœ—';
208
+ console.log(` ${status} ${path}`);
209
+ }
210
+ console.log('');
211
+ });
212
+ // Validate coverage against thresholds
213
+ coverageCommand
214
+ .command('check')
215
+ .description('Check if coverage meets thresholds')
216
+ .option('-f, --file <path>', 'Coverage file (JSON, LCOV, or Istanbul format)')
217
+ .option('-t, --threshold <value>', 'Coverage threshold (default: line:80,branch:70)', 'line:80,branch:70')
218
+ .option('--fail', 'Exit with error code if thresholds not met')
219
+ .action(async (options) => {
220
+ if (!options.file) {
221
+ console.error('Error: Please specify --file');
222
+ process.exit(1);
223
+ }
224
+ if (!existsSync(options.file)) {
225
+ console.error(`Error: File not found: ${options.file}`);
226
+ process.exit(1);
227
+ }
228
+ const collector = new CoverageCollector();
229
+ const analyzer = new CoverageAnalyzer();
230
+ const result = await collector.collectFromFile(options.file);
231
+ if (!result) {
232
+ console.error('Error: Could not parse coverage file');
233
+ process.exit(1);
234
+ }
235
+ const threshold = parseCoverageThreshold(options.threshold);
236
+ const passed = analyzer.checkThresholds(result.metrics, threshold);
237
+ console.log('\nšŸ“Š Coverage Check\n');
238
+ console.log(`Threshold: ${formatCoverageThreshold(threshold)}`);
239
+ console.log(`Line Coverage: ${result.metrics.lineCoverage.toFixed(1)}% ${result.metrics.lineCoverage >= (threshold.line || 0) ? 'āœ“' : 'āœ—'}`);
240
+ console.log(`Branch Coverage: ${result.metrics.branchCoverage.toFixed(1)}% ${result.metrics.branchCoverage >= (threshold.branch || 0) ? 'āœ“' : 'āœ—'}`);
241
+ console.log(`Function Coverage: ${result.metrics.functionCoverage.toFixed(1)}% ${result.metrics.functionCoverage >= (threshold.function || 0) ? 'āœ“' : 'āœ—'}`);
242
+ if (passed) {
243
+ console.log('\nāœ… All thresholds met!\n');
244
+ }
245
+ else {
246
+ console.log('\nāŒ Some thresholds not met!\n');
247
+ if (options.fail) {
248
+ process.exit(1);
249
+ }
250
+ }
251
+ });
252
+ export default coverageCommand;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * QA360 Explain Command
3
+ *
4
+ * Advanced error and failure explanations with:
5
+ * - Static error code database
6
+ * - AI-powered explanations
7
+ * - Vault-based historical context
8
+ * - Flakiness insights
9
+ *
10
+ * Usage:
11
+ * qa360 explain QX001 # Static error code
12
+ * qa360 explain --ai "my test failed" # AI explanation
13
+ * qa360 explain --run run-xxx # Explain run results
14
+ * qa360 explain --gate api_smoke # Explain gate failure
15
+ */
16
+ export interface ExplainOptions {
17
+ ai?: boolean;
18
+ provider?: string;
19
+ run?: string;
20
+ gate?: string;
21
+ json?: boolean;
22
+ }
23
+ /**
24
+ * Main explain command
25
+ */
26
+ export declare function explainCommand(input: string | undefined, options?: ExplainOptions): Promise<void>;
27
+ export default explainCommand;