@ai-qa/workflow 2.0.11 → 2.0.14

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/ai-qa-workflow.js CHANGED
@@ -1,33 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { DIRS, ROOT, CONFIG, ensureDir, listUserStories, listTestPlans, listTestSpecs, timestamp, log, reloadConfig, autoDetectConfig } = require('./scripts/utils');
4
- const { generateTestPlan } = require('./scripts/planner');
5
- const { generateTestSpec } = require('./scripts/generator');
4
+ const context = require('./scripts/context-manager');
6
5
  const { executeTests } = require('./scripts/executor');
7
6
  const { selfHeal } = require('./scripts/healer');
8
7
  const { generateReport } = require('./scripts/reporter');
9
8
  const path = require('path');
10
9
  const fs = require('fs');
11
10
 
12
- const PROJECT_NAME = CONFIG.project.name;
13
-
14
11
  const COMMANDS = {
15
12
  init: { desc: 'Create required directories and config', fn: cmdInit },
16
- plan: { desc: '<user-story.md> Generate test plan from user story', fn: cmdPlan },
17
- generate:{ desc: '<test-plan.md> Generate test spec from test plan', fn: cmdGenerate },
13
+ plan: { desc: '(handled by AI agent see playwright-test-planner.agent.md)', fn: cmdPlan },
14
+ generate:{ desc: '(handled by AI agent — see playwright-test-generator.agent.md)', fn: cmdGenerate },
18
15
  execute: { desc: '[test-name] Run tests with Playwright', fn: cmdExecute },
19
- heal: { desc: '[run-id] Self-heal failed tests', fn: cmdHeal },
16
+ heal: { desc: '[run-id] Retry failed tests (AI handles deeper diagnosis)', fn: cmdHeal },
20
17
  report: { desc: '[run-id] Generate execution report', fn: cmdReport },
21
18
  'report:allure': { desc: '[run-id] Generate Allure report from test results', fn: cmdAllure },
22
- run: { desc: '<story-name.md> Full pipeline: plan → generate → execute → heal → report', fn: cmdRun },
23
19
  status: { desc: 'Show workflow state', fn: cmdStatus },
24
20
  list: { desc: 'List user stories, test plans, and test specs', fn: cmdList },
21
+ context: { desc: '[phase] [story] Mark a pipeline phase complete for a story', fn: cmdContext },
25
22
  };
26
23
 
