@openqa/cli 1.3.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +203 -6
  2. package/dist/agent/brain/diff-analyzer.js +140 -0
  3. package/dist/agent/brain/diff-analyzer.js.map +1 -0
  4. package/dist/agent/brain/llm-cache.js +47 -0
  5. package/dist/agent/brain/llm-cache.js.map +1 -0
  6. package/dist/agent/brain/llm-resilience.js +252 -0
  7. package/dist/agent/brain/llm-resilience.js.map +1 -0
  8. package/dist/agent/config/index.js +588 -0
  9. package/dist/agent/config/index.js.map +1 -0
  10. package/dist/agent/coverage/index.js +74 -0
  11. package/dist/agent/coverage/index.js.map +1 -0
  12. package/dist/agent/export/index.js +158 -0
  13. package/dist/agent/export/index.js.map +1 -0
  14. package/dist/agent/index-v2.js +2795 -0
  15. package/dist/agent/index-v2.js.map +1 -0
  16. package/dist/agent/index.js +369 -105
  17. package/dist/agent/index.js.map +1 -1
  18. package/dist/agent/logger.js +41 -0
  19. package/dist/agent/logger.js.map +1 -0
  20. package/dist/agent/metrics.js +39 -0
  21. package/dist/agent/metrics.js.map +1 -0
  22. package/dist/agent/notifications/index.js +106 -0
  23. package/dist/agent/notifications/index.js.map +1 -0
  24. package/dist/agent/openapi/spec.js +338 -0
  25. package/dist/agent/openapi/spec.js.map +1 -0
  26. package/dist/agent/tools/project-runner.js +481 -0
  27. package/dist/agent/tools/project-runner.js.map +1 -0
  28. package/dist/cli/config.html.js +454 -0
  29. package/dist/cli/daemon.js +8810 -0
  30. package/dist/cli/dashboard.html.js +1622 -0
  31. package/dist/cli/env-config.js +391 -0
  32. package/dist/cli/env-routes.js +820 -0
  33. package/dist/cli/env.html.js +679 -0
  34. package/dist/cli/index.js +5980 -1896
  35. package/dist/cli/kanban.html.js +577 -0
  36. package/dist/cli/routes.js +895 -0
  37. package/dist/cli/routes.js.map +1 -0
  38. package/dist/cli/server.js +5855 -1860
  39. package/dist/database/index.js +485 -60
  40. package/dist/database/index.js.map +1 -1
  41. package/dist/database/sqlite.js +281 -0
  42. package/dist/database/sqlite.js.map +1 -0
  43. package/install.sh +19 -10
  44. package/package.json +19 -5
@@ -1,4 +1,28 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+
6
+ // node_modules/tsup/assets/esm_shims.js
7
+ import path from "path";
8
+ import { fileURLToPath } from "url";
9
+ var init_esm_shims = __esm({
10
+ "node_modules/tsup/assets/esm_shims.js"() {
11
+ "use strict";
12
+ }
13
+ });
14
+
15
+ // database/sqlite.ts
16
+ import Database from "better-sqlite3";
17
+ var init_sqlite = __esm({
18
+ "database/sqlite.ts"() {
19
+ "use strict";
20
+ init_esm_shims();
21
+ }
22
+ });
23
+
1
24
  // agent/index.ts
25
+ init_esm_shims();
2
26
  import { ReActAgent as ReActAgent2 } from "@orka-js/agent";
3
27
  import { OpenAIAdapter as OpenAIAdapter2 } from "@orka-js/openai";
4
28
  import { AnthropicAdapter as AnthropicAdapter2 } from "@orka-js/anthropic";
@@ -7,13 +31,15 @@ import { Tracer } from "@orka-js/observability";
7
31
  import { EventEmitter as EventEmitter3 } from "events";
8
32
 
9
33
  // database/index.ts
34
+ init_esm_shims();
35
+ init_sqlite();
10
36
  import { Low } from "lowdb";
11
37
  import { JSONFile } from "lowdb/node";
12
38
  import { dirname } from "path";
13
- import { fileURLToPath } from "url";
39
+ import { fileURLToPath as fileURLToPath2 } from "url";
14
40
  import { mkdirSync } from "fs";
15
- var __filename = fileURLToPath(import.meta.url);
16
- var __dirname = dirname(__filename);
41
+ var __filename2 = fileURLToPath2(import.meta.url);
42
+ var __dirname2 = dirname(__filename2);
17
43
  var OpenQADatabase = class {
18
44
  constructor(dbPath = "./data/openqa.json") {
19
45
  this.dbPath = dbPath;
@@ -29,7 +55,8 @@ var OpenQADatabase = class {
29
55
  test_sessions: [],
30
56
  actions: [],
31
57
  bugs: [],
32
- kanban_tickets: []
58
+ kanban_tickets: [],
59
+ users: []
33
60
  });
34
61
  this.db.read();
35
62
  if (!this.db.data) {
@@ -38,7 +65,8 @@ var OpenQADatabase = class {
38
65
  test_sessions: [],
39
66
  actions: [],
40
67
  bugs: [],
41
- kanban_tickets: []
68
+ kanban_tickets: [],
69
+ users: []
42
70
  };
43
71
  this.db.write();
44
72
  }
@@ -48,6 +76,12 @@ var OpenQADatabase = class {
48
76
  this.initialize();
49
77
  }
50
78
  await this.db.read();
79
+ let migrated = false;
80
+ if (!this.db.data.users) {
81
+ this.db.data.users = [];
82
+ migrated = true;
83
+ }
84
+ if (migrated) await this.db.write();
51
85
  }
