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
@@ -5,6 +5,7 @@
5
5
  * qa360 init
6
6
  * qa360 init --template api-basic
7
7
  * qa360 init --output custom-pack.yml
8
+ * qa360 init --beginner # Guided mode for first-time users
8
9
  */
9
10
  import { existsSync, writeFileSync, mkdirSync } from 'fs';
10
11
  import { join, resolve } from 'path';
@@ -19,41 +20,243 @@ export const TEMPLATES = {
19
20
  name: 'API Basic',
20
21
  description: 'Simple API smoke tests (REST/GraphQL)',
21
22
  gates: ['api_smoke'],
23
+ icon: '🔌',
22
24
  },
23
25
  'ui-basic': {
24
26
  name: 'UI Basic',
25
27
  description: 'Basic UI/E2E browser tests',
26
28
  gates: ['ui'],
29
+ icon: '🌐',
27
30
  },
28
31
  'fullstack': {
29
32
  name: 'Full Stack',
30
33
  description: 'API + UI + Performance tests',
31
34
  gates: ['api_smoke', 'ui', 'perf'],
35
+ icon: '🎯',
32
36
  },
33
37
  'security': {
34
38
  name: 'Security',
35
39
  description: 'SAST, DAST, secrets scanning, dependency checks',
36
40
  gates: ['sast', 'dast', 'secrets', 'deps'],
41
+ icon: '🛡️',
37
42
  },
38
43
  'complete': {
39
44
  name: 'Complete',
40
45
  description: 'All quality gates (API, UI, Performance, Security, Accessibility)',
41
46
  gates: ['api_smoke', 'ui', 'a11y', 'perf', 'sast', 'dast', 'secrets', 'deps'],
47
+ icon: '✨',
42
48
  },
43
49
  };
44
50
  /**
45
- * Gate descriptions
51
+ * Gate descriptions with beginner-friendly explanations
46
52
  */
47
53
  export const GATE_DESCRIPTIONS = {
48
- api_smoke: 'API smoke tests (REST/GraphQL health checks)',
49
- ui: 'UI/E2E tests (browser automation)',
50
- a11y: 'Accessibility tests (WCAG compliance)',
51
- perf: 'Performance tests (load/stress testing)',
52
- sast: 'Static security analysis (code scanning)',
53
- dast: 'Dynamic security testing (runtime scanning)',
54
- secrets: 'Secrets detection (credential scanning)',
55
- deps: 'Dependency vulnerability checks',
54
+ api_smoke: {
55
+ short: 'API smoke tests (REST/GraphQL health checks)',
56
+ beginner: 'Tests if your API is alive and responds correctly. Like checking if the server is up.',
57
+ example: 'Checks if GET /api/health returns 200 OK',
58
+ icon: '🔌',
59
+ },
60
+ ui: {
61
+ short: 'UI/E2E tests (browser automation)',
62
+ beginner: 'Tests your website in a real browser. Checks if pages load and buttons work.',
63
+ example: 'Opens your site and verifies the login form appears',
64
+ icon: '🌐',
65
+ },
66
+ a11y: {
67
+ short: 'Accessibility tests (WCAG compliance)',
68
+ beginner: 'Tests if your site is usable by people with disabilities (screen readers, color blindness).',
69
+ example: 'Checks if images have alt text for blind users',
70
+ icon: '♿',
71
+ },
72
+ perf: {
73
+ short: 'Performance tests (load/stress testing)',
74
+ beginner: 'Tests if your site stays fast when many people visit at once.',
75
+ example: 'Simulates 100 users visiting simultaneously',
76
+ icon: '⚡',
77
+ },
78
+ sast: {
79
+ short: 'Static security analysis (code scanning)',
80
+ beginner: 'Analyzes your source code for security vulnerabilities without running it.',
81
+ example: 'Finds hardcoded passwords or unsafe functions',
82
+ icon: '🔍',
83
+ },
84
+ dast: {
85
+ short: 'Dynamic security testing (runtime scanning)',
86
+ beginner: 'Attacks your running application to find security weaknesses.',
87
+ example: 'Tries common attacks like SQL injection',
88
+ icon: '⚔️',
89
+ },
90
+ secrets: {
91
+ short: 'Secrets detection (credential scanning)',
92
+ beginner: 'Scans for accidentally committed passwords, API keys, or tokens.',
93
+ example: 'Finds AWS keys in your code',
94
+ icon: '🔑',
95
+ },
96
+ deps: {
97
+ short: 'Dependency vulnerability checks',
98
+ beginner: 'Checks if your libraries have known security issues.',
99
+ example: 'Checks if you use an old version of a package with bugs',
100
+ icon: '📦',
101
+ },
56
102
  };
