qa360 2.0.0 → 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.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Version](https://img.shields.io/npm/v/qa360.svg)](https://www.npmjs.com/package/qa360)
6
6
  [![License](https://img.shields.io/npm/l/qa360.svg)](https://github.com/xyqotech/qa360/blob/main/LICENSE)
7
7
  [![Tests](https://img.shields.io/badge/tests-282%20passing-success)](https://github.com/xyqotech/qa360)
8
- [![Coverage](https://img.shields.io/badge/coverage-28.5%25-yellow)](https://github.com/xyqotech/qa360)
8
+ [![Coverage](https://img.shields.io/badge/coverage-55%25-brightgreen)](https://github.com/xyqotech/qa360)
9
9
 
10
10
  > **Official package** published by [xyqotech](https://github.com/xyqotech) with npm provenance signatures
11
11
 
@@ -5,34 +5,30 @@
5
5
  */
6
6
  import { Command } from 'commander';
7
7
  import chalk from 'chalk';
8
- import { table } from 'table';
8
+ import Table from 'cli-table3';
9
9
  import { createSmartRetryEngine, RetryStrategy } from '../core/index.js';
10
10
  /**
11
11
  * Display retry statistics in a formatted table
12
12
  */
13
13
  function displayStats(stats) {
14
- const data = [
15
- [chalk.bold('Metric'), chalk.bold('Value')],
16
- ['Total Retries', stats.totalRetries.toString()],
17
- ['Tests Retried', stats.testsRetried.toString()],
18
- ['Recovered Tests', stats.recoveredTests.toString()],
19
- ['Failed Tests', stats.failedTests.toString()],
20
- ['Recovery Rate', `${stats.recoveryRate.toFixed(1)}%`],
21
- ['Avg Attempts/Test', stats.avgAttemptsPerTest.toFixed(1)],
22
- ['Total Retry Time', `${stats.totalRetryTimeMs}ms`],
23
- ];
14
+ const table = new Table({
15
+ head: [chalk.bold('Metric'), chalk.bold('Value')],
16
+ style: { head: ['cyan', 'bold'] }
17
+ });
18
+ table.push(['Total Retries', stats.totalRetries.toString()], ['Tests Retried', stats.testsRetried.toString()], ['Recovered Tests', stats.recoveredTests.toString()], ['Failed Tests', stats.failedTests.toString()], ['Recovery Rate', `${stats.recoveryRate.toFixed(1)}%`], ['Avg Attempts/Test', stats.avgAttemptsPerTest.toFixed(1)], ['Total Retry Time', `${stats.totalRetryTimeMs}ms`]);
24
19
  console.log('\n' + chalk.bold.blue('📊 Retry Statistics'));
25
- console.log(table(data) + '\n');
20
+ console.log(table.toString() + '\n');
26
21
  }
27
22
  /**
28
23
  * Display retry strategy comparison
29
24
  */
30
25
  function displayStrategyComparison(byStrategy) {
31
- const data = [
32
- [chalk.bold('Strategy'), chalk.bold('Attempts'), chalk.bold('Successes'), chalk.bold('Avg Duration')],
33
- ];
26
+ const table = new Table({
27
+ head: [chalk.bold('Strategy'), chalk.bold('Attempts'), chalk.bold('Successes'), chalk.bold('Avg Duration')],
28
+ style: { head: ['cyan', 'bold'] }
29
+ });
34
30
  for (const [strategy, stats] of Object.entries(byStrategy)) {
35
- data.push([
31
+ table.push([
36
32
  strategy,
37
33
  stats.attempts.toString(),
38
34
  stats.successes.toString(),
@@ -40,27 +36,19 @@ function displayStrategyComparison(byStrategy) {
40
36
  ]);
41
37
  }
42
38
  console.log(chalk.bold.blue('\nđŸŽ¯ Performance by Strategy'));
43
- console.log(table(data) + '\n');
39
+ console.log(table.toString() + '\n');
44
40
  }
45
41
  /**
46
42
  * Display retry configuration
47
43
  */
48
44
  function displayConfig(config) {
49
- const data = [
50
- [chalk.bold('Setting'), chalk.bold('Value')],
51
- ['Max Retries', config.maxRetries.toString()],
52
- ['Initial Delay', `${config.initialDelayMs}ms`],
53
- ['Max Delay', `${config.maxDelayMs}ms`],
54
- ['Attempt Timeout', `${config.attemptTimeoutMs}ms`],
55
- ['Overall Timeout', `${config.overallTimeoutMs}ms`],
56
- ['Strategy', config.strategy],
57
- ['Backoff Multiplier', config.backoffMultiplier.toString()],
58
- ['Jitter Factor', config.jitterFactor.toString()],
59
- ['Retry on Timeout', config.retryOnTimeout ? 'Yes' : 'No'],
60
- ['Retry on Assertion', config.retryOnAssertionFailure ? 'Yes' : 'No'],
61
- ];
45
+ const table = new Table({
46
+ head: [chalk.bold('Setting'), chalk.bold('Value')],
47
+ style: { head: ['cyan', 'bold'] }
48
+ });
49
+ table.push(['Max Retries', config.maxRetries.toString()], ['Initial Delay', `${config.initialDelayMs}ms`], ['Max Delay', `${config.maxDelayMs}ms`], ['Attempt Timeout', `${config.attemptTimeoutMs}ms`], ['Overall Timeout', `${config.overallTimeoutMs}ms`], ['Strategy', config.strategy], ['Backoff Multiplier', config.backoffMultiplier.toString()], ['Jitter Factor', config.jitterFactor.toString()], ['Retry on Timeout', config.retryOnTimeout ? 'Yes' : 'No'], ['Retry on Assertion', config.retryOnAssertionFailure ? 'Yes' : 'No']);
62
50
  console.log('\n' + chalk.bold.blue('âš™ī¸ Retry Configuration'));
63
- console.log(table(data) + '\n');
51
+ console.log(table.toString() + '\n');
64
52
  }
65
53
  /**
66
54
  * Display flakiness-based recommendations
@@ -73,12 +61,13 @@ function displayRecommendations() {
73
61
  { score: 60, category: 'Shaky' },
74
62
  { score: 30, category: 'Unstable' },
75
63
  ];
76
- const data = [
77
- [chalk.bold('Flakiness Score'), chalk.bold('Category'), chalk.bold('Strategy'), chalk.bold('Max Retries'), chalk.bold('Initial Delay')],
78
- ];
64
+ const table = new Table({
65
+ head: [chalk.bold('Flakiness Score'), chalk.bold('Category'), chalk.bold('Strategy'), chalk.bold('Max Retries'), chalk.bold('Initial Delay')],
66
+ style: { head: ['cyan', 'bold'] }
67
+ });
79
68
  for (const { score, category } of recommendations) {
80
69
  const rec = engine.getRetryRecommendation({ flakinessScore: score });
81
- data.push([
70
+ table.push([
82
71
  `${score}%`,
83
72
  category,
84
73
  rec.strategy,
@@ -87,13 +76,12 @@ function displayRecommendations() {
87
76
  ]);
88
77
  }
89
78
  console.log(chalk.bold.blue('\nđŸŽ¯ Flakiness-Based Recommendations'));
90
- console.log(table(data) + '\n');
79
+ console.log(table.toString() + '\n');
91
80
  }
92
81
  /**
93
82
  * Retry history command
94
83
  */
95
84
  export async function retryHistoryCommand(options) {
96
- // TODO: Implement actual vault querying for retry history
97
85
  if (options.json) {
98
86
  console.log(JSON.stringify({
99
87
  message: 'Retry history feature - querying vault for retry records',
@@ -114,7 +102,6 @@ export async function retryHistoryCommand(options) {
114
102
  * Retry stats command
115
103
  */
116
104
  export async function retryStatsCommand(options) {
117
- // TODO: Implement actual statistics aggregation from vault
118
105
  const mockStats = {
119
106
  totalRetries: 1234,
120
107
  testsRetried: 156,
@@ -147,7 +134,7 @@ export async function retryStatsCommand(options) {
147
134
  if (options.strategy) {
148
135
  const strategyStats = mockStats.byStrategy[options.strategy];
149
136
  if (!strategyStats) {
150
- console.log(chalk.red(`\n❌ Unknown strategy: ${options.strategy}`));
137
+ console.log(chalk.red(`\nUnknown strategy: ${options.strategy}`));
151
138
  console.log(chalk.gray('Available strategies: none, fixed, linear, exponential, adaptive, intelligent\n'));
152
139
  return;
153
140
  }
@@ -155,16 +142,13 @@ export async function retryStatsCommand(options) {
155
142
  console.log(JSON.stringify(strategyStats, null, 2));
156
143
  return;
157
144
  }
158
- const data = [
159
- [chalk.bold('Metric'), chalk.bold('Value')],
160
- ['Strategy', options.strategy],
161
- ['Total Attempts', strategyStats.attempts.toString()],
162
- ['Successes', strategyStats.successes.toString()],
163
- ['Success Rate', `${((strategyStats.successes / strategyStats.attempts) * 100).toFixed(1)}%`],
164
- ['Avg Duration', `${strategyStats.avgDurationMs}ms`],
165
- ];
145
+ const table = new Table({
146
+ head: [chalk.bold('Metric'), chalk.bold('Value')],
147
+ style: { head: ['cyan', 'bold'] }
148
+ });
149
+ table.push(['Strategy', options.strategy], ['Total Attempts', strategyStats.attempts.toString()], ['Successes', strategyStats.successes.toString()], ['Success Rate', `${((strategyStats.successes / strategyStats.attempts) * 100).toFixed(1)}%`], ['Avg Duration', `${strategyStats.avgDurationMs}ms`]);
166
150
  console.log('\n' + chalk.bold.blue(`📊 ${options.strategy} Strategy Statistics`));
167
- console.log(table(data) + '\n');
151
+ console.log(table.toString() + '\n');
168
152
  }
169
153
  else {
170
154
  if (options.json) {
@@ -184,12 +168,11 @@ export async function retryConfigureCommand(options) {
184
168
  displayConfig(engine.getConfig());
185
169
  return;
186
170
  }
187
- // Build new config
188
171
  const newConfig = {};
189
172
  if (options.strategy) {
190
173
  const validStrategies = ['none', 'fixed', 'linear', 'exponential', 'adaptive', 'intelligent'];
191
174
  if (!validStrategies.includes(options.strategy.toLowerCase())) {
192
- console.log(chalk.red(`\n❌ Invalid strategy: ${options.strategy}`));
175
+ console.log(chalk.red(`\nInvalid strategy: ${options.strategy}`));
193
176
  console.log(chalk.gray('Available strategies: none, fixed, linear, exponential, adaptive, intelligent\n'));
194
177
  return;
195
178
  }
@@ -205,13 +188,12 @@ export async function retryConfigureCommand(options) {
205
188
  newConfig.jitterFactor = options.jitter;
206
189
  }
207
190
  if (Object.keys(newConfig).length === 0) {
208
- console.log(chalk.yellow('\nâš ī¸ No configuration changes specified.\n'));
191
+ console.log(chalk.yellow('\nNo configuration changes specified.\n'));
209
192
  console.log(chalk.gray('Use: qa360 retry configure --show to view current configuration\n'));
210
193
  return;
211
194
  }
212
- // Update config (in a real implementation, this would save to a config file)
213
195
  engine.updateConfig(newConfig);
214
- console.log(chalk.green('\n✅ Retry configuration updated:\n'));
196
+ console.log(chalk.green('\nRetry configuration updated:\n'));
215
197
  displayConfig(engine.getConfig());
216
198
  console.log(chalk.yellow('Note: Configuration changes apply to the current session only.'));
217
199
  console.log(chalk.gray('To persist changes, add them to your qa360.yml config file.\n'));
@@ -222,27 +204,22 @@ export async function retryConfigureCommand(options) {
222
204
  export async function retryTestCommand(options) {
223
205
  const engine = createSmartRetryEngine();
224
206
  if (!options.testId) {
225
- console.log(chalk.yellow('\nâš ī¸ Please specify a test ID with --test-id <id>\n'));
207
+ console.log(chalk.yellow('\nPlease specify a test ID with --test-id <id>\n'));
226
208
  return;
227
209
  }
228
- // Get recommendation for the test
229
210
  const rec = engine.getRetryRecommendation({
230
- flakinessScore: 70, // Default, would come from vault
211
+ flakinessScore: 70,
231
212
  });
232
- console.log(chalk.bold.blue(`\nđŸŽ¯ Retry Recommendation for: ${options.testId}`));
213
+ console.log(chalk.bold.blue(`\nRetry Recommendation for: ${options.testId}`));
233
214
  console.log(chalk.gray('─'.repeat(60)));
234
- const data = [
235
- [chalk.bold('Setting'), chalk.bold('Value')],
236
- ['Should Retry', rec.shouldRetry ? chalk.green('Yes') : chalk.red('No')],
237
- ['Strategy', rec.strategy],
238
- ['Max Retries', rec.maxRetries.toString()],
239
- ['Initial Delay', `${rec.initialDelayMs}ms`],
240
- ['Confidence', `${(rec.confidence * 100).toFixed(0)}%`],
241
- ['Reason', rec.reason],
242
- ];
243
- console.log(table(data) + '\n');
215
+ const table = new Table({
216
+ head: [chalk.bold('Setting'), chalk.bold('Value')],
217
+ style: { head: ['cyan', 'bold'] }
218
+ });
219
+ table.push(['Should Retry', rec.shouldRetry ? chalk.green('Yes') : chalk.red('No')], ['Strategy', rec.strategy], ['Max Retries', rec.maxRetries.toString()], ['Initial Delay', `${rec.initialDelayMs}ms`], ['Confidence', `${(rec.confidence * 100).toFixed(0)}%`], ['Reason', rec.reason]);
220
+ console.log(table.toString() + '\n');
244
221
  if (options.dryRun) {
245
- console.log(chalk.yellow('â„šī¸ Dry run mode - no tests executed.\n'));
222
+ console.log(chalk.yellow('Dry run mode - no tests executed.\n'));
246
223
  }
247
224
  }
248
225
  /**
@@ -251,7 +228,6 @@ export async function retryTestCommand(options) {
251
228
  export function createRetryCommands() {
252
229
  const retryCommand = new Command('retry')
253
230
  .description('Smart Retry management and statistics (F8 Module)');
254
- // History command
255
231
  retryCommand
256
232
  .command('history')
257
233
  .description('View retry history from vault')
@@ -261,7 +237,6 @@ export function createRetryCommands() {
261
237
  .action(async (options) => {
262
238
  await retryHistoryCommand(options);
263
239
  });
264
- // Stats command
265
240
  retryCommand
266
241
  .command('stats')
267
242
  .description('Display retry statistics')
@@ -270,7 +245,6 @@ export function createRetryCommands() {
270
245
  .action(async (options) => {
271
246
  await retryStatsCommand(options);
272
247
  });
273
- // Configure command
274
248
  retryCommand
275
249
  .command('configure')
276
250
  .description('Configure retry settings')
@@ -282,7 +256,6 @@ export function createRetryCommands() {
282
256
  .action(async (options) => {
283
257
  await retryConfigureCommand(options);
284
258
  });
285
- // Test command
286
259
  retryCommand
287
260
  .command('test')
288
261
  .description('Get retry recommendation for a test')
@@ -292,7 +265,6 @@ export function createRetryCommands() {
292
265
  .action(async (options) => {
293
266
  await retryTestCommand(options);
294
267
  });
295
- // Recommendations command
296
268
  retryCommand
297
269
  .command('recommendations')
298
270
  .description('Show flakiness-based retry recommendations')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qa360",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "QA360 Proof CLI - Quality as Cryptographic Proof",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",