@openqa/cli 1.0.1 → 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 +4 -4
- package/dist/cli/{index.js → index.cjs} +155 -129
- package/package.json +3 -3
- package/dist/cli/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://www.npmjs.com/package/
|
|
13
|
-
<a href="https://www.npmjs.com/package/
|
|
14
|
-
<a href="https://github.com/
|
|
15
|
-
<a href="https://orkajs.com"><img src="https://img.shields.io/badge/docs-orkajs.com-blue.svg" alt="documentation"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@openqa/cli"><img src="https://img.shields.io/npm/v/@openqa/cli.svg" alt="npm version"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@openqa/cli"><img src="https://img.shields.io/npm/dm/@openqa/cli.svg" alt="npm downloads"></a>
|
|
14
|
+
<a href="https://github.com/Orka-Community/OpenQA/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@openqa/cli.svg" alt="license"></a>
|
|
15
|
+
<a href="https://openqa.orkajs.com"><img src="https://img.shields.io/badge/docs-orkajs.com-blue.svg" alt="documentation"></a>
|
|
16
16
|
<a href="https://discord.com/invite/DScfpuPysP"><img src="https://img.shields.io/badge/discord-join%20chat-7289da.svg" alt="discord"></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
@@ -1,35 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
#!/usr/bin/env node
|
|
3
|
+
"use strict";
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
28
|
+
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
29
|
+
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
3
30
|
|
|
4
31
|
// cli/index.ts
|
|
5
|
-
|
|
32
|
+
var import_commander = require("commander");
|
|
6
33
|
|
|
7
34
|
// agent/index.ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
35
|
+
var import_agent2 = require("@orka-js/agent");
|
|
36
|
+
var import_openai2 = require("@orka-js/openai");
|
|
37
|
+
var import_anthropic2 = require("@orka-js/anthropic");
|
|
38
|
+
var import_memory_store = require("@orka-js/memory-store");
|
|
39
|
+
var import_observability = require("@orka-js/observability");
|
|
40
|
+
var import_events3 = require("events");
|
|
14
41
|
|
|
15
42
|
// database/index.ts
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
var
|
|
22
|
-
var __dirname = dirname(
|
|
43
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
44
|
+
var import_fs = require("fs");
|
|
45
|
+
var import_path = require("path");
|
|
46
|
+
var import_url = require("url");
|
|
47
|
+
var import_fs2 = require("fs");
|
|
48
|
+
var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
49
|
+
var __dirname = (0, import_path.dirname)(__filename2);
|
|
23
50
|
var OpenQADatabase = class {
|
|
24
51
|
db;
|
|
25
52
|
constructor(dbPath = "./data/openqa.db") {
|
|
26
|
-
const dir = dirname(dbPath);
|
|
27
|
-
mkdirSync(dir, { recursive: true });
|
|
28
|
-
this.db = new
|
|
53
|
+
const dir = (0, import_path.dirname)(dbPath);
|
|
54
|
+
(0, import_fs2.mkdirSync)(dir, { recursive: true });
|
|
55
|
+
this.db = new import_better_sqlite3.default(dbPath);
|
|
29
56
|
this.initialize();
|
|
30
57
|
}
|
|
31
58
|
initialize() {
|
|
32
|
-
const schema = readFileSync(join(__dirname, "schema.sql"), "utf-8");
|
|
59
|
+
const schema = (0, import_fs.readFileSync)((0, import_path.join)(__dirname, "schema.sql"), "utf-8");
|
|
33
60
|
this.db.exec(schema);
|
|
34
61
|
}
|
|
35
62
|
getConfig(key) {
|
|
@@ -134,8 +161,8 @@ var OpenQADatabase = class {
|
|
|
134
161
|
};
|
|
135
162
|
|
|
136
163
|
// agent/config/index.ts
|
|
137
|
-
|
|
138
|
-
|
|
164
|
+
var import_dotenv = require("dotenv");
|
|
165
|
+
(0, import_dotenv.config)();
|
|
139
166
|
var ConfigManager = class {
|
|
140
167
|
db;
|
|
141
168
|
envConfig;
|
|
@@ -213,9 +240,9 @@ var ConfigManager = class {
|
|
|
213
240
|
};
|
|
214
241
|
|
|
215
242
|
// agent/tools/browser.ts
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
243
|
+
var import_playwright = require("playwright");
|
|
244
|
+
var import_fs3 = require("fs");
|
|
245
|
+
var import_path2 = require("path");
|
|
219
246
|
var BrowserTools = class {
|
|
220
247
|
browser = null;
|
|
221
248
|
page = null;
|
|
@@ -225,10 +252,10 @@ var BrowserTools = class {
|
|
|
225
252
|
constructor(db, sessionId) {
|
|
226
253
|
this.db = db;
|
|
227
254
|
this.sessionId = sessionId;
|
|
228
|
-
|
|
255
|
+
(0, import_fs3.mkdirSync)(this.screenshotDir, { recursive: true });
|
|
229
256
|
}
|
|
230
257
|
async initialize() {
|
|
231
|
-
this.browser = await chromium.launch({ headless: true });
|
|
258
|
+
this.browser = await import_playwright.chromium.launch({ headless: true });
|
|
232
259
|
const context = await this.browser.newContext({
|
|
233
260
|
viewport: { width: 1920, height: 1080 },
|
|
234
261
|
userAgent: "OpenQA/1.0 (Automated Testing Agent)"
|
|
@@ -332,7 +359,7 @@ var BrowserTools = class {
|
|
|
332
359
|
if (!this.page) return "Browser not initialized. Navigate to a page first.";
|
|
333
360
|
try {
|
|
334
361
|
const filename = `${Date.now()}_${name}.png`;
|
|
335
|
-
const path =
|
|
362
|
+
const path = (0, import_path2.join)(this.screenshotDir, filename);
|
|
336
363
|
await this.page.screenshot({ path, fullPage: true });
|
|
337
364
|
this.db.createAction({
|
|
338
365
|
session_id: this.sessionId,
|
|
@@ -398,7 +425,7 @@ ${errors.join("\n")}`;
|
|
|
398
425
|
};
|
|
399
426
|
|
|
400
427
|
// agent/tools/github.ts
|
|
401
|
-
|
|
428
|
+
var import_rest = require("@octokit/rest");
|
|
402
429
|
var GitHubTools = class {
|
|
403
430
|
octokit = null;
|
|
404
431
|
db;
|
|
@@ -409,7 +436,7 @@ var GitHubTools = class {
|
|
|
409
436
|
this.sessionId = sessionId;
|
|
410
437
|
this.config = config;
|
|
411
438
|
if (config.token) {
|
|
412
|
-
this.octokit = new Octokit({ auth: config.token });
|
|
439
|
+
this.octokit = new import_rest.Octokit({ auth: config.token });
|
|
413
440
|
}
|
|
414
441
|
}
|
|
415
442
|
getTools() {
|
|
@@ -594,9 +621,9 @@ Total: ${tickets.length} tickets
|
|
|
594
621
|
};
|
|
595
622
|
|
|
596
623
|
// agent/webhooks/git-listener.ts
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
var GitListener = class extends EventEmitter {
|
|
624
|
+
var import_events = require("events");
|
|
625
|
+
var import_rest2 = require("@octokit/rest");
|
|
626
|
+
var GitListener = class extends import_events.EventEmitter {
|
|
600
627
|
config;
|
|
601
628
|
octokit = null;
|
|
602
629
|
lastCommitSha = null;
|
|
@@ -612,7 +639,7 @@ var GitListener = class extends EventEmitter {
|
|
|
612
639
|
...config
|
|
613
640
|
};
|
|
614
641
|
if (config.provider === "github" && config.token) {
|
|
615
|
-
this.octokit = new
|
|
642
|
+
this.octokit = new import_rest2.Octokit({ auth: config.token });
|
|
616
643
|
}
|
|
617
644
|
}
|
|
618
645
|
async start() {
|
|
@@ -881,10 +908,10 @@ var GitListener = class extends EventEmitter {
|
|
|
881
908
|
};
|
|
882
909
|
|
|
883
910
|
// agent/specialists/index.ts
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
911
|
+
var import_agent = require("@orka-js/agent");
|
|
912
|
+
var import_openai = require("@orka-js/openai");
|
|
913
|
+
var import_anthropic = require("@orka-js/anthropic");
|
|
914
|
+
var import_events2 = require("events");
|
|
888
915
|
var SPECIALIST_PROMPTS = {
|
|
889
916
|
"form-tester": `You are a Form Testing Specialist. Your mission:
|
|
890
917
|
- Find all forms on the page (login, signup, contact, search, etc.)
|
|
@@ -973,7 +1000,7 @@ var SPECIALIST_PROMPTS = {
|
|
|
973
1000
|
- Test pagination and infinite scroll
|
|
974
1001
|
- Report navigation issues with affected URLs`
|
|
975
1002
|
};
|
|
976
|
-
var SpecialistAgentManager = class extends
|
|
1003
|
+
var SpecialistAgentManager = class extends import_events2.EventEmitter {
|
|
977
1004
|
agents = /* @__PURE__ */ new Map();
|
|
978
1005
|
agentStatuses = /* @__PURE__ */ new Map();
|
|
979
1006
|
db;
|
|
@@ -989,12 +1016,12 @@ var SpecialistAgentManager = class extends EventEmitter2 {
|
|
|
989
1016
|
}
|
|
990
1017
|
createLLMAdapter() {
|
|
991
1018
|
if (this.llmConfig.provider === "anthropic") {
|
|
992
|
-
return new AnthropicAdapter({
|
|
1019
|
+
return new import_anthropic.AnthropicAdapter({
|
|
993
1020
|
apiKey: this.llmConfig.apiKey,
|
|
994
1021
|
model: this.llmConfig.model || "claude-3-5-sonnet-20241022"
|
|
995
1022
|
});
|
|
996
1023
|
}
|
|
997
|
-
return new OpenAIAdapter({
|
|
1024
|
+
return new import_openai.OpenAIAdapter({
|
|
998
1025
|
apiKey: this.llmConfig.apiKey,
|
|
999
1026
|
model: this.llmConfig.model || "gpt-4"
|
|
1000
1027
|
});
|
|
@@ -1002,7 +1029,7 @@ var SpecialistAgentManager = class extends EventEmitter2 {
|
|
|
1002
1029
|
createSpecialist(type, customPrompt) {
|
|
1003
1030
|
const agentId = `${type}_${Date.now()}`;
|
|
1004
1031
|
const systemPrompt = customPrompt || SPECIALIST_PROMPTS[type];
|
|
1005
|
-
const agent = new ReActAgent({
|
|
1032
|
+
const agent = new import_agent.ReActAgent({
|
|
1006
1033
|
llm: this.createLLMAdapter(),
|
|
1007
1034
|
tools: this.browserTools.getTools(),
|
|
1008
1035
|
maxIterations: 15,
|
|
@@ -1311,7 +1338,7 @@ Remember to report findings from each skill separately.
|
|
|
1311
1338
|
};
|
|
1312
1339
|
|
|
1313
1340
|
// agent/index.ts
|
|
1314
|
-
var OpenQAAgent = class extends
|
|
1341
|
+
var OpenQAAgent = class extends import_events3.EventEmitter {
|
|
1315
1342
|
agent = null;
|
|
1316
1343
|
db;
|
|
1317
1344
|
config;
|
|
@@ -1333,13 +1360,13 @@ var OpenQAAgent = class extends EventEmitter3 {
|
|
|
1333
1360
|
const cfg = this.config.getConfig();
|
|
1334
1361
|
switch (cfg.llm.provider) {
|
|
1335
1362
|
case "anthropic":
|
|
1336
|
-
return new
|
|
1363
|
+
return new import_anthropic2.AnthropicAdapter({
|
|
1337
1364
|
apiKey: cfg.llm.apiKey || process.env.ANTHROPIC_API_KEY,
|
|
1338
1365
|
model: cfg.llm.model || "claude-3-5-sonnet-20241022"
|
|
1339
1366
|
});
|
|
1340
1367
|
case "openai":
|
|
1341
1368
|
default:
|
|
1342
|
-
return new
|
|
1369
|
+
return new import_openai2.OpenAIAdapter({
|
|
1343
1370
|
apiKey: cfg.llm.apiKey || process.env.OPENAI_API_KEY,
|
|
1344
1371
|
model: cfg.llm.model || "gpt-4"
|
|
1345
1372
|
});
|
|
@@ -1363,8 +1390,8 @@ var OpenQAAgent = class extends EventEmitter3 {
|
|
|
1363
1390
|
...kanbanTools.getTools()
|
|
1364
1391
|
];
|
|
1365
1392
|
const llm = this.createLLMAdapter();
|
|
1366
|
-
const memory = new SessionMemory({ maxMessages: 50 });
|
|
1367
|
-
const tracer = new Tracer({ logLevel: "info" });
|
|
1393
|
+
const memory = new import_memory_store.SessionMemory({ maxMessages: 50 });
|
|
1394
|
+
const tracer = new import_observability.Tracer({ logLevel: "info" });
|
|
1368
1395
|
const enabledSkills = this.skillManager.getEnabledSkills();
|
|
1369
1396
|
const skillPrompt = this.skillManager.generateSkillPrompt(enabledSkills);
|
|
1370
1397
|
const agentConfig = {
|
|
@@ -1403,7 +1430,7 @@ ${skillPrompt}
|
|
|
1403
1430
|
|
|
1404
1431
|
Always provide clear, actionable information with steps to reproduce. Think step by step like a human QA expert.`
|
|
1405
1432
|
};
|
|
1406
|
-
this.agent = new
|
|
1433
|
+
this.agent = new import_agent2.ReActAgent(agentConfig, llm, memory);
|
|
1407
1434
|
this.specialistManager = new SpecialistAgentManager(
|
|
1408
1435
|
this.db,
|
|
1409
1436
|
this.sessionId,
|
|
@@ -1583,84 +1610,84 @@ Always provide clear, actionable information with steps to reproduce. Think step
|
|
|
1583
1610
|
};
|
|
1584
1611
|
|
|
1585
1612
|
// cli/index.ts
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
var program = new Command();
|
|
1613
|
+
var import_child_process = require("child_process");
|
|
1614
|
+
var import_fs4 = require("fs");
|
|
1615
|
+
var import_path3 = require("path");
|
|
1616
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
1617
|
+
var import_ora = __toESM(require("ora"), 1);
|
|
1618
|
+
var program = new import_commander.Command();
|
|
1592
1619
|
var PID_FILE = "./data/openqa.pid";
|
|
1593
1620
|
program.name("openqa").description("OpenQA - Autonomous QA Testing Agent powered by Orka.js").version("1.0.0");
|
|
1594
1621
|
program.command("start").description("Start the OpenQA agent and web UI").option("-d, --daemon", "Run in daemon mode").action(async (options) => {
|
|
1595
|
-
const spinner =
|
|
1622
|
+
const spinner = (0, import_ora.default)("Starting OpenQA...").start();
|
|
1596
1623
|
try {
|
|
1597
|
-
if (existsSync(PID_FILE)) {
|
|
1598
|
-
const pid =
|
|
1624
|
+
if ((0, import_fs4.existsSync)(PID_FILE)) {
|
|
1625
|
+
const pid = (0, import_fs4.readFileSync)(PID_FILE, "utf-8").trim();
|
|
1599
1626
|
try {
|
|
1600
1627
|
process.kill(parseInt(pid), 0);
|
|
1601
|
-
spinner.fail(
|
|
1602
|
-
console.log(
|
|
1603
|
-
console.log(
|
|
1628
|
+
spinner.fail(import_chalk.default.red("OpenQA is already running"));
|
|
1629
|
+
console.log(import_chalk.default.yellow(`PID: ${pid}`));
|
|
1630
|
+
console.log(import_chalk.default.cyan('Run "openqa stop" to stop it first'));
|
|
1604
1631
|
process.exit(1);
|
|
1605
1632
|
} catch {
|
|
1606
|
-
unlinkSync(PID_FILE);
|
|
1633
|
+
(0, import_fs4.unlinkSync)(PID_FILE);
|
|
1607
1634
|
}
|
|
1608
1635
|
}
|
|
1609
1636
|
if (options.daemon) {
|
|
1610
|
-
const child = spawn("node", [
|
|
1637
|
+
const child = (0, import_child_process.spawn)("node", [(0, import_path3.join)(process.cwd(), "dist/cli/daemon.js")], {
|
|
1611
1638
|
detached: true,
|
|
1612
1639
|
stdio: "ignore"
|
|
1613
1640
|
});
|
|
1614
1641
|
child.unref();
|
|
1615
|
-
writeFileSync(PID_FILE, child.pid.toString());
|
|
1616
|
-
spinner.succeed(
|
|
1617
|
-
console.log(
|
|
1642
|
+
(0, import_fs4.writeFileSync)(PID_FILE, child.pid.toString());
|
|
1643
|
+
spinner.succeed(import_chalk.default.green("OpenQA started in daemon mode"));
|
|
1644
|
+
console.log(import_chalk.default.cyan(`PID: ${child.pid}`));
|
|
1618
1645
|
} else {
|
|
1619
|
-
spinner.succeed(
|
|
1646
|
+
spinner.succeed(import_chalk.default.green("OpenQA started"));
|
|
1620
1647
|
const agent = new OpenQAAgent();
|
|
1621
1648
|
const config = new ConfigManager();
|
|
1622
1649
|
const cfg = config.getConfig();
|
|
1623
|
-
console.log(
|
|
1624
|
-
console.log(
|
|
1625
|
-
console.log(
|
|
1626
|
-
console.log(
|
|
1627
|
-
console.log(
|
|
1628
|
-
console.log(
|
|
1629
|
-
console.log(
|
|
1630
|
-
console.log(
|
|
1650
|
+
console.log(import_chalk.default.cyan("\n\u{1F4CA} OpenQA Status:"));
|
|
1651
|
+
console.log(import_chalk.default.white(` Agent: Running`));
|
|
1652
|
+
console.log(import_chalk.default.white(` Target: ${cfg.saas.url || "Not configured"}`));
|
|
1653
|
+
console.log(import_chalk.default.white(` Web UI: http://localhost:${cfg.web.port}`));
|
|
1654
|
+
console.log(import_chalk.default.white(` DevTools: http://localhost:${cfg.web.port}`));
|
|
1655
|
+
console.log(import_chalk.default.white(` Kanban: http://localhost:${cfg.web.port}/kanban`));
|
|
1656
|
+
console.log(import_chalk.default.white(` Config: http://localhost:${cfg.web.port}/config`));
|
|
1657
|
+
console.log(import_chalk.default.gray("\nPress Ctrl+C to stop\n"));
|
|
1631
1658
|
if (cfg.agent.autoStart) {
|
|
1632
1659
|
await agent.startAutonomous();
|
|
1633
1660
|
} else {
|
|
1634
|
-
console.log(
|
|
1635
|
-
console.log(
|
|
1661
|
+
console.log(import_chalk.default.yellow("Auto-start disabled. Agent is idle."));
|
|
1662
|
+
console.log(import_chalk.default.cyan("Set AGENT_AUTO_START=true to enable autonomous mode"));
|
|
1636
1663
|
}
|
|
1637
1664
|
}
|
|
1638
1665
|
} catch (error) {
|
|
1639
|
-
spinner.fail(
|
|
1640
|
-
console.error(
|
|
1666
|
+
spinner.fail(import_chalk.default.red("Failed to start OpenQA"));
|
|
1667
|
+
console.error(import_chalk.default.red(error.message));
|
|
1641
1668
|
process.exit(1);
|
|
1642
1669
|
}
|
|
1643
1670
|
});
|
|
1644
1671
|
program.command("stop").description("Stop the OpenQA agent").action(() => {
|
|
1645
|
-
const spinner =
|
|
1672
|
+
const spinner = (0, import_ora.default)("Stopping OpenQA...").start();
|
|
1646
1673
|
try {
|
|
1647
|
-
if (!existsSync(PID_FILE)) {
|
|
1648
|
-
spinner.fail(
|
|
1674
|
+
if (!(0, import_fs4.existsSync)(PID_FILE)) {
|
|
1675
|
+
spinner.fail(import_chalk.default.red("OpenQA is not running"));
|
|
1649
1676
|
process.exit(1);
|
|
1650
1677
|
}
|
|
1651
|
-
const pid =
|
|
1678
|
+
const pid = (0, import_fs4.readFileSync)(PID_FILE, "utf-8").trim();
|
|
1652
1679
|
try {
|
|
1653
1680
|
process.kill(parseInt(pid), "SIGTERM");
|
|
1654
|
-
unlinkSync(PID_FILE);
|
|
1655
|
-
spinner.succeed(
|
|
1681
|
+
(0, import_fs4.unlinkSync)(PID_FILE);
|
|
1682
|
+
spinner.succeed(import_chalk.default.green("OpenQA stopped"));
|
|
1656
1683
|
} catch (error) {
|
|
1657
|
-
spinner.fail(
|
|
1658
|
-
console.error(
|
|
1659
|
-
unlinkSync(PID_FILE);
|
|
1684
|
+
spinner.fail(import_chalk.default.red("Failed to stop OpenQA"));
|
|
1685
|
+
console.error(import_chalk.default.red("Process not found. Cleaning up PID file..."));
|
|
1686
|
+
(0, import_fs4.unlinkSync)(PID_FILE);
|
|
1660
1687
|
}
|
|
1661
1688
|
} catch (error) {
|
|
1662
|
-
spinner.fail(
|
|
1663
|
-
console.error(
|
|
1689
|
+
spinner.fail(import_chalk.default.red("Failed to stop OpenQA"));
|
|
1690
|
+
console.error(import_chalk.default.red(error.message));
|
|
1664
1691
|
process.exit(1);
|
|
1665
1692
|
}
|
|
1666
1693
|
});
|
|
@@ -1668,38 +1695,38 @@ program.command("status").description("Show OpenQA status").action(() => {
|
|
|
1668
1695
|
const config = new ConfigManager();
|
|
1669
1696
|
const cfg = config.getConfig();
|
|
1670
1697
|
const db = new OpenQADatabase(cfg.database.path);
|
|
1671
|
-
console.log(
|
|
1672
|
-
if (existsSync(PID_FILE)) {
|
|
1673
|
-
const pid =
|
|
1698
|
+
console.log(import_chalk.default.cyan.bold("\n\u{1F4CA} OpenQA Status\n"));
|
|
1699
|
+
if ((0, import_fs4.existsSync)(PID_FILE)) {
|
|
1700
|
+
const pid = (0, import_fs4.readFileSync)(PID_FILE, "utf-8").trim();
|
|
1674
1701
|
try {
|
|
1675
1702
|
process.kill(parseInt(pid), 0);
|
|
1676
|
-
console.log(
|
|
1677
|
-
console.log(
|
|
1703
|
+
console.log(import_chalk.default.green("\u2713 Agent: Running"));
|
|
1704
|
+
console.log(import_chalk.default.white(` PID: ${pid}`));
|
|
1678
1705
|
} catch {
|
|
1679
|
-
console.log(
|
|
1680
|
-
unlinkSync(PID_FILE);
|
|
1706
|
+
console.log(import_chalk.default.red("\u2717 Agent: Stopped (stale PID file)"));
|
|
1707
|
+
(0, import_fs4.unlinkSync)(PID_FILE);
|
|
1681
1708
|
}
|
|
1682
1709
|
} else {
|
|
1683
|
-
console.log(
|
|
1684
|
-
}
|
|
1685
|
-
console.log(
|
|
1686
|
-
console.log(
|
|
1687
|
-
console.log(
|
|
1688
|
-
console.log(
|
|
1689
|
-
console.log(
|
|
1690
|
-
console.log(
|
|
1691
|
-
console.log(
|
|
1692
|
-
console.log(
|
|
1693
|
-
console.log(
|
|
1710
|
+
console.log(import_chalk.default.red("\u2717 Agent: Stopped"));
|
|
1711
|
+
}
|
|
1712
|
+
console.log(import_chalk.default.cyan("\n\u{1F310} Web Interfaces:"));
|
|
1713
|
+
console.log(import_chalk.default.white(` DevTools: http://localhost:${cfg.web.port}`));
|
|
1714
|
+
console.log(import_chalk.default.white(` Kanban: http://localhost:${cfg.web.port}/kanban`));
|
|
1715
|
+
console.log(import_chalk.default.white(` Config: http://localhost:${cfg.web.port}/config`));
|
|
1716
|
+
console.log(import_chalk.default.cyan("\n\u2699\uFE0F Configuration:"));
|
|
1717
|
+
console.log(import_chalk.default.white(` LLM Provider: ${cfg.llm.provider}`));
|
|
1718
|
+
console.log(import_chalk.default.white(` Target SaaS: ${cfg.saas.url || "Not configured"}`));
|
|
1719
|
+
console.log(import_chalk.default.white(` GitHub: ${cfg.github?.token ? "Configured" : "Not configured"}`));
|
|
1720
|
+
console.log(import_chalk.default.white(` Test Interval: ${cfg.agent.intervalMs / 1e3 / 60} minutes`));
|
|
1694
1721
|
const sessions = db.getRecentSessions(5);
|
|
1695
|
-
console.log(
|
|
1722
|
+
console.log(import_chalk.default.cyan(`
|
|
1696
1723
|
\u{1F4CB} Recent Sessions (${sessions.length}):`));
|
|
1697
1724
|
sessions.forEach((s) => {
|
|
1698
|
-
const status = s.status === "completed" ?
|
|
1699
|
-
console.log(
|
|
1725
|
+
const status = s.status === "completed" ? import_chalk.default.green("\u2713") : s.status === "failed" ? import_chalk.default.red("\u2717") : import_chalk.default.yellow("\u27F3");
|
|
1726
|
+
console.log(import_chalk.default.white(` ${status} ${s.id} - ${s.bugs_found} bugs found`));
|
|
1700
1727
|
});
|
|
1701
1728
|
const bugs = db.getBugsByStatus("open");
|
|
1702
|
-
console.log(
|
|
1729
|
+
console.log(import_chalk.default.cyan(`
|
|
1703
1730
|
\u{1F41B} Open Bugs: ${bugs.length}`));
|
|
1704
1731
|
const tickets = db.getKanbanTickets();
|
|
1705
1732
|
const byColumn = {
|
|
@@ -1708,42 +1735,42 @@ program.command("status").description("Show OpenQA status").action(() => {
|
|
|
1708
1735
|
"in-progress": tickets.filter((t) => t.column === "in-progress").length,
|
|
1709
1736
|
done: tickets.filter((t) => t.column === "done").length
|
|
1710
1737
|
};
|
|
1711
|
-
console.log(
|
|
1712
|
-
console.log(
|
|
1713
|
-
console.log(
|
|
1714
|
-
console.log(
|
|
1715
|
-
console.log(
|
|
1738
|
+
console.log(import_chalk.default.cyan("\n\u{1F4CA} Kanban Board:"));
|
|
1739
|
+
console.log(import_chalk.default.white(` Backlog: ${byColumn.backlog}`));
|
|
1740
|
+
console.log(import_chalk.default.white(` To Do: ${byColumn["to-do"]}`));
|
|
1741
|
+
console.log(import_chalk.default.white(` In Progress: ${byColumn["in-progress"]}`));
|
|
1742
|
+
console.log(import_chalk.default.white(` Done: ${byColumn.done}`));
|
|
1716
1743
|
console.log("");
|
|
1717
1744
|
});
|
|
1718
1745
|
program.command("config").description("Manage configuration").argument("[action]", "Action: get, set, list").argument("[key]", "Configuration key (e.g., llm.provider)").argument("[value]", "Configuration value").action((action, key, value) => {
|
|
1719
1746
|
const config = new ConfigManager();
|
|
1720
1747
|
if (!action || action === "list") {
|
|
1721
1748
|
const cfg = config.getConfig();
|
|
1722
|
-
console.log(
|
|
1749
|
+
console.log(import_chalk.default.cyan.bold("\n\u2699\uFE0F OpenQA Configuration\n"));
|
|
1723
1750
|
console.log(JSON.stringify(cfg, null, 2));
|
|
1724
1751
|
console.log("");
|
|
1725
1752
|
return;
|
|
1726
1753
|
}
|
|
1727
1754
|
if (action === "get") {
|
|
1728
1755
|
if (!key) {
|
|
1729
|
-
console.error(
|
|
1756
|
+
console.error(import_chalk.default.red('Error: key is required for "get" action'));
|
|
1730
1757
|
process.exit(1);
|
|
1731
1758
|
}
|
|
1732
1759
|
const val = config.get(key);
|
|
1733
|
-
console.log(
|
|
1760
|
+
console.log(import_chalk.default.cyan(`${key}:`), import_chalk.default.white(val || "Not set"));
|
|
1734
1761
|
return;
|
|
1735
1762
|
}
|
|
1736
1763
|
if (action === "set") {
|
|
1737
1764
|
if (!key || !value) {
|
|
1738
|
-
console.error(
|
|
1765
|
+
console.error(import_chalk.default.red('Error: key and value are required for "set" action'));
|
|
1739
1766
|
process.exit(1);
|
|
1740
1767
|
}
|
|
1741
1768
|
config.set(key, value);
|
|
1742
|
-
console.log(
|
|
1769
|
+
console.log(import_chalk.default.green(`\u2713 Set ${key} = ${value}`));
|
|
1743
1770
|
return;
|
|
1744
1771
|
}
|
|
1745
|
-
console.error(
|
|
1746
|
-
console.log(
|
|
1772
|
+
console.error(import_chalk.default.red(`Unknown action: ${action}`));
|
|
1773
|
+
console.log(import_chalk.default.cyan("Available actions: get, set, list"));
|
|
1747
1774
|
process.exit(1);
|
|
1748
1775
|
});
|
|
1749
1776
|
program.command("logs").description("Show agent logs").option("-f, --follow", "Follow log output").option("-n, --lines <number>", "Number of lines to show", "50").action((options) => {
|
|
@@ -1752,28 +1779,27 @@ program.command("logs").description("Show agent logs").option("-f, --follow", "F
|
|
|
1752
1779
|
const db = new OpenQADatabase(cfg.database.path);
|
|
1753
1780
|
const sessions = db.getRecentSessions(1);
|
|
1754
1781
|
if (sessions.length === 0) {
|
|
1755
|
-
console.log(
|
|
1782
|
+
console.log(import_chalk.default.yellow("No sessions found"));
|
|
1756
1783
|
return;
|
|
1757
1784
|
}
|
|
1758
1785
|
const session = sessions[0];
|
|
1759
1786
|
const actions = db.getSessionActions(session.id);
|
|
1760
|
-
console.log(
|
|
1787
|
+
console.log(import_chalk.default.cyan.bold(`
|
|
1761
1788
|
\u{1F4CB} Session Logs: ${session.id}
|
|
1762
1789
|
`));
|
|
1763
|
-
console.log(
|
|
1764
|
-
console.log(
|
|
1765
|
-
console.log(
|
|
1790
|
+
console.log(import_chalk.default.white(`Status: ${session.status}`));
|
|
1791
|
+
console.log(import_chalk.default.white(`Started: ${session.started_at}`));
|
|
1792
|
+
console.log(import_chalk.default.white(`Actions: ${actions.length}
|
|
1766
1793
|
`));
|
|
1767
1794
|
const limit = parseInt(options.lines);
|
|
1768
1795
|
const displayActions = actions.slice(0, limit);
|
|
1769
1796
|
displayActions.forEach((action) => {
|
|
1770
1797
|
const icon = action.type === "navigate" ? "\u{1F310}" : action.type === "click" ? "\u{1F446}" : action.type === "fill" ? "\u2328\uFE0F" : action.type === "screenshot" ? "\u{1F4F8}" : action.type === "github_issue" ? "\u{1F41B}" : action.type === "kanban_ticket" ? "\u{1F4CB}" : "\u2022";
|
|
1771
|
-
console.log(
|
|
1798
|
+
console.log(import_chalk.default.gray(`[${action.timestamp}]`), icon, import_chalk.default.white(action.description));
|
|
1772
1799
|
if (action.output) {
|
|
1773
|
-
console.log(
|
|
1800
|
+
console.log(import_chalk.default.gray(` \u2192 ${action.output}`));
|
|
1774
1801
|
}
|
|
1775
1802
|
});
|
|
1776
1803
|
console.log("");
|
|
1777
1804
|
});
|
|
1778
1805
|
program.parse();
|
|
1779
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openqa/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Autonomous QA testing agent powered by Orka.js",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/cli/index.
|
|
6
|
+
"main": "./dist/cli/index.cjs",
|
|
7
7
|
"bin": {
|
|
8
|
-
"openqa": "./dist/cli/index.
|
|
8
|
+
"openqa": "./dist/cli/index.cjs"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
package/dist/cli/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../cli/index.ts","../../agent/index.ts","../../database/index.ts","../../agent/config/index.ts","../../agent/tools/browser.ts","../../agent/tools/github.ts","../../agent/tools/kanban.ts","../../agent/webhooks/git-listener.ts","../../agent/specialists/index.ts","../../agent/skills/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { OpenQAAgent } from '../agent/index.js';\nimport { ConfigManager } from '../agent/config/index.js';\nimport { OpenQADatabase } from '../database/index.js';\nimport { spawn } from 'child_process';\nimport { writeFileSync, readFileSync, existsSync, unlinkSync } from 'fs';\nimport { join } from 'path';\nimport chalk from 'chalk';\nimport ora from 'ora';\n\nconst program = new Command();\nconst PID_FILE = './data/openqa.pid';\n\nprogram\n .name('openqa')\n .description('OpenQA - Autonomous QA Testing Agent powered by Orka.js')\n .version('1.0.0');\n\nprogram\n .command('start')\n .description('Start the OpenQA agent and web UI')\n .option('-d, --daemon', 'Run in daemon mode')\n .action(async (options) => {\n const spinner = ora('Starting OpenQA...').start();\n\n try {\n if (existsSync(PID_FILE)) {\n const pid = readFileSync(PID_FILE, 'utf-8').trim();\n try {\n process.kill(parseInt(pid), 0);\n spinner.fail(chalk.red('OpenQA is already running'));\n console.log(chalk.yellow(`PID: ${pid}`));\n console.log(chalk.cyan('Run \"openqa stop\" to stop it first'));\n process.exit(1);\n } catch {\n unlinkSync(PID_FILE);\n }\n }\n\n if (options.daemon) {\n const child = spawn('node', [join(process.cwd(), 'dist/cli/daemon.js')], {\n detached: true,\n stdio: 'ignore'\n });\n child.unref();\n \n writeFileSync(PID_FILE, child.pid!.toString());\n \n spinner.succeed(chalk.green('OpenQA started in daemon mode'));\n console.log(chalk.cyan(`PID: ${child.pid}`));\n } else {\n spinner.succeed(chalk.green('OpenQA started'));\n \n const agent = new OpenQAAgent();\n const config = new ConfigManager();\n const cfg = config.getConfig();\n\n console.log(chalk.cyan('\\n📊 OpenQA Status:'));\n console.log(chalk.white(` Agent: Running`));\n console.log(chalk.white(` Target: ${cfg.saas.url || 'Not configured'}`));\n console.log(chalk.white(` Web UI: http://localhost:${cfg.web.port}`));\n console.log(chalk.white(` DevTools: http://localhost:${cfg.web.port}`));\n console.log(chalk.white(` Kanban: http://localhost:${cfg.web.port}/kanban`));\n console.log(chalk.white(` Config: http://localhost:${cfg.web.port}/config`));\n console.log(chalk.gray('\\nPress Ctrl+C to stop\\n'));\n\n if (cfg.agent.autoStart) {\n await agent.startAutonomous();\n } else {\n console.log(chalk.yellow('Auto-start disabled. Agent is idle.'));\n console.log(chalk.cyan('Set AGENT_AUTO_START=true to enable autonomous mode'));\n }\n }\n } catch (error: any) {\n spinner.fail(chalk.red('Failed to start OpenQA'));\n console.error(chalk.red(error.message));\n process.exit(1);\n }\n });\n\nprogram\n .command('stop')\n .description('Stop the OpenQA agent')\n .action(() => {\n const spinner = ora('Stopping OpenQA...').start();\n\n try {\n if (!existsSync(PID_FILE)) {\n spinner.fail(chalk.red('OpenQA is not running'));\n process.exit(1);\n }\n\n const pid = readFileSync(PID_FILE, 'utf-8').trim();\n \n try {\n process.kill(parseInt(pid), 'SIGTERM');\n unlinkSync(PID_FILE);\n spinner.succeed(chalk.green('OpenQA stopped'));\n } catch (error) {\n spinner.fail(chalk.red('Failed to stop OpenQA'));\n console.error(chalk.red('Process not found. Cleaning up PID file...'));\n unlinkSync(PID_FILE);\n }\n } catch (error: any) {\n spinner.fail(chalk.red('Failed to stop OpenQA'));\n console.error(chalk.red(error.message));\n process.exit(1);\n }\n });\n\nprogram\n .command('status')\n .description('Show OpenQA status')\n .action(() => {\n const config = new ConfigManager();\n const cfg = config.getConfig();\n const db = new OpenQADatabase(cfg.database.path);\n\n console.log(chalk.cyan.bold('\\n📊 OpenQA Status\\n'));\n\n if (existsSync(PID_FILE)) {\n const pid = readFileSync(PID_FILE, 'utf-8').trim();\n try {\n process.kill(parseInt(pid), 0);\n console.log(chalk.green('✓ Agent: Running'));\n console.log(chalk.white(` PID: ${pid}`));\n } catch {\n console.log(chalk.red('✗ Agent: Stopped (stale PID file)'));\n unlinkSync(PID_FILE);\n }\n } else {\n console.log(chalk.red('✗ Agent: Stopped'));\n }\n\n console.log(chalk.cyan('\\n🌐 Web Interfaces:'));\n console.log(chalk.white(` DevTools: http://localhost:${cfg.web.port}`));\n console.log(chalk.white(` Kanban: http://localhost:${cfg.web.port}/kanban`));\n console.log(chalk.white(` Config: http://localhost:${cfg.web.port}/config`));\n\n console.log(chalk.cyan('\\n⚙️ Configuration:'));\n console.log(chalk.white(` LLM Provider: ${cfg.llm.provider}`));\n console.log(chalk.white(` Target SaaS: ${cfg.saas.url || 'Not configured'}`));\n console.log(chalk.white(` GitHub: ${cfg.github?.token ? 'Configured' : 'Not configured'}`));\n console.log(chalk.white(` Test Interval: ${cfg.agent.intervalMs / 1000 / 60} minutes`));\n\n const sessions = db.getRecentSessions(5);\n console.log(chalk.cyan(`\\n📋 Recent Sessions (${sessions.length}):`));\n sessions.forEach(s => {\n const status = s.status === 'completed' ? chalk.green('✓') : s.status === 'failed' ? chalk.red('✗') : chalk.yellow('⟳');\n console.log(chalk.white(` ${status} ${s.id} - ${s.bugs_found} bugs found`));\n });\n\n const bugs = db.getBugsByStatus('open');\n console.log(chalk.cyan(`\\n🐛 Open Bugs: ${bugs.length}`));\n\n const tickets = db.getKanbanTickets();\n const byColumn = {\n backlog: tickets.filter(t => t.column === 'backlog').length,\n 'to-do': tickets.filter(t => t.column === 'to-do').length,\n 'in-progress': tickets.filter(t => t.column === 'in-progress').length,\n done: tickets.filter(t => t.column === 'done').length\n };\n console.log(chalk.cyan('\\n📊 Kanban Board:'));\n console.log(chalk.white(` Backlog: ${byColumn.backlog}`));\n console.log(chalk.white(` To Do: ${byColumn['to-do']}`));\n console.log(chalk.white(` In Progress: ${byColumn['in-progress']}`));\n console.log(chalk.white(` Done: ${byColumn.done}`));\n console.log('');\n });\n\nprogram\n .command('config')\n .description('Manage configuration')\n .argument('[action]', 'Action: get, set, list')\n .argument('[key]', 'Configuration key (e.g., llm.provider)')\n .argument('[value]', 'Configuration value')\n .action((action, key, value) => {\n const config = new ConfigManager();\n\n if (!action || action === 'list') {\n const cfg = config.getConfig();\n console.log(chalk.cyan.bold('\\n⚙️ OpenQA Configuration\\n'));\n console.log(JSON.stringify(cfg, null, 2));\n console.log('');\n return;\n }\n\n if (action === 'get') {\n if (!key) {\n console.error(chalk.red('Error: key is required for \"get\" action'));\n process.exit(1);\n }\n const val = config.get(key);\n console.log(chalk.cyan(`${key}:`), chalk.white(val || 'Not set'));\n return;\n }\n\n if (action === 'set') {\n if (!key || !value) {\n console.error(chalk.red('Error: key and value are required for \"set\" action'));\n process.exit(1);\n }\n config.set(key, value);\n console.log(chalk.green(`✓ Set ${key} = ${value}`));\n return;\n }\n\n console.error(chalk.red(`Unknown action: ${action}`));\n console.log(chalk.cyan('Available actions: get, set, list'));\n process.exit(1);\n });\n\nprogram\n .command('logs')\n .description('Show agent logs')\n .option('-f, --follow', 'Follow log output')\n .option('-n, --lines <number>', 'Number of lines to show', '50')\n .action((options) => {\n const config = new ConfigManager();\n const cfg = config.getConfig();\n const db = new OpenQADatabase(cfg.database.path);\n\n const sessions = db.getRecentSessions(1);\n if (sessions.length === 0) {\n console.log(chalk.yellow('No sessions found'));\n return;\n }\n\n const session = sessions[0];\n const actions = db.getSessionActions(session.id);\n\n console.log(chalk.cyan.bold(`\\n📋 Session Logs: ${session.id}\\n`));\n console.log(chalk.white(`Status: ${session.status}`));\n console.log(chalk.white(`Started: ${session.started_at}`));\n console.log(chalk.white(`Actions: ${actions.length}\\n`));\n\n const limit = parseInt(options.lines);\n const displayActions = actions.slice(0, limit);\n\n displayActions.forEach(action => {\n const icon = action.type === 'navigate' ? '🌐' : \n action.type === 'click' ? '👆' :\n action.type === 'fill' ? '⌨️' :\n action.type === 'screenshot' ? '📸' :\n action.type === 'github_issue' ? '🐛' :\n action.type === 'kanban_ticket' ? '📋' : '•';\n \n console.log(chalk.gray(`[${action.timestamp}]`), icon, chalk.white(action.description));\n if (action.output) {\n console.log(chalk.gray(` → ${action.output}`));\n }\n });\n\n console.log('');\n });\n\nprogram.parse();\n","import { ReActAgent } from '@orka-js/agent';\nimport { OpenAIAdapter } from '@orka-js/openai';\nimport { AnthropicAdapter } from '@orka-js/anthropic';\nimport { SessionMemory } from '@orka-js/memory-store';\nimport { Tracer } from '@orka-js/observability';\nimport { EventEmitter } from 'events';\nimport { OpenQADatabase } from '../database/index.js';\nimport { ConfigManager } from './config/index.js';\nimport { BrowserTools } from './tools/browser.js';\nimport { GitHubTools } from './tools/github.js';\nimport { KanbanTools } from './tools/kanban.js';\nimport { GitListener, GitEvent } from './webhooks/git-listener.js';\nimport { SpecialistAgentManager, AgentType, AgentStatus } from './specialists/index.js';\nimport { SkillManager, Skill } from './skills/index.js';\n\nexport class OpenQAAgent extends EventEmitter {\n private agent: ReActAgent | null = null;\n private db: OpenQADatabase;\n private config: ConfigManager;\n private browserTools: BrowserTools | null = null;\n private sessionId: string = '';\n private isRunning: boolean = false;\n private intervalId: NodeJS.Timeout | null = null;\n \n // New v2 features\n private gitListener: GitListener | null = null;\n private specialistManager: SpecialistAgentManager | null = null;\n private skillManager: SkillManager;\n\n constructor(configPath?: string) {\n super();\n this.config = new ConfigManager(configPath);\n this.db = new OpenQADatabase(this.config.get('database.path') || undefined);\n this.skillManager = new SkillManager(this.db);\n }\n\n private createLLMAdapter() {\n const cfg = this.config.getConfig();\n \n switch (cfg.llm.provider) {\n case 'anthropic':\n return new AnthropicAdapter({\n apiKey: cfg.llm.apiKey || process.env.ANTHROPIC_API_KEY!,\n model: cfg.llm.model || 'claude-3-5-sonnet-20241022'\n });\n case 'openai':\n default:\n return new OpenAIAdapter({\n apiKey: cfg.llm.apiKey || process.env.OPENAI_API_KEY!,\n model: cfg.llm.model || 'gpt-4'\n });\n }\n }\n\n async initialize(triggerType: 'manual' | 'scheduled' | 'merge' | 'pipeline' | 'webhook' = 'manual', triggerData?: any) {\n const cfg = this.config.getConfig();\n this.sessionId = `session_${Date.now()}`;\n\n this.db.createSession(this.sessionId, {\n config: cfg,\n started_at: new Date().toISOString(),\n trigger_type: triggerType,\n trigger_data: triggerData ? JSON.stringify(triggerData) : null\n });\n\n this.browserTools = new BrowserTools(this.db, this.sessionId);\n const githubTools = new GitHubTools(this.db, this.sessionId, cfg.github || {});\n const kanbanTools = new KanbanTools(this.db, this.sessionId);\n\n const allTools = [\n ...this.browserTools.getTools(),\n ...githubTools.getTools(),\n ...kanbanTools.getTools()\n ];\n\n const llm = this.createLLMAdapter();\n const memory = new SessionMemory({ maxMessages: 50 });\n const tracer = new Tracer({ logLevel: 'info' });\n\n // Get enabled skills and generate skill prompt\n const enabledSkills = this.skillManager.getEnabledSkills();\n const skillPrompt = this.skillManager.generateSkillPrompt(enabledSkills);\n\n const agentConfig = {\n goal: \"Test the SaaS application comprehensively and identify bugs\",\n tools: allTools,\n tracer,\n maxIterations: cfg.agent.maxIterations,\n systemPrompt: `You are OpenQA, an autonomous QA testing agent - intelligent and thorough like a senior QA engineer.\n\nYour mission:\n1. **Systematically test the SaaS application** at ${cfg.saas.url}\n2. **Create comprehensive test flows** - think like a real user AND a security expert\n3. **Identify bugs and issues** - UI bugs, console errors, broken flows, UX issues, security vulnerabilities\n4. **Report findings appropriately**:\n - Use create_github_issue for critical bugs requiring developer attention\n - Use create_kanban_ticket for QA tracking, minor issues, or improvements\n - You can create BOTH for critical bugs\n5. **Learn from previous sessions** - avoid repeating the same tests\n6. **Spawn specialist agents** when needed for deep testing (security, forms, etc.)\n\nTesting strategy:\n- Start with core user flows (signup, login, main features)\n- Test edge cases and error handling\n- Check for console errors and network issues\n- Test security (SQL injection, XSS, auth bypass)\n- Test forms thoroughly (validation, edge cases)\n- Take screenshots as evidence\n- Document steps to reproduce clearly\n\nReporting guidelines:\n- **Critical/High severity** → GitHub issue + Kanban ticket\n- **Medium severity** → Kanban ticket (optionally GitHub if it blocks users)\n- **Low severity/Improvements** → Kanban ticket only\n\n${skillPrompt}\n\nAlways provide clear, actionable information with steps to reproduce. Think step by step like a human QA expert.`\n };\n\n this.agent = new ReActAgent(agentConfig, llm, memory);\n\n // Initialize specialist manager\n this.specialistManager = new SpecialistAgentManager(\n this.db,\n this.sessionId,\n { provider: cfg.llm.provider, apiKey: cfg.llm.apiKey || '' },\n this.browserTools\n );\n\n // Forward specialist events\n this.specialistManager.on('agent-created', (status: AgentStatus) => this.emit('specialist-created', status));\n this.specialistManager.on('agent-started', (status: AgentStatus) => this.emit('specialist-started', status));\n this.specialistManager.on('agent-completed', (data: any) => this.emit('specialist-completed', data));\n this.specialistManager.on('agent-failed', (data: any) => this.emit('specialist-failed', data));\n\n console.log(`✅ OpenQA Agent initialized (Session: ${this.sessionId})`);\n }\n\n async runSession() {\n if (!this.agent) {\n await this.initialize();\n }\n\n const cfg = this.config.getConfig();\n console.log(`🚀 Starting test session for ${cfg.saas.url}`);\n\n try {\n const result = await this.agent!.run(\n `Continue testing the application at ${cfg.saas.url}. Review previous findings, create new test scenarios, and report any issues discovered. Focus on areas not yet tested.`\n );\n\n this.db.updateSession(this.sessionId, {\n status: 'completed',\n ended_at: new Date().toISOString()\n });\n\n console.log('✅ Test session completed:', result);\n return result;\n } catch (error: any) {\n console.error('❌ Session error:', error);\n \n this.db.updateSession(this.sessionId, {\n status: 'failed',\n ended_at: new Date().toISOString()\n });\n\n throw error;\n } finally {\n if (this.browserTools) {\n await this.browserTools.close();\n }\n }\n }\n\n async startAutonomous() {\n if (this.isRunning) {\n console.log('⚠️ Agent is already running');\n return;\n }\n\n this.isRunning = true;\n const cfg = this.config.getConfig();\n \n console.log(`🤖 OpenQA Agent starting in autonomous mode`);\n console.log(`📍 Target: ${cfg.saas.url}`);\n console.log(`⏱️ Interval: ${cfg.agent.intervalMs}ms (${cfg.agent.intervalMs / 1000 / 60} minutes)`);\n\n // Start Git listener if configured\n await this.startGitListener();\n\n const runLoop = async () => {\n if (!this.isRunning) return;\n\n try {\n await this.runSession();\n } catch (error) {\n console.error('Session failed, will retry on next interval');\n }\n\n if (this.isRunning) {\n this.sessionId = `session_${Date.now()}`;\n this.agent = null;\n this.browserTools = null;\n \n this.intervalId = setTimeout(runLoop, cfg.agent.intervalMs);\n }\n };\n\n await runLoop();\n }\n\n stop() {\n console.log('🛑 Stopping OpenQA Agent...');\n this.isRunning = false;\n \n if (this.intervalId) {\n clearTimeout(this.intervalId);\n this.intervalId = null;\n }\n\n if (this.gitListener) {\n this.gitListener.stop();\n this.gitListener = null;\n }\n\n if (this.specialistManager) {\n this.specialistManager.stopAll();\n }\n\n if (this.browserTools) {\n this.browserTools.close();\n }\n }\n\n // Git integration\n private async startGitListener() {\n const cfg = this.config.getConfig();\n \n // Try GitHub first\n if (cfg.github?.token && cfg.github?.owner && cfg.github?.repo) {\n this.gitListener = new GitListener({\n provider: 'github',\n token: cfg.github.token,\n owner: cfg.github.owner,\n repo: cfg.github.repo,\n branch: 'main',\n pollIntervalMs: 60000\n });\n }\n // Try GitLab\n else if (this.config.get('gitlab.token') && this.config.get('gitlab.project')) {\n const [owner, repo] = (this.config.get('gitlab.project') || '').split('/');\n this.gitListener = new GitListener({\n provider: 'gitlab',\n token: this.config.get('gitlab.token') || '',\n owner,\n repo,\n branch: 'main',\n pollIntervalMs: 60000,\n gitlabUrl: this.config.get('gitlab.url') || 'https://gitlab.com'\n });\n }\n\n if (this.gitListener) {\n // Listen for merges to trigger tests\n this.gitListener.on('merge', async (event: GitEvent) => {\n console.log(`🔀 Merge detected! Starting test session...`);\n this.emit('git-merge', event);\n \n // Reset and run new session\n this.sessionId = `session_${Date.now()}`;\n this.agent = null;\n this.browserTools = null;\n await this.runSession();\n });\n\n // Listen for successful pipelines\n this.gitListener.on('pipeline-success', async (event: GitEvent) => {\n console.log(`✅ Pipeline success! Starting test session...`);\n this.emit('git-pipeline-success', event);\n \n // Reset and run new session\n this.sessionId = `session_${Date.now()}`;\n this.agent = null;\n this.browserTools = null;\n await this.runSession();\n });\n\n await this.gitListener.start();\n console.log(`🔗 Git listener started for ${this.gitListener ? 'repository' : 'none'}`);\n }\n }\n\n // Specialist agents management\n async runSecurityScan(): Promise<void> {\n if (!this.specialistManager) {\n await this.initialize();\n }\n const cfg = this.config.getConfig();\n await this.specialistManager!.runSecuritySuite(cfg.saas.url);\n }\n\n async runSpecialist(type: AgentType): Promise<void> {\n if (!this.specialistManager) {\n await this.initialize();\n }\n const cfg = this.config.getConfig();\n const agentId = this.specialistManager!.createSpecialist(type);\n await this.specialistManager!.runSpecialist(agentId, cfg.saas.url);\n }\n\n getSpecialistStatuses(): AgentStatus[] {\n return this.specialistManager?.getAllStatuses() || [];\n }\n\n // Skills management\n getSkills(): Skill[] {\n return this.skillManager.getAllSkills();\n }\n\n createSkill(data: Omit<Skill, 'id' | 'createdAt' | 'updatedAt'>): Skill {\n return this.skillManager.createSkill(data);\n }\n\n updateSkill(id: string, updates: Partial<Skill>): Skill | null {\n return this.skillManager.updateSkill(id, updates);\n }\n\n deleteSkill(id: string): boolean {\n return this.skillManager.deleteSkill(id);\n }\n\n toggleSkill(id: string): Skill | null {\n return this.skillManager.toggleSkill(id);\n }\n\n getStatus() {\n return {\n isRunning: this.isRunning,\n sessionId: this.sessionId,\n config: this.config.getConfig(),\n gitListenerActive: !!this.gitListener,\n specialists: this.getSpecialistStatuses(),\n skills: this.skillManager.getEnabledSkills().length\n };\n }\n}\n","import Database from 'better-sqlite3';\nimport { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { mkdirSync } from 'fs';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nexport interface TestSession {\n id: string;\n started_at: string;\n ended_at?: string;\n status: 'running' | 'completed' | 'failed';\n total_actions: number;\n bugs_found: number;\n metadata?: string;\n}\n\nexport interface Action {\n id: string;\n session_id: string;\n timestamp: string;\n type: string;\n description: string;\n input?: string;\n output?: string;\n screenshot_path?: string;\n}\n\nexport interface Bug {\n id: string;\n session_id: string;\n title: string;\n description: string;\n severity: 'low' | 'medium' | 'high' | 'critical';\n status: 'open' | 'in-progress' | 'resolved' | 'closed';\n github_issue_url?: string;\n screenshot_path?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface KanbanTicket {\n id: string;\n bug_id?: string;\n title: string;\n description: string;\n priority: 'low' | 'medium' | 'high' | 'critical';\n column: 'backlog' | 'to-do' | 'in-progress' | 'done';\n tags?: string;\n screenshot_url?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport class OpenQADatabase {\n private db: Database.Database;\n\n constructor(dbPath: string = './data/openqa.db') {\n const dir = dirname(dbPath);\n mkdirSync(dir, { recursive: true });\n\n this.db = new Database(dbPath);\n this.initialize();\n }\n\n private initialize() {\n const schema = readFileSync(join(__dirname, 'schema.sql'), 'utf-8');\n this.db.exec(schema);\n }\n\n getConfig(key: string): string | null {\n const row = this.db.prepare('SELECT value FROM config WHERE key = ?').get(key) as { value: string } | undefined;\n return row?.value || null;\n }\n\n setConfig(key: string, value: string) {\n this.db.prepare('INSERT OR REPLACE INTO config (key, value, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)').run(key, value);\n }\n\n getAllConfig(): Record<string, string> {\n const rows = this.db.prepare('SELECT key, value FROM config').all() as { key: string; value: string }[];\n return Object.fromEntries(rows.map(r => [r.key, r.value]));\n }\n\n createSession(id: string, metadata?: any): TestSession {\n this.db.prepare('INSERT INTO test_sessions (id, status, metadata) VALUES (?, ?, ?)').run(\n id,\n 'running',\n metadata ? JSON.stringify(metadata) : null\n );\n return this.getSession(id)!;\n }\n\n getSession(id: string): TestSession | null {\n return this.db.prepare('SELECT * FROM test_sessions WHERE id = ?').get(id) as TestSession | null;\n }\n\n updateSession(id: string, updates: Partial<TestSession>) {\n const fields = Object.keys(updates).map(k => `${k} = ?`).join(', ');\n const values = [...Object.values(updates), id];\n this.db.prepare(`UPDATE test_sessions SET ${fields} WHERE id = ?`).run(...values);\n }\n\n getRecentSessions(limit: number = 10): TestSession[] {\n return this.db.prepare('SELECT * FROM test_sessions ORDER BY started_at DESC LIMIT ?').all(limit) as TestSession[];\n }\n\n createAction(action: Omit<Action, 'id' | 'timestamp'>): Action {\n const id = `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.db.prepare('INSERT INTO actions (id, session_id, type, description, input, output, screenshot_path) VALUES (?, ?, ?, ?, ?, ?, ?)').run(\n id,\n action.session_id,\n action.type,\n action.description,\n action.input || null,\n action.output || null,\n action.screenshot_path || null\n );\n return this.db.prepare('SELECT * FROM actions WHERE id = ?').get(id) as Action;\n }\n\n getSessionActions(sessionId: string): Action[] {\n return this.db.prepare('SELECT * FROM actions WHERE session_id = ? ORDER BY timestamp DESC').all(sessionId) as Action[];\n }\n\n createBug(bug: Omit<Bug, 'id' | 'created_at' | 'updated_at'>): Bug {\n const id = `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.db.prepare('INSERT INTO bugs (id, session_id, title, description, severity, status, github_issue_url, screenshot_path) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(\n id,\n bug.session_id,\n bug.title,\n bug.description,\n bug.severity,\n bug.status,\n bug.github_issue_url || null,\n bug.screenshot_path || null\n );\n return this.db.prepare('SELECT * FROM bugs WHERE id = ?').get(id) as Bug;\n }\n\n updateBug(id: string, updates: Partial<Bug>) {\n const fields = Object.keys(updates).map(k => `${k} = ?`).join(', ');\n const values = [...Object.values(updates), id];\n this.db.prepare(`UPDATE bugs SET ${fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(...values);\n }\n\n getAllBugs(): Bug[] {\n return this.db.prepare('SELECT * FROM bugs ORDER BY created_at DESC').all() as Bug[];\n }\n\n getBugsByStatus(status: Bug['status']): Bug[] {\n return this.db.prepare('SELECT * FROM bugs WHERE status = ? ORDER BY created_at DESC').all(status) as Bug[];\n }\n\n createKanbanTicket(ticket: Omit<KanbanTicket, 'id' | 'created_at' | 'updated_at'>): KanbanTicket {\n const id = `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.db.prepare('INSERT INTO kanban_tickets (id, bug_id, title, description, priority, column, tags, screenshot_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(\n id,\n ticket.bug_id || null,\n ticket.title,\n ticket.description,\n ticket.priority,\n ticket.column,\n ticket.tags || null,\n ticket.screenshot_url || null\n );\n return this.db.prepare('SELECT * FROM kanban_tickets WHERE id = ?').get(id) as KanbanTicket;\n }\n\n updateKanbanTicket(id: string, updates: Partial<KanbanTicket>) {\n const fields = Object.keys(updates).map(k => `${k} = ?`).join(', ');\n const values = [...Object.values(updates), id];\n this.db.prepare(`UPDATE kanban_tickets SET ${fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(...values);\n }\n\n getKanbanTickets(): KanbanTicket[] {\n return this.db.prepare('SELECT * FROM kanban_tickets ORDER BY created_at DESC').all() as KanbanTicket[];\n }\n\n getKanbanTicketsByColumn(column: KanbanTicket['column']): KanbanTicket[] {\n return this.db.prepare('SELECT * FROM kanban_tickets WHERE column = ? ORDER BY created_at DESC').all(column) as KanbanTicket[];\n }\n\n close() {\n this.db.close();\n }\n}\n","import { config as dotenvConfig } from 'dotenv';\nimport { OpenQADatabase } from '../../database/index.js';\n\ndotenvConfig();\n\nexport interface OpenQAConfig {\n llm: {\n provider: 'openai' | 'anthropic' | 'ollama';\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n saas: {\n url: string;\n authType: 'none' | 'basic' | 'session';\n username?: string;\n password?: string;\n };\n github?: {\n token: string;\n owner: string;\n repo: string;\n };\n agent: {\n intervalMs: number;\n maxIterations: number;\n autoStart: boolean;\n };\n web: {\n port: number;\n host: string;\n };\n database: {\n path: string;\n };\n notifications?: {\n slack?: string;\n discord?: string;\n };\n}\n\nexport class ConfigManager {\n private db: OpenQADatabase;\n private envConfig: OpenQAConfig;\n\n constructor(dbPath?: string) {\n this.db = new OpenQADatabase(dbPath || process.env.DB_PATH || './data/openqa.db');\n this.envConfig = this.loadFromEnv();\n }\n\n private loadFromEnv(): OpenQAConfig {\n return {\n llm: {\n provider: (process.env.LLM_PROVIDER as any) || 'openai',\n apiKey: process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY,\n model: process.env.LLM_MODEL,\n baseUrl: process.env.OLLAMA_BASE_URL\n },\n saas: {\n url: process.env.SAAS_URL || '',\n authType: (process.env.SAAS_AUTH_TYPE as any) || 'none',\n username: process.env.SAAS_USERNAME,\n password: process.env.SAAS_PASSWORD\n },\n github: process.env.GITHUB_TOKEN ? {\n token: process.env.GITHUB_TOKEN,\n owner: process.env.GITHUB_OWNER || '',\n repo: process.env.GITHUB_REPO || ''\n } : undefined,\n agent: {\n intervalMs: parseInt(process.env.AGENT_INTERVAL_MS || '3600000'),\n maxIterations: parseInt(process.env.AGENT_MAX_ITERATIONS || '20'),\n autoStart: process.env.AGENT_AUTO_START === 'true'\n },\n web: {\n port: parseInt(process.env.WEB_PORT || '3000'),\n host: process.env.WEB_HOST || '0.0.0.0'\n },\n database: {\n path: process.env.DB_PATH || './data/openqa.db'\n },\n notifications: {\n slack: process.env.SLACK_WEBHOOK_URL,\n discord: process.env.DISCORD_WEBHOOK_URL\n }\n };\n }\n\n get(key: string): string | null {\n const dbValue = this.db.getConfig(key);\n if (dbValue) return dbValue;\n\n const keys = key.split('.');\n let value: any = this.envConfig;\n for (const k of keys) {\n value = value?.[k];\n }\n return value?.toString() || null;\n }\n\n set(key: string, value: string) {\n this.db.setConfig(key, value);\n }\n\n getAll(): OpenQAConfig {\n const dbConfig = this.db.getAllConfig();\n const merged = { ...this.envConfig };\n\n for (const [key, value] of Object.entries(dbConfig)) {\n const keys = key.split('.');\n let obj: any = merged;\n for (let i = 0; i < keys.length - 1; i++) {\n if (!obj[keys[i]]) obj[keys[i]] = {};\n obj = obj[keys[i]];\n }\n obj[keys[keys.length - 1]] = value;\n }\n\n return merged;\n }\n\n getConfig(): OpenQAConfig {\n return this.getAll();\n }\n}\n","import { chromium, Browser, Page } from 'playwright';\nimport { OpenQADatabase } from '../../database/index.js';\nimport { mkdirSync } from 'fs';\nimport { join } from 'path';\n\nexport class BrowserTools {\n private browser: Browser | null = null;\n private page: Page | null = null;\n private db: OpenQADatabase;\n private sessionId: string;\n private screenshotDir: string = './data/screenshots';\n\n constructor(db: OpenQADatabase, sessionId: string) {\n this.db = db;\n this.sessionId = sessionId;\n mkdirSync(this.screenshotDir, { recursive: true });\n }\n\n async initialize() {\n this.browser = await chromium.launch({ headless: true });\n const context = await this.browser.newContext({\n viewport: { width: 1920, height: 1080 },\n userAgent: 'OpenQA/1.0 (Automated Testing Agent)'\n });\n this.page = await context.newPage();\n }\n\n getTools() {\n return [\n {\n name: 'navigate_to_page',\n description: 'Navigate to a specific URL in the application',\n parameters: {\n type: 'object',\n properties: {\n url: { type: 'string', description: 'The URL to navigate to' }\n },\n required: ['url']\n },\n execute: async ({ url }: { url: string }) => {\n if (!this.page) await this.initialize();\n \n try {\n await this.page!.goto(url, { waitUntil: 'networkidle' });\n const title = await this.page!.title();\n \n this.db.createAction({\n session_id: this.sessionId,\n type: 'navigate',\n description: `Navigated to ${url}`,\n input: url,\n output: `Page title: ${title}`\n });\n \n return `Successfully navigated to ${url}. Page title: \"${title}\"`;\n } catch (error: any) {\n return `Failed to navigate: ${error.message}`;\n }\n }\n },\n {\n name: 'click_element',\n description: 'Click on an element using a CSS selector',\n parameters: {\n type: 'object',\n properties: {\n selector: { type: 'string', description: 'CSS selector of the element to click' }\n },\n required: ['selector']\n },\n execute: async ({ selector }: { selector: string }) => {\n if (!this.page) return 'Browser not initialized. Navigate to a page first.';\n \n try {\n await this.page.click(selector, { timeout: 5000 });\n \n this.db.createAction({\n session_id: this.sessionId,\n type: 'click',\n description: `Clicked element: ${selector}`,\n input: selector\n });\n \n return `Successfully clicked element: ${selector}`;\n } catch (error: any) {\n return `Failed to click element: ${error.message}`;\n }\n }\n },\n {\n name: 'fill_input',\n description: 'Fill an input field with text',\n parameters: {\n type: 'object',\n properties: {\n selector: { type: 'string', description: 'CSS selector of the input field' },\n text: { type: 'string', description: 'Text to fill in the input' }\n },\n required: ['selector', 'text']\n },\n execute: async ({ selector, text }: { selector: string; text: string }) => {\n if (!this.page) return 'Browser not initialized. Navigate to a page first.';\n \n try {\n await this.page.fill(selector, text);\n \n this.db.createAction({\n session_id: this.sessionId,\n type: 'fill',\n description: `Filled input ${selector}`,\n input: `${selector} = ${text}`\n });\n \n return `Successfully filled input ${selector} with text`;\n } catch (error: any) {\n return `Failed to fill input: ${error.message}`;\n }\n }\n },\n {\n name: 'take_screenshot',\n description: 'Take a screenshot of the current page for evidence',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Name for the screenshot file' }\n },\n required: ['name']\n },\n execute: async ({ name }: { name: string }) => {\n if (!this.page) return 'Browser not initialized. Navigate to a page first.';\n \n try {\n const filename = `${Date.now()}_${name}.png`;\n const path = join(this.screenshotDir, filename);\n await this.page.screenshot({ path, fullPage: true });\n \n this.db.createAction({\n session_id: this.sessionId,\n type: 'screenshot',\n description: `Screenshot: ${name}`,\n screenshot_path: path\n });\n \n return `Screenshot saved: ${path}`;\n } catch (error: any) {\n return `Failed to take screenshot: ${error.message}`;\n }\n }\n },\n {\n name: 'get_page_content',\n description: 'Get the text content of the current page',\n parameters: {\n type: 'object',\n properties: {}\n },\n execute: async () => {\n if (!this.page) return 'Browser not initialized. Navigate to a page first.';\n \n try {\n const content = await this.page.textContent('body');\n return content?.slice(0, 1000) || 'No content found';\n } catch (error: any) {\n return `Failed to get content: ${error.message}`;\n }\n }\n },\n {\n name: 'check_console_errors',\n description: 'Check for JavaScript console errors on the page',\n parameters: {\n type: 'object',\n properties: {}\n },\n execute: async () => {\n if (!this.page) return 'Browser not initialized. Navigate to a page first.';\n \n const errors: string[] = [];\n this.page.on('console', msg => {\n if (msg.type() === 'error') {\n errors.push(msg.text());\n }\n });\n \n await this.page.waitForTimeout(2000);\n \n if (errors.length > 0) {\n return `Found ${errors.length} console errors:\\n${errors.join('\\n')}`;\n }\n return 'No console errors detected';\n }\n }\n ];\n }\n\n async close() {\n if (this.browser) {\n await this.browser.close();\n this.browser = null;\n this.page = null;\n }\n }\n}\n","import { Octokit } from '@octokit/rest';\nimport { OpenQADatabase } from '../../database/index.js';\n\nexport class GitHubTools {\n private octokit: Octokit | null = null;\n private db: OpenQADatabase;\n private sessionId: string;\n private config: { token?: string; owner?: string; repo?: string };\n\n constructor(db: OpenQADatabase, sessionId: string, config: { token?: string; owner?: string; repo?: string }) {\n this.db = db;\n this.sessionId = sessionId;\n this.config = config;\n \n if (config.token) {\n this.octokit = new Octokit({ auth: config.token });\n }\n }\n\n getTools() {\n return [\n {\n name: 'create_github_issue',\n description: 'Create a GitHub issue when a critical bug is found. Use this for bugs that require developer attention.',\n parameters: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Issue title (concise and descriptive)' },\n body: { type: 'string', description: 'Detailed description with steps to reproduce' },\n severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'Bug severity' },\n labels: { type: 'array', items: { type: 'string' }, description: 'Labels for the issue' },\n screenshot_path: { type: 'string', description: 'Path to screenshot evidence' }\n },\n required: ['title', 'body', 'severity']\n },\n execute: async ({ title, body, severity, labels = [], screenshot_path }: any) => {\n if (!this.octokit || !this.config.owner || !this.config.repo) {\n return 'GitHub not configured. Please set GITHUB_TOKEN, GITHUB_OWNER, and GITHUB_REPO.';\n }\n\n try {\n const severityLabel = `severity: ${severity}`;\n const allLabels = ['automated-qa', severityLabel, ...labels];\n\n const issueBody = `## 🤖 Automated QA Report\n\n${body}\n\n---\n\n**Severity:** ${severity.toUpperCase()}\n**Detected by:** OpenQA Agent\n**Session ID:** ${this.sessionId}\n${screenshot_path ? `**Screenshot:** ${screenshot_path}` : ''}\n\n*This issue was automatically created by OpenQA during automated testing.*`;\n\n const issue = await this.octokit.rest.issues.create({\n owner: this.config.owner,\n repo: this.config.repo,\n title: `[QA] ${title}`,\n body: issueBody,\n labels: allLabels\n });\n\n this.db.createAction({\n session_id: this.sessionId,\n type: 'github_issue',\n description: `Created GitHub issue: ${title}`,\n input: JSON.stringify({ title, severity }),\n output: issue.data.html_url\n });\n\n const bug = this.db.createBug({\n session_id: this.sessionId,\n title,\n description: body,\n severity: severity as any,\n status: 'open',\n github_issue_url: issue.data.html_url,\n screenshot_path\n });\n\n return `✅ GitHub issue created successfully!\\nURL: ${issue.data.html_url}\\nIssue #${issue.data.number}`;\n } catch (error: any) {\n return `❌ Failed to create GitHub issue: ${error.message}`;\n }\n }\n }\n ];\n }\n}\n","import { OpenQADatabase } from '../../database/index.js';\n\nexport class KanbanTools {\n private db: OpenQADatabase;\n private sessionId: string;\n\n constructor(db: OpenQADatabase, sessionId: string) {\n this.db = db;\n this.sessionId = sessionId;\n }\n\n getTools() {\n return [\n {\n name: 'create_kanban_ticket',\n description: 'Create a ticket on the internal Kanban board for QA tracking. Use this for bugs, improvements, or test findings.',\n parameters: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Ticket title' },\n description: { type: 'string', description: 'Detailed description' },\n priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'Ticket priority' },\n column: { type: 'string', enum: ['backlog', 'to-do', 'in-progress', 'done'], description: 'Kanban column' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Tags for categorization' },\n screenshot_path: { type: 'string', description: 'Path to screenshot evidence' }\n },\n required: ['title', 'description', 'priority']\n },\n execute: async ({ title, description, priority, column = 'to-do', tags = [], screenshot_path }: any) => {\n try {\n const allTags = ['automated-qa', ...tags];\n \n const ticket = this.db.createKanbanTicket({\n title,\n description,\n priority: priority as any,\n column: column as any,\n tags: JSON.stringify(allTags),\n screenshot_url: screenshot_path\n });\n\n this.db.createAction({\n session_id: this.sessionId,\n type: 'kanban_ticket',\n description: `Created Kanban ticket: ${title}`,\n input: JSON.stringify({ title, priority, column }),\n output: ticket.id\n });\n\n return `✅ Kanban ticket created successfully!\\nID: ${ticket.id}\\nColumn: ${column}\\nPriority: ${priority}`;\n } catch (error: any) {\n return `❌ Failed to create Kanban ticket: ${error.message}`;\n }\n }\n },\n {\n name: 'update_kanban_ticket',\n description: 'Update an existing Kanban ticket (move columns, change priority, etc.)',\n parameters: {\n type: 'object',\n properties: {\n ticket_id: { type: 'string', description: 'ID of the ticket to update' },\n column: { type: 'string', enum: ['backlog', 'to-do', 'in-progress', 'done'], description: 'New column' },\n priority: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], description: 'New priority' }\n },\n required: ['ticket_id']\n },\n execute: async ({ ticket_id, column, priority }: any) => {\n try {\n const updates: any = {};\n if (column) updates.column = column;\n if (priority) updates.priority = priority;\n\n this.db.updateKanbanTicket(ticket_id, updates);\n\n return `✅ Kanban ticket ${ticket_id} updated successfully!`;\n } catch (error: any) {\n return `❌ Failed to update Kanban ticket: ${error.message}`;\n }\n }\n },\n {\n name: 'get_kanban_board',\n description: 'Get all tickets from the Kanban board to see current status',\n parameters: {\n type: 'object',\n properties: {}\n },\n execute: async () => {\n try {\n const tickets = this.db.getKanbanTickets();\n \n const byColumn = {\n backlog: tickets.filter(t => t.column === 'backlog'),\n 'to-do': tickets.filter(t => t.column === 'to-do'),\n 'in-progress': tickets.filter(t => t.column === 'in-progress'),\n done: tickets.filter(t => t.column === 'done')\n };\n\n const summary = `\n📊 Kanban Board Status:\n- Backlog: ${byColumn.backlog.length} tickets\n- To Do: ${byColumn['to-do'].length} tickets\n- In Progress: ${byColumn['in-progress'].length} tickets\n- Done: ${byColumn.done.length} tickets\n\nTotal: ${tickets.length} tickets\n `.trim();\n\n return summary;\n } catch (error: any) {\n return `❌ Failed to get Kanban board: ${error.message}`;\n }\n }\n }\n ];\n }\n}\n","import { EventEmitter } from 'events';\nimport { Octokit } from '@octokit/rest';\n\nexport interface GitEvent {\n type: 'merge' | 'push' | 'pipeline_success' | 'pipeline_failure' | 'tag';\n provider: 'github' | 'gitlab';\n branch: string;\n commit: string;\n author: string;\n message: string;\n timestamp: Date;\n pipelineId?: string;\n pipelineStatus?: string;\n changedFiles?: string[];\n}\n\nexport interface GitListenerConfig {\n provider: 'github' | 'gitlab';\n token: string;\n owner: string;\n repo: string;\n branch?: string;\n pollIntervalMs?: number;\n gitlabUrl?: string;\n}\n\ninterface GitLabCommit {\n id: string;\n author_name: string;\n message: string;\n created_at: string;\n parent_ids?: string[];\n}\n\ninterface GitLabPipeline {\n id: number;\n status: string;\n ref: string;\n sha: string;\n created_at: string;\n updated_at: string;\n user?: {\n name: string;\n username: string;\n };\n}\n\ninterface GitLabWebhook {\n id: number;\n url: string;\n push_events: boolean;\n merge_requests_events: boolean;\n pipeline_events: boolean;\n}\n\nexport class GitListener extends EventEmitter {\n private config: GitListenerConfig;\n private octokit: Octokit | null = null;\n private lastCommitSha: string | null = null;\n private lastPipelineId: string | null = null;\n private pollInterval: NodeJS.Timeout | null = null;\n private isRunning: boolean = false;\n\n constructor(config: GitListenerConfig) {\n super();\n this.config = {\n branch: 'main',\n pollIntervalMs: 60000,\n gitlabUrl: 'https://gitlab.com',\n ...config\n };\n\n if (config.provider === 'github' && config.token) {\n this.octokit = new Octokit({ auth: config.token });\n }\n }\n\n async start() {\n if (this.isRunning) return;\n this.isRunning = true;\n\n console.log(`🔗 GitListener started for ${this.config.provider}/${this.config.owner}/${this.config.repo}`);\n \n await this.checkInitialState();\n \n this.pollInterval = setInterval(() => {\n this.poll().catch(console.error);\n }, this.config.pollIntervalMs);\n }\n\n stop() {\n this.isRunning = false;\n if (this.pollInterval) {\n clearInterval(this.pollInterval);\n this.pollInterval = null;\n }\n console.log('🔗 GitListener stopped');\n }\n\n private async checkInitialState() {\n try {\n if (this.config.provider === 'github') {\n await this.checkGitHubState();\n } else {\n await this.checkGitLabState();\n }\n } catch (error) {\n console.error('Failed to check initial state:', error);\n }\n }\n\n private async poll() {\n try {\n if (this.config.provider === 'github') {\n await this.pollGitHub();\n } else {\n await this.pollGitLab();\n }\n } catch (error) {\n console.error('Poll error:', error);\n }\n }\n\n private async checkGitHubState() {\n if (!this.octokit) return;\n\n const { data: commits } = await this.octokit.repos.listCommits({\n owner: this.config.owner,\n repo: this.config.repo,\n sha: this.config.branch,\n per_page: 1\n });\n\n if (commits.length > 0) {\n this.lastCommitSha = commits[0].sha;\n }\n\n try {\n const { data: runs } = await this.octokit.actions.listWorkflowRunsForRepo({\n owner: this.config.owner,\n repo: this.config.repo,\n branch: this.config.branch,\n per_page: 1\n });\n\n if (runs.workflow_runs.length > 0) {\n this.lastPipelineId = runs.workflow_runs[0].id.toString();\n }\n } catch {\n }\n }\n\n private async pollGitHub() {\n if (!this.octokit) return;\n\n const { data: commits } = await this.octokit.repos.listCommits({\n owner: this.config.owner,\n repo: this.config.repo,\n sha: this.config.branch,\n per_page: 5\n });\n\n for (const commit of commits) {\n if (this.lastCommitSha && commit.sha === this.lastCommitSha) break;\n\n const isMerge = commit.parents && commit.parents.length > 1;\n \n const event: GitEvent = {\n type: isMerge ? 'merge' : 'push',\n provider: 'github',\n branch: this.config.branch!,\n commit: commit.sha,\n author: commit.commit.author?.name || 'unknown',\n message: commit.commit.message,\n timestamp: new Date(commit.commit.author?.date || Date.now())\n };\n\n this.emit('git-event', event);\n \n if (isMerge) {\n this.emit('merge', event);\n console.log(`🔀 Merge detected on ${this.config.branch}: ${commit.sha.slice(0, 7)}`);\n }\n }\n\n if (commits.length > 0) {\n this.lastCommitSha = commits[0].sha;\n }\n\n try {\n const { data: runs } = await this.octokit.actions.listWorkflowRunsForRepo({\n owner: this.config.owner,\n repo: this.config.repo,\n branch: this.config.branch,\n per_page: 5\n });\n\n for (const run of runs.workflow_runs) {\n if (this.lastPipelineId && run.id.toString() === this.lastPipelineId) break;\n\n if (run.status === 'completed') {\n const event: GitEvent = {\n type: run.conclusion === 'success' ? 'pipeline_success' : 'pipeline_failure',\n provider: 'github',\n branch: this.config.branch!,\n commit: run.head_sha,\n author: run.actor?.login || 'unknown',\n message: run.name || '',\n timestamp: new Date(run.updated_at || Date.now()),\n pipelineId: run.id.toString(),\n pipelineStatus: run.conclusion || undefined\n };\n\n this.emit('git-event', event);\n \n if (run.conclusion === 'success') {\n this.emit('pipeline-success', event);\n console.log(`✅ Pipeline success: ${run.name} (${run.id})`);\n } else {\n this.emit('pipeline-failure', event);\n console.log(`❌ Pipeline failure: ${run.name} (${run.id})`);\n }\n }\n }\n\n if (runs.workflow_runs.length > 0) {\n this.lastPipelineId = runs.workflow_runs[0].id.toString();\n }\n } catch {\n }\n }\n\n private async checkGitLabState() {\n const headers = { 'PRIVATE-TOKEN': this.config.token };\n const projectPath = encodeURIComponent(`${this.config.owner}/${this.config.repo}`);\n const baseUrl = this.config.gitlabUrl;\n\n try {\n const commitsRes = await fetch(\n `${baseUrl}/api/v4/projects/${projectPath}/repository/commits?ref_name=${this.config.branch}&per_page=1`,\n { headers }\n );\n const commits = await commitsRes.json() as GitLabCommit[];\n if (commits.length > 0) {\n this.lastCommitSha = commits[0].id;\n }\n\n const pipelinesRes = await fetch(\n `${baseUrl}/api/v4/projects/${projectPath}/pipelines?ref=${this.config.branch}&per_page=1`,\n { headers }\n );\n const pipelines = await pipelinesRes.json() as GitLabPipeline[];\n if (pipelines.length > 0) {\n this.lastPipelineId = pipelines[0].id.toString();\n }\n } catch (error) {\n console.error('GitLab initial state error:', error);\n }\n }\n\n private async pollGitLab() {\n const headers = { 'PRIVATE-TOKEN': this.config.token };\n const projectPath = encodeURIComponent(`${this.config.owner}/${this.config.repo}`);\n const baseUrl = this.config.gitlabUrl;\n\n try {\n const commitsRes = await fetch(\n `${baseUrl}/api/v4/projects/${projectPath}/repository/commits?ref_name=${this.config.branch}&per_page=5`,\n { headers }\n );\n const commits = await commitsRes.json() as GitLabCommit[];\n\n for (const commit of commits) {\n if (this.lastCommitSha && commit.id === this.lastCommitSha) break;\n\n const isMerge = commit.parent_ids && commit.parent_ids.length > 1;\n\n const event: GitEvent = {\n type: isMerge ? 'merge' : 'push',\n provider: 'gitlab',\n branch: this.config.branch!,\n commit: commit.id,\n author: commit.author_name,\n message: commit.message,\n timestamp: new Date(commit.created_at)\n };\n\n this.emit('git-event', event);\n \n if (isMerge) {\n this.emit('merge', event);\n console.log(`🔀 Merge detected on ${this.config.branch}: ${commit.id.slice(0, 7)}`);\n }\n }\n\n if (commits.length > 0) {\n this.lastCommitSha = commits[0].id;\n }\n\n const pipelinesRes = await fetch(\n `${baseUrl}/api/v4/projects/${projectPath}/pipelines?ref=${this.config.branch}&per_page=5`,\n { headers }\n );\n const pipelines = await pipelinesRes.json() as GitLabPipeline[];\n\n for (const pipeline of pipelines) {\n if (this.lastPipelineId && pipeline.id.toString() === this.lastPipelineId) break;\n\n if (pipeline.status === 'success' || pipeline.status === 'failed') {\n const event: GitEvent = {\n type: pipeline.status === 'success' ? 'pipeline_success' : 'pipeline_failure',\n provider: 'gitlab',\n branch: this.config.branch!,\n commit: pipeline.sha,\n author: pipeline.user?.name || 'unknown',\n message: `Pipeline #${pipeline.id}`,\n timestamp: new Date(pipeline.updated_at),\n pipelineId: pipeline.id.toString(),\n pipelineStatus: pipeline.status\n };\n\n this.emit('git-event', event);\n \n if (pipeline.status === 'success') {\n this.emit('pipeline-success', event);\n console.log(`✅ Pipeline success: #${pipeline.id}`);\n } else {\n this.emit('pipeline-failure', event);\n console.log(`❌ Pipeline failure: #${pipeline.id}`);\n }\n }\n }\n\n if (pipelines.length > 0) {\n this.lastPipelineId = pipelines[0].id.toString();\n }\n } catch (error) {\n console.error('GitLab poll error:', error);\n }\n }\n\n async setupWebhook(webhookUrl: string): Promise<string> {\n if (this.config.provider === 'github') {\n return this.setupGitHubWebhook(webhookUrl);\n } else {\n return this.setupGitLabWebhook(webhookUrl);\n }\n }\n\n private async setupGitHubWebhook(webhookUrl: string): Promise<string> {\n if (!this.octokit) throw new Error('GitHub not configured');\n\n const { data } = await this.octokit.repos.createWebhook({\n owner: this.config.owner,\n repo: this.config.repo,\n config: {\n url: webhookUrl,\n content_type: 'json'\n },\n events: ['push', 'pull_request', 'workflow_run']\n });\n\n return data.id.toString();\n }\n\n private async setupGitLabWebhook(webhookUrl: string): Promise<string> {\n const headers = { \n 'PRIVATE-TOKEN': this.config.token,\n 'Content-Type': 'application/json'\n };\n const projectPath = encodeURIComponent(`${this.config.owner}/${this.config.repo}`);\n\n const res = await fetch(\n `${this.config.gitlabUrl}/api/v4/projects/${projectPath}/hooks`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n url: webhookUrl,\n push_events: true,\n merge_requests_events: true,\n pipeline_events: true\n })\n }\n );\n\n const data = await res.json() as GitLabWebhook;\n return data.id.toString();\n }\n}\n","import { ReActAgent } from '@orka-js/agent';\nimport { OpenAIAdapter } from '@orka-js/openai';\nimport { AnthropicAdapter } from '@orka-js/anthropic';\nimport { EventEmitter } from 'events';\nimport { OpenQADatabase } from '../../database/index.js';\nimport { BrowserTools } from '../tools/browser.js';\n\nexport type AgentType = \n | 'form-tester'\n | 'security-scanner'\n | 'sql-injection'\n | 'xss-tester'\n | 'component-tester'\n | 'accessibility-tester'\n | 'performance-tester'\n | 'api-tester'\n | 'auth-tester'\n | 'navigation-tester';\n\nexport interface AgentStatus {\n id: string;\n type: AgentType;\n status: 'idle' | 'running' | 'completed' | 'failed';\n currentTask?: string;\n progress: number;\n startedAt?: Date;\n completedAt?: Date;\n findings: number;\n actions: number;\n}\n\nexport interface SpecialistConfig {\n type: AgentType;\n enabled: boolean;\n priority: number;\n maxIterations: number;\n customPrompt?: string;\n}\n\nconst SPECIALIST_PROMPTS: Record<AgentType, string> = {\n 'form-tester': `You are a Form Testing Specialist. Your mission:\n- Find all forms on the page (login, signup, contact, search, etc.)\n- Test form validation (empty fields, invalid formats, boundary values)\n- Test error messages and user feedback\n- Test form submission success/failure scenarios\n- Check for proper field types (email, password, phone)\n- Test autofill behavior\n- Report any form-related bugs with clear reproduction steps`,\n\n 'security-scanner': `You are a Security Scanner Specialist. Your mission:\n- Identify potential security vulnerabilities\n- Check for exposed sensitive data in page source\n- Look for insecure HTTP resources on HTTPS pages\n- Check for missing security headers\n- Identify potential CSRF vulnerabilities\n- Check for information disclosure in error messages\n- Look for hardcoded credentials or API keys\n- Report security issues with severity ratings`,\n\n 'sql-injection': `You are a SQL Injection Testing Specialist. Your mission:\n- Identify input fields that might interact with databases\n- Test common SQL injection payloads (', \", --, ;, OR 1=1, etc.)\n- Test for blind SQL injection (time-based, boolean-based)\n- Check URL parameters for injection vulnerabilities\n- Test search fields, login forms, and filters\n- Document any successful injections with exact payloads\n- Rate severity based on data exposure risk`,\n\n 'xss-tester': `You are an XSS (Cross-Site Scripting) Testing Specialist. Your mission:\n- Find all user input fields that reflect content\n- Test for reflected XSS (<script>, onerror, onload, etc.)\n- Test for stored XSS in comments, profiles, messages\n- Check for DOM-based XSS vulnerabilities\n- Test various encoding bypasses\n- Check if Content-Security-Policy is properly configured\n- Document successful XSS with exact payloads`,\n\n 'component-tester': `You are a UI Component Testing Specialist. Your mission:\n- Test all interactive components (buttons, dropdowns, modals, tabs)\n- Verify component states (hover, active, disabled, loading)\n- Test responsive behavior at different viewport sizes\n- Check for broken layouts or overlapping elements\n- Test keyboard navigation and focus management\n- Verify animations and transitions work correctly\n- Report visual bugs with screenshots`,\n\n 'accessibility-tester': `You are an Accessibility Testing Specialist. Your mission:\n- Check for proper ARIA labels and roles\n- Verify keyboard navigation works for all interactive elements\n- Check color contrast ratios\n- Verify images have alt text\n- Test screen reader compatibility\n- Check for proper heading hierarchy\n- Verify focus indicators are visible\n- Report WCAG violations with severity`,\n\n 'performance-tester': `You are a Performance Testing Specialist. Your mission:\n- Measure page load times\n- Identify slow-loading resources\n- Check for render-blocking resources\n- Monitor network requests and response times\n- Identify memory leaks or excessive DOM nodes\n- Check for unnecessary re-renders\n- Test under simulated slow network conditions\n- Report performance issues with metrics`,\n\n 'api-tester': `You are an API Testing Specialist. Your mission:\n- Monitor network requests made by the application\n- Test API error handling\n- Check for proper authentication on API calls\n- Verify API response formats\n- Test rate limiting behavior\n- Check for exposed internal APIs\n- Verify proper HTTP methods are used\n- Report API issues with request/response details`,\n\n 'auth-tester': `You are an Authentication Testing Specialist. Your mission:\n- Test login with valid/invalid credentials\n- Test password reset flow\n- Check session management (timeout, persistence)\n- Test logout functionality\n- Check for session fixation vulnerabilities\n- Test remember me functionality\n- Verify proper access control on protected pages\n- Test multi-factor authentication if present`,\n\n 'navigation-tester': `You are a Navigation Testing Specialist. Your mission:\n- Test all navigation links and menus\n- Verify breadcrumbs work correctly\n- Test browser back/forward behavior\n- Check for broken links (404s)\n- Test deep linking and URL sharing\n- Verify redirects work properly\n- Test pagination and infinite scroll\n- Report navigation issues with affected URLs`\n};\n\nexport class SpecialistAgentManager extends EventEmitter {\n private agents: Map<string, ReActAgent> = new Map();\n private agentStatuses: Map<string, AgentStatus> = new Map();\n private db: OpenQADatabase;\n private sessionId: string;\n private llmConfig: { provider: string; apiKey: string; model?: string };\n private browserTools: BrowserTools;\n\n constructor(\n db: OpenQADatabase,\n sessionId: string,\n llmConfig: { provider: string; apiKey: string; model?: string },\n browserTools: BrowserTools\n ) {\n super();\n this.db = db;\n this.sessionId = sessionId;\n this.llmConfig = llmConfig;\n this.browserTools = browserTools;\n }\n\n private createLLMAdapter() {\n if (this.llmConfig.provider === 'anthropic') {\n return new AnthropicAdapter({\n apiKey: this.llmConfig.apiKey,\n model: this.llmConfig.model || 'claude-3-5-sonnet-20241022'\n });\n }\n return new OpenAIAdapter({\n apiKey: this.llmConfig.apiKey,\n model: this.llmConfig.model || 'gpt-4'\n });\n }\n\n createSpecialist(type: AgentType, customPrompt?: string): string {\n const agentId = `${type}_${Date.now()}`;\n \n const systemPrompt = customPrompt || SPECIALIST_PROMPTS[type];\n \n const agent = new ReActAgent({\n llm: this.createLLMAdapter(),\n tools: this.browserTools.getTools(),\n maxIterations: 15,\n systemPrompt: `${systemPrompt}\n\nIMPORTANT RULES:\n- Take screenshots as evidence for any bug found\n- Create Kanban tickets for all findings\n- Create GitHub issues for critical/high severity bugs\n- Be thorough but efficient\n- Stop when you've tested the main scenarios for your specialty`\n });\n\n this.agents.set(agentId, agent);\n \n const status: AgentStatus = {\n id: agentId,\n type,\n status: 'idle',\n progress: 0,\n findings: 0,\n actions: 0\n };\n this.agentStatuses.set(agentId, status);\n\n this.emit('agent-created', status);\n \n return agentId;\n }\n\n async runSpecialist(agentId: string, targetUrl: string): Promise<void> {\n const agent = this.agents.get(agentId);\n const status = this.agentStatuses.get(agentId);\n \n if (!agent || !status) {\n throw new Error(`Agent ${agentId} not found`);\n }\n\n status.status = 'running';\n status.startedAt = new Date();\n status.progress = 0;\n this.emit('agent-started', status);\n\n try {\n const result = await agent.run(\n `Test the application at ${targetUrl}. Focus on your specialty area. Report all findings.`\n );\n\n status.status = 'completed';\n status.completedAt = new Date();\n status.progress = 100;\n \n this.emit('agent-completed', { ...status, result });\n \n } catch (error: any) {\n status.status = 'failed';\n status.completedAt = new Date();\n \n this.emit('agent-failed', { ...status, error: error.message });\n }\n }\n\n async runAllSpecialists(targetUrl: string, types?: AgentType[]): Promise<void> {\n const agentTypes = types || [\n 'form-tester',\n 'security-scanner',\n 'component-tester',\n 'navigation-tester'\n ];\n\n const agentIds = agentTypes.map(type => this.createSpecialist(type));\n\n for (const agentId of agentIds) {\n await this.runSpecialist(agentId, targetUrl);\n }\n }\n\n async runSecuritySuite(targetUrl: string): Promise<void> {\n const securityTypes: AgentType[] = [\n 'security-scanner',\n 'sql-injection',\n 'xss-tester',\n 'auth-tester'\n ];\n\n await this.runAllSpecialists(targetUrl, securityTypes);\n }\n\n getAgentStatus(agentId: string): AgentStatus | undefined {\n return this.agentStatuses.get(agentId);\n }\n\n getAllStatuses(): AgentStatus[] {\n return Array.from(this.agentStatuses.values());\n }\n\n stopAgent(agentId: string): void {\n const status = this.agentStatuses.get(agentId);\n if (status && status.status === 'running') {\n status.status = 'failed';\n status.completedAt = new Date();\n this.emit('agent-stopped', status);\n }\n }\n\n stopAll(): void {\n for (const [agentId] of this.agents) {\n this.stopAgent(agentId);\n }\n }\n}\n","import { OpenQADatabase } from '../../database/index.js';\n\nexport interface Skill {\n id: string;\n name: string;\n description: string;\n type: 'directive' | 'test-scenario' | 'custom-check' | 'workflow';\n enabled: boolean;\n priority: number;\n prompt: string;\n triggers?: string[];\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface SkillExecution {\n skillId: string;\n sessionId: string;\n startedAt: Date;\n completedAt?: Date;\n status: 'running' | 'completed' | 'failed';\n result?: string;\n}\n\nconst DEFAULT_SKILLS: Omit<Skill, 'id' | 'createdAt' | 'updatedAt'>[] = [\n {\n name: 'GDPR Compliance Check',\n description: 'Check for GDPR compliance (cookie consent, privacy policy, data handling)',\n type: 'custom-check',\n enabled: true,\n priority: 1,\n prompt: `Check GDPR compliance:\n- Verify cookie consent banner exists and works\n- Check for privacy policy link\n- Verify data deletion/export options if user accounts exist\n- Check for proper consent checkboxes on forms\n- Report any GDPR violations`,\n triggers: ['eu', 'gdpr', 'privacy', 'cookies']\n },\n {\n name: 'Mobile Responsiveness',\n description: 'Test application on mobile viewport sizes',\n type: 'test-scenario',\n enabled: true,\n priority: 2,\n prompt: `Test mobile responsiveness:\n- Test at 375px width (iPhone)\n- Test at 768px width (tablet)\n- Check for horizontal scrolling issues\n- Verify touch targets are large enough\n- Check navigation menu behavior on mobile\n- Report any responsive design issues`,\n triggers: ['mobile', 'responsive', 'viewport']\n },\n {\n name: 'E-commerce Flow',\n description: 'Test complete e-commerce purchase flow',\n type: 'workflow',\n enabled: false,\n priority: 3,\n prompt: `Test e-commerce flow:\n- Browse products\n- Add items to cart\n- Verify cart updates correctly\n- Test checkout process\n- Test payment form validation\n- Verify order confirmation\n- Report any issues in the purchase flow`,\n triggers: ['shop', 'cart', 'checkout', 'payment', 'ecommerce']\n },\n {\n name: 'Dark Mode Testing',\n description: 'Test dark mode if available',\n type: 'custom-check',\n enabled: true,\n priority: 4,\n prompt: `Test dark mode:\n- Look for dark mode toggle\n- Switch between light and dark modes\n- Check for contrast issues in dark mode\n- Verify all text is readable\n- Check images and icons visibility\n- Report any dark mode specific bugs`,\n triggers: ['dark', 'theme', 'mode']\n },\n {\n name: 'Error Handling',\n description: 'Test application error handling',\n type: 'test-scenario',\n enabled: true,\n priority: 1,\n prompt: `Test error handling:\n- Try accessing non-existent pages (404)\n- Submit forms with invalid data\n- Test with network errors (if possible)\n- Check error message clarity\n- Verify errors don't expose sensitive info\n- Test recovery from error states\n- Report poor error handling`,\n triggers: ['error', '404', 'exception']\n },\n {\n name: 'Rate Limiting Check',\n description: 'Test for rate limiting on sensitive endpoints',\n type: 'custom-check',\n enabled: true,\n priority: 2,\n prompt: `Test rate limiting:\n- Attempt multiple rapid login attempts\n- Test API endpoints for rate limiting\n- Check for CAPTCHA on repeated failures\n- Verify account lockout mechanisms\n- Report missing rate limiting as security issue`,\n triggers: ['rate', 'limit', 'brute', 'ddos']\n }\n];\n\nexport class SkillManager {\n private db: OpenQADatabase;\n private skills: Map<string, Skill> = new Map();\n\n constructor(db: OpenQADatabase) {\n this.db = db;\n this.loadSkills();\n }\n\n private loadSkills() {\n const savedSkills = this.db.getConfig('skills');\n \n if (savedSkills) {\n const parsed = JSON.parse(savedSkills) as Skill[];\n parsed.forEach(skill => this.skills.set(skill.id, skill));\n } else {\n DEFAULT_SKILLS.forEach(skill => {\n this.createSkill(skill);\n });\n }\n }\n\n private saveSkills() {\n const skillsArray = Array.from(this.skills.values());\n this.db.setConfig('skills', JSON.stringify(skillsArray));\n }\n\n createSkill(data: Omit<Skill, 'id' | 'createdAt' | 'updatedAt'>): Skill {\n const skill: Skill = {\n ...data,\n id: `skill_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n createdAt: new Date(),\n updatedAt: new Date()\n };\n\n this.skills.set(skill.id, skill);\n this.saveSkills();\n \n return skill;\n }\n\n updateSkill(id: string, updates: Partial<Omit<Skill, 'id' | 'createdAt'>>): Skill | null {\n const skill = this.skills.get(id);\n if (!skill) return null;\n\n const updated: Skill = {\n ...skill,\n ...updates,\n updatedAt: new Date()\n };\n\n this.skills.set(id, updated);\n this.saveSkills();\n \n return updated;\n }\n\n deleteSkill(id: string): boolean {\n const deleted = this.skills.delete(id);\n if (deleted) {\n this.saveSkills();\n }\n return deleted;\n }\n\n getSkill(id: string): Skill | undefined {\n return this.skills.get(id);\n }\n\n getAllSkills(): Skill[] {\n return Array.from(this.skills.values());\n }\n\n getEnabledSkills(): Skill[] {\n return this.getAllSkills()\n .filter(s => s.enabled)\n .sort((a, b) => a.priority - b.priority);\n }\n\n getSkillsByType(type: Skill['type']): Skill[] {\n return this.getAllSkills().filter(s => s.type === type);\n }\n\n findSkillsByTrigger(text: string): Skill[] {\n const lowerText = text.toLowerCase();\n return this.getEnabledSkills().filter(skill => \n skill.triggers?.some(trigger => lowerText.includes(trigger.toLowerCase()))\n );\n }\n\n generateSkillPrompt(skills: Skill[]): string {\n if (skills.length === 0) return '';\n\n const skillInstructions = skills.map((skill, index) => \n `### Skill ${index + 1}: ${skill.name}\\n${skill.prompt}`\n ).join('\\n\\n');\n\n return `\n## Additional Skills/Directives to Follow\n\nThe following skills have been configured. Execute them as part of your testing:\n\n${skillInstructions}\n\nRemember to report findings from each skill separately.\n`;\n }\n\n toggleSkill(id: string): Skill | null {\n const skill = this.skills.get(id);\n if (!skill) return null;\n\n return this.updateSkill(id, { enabled: !skill.enabled });\n }\n\n reorderSkills(orderedIds: string[]): void {\n orderedIds.forEach((id, index) => {\n const skill = this.skills.get(id);\n if (skill) {\n skill.priority = index + 1;\n skill.updatedAt = new Date();\n }\n });\n this.saveSkills();\n }\n\n exportSkills(): string {\n return JSON.stringify(this.getAllSkills(), null, 2);\n }\n\n importSkills(json: string): number {\n const imported = JSON.parse(json) as Skill[];\n let count = 0;\n\n imported.forEach(skill => {\n const newSkill = this.createSkill({\n name: skill.name,\n description: skill.description,\n type: skill.type,\n enabled: skill.enabled,\n priority: skill.priority,\n prompt: skill.prompt,\n triggers: skill.triggers\n });\n if (newSkill) count++;\n });\n\n return count;\n }\n}\n"],"mappings":"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","names":["ReActAgent","OpenAIAdapter","AnthropicAdapter","EventEmitter","mkdirSync","join","Octokit","EventEmitter","EventEmitter","AnthropicAdapter","OpenAIAdapter","ReActAgent","readFileSync","join"]}
|