52
86
  async getConfig(key) {
53
87
  await this.ensureInitialized();
@@ -171,85 +205,297 @@ var OpenQADatabase = class {
171
205
  await this.ensureInitialized();
172
206
  return this.db.data.kanban_tickets.filter((t) => t.column === column).sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
173
207
  }
208
+ async deleteKanbanTicket(id) {
209
+ await this.ensureInitialized();
210
+ const index = this.db.data.kanban_tickets.findIndex((t) => t.id === id);
211
+ if (index !== -1) {
212
+ this.db.data.kanban_tickets.splice(index, 1);
213
+ await this.db.write();
214
+ }
215
+ }
174
216
  async clearAllConfig() {
175
217
  await this.ensureInitialized();
176
218
  this.db.data.config = {};
177
219
  await this.db.write();
178
220
  }
179
- // Get real data methods
221
+ // Get real data methods - connected to actual database records
180
222
  async getActiveAgents() {
181
223
  await this.ensureInitialized();
182
224
  const sessions = await this.getRecentSessions(1);
183
225
  const currentSession = sessions[0];
184
- if (!currentSession) {
185
- return [{ name: "Main Agent", status: "idle", purpose: "Autonomous testing", performance: 0, tasks: 0 }];
186
- }
187
- return [
188
- { name: "Main Agent", status: "running", purpose: "Autonomous testing", performance: 85, tasks: currentSession.total_actions || 0 },
189
- { name: "Browser Specialist", status: "running", purpose: "UI testing", performance: 92, tasks: Math.floor((currentSession.total_actions || 0) * 0.3) },
190
- { name: "API Tester", status: "running", purpose: "API testing", performance: 78, tasks: Math.floor((currentSession.total_actions || 0) * 0.2) },
191
- { name: "Auth Specialist", status: "idle", purpose: "Authentication testing", performance: 95, tasks: Math.floor((currentSession.total_actions || 0) * 0.1) },
192
- { name: "UI Tester", status: "running", purpose: "User interface testing", performance: 88, tasks: Math.floor((currentSession.total_actions || 0) * 0.25) },
193
- { name: "Security Scanner", status: "idle", purpose: "Security testing", performance: 91, tasks: Math.floor((currentSession.total_actions || 0) * 0.15) }
226
+ const isRunning = currentSession?.status === "running";
227
+ const totalActions = currentSession?.total_actions || 0;
228
+ const agents = [
229
+ {
230
+ name: "Main Agent",
231
+ status: isRunning ? "running" : "idle",
232
+ purpose: "Autonomous QA orchestration",
233
+ performance: totalActions > 0 ? Math.min(100, Math.round(totalActions / 100 * 100)) : 0,
234
+ tasks: totalActions
235
+ }
194
236
  ];
237
+ if (currentSession && totalActions > 0) {
238
+ const actions = await this.getSessionActions(currentSession.id);
239
+ const actionTypes = actions.reduce((acc, action) => {
240
+ const type = action.type || "unknown";
241
+ acc[type] = (acc[type] || 0) + 1;
242
+ return acc;
243
+ }, {});
244
+ if (actionTypes["navigate"] || actionTypes["click"] || actionTypes["screenshot"]) {
245
+ agents.push({
246
+ name: "Browser Specialist",
247
+ status: isRunning ? "running" : "idle",
248
+ purpose: "UI navigation and interaction",
249
+ performance: Math.round(((actionTypes["navigate"] || 0) + (actionTypes["click"] || 0)) / totalActions * 100),
250
+ tasks: (actionTypes["navigate"] || 0) + (actionTypes["click"] || 0)
251
+ });
252
+ }
253
+ if (actionTypes["api_call"] || actionTypes["request"]) {
254
+ agents.push({
255
+ name: "API Tester",
256
+ status: isRunning ? "running" : "idle",
257
+ purpose: "API endpoint testing",
258
+ performance: Math.round((actionTypes["api_call"] || actionTypes["request"] || 0) / totalActions * 100),
259
+ tasks: actionTypes["api_call"] || actionTypes["request"] || 0
260
+ });
261
+ }
262
+ if (actionTypes["auth"] || actionTypes["login"]) {
263
+ agents.push({
264
+ name: "Auth Specialist",
265
+ status: isRunning ? "running" : "idle",
266
+ purpose: "Authentication testing",
267
+ performance: Math.round((actionTypes["auth"] || actionTypes["login"] || 0) / totalActions * 100),
268
+ tasks: actionTypes["auth"] || actionTypes["login"] || 0
269
+ });
270
+ }
271
+ }
272
+ return agents;
195
273
  }
196
274
  async getCurrentTasks() {
197
275
  await this.ensureInitialized();
198
276
  const sessions = await this.getRecentSessions(1);
199
277
  const currentSession = sessions[0];
200
- if (!currentSession || currentSession.status === "completed") {
278
+ if (!currentSession) {
201
279
  return [];
202
280
  }
203
- const tasks = [];
204
- const taskTypes = ["Scan Application", "Test Authentication", "Generate Tests", "Analyze Results", "Create Reports"];
205
- for (let i = 0; i < Math.min(5, Math.floor((currentSession.total_actions || 0) / 10)); i++) {
206
- const taskType = taskTypes[i % taskTypes.length];
207
- const status = i === 0 ? "running" : i === 1 ? "pending" : "completed";
208
- const progress = status === "completed" ? "100%" : status === "running" ? "65%" : "0%";
209
- tasks.push({
210
- id: `task_${i + 1}`,
211
- name: taskType,
212
- status,
213
- progress,
214
- agent: ["Main Agent", "Browser Specialist", "API Tester", "UI Tester"][i % 4],
215
- started_at: new Date(Date.now() - i * 10 * 60 * 1e3).toISOString(),
216
- result: status === "completed" ? "Successfully completed task execution" : null
217
- });
218
- }
219
- return tasks;
281
+ const actions = await this.getSessionActions(currentSession.id);
282
+ const recentActions = actions.slice(-10).reverse();
283
+ return recentActions.map((action, index) => ({
284
+ id: action.id,
285
+ name: action.type || "Unknown Action",
286
+ status: index === 0 && currentSession.status === "running" ? "running" : "completed",
287
+ progress: index === 0 && currentSession.status === "running" ? "65%" : "100%",
288
+ agent: "Main Agent",
289
+ started_at: action.timestamp,
290
+ result: action.output || action.description || "Completed"
291
+ }));
220
292
  }
221
293
  async getCurrentIssues() {
222
294
  await this.ensureInitialized();
223
- const sessions = await this.getRecentSessions(1);
224
- const currentSession = sessions[0];
225
- if (!currentSession) {
226
- return [];
295
+ const bugs = await this.getAllBugs();
296
+ return bugs.slice(0, 10).map((bug) => ({
297
+ id: bug.id,
298
+ title: bug.title,
299
+ description: bug.description,
300
+ severity: bug.severity || "medium",
301
+ status: bug.status || "open",
302
+ discovered_at: bug.created_at,
303
+ agent: "Main Agent"
304
+ }));
305
+ }
306
+ async pruneOldSessions(maxAgeDays) {
307
+ await this.ensureInitialized();
308
+ const cutoff = new Date(Date.now() - maxAgeDays * 864e5).toISOString();
309
+ const oldSessions = this.db.data.test_sessions.filter((s) => s.started_at < cutoff);
310
+ const oldSessionIds = new Set(oldSessions.map((s) => s.id));
311
+ const actionsBefore = this.db.data.actions.length;
312
+ this.db.data.actions = this.db.data.actions.filter((a) => !oldSessionIds.has(a.session_id));
313
+ const actionsRemoved = actionsBefore - this.db.data.actions.length;
314
+ this.db.data.test_sessions = this.db.data.test_sessions.filter((s) => s.started_at >= cutoff);
315
+ await this.db.write();
316
+ return { sessionsRemoved: oldSessions.length, actionsRemoved };
317
+ }
318
+ async getStorageStats() {
319
+ await this.ensureInitialized();
320
+ return {
321
+ sessions: this.db.data.test_sessions.length,
322
+ actions: this.db.data.actions.length,
323
+ bugs: this.db.data.bugs.length,
324
+ tickets: this.db.data.kanban_tickets.length
325
+ };
326
+ }
327
+ // ── User management ──────────────────────────────────────────────────────────
328
+ async countUsers() {
329
+ await this.ensureInitialized();
330
+ return this.db.data.users.length;
331
+ }
332
+ async findUserByUsername(username) {
333
+ await this.ensureInitialized();
334
+ return this.db.data.users.find((u) => u.username === username) ?? null;
335
+ }
336
+ async getUserById(id) {
337
+ await this.ensureInitialized();
338
+ return this.db.data.users.find((u) => u.id === id) ?? null;
339
+ }
340
+ async getAllUsers() {
341
+ await this.ensureInitialized();
342
+ return [...this.db.data.users];
343
+ }
344
+ async createUser(data) {
345
+ await this.ensureInitialized();
346
+ const now = (/* @__PURE__ */ new Date()).toISOString();
347
+ const user = {
348
+ id: `user_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
349
+ username: data.username,
350
+ passwordHash: data.passwordHash,
351
+ role: data.role,
352
+ createdAt: now,
353
+ updatedAt: now
354
+ };
355
+ this.db.data.users.push(user);
356
+ await this.db.write();
357
+ return user;
358
+ }
359
+ async updateUser(id, updates) {
360
+ await this.ensureInitialized();
361
+ const idx = this.db.data.users.findIndex((u) => u.id === id);
362
+ if (idx !== -1) {
363
+ this.db.data.users[idx] = {
364
+ ...this.db.data.users[idx],
365
+ ...updates,
366
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
367
+ };
368
+ await this.db.write();
227
369
  }
228
- const issues = [];
229
- const bugCount = currentSession.bugs_found || 0;
230
- if (bugCount > 0) {
231
- const issueTypes = ["Critical Security Issue", "Performance Bottleneck", "UI Bug", "API Error", "Authentication Flaw"];
232
- const severities = ["critical", "high", "medium", "low"];
233
- for (let i = 0; i < Math.min(bugCount, 5); i++) {
234
- issues.push({
235
- id: `issue_${i + 1}`,
236
- title: issueTypes[i % issueTypes.length],
237
- description: `Issue detected during automated testing session`,
238
- severity: severities[i % severities.length],
239
- status: "open",
240
- discovered_at: new Date(Date.now() - i * 30 * 60 * 1e3).toISOString(),
241
- agent: ["Main Agent", "Browser Specialist", "API Tester"][i % 3]
242
- });
243
- }
370
+ }
371
+ async deleteUser(id) {
372
+ await this.ensureInitialized();
373
+ const idx = this.db.data.users.findIndex((u) => u.id === id);
374
+ if (idx !== -1) {
375
+ this.db.data.users.splice(idx, 1);
376
+ await this.db.write();
244
377
  }
245
- return issues;
246
378
  }
247
379
  async close() {
248
380
  }
249
381
  };
250
382
 
251
383
  // agent/config/index.ts
384
+ init_esm_shims();
252
385
  import { config as dotenvConfig } from "dotenv";
386
+
387
+ // agent/config/schema.ts
388
+ init_esm_shims();
389
+ import { z } from "zod";
390
+ var llmConfigSchema = z.object({
391
+ provider: z.enum(["openai", "anthropic", "ollama"]).default("openai"),
392
+ apiKey: z.string().optional(),
393
+ model: z.string().optional(),
394
+ baseUrl: z.string().url().optional()
395
+ });
396
+ var saasConfigSchema = z.object({
397
+ url: z.string().default(""),
398
+ authType: z.enum(["none", "basic", "bearer", "session"]).default("none"),
399
+ username: z.string().optional(),
400
+ password: z.string().optional()
401
+ });
402
+ var githubConfigSchema = z.object({
403
+ token: z.string().min(1, "GITHUB_TOKEN is required when GitHub is configured"),
404
+ owner: z.string().default(""),
405
+ repo: z.string().default("")
406
+ });
407
+ var agentConfigSchema = z.object({
408
+ intervalMs: z.number().int().positive().default(36e5),
409
+ maxIterations: z.number().int().positive().default(20),
410
+ autoStart: z.boolean().default(false)
411
+ });
412
+ var webConfigSchema = z.object({
413
+ port: z.number().int().min(1).max(65535).default(4242),
414
+ host: z.string().default("0.0.0.0")
415
+ });
416
+ var databaseConfigSchema = z.object({
417
+ path: z.string().default("./data/openqa.db")
418
+ });
419
+ var notificationsConfigSchema = z.object({
420
+ slack: z.string().url().optional(),
421
+ discord: z.string().url().optional()
422
+ });
423
+ var openQAConfigSchema = z.object({
424
+ llm: llmConfigSchema,
425
+ saas: saasConfigSchema,
426
+ github: githubConfigSchema.optional(),
427
+ agent: agentConfigSchema,
428
+ web: webConfigSchema,
429
+ database: databaseConfigSchema,
430
+ notifications: notificationsConfigSchema.optional()
431
+ });
432
+ var saasAppConfigSchema = z.object({
433
+ name: z.string().min(1, "SaaS application name is required"),
434
+ description: z.string().min(1, "SaaS application description is required"),
435
+ url: z.string().url("SaaS application URL must be a valid URL"),
436
+ repoUrl: z.string().url().optional(),
437
+ localPath: z.string().optional(),
438
+ techStack: z.array(z.string()).optional(),
439
+ authInfo: z.object({
440
+ type: z.enum(["none", "basic", "oauth", "session"]),
441
+ testCredentials: z.object({
442
+ username: z.string(),
443
+ password: z.string()
444
+ }).optional()
445
+ }).optional(),
446
+ directives: z.array(z.string()).optional()
447
+ });
448
+ function validateConfigSafe(config) {
449
+ const result = openQAConfigSchema.safeParse(config);
450
+ if (result.success) {
451
+ return { success: true, data: result.data };
452
+ }
453
+ return {
454
+ success: false,
455
+ errors: result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
456
+ };
457
+ }
458
+
459
+ // agent/logger.ts
460
+ init_esm_shims();
461
+ var LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
462
+ var MIN_LEVEL = process.env.LOG_LEVEL || "info";
463
+ function shouldLog(level) {
464
+ return LEVELS[level] >= LEVELS[MIN_LEVEL];
465
+ }
466
+ function format(level, message, context) {
467
+ const entry = {
468
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
469
+ level,
470
+ msg: message,
471
+ ...context
472
+ };
473
+ return JSON.stringify(entry);
474
+ }
475
+ var logger = {
476
+ debug(message, context) {
477
+ if (shouldLog("debug")) process.stdout.write(format("debug", message, context) + "\n");
478
+ },
479
+ info(message, context) {
480
+ if (shouldLog("info")) process.stdout.write(format("info", message, context) + "\n");
481
+ },
482
+ warn(message, context) {
483
+ if (shouldLog("warn")) process.stderr.write(format("warn", message, context) + "\n");
484
+ },
485
+ error(message, context) {
486
+ if (shouldLog("error")) process.stderr.write(format("error", message, context) + "\n");
487
+ },
488
+ child(defaults) {
489
+ return {
490
+ debug: (msg, ctx) => logger.debug(msg, { ...defaults, ...ctx }),
491
+ info: (msg, ctx) => logger.info(msg, { ...defaults, ...ctx }),
492
+ warn: (msg, ctx) => logger.warn(msg, { ...defaults, ...ctx }),
493
+ error: (msg, ctx) => logger.error(msg, { ...defaults, ...ctx })
494
+ };
495
+ }
496
+ };
497
+
498
+ // agent/config/index.ts
253
499
  dotenvConfig();
254
500
  var ConfigManager = class {
255
501
  db = null;
@@ -258,7 +504,7 @@ var ConfigManager = class {
258
504
  this.envConfig = this.loadFromEnv();
259
505
  }
260
506
  loadFromEnv() {
261
- return {
507
+ const raw = {
262
508
  llm: {
263
509
  provider: process.env.LLM_PROVIDER || "openai",
264
510
  apiKey: process.env.OPENAI_API_KEY || process.env.ANTHROPIC_API_KEY,
@@ -293,6 +539,12 @@ var ConfigManager = class {
293
539
  discord: process.env.DISCORD_WEBHOOK_URL
294
540
  }
295
541
  };
542
+ const result = validateConfigSafe(raw);
543
+ if (!result.success) {
544
+ logger.warn("Config validation warnings", { errors: result.errors });
545
+ return raw;
546
+ }
547
+ return result.data;
296
548
  }
297
549
  getDB() {
298
550
  if (!this.db) {
@@ -306,9 +558,13 @@ var ConfigManager = class {
306
558
  const keys = key.split(".");
307
559
  let value = this.envConfig;
308
560
  for (const k of keys) {
309
- value = value?.[k];
561
+ if (value && typeof value === "object") {
562
+ value = value[k];
563
+ } else {
564
+ return null;
565
+ }
310
566
  }
311
- return value?.toString() || null;
567
+ return value != null ? String(value) : null;
312
568
  }
313
569
  async set(key, value) {
314
570
  await this.getDB().setConfig(key, value);
@@ -320,7 +576,7 @@ var ConfigManager = class {
320
576
  const keys = key.split(".");
321
577
  let obj = merged;
322
578
  for (let i = 0; i < keys.length - 1; i++) {
323
- if (!obj[keys[i]]) obj[keys[i]] = {};
579
+ if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") obj[keys[i]] = {};
324
580
  obj = obj[keys[i]];
325
581
  }
326
582
  obj[keys[keys.length - 1]] = value;
@@ -337,6 +593,7 @@ var ConfigManager = class {
337
593
  };
338
594
 
339
595
  // agent/tools/browser.ts
596
+ init_esm_shims();
340
597
  import { chromium } from "playwright";
341
598
  import { mkdirSync as mkdirSync2 } from "fs";
342
599
  import { join as join2 } from "path";
@@ -385,7 +642,7 @@ var BrowserTools = class {
385
642
  });
386
643
  return `Successfully navigated to ${url}. Page title: "${title}"`;
387
644
  } catch (error) {
388
- return `Failed to navigate: ${error.message}`;
645
+ return `Failed to navigate: ${error instanceof Error ? error.message : String(error)}`;
389
646
  }
390
647
  }
391
648
  },
@@ -411,7 +668,7 @@ var BrowserTools = class {
411
668
  });
412
669
  return `Successfully clicked element: ${selector}`;
413
670
  } catch (error) {
414
- return `Failed to click element: ${error.message}`;
671
+ return `Failed to click element: ${error instanceof Error ? error.message : String(error)}`;
415
672
  }
416
673
  }
417
674
  },
@@ -438,7 +695,7 @@ var BrowserTools = class {
438
695
  });
439
696
  return `Successfully filled input ${selector} with text`;
440
697
  } catch (error) {
441
- return `Failed to fill input: ${error.message}`;
698
+ return `Failed to fill input: ${error instanceof Error ? error.message : String(error)}`;
442
699
  }
443
700
  }
444
701
  },
@@ -456,17 +713,17 @@ var BrowserTools = class {
456
713
  if (!this.page) return "Browser not initialized. Navigate to a page first.";
457
714
  try {
458
715
  const filename = `${Date.now()}_${name}.png`;
459
- const path = join2(this.screenshotDir, filename);
460
- await this.page.screenshot({ path, fullPage: true });
716
+ const path2 = join2(this.screenshotDir, filename);
717
+ await this.page.screenshot({ path: path2, fullPage: true });
461
718
  this.db.createAction({
462
719
  session_id: this.sessionId,
463
720
  type: "screenshot",
464
721
  description: `Screenshot: ${name}`,
465
- screenshot_path: path
722
+ screenshot_path: path2
466
723
  });
467
- return `Screenshot saved: ${path}`;
724
+ return `Screenshot saved: ${path2}`;
468
725
  } catch (error) {
469
- return `Failed to take screenshot: ${error.message}`;
726
+ return `Failed to take screenshot: ${error instanceof Error ? error.message : String(error)}`;
470
727
  }
471
728
  }
472
729
  },
@@ -483,7 +740,7 @@ var BrowserTools = class {
483
740
  const content = await this.page.textContent("body");
484
741
  return content?.slice(0, 1e3) || "No content found";
485
742
  } catch (error) {
486
- return `Failed to get content: ${error.message}`;
743
+ return `Failed to get content: ${error instanceof Error ? error.message : String(error)}`;
487
744
  }
488
745
  }
489
746
  },
@@ -522,6 +779,7 @@ ${errors.join("\n")}`;
522
779
  };
523
780
 
524
781
  // agent/tools/github.ts
782
+ init_esm_shims();
525
783
  import { Octokit } from "@octokit/rest";
526
784
  var GitHubTools = class {
527
785
  octokit = null;
@@ -598,7 +856,7 @@ ${screenshot_path ? `**Screenshot:** ${screenshot_path}` : ""}
598
856
  URL: ${issue.data.html_url}
599
857
  Issue #${issue.data.number}`;
600
858
  } catch (error) {
601
- return `\u274C Failed to create GitHub issue: ${error.message}`;
859
+ return `\u274C Failed to create GitHub issue: ${error instanceof Error ? error.message : String(error)}`;
602
860
  }
603
861
  }
604
862
  }
@@ -607,6 +865,7 @@ Issue #${issue.data.number}`;
607
865
  };
608
866
 
609
867
  // agent/tools/kanban.ts
868
+ init_esm_shims();
610
869
  var KanbanTools = class {
611
870
  db;
612
871
  sessionId;
@@ -634,7 +893,7 @@ var KanbanTools = class {
634
893
  execute: async ({ title, description, priority, column = "to-do", tags = [], screenshot_path }) => {
635
894
  try {
636
895
  const allTags = ["automated-qa", ...tags];
637
- const ticket = this.db.createKanbanTicket({
896
+ const ticket = await this.db.createKanbanTicket({
638
897
  title,
639
898
  description,
640
899
  priority,
@@ -642,7 +901,7 @@ var KanbanTools = class {
642
901
  tags: JSON.stringify(allTags),
643
902
  screenshot_url: screenshot_path
644
903
  });
645
- this.db.createAction({
904
+ await this.db.createAction({
646
905
  session_id: this.sessionId,
647
906
  type: "kanban_ticket",
648
907
  description: `Created Kanban ticket: ${title}`,
@@ -654,7 +913,7 @@ ID: ${ticket.id}
654
913
  Column: ${column}
655
914
  Priority: ${priority}`;
656
915
  } catch (error) {
657
- return `\u274C Failed to create Kanban ticket: ${error.message}`;
916
+ return `\u274C Failed to create Kanban ticket: ${error instanceof Error ? error.message : String(error)}`;
658
917
  }
659
918
  }
660
919
  },
@@ -675,10 +934,10 @@ Priority: ${priority}`;
675
934
  const updates = {};
676
935
  if (column) updates.column = column;
677
936
  if (priority) updates.priority = priority;
678
- this.db.updateKanbanTicket(ticket_id, updates);
937
+ await this.db.updateKanbanTicket(ticket_id, updates);
679
938
  return `\u2705 Kanban ticket ${ticket_id} updated successfully!`;
680
939
  } catch (error) {
681
- return `\u274C Failed to update Kanban ticket: ${error.message}`;
940
+ return `\u274C Failed to update Kanban ticket: ${error instanceof Error ? error.message : String(error)}`;
682
941
  }
683
942
  }
684
943
  },
@@ -691,7 +950,7 @@ Priority: ${priority}`;
691
950
  },
692
951
  execute: async () => {
693
952
  try {
694
- const tickets = this.db.getKanbanTickets();
953
+ const tickets = await this.db.getKanbanTickets();
695
954
  const byColumn = {
696
955
  backlog: tickets.filter((t) => t.column === "backlog"),
697
956
  "to-do": tickets.filter((t) => t.column === "to-do"),
@@ -709,7 +968,7 @@ Total: ${tickets.length} tickets
709
968
  `.trim();
710
969
  return summary;
711
970
  } catch (error) {
712
- return `\u274C Failed to get Kanban board: ${error.message}`;
971
+ return `\u274C Failed to get Kanban board: ${error instanceof Error ? error.message : String(error)}`;
713
972
  }
714
973
  }
715
974
  }
@@ -718,6 +977,7 @@ Total: ${tickets.length} tickets
718
977
  };
719
978
 
720
979
  // agent/webhooks/git-listener.ts
980
+ init_esm_shims();
721
981
  import { EventEmitter } from "events";
722
982
  import { Octokit as Octokit2 } from "@octokit/rest";
723
983
  var GitListener = class extends EventEmitter {
@@ -742,10 +1002,10 @@ var GitListener = class extends EventEmitter {
742
1002
  async start() {
743
1003
  if (this.isRunning) return;
744
1004
  this.isRunning = true;
745
- console.log(`\u{1F517} GitListener started for ${this.config.provider}/${this.config.owner}/${this.config.repo}`);
1005
+ logger.info("GitListener started", { provider: this.config.provider, owner: this.config.owner, repo: this.config.repo });
746
1006
  await this.checkInitialState();
747
1007
  this.pollInterval = setInterval(() => {
748
- this.poll().catch(console.error);
1008
+ this.poll().catch((e) => logger.error("Poll error", { error: e instanceof Error ? e.message : String(e) }));
749
1009
  }, this.config.pollIntervalMs);
750
1010
  }
751
1011
  stop() {
@@ -754,7 +1014,7 @@ var GitListener = class extends EventEmitter {
754
1014
  clearInterval(this.pollInterval);
755
1015
  this.pollInterval = null;
756
1016
  }
757
- console.log("\u{1F517} GitListener stopped");
1017
+ logger.info("GitListener stopped");
758
1018
  }
759
1019
  async checkInitialState() {
760
1020
  try {
@@ -764,7 +1024,7 @@ var GitListener = class extends EventEmitter {
764
1024
  await this.checkGitLabState();
765
1025
  }
766
1026
  } catch (error) {
767
- console.error("Failed to check initial state:", error);
1027
+ logger.error("Failed to check initial state", { error: error instanceof Error ? error.message : String(error) });
768
1028
  }
769
1029
  }
770
1030
  async poll() {
@@ -775,7 +1035,7 @@ var GitListener = class extends EventEmitter {
775
1035
  await this.pollGitLab();
776
1036
  }
777
1037
  } catch (error) {
778
- console.error("Poll error:", error);
1038
+ logger.error("Poll error", { error: error instanceof Error ? error.message : String(error) });
779
1039
  }
780
1040
  }
781
1041
  async checkGitHubState() {
@@ -825,7 +1085,7 @@ var GitListener = class extends EventEmitter {
825
1085
  this.emit("git-event", event);
826
1086
  if (isMerge) {
827
1087
  this.emit("merge", event);
828
- console.log(`\u{1F500} Merge detected on ${this.config.branch}: ${commit.sha.slice(0, 7)}`);
1088
+ logger.info("Merge detected", { branch: this.config.branch, sha: commit.sha.slice(0, 7) });
829
1089
  }
830
1090
  }
831
1091
  if (commits.length > 0) {
@@ -855,10 +1115,10 @@ var GitListener = class extends EventEmitter {
855
1115
  this.emit("git-event", event);
856
1116
  if (run.conclusion === "success") {
857
1117
  this.emit("pipeline-success", event);
858
- console.log(`\u2705 Pipeline success: ${run.name} (${run.id})`);
1118
+ logger.info("Pipeline success", { name: run.name, id: run.id });
859
1119
  } else {
860
1120
  this.emit("pipeline-failure", event);
861
- console.log(`\u274C Pipeline failure: ${run.name} (${run.id})`);
1121
+ logger.warn("Pipeline failure", { name: run.name, id: run.id });
862
1122
  }
863
1123
  }
864
1124
  }
@@ -890,7 +1150,7 @@ var GitListener = class extends EventEmitter {
890
1150
  this.lastPipelineId = pipelines[0].id.toString();
891
1151
  }
892
1152
  } catch (error) {
893
- console.error("GitLab initial state error:", error);
1153
+ logger.error("GitLab initial state error", { error: error instanceof Error ? error.message : String(error) });
894
1154
  }
895
1155
  }
896
1156
  async pollGitLab() {
@@ -918,7 +1178,7 @@ var GitListener = class extends EventEmitter {
918
1178
  this.emit("git-event", event);
919
1179
  if (isMerge) {
920
1180
  this.emit("merge", event);
921
- console.log(`\u{1F500} Merge detected on ${this.config.branch}: ${commit.id.slice(0, 7)}`);
1181
+ logger.info("Merge detected", { branch: this.config.branch, id: commit.id.slice(0, 7) });
922
1182
  }
923
1183
  }
924
1184
  if (commits.length > 0) {
@@ -946,10 +1206,10 @@ var GitListener = class extends EventEmitter {
946
1206
  this.emit("git-event", event);
947
1207
  if (pipeline.status === "success") {
948
1208
  this.emit("pipeline-success", event);
949
- console.log(`\u2705 Pipeline success: #${pipeline.id}`);
1209
+ logger.info("Pipeline success", { id: pipeline.id });
950
1210
  } else {
951
1211
  this.emit("pipeline-failure", event);
952
- console.log(`\u274C Pipeline failure: #${pipeline.id}`);
1212
+ logger.warn("Pipeline failure", { id: pipeline.id });
953
1213
  }
954
1214
  }
955
1215
  }
@@ -957,7 +1217,7 @@ var GitListener = class extends EventEmitter {
957
1217
  this.lastPipelineId = pipelines[0].id.toString();
958
1218
  }
959
1219
  } catch (error) {
960
- console.error("GitLab poll error:", error);
1220
+ logger.error("GitLab poll error", { error: error instanceof Error ? error.message : String(error) });
961
1221
  }
962
1222
  }
963
1223
  async setupWebhook(webhookUrl) {
@@ -1005,6 +1265,7 @@ var GitListener = class extends EventEmitter {
1005
1265
  };
1006
1266
 
1007
1267
  // agent/specialists/index.ts
1268
+ init_esm_shims();
1008
1269
  import { ReActAgent } from "@orka-js/agent";
1009
1270
  import { OpenAIAdapter } from "@orka-js/openai";
1010
1271
  import { AnthropicAdapter } from "@orka-js/anthropic";
@@ -1126,8 +1387,8 @@ var SpecialistAgentManager = class extends EventEmitter2 {
1126
1387
  createSpecialist(type, customPrompt) {
1127
1388
  const agentId = `${type}_${Date.now()}`;
1128
1389
  const systemPrompt = customPrompt || SPECIALIST_PROMPTS[type];
1390
+ const llm = this.createLLMAdapter();
1129
1391
  const agent = new ReActAgent({
1130
- llm: this.createLLMAdapter(),
1131
1392
  tools: this.browserTools.getTools(),
1132
1393
  maxIterations: 15,
1133
1394
  systemPrompt: `${systemPrompt}
@@ -1138,7 +1399,7 @@ IMPORTANT RULES:
1138
1399
  - Create GitHub issues for critical/high severity bugs
1139
1400
  - Be thorough but efficient
1140
1401
  - Stop when you've tested the main scenarios for your specialty`
1141
- });
1402
+ }, llm);
1142
1403
  this.agents.set(agentId, agent);
1143
1404
  const status = {
1144
1405
  id: agentId,
@@ -1173,7 +1434,7 @@ IMPORTANT RULES:
1173
1434
  } catch (error) {
1174
1435
  status.status = "failed";
1175
1436
  status.completedAt = /* @__PURE__ */ new Date();
1176
- this.emit("agent-failed", { ...status, error: error.message });
1437
+ this.emit("agent-failed", { ...status, error: error instanceof Error ? error.message : String(error) });
1177
1438
  }
1178
1439
  }
1179
1440
  async runAllSpecialists(targetUrl, types) {
@@ -1219,6 +1480,7 @@ IMPORTANT RULES:
1219
1480
  };
1220
1481
 
1221
1482
  // agent/skills/index.ts
1483
+ init_esm_shims();
1222
1484
  var DEFAULT_SKILLS = [
1223
1485
  {
1224
1486
  name: "GDPR Compliance Check",
@@ -1466,9 +1728,7 @@ var OpenQAAgent = class extends EventEmitter3 {
1466
1728
  this.sessionId = `session_${Date.now()}`;
1467
1729
  await this.db.createSession(this.sessionId, {
1468
1730
  config: cfg,
1469
- started_at: (/* @__PURE__ */ new Date()).toISOString(),
1470
- trigger_type: triggerType,
1471
- trigger_data: triggerData ? JSON.stringify(triggerData) : null
1731
+ started_at: (/* @__PURE__ */ new Date()).toISOString()
1472
1732
  });
1473
1733
  this.browserTools = new BrowserTools(this.db, this.sessionId);
1474
1734
  const githubTools = new GitHubTools(this.db, this.sessionId, cfg.github || {});
@@ -1519,7 +1779,11 @@ ${skillPrompt}
1519
1779
 
1520
1780
  Always provide clear, actionable information with steps to reproduce. Think step by step like a human QA expert.`
1521
1781
  };
1522
- this.agent = new ReActAgent2(agentConfig, llm, memory);
1782
+ this.agent = new ReActAgent2({
1783
+ tools: allTools,
1784
+ maxIterations: cfg.agent.maxIterations,
1785
+ systemPrompt: agentConfig.systemPrompt
1786
+ }, llm, memory);
1523
1787
  this.specialistManager = new SpecialistAgentManager(
1524
1788
  this.db,
1525
1789
  this.sessionId,
@@ -1536,13 +1800,13 @@ Always provide clear, actionable information with steps to reproduce. Think step
1536
1800
  if (!this.agent) {
1537
1801
  await this.initialize();
1538
1802
  }
1539
- const cfg = this.config.getConfig();
1803
+ const cfg = await this.config.getConfig();
1540
1804
  console.log(`\u{1F680} Starting test session for ${cfg.saas.url}`);
1541
1805
  try {
1542
1806
  const result = await this.agent.run(
1543
1807
  `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.`
1544
1808
  );
1545
- this.db.updateSession(this.sessionId, {
1809
+ await this.db.updateSession(this.sessionId, {
1546
1810
  status: "completed",
1547
1811
  ended_at: (/* @__PURE__ */ new Date()).toISOString()
1548
1812
  });
@@ -1550,7 +1814,7 @@ Always provide clear, actionable information with steps to reproduce. Think step
1550
1814
  return result;
1551
1815
  } catch (error) {
1552
1816
  console.error("\u274C Session error:", error);
1553
- this.db.updateSession(this.sessionId, {
1817
+ await this.db.updateSession(this.sessionId, {
1554
1818
  status: "failed",
1555
1819
  ended_at: (/* @__PURE__ */ new Date()).toISOString()
1556
1820
  });
@@ -1567,7 +1831,7 @@ Always provide clear, actionable information with steps to reproduce. Think step
1567
1831
  return;
1568
1832
  }
1569
1833
  this.isRunning = true;
1570
- const cfg = this.config.getConfig();
1834
+ const cfg = await this.config.getConfig();
1571
1835
  console.log(`\u{1F916} OpenQA Agent starting in autonomous mode`);
1572
1836
  console.log(`\u{1F4CD} Target: ${cfg.saas.url}`);
1573
1837
  console.log(`\u23F1\uFE0F Interval: ${cfg.agent.intervalMs}ms (${cfg.agent.intervalMs / 1e3 / 60} minutes)`);
@@ -1608,7 +1872,7 @@ Always provide clear, actionable information with steps to reproduce. Think step
1608
1872
  }
1609
1873
  // Git integration
1610
1874
  async startGitListener() {
1611
- const cfg = this.config.getConfig();
1875
+ const cfg = await this.config.getConfig();
1612
1876
  if (cfg.github?.token && cfg.github?.owner && cfg.github?.repo) {
1613
1877
  this.gitListener = new GitListener({
1614
1878
  provider: "github",
@@ -1656,14 +1920,14 @@ Always provide clear, actionable information with steps to reproduce. Think step
1656
1920
  if (!this.specialistManager) {
1657
1921
  await this.initialize();
1658
1922
  }
1659
- const cfg = this.config.getConfig();
1923
+ const cfg = await this.config.getConfig();
1660
1924
  await this.specialistManager.runSecuritySuite(cfg.saas.url);
1661
1925
  }
1662
1926
  async runSpecialist(type) {
1663
1927
  if (!this.specialistManager) {
1664
1928
  await this.initialize();
1665
1929
  }
1666
- const cfg = this.config.getConfig();
1930
+ const cfg = await this.config.getConfig();
1667
1931
  const agentId = this.specialistManager.createSpecialist(type);
1668
1932
  await this.specialistManager.runSpecialist(agentId, cfg.saas.url);
1669
1933
  }
@@ -1686,11 +1950,11 @@ Always provide clear, actionable information with steps to reproduce. Think step
1686
1950
  toggleSkill(id) {
1687
1951
  return this.skillManager.toggleSkill(id);
1688
1952
  }
1689
- getStatus() {
1953
+ async getStatus() {
1690
1954
  return {
1691
1955
  isRunning: this.isRunning,
1692
1956
  sessionId: this.sessionId,
1693
- config: this.config.getConfig(),
1957
+ config: await this.config.getConfig(),
1694
1958
  gitListenerActive: !!this.gitListener,
1695
1959
  specialists: this.getSpecialistStatuses(),
1696
1960
  skills: this.skillManager.getEnabledSkills().length