qa360 2.0.12 → 2.1.0

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 (66) hide show
  1. package/dist/commands/ai.js +26 -14
  2. package/dist/commands/ask.d.ts +75 -23
  3. package/dist/commands/ask.js +413 -265
  4. package/dist/commands/crawl.d.ts +24 -0
  5. package/dist/commands/crawl.js +121 -0
  6. package/dist/commands/history.js +38 -3
  7. package/dist/commands/init.d.ts +89 -95
  8. package/dist/commands/init.js +282 -200
  9. package/dist/commands/run.d.ts +1 -0
  10. package/dist/core/adapters/playwright-native-adapter.d.ts +121 -0
  11. package/dist/core/adapters/playwright-native-adapter.js +339 -0
  12. package/dist/core/adapters/playwright-ui.d.ts +83 -7
  13. package/dist/core/adapters/playwright-ui.js +525 -59
  14. package/dist/core/artifacts/index.d.ts +6 -0
  15. package/dist/core/artifacts/index.js +6 -0
  16. package/dist/core/artifacts/ui-artifacts.d.ts +133 -0
  17. package/dist/core/artifacts/ui-artifacts.js +304 -0
  18. package/dist/core/assertions/engine.d.ts +51 -0
  19. package/dist/core/assertions/engine.js +530 -0
  20. package/dist/core/assertions/index.d.ts +11 -0
  21. package/dist/core/assertions/index.js +11 -0
  22. package/dist/core/assertions/types.d.ts +121 -0
  23. package/dist/core/assertions/types.js +37 -0
  24. package/dist/core/crawler/index.d.ts +57 -0
  25. package/dist/core/crawler/index.js +281 -0
  26. package/dist/core/crawler/journey-generator.d.ts +49 -0
  27. package/dist/core/crawler/journey-generator.js +412 -0
  28. package/dist/core/crawler/page-analyzer.d.ts +88 -0
  29. package/dist/core/crawler/page-analyzer.js +709 -0
  30. package/dist/core/crawler/selector-generator.d.ts +34 -0
  31. package/dist/core/crawler/selector-generator.js +240 -0
  32. package/dist/core/crawler/types.d.ts +353 -0
  33. package/dist/core/crawler/types.js +6 -0
  34. package/dist/core/generation/crawler-pack-generator.d.ts +44 -0
  35. package/dist/core/generation/crawler-pack-generator.js +231 -0
  36. package/dist/core/generation/index.d.ts +2 -0
  37. package/dist/core/generation/index.js +2 -0
  38. package/dist/core/index.d.ts +9 -0
  39. package/dist/core/index.js +13 -0
  40. package/dist/core/parallel/index.d.ts +6 -0
  41. package/dist/core/parallel/index.js +6 -0
  42. package/dist/core/parallel/parallel-runner.d.ts +107 -0
  43. package/dist/core/parallel/parallel-runner.js +192 -0
  44. package/dist/core/reporting/html-reporter.d.ts +119 -0
  45. package/dist/core/reporting/html-reporter.js +737 -0
  46. package/dist/core/reporting/index.d.ts +6 -0
  47. package/dist/core/reporting/index.js +6 -0
  48. package/dist/core/runner/phase3-runner.js +5 -1
  49. package/dist/core/types/pack-v1.d.ts +90 -0
  50. package/dist/core/vault/cas.d.ts +5 -1
  51. package/dist/core/vault/cas.js +6 -0
  52. package/dist/core/visual/index.d.ts +6 -0
  53. package/dist/core/visual/index.js +6 -0
  54. package/dist/core/visual/visual-regression.d.ts +113 -0
  55. package/dist/core/visual/visual-regression.js +236 -0
  56. package/dist/index.js +6 -2
  57. package/examples/README.md +38 -0
  58. package/examples/accessibility.yml +39 -16
  59. package/examples/api-basic.yml +19 -14
  60. package/examples/complete.yml +134 -42
  61. package/examples/crawler.yml +38 -0
  62. package/examples/fullstack.yml +66 -31
  63. package/examples/security.yml +47 -15
  64. package/examples/ui-advanced.yml +49 -0
  65. package/examples/ui-basic.yml +16 -12
  66. package/package.json +1 -1