103
+ /**
104
+ * Beginner mode - Step by step guided experience
105
+ */
106
+ async function beginnerMode() {
107
+ console.log(chalk.bold.cyan('\n╔════════════════════════════════════════════════════════════╗'));
108
+ console.log(chalk.bold.cyan('║ 👋 Welcome to QA360 - Your Quality Assistant! ║'));
109
+ console.log(chalk.bold.cyan('║ ║'));
110
+ console.log(chalk.bold.cyan('║ Let\'s create your first test pack together, step by step. ║'));
111
+ console.log(chalk.bold.cyan('╚════════════════════════════════════════════════════════════╝\n'));
112
+ console.log(chalk.gray('📦 What is a "test pack"?'));
113
+ console.log(chalk.white(' A test pack defines WHAT to test (your API, website) and HOW (smoke tests, security scans).\n'));
114
+ // Step 1: Project name
115
+ console.log(chalk.bold('Step 1️⃣ - Project Name'));
116
+ console.log(chalk.gray(' Give your test pack a memorable name.\n'));
117
+ const { name } = await inquirer.prompt([
118
+ {
119
+ type: 'input',
120
+ name: 'name',
121
+ message: 'What should we call your test pack?',
122
+ default: 'my-first-tests',
123
+ validate: (input) => input.length > 0 || 'Name is required',
124
+ },
125
+ ]);
126
+ console.log(chalk.green(` ✓ Great! Your test pack is called "${name}"\n`));
127
+ // Step 2: What to test?
128
+ console.log(chalk.bold('Step 2️⃣ - What do you want to test?'));
129
+ console.log(chalk.gray(' Select the type of application you want to test.\n'));
130
+ const { appType } = await inquirer.prompt([
131
+ {
132
+ type: 'list',
133
+ name: 'appType',
134
+ message: 'What type of application are you testing?',
135
+ choices: [
136
+ { name: '🔌 API / Backend - REST or GraphQL API', value: 'api' },
137
+ { name: '🌐 Website / Frontend - Web application', value: 'web' },
138
+ { name: '🎯 Full Stack - Both API and Website', value: 'fullstack' },
139
+ { name: '🛡️ Security Scan - Check for vulnerabilities', value: 'security' },
140
+ { name: '✨ Everything - All tests enabled', value: 'complete' },
141
+ ],
142
+ },
143
+ ]);
144
+ console.log(chalk.green(` ✓ You chose: ${appType}\n`));
145
+ // Step 3: Gates explanation and selection
146
+ const suggestedGates = TEMPLATES[appType === 'complete' ? 'complete' : appType === 'fullstack' ? 'fullstack' : appType === 'api' ? 'api-basic' : appType === 'web' ? 'ui-basic' : 'security']?.gates || [];
147
+ console.log(chalk.bold('Step 3️⃣ - Quality Gates'));
148
+ console.log(chalk.gray(' Gates are different types of tests. We\'ll suggest some based on your choice.\n'));
149
+ console.log(chalk.cyan(' Suggested gates for you:\n'));
150
+ for (const gate of suggestedGates) {
151
+ const info = GATE_DESCRIPTIONS[gate];
152
+ console.log(chalk.cyan(` ${info?.icon} ${gate}`));
153
+ console.log(chalk.gray(` ${info?.beginner}`));
154
+ console.log(chalk.gray(` Example: ${info?.example}\n`));
155
+ }
156
+ const { useSuggested } = await inquirer.prompt([
157
+ {
158
+ type: 'confirm',
159
+ name: 'useSuggested',
160
+ message: 'Use the suggested gates?',
161
+ default: true,
162
+ },
163
+ ]);
164
+ let gates = suggestedGates;
165
+ if (!useSuggested) {
166
+ const { customGates } = await inquirer.prompt([
167
+ {
168
+ type: 'checkbox',
169
+ name: 'customGates',
170
+ message: 'Select the gates you want:',
171
+ choices: Object.entries(GATE_DESCRIPTIONS).map(([key, info]) => ({
172
+ name: `${info?.icon} ${key} - ${info?.short}`,
173
+ value: key,
174
+ })),
175
+ validate: (input) => input.length > 0 || 'Select at least one gate',
176
+ },
177
+ ]);
178
+ gates = customGates;
179
+ }
180
+ console.log(chalk.green(` ✓ Selected gates: ${gates.join(', ')}\n`));
181
+ // Step 4: URLs
182
+ console.log(chalk.bold('Step 4️⃣ - Application URLs'));
183
+ console.log(chalk.gray(' Where is your application running?\n'));
184
+ const targets = {};
185
+ if (gates.includes('api_smoke')) {
186
+ console.log(chalk.cyan(' 📡 API Configuration'));
187
+ const apiAnswers = await inquirer.prompt([
188
+ {
189
+ type: 'input',
190
+ name: 'apiUrl',
191
+ message: 'What is your API base URL?',
192
+ default: 'https://api.example.com',
193
+ validate: (input) => input.startsWith('http') || 'Must start with http:// or https://',
194
+ },
195
+ {
196
+ type: 'input',
197
+ name: 'smokeTests',
198
+ message: 'Which endpoints should we test? (format: "METHOD /path -> status")',
199
+ default: 'GET /health -> 200',
200
+ },
201
+ ]);
202
+ targets.api = {
203
+ baseUrl: apiAnswers.apiUrl,
204
+ smoke: [apiAnswers.smokeTests],
205
+ };
206
+ console.log(chalk.green(` ✓ API: ${apiAnswers.apiUrl}\n`));
207
+ }
208
+ if (gates.includes('ui') || gates.includes('a11y')) {
209
+ console.log(chalk.cyan(' 🌐 Website Configuration'));
210
+ const uiAnswers = await inquirer.prompt([
211
+ {
212
+ type: 'input',
213
+ name: 'webUrl',
214
+ message: 'What is your website URL?',
215
+ default: 'https://example.com',
216
+ validate: (input) => input.startsWith('http') || 'Must start with http:// or https://',
217
+ },
218
+ ]);
219
+ targets.web = {
220
+ baseUrl: uiAnswers.webUrl,
221
+ pages: [uiAnswers.webUrl],
222
+ };
223
+ console.log(chalk.green(` ✓ Website: ${uiAnswers.webUrl}\n`));
224
+ }
225
+ // Build pack
226
+ const pack = {
227
+ version: 1,
228
+ name,
229
+ gates: gates,
230
+ targets,
231
+ };
232
+ // Add budgets
233
+ if (gates.includes('perf') || gates.includes('a11y')) {
234
+ pack.budgets = {};
235
+ if (gates.includes('perf')) {
236
+ pack.budgets.perf_p95_ms = 2000;
237
+ }
238
+ if (gates.includes('a11y')) {
239
+ pack.budgets.a11y_min = 90;
240
+ }
241
+ }
242
+ // Add security config
243
+ if (gates.some((g) => ['sast', 'dast', 'secrets', 'deps'].includes(g))) {
244
+ pack.security = {};
245
+ if (gates.includes('sast')) {
246
+ pack.security.sast = { max_critical: 0, max_high: 3 };
247
+ }
248
+ if (gates.includes('dast')) {
249
+ pack.security.dast = { max_high: 5 };
250
+ }
251
+ }
252
+ // Final summary
253
+ console.log(chalk.bold.cyan('\n✨ Almost done! Here\'s your test pack summary:\n'));
254
+ console.log(chalk.white(` Name: ${chalk.bold(name)}`));
255
+ console.log(chalk.white(` Gates: ${gates.map(g => `${GATE_DESCRIPTIONS[g]?.icon} ${g}`).join(', ')}`));
256
+ console.log(chalk.white(` API: ${targets.api?.baseUrl || 'N/A'}`));
257
+ console.log(chalk.white(` Website: ${targets.web?.baseUrl || 'N/A'}`));
258
+ return pack;
259
+ }
57
260
  /**
58
261
  * Interactive prompts
59
262
  */