27
24
  function cmdInit() {
28
25
  log('INIT', 'Creating required directories...');
29
26
  Object.values(DIRS).forEach(dir => ensureDir(dir));
30
27
 
28
+ const created = ['user-story', 'specs', 'tests', 'test-results', 'docs', '.qa-context', '.auth'];
29
+ log('INIT', `Directories: ${created.join(', ')}`);
30
+
31
31
  const configPath = path.join(ROOT, '.qa-workflow.json');
32
32
  if (!fs.existsSync(configPath)) {
33
33
  log('INIT', 'Scanning project to auto-detect configuration...');
@@ -65,36 +65,38 @@ function cmdInit() {
65
65
  log('INIT', 'docs/application-context.md created — AI agents will use this for context');
66
66
  }
67
67
 
68
- log('INIT', 'Ready. Directories: user-story/, specs/, tests/, test-results/, docs/');
69
- log('INIT', 'Edit .qa-workflow.json to override auto-detected values');
68
+ context.init();
69
+ log('INIT', '.qa-context/ initialized (pipeline.json, selectors.json, heal-history.json, traceability.json)');
70
+
71
+ const authGitignore = path.join(DIRS.auth, '.gitignore');
72
+ if (!fs.existsSync(authGitignore)) {
73
+ fs.writeFileSync(authGitignore, '# Auth credentials and Playwright storage state — never commit\n*\n', 'utf-8');
74
+ log('INIT', '.auth/ created (credentials.json, storage-state.json) — gitignored');
75
+ }
76
+
77
+ log('INIT', 'Ready. Edit .qa-workflow.json to override auto-detected values');
70
78
  }
71
79
 
72
80
  function cmdPlan() {
73
- const storyName = process.argv[3];
74
- if (!storyName) {
75
- console.log(' Usage: node ai-qa-workflow.js plan <user-story-file.md>');
76
- console.log(` Available: ${listUserStories().join(', ')}`);
77
- process.exit(1);
78
- }
79
- ensureDir(DIRS.specs);
80
- const result = generateTestPlan(storyName);
81
- console.log(`\n ✓ Test plan generated: specs/${path.basename(result.planPath)}`);
82
- console.log(`\n Next step: Review and edit the test plan, then run:`);
83
- console.log(` node ai-qa-workflow.js generate ${path.basename(result.planPath)}`);
81
+ console.log('');
82
+ console.log('╔══════════════════════════════════════════════════════════╗');
83
+ console.log(' PLANNING is handled by the AI agent ║');
84
+ console.log('║ ║');
85
+ console.log('║ Tell your AI agent: ║');
86
+ console.log('║ "Read router.md and plan tests for my-story.md" ║');
87
+ console.log('╚══════════════════════════════════════════════════════════╝');
88
+ console.log('');
84
89
  }
85
90
 
86
91
  function cmdGenerate() {
87
- const planName = process.argv[3];
88
- if (!planName) {
89
- console.log(' Usage: node ai-qa-workflow.js generate <test-plan-file.md>');
90
- console.log(` Available: ${listTestPlans().join(', ')}`);
91
- process.exit(1);
92
- }
93
- ensureDir(DIRS.tests);
94
- const result = generateTestSpec(planName);
95
- console.log(`\n ✓ Test spec generated: tests/${result.specName}.spec.ts`);
96
- console.log(`\n Next step: Implement test logic in the spec file, then run:`);
97
- console.log(` node ai-qa-workflow.js execute ${result.specName}`);
92
+ console.log('');
93
+ console.log('╔══════════════════════════════════════════════════════════╗');
94
+ console.log(' TEST GENERATION is handled by the AI agent ║');
95
+ console.log('║ ║');
96
+ console.log('║ Tell your AI agent: ║');
97
+ console.log('║ "Generate tests for the plan in specs/" ║');
98
+ console.log('╚══════════════════════════════════════════════════════════╝');
99
+ console.log('');
98
100
  }
99
101
 
100
102
  function cmdExecute() {
@@ -123,22 +125,18 @@ function cmdExecute() {
123
125
 
124
126
  function cmdHeal() {
125
127
  const runId = process.argv[3];
126
- const result = selfHeal(runId, PROJECT_NAME);
128
+ const result = selfHeal(runId);
127
129
 
128
- if (result.healed.length > 0) {
129
- console.log(`\n Healed: ${result.healed.length} test(s)`);
130
- result.healed.forEach(h => console.log(` - ${h.test || h.file} (${h.strategy})`));
130
+ if (result.rerun.length > 0) {
131
+ console.log(`\n Re-ran ${result.rerun.length} test(s) with longer timeout`);
131
132
  }
132
- if (result.remaining.length > 0) {
133
- console.log(`\n ✗ Still failing: ${result.remaining.length} test(s)`);
134
- result.remaining.forEach(ft => console.log(` - ${ft.test || ft.file}`));
133
+ if (result.stillFailing.length > 0) {
134
+ console.log(`\n ${result.stillFailing.length} test(s) still failing — AI agent should diagnose`);
135
+ console.log(` Tell your AI agent: "Debug the failing tests in test-results/"`);
135
136
  }
136
- if (result.healed.length === 0 && result.remaining.length === 0) {
137
- console.log('\n No failures to heal.');
137
+ if (result.rerun.length === 0 && result.stillFailing.length === 0) {
138
+ console.log('\n No failures to retry.');
138
139
  }
139
-
140
- console.log(`\n Next step: Generate report:`);
141
- console.log(` node ai-qa-workflow.js report ${result.reportPath ? path.basename(path.dirname(result.reportPath)) : runId || '(latest)'}`);
142
140
  }
143
141
 
144
142
  function cmdReport() {
@@ -187,60 +185,6 @@ function cmdAllure() {
187
185
  }
188
186
  }
189
187
 
190
- function cmdRun() {
191
- const storyName = process.argv[3];
192
- if (!storyName) {
193
- console.log(' Usage: node ai-qa-workflow.js run <user-story-file.md>');
194
- console.log(` Available: ${listUserStories().join(', ')}`);
195
- process.exit(1);
196
- }
197
-
198
- console.log('\n╔════════════════════════════════════════╗');
199
- console.log('║ AI QA WORKFLOW - FULL PIPELINE ║');
200
- console.log('╚════════════════════════════════════════╝\n');
201
-
202
- // Step 1: Plan
203
- log('RUN', 'Step 1/5: Generating test plan...');
204
- ensureDir(DIRS.specs);
205
- const plan = generateTestPlan(storyName);
206
- console.log(` → specs/${path.basename(plan.planPath)}\n`);
207
-
208
- // Step 2: Generate
209
- log('RUN', 'Step 2/5: Generating test spec...');
210
- ensureDir(DIRS.tests);
211
- const spec = generateTestSpec(path.basename(plan.planPath));
212
- console.log(` → tests/${spec.specName}.spec.ts\n`);
213
-
214
- // Step 3: Execute
215
- log('RUN', 'Step 3/5: Executing tests...');
216
- ensureDir(DIRS.testResults);
217
- const execResult = executeTests(spec.specName);
218
- console.log(` → ${execResult.success ? '✓ PASSED' : '✗ FAILED'} (${(execResult.duration / 1000).toFixed(1)}s)\n`);
219
-
220
- // Step 4: Heal (if needed)
221
- if (!execResult.success) {
222
- log('RUN', 'Step 4/5: Self-healing...');
223
- const healResult = selfHeal(execResult.runId, PROJECT_NAME);
224
- console.log(` → Healed: ${healResult.healed.length} | Remaining: ${healResult.remaining.length}\n`);
225
- } else {
226
- log('RUN', 'Step 4/5: Skipped (all tests passed)');
227
- console.log('');
228
- }
229
-
230
- // Step 5: Report
231
- log('RUN', 'Step 5/5: Generating report...');
232
- const report = generateReport(execResult.runId);
233
- console.log(` → ${report ? report.reportPath : 'N/A'}\n`);
234
-
235
- console.log('╔════════════════════════════════════════╗');
236
- console.log('║ WORKFLOW COMPLETE ║');
237
- console.log('╚════════════════════════════════════════╝');
238
- if (report) {
239
- console.log(`\n Report: test-results/${execResult.runId}/final-test-report.md`);
240
- console.log(` Passed: ${report.stats.passed} | Failed: ${report.stats.failed} | Healed: ${report.stats.healed}`);
241
- }
242
- }
243
-
244
188
  function cmdStatus() {
245
189
  console.log('\n📊 AI QA Workflow Status\n');
246
190
 
@@ -298,6 +242,35 @@ function cmdList() {
298
242
  console.log('');
299
243
  }
300
244
 
245
+ function cmdContext() {
246
+ const phase = process.argv[3];
247
+ const story = process.argv[4];
248
+
249
+ if (!phase || !story) {
250
+ console.log('\nUsage: node ai-qa-workflow.js context <phase> <story>');
251
+ console.log('Phases: plan, generate, execute, heal, report');
252
+ console.log('Example: node ai-qa-workflow.js context plan login\n');
253
+ process.exit(1);
254
+ }
255
+
256
+ const validPhases = ['plan', 'generate', 'execute', 'heal', 'report'];
257
+ if (!validPhases.includes(phase)) {
258
+ console.log(`\nInvalid phase: ${phase}`);
259
+ console.log(`Valid: ${validPhases.join(', ')}\n`);
260
+ process.exit(1);
261
+ }
262
+
263
+ context.phaseComplete(phase, story);
264
+ context.setCurrentStory(story);
265
+
266
+ const pipeline = context.getPipeline();
267
+ const storyData = pipeline.phases[phase];
268
+ const completed = storyData ? storyData.completed.join(', ') : '—';
269
+
270
+ console.log(`\n ✓ Phase "${phase}" marked complete for story "${story}"`);
271
+ console.log(` Completed for this phase: ${completed}\n`);
272
+ }
273
+
301
274
  const cmd = process.argv[2];
302
275
 
303
276
  if (!cmd || cmd === '--help' || cmd === '-h') {
@@ -307,14 +280,19 @@ if (!cmd || cmd === '--help' || cmd === '-h') {
307
280
  for (const [name, { desc }] of Object.entries(COMMANDS)) {
308
281
  console.log(` ${name.padEnd(12)} ${desc}`);
309
282
  }
310
- console.log('\nExamples:');
283
+ console.log('\nNote: Planning and test generation are done by the AI agent, not CLI commands.');
284
+ console.log('See: .github/agents/ and prompts/ for AI instructions.\n');
285
+ console.log('Examples:');
311
286
  console.log(' node ai-qa-workflow.js init');
312
- console.log(' node ai-qa-workflow.js plan US-EXPLORE-01.md');
313
- console.log(' node ai-qa-workflow.js generate us-explore-01-test-plan.md');
314
- console.log(' node ai-qa-workflow.js execute us-explore-01');
315
- console.log(' node ai-qa-workflow.js run US-EXPLORE-01.md');
287
+ console.log(' node ai-qa-workflow.js execute');
288
+ console.log(' node ai-qa-workflow.js execute my-feature');
289
+ console.log(' node ai-qa-workflow.js heal');
290
+ console.log(' node ai-qa-workflow.js heal run-2026-05-24');
291
+ console.log(' node ai-qa-workflow.js report');
316
292
  console.log(' node ai-qa-workflow.js report:allure');
317
- console.log(' node ai-qa-workflow.js status\n');
293
+ console.log(' node ai-qa-workflow.js status');
294
+ console.log(' node ai-qa-workflow.js list');
295
+ console.log(' node ai-qa-workflow.js context plan login\n');
318
296
  process.exit(0);
319
297
  }
320
298
 
package/install.js CHANGED
@@ -22,11 +22,8 @@ const USER_DIRS = new Set([
22
22
  'specs',
23
23
  'tests',
24
24
  'test-results',
25
-
26
-
27
-
28
-
29
-
25
+ '.qa-context',
26
+ '.auth',
30
27
  ]);
31
28
 
32
29
  // Template files to copy/update
@@ -39,14 +36,12 @@ const QA_ITEMS = [
39
36
  { src: '.opencode', dest: '.opencode', dir: true },
40
37
  { src: 'README.md', dest: 'README.md' },
41
38
  { src: 'PROJECT_GUIDE.md', dest: 'PROJECT_GUIDE.md' },
39
+ { src: 'prompting_template.md', dest: 'prompting_template.md' },
42
40
  { src: '.cursorrules', dest: '.cursorrules' },
43
41
  { src: '.geminirules', dest: '.geminirules' },
44
42
  { src: '.github/copilot-instructions.md', dest: '.github/copilot-instructions.md' },
45
43
  { src: 'router.md', dest: 'router.md' },
46
- { src: 'user-story', dest: 'user-story', dir: true },
47
- { src: 'specs', dest: 'specs', dir: true },
48
- { src: 'tests', dest: 'tests', dir: true },
49
- { src: '.opencode.json', dest: '.opencode.json' },
44
+ { src: 'opencode.json', dest: 'opencode.json' },
50
45
 
51
46
  ];
52
47
 
@@ -56,7 +51,7 @@ const UPDATE_ITEMS = QA_ITEMS.filter(item => {
56
51
  return !USER_FILES.has(item.dest);
57
52
  });
58
53
 
59
- const DIRS_TO_CREATE = ['user-story', 'specs', 'tests', 'test-results'];
54
+ const DIRS_TO_CREATE = ['user-story', 'specs', 'tests', 'test-results', '.qa-context', '.auth', 'templates'];
60
55
 
61
56
  const NPM_SCRIPTS = {
62
57
  'qa': 'node ai-qa-workflow.js',
@@ -65,9 +60,9 @@ const NPM_SCRIPTS = {
65
60
  'qa:generate': 'node ai-qa-workflow.js generate',
66
61
  'qa:execute': 'node ai-qa-workflow.js execute',
67
62
  'qa:heal': 'node ai-qa-workflow.js heal',
63
+ 'qa:retry': 'node ai-qa-workflow.js heal',
68
64
  'qa:report': 'node ai-qa-workflow.js report',
69
65
  'qa:report:allure': 'node ai-qa-workflow.js report:allure',
70
- 'qa:run': 'node ai-qa-workflow.js run',
71
66
  'qa:status': 'node ai-qa-workflow.js status',
72
67
  'qa:list': 'node ai-qa-workflow.js list',
73
68
  'dashboard': 'cd qa-dashboard && npm start',
@@ -239,8 +234,8 @@ async function install(targetPath, mode) {
239
234
  } else {
240
235
  console.log(` Files: ~${totalFiles} scripts + ${dashboardCount} dashboard files`);
241
236
  console.log(` Next:\n`);
242
- console.log(` npm run qa:init Initialize pipeline (auto-detect config)`);
243
- console.log(` npm run qa:run Run a user story through full pipeline`);
237
+ console.log(` npm run qa:init Initialize pipeline (config + dirs + auth)`);
238
+ console.log(` npm run qa:execute Run Playwright tests`);
244
239
  console.log(` npm run qa:status Check pipeline state`);
245
240
  console.log(` npm run dashboard Start dashboard (port 4000)\n`);
246
241
  }
package/opencode.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "mcp": {
4
+ "playwright": {
5
+ "type": "local",
6
+ "command": ["npx", "-y", "@playwright/mcp"],
7
+ "enabled": true,
8
+ "description": "Browser automation - navigate, click, type, screenshot. Required for test generation. Install: npm install -D @playwright/mcp"
9
+ },
10
+ "github": {
11
+ "type": "local",
12
+ "command": ["npx", "-y", "@modelcontextprotocol/server-github"],
13
+ "enabled": true,
14
+ "description": "GitHub integration - PRs, issues, commits. Requires GITHUB_TOKEN env var. Install: npm install -D @modelcontextprotocol/server-github"
15
+ },
16
+ "applitools-mcp": {
17
+ "type": "local",
18
+ "command": ["npx", "-y", "@applitools/mcp@latest"],
19
+ "enabled": true,
20
+ "description": "Visual testing - requires APPLITOOLS_API_KEY env var",
21
+ "env": {
22
+ "APPLITOOLS_API_KEY": "${APPLITOOLS_API_KEY}"
23
+ }
24
+ }
25
+ },
26
+ "agent": {
27
+ "qa-planner": {
28
+ "description": "Reads user story, explores website via Playwright MCP, creates test plan in specs/",
29
+ "mode": "subagent"
30
+ },
31
+ "qa-generator": {
32
+ "description": "Opens browser via MCP, captures real selectors, writes Playwright .spec.ts files from test plans",
33
+ "mode": "subagent"
34
+ },
35
+ "qa-healer": {
36
+ "description": "Debugs failing Playwright tests, fixes selectors/timing, classifies defects (2 attempts max)",
37
+ "mode": "subagent"
38
+ }
39
+ },
40
+ "default_agent": "general"
41
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ai-qa/workflow",
3
- "version": "2.0.11",
4
- "description": "One-command AI QA PipelineUser Story to Test Report. Auto-detects project config, generates Playwright tests, self-heals failures, dashboard UI.",
3
+ "version": "2.0.14",
4
+ "description": "AI QA Workflow Template transforms any AI agent into an autonomous QA engineer. AI explores, plans, generates tests, and heals. Scripts execute and report.",
5
5
  "keywords": [
6
6
  "qa",
7
7
  "testing",
@@ -16,20 +16,20 @@
16
16
  "prompts/",
17
17
  "scripts/",
18
18
  "qa-dashboard/",
19
- "user-story/",
20
- "specs/",
21
- "tests/",
22
19
  "test-results/",
23
20
  "docs/",
21
+ ".qa-context/",
24
22
  "templates/",
25
23
  "ai-qa-workflow.js",
26
24
  "cli.js",
27
25
  "install.js",
28
26
  "README.md",
29
27
  "PROJECT_GUIDE.md",
28
+ "prompting_template.md",
30
29
  ".cursorrules",
31
30
  ".geminirules",
32
31
  ".opencode/",
32
+ "opencode.json",
33
33
  ".qa-workflow.json",
34
34
  "router.md",
35
35
  ".github/"
@@ -50,9 +50,9 @@
50
50
  "qa:generate": "node ai-qa-workflow.js generate",
51
51
  "qa:execute": "node ai-qa-workflow.js execute",
52
52
  "qa:heal": "node ai-qa-workflow.js heal",
53
+ "qa:retry": "node ai-qa-workflow.js heal",
53
54
  "qa:report": "node ai-qa-workflow.js report",
54
55
  "qa:report:allure": "node ai-qa-workflow.js report:allure",
55
- "qa:run": "node ai-qa-workflow.js run",
56
56
  "qa:status": "node ai-qa-workflow.js status",
57
57
  "qa:list": "node ai-qa-workflow.js list",
58
58
  "dashboard": "cd qa-dashboard && npm start",