@qa-gentic/agents 1.1.2
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 +203 -0
- package/bin/postinstall.js +75 -0
- package/bin/qa-stlc.js +76 -0
- package/package.json +48 -0
- package/skills/qa-stlc/AGENT-BEHAVIOR.md +373 -0
- package/skills/qa-stlc/deduplication-protocol.md +303 -0
- package/skills/qa-stlc/generate-gherkin.md +550 -0
- package/skills/qa-stlc/generate-playwright-code.md +439 -0
- package/skills/qa-stlc/generate-test-cases.md +176 -0
- package/skills/qa-stlc/write-helix-files.md +349 -0
- package/src/cmd-init.js +84 -0
- package/src/cmd-mcp-config.js +177 -0
- package/src/cmd-skills.js +124 -0
- package/src/cmd-verify.js +129 -0
- package/src/qa_stlc_agents/__init__.py +0 -0
- package/src/qa_stlc_agents/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/server.py +502 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/tools/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/tools/__pycache__/ado_gherkin.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_gherkin_generator/tools/ado_gherkin.py +854 -0
- package/src/qa_stlc_agents/agent_helix_writer/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/__pycache__/server.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/server.py +529 -0
- package/src/qa_stlc_agents/agent_helix_writer/tools/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/tools/__pycache__/helix_write.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_helix_writer/tools/helix_write.py +622 -0
- package/src/qa_stlc_agents/agent_playwright_generator/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/__pycache__/server.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/server.py +2771 -0
- package/src/qa_stlc_agents/agent_playwright_generator/tools/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/tools/__pycache__/ado_attach.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_playwright_generator/tools/ado_attach.py +62 -0
- package/src/qa_stlc_agents/agent_test_case_manager/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/__pycache__/server.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/server.py +483 -0
- package/src/qa_stlc_agents/agent_test_case_manager/tools/__init__.py +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/tools/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/tools/__pycache__/ado_workitem.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/agent_test_case_manager/tools/ado_workitem.py +302 -0
- package/src/qa_stlc_agents/shared/__init__.py +0 -0
- package/src/qa_stlc_agents/shared/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/shared/__pycache__/auth.cpython-310.pyc +0 -0
- package/src/qa_stlc_agents/shared/auth.py +119 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cmd-skills.js — `qa-stlc skills`
|
|
3
|
+
*
|
|
4
|
+
* Copies skill markdown files into the correct directory for each coding agent:
|
|
5
|
+
*
|
|
6
|
+
* claude → .claude/skills/ + .claude/AGENT-BEHAVIOR.md
|
|
7
|
+
* vscode → .github/copilot-instructions/
|
|
8
|
+
* cursor → .cursor/rules/ (one file per skill)
|
|
9
|
+
* windsurf → .windsurf/rules/
|
|
10
|
+
* both → claude + vscode
|
|
11
|
+
* print → stdout only
|
|
12
|
+
*/
|
|
13
|
+
"use strict";
|
|
14
|
+
|
|
15
|
+
const path = require("path");
|
|
16
|
+
const fs = require("fs");
|
|
17
|
+
|
|
18
|
+
const C = {
|
|
19
|
+
reset: "\x1b[0m", bold: "\x1b[1m",
|
|
20
|
+
green: "\x1b[32m", yellow: "\x1b[33m", dim: "\x1b[2m",
|
|
21
|
+
};
|
|
22
|
+
const ok = (m) => console.log(`${C.green}✓${C.reset} ${m}`);
|
|
23
|
+
const info = (m) => console.log(` ${C.dim}${m}${C.reset}`);
|
|
24
|
+
const warn = (m) => console.log(`${C.yellow}⚠${C.reset} ${m}`);
|
|
25
|
+
|
|
26
|
+
// Resolve the skills bundled with this npm package
|
|
27
|
+
const PKG_ROOT = path.resolve(__dirname, "..");
|
|
28
|
+
const SKILLS_DIR = path.join(PKG_ROOT, "skills", "qa-stlc");
|
|
29
|
+
const BEHAVIOR_MD = path.join(SKILLS_DIR, "AGENT-BEHAVIOR.md");
|
|
30
|
+
|
|
31
|
+
/** Copy a file, creating parent dirs as needed. */
|
|
32
|
+
function cp(src, dest) {
|
|
33
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
34
|
+
fs.copyFileSync(src, dest);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** List all .md files in SKILLS_DIR (flat). */
|
|
38
|
+
function skillFiles() {
|
|
39
|
+
return fs.readdirSync(SKILLS_DIR)
|
|
40
|
+
.filter((f) => f.endsWith(".md") && f !== "AGENT-BEHAVIOR.md")
|
|
41
|
+
.map((f) => path.join(SKILLS_DIR, f));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const CWD = process.cwd();
|
|
45
|
+
|
|
46
|
+
function installClaude() {
|
|
47
|
+
const dest = path.join(CWD, ".claude", "skills");
|
|
48
|
+
for (const src of skillFiles()) {
|
|
49
|
+
cp(src, path.join(dest, path.basename(src)));
|
|
50
|
+
}
|
|
51
|
+
cp(BEHAVIOR_MD, path.join(CWD, ".claude", "AGENT-BEHAVIOR.md"));
|
|
52
|
+
ok(`Skills installed → .claude/skills/`);
|
|
53
|
+
info("AGENT-BEHAVIOR.md → .claude/AGENT-BEHAVIOR.md");
|
|
54
|
+
skillFiles().forEach((f) => info(path.basename(f)));
|
|
55
|
+
printPlaywrightHint();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function installVscode() {
|
|
59
|
+
const dest = path.join(CWD, ".github", "copilot-instructions");
|
|
60
|
+
for (const src of skillFiles()) {
|
|
61
|
+
cp(src, path.join(dest, path.basename(src)));
|
|
62
|
+
}
|
|
63
|
+
cp(BEHAVIOR_MD, path.join(dest, "AGENT-BEHAVIOR.md"));
|
|
64
|
+
ok(`Skills installed → .github/copilot-instructions/`);
|
|
65
|
+
info("Add to .github/copilot-instructions.md:");
|
|
66
|
+
info(" @.github/copilot-instructions/AGENT-BEHAVIOR.md");
|
|
67
|
+
printPlaywrightHint();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function installCursor() {
|
|
71
|
+
const dest = path.join(CWD, ".cursor", "rules");
|
|
72
|
+
for (const src of skillFiles()) {
|
|
73
|
+
cp(src, path.join(dest, path.basename(src)));
|
|
74
|
+
}
|
|
75
|
+
cp(BEHAVIOR_MD, path.join(dest, "AGENT-BEHAVIOR.md"));
|
|
76
|
+
ok(`Skills installed → .cursor/rules/`);
|
|
77
|
+
printPlaywrightHint();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function installWindsurf() {
|
|
81
|
+
const dest = path.join(CWD, ".windsurf", "rules");
|
|
82
|
+
for (const src of skillFiles()) {
|
|
83
|
+
cp(src, path.join(dest, path.basename(src)));
|
|
84
|
+
}
|
|
85
|
+
cp(BEHAVIOR_MD, path.join(dest, "AGENT-BEHAVIOR.md"));
|
|
86
|
+
ok(`Skills installed → .windsurf/rules/`);
|
|
87
|
+
printPlaywrightHint();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function printSkills() {
|
|
91
|
+
console.log("\nAvailable skills:\n");
|
|
92
|
+
skillFiles().forEach((f) => console.log(` ${path.basename(f)}`));
|
|
93
|
+
console.log(` AGENT-BEHAVIOR.md`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function printPlaywrightHint() {
|
|
97
|
+
console.log(`
|
|
98
|
+
${C.dim}Start Playwright MCP before running generation workflows:${C.reset}
|
|
99
|
+
npx @playwright/mcp@latest --port 8931
|
|
100
|
+
`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = async function skills(opts) {
|
|
104
|
+
const target = (opts.target || "claude").toLowerCase();
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
107
|
+
console.error(`Skills directory not found: ${SKILLS_DIR}`);
|
|
108
|
+
console.error("Try reinstalling: npm install -g @qa-stlc/agents");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
switch (target) {
|
|
113
|
+
case "claude": installClaude(); break;
|
|
114
|
+
case "vscode": installVscode(); break;
|
|
115
|
+
case "cursor": installCursor(); break;
|
|
116
|
+
case "windsurf": installWindsurf(); break;
|
|
117
|
+
case "both": installClaude(); installVscode(); break;
|
|
118
|
+
case "print": printSkills(); break;
|
|
119
|
+
default:
|
|
120
|
+
warn(`Unknown target: ${target}`);
|
|
121
|
+
warn("Valid targets: claude, vscode, cursor, windsurf, both, print");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cmd-verify.js — `qa-stlc verify`
|
|
3
|
+
*
|
|
4
|
+
* Quick sanity checks:
|
|
5
|
+
* 1. Are the four Python MCP agents on PATH (or in .venv)?
|
|
6
|
+
* 2. Is Playwright MCP reachable on the expected port?
|
|
7
|
+
* 3. Is MSAL auth cache present?
|
|
8
|
+
*/
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const http = require("http");
|
|
14
|
+
const https = require("https");
|
|
15
|
+
const { spawnSync } = require("child_process");
|
|
16
|
+
const os = require("os");
|
|
17
|
+
|
|
18
|
+
const C = {
|
|
19
|
+
reset: "\x1b[0m", bold: "\x1b[1m",
|
|
20
|
+
green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", dim: "\x1b[2m",
|
|
21
|
+
};
|
|
22
|
+
const ok = (m) => console.log(` ${C.green}✓${C.reset} ${m}`);
|
|
23
|
+
const fail = (m) => console.log(` ${C.red}✗${C.reset} ${m}`);
|
|
24
|
+
const warn = (m) => console.log(` ${C.yellow}⚠${C.reset} ${m}`);
|
|
25
|
+
const head = (m) => console.log(`\n${C.bold}${m}${C.reset}`);
|
|
26
|
+
|
|
27
|
+
const CWD = process.cwd();
|
|
28
|
+
const IS_WIN = process.platform === "win32";
|
|
29
|
+
const EXT = IS_WIN ? ".exe" : "";
|
|
30
|
+
|
|
31
|
+
const AGENT_NAMES = [
|
|
32
|
+
"qa-test-case-manager",
|
|
33
|
+
"qa-gherkin-generator",
|
|
34
|
+
"qa-playwright-generator",
|
|
35
|
+
"qa-helix-writer",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
function findBinary(name) {
|
|
39
|
+
// .venv first
|
|
40
|
+
const venvBin = IS_WIN
|
|
41
|
+
? path.join(CWD, ".venv", "Scripts", name + EXT)
|
|
42
|
+
: path.join(CWD, ".venv", "bin", name);
|
|
43
|
+
if (fs.existsSync(venvBin)) return venvBin;
|
|
44
|
+
// system PATH
|
|
45
|
+
const w = spawnSync(IS_WIN ? "where" : "which", [name], { encoding: "utf8" });
|
|
46
|
+
if (w.status === 0 && w.stdout.trim()) return w.stdout.trim().split("\n")[0].trim();
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkPort(port) {
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
const req = http.get(`http://localhost:${port}/`, (res) => {
|
|
53
|
+
res.destroy();
|
|
54
|
+
resolve(true);
|
|
55
|
+
});
|
|
56
|
+
req.setTimeout(2000, () => { req.destroy(); resolve(false); });
|
|
57
|
+
req.on("error", () => resolve(false));
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = async function verify(opts) {
|
|
62
|
+
const playwrightPort = opts.playwrightPort || "8931";
|
|
63
|
+
let allOk = true;
|
|
64
|
+
|
|
65
|
+
// ── 1. Python agents ──────────────────────────────────────────────────────
|
|
66
|
+
head("Python MCP Agents");
|
|
67
|
+
for (const name of AGENT_NAMES) {
|
|
68
|
+
const bin = findBinary(name);
|
|
69
|
+
if (bin) {
|
|
70
|
+
ok(`${name} ${C.dim}${bin}${C.reset}`);
|
|
71
|
+
} else {
|
|
72
|
+
fail(`${name} — not found`);
|
|
73
|
+
allOk = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!allOk) {
|
|
77
|
+
console.log(`\n ${C.yellow}Fix: pip install qa-gentic-agents${C.reset}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── 2. Playwright MCP ─────────────────────────────────────────────────────
|
|
81
|
+
head("Playwright MCP");
|
|
82
|
+
const pwReachable = await checkPort(playwrightPort);
|
|
83
|
+
if (pwReachable) {
|
|
84
|
+
ok(`Reachable on port ${playwrightPort}`);
|
|
85
|
+
} else {
|
|
86
|
+
warn(`Not reachable on port ${playwrightPort} ${C.dim}(start it with: npx @playwright/mcp@latest --port ${playwrightPort})${C.reset}`);
|
|
87
|
+
// Don't fail — it's optional until generation time
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── 3. MSAL token cache ───────────────────────────────────────────────────
|
|
91
|
+
head("Azure DevOps Auth (MSAL)");
|
|
92
|
+
const msalCache = path.join(os.homedir(), ".msal-cache", "msal-cache.json");
|
|
93
|
+
if (fs.existsSync(msalCache)) {
|
|
94
|
+
const stat = fs.statSync(msalCache);
|
|
95
|
+
ok(`Token cache found ${C.dim}${msalCache} (${Math.round(stat.size / 1024)} KB)${C.reset}`);
|
|
96
|
+
} else {
|
|
97
|
+
warn(`No MSAL cache at ${msalCache}`);
|
|
98
|
+
warn(`A browser will open the first time an agent calls Azure DevOps.`);
|
|
99
|
+
warn(`Set AZURE_CLIENT_ID + AZURE_CLIENT_SECRET + AZURE_TENANT_ID for CI/CD.`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── 4. MCP config files ───────────────────────────────────────────────────
|
|
103
|
+
head("MCP Config");
|
|
104
|
+
const mcpJson = path.join(CWD, ".mcp.json");
|
|
105
|
+
const vscodeMcp = path.join(CWD, ".vscode", "mcp.json");
|
|
106
|
+
if (fs.existsSync(mcpJson)) ok(`.mcp.json present`);
|
|
107
|
+
else warn(`.mcp.json missing — run: qa-stlc mcp-config`);
|
|
108
|
+
if (fs.existsSync(vscodeMcp)) ok(`.vscode/mcp.json present`);
|
|
109
|
+
else warn(`.vscode/mcp.json missing — run: qa-stlc mcp-config --vscode`);
|
|
110
|
+
|
|
111
|
+
// ── 5. Skills ─────────────────────────────────────────────────────────────
|
|
112
|
+
head("Skills");
|
|
113
|
+
const claudeSkills = path.join(CWD, ".claude", "skills");
|
|
114
|
+
const copilotSkills = path.join(CWD, ".github", "copilot-instructions");
|
|
115
|
+
if (fs.existsSync(claudeSkills)) {
|
|
116
|
+
const files = fs.readdirSync(claudeSkills).filter((f) => f.endsWith(".md"));
|
|
117
|
+
ok(`Claude Code skills (${files.length} files) ${C.dim}${claudeSkills}${C.reset}`);
|
|
118
|
+
} else {
|
|
119
|
+
warn(`No Claude Code skills — run: qa-stlc skills`);
|
|
120
|
+
}
|
|
121
|
+
if (fs.existsSync(copilotSkills)) {
|
|
122
|
+
const files = fs.readdirSync(copilotSkills).filter((f) => f.endsWith(".md"));
|
|
123
|
+
ok(`Copilot instructions (${files.length} files) ${C.dim}${copilotSkills}${C.reset}`);
|
|
124
|
+
} else {
|
|
125
|
+
warn(`No Copilot instructions — run: qa-stlc skills --target vscode`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log();
|
|
129
|
+
};
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
Binary file
|