@@ -263,7 +466,11 @@ export async function initCommand(options = {}) {
263
466
  }
264
467
  // Generate pack config
265
468
  let pack;
266
- if (options.template) {
469
+ if (options.beginner) {
470
+ // Beginner guided mode
471
+ pack = await beginnerMode();
472
+ }
473
+ else if (options.template) {
267
474
  // Use template directly
268
475
  pack = generateFromTemplate(options.template);
269
476
  console.log(chalk.green(`✅ Using template: ${TEMPLATES[options.template]?.name || options.template}`));
@@ -0,0 +1,27 @@
1
+ /**
2
+ * CLI Commands for TUI and Dashboard monitoring
3
+ * Phase 8: Real-time test execution visualization
4
+ */
5
+ import { Command } from 'commander';
6
+ /**
7
+ * Monitor command - Run tests with TUI
8
+ */
9
+ export declare const monitorCommand: (pack: string | undefined, options: {
10
+ mode?: string;
11
+ retries?: string;
12
+ timeout?: string;
13
+ docker?: boolean;
14
+ }) => Promise<void>;
15
+ /**
16
+ * Dashboard command - Run tests with web dashboard
17
+ */
18
+ export declare const dashboardCommand: (pack: string | undefined, options: {
19
+ port?: string;
20
+ host?: string;
21
+ autoOpen?: boolean;
22
+ }) => Promise<void>;
23
+ /**
24
+ * Create monitor and dashboard commands
25
+ */
26
+ export declare function createMonitorCommands(): Command;
27
+ export declare function createDashboardCommand(): Command;
@@ -0,0 +1,225 @@
1
+ /**
2
+ * CLI Commands for TUI and Dashboard monitoring
3
+ * Phase 8: Real-time test execution visualization
4
+ */
5
+ import { Command } from 'commander';
6
+ import chalk from 'chalk';
7
+ import { TUIMonitor } from '../core/index.js';
8
+ import { DashboardServer, EvidenceVault } from '../core/index.js';
9
+ import { Phase3Runner } from '../core/index.js';
10
+ import { existsSync } from 'fs';
11
+ import { join } from 'path';
12
+ import { loadPackConfig } from '../utils/config.js';
13
+ /**
14
+ * Monitor command - Run tests with TUI
15
+ */
16
+ export const monitorCommand = async (pack, options) => {
17
+ const packPath = pack || findDefaultPack();
18
+ if (!packPath) {
19
+ console.error(chalk.red('Error: No pack file found. Specify a pack file or run qa360 init.'));
20
+ process.exit(1);
21
+ }
22
+ // Load pack config
23
+ const packConfig = await loadPackConfig(packPath);
24
+ const workingDir = process.cwd();
25
+ // Get gate names
26
+ const gateNames = getGateNames(packConfig);
27
+ // Create TUI monitor
28
+ const monitor = new TUIMonitor({
29
+ refreshRate: 500,
30
+ colors: true,
31
+ compact: false
32
+ });
33
+ monitor.start(gateNames.length);
34
+ try {
35
+ // Create runner with event emission
36
+ const runner = new Phase3Runner({
37
+ workingDir,
38
+ pack: packConfig
39
+ });
40
+ // Emit events to monitor
41
+ monitor.emit({
42
+ type: 'phase_start',
43
+ timestamp: Date.now(),
44
+ data: { phase: 'Initializing' }
45
+ });
46
+ // Run tests (simplified - in real implementation, Phase3Runner would emit events)
47
+ const result = await runner.run();
48
+ // Update monitor with results
49
+ for (const gate of result.gates) {
50
+ monitor.emit({
51
+ type: 'gate_start',
52
+ timestamp: Date.now(),
53
+ data: { gate: gate.gate }
54
+ });
55
+ monitor.emit({
56
+ type: 'gate_end',
57
+ timestamp: Date.now(),
58
+ data: {
59
+ gate: gate.gate,
60
+ success: gate.success,
61
+ results: {
62
+ total: gate.results?.summary?.total || 0,
63
+ passed: gate.results?.summary?.passed || 0,
64
+ failed: gate.results?.summary?.failed || 0
65
+ }
66
+ }
67
+ });
68
+ }
69
+ monitor.complete();
70
+ }
71
+ catch (error) {
72
+ monitor.emit({
73
+ type: 'error',
74
+ timestamp: Date.now(),
75
+ data: { error: error instanceof Error ? error.message : String(error) }
76
+ });
77
+ }
78
+ };
79
+ /**
80
+ * Dashboard command - Run tests with web dashboard
81
+ */
82
+ export const dashboardCommand = async (pack, options) => {
83
+ const packPath = pack || findDefaultPack();
84
+ if (!packPath) {
85
+ console.error(chalk.red('Error: No pack file found. Specify a pack file or run qa360 init.'));
86
+ process.exit(1);
87
+ }
88
+ const port = options.port ? parseInt(options.port) : 8080;
89
+ const host = options.host || '127.0.0.1';
90
+ const workingDir = process.cwd();
91
+ // Load pack config
92
+ const packConfig = await loadPackConfig(packPath);
93
+ const gateNames = getGateNames(packConfig);
94
+ // Open vault for flakiness data
95
+ const vaultPath = join(workingDir, '.qa360');
96
+ const vault = await EvidenceVault.open(vaultPath);
97
+ // Create dashboard server
98
+ const dashboard = new DashboardServer({
99
+ port,
100
+ host,
101
+ autoOpen: options.autoOpen ?? true,
102
+ refreshRate: 1000
103
+ });
104
+ // Connect vault to dashboard for flakiness data
105
+ dashboard.setVault(vault);
106
+ await dashboard.start();
107
+ dashboard.setGates(gateNames);
108
+ console.log(chalk.green('✓ Dashboard started'));
109
+ console.log(chalk.gray(` Open http://${host}:${port} in your browser`));
110
+ // Run tests with dashboard updates
111
+ try {
112
+ const runner = new Phase3Runner({
113
+ workingDir,
114
+ pack: packConfig
115
+ });
116
+ dashboard.emit({
117
+ type: 'start',
118
+ timestamp: Date.now(),
119
+ data: { phase: 'Running tests' }
120
+ });
121
+ const result = await runner.run();
122
+ // Set run ID for flakiness tracking
123
+ if (result.runId) {
124
+ dashboard.setRunId(result.runId);
125
+ }
126
+ // Update dashboard with gate results
127
+ for (const gate of result.gates) {
128
+ dashboard.emit({
129
+ type: 'gate_start',
130
+ timestamp: Date.now(),
131
+ data: { gate: gate.gate }
132
+ });
133
+ dashboard.emit({
134
+ type: 'gate_end',
135
+ timestamp: Date.now(),
136
+ data: {
137
+ gate: gate.gate,
138
+ success: gate.success,
139
+ duration: gate.duration,
140
+ results: {
141
+ total: gate.results?.summary?.total || 0,
142
+ passed: gate.results?.summary?.passed || 0,
143
+ failed: gate.results?.summary?.failed || 0
144
+ }
145
+ }
146
+ });
147
+ }
148
+ await dashboard.emit({
149
+ type: 'complete',
150
+ timestamp: Date.now(),
151
+ data: {}
152
+ });
153
+ console.log(chalk.green('✓ Tests completed. Dashboard will remain open.'));
154
+ console.log(chalk.gray('Press Ctrl+C to exit.'));
155
+ }
156
+ catch (error) {
157
+ await dashboard.emit({
158
+ type: 'error',
159
+ timestamp: Date.now(),
160
+ data: { error: error instanceof Error ? error.message : String(error) }
161
+ });
162
+ }
163
+ // Keep dashboard open until user exits
164
+ // Vault stays open for flakiness data access
165
+ try {
166
+ await keepAlive();
167
+ }
168
+ finally {
169
+ // Close vault when user exits
170
+ await vault.close();
171
+ await dashboard.stop();
172
+ }
173
+ };
174
+ /**
175
+ * Create monitor and dashboard commands
176
+ */
177
+ export function createMonitorCommands() {
178
+ const cmd = new Command('monitor');
179
+ cmd
180
+ .description('Run tests with terminal UI monitoring')
181
+ .argument('[pack]', 'Path to pack file')
182
+ .option('--mode <mode>', 'Execution mode: soft or strict', 'soft')
183
+ .option('--retries <number>', 'Number of retries for failed tests', '2')
184
+ .option('--timeout <ms>', 'Global timeout in milliseconds', '30000')
185
+ .option('--docker', 'Use Docker fallback for missing tools')
186
+ .action(monitorCommand);
187
+ return cmd;
188
+ }
189
+ export function createDashboardCommand() {
190
+ const cmd = new Command('dashboard');
191
+ cmd
192
+ .description('Run tests with web dashboard')
193
+ .argument('[pack]', 'Path to pack file')
194
+ .option('--port <number>', 'Dashboard port', '8080')
195
+ .option('--host <address>', 'Dashboard host', '127.0.0.1')
196
+ .option('--no-auto-open', 'Do not auto-open browser')
197
+ .action(dashboardCommand);
198
+ return cmd;
199
+ }
200
+ // Helper functions
201
+ function findDefaultPack() {
202
+ const candidates = ['qa360.yml', 'qa360.yaml', 'pack.yml', 'pack.yaml', '.qa360/pack.yml'];
203
+ for (const candidate of candidates) {
204
+ if (existsSync(join(process.cwd(), candidate))) {
205
+ return candidate;
206
+ }
207
+ }
208
+ return undefined;
209
+ }
210
+ function getGateNames(packConfig) {
211
+ if (packConfig.version === 2 && packConfig.gates) {
212
+ // v2: gates is an object
213
+ return Object.keys(packConfig.gates);
214
+ }
215
+ else if (packConfig.gates && Array.isArray(packConfig.gates)) {
216
+ // v1: gates is an array
217
+ return packConfig.gates;
218
+ }
219
+ return [];
220
+ }
221
+ async function keepAlive() {
222
+ return new Promise(() => {
223
+ // Keep process alive
224
+ });
225
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * QA360 Ollama Command
3
+ *
4
+ * Manage Ollama integration for AI-powered test generation.
5
+ * This command handles connection testing, model management, and configuration.
6
+ */
7
+ import { Command } from 'commander';
8
+ /**
9
+ * Test Ollama connection
10
+ */
11
+ export declare function ollamaTestCommand(options?: {
12
+ model?: string;
13
+ }): Promise<void>;
14
+ /**
15
+ * List available models
16
+ */
17
+ export declare function ollamaListCommand(): Promise<void>;
18
+ /**
19
+ * Pull a model
20
+ */
21
+ export declare function ollamaPullCommand(model: string): Promise<void>;
22
+ /**
23
+ * Generate tests using Ollama
24
+ */
25
+ export declare function ollamaGenerateCommand(prompt: string, options?: {
26
+ model?: string;
27
+ type?: string;
28
+ json?: boolean;
29
+ }): Promise<void>;
30
+ /**
31
+ * Show Ollama configuration
32
+ */
33
+ export declare function ollamaConfigCommand(options?: {
34
+ setUrl?: string;
35
+ setModel?: string;
36
+ }): Promise<void>;
37
+ /**
38
+ * Create Ollama commands
39
+ */
40
+ export declare function createOllamaCommands(): Command;