@@ -31,12 +31,24 @@ export async function aiListCommand() {
31
31
  const status = provider.available
32
32
  ? chalk.green('✓ Available')
33
33
  : chalk.gray('✗ Not set up');
34
- const costLevel = {
35
- free: chalk.green('FREE'),
36
- low: chalk.yellow('LOW'),
37
- medium: chalk.yellow('MED'),
38
- high: chalk.red('HIGH')
39
- }[provider.costLevel];
34
+ // Get cost level display
35
+ let costLevel;
36
+ switch (provider.costLevel) {
37
+ case 'free':
38
+ costLevel = chalk.green('FREE');
39
+ break;
40
+ case 'low':
41
+ costLevel = chalk.yellow('LOW');
42
+ break;
43
+ case 'medium':
44
+ costLevel = chalk.yellow('MED');
45
+ break;
46
+ case 'high':
47
+ costLevel = chalk.red('HIGH');
48
+ break;
49
+ default:
50
+ costLevel = provider.costLevel;
51
+ }
40
52
  table.push([
41
53
  chalk.bold(provider.name),
42
54
  status,
@@ -46,33 +58,33 @@ export async function aiListCommand() {
46
58
  }
47
59
  console.log(table.toString());
48
60
  // Show setup instructions for unavailable providers
49
- const unavailable = providers.filter(p => !p.available && p.type !== 'mock');
61
+ const unavailable = providers.filter((p) => !p.available && p.type !== 'mock');
50
62
  if (unavailable.length > 0) {
51
63
  console.log(chalk.yellow('\n[INFO] Setup available providers:\n'));
52
- if (!providers.find(p => p.type === 'deepseek')?.available) {
64
+ if (!providers.find((p) => p.type === 'deepseek')?.available) {
53
65
  console.log(chalk.cyan('DeepSeek (Recommended - Best Value):'));
54
66
  console.log(chalk.gray(' 1. Get API key: https://platform.deepseek.com/api_keys'));
55
67
  console.log(chalk.gray(' 2. Run: qa360 secrets add DEEPSEEK_API_KEY\n'));
56
68
  }
57
- if (!providers.find(p => p.type === 'ollama')?.available) {
69
+ if (!providers.find((p) => p.type === 'ollama')?.available) {
58
70
  console.log(chalk.cyan('Ollama (Free - Local):'));
59
71
  console.log(chalk.gray(' 1. Install: brew install ollama'));
60
72
  console.log(chalk.gray(' 2. Run: ollama serve'));
61
73
  console.log(chalk.gray(' 3. Pull model: ollama pull deepseek-coder\n'));
62
74
  }
63
- if (!providers.find(p => p.type === 'openai')?.available) {
75
+ if (!providers.find((p) => p.type === 'openai')?.available) {
64
76
  console.log(chalk.cyan('OpenAI:'));
65
77
  console.log(chalk.gray(' 1. Get API key: https://platform.openai.com/api-keys'));
66
78
  console.log(chalk.gray(' 2. Run: qa360 secrets add OPENAI_API_KEY\n'));
67
79
  }
68
- if (!providers.find(p => p.type === 'anthropic')?.available) {
80
+ if (!providers.find((p) => p.type === 'anthropic')?.available) {
69
81
  console.log(chalk.cyan('Anthropic:'));
70
82
  console.log(chalk.gray(' 1. Get API key: https://console.anthropic.com/'));
71
83
  console.log(chalk.gray(' 2. Run: qa360 secrets add ANTHROPIC_API_KEY\n'));
72
84
  }
73
85
  }
74
86
  // Show best provider
75
- const bestProvider = providers.find(p => p.available && p.type !== 'mock');
87
+ const bestProvider = providers.find((p) => p.available && p.type !== 'mock');
76
88
  if (bestProvider) {
77
89
  console.log(chalk.green(`\n[STAR] Best available: ${chalk.bold(bestProvider.name)}`));
78
90
  console.log(chalk.gray(` ${bestProvider.description}`));
@@ -263,7 +275,7 @@ export async function aiGenerateCommand(prompt, options = {}) {
263
275
  spinner?.fail('Generation failed');
264
276
  if (error instanceof DeepSeekError) {
265
277
  console.error(chalk.red('\nDeepSeek Error:'), error.message);
266
- if (error.details) {
278
+ if ('details' in error && error.details) {
267
279
  console.error(chalk.gray(JSON.stringify(error.details, null, 2)));
268
280
  }
269
281
  }
@@ -277,7 +289,7 @@ export async function aiGenerateCommand(prompt, options = {}) {
277
289
  console.error(chalk.red('\nAnthropic Error:'), error.message);
278
290
  }
279
291
  else {
280
- console.error(chalk.red('Error:'), error.message);
292
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));
281
293
  }
282
294
  }
283
295
  }
@@ -1,32 +1,84 @@
1
1
  /**
2
- * QA360 Ask Command - Natural language to pack.yml generation
2
+ * QA360 Ask Command - Natural language to pack.yml generation (v2)
3
3
  */
4
- export interface PackConfig {
4
+ export interface PackConfigV2 {
5
+ version: 2;
5
6
  name: string;
6
- version: string;
7
- description: string;
8
- adapters: string[];
9
- tests: TestSpec[];
10
- hooks?: PackHooks;
11
- secrets?: string[];
12
- environment?: Record<string, string>;
13
- }
14
- export interface TestSpec {
15
- name: string;
16
- adapter: string;
17
- config: Record<string, any>;
7
+ description?: string;
8
+ profile?: string;
9
+ auth?: AuthConfigV2;
10
+ gates: Record<string, GateConfigV2>;
11
+ hooks?: HooksConfig;
12
+ execution?: ExecutionConfigV2;
13
+ variables?: Record<string, string>;
14
+ metadata?: Record<string, unknown>;
15
+ }
16
+ export interface AuthConfigV2 {
17
+ api?: string;
18
+ ui?: string;
19
+ profiles?: Record<string, AuthProfile>;
20
+ }
21
+ export interface AuthProfile {
22
+ type: string;
23
+ config: Record<string, unknown>;
24
+ cache?: {
25
+ enabled?: boolean;
26
+ ttl?: number;
27
+ };
28
+ }
29
+ export interface GateConfigV2 {
30
+ adapter?: string;
31
+ test_files?: string[];
32
+ config?: Record<string, unknown>;
33
+ auth?: string;
34
+ budgets?: Record<string, unknown>;
35
+ options?: {
36
+ timeout?: number;
37
+ retries?: number;
38
+ continue_on_failure?: boolean;
39
+ };
40
+ enabled?: boolean;
41
+ depends_on?: string[];
42
+ parallel?: boolean;
43
+ }
44
+ export interface HooksConfig {
45
+ beforeAll?: Hook[];
46
+ afterAll?: Hook[];
47
+ beforeEach?: Hook[];
48
+ afterEach?: Hook[];
49
+ }
50
+ export interface Hook {
51
+ type: 'run' | 'wait_on' | 'script' | 'docker';
52
+ command?: string;
53
+ cwd?: string;
18
54
  timeout?: number;
19
- retries?: number;
55
+ env?: Record<string, string>;
56
+ wait_for?: {
57
+ resource: string;
58
+ timeout?: number;
59
+ };
60
+ compose?: {
61
+ file?: string;
62
+ services?: string[];
63
+ command?: string;
64
+ };
20
65
  }
21
- export interface PackHooks {
22
- beforeAll?: string[];
23
- afterAll?: string[];
24
- beforeEach?: string[];
25
- afterEach?: string[];
66
+ export interface ExecutionConfigV2 {
67
+ parallel?: boolean;
68
+ max_concurrency?: number;
69
+ default_timeout?: number;
70
+ default_retries?: number;
71
+ on_failure: 'stop' | 'continue' | 'proceed';
72
+ limits?: {
73
+ cpu?: string;
74
+ memory?: string;
75
+ };
76
+ compose_file?: string;
77
+ hook_timeout_ms?: number;
26
78
  }
27
79
  export declare class QA360Ask {
28
80
  private qa360Dir;
29
- generatePack(query?: string): Promise<PackConfig>;
81
+ generatePack(query?: string): Promise<PackConfigV2>;
30
82
  private interactiveMode;
31
83
  private parseNaturalLanguage;
32
84
  private generatePackFromAnswers;
@@ -36,7 +88,7 @@ export declare class QA360Ask {
36
88
  private generateSecurityPack;
37
89
  private generateAccessibilityPack;
38
90
  private generateCompletePack;
39
- savePack(pack: PackConfig): Promise<string>;
40
- displayPack(pack: PackConfig): void;
91
+ savePack(pack: PackConfigV2): Promise<string>;
92
+ displayPack(pack: PackConfigV2): void;
41
93
  }
42
94
  export declare function askCommand(query?: string): Promise<void>;