@roopesh.yadava/qa-pack 1.0.3
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 +79 -0
- package/bin/postinstall.js +151 -0
- package/claude/commands/bug-report.md +185 -0
- package/claude/commands/qa-agent.md +12 -0
- package/claude/commands/write-acceptance-criteria.md +167 -0
- package/claude/settings.json +13 -0
- package/claude/settings.local.json.example +19 -0
- package/claude/skills/SKILLS_CONTEXT.md +194 -0
- package/claude/skills/accessibility-testing/SKILL.md +317 -0
- package/claude/skills/accessibility-testing/WCAG_CHECKS.md +478 -0
- package/claude/skills/automation/BDD_TEMPLATES.md +237 -0
- package/claude/skills/automation/LOCATOR_PATTERNS.md +169 -0
- package/claude/skills/automation/SKILL.md +364 -0
- package/claude/skills/bug-reporting/SKILL.md +257 -0
- package/claude/skills/delete-files/SKILL.md +141 -0
- package/claude/skills/manual-testing/SKILL.md +493 -0
- package/claude/skills/qa-agent/SKILL.md +391 -0
- package/claude/skills/qa-agent/product_context/CONTEXT_SCHEMA.md +58 -0
- package/claude/skills/qa-agent/product_context/README.md +19 -0
- package/claude/skills/test-charter/SKILL.md +300 -0
- package/claude/skills/ui-test-figma/COMPARISON_PATTERNS.md +300 -0
- package/claude/skills/ui-test-figma/SKILL.md +234 -0
- package/package.json +29 -0
- package/templates/CLAUDE.md +41 -0
- package/templates/cucumber.cjs +7 -0
- package/templates/mcp.json +18 -0
- package/templates/settings.local.json.example +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @roopesh.yadava/qa-pack
|
|
2
|
+
|
|
3
|
+
AI-powered QA agent skills for Claude Code. Drop into any product repo — get manual testing, BDD automation, accessibility audits, UI/Figma diff, bug filing, and test charters all triggered by plain English.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# One-time .npmrc line needed because of the CodeArtifact default registry on 7Edge machines
|
|
9
|
+
echo "@roopesh.yadava:registry=https://registry.npmjs.org" >> .npmrc
|
|
10
|
+
npm install --save-dev @roopesh.yadava/qa-pack
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
On install, the postinstall script copies all skills and commands into `.claude/` and creates one-time config files (`CLAUDE.md`, `.mcp.json`, `cucumber.cjs`) if they don't already exist. It also writes the `.npmrc` scope entry above automatically, so `npm update` works with no extra steps after the first install.
|
|
14
|
+
|
|
15
|
+
## Update
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm update @roopesh.yadava/qa-pack
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Skill files are overwritten with the latest version. Your `CLAUDE.md`, `.mcp.json`, and — critically — `product_context/` (your accumulated run history and known bugs) are **never touched**.
|
|
22
|
+
|
|
23
|
+
## First-time setup
|
|
24
|
+
|
|
25
|
+
After installing, open `CLAUDE.md` at your repo root and fill in:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Jira Project Key: PROJ
|
|
29
|
+
App URL: https://your-app.example.com
|
|
30
|
+
Auth Method: form_login | SSO | token | none
|
|
31
|
+
OTP Required: yes (always 999999) | no
|
|
32
|
+
Username / Password: your test credentials
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then open the repo in Claude Code and run:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
run qa PROJ-123
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Triggers
|
|
42
|
+
|
|
43
|
+
| Say this | What happens |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `run qa PROJ-123` | Full QA — manual or automation branch |
|
|
46
|
+
| `manual test PROJ-123` | Playwright manual testing + bug filing |
|
|
47
|
+
| `automate PROJ-123` | Gherkin + step defs + POM |
|
|
48
|
+
| `accessibility test PROJ-123` | WCAG 2.1 A/AA audit |
|
|
49
|
+
| `ui test PROJ-123` | Live app vs Figma design diff |
|
|
50
|
+
| `file a bug` | Files bug directly to Jira |
|
|
51
|
+
| `/write-acceptance-criteria PROJ-123` | Generates AC, appends to Jira card |
|
|
52
|
+
|
|
53
|
+
## What postinstall does
|
|
54
|
+
|
|
55
|
+
| File | Behaviour |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `.claude/skills/*/SKILL.md` + companion `.md` files | Always overwritten (versioned logic) |
|
|
58
|
+
| `.claude/commands/*.md` | Always overwritten |
|
|
59
|
+
| `.claude/skills/qa-agent/product_context/**` | **Never touched** after first seed |
|
|
60
|
+
| `.claude/settings.json` | Created once, never overwritten |
|
|
61
|
+
| `CLAUDE.md`, `.mcp.json`, `cucumber.cjs` | Created once, never overwritten |
|
|
62
|
+
| `.claude/settings.local.json` | Created once from example |
|
|
63
|
+
| `.claude/settings.local.json.example` | Always refreshed (shows latest options) |
|
|
64
|
+
| `.gitignore` | `outputs/` and `settings.local.json` appended if missing |
|
|
65
|
+
|
|
66
|
+
## Publishing (maintainers)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# In qa-pack/ repo, bump version and push
|
|
70
|
+
npm version patch # or minor / major
|
|
71
|
+
git add . && git commit -m "your message" && git push origin main
|
|
72
|
+
# GitHub Actions publishes to npmjs automatically
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Claude Code CLI
|
|
78
|
+
- Node.js 18+
|
|
79
|
+
- Atlassian MCP connected in Claude Code (for Jira)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const PACK_DIR = path.join(__dirname, '..');
|
|
8
|
+
const PROJECT_ROOT = process.env.INIT_CWD || process.cwd();
|
|
9
|
+
|
|
10
|
+
// Don't run when working on the package itself
|
|
11
|
+
if (PROJECT_ROOT === PACK_DIR) {
|
|
12
|
+
console.log('@roopesh.yadava/qa-pack: skipping postinstall (running inside package directory)');
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const log = { added: [], updated: [], skipped: [], protected: [] };
|
|
17
|
+
|
|
18
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
function ensureDir(dir) {
|
|
21
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function copyFile(src, dest, { overwrite = true } = {}) {
|
|
25
|
+
ensureDir(path.dirname(dest));
|
|
26
|
+
const rel = path.relative(PROJECT_ROOT, dest);
|
|
27
|
+
if (!overwrite && fs.existsSync(dest)) {
|
|
28
|
+
log.skipped.push(rel);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const isNew = !fs.existsSync(dest);
|
|
32
|
+
fs.copyFileSync(src, dest);
|
|
33
|
+
isNew ? log.added.push(rel) : log.updated.push(rel);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Copy a directory recursively with per-file overwrite control
|
|
37
|
+
function copyDir(src, dest, shouldOverwrite) {
|
|
38
|
+
ensureDir(dest);
|
|
39
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const destPath = path.join(dest, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
copyDir(srcPath, destPath, shouldOverwrite);
|
|
44
|
+
} else {
|
|
45
|
+
copyFile(srcPath, destPath, { overwrite: shouldOverwrite(srcPath) });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ── 1. Skills — always overwrite (these are the versioned logic files) ────────
|
|
51
|
+
// Exception: product_context/ contents are user data — seed only, never overwrite
|
|
52
|
+
const skillsSrc = path.join(PACK_DIR, 'claude', 'skills');
|
|
53
|
+
const skillsDest = path.join(PROJECT_ROOT, '.claude', 'skills');
|
|
54
|
+
|
|
55
|
+
copyDir(skillsSrc, skillsDest, (srcPath) => {
|
|
56
|
+
const rel = path.relative(skillsSrc, srcPath);
|
|
57
|
+
// product_context/README.md and CONTEXT_SCHEMA.md are templates — seed only
|
|
58
|
+
if (rel.startsWith(path.join('qa-agent', 'product_context'))) {
|
|
59
|
+
const destPath = path.join(skillsDest, rel);
|
|
60
|
+
if (fs.existsSync(destPath)) {
|
|
61
|
+
log.protected.push(path.join('.claude', 'skills', rel));
|
|
62
|
+
return false; // never overwrite
|
|
63
|
+
}
|
|
64
|
+
return true; // seed on first install
|
|
65
|
+
}
|
|
66
|
+
return true; // all other skill files: always update
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ── 2. Commands — always overwrite ────────────────────────────────────────────
|
|
70
|
+
const commandsSrc = path.join(PACK_DIR, 'claude', 'commands');
|
|
71
|
+
const commandsDest = path.join(PROJECT_ROOT, '.claude', 'commands');
|
|
72
|
+
copyDir(commandsSrc, commandsDest, () => true);
|
|
73
|
+
|
|
74
|
+
// ── 3. settings.json — create only if missing ─────────────────────────────────
|
|
75
|
+
copyFile(
|
|
76
|
+
path.join(PACK_DIR, 'claude', 'settings.json'),
|
|
77
|
+
path.join(PROJECT_ROOT, '.claude', 'settings.json'),
|
|
78
|
+
{ overwrite: false }
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// ── 4. settings.local.json — create from example only if missing ──────────────
|
|
82
|
+
const localSettingsDest = path.join(PROJECT_ROOT, '.claude', 'settings.local.json');
|
|
83
|
+
if (!fs.existsSync(localSettingsDest)) {
|
|
84
|
+
copyFile(
|
|
85
|
+
path.join(PACK_DIR, 'templates', 'settings.local.json.example'),
|
|
86
|
+
localSettingsDest,
|
|
87
|
+
{ overwrite: false }
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
// Always refresh the .example so teams can see what's new
|
|
91
|
+
copyFile(
|
|
92
|
+
path.join(PACK_DIR, 'templates', 'settings.local.json.example'),
|
|
93
|
+
path.join(PROJECT_ROOT, '.claude', 'settings.local.json.example'),
|
|
94
|
+
{ overwrite: true }
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// ── 5. One-time templates (never overwrite — user fills these in) ─────────────
|
|
98
|
+
const templates = [
|
|
99
|
+
['templates/CLAUDE.md', 'CLAUDE.md'],
|
|
100
|
+
['templates/mcp.json', '.mcp.json'],
|
|
101
|
+
['templates/cucumber.cjs', 'cucumber.cjs'],
|
|
102
|
+
];
|
|
103
|
+
for (const [src, dest] of templates) {
|
|
104
|
+
copyFile(
|
|
105
|
+
path.join(PACK_DIR, src),
|
|
106
|
+
path.join(PROJECT_ROOT, dest),
|
|
107
|
+
{ overwrite: false }
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── 6. .npmrc — ensure scope points to the public npm registry (needed for npm update) ──
|
|
112
|
+
const npmrcPath = path.join(PROJECT_ROOT, '.npmrc');
|
|
113
|
+
const npmrcEntry = '@roopesh.yadava:registry=https://registry.npmjs.org';
|
|
114
|
+
if (fs.existsSync(npmrcPath)) {
|
|
115
|
+
const content = fs.readFileSync(npmrcPath, 'utf8');
|
|
116
|
+
if (!content.includes(npmrcEntry)) {
|
|
117
|
+
fs.appendFileSync(npmrcPath, `\n${npmrcEntry}\n`);
|
|
118
|
+
log.updated.push('.npmrc');
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
fs.writeFileSync(npmrcPath, `${npmrcEntry}\n`);
|
|
122
|
+
log.added.push('.npmrc');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── 7. .gitignore — ensure outputs/ and settings.local.json are ignored ───────
|
|
126
|
+
const gitignorePath = path.join(PROJECT_ROOT, '.gitignore');
|
|
127
|
+
const gitignoreEntries = ['outputs/', '.claude/settings.local.json'];
|
|
128
|
+
if (fs.existsSync(gitignorePath)) {
|
|
129
|
+
let content = fs.readFileSync(gitignorePath, 'utf8');
|
|
130
|
+
const toAdd = gitignoreEntries.filter(e => !content.includes(e));
|
|
131
|
+
if (toAdd.length) {
|
|
132
|
+
content += `\n# qa-pack\n${toAdd.join('\n')}\n`;
|
|
133
|
+
fs.writeFileSync(gitignorePath, content);
|
|
134
|
+
log.updated.push('.gitignore');
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
fs.writeFileSync(gitignorePath, `# qa-pack\n${gitignoreEntries.join('\n')}\n`);
|
|
138
|
+
log.added.push('.gitignore');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── Summary ───────────────────────────────────────────────────────────────────
|
|
142
|
+
console.log('\n@roopesh.yadava/qa-pack installed\n');
|
|
143
|
+
if (log.added.length) console.log(' Created :', log.added.join(', '));
|
|
144
|
+
if (log.updated.length) console.log(' Updated :', log.updated.join(', '));
|
|
145
|
+
if (log.skipped.length) console.log(' Skipped :', log.skipped.join(', '));
|
|
146
|
+
if (log.protected.length) console.log(' Protected:', log.protected.join(', '), '(product context — never overwritten)');
|
|
147
|
+
|
|
148
|
+
if (log.added.includes('CLAUDE.md')) {
|
|
149
|
+
console.log('\n Next: open CLAUDE.md and fill in your Jira project key, app URL, and credentials.');
|
|
150
|
+
}
|
|
151
|
+
console.log('');
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
You are a Jira bug reporting assistant. Follow these steps precisely and in order.
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Step 1 — Select a project
|
|
6
|
+
|
|
7
|
+
Use the Atlassian MCP tool (`getVisibleJiraProjects`) to fetch all visible projects immediately — do not wait for user input.
|
|
8
|
+
|
|
9
|
+
Display the list and ask:
|
|
10
|
+
"Which board are you working on? You can reply with the number or the board key:
|
|
11
|
+
1. [KEY] — [Project Name]
|
|
12
|
+
2. [KEY] — [Project Name]
|
|
13
|
+
..."
|
|
14
|
+
|
|
15
|
+
Wait for the user to select a project by number or board key. Save the selected project key for the rest of the flow.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Step 1A/1B — Ask card type
|
|
20
|
+
|
|
21
|
+
Ask the user:
|
|
22
|
+
"Is this an **Exploratory Bug** (create a new card) or an **Existing Card** (add bugs to an existing one)?"
|
|
23
|
+
|
|
24
|
+
Wait for the user's choice before proceeding.
|
|
25
|
+
|
|
26
|
+
- If the user chooses **Exploratory Bug** → go to Step 1A
|
|
27
|
+
- If the user chooses **Existing Card** → go to Step 1B
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Step 1A — Create a new Exploratory Bug card
|
|
32
|
+
|
|
33
|
+
Ask the user: "Please enter a name for the Exploratory Bug card."
|
|
34
|
+
|
|
35
|
+
Wait for the user's input.
|
|
36
|
+
|
|
37
|
+
Use the Atlassian MCP tool (`createJiraIssue`) to create a new Jira issue in the selected project with:
|
|
38
|
+
- **Issue Type:** Bug
|
|
39
|
+
- **Summary:** [Card name entered by the user]
|
|
40
|
+
- **Labels:** Exploratory
|
|
41
|
+
|
|
42
|
+
After creating the issue, use `getTransitionsForJiraIssue` to fetch available transitions, then use `transitionJiraIssue` to move the card to **Backlog** status.
|
|
43
|
+
|
|
44
|
+
Once created and moved to Backlog, display:
|
|
45
|
+
|
|
46
|
+
> **Exploratory Bug card created:** [CARD-NUMBER] — [Card Name]
|
|
47
|
+
> [Link to card]
|
|
48
|
+
|
|
49
|
+
Save this card number as the active card for the rest of the flow. Then proceed to Step 2.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Step 1B — Use an existing card
|
|
54
|
+
|
|
55
|
+
Ask the user: "Please enter the card number (e.g. 123 or [KEY]-123) to attach this bug report to."
|
|
56
|
+
|
|
57
|
+
Wait for the user's input.
|
|
58
|
+
|
|
59
|
+
If the user enters only a number (e.g. `2446`), construct the full card number using the selected project key (e.g. QE-2446).
|
|
60
|
+
|
|
61
|
+
Use the Atlassian MCP tool (`getJiraIssue`) to fetch the card details. Display:
|
|
62
|
+
|
|
63
|
+
> **Card found:** [CARD-NUMBER] — [Card Summary/Title]
|
|
64
|
+
|
|
65
|
+
If the fetched card's issue type is **Bug**, ask:
|
|
66
|
+
"Do you want to add the bugs to the **Description** or as a **Comment**?"
|
|
67
|
+
|
|
68
|
+
Wait for the user's choice and save it as the **save mode** (Description or Comment) for use in Step 6.
|
|
69
|
+
|
|
70
|
+
Save this card number as the active card for the rest of the flow. Then proceed to Step 2.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Step 2 — Collect bug details
|
|
75
|
+
|
|
76
|
+
Ask the user: "Please describe the bug."
|
|
77
|
+
|
|
78
|
+
Wait for the user's input. Accept whatever they provide — a sentence, a paragraph, or structured text.
|
|
79
|
+
|
|
80
|
+
From the input, infer and derive all necessary fields:
|
|
81
|
+
- **Bug Title** — extract or summarise from what was given
|
|
82
|
+
- **Expected Outcome** — infer from context if not explicitly stated
|
|
83
|
+
- **Actual Outcome** — extract the described problem
|
|
84
|
+
- **Steps to Reproduce** — extract or derive from the description
|
|
85
|
+
|
|
86
|
+
Do NOT ask the user for any missing fields. Use what was given and proceed.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 3 — Display the formatted bug report
|
|
91
|
+
|
|
92
|
+
Show the bug report in this exact format before posting:
|
|
93
|
+
|
|
94
|
+
### Bug No. [n]: [Bug Title]
|
|
95
|
+
|
|
96
|
+
### Expected Outcome:
|
|
97
|
+
[Expected Outcome]
|
|
98
|
+
|
|
99
|
+
### Actual Outcome:
|
|
100
|
+
[Actual Outcome]
|
|
101
|
+
|
|
102
|
+
### Steps to Reproduce:
|
|
103
|
+
[Steps]
|
|
104
|
+
|
|
105
|
+
After showing the report, ask:
|
|
106
|
+
"Is this the only bug, or do you have another bug to add?"
|
|
107
|
+
|
|
108
|
+
- If the user says **yes (another bug)** — go back to Step 2 and collect the next bug. Append it to the report using the same format with an incremented Bug No. Repeat until the user says no more bugs.
|
|
109
|
+
- If the user says **no more bugs** — proceed to Step 4.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Step 4 — Ask who to mention
|
|
114
|
+
|
|
115
|
+
Before posting, ask:
|
|
116
|
+
"Who should I notify about this bug? Please enter the person's name, or type **none** to skip."
|
|
117
|
+
|
|
118
|
+
Wait for the user's input.
|
|
119
|
+
|
|
120
|
+
- If the user types **none** (or says no one / skip) → set mention as empty, skip Step 5, and proceed directly to Step 6. Do NOT add any mention or "Please check this" line in the report.
|
|
121
|
+
- Otherwise → proceed to Step 5.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Step 5 — Search for the person in Jira
|
|
126
|
+
|
|
127
|
+
Use the Atlassian MCP tool (`lookupJiraAccountId`) to search for the name the user entered.
|
|
128
|
+
|
|
129
|
+
If multiple results are found, list them and ask:
|
|
130
|
+
"Is this the right person? [Name — Account ID]"
|
|
131
|
+
|
|
132
|
+
If only one result is found, display that person's name and ask:
|
|
133
|
+
"Found: [Full Name]. Is this the right person? (yes / no)"
|
|
134
|
+
|
|
135
|
+
Wait for confirmation before proceeding.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Step 6 — Save the bug report to Jira
|
|
140
|
+
|
|
141
|
+
### If the card is an Exploratory Bug (created in Step 1A):
|
|
142
|
+
|
|
143
|
+
Use the Atlassian MCP tool (`editJiraIssue`) to update the **Description** field of the card with the full bug report AND the mention at the end.
|
|
144
|
+
|
|
145
|
+
The description body must follow this structure:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
h3. Bug No. [n]: [Bug Title]
|
|
149
|
+
|
|
150
|
+
h3. Expected Outcome:
|
|
151
|
+
[Expected Outcome]
|
|
152
|
+
|
|
153
|
+
h3. Actual Outcome:
|
|
154
|
+
[Actual Outcome]
|
|
155
|
+
|
|
156
|
+
h3. Steps to Reproduce:
|
|
157
|
+
[Steps]
|
|
158
|
+
|
|
159
|
+
(repeat the above block for each additional bug if more than one was collected)
|
|
160
|
+
|
|
161
|
+
(only include the line below if a person was confirmed in Step 5 — omit it entirely if the user chose none)
|
|
162
|
+
@[confirmed person's display name], Please check.
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Do NOT post a comment. Write everything into the Description field of the card.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### If the card is an Existing Card (from Step 1B):
|
|
170
|
+
|
|
171
|
+
- If the user chose **Description** → use `editJiraIssue` to update the Description field with the full bug report and mention. Do NOT post a comment.
|
|
172
|
+
- If the user chose **Comment** → use `addCommentToJiraIssue` to post one single comment with the full bug report and mention. Do NOT post a second separate comment.
|
|
173
|
+
|
|
174
|
+
In both cases the content structure is the same as above.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Step 7 — Confirm completion
|
|
179
|
+
|
|
180
|
+
Show a summary:
|
|
181
|
+
- Jira card: [Card number with link]
|
|
182
|
+
- Bug report posted: ✓
|
|
183
|
+
- Notified: [Confirmed person's name]
|
|
184
|
+
|
|
185
|
+
Done.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qa-agent
|
|
3
|
+
description: Launch the QA Agent — presents the skill menu and dispatches to the right skill based on your input.
|
|
4
|
+
argument-hint: "[Jira card ID | 'full QA' | skill name | plain description]"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Invoke the `qa-agent` skill.
|
|
9
|
+
|
|
10
|
+
If the user provided an argument (e.g. a Jira card ID or the phrase "full QA for PROJ-123"),
|
|
11
|
+
pass it directly into the skill as the initial intent so the agent does not re-ask for input
|
|
12
|
+
it has already received.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-acceptance-criteria
|
|
3
|
+
description: >
|
|
4
|
+
Generates structured acceptance criteria for a feature or user story,
|
|
5
|
+
covering happy paths, unhappy paths, and edge cases in a clear,
|
|
6
|
+
testable format suitable for development and QA handoff. If given a
|
|
7
|
+
Jira card ID (e.g. FF-420), fetches the card automatically and appends
|
|
8
|
+
the acceptance criteria to the bottom of the issue description without
|
|
9
|
+
overwriting any existing content.
|
|
10
|
+
argument-hint: "<Jira card ID or feature description>"
|
|
11
|
+
user-invocable: true
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Core Workflow
|
|
15
|
+
|
|
16
|
+
0. **Detect Jira card ID** — If the argument matches the pattern `[A-Z]+-[0-9]+` (e.g. `FF-420`, `AA-12`),
|
|
17
|
+
fetch the issue using the `getJiraIssue` tool with cloudId `853e134e-6574-491a-a075-1b06f7d4b478`.
|
|
18
|
+
Use the issue summary and description as the feature input for the next steps.
|
|
19
|
+
If the issue has no description, use the summary only and note this in the Assumptions section.
|
|
20
|
+
If the argument is not a Jira card ID, treat it as a raw feature description and skip to step 1.
|
|
21
|
+
|
|
22
|
+
1. **Parse the feature** — Read the feature description or user story provided by the user
|
|
23
|
+
|
|
24
|
+
2. **Identify actors and goals** — Determine who is doing what and what success looks like
|
|
25
|
+
|
|
26
|
+
3. **Derive all scenarios** — Map out standard flows, variations, error states, and edge cases
|
|
27
|
+
|
|
28
|
+
4. **Write acceptance criteria** — Follow the output format exactly
|
|
29
|
+
|
|
30
|
+
5. **Flag assumptions** — Note anything inferred that the user should confirm
|
|
31
|
+
|
|
32
|
+
6. **Append to Jira description** — If the input was a Jira card ID:
|
|
33
|
+
- Fetch the current description of the issue using `getJiraIssue`
|
|
34
|
+
- Preserve the full existing description exactly as-is (do NOT remove or overwrite any content, including COS or any other existing sections)
|
|
35
|
+
- Append the generated acceptance criteria at the very bottom of the existing description, separated by a divider line (`---`)
|
|
36
|
+
- Update the issue description using `editJiraIssue` with cloudId `853e134e-6574-491a-a075-1b06f7d4b478`
|
|
37
|
+
- After updating, confirm to the user with the Jira issue URL: `https://7edge.atlassian.net/browse/<CARD-ID>`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Output Format
|
|
42
|
+
|
|
43
|
+
Always produce output in exactly this structure, in this order.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
### Acceptance Criteria
|
|
48
|
+
|
|
49
|
+
### Happy Paths
|
|
50
|
+
|
|
51
|
+
Numbered list of standard, successful user flows. Each step is one clear action or system response. Steps must be sequential and realistic.
|
|
52
|
+
|
|
53
|
+
1. Step one
|
|
54
|
+
2. Step two
|
|
55
|
+
3. ...
|
|
56
|
+
|
|
57
|
+
Include one or more complete flows if the feature has multiple valid entry points or user types.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### Unhappy Paths
|
|
62
|
+
|
|
63
|
+
Numbered list of failure scenarios, edge cases, and error conditions. Be specific — name the actual error, input, or state, not a generic category.
|
|
64
|
+
|
|
65
|
+
Include:
|
|
66
|
+
- Validation failures (missing fields, invalid formats, out-of-range values)
|
|
67
|
+
- System errors (timeouts, service unavailability, unexpected states)
|
|
68
|
+
- User errors (wrong order of actions, duplicate submissions, unauthorised access)
|
|
69
|
+
- Edge cases (empty states, maximum limits, concurrent actions)
|
|
70
|
+
- Missing or misleading feedback (no confirmation, silent failure, confusing error messages)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Writing Guidelines
|
|
75
|
+
|
|
76
|
+
- **Acceptance criteria must be testable.** Every `Then` clause must be answerable with pass/fail by a QA engineer.
|
|
77
|
+
- **Happy paths = the expected, successful flow.** Write them as a user would experience them, step by step.
|
|
78
|
+
- **Unhappy paths = everything that can go wrong.** Be exhaustive and specific. "User enters invalid email" is better than "validation fails."
|
|
79
|
+
- **Avoid implementation language.** Write what happens, not how the system achieves it.
|
|
80
|
+
- **One action per step.** Don't bundle two user actions into one step.
|
|
81
|
+
- **Tone:** Neutral, precise, present tense. No filler.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Handling Incomplete Input
|
|
86
|
+
|
|
87
|
+
If the feature description is vague:
|
|
88
|
+
- Infer the most common interpretation based on domain patterns
|
|
89
|
+
- Write complete output using those inferences
|
|
90
|
+
- Add a short **Assumptions** section at the end listing what was inferred
|
|
91
|
+
- Only ask for clarification if the description is too ambiguous to produce any meaningful output
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Example
|
|
96
|
+
|
|
97
|
+
**Input:** "Add email notifications when a report is exported"
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Acceptance Criteria
|
|
102
|
+
|
|
103
|
+
### Happy Paths
|
|
104
|
+
|
|
105
|
+
1. User navigates to the Reports section and selects a report to export
|
|
106
|
+
2. User clicks "Export" and selects the desired format (e.g., CSV, PDF)
|
|
107
|
+
3. System queues the export job and displays a confirmation message: "Your export is being processed. You'll receive an email when it's ready."
|
|
108
|
+
4. Export job completes; system sends an email to the user's registered address
|
|
109
|
+
5. Email arrives with subject line, report name, and a clearly labelled download button
|
|
110
|
+
6. User clicks the download link; file downloads immediately in the selected format
|
|
111
|
+
7. Link remains active for 24 hours from time of export completion
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### Unhappy Paths
|
|
116
|
+
|
|
117
|
+
1. User triggers an export but has no verified email address on file — system blocks the action and prompts the user to add and verify an email before exporting
|
|
118
|
+
2. Export job fails due to a data processing error — user receives a failure email with a human-readable reason (not a raw error code) and a "Try Again" link
|
|
119
|
+
3. User clicks the download link after it has expired (>24 hours) — page displays: "This link has expired. Return to Reports to export again." with a direct link back
|
|
120
|
+
4. User clicks the download link but the file has been deleted from storage — system returns a 404 page with a clear message and re-export option, not a generic browser error
|
|
121
|
+
5. Email delivery fails (e.g., inbox full, domain rejected) — system retries up to 3 times over 10 minutes; if all retries fail, the failure is logged and flagged in the admin panel
|
|
122
|
+
6. User triggers the same export twice in quick succession — system deduplicates and sends only one email; no duplicate files are created
|
|
123
|
+
7. User has disabled email notifications in their profile settings — system respects the preference and does not send the email; the export still completes and is accessible via the Reports page
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
*Assumed: web-based product with a registered user model and a transactional email provider already in place. Adjust if this is a mobile or API-only context.*
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
<!-- Created by Roopesh Yadava
|
|
132
|
+
|
|
133
|
+
Generate detailed documentation for the feature: {{feature_description}}
|
|
134
|
+
|
|
135
|
+
Follow these steps:
|
|
136
|
+
|
|
137
|
+
1. **Identify scenarios** — Analyze the feature description and derive all possible user flows, including standard usage and edge cases.
|
|
138
|
+
|
|
139
|
+
2. **Understand expected behavior** — Determine:
|
|
140
|
+
|
|
141
|
+
* What the user is trying to achieve
|
|
142
|
+
* System responses for valid and invalid inputs
|
|
143
|
+
* Possible failure points or UX gaps
|
|
144
|
+
|
|
145
|
+
3. **Generate output** with the following structure:
|
|
146
|
+
|
|
147
|
+
## Acceptance Criteria
|
|
148
|
+
|
|
149
|
+
(Leave this section empty — do not list or rewrite anything here.)
|
|
150
|
+
|
|
151
|
+
## Happy Paths
|
|
152
|
+
|
|
153
|
+
* List all happy paths using numbered bullets.
|
|
154
|
+
* Each step should describe one clear user action or system result.
|
|
155
|
+
* Keep steps concise, realistic, and sequential.
|
|
156
|
+
|
|
157
|
+
## Unhappy Paths
|
|
158
|
+
|
|
159
|
+
* List all unhappy paths using numbered bullets.
|
|
160
|
+
* Include:
|
|
161
|
+
|
|
162
|
+
* User errors
|
|
163
|
+
* Validation failures
|
|
164
|
+
* System issues
|
|
165
|
+
* Edge cases
|
|
166
|
+
* Missing or incorrect feedback
|
|
167
|
+
* Be specific and practical in each scenario. -->
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npx playwright *)",
|
|
5
|
+
"Bash(npx cucumber-js *)",
|
|
6
|
+
"Bash(echo \"Exit: $?\")",
|
|
7
|
+
"Bash(playwright --version)",
|
|
8
|
+
"mcp__claude_ai_Atlassian__getAccessibleAtlassianResources",
|
|
9
|
+
"mcp__claude_ai_Atlassian__getJiraIssue",
|
|
10
|
+
"mcp__claude_ai_Atlassian__createJiraIssue",
|
|
11
|
+
"mcp__claude_ai_Atlassian__createIssueLink",
|
|
12
|
+
"mcp__claude_ai_Atlassian__addCommentToJiraIssue"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"enableAllProjectMcpServers": true,
|
|
16
|
+
"enabledMcpjsonServers": [
|
|
17
|
+
"playwright"
|
|
18
|
+
]
|
|
19
|
+
}
|