@openqa/cli 1.0.9 → 1.0.11

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.
@@ -179,10 +179,9 @@ var OpenQADatabase = class {
179
179
  import { config as dotenvConfig } from "dotenv";
180
180
  dotenvConfig();
181
181
  var ConfigManager = class {
182
- db;
182
+ db = null;
183
183
  envConfig;
184
184
  constructor(dbPath) {
185
- this.db = new OpenQADatabase(dbPath || process.env.DB_PATH || "./data/openqa.db");
186
185
  this.envConfig = this.loadFromEnv();
187
186
  }
188
187
  loadFromEnv() {
@@ -222,8 +221,14 @@ var ConfigManager = class {
222
221
  }
223
222
  };
224
223
  }
224
+ getDB() {
225
+ if (!this.db) {
226
+ this.db = new OpenQADatabase("./data/openqa.json");
227
+ }
228
+ return this.db;
229
+ }
225
230
  async get(key) {
226
- const dbValue = await this.db.getConfig(key);
231
+ const dbValue = await this.getDB().getConfig(key);
227
232
  if (dbValue) return dbValue;
228
233
  const keys = key.split(".");
229
234
  let value = this.envConfig;
@@ -233,10 +238,10 @@ var ConfigManager = class {
233
238
  return value?.toString() || null;
234
239
  }
235
240
  async set(key, value) {
236
- await this.db.setConfig(key, value);
241
+ await this.getDB().setConfig(key, value);
237
242
  }
238
243
  async getAll() {
239
- const dbConfig = await this.db.getAllConfig();
244
+ const dbConfig = await this.getDB().getAllConfig();
240
245
  const merged = { ...this.envConfig };
241
246
  for (const [key, value] of Object.entries(dbConfig)) {
242
247
  const keys = key.split(".");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../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":["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('./data/openqa.json');\n this.skillManager = new SkillManager(this.db);\n }\n\n private createLLMAdapter() {\n const cfg = this.config.getConfigSync();\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.getConfigSync();\n this.sessionId = `session_${Date.now()}`;\n\n await 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 { Low } from 'lowdb';\nimport { JSONFile } from 'lowdb/node';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { mkdirSync, writeFileSync, readFileSync } 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\ninterface DatabaseSchema {\n config: Record<string, string>;\n test_sessions: TestSession[];\n actions: Action[];\n bugs: Bug[];\n kanban_tickets: KanbanTicket[];\n}\n\nexport class OpenQADatabase {\n private db: Low<DatabaseSchema> | null = null;\n\n constructor(private dbPath: string = './data/openqa.json') {\n this.initialize();\n }\n\n private initialize() {\n const dir = dirname(this.dbPath);\n mkdirSync(dir, { recursive: true });\n\n const adapter = new JSONFile<DatabaseSchema>(this.dbPath);\n this.db = new Low<DatabaseSchema>(adapter, {\n config: {},\n test_sessions: [],\n actions: [],\n bugs: [],\n kanban_tickets: []\n });\n\n this.db.read();\n if (!this.db.data) {\n this.db.data = {\n config: {},\n test_sessions: [],\n actions: [],\n bugs: [],\n kanban_tickets: []\n };\n this.db.write();\n }\n }\n\n private async ensureInitialized() {\n if (!this.db) {\n this.initialize();\n }\n await this.db!.read();\n }\n\n async getConfig(key: string): Promise<string | null> {\n await this.ensureInitialized();\n return this.db!.data.config[key] || null;\n }\n\n async setConfig(key: string, value: string) {\n await this.ensureInitialized();\n this.db!.data.config[key] = value;\n await this.db!.write();\n }\n\n async getAllConfig(): Promise<Record<string, string>> {\n await this.ensureInitialized();\n return this.db!.data.config;\n }\n\n async createSession(id: string, metadata?: any): Promise<TestSession> {\n await this.ensureInitialized();\n const session: TestSession = {\n id,\n started_at: new Date().toISOString(),\n status: 'running',\n total_actions: 0,\n bugs_found: 0,\n metadata: metadata ? JSON.stringify(metadata) : undefined\n };\n this.db!.data.test_sessions.push(session);\n await this.db!.write();\n return session;\n }\n\n async getSession(id: string): Promise<TestSession | null> {\n await this.ensureInitialized();\n return this.db!.data.test_sessions.find(s => s.id === id) || null;\n }\n\n async updateSession(id: string, updates: Partial<TestSession>) {\n await this.ensureInitialized();\n const index = this.db!.data.test_sessions.findIndex(s => s.id === id);\n if (index !== -1) {\n this.db!.data.test_sessions[index] = { ...this.db!.data.test_sessions[index], ...updates };\n await this.db!.write();\n }\n }\n\n async getRecentSessions(limit: number = 10): Promise<TestSession[]> {\n await this.ensureInitialized();\n return this.db!.data.test_sessions\n .sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime())\n .slice(0, limit);\n }\n\n async createAction(action: Omit<Action, 'id' | 'timestamp'>): Promise<Action> {\n await this.ensureInitialized();\n const newAction: Action = {\n id: `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n timestamp: new Date().toISOString(),\n ...action\n };\n this.db!.data.actions.push(newAction);\n await this.db!.write();\n return newAction;\n }\n\n async getSessionActions(sessionId: string): Promise<Action[]> {\n await this.ensureInitialized();\n return this.db!.data.actions\n .filter(a => a.session_id === sessionId)\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n }\n\n async createBug(bug: Omit<Bug, 'id' | 'created_at' | 'updated_at'>): Promise<Bug> {\n await this.ensureInitialized();\n const newBug: Bug = {\n id: `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n ...bug\n };\n this.db!.data.bugs.push(newBug);\n await this.db!.write();\n return newBug;\n }\n\n async updateBug(id: string, updates: Partial<Bug>) {\n await this.ensureInitialized();\n const index = this.db!.data.bugs.findIndex(b => b.id === id);\n if (index !== -1) {\n this.db!.data.bugs[index] = { \n ...this.db!.data.bugs[index], \n ...updates, \n updated_at: new Date().toISOString() \n };\n await this.db!.write();\n }\n }\n\n async getAllBugs(): Promise<Bug[]> {\n await this.ensureInitialized();\n return this.db!.data.bugs.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async getBugsByStatus(status: Bug['status']): Promise<Bug[]> {\n await this.ensureInitialized();\n return this.db!.data.bugs\n .filter(b => b.status === status)\n .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async createKanbanTicket(ticket: Omit<KanbanTicket, 'id' | 'created_at' | 'updated_at'>): Promise<KanbanTicket> {\n await this.ensureInitialized();\n const newTicket: KanbanTicket = {\n id: `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n ...ticket\n };\n this.db!.data.kanban_tickets.push(newTicket);\n await this.db!.write();\n return newTicket;\n }\n\n async updateKanbanTicket(id: string, updates: Partial<KanbanTicket>) {\n await this.ensureInitialized();\n const index = this.db!.data.kanban_tickets.findIndex(t => t.id === id);\n if (index !== -1) {\n this.db!.data.kanban_tickets[index] = { \n ...this.db!.data.kanban_tickets[index], \n ...updates, \n updated_at: new Date().toISOString() \n };\n await this.db!.write();\n }\n }\n\n async getKanbanTickets(): Promise<KanbanTicket[]> {\n await this.ensureInitialized();\n return this.db!.data.kanban_tickets.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async getKanbanTicketsByColumn(column: KanbanTicket['column']): Promise<KanbanTicket[]> {\n await this.ensureInitialized();\n return this.db!.data.kanban_tickets\n .filter(t => t.column === column)\n .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async close() {\n // LowDB doesn't need explicit closing\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 async get(key: string): Promise<string | null> {\n const dbValue = await 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 async set(key: string, value: string) {\n await this.db.setConfig(key, value);\n }\n\n async getAll(): Promise<OpenQAConfig> {\n const dbConfig = await 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 async getConfig(): Promise<OpenQAConfig> {\n return await this.getAll();\n }\n\n // Synchronous version that only uses env vars (no DB)\n getConfigSync(): OpenQAConfig {\n return this.envConfig;\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"]}
1
+ {"version":3,"sources":["../../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":["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('./data/openqa.json');\n this.skillManager = new SkillManager(this.db);\n }\n\n private createLLMAdapter() {\n const cfg = this.config.getConfigSync();\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.getConfigSync();\n this.sessionId = `session_${Date.now()}`;\n\n await 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 { Low } from 'lowdb';\nimport { JSONFile } from 'lowdb/node';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { mkdirSync, writeFileSync, readFileSync } 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\ninterface DatabaseSchema {\n config: Record<string, string>;\n test_sessions: TestSession[];\n actions: Action[];\n bugs: Bug[];\n kanban_tickets: KanbanTicket[];\n}\n\nexport class OpenQADatabase {\n private db: Low<DatabaseSchema> | null = null;\n\n constructor(private dbPath: string = './data/openqa.json') {\n this.initialize();\n }\n\n private initialize() {\n const dir = dirname(this.dbPath);\n mkdirSync(dir, { recursive: true });\n\n const adapter = new JSONFile<DatabaseSchema>(this.dbPath);\n this.db = new Low<DatabaseSchema>(adapter, {\n config: {},\n test_sessions: [],\n actions: [],\n bugs: [],\n kanban_tickets: []\n });\n\n this.db.read();\n if (!this.db.data) {\n this.db.data = {\n config: {},\n test_sessions: [],\n actions: [],\n bugs: [],\n kanban_tickets: []\n };\n this.db.write();\n }\n }\n\n private async ensureInitialized() {\n if (!this.db) {\n this.initialize();\n }\n await this.db!.read();\n }\n\n async getConfig(key: string): Promise<string | null> {\n await this.ensureInitialized();\n return this.db!.data.config[key] || null;\n }\n\n async setConfig(key: string, value: string) {\n await this.ensureInitialized();\n this.db!.data.config[key] = value;\n await this.db!.write();\n }\n\n async getAllConfig(): Promise<Record<string, string>> {\n await this.ensureInitialized();\n return this.db!.data.config;\n }\n\n async createSession(id: string, metadata?: any): Promise<TestSession> {\n await this.ensureInitialized();\n const session: TestSession = {\n id,\n started_at: new Date().toISOString(),\n status: 'running',\n total_actions: 0,\n bugs_found: 0,\n metadata: metadata ? JSON.stringify(metadata) : undefined\n };\n this.db!.data.test_sessions.push(session);\n await this.db!.write();\n return session;\n }\n\n async getSession(id: string): Promise<TestSession | null> {\n await this.ensureInitialized();\n return this.db!.data.test_sessions.find(s => s.id === id) || null;\n }\n\n async updateSession(id: string, updates: Partial<TestSession>) {\n await this.ensureInitialized();\n const index = this.db!.data.test_sessions.findIndex(s => s.id === id);\n if (index !== -1) {\n this.db!.data.test_sessions[index] = { ...this.db!.data.test_sessions[index], ...updates };\n await this.db!.write();\n }\n }\n\n async getRecentSessions(limit: number = 10): Promise<TestSession[]> {\n await this.ensureInitialized();\n return this.db!.data.test_sessions\n .sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime())\n .slice(0, limit);\n }\n\n async createAction(action: Omit<Action, 'id' | 'timestamp'>): Promise<Action> {\n await this.ensureInitialized();\n const newAction: Action = {\n id: `action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n timestamp: new Date().toISOString(),\n ...action\n };\n this.db!.data.actions.push(newAction);\n await this.db!.write();\n return newAction;\n }\n\n async getSessionActions(sessionId: string): Promise<Action[]> {\n await this.ensureInitialized();\n return this.db!.data.actions\n .filter(a => a.session_id === sessionId)\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n }\n\n async createBug(bug: Omit<Bug, 'id' | 'created_at' | 'updated_at'>): Promise<Bug> {\n await this.ensureInitialized();\n const newBug: Bug = {\n id: `bug_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n ...bug\n };\n this.db!.data.bugs.push(newBug);\n await this.db!.write();\n return newBug;\n }\n\n async updateBug(id: string, updates: Partial<Bug>) {\n await this.ensureInitialized();\n const index = this.db!.data.bugs.findIndex(b => b.id === id);\n if (index !== -1) {\n this.db!.data.bugs[index] = { \n ...this.db!.data.bugs[index], \n ...updates, \n updated_at: new Date().toISOString() \n };\n await this.db!.write();\n }\n }\n\n async getAllBugs(): Promise<Bug[]> {\n await this.ensureInitialized();\n return this.db!.data.bugs.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async getBugsByStatus(status: Bug['status']): Promise<Bug[]> {\n await this.ensureInitialized();\n return this.db!.data.bugs\n .filter(b => b.status === status)\n .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async createKanbanTicket(ticket: Omit<KanbanTicket, 'id' | 'created_at' | 'updated_at'>): Promise<KanbanTicket> {\n await this.ensureInitialized();\n const newTicket: KanbanTicket = {\n id: `ticket_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n ...ticket\n };\n this.db!.data.kanban_tickets.push(newTicket);\n await this.db!.write();\n return newTicket;\n }\n\n async updateKanbanTicket(id: string, updates: Partial<KanbanTicket>) {\n await this.ensureInitialized();\n const index = this.db!.data.kanban_tickets.findIndex(t => t.id === id);\n if (index !== -1) {\n this.db!.data.kanban_tickets[index] = { \n ...this.db!.data.kanban_tickets[index], \n ...updates, \n updated_at: new Date().toISOString() \n };\n await this.db!.write();\n }\n }\n\n async getKanbanTickets(): Promise<KanbanTicket[]> {\n await this.ensureInitialized();\n return this.db!.data.kanban_tickets.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async getKanbanTicketsByColumn(column: KanbanTicket['column']): Promise<KanbanTicket[]> {\n await this.ensureInitialized();\n return this.db!.data.kanban_tickets\n .filter(t => t.column === column)\n .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());\n }\n\n async close() {\n // LowDB doesn't need explicit closing\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 | null = null;\n private envConfig: OpenQAConfig;\n\n constructor(dbPath?: string) {\n // Don't initialize database in constructor to avoid async issues\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 private getDB(): OpenQADatabase {\n if (!this.db) {\n this.db = new OpenQADatabase('./data/openqa.json');\n }\n return this.db;\n }\n\n async get(key: string): Promise<string | null> {\n const dbValue = await this.getDB().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 async set(key: string, value: string) {\n await this.getDB().setConfig(key, value);\n }\n\n async getAll(): Promise<OpenQAConfig> {\n const dbConfig = await this.getDB().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 async getConfig(): Promise<OpenQAConfig> {\n return await this.getAll();\n }\n\n // Synchronous version that only uses env vars (no DB)\n getConfigSync(): OpenQAConfig {\n return this.envConfig;\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":";AAAA,SAAS,cAAAA,mBAAkB;AAC3B,SAAS,iBAAAC,sBAAqB;AAC9B,SAAS,oBAAAC,yBAAwB;AACjC,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,gBAAAC,qBAAoB;;;ACL7B,SAAS,WAAW;AACpB,SAAS,gBAAgB;AACzB,SAAe,eAAe;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,iBAA8C;AAEvD,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAyD7B,IAAM,iBAAN,MAAqB;AAAA,EAG1B,YAAoB,SAAiB,sBAAsB;AAAvC;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA,EAJQ,KAAiC;AAAA,EAMjC,aAAa;AACnB,UAAM,MAAM,QAAQ,KAAK,MAAM;AAC/B,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAElC,UAAM,UAAU,IAAI,SAAyB,KAAK,MAAM;AACxD,SAAK,KAAK,IAAI,IAAoB,SAAS;AAAA,MACzC,QAAQ,CAAC;AAAA,MACT,eAAe,CAAC;AAAA,MAChB,SAAS,CAAC;AAAA,MACV,MAAM,CAAC;AAAA,MACP,gBAAgB,CAAC;AAAA,IACnB,CAAC;AAED,SAAK,GAAG,KAAK;AACb,QAAI,CAAC,KAAK,GAAG,MAAM;AACjB,WAAK,GAAG,OAAO;AAAA,QACb,QAAQ,CAAC;AAAA,QACT,eAAe,CAAC;AAAA,QAChB,SAAS,CAAC;AAAA,QACV,MAAM,CAAC;AAAA,QACP,gBAAgB,CAAC;AAAA,MACnB;AACA,WAAK,GAAG,MAAM;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB;AAChC,QAAI,CAAC,KAAK,IAAI;AACZ,WAAK,WAAW;AAAA,IAClB;AACA,UAAM,KAAK,GAAI,KAAK;AAAA,EACtB;AAAA,EAEA,MAAM,UAAU,KAAqC;AACnD,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,OAAO,GAAG,KAAK;AAAA,EACtC;AAAA,EAEA,MAAM,UAAU,KAAa,OAAe;AAC1C,UAAM,KAAK,kBAAkB;AAC7B,SAAK,GAAI,KAAK,OAAO,GAAG,IAAI;AAC5B,UAAM,KAAK,GAAI,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,eAAgD;AACpD,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK;AAAA,EACvB;AAAA,EAEA,MAAM,cAAc,IAAY,UAAsC;AACpE,UAAM,KAAK,kBAAkB;AAC7B,UAAM,UAAuB;AAAA,MAC3B;AAAA,MACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,UAAU,WAAW,KAAK,UAAU,QAAQ,IAAI;AAAA,IAClD;AACA,SAAK,GAAI,KAAK,cAAc,KAAK,OAAO;AACxC,UAAM,KAAK,GAAI,MAAM;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,IAAyC;AACxD,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,cAAc,KAAK,OAAK,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/D;AAAA,EAEA,MAAM,cAAc,IAAY,SAA+B;AAC7D,UAAM,KAAK,kBAAkB;AAC7B,UAAM,QAAQ,KAAK,GAAI,KAAK,cAAc,UAAU,OAAK,EAAE,OAAO,EAAE;AACpE,QAAI,UAAU,IAAI;AAChB,WAAK,GAAI,KAAK,cAAc,KAAK,IAAI,EAAE,GAAG,KAAK,GAAI,KAAK,cAAc,KAAK,GAAG,GAAG,QAAQ;AACzF,YAAM,KAAK,GAAI,MAAM;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,QAAgB,IAA4B;AAClE,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,cAClB,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,EAClF,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,MAAM,aAAa,QAA2D;AAC5E,UAAM,KAAK,kBAAkB;AAC7B,UAAM,YAAoB;AAAA,MACxB,IAAI,UAAU,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,MACnE,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,GAAG;AAAA,IACL;AACA,SAAK,GAAI,KAAK,QAAQ,KAAK,SAAS;AACpC,UAAM,KAAK,GAAI,MAAM;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,kBAAkB,WAAsC;AAC5D,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,QAClB,OAAO,OAAK,EAAE,eAAe,SAAS,EACtC,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EACrF;AAAA,EAEA,MAAM,UAAU,KAAkE;AAChF,UAAM,KAAK,kBAAkB;AAC7B,UAAM,SAAc;AAAA,MAClB,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,MAChE,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,GAAG;AAAA,IACL;AACA,SAAK,GAAI,KAAK,KAAK,KAAK,MAAM;AAC9B,UAAM,KAAK,GAAI,MAAM;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,IAAY,SAAuB;AACjD,UAAM,KAAK,kBAAkB;AAC7B,UAAM,QAAQ,KAAK,GAAI,KAAK,KAAK,UAAU,OAAK,EAAE,OAAO,EAAE;AAC3D,QAAI,UAAU,IAAI;AAChB,WAAK,GAAI,KAAK,KAAK,KAAK,IAAI;AAAA,QAC1B,GAAG,KAAK,GAAI,KAAK,KAAK,KAAK;AAAA,QAC3B,GAAG;AAAA,QACH,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AACA,YAAM,KAAK,GAAI,MAAM;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,aAA6B;AACjC,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,KAAK,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;AAAA,EAC9G;AAAA,EAEA,MAAM,gBAAgB,QAAuC;AAC3D,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,KAClB,OAAO,OAAK,EAAE,WAAW,MAAM,EAC/B,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;AAAA,EACvF;AAAA,EAEA,MAAM,mBAAmB,QAAuF;AAC9G,UAAM,KAAK,kBAAkB;AAC7B,UAAM,YAA0B;AAAA,MAC9B,IAAI,UAAU,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,MACnE,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,GAAG;AAAA,IACL;AACA,SAAK,GAAI,KAAK,eAAe,KAAK,SAAS;AAC3C,UAAM,KAAK,GAAI,MAAM;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,mBAAmB,IAAY,SAAgC;AACnE,UAAM,KAAK,kBAAkB;AAC7B,UAAM,QAAQ,KAAK,GAAI,KAAK,eAAe,UAAU,OAAK,EAAE,OAAO,EAAE;AACrE,QAAI,UAAU,IAAI;AAChB,WAAK,GAAI,KAAK,eAAe,KAAK,IAAI;AAAA,QACpC,GAAG,KAAK,GAAI,KAAK,eAAe,KAAK;AAAA,QACrC,GAAG;AAAA,QACH,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AACA,YAAM,KAAK,GAAI,MAAM;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,mBAA4C;AAChD,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,eAAe,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;AAAA,EACxH;AAAA,EAEA,MAAM,yBAAyB,QAAyD;AACtF,UAAM,KAAK,kBAAkB;AAC7B,WAAO,KAAK,GAAI,KAAK,eAClB,OAAO,OAAK,EAAE,WAAW,MAAM,EAC/B,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;AAAA,EACvF;AAAA,EAEA,MAAM,QAAQ;AAAA,EAEd;AACF;;;AC9PA,SAAS,UAAU,oBAAoB;AAGvC,aAAa;AAsCN,IAAM,gBAAN,MAAoB;AAAA,EACjB,KAA4B;AAAA,EAC5B;AAAA,EAER,YAAY,QAAiB;AAE3B,SAAK,YAAY,KAAK,YAAY;AAAA,EACpC;AAAA,EAEQ,cAA4B;AAClC,WAAO;AAAA,MACL,KAAK;AAAA,QACH,UAAW,QAAQ,IAAI,gBAAwB;AAAA,QAC/C,QAAQ,QAAQ,IAAI,kBAAkB,QAAQ,IAAI;AAAA,QAClD,OAAO,QAAQ,IAAI;AAAA,QACnB,SAAS,QAAQ,IAAI;AAAA,MACvB;AAAA,MACA,MAAM;AAAA,QACJ,KAAK,QAAQ,IAAI,YAAY;AAAA,QAC7B,UAAW,QAAQ,IAAI,kBAA0B;AAAA,QACjD,UAAU,QAAQ,IAAI;AAAA,QACtB,UAAU,QAAQ,IAAI;AAAA,MACxB;AAAA,MACA,QAAQ,QAAQ,IAAI,eAAe;AAAA,QACjC,OAAO,QAAQ,IAAI;AAAA,QACnB,OAAO,QAAQ,IAAI,gBAAgB;AAAA,QACnC,MAAM,QAAQ,IAAI,eAAe;AAAA,MACnC,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,YAAY,SAAS,QAAQ,IAAI,qBAAqB,SAAS;AAAA,QAC/D,eAAe,SAAS,QAAQ,IAAI,wBAAwB,IAAI;AAAA,QAChE,WAAW,QAAQ,IAAI,qBAAqB;AAAA,MAC9C;AAAA,MACA,KAAK;AAAA,QACH,MAAM,SAAS,QAAQ,IAAI,YAAY,MAAM;AAAA,QAC7C,MAAM,QAAQ,IAAI,YAAY;AAAA,MAChC;AAAA,MACA,UAAU;AAAA,QACR,MAAM,QAAQ,IAAI,WAAW;AAAA,MAC/B;AAAA,MACA,eAAe;AAAA,QACb,OAAO,QAAQ,IAAI;AAAA,QACnB,SAAS,QAAQ,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,QAAwB;AAC9B,QAAI,CAAC,KAAK,IAAI;AACZ,WAAK,KAAK,IAAI,eAAe,oBAAoB;AAAA,IACnD;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,IAAI,KAAqC;AAC7C,UAAM,UAAU,MAAM,KAAK,MAAM,EAAE,UAAU,GAAG;AAChD,QAAI,QAAS,QAAO;AAEpB,UAAM,OAAO,IAAI,MAAM,GAAG;AAC1B,QAAI,QAAa,KAAK;AACtB,eAAW,KAAK,MAAM;AACpB,cAAQ,QAAQ,CAAC;AAAA,IACnB;AACA,WAAO,OAAO,SAAS,KAAK;AAAA,EAC9B;AAAA,EAEA,MAAM,IAAI,KAAa,OAAe;AACpC,UAAM,KAAK,MAAM,EAAE,UAAU,KAAK,KAAK;AAAA,EACzC;AAAA,EAEA,MAAM,SAAgC;AACpC,UAAM,WAAW,MAAM,KAAK,MAAM,EAAE,aAAa;AACjD,UAAM,SAAS,EAAE,GAAG,KAAK,UAAU;AAEnC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,YAAM,OAAO,IAAI,MAAM,GAAG;AAC1B,UAAI,MAAW;AACf,eAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACxC,YAAI,CAAC,IAAI,KAAK,CAAC,CAAC,EAAG,KAAI,KAAK,CAAC,CAAC,IAAI,CAAC;AACnC,cAAM,IAAI,KAAK,CAAC,CAAC;AAAA,MACnB;AACA,UAAI,KAAK,KAAK,SAAS,CAAC,CAAC,IAAI;AAAA,IAC/B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAmC;AACvC,WAAO,MAAM,KAAK,OAAO;AAAA,EAC3B;AAAA;AAAA,EAGA,gBAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AACF;;;ACxIA,SAAS,gBAA+B;AAExC,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,QAAAC,aAAY;AAEd,IAAM,eAAN,MAAmB;AAAA,EAChB,UAA0B;AAAA,EAC1B,OAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA,gBAAwB;AAAA,EAEhC,YAAY,IAAoB,WAAmB;AACjD,SAAK,KAAK;AACV,SAAK,YAAY;AACjB,IAAAD,WAAU,KAAK,eAAe,EAAE,WAAW,KAAK,CAAC;AAAA,EACnD;AAAA,EAEA,MAAM,aAAa;AACjB,SAAK,UAAU,MAAM,SAAS,OAAO,EAAE,UAAU,KAAK,CAAC;AACvD,UAAM,UAAU,MAAM,KAAK,QAAQ,WAAW;AAAA,MAC5C,UAAU,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,MACtC,WAAW;AAAA,IACb,CAAC;AACD,SAAK,OAAO,MAAM,QAAQ,QAAQ;AAAA,EACpC;AAAA,EAEA,WAAW;AACT,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,KAAK,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,UAC/D;AAAA,UACA,UAAU,CAAC,KAAK;AAAA,QAClB;AAAA,QACA,SAAS,OAAO,EAAE,IAAI,MAAuB;AAC3C,cAAI,CAAC,KAAK,KAAM,OAAM,KAAK,WAAW;AAEtC,cAAI;AACF,kBAAM,KAAK,KAAM,KAAK,KAAK,EAAE,WAAW,cAAc,CAAC;AACvD,kBAAM,QAAQ,MAAM,KAAK,KAAM,MAAM;AAErC,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,gBAAgB,GAAG;AAAA,cAChC,OAAO;AAAA,cACP,QAAQ,eAAe,KAAK;AAAA,YAC9B,CAAC;AAED,mBAAO,6BAA6B,GAAG,kBAAkB,KAAK;AAAA,UAChE,SAAS,OAAY;AACnB,mBAAO,uBAAuB,MAAM,OAAO;AAAA,UAC7C;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,UAAU,EAAE,MAAM,UAAU,aAAa,uCAAuC;AAAA,UAClF;AAAA,UACA,UAAU,CAAC,UAAU;AAAA,QACvB;AAAA,QACA,SAAS,OAAO,EAAE,SAAS,MAA4B;AACrD,cAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,cAAI;AACF,kBAAM,KAAK,KAAK,MAAM,UAAU,EAAE,SAAS,IAAK,CAAC;AAEjD,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,oBAAoB,QAAQ;AAAA,cACzC,OAAO;AAAA,YACT,CAAC;AAED,mBAAO,iCAAiC,QAAQ;AAAA,UAClD,SAAS,OAAY;AACnB,mBAAO,4BAA4B,MAAM,OAAO;AAAA,UAClD;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,UAAU,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,YAC3E,MAAM,EAAE,MAAM,UAAU,aAAa,4BAA4B;AAAA,UACnE;AAAA,UACA,UAAU,CAAC,YAAY,MAAM;AAAA,QAC/B;AAAA,QACA,SAAS,OAAO,EAAE,UAAU,KAAK,MAA0C;AACzE,cAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,cAAI;AACF,kBAAM,KAAK,KAAK,KAAK,UAAU,IAAI;AAEnC,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,gBAAgB,QAAQ;AAAA,cACrC,OAAO,GAAG,QAAQ,MAAM,IAAI;AAAA,YAC9B,CAAC;AAED,mBAAO,6BAA6B,QAAQ;AAAA,UAC9C,SAAS,OAAY;AACnB,mBAAO,yBAAyB,MAAM,OAAO;AAAA,UAC/C;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,MAAM,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,UACtE;AAAA,UACA,UAAU,CAAC,MAAM;AAAA,QACnB;AAAA,QACA,SAAS,OAAO,EAAE,KAAK,MAAwB;AAC7C,cAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,cAAI;AACF,kBAAM,WAAW,GAAG,KAAK,IAAI,CAAC,IAAI,IAAI;AACtC,kBAAM,OAAOC,MAAK,KAAK,eAAe,QAAQ;AAC9C,kBAAM,KAAK,KAAK,WAAW,EAAE,MAAM,UAAU,KAAK,CAAC;AAEnD,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,eAAe,IAAI;AAAA,cAChC,iBAAiB;AAAA,YACnB,CAAC;AAED,mBAAO,qBAAqB,IAAI;AAAA,UAClC,SAAS,OAAY;AACnB,mBAAO,8BAA8B,MAAM,OAAO;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY,CAAC;AAAA,QACf;AAAA,QACA,SAAS,YAAY;AACnB,cAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,cAAI;AACF,kBAAM,UAAU,MAAM,KAAK,KAAK,YAAY,MAAM;AAClD,mBAAO,SAAS,MAAM,GAAG,GAAI,KAAK;AAAA,UACpC,SAAS,OAAY;AACnB,mBAAO,0BAA0B,MAAM,OAAO;AAAA,UAChD;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY,CAAC;AAAA,QACf;AAAA,QACA,SAAS,YAAY;AACnB,cAAI,CAAC,KAAK,KAAM,QAAO;AAEvB,gBAAM,SAAmB,CAAC;AAC1B,eAAK,KAAK,GAAG,WAAW,SAAO;AAC7B,gBAAI,IAAI,KAAK,MAAM,SAAS;AAC1B,qBAAO,KAAK,IAAI,KAAK,CAAC;AAAA,YACxB;AAAA,UACF,CAAC;AAED,gBAAM,KAAK,KAAK,eAAe,GAAI;AAEnC,cAAI,OAAO,SAAS,GAAG;AACrB,mBAAO,SAAS,OAAO,MAAM;AAAA,EAAqB,OAAO,KAAK,IAAI,CAAC;AAAA,UACrE;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ;AACZ,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,QAAQ,MAAM;AACzB,WAAK,UAAU;AACf,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AACF;;;AC3MA,SAAS,eAAe;AAGjB,IAAM,cAAN,MAAkB;AAAA,EACf,UAA0B;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,IAAoB,WAAmB,QAA2D;AAC5G,SAAK,KAAK;AACV,SAAK,YAAY;AACjB,SAAK,SAAS;AAEd,QAAI,OAAO,OAAO;AAChB,WAAK,UAAU,IAAI,QAAQ,EAAE,MAAM,OAAO,MAAM,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,WAAW;AACT,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,OAAO,EAAE,MAAM,UAAU,aAAa,wCAAwC;AAAA,YAC9E,MAAM,EAAE,MAAM,UAAU,aAAa,+CAA+C;AAAA,YACpF,UAAU,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,UAAU,QAAQ,UAAU,GAAG,aAAa,eAAe;AAAA,YACrG,QAAQ,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,uBAAuB;AAAA,YACxF,iBAAiB,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,UAChF;AAAA,UACA,UAAU,CAAC,SAAS,QAAQ,UAAU;AAAA,QACxC;AAAA,QACA,SAAS,OAAO,EAAE,OAAO,MAAM,UAAU,SAAS,CAAC,GAAG,gBAAgB,MAAW;AAC/E,cAAI,CAAC,KAAK,WAAW,CAAC,KAAK,OAAO,SAAS,CAAC,KAAK,OAAO,MAAM;AAC5D,mBAAO;AAAA,UACT;AAEA,cAAI;AACF,kBAAM,gBAAgB,aAAa,QAAQ;AAC3C,kBAAM,YAAY,CAAC,gBAAgB,eAAe,GAAG,MAAM;AAE3D,kBAAM,YAAY;AAAA;AAAA,EAE5B,IAAI;AAAA;AAAA;AAAA;AAAA,gBAIU,SAAS,YAAY,CAAC;AAAA;AAAA,kBAEpB,KAAK,SAAS;AAAA,EAC9B,kBAAkB,mBAAmB,eAAe,KAAK,EAAE;AAAA;AAAA;AAIjD,kBAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK,OAAO,OAAO;AAAA,cAClD,OAAO,KAAK,OAAO;AAAA,cACnB,MAAM,KAAK,OAAO;AAAA,cAClB,OAAO,QAAQ,KAAK;AAAA,cACpB,MAAM;AAAA,cACN,QAAQ;AAAA,YACV,CAAC;AAED,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,yBAAyB,KAAK;AAAA,cAC3C,OAAO,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,cACzC,QAAQ,MAAM,KAAK;AAAA,YACrB,CAAC;AAED,kBAAM,MAAM,KAAK,GAAG,UAAU;AAAA,cAC5B,YAAY,KAAK;AAAA,cACjB;AAAA,cACA,aAAa;AAAA,cACb;AAAA,cACA,QAAQ;AAAA,cACR,kBAAkB,MAAM,KAAK;AAAA,cAC7B;AAAA,YACF,CAAC;AAED,mBAAO;AAAA,OAA8C,MAAM,KAAK,QAAQ;AAAA,SAAY,MAAM,KAAK,MAAM;AAAA,UACvG,SAAS,OAAY;AACnB,mBAAO,yCAAoC,MAAM,OAAO;AAAA,UAC1D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzFO,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA;AAAA,EAER,YAAY,IAAoB,WAAmB;AACjD,SAAK,KAAK;AACV,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,WAAW;AACT,WAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,OAAO,EAAE,MAAM,UAAU,aAAa,eAAe;AAAA,YACrD,aAAa,EAAE,MAAM,UAAU,aAAa,uBAAuB;AAAA,YACnE,UAAU,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,UAAU,QAAQ,UAAU,GAAG,aAAa,kBAAkB;AAAA,YACxG,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,WAAW,SAAS,eAAe,MAAM,GAAG,aAAa,gBAAgB;AAAA,YAC1G,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,GAAG,aAAa,0BAA0B;AAAA,YACzF,iBAAiB,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,UAChF;AAAA,UACA,UAAU,CAAC,SAAS,eAAe,UAAU;AAAA,QAC/C;AAAA,QACA,SAAS,OAAO,EAAE,OAAO,aAAa,UAAU,SAAS,SAAS,OAAO,CAAC,GAAG,gBAAgB,MAAW;AACtG,cAAI;AACF,kBAAM,UAAU,CAAC,gBAAgB,GAAG,IAAI;AAExC,kBAAM,SAAS,KAAK,GAAG,mBAAmB;AAAA,cACxC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,MAAM,KAAK,UAAU,OAAO;AAAA,cAC5B,gBAAgB;AAAA,YAClB,CAAC;AAED,iBAAK,GAAG,aAAa;AAAA,cACnB,YAAY,KAAK;AAAA,cACjB,MAAM;AAAA,cACN,aAAa,0BAA0B,KAAK;AAAA,cAC5C,OAAO,KAAK,UAAU,EAAE,OAAO,UAAU,OAAO,CAAC;AAAA,cACjD,QAAQ,OAAO;AAAA,YACjB,CAAC;AAED,mBAAO;AAAA,MAA8C,OAAO,EAAE;AAAA,UAAa,MAAM;AAAA,YAAe,QAAQ;AAAA,UAC1G,SAAS,OAAY;AACnB,mBAAO,0CAAqC,MAAM,OAAO;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,YACV,WAAW,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,YACvE,QAAQ,EAAE,MAAM,UAAU,MAAM,CAAC,WAAW,SAAS,eAAe,MAAM,GAAG,aAAa,aAAa;AAAA,YACvG,UAAU,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,UAAU,QAAQ,UAAU,GAAG,aAAa,eAAe;AAAA,UACvG;AAAA,UACA,UAAU,CAAC,WAAW;AAAA,QACxB;AAAA,QACA,SAAS,OAAO,EAAE,WAAW,QAAQ,SAAS,MAAW;AACvD,cAAI;AACF,kBAAM,UAAe,CAAC;AACtB,gBAAI,OAAQ,SAAQ,SAAS;AAC7B,gBAAI,SAAU,SAAQ,WAAW;AAEjC,iBAAK,GAAG,mBAAmB,WAAW,OAAO;AAE7C,mBAAO,wBAAmB,SAAS;AAAA,UACrC,SAAS,OAAY;AACnB,mBAAO,0CAAqC,MAAM,OAAO;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY,CAAC;AAAA,QACf;AAAA,QACA,SAAS,YAAY;AACnB,cAAI;AACF,kBAAM,UAAU,KAAK,GAAG,iBAAiB;AAEzC,kBAAM,WAAW;AAAA,cACf,SAAS,QAAQ,OAAO,OAAK,EAAE,WAAW,SAAS;AAAA,cACnD,SAAS,QAAQ,OAAO,OAAK,EAAE,WAAW,OAAO;AAAA,cACjD,eAAe,QAAQ,OAAO,OAAK,EAAE,WAAW,aAAa;AAAA,cAC7D,MAAM,QAAQ,OAAO,OAAK,EAAE,WAAW,MAAM;AAAA,YAC/C;AAEA,kBAAM,UAAU;AAAA;AAAA,aAEf,SAAS,QAAQ,MAAM;AAAA,WACzB,SAAS,OAAO,EAAE,MAAM;AAAA,iBAClB,SAAS,aAAa,EAAE,MAAM;AAAA,UACrC,SAAS,KAAK,MAAM;AAAA;AAAA,SAErB,QAAQ,MAAM;AAAA,cACT,KAAK;AAEP,mBAAO;AAAA,UACT,SAAS,OAAY;AACnB,mBAAO,sCAAiC,MAAM,OAAO;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACrHA,SAAS,oBAAoB;AAC7B,SAAS,WAAAC,gBAAe;AAsDjB,IAAM,cAAN,cAA0B,aAAa;AAAA,EACpC;AAAA,EACA,UAA0B;AAAA,EAC1B,gBAA+B;AAAA,EAC/B,iBAAgC;AAAA,EAChC,eAAsC;AAAA,EACtC,YAAqB;AAAA,EAE7B,YAAY,QAA2B;AACrC,UAAM;AACN,SAAK,SAAS;AAAA,MACZ,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,GAAG;AAAA,IACL;AAEA,QAAI,OAAO,aAAa,YAAY,OAAO,OAAO;AAChD,WAAK,UAAU,IAAIA,SAAQ,EAAE,MAAM,OAAO,MAAM,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ;AACZ,QAAI,KAAK,UAAW;AACpB,SAAK,YAAY;AAEjB,YAAQ,IAAI,qCAA8B,KAAK,OAAO,QAAQ,IAAI,KAAK,OAAO,KAAK,IAAI,KAAK,OAAO,IAAI,EAAE;AAEzG,UAAM,KAAK,kBAAkB;AAE7B,SAAK,eAAe,YAAY,MAAM;AACpC,WAAK,KAAK,EAAE,MAAM,QAAQ,KAAK;AAAA,IACjC,GAAG,KAAK,OAAO,cAAc;AAAA,EAC/B;AAAA,EAEA,OAAO;AACL,SAAK,YAAY;AACjB,QAAI,KAAK,cAAc;AACrB,oBAAc,KAAK,YAAY;AAC/B,WAAK,eAAe;AAAA,IACtB;AACA,YAAQ,IAAI,+BAAwB;AAAA,EACtC;AAAA,EAEA,MAAc,oBAAoB;AAChC,QAAI;AACF,UAAI,KAAK,OAAO,aAAa,UAAU;AACrC,cAAM,KAAK,iBAAiB;AAAA,MAC9B,OAAO;AACL,cAAM,KAAK,iBAAiB;AAAA,MAC9B;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,kCAAkC,KAAK;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAc,OAAO;AACnB,QAAI;AACF,UAAI,KAAK,OAAO,aAAa,UAAU;AACrC,cAAM,KAAK,WAAW;AAAA,MACxB,OAAO;AACL,cAAM,KAAK,WAAW;AAAA,MACxB;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,eAAe,KAAK;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB;AAC/B,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,KAAK,QAAQ,MAAM,YAAY;AAAA,MAC7D,OAAO,KAAK,OAAO;AAAA,MACnB,MAAM,KAAK,OAAO;AAAA,MAClB,KAAK,KAAK,OAAO;AAAA,MACjB,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,QAAQ,SAAS,GAAG;AACtB,WAAK,gBAAgB,QAAQ,CAAC,EAAE;AAAA,IAClC;AAEA,QAAI;AACF,YAAM,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,QAAQ,QAAQ,wBAAwB;AAAA,QACxE,OAAO,KAAK,OAAO;AAAA,QACnB,MAAM,KAAK,OAAO;AAAA,QAClB,QAAQ,KAAK,OAAO;AAAA,QACpB,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,KAAK,cAAc,SAAS,GAAG;AACjC,aAAK,iBAAiB,KAAK,cAAc,CAAC,EAAE,GAAG,SAAS;AAAA,MAC1D;AAAA,IACF,QAAQ;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,aAAa;AACzB,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,EAAE,MAAM,QAAQ,IAAI,MAAM,KAAK,QAAQ,MAAM,YAAY;AAAA,MAC7D,OAAO,KAAK,OAAO;AAAA,MACnB,MAAM,KAAK,OAAO;AAAA,MAClB,KAAK,KAAK,OAAO;AAAA,MACjB,UAAU;AAAA,IACZ,CAAC;AAED,eAAW,UAAU,SAAS;AAC5B,UAAI,KAAK,iBAAiB,OAAO,QAAQ,KAAK,cAAe;AAE7D,YAAM,UAAU,OAAO,WAAW,OAAO,QAAQ,SAAS;AAE1D,YAAM,QAAkB;AAAA,QACtB,MAAM,UAAU,UAAU;AAAA,QAC1B,UAAU;AAAA,QACV,QAAQ,KAAK,OAAO;AAAA,QACpB,QAAQ,OAAO;AAAA,QACf,QAAQ,OAAO,OAAO,QAAQ,QAAQ;AAAA,QACtC,SAAS,OAAO,OAAO;AAAA,QACvB,WAAW,IAAI,KAAK,OAAO,OAAO,QAAQ,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC9D;AAEA,WAAK,KAAK,aAAa,KAAK;AAE5B,UAAI,SAAS;AACX,aAAK,KAAK,SAAS,KAAK;AACxB,gBAAQ,IAAI,+BAAwB,KAAK,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,GAAG,CAAC,CAAC,EAAE;AAAA,MACrF;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,GAAG;AACtB,WAAK,gBAAgB,QAAQ,CAAC,EAAE;AAAA,IAClC;AAEA,QAAI;AACF,YAAM,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,QAAQ,QAAQ,wBAAwB;AAAA,QACxE,OAAO,KAAK,OAAO;AAAA,QACnB,MAAM,KAAK,OAAO;AAAA,QAClB,QAAQ,KAAK,OAAO;AAAA,QACpB,UAAU;AAAA,MACZ,CAAC;AAED,iBAAW,OAAO,KAAK,eAAe;AACpC,YAAI,KAAK,kBAAkB,IAAI,GAAG,SAAS,MAAM,KAAK,eAAgB;AAEtE,YAAI,IAAI,WAAW,aAAa;AAC9B,gBAAM,QAAkB;AAAA,YACtB,MAAM,IAAI,eAAe,YAAY,qBAAqB;AAAA,YAC1D,UAAU;AAAA,YACV,QAAQ,KAAK,OAAO;AAAA,YACpB,QAAQ,IAAI;AAAA,YACZ,QAAQ,IAAI,OAAO,SAAS;AAAA,YAC5B,SAAS,IAAI,QAAQ;AAAA,YACrB,WAAW,IAAI,KAAK,IAAI,cAAc,KAAK,IAAI,CAAC;AAAA,YAChD,YAAY,IAAI,GAAG,SAAS;AAAA,YAC5B,gBAAgB,IAAI,cAAc;AAAA,UACpC;AAEA,eAAK,KAAK,aAAa,KAAK;AAE5B,cAAI,IAAI,eAAe,WAAW;AAChC,iBAAK,KAAK,oBAAoB,KAAK;AACnC,oBAAQ,IAAI,4BAAuB,IAAI,IAAI,KAAK,IAAI,EAAE,GAAG;AAAA,UAC3D,OAAO;AACL,iBAAK,KAAK,oBAAoB,KAAK;AACnC,oBAAQ,IAAI,4BAAuB,IAAI,IAAI,KAAK,IAAI,EAAE,GAAG;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAEA,UAAI,KAAK,cAAc,SAAS,GAAG;AACjC,aAAK,iBAAiB,KAAK,cAAc,CAAC,EAAE,GAAG,SAAS;AAAA,MAC1D;AAAA,IACF,QAAQ;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB;AAC/B,UAAM,UAAU,EAAE,iBAAiB,KAAK,OAAO,MAAM;AACrD,UAAM,cAAc,mBAAmB,GAAG,KAAK,OAAO,KAAK,IAAI,KAAK,OAAO,IAAI,EAAE;AACjF,UAAM,UAAU,KAAK,OAAO;AAE5B,QAAI;AACF,YAAM,aAAa,MAAM;AAAA,QACvB,GAAG,OAAO,oBAAoB,WAAW,gCAAgC,KAAK,OAAO,MAAM;AAAA,QAC3F,EAAE,QAAQ;AAAA,MACZ;AACA,YAAM,UAAU,MAAM,WAAW,KAAK;AACtC,UAAI,QAAQ,SAAS,GAAG;AACtB,aAAK,gBAAgB,QAAQ,CAAC,EAAE;AAAA,MAClC;AAEA,YAAM,eAAe,MAAM;AAAA,QACzB,GAAG,OAAO,oBAAoB,WAAW,kBAAkB,KAAK,OAAO,MAAM;AAAA,QAC7E,EAAE,QAAQ;AAAA,MACZ;AACA,YAAM,YAAY,MAAM,aAAa,KAAK;AAC1C,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,iBAAiB,UAAU,CAAC,EAAE,GAAG,SAAS;AAAA,MACjD;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,+BAA+B,KAAK;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAc,aAAa;AACzB,UAAM,UAAU,EAAE,iBAAiB,KAAK,OAAO,MAAM;AACrD,UAAM,cAAc,mBAAmB,GAAG,KAAK,OAAO,KAAK,IAAI,KAAK,OAAO,IAAI,EAAE;AACjF,UAAM,UAAU,KAAK,OAAO;AAE5B,QAAI;AACF,YAAM,aAAa,MAAM;AAAA,QACvB,GAAG,OAAO,oBAAoB,WAAW,gCAAgC,KAAK,OAAO,MAAM;AAAA,QAC3F,EAAE,QAAQ;AAAA,MACZ;AACA,YAAM,UAAU,MAAM,WAAW,KAAK;AAEtC,iBAAW,UAAU,SAAS;AAC5B,YAAI,KAAK,iBAAiB,OAAO,OAAO,KAAK,cAAe;AAE5D,cAAM,UAAU,OAAO,cAAc,OAAO,WAAW,SAAS;AAEhE,cAAM,QAAkB;AAAA,UACtB,MAAM,UAAU,UAAU;AAAA,UAC1B,UAAU;AAAA,UACV,QAAQ,KAAK,OAAO;AAAA,UACpB,QAAQ,OAAO;AAAA,UACf,QAAQ,OAAO;AAAA,UACf,SAAS,OAAO;AAAA,UAChB,WAAW,IAAI,KAAK,OAAO,UAAU;AAAA,QACvC;AAEA,aAAK,KAAK,aAAa,KAAK;AAE5B,YAAI,SAAS;AACX,eAAK,KAAK,SAAS,KAAK;AACxB,kBAAQ,IAAI,+BAAwB,KAAK,OAAO,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE;AAAA,QACpF;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,GAAG;AACtB,aAAK,gBAAgB,QAAQ,CAAC,EAAE;AAAA,MAClC;AAEA,YAAM,eAAe,MAAM;AAAA,QACzB,GAAG,OAAO,oBAAoB,WAAW,kBAAkB,KAAK,OAAO,MAAM;AAAA,QAC7E,EAAE,QAAQ;AAAA,MACZ;AACA,YAAM,YAAY,MAAM,aAAa,KAAK;AAE1C,iBAAW,YAAY,WAAW;AAChC,YAAI,KAAK,kBAAkB,SAAS,GAAG,SAAS,MAAM,KAAK,eAAgB;AAE3E,YAAI,SAAS,WAAW,aAAa,SAAS,WAAW,UAAU;AACjE,gBAAM,QAAkB;AAAA,YACtB,MAAM,SAAS,WAAW,YAAY,qBAAqB;AAAA,YAC3D,UAAU;AAAA,YACV,QAAQ,KAAK,OAAO;AAAA,YACpB,QAAQ,SAAS;AAAA,YACjB,QAAQ,SAAS,MAAM,QAAQ;AAAA,YAC/B,SAAS,aAAa,SAAS,EAAE;AAAA,YACjC,WAAW,IAAI,KAAK,SAAS,UAAU;AAAA,YACvC,YAAY,SAAS,GAAG,SAAS;AAAA,YACjC,gBAAgB,SAAS;AAAA,UAC3B;AAEA,eAAK,KAAK,aAAa,KAAK;AAE5B,cAAI,SAAS,WAAW,WAAW;AACjC,iBAAK,KAAK,oBAAoB,KAAK;AACnC,oBAAQ,IAAI,6BAAwB,SAAS,EAAE,EAAE;AAAA,UACnD,OAAO;AACL,iBAAK,KAAK,oBAAoB,KAAK;AACnC,oBAAQ,IAAI,6BAAwB,SAAS,EAAE,EAAE;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAEA,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,iBAAiB,UAAU,CAAC,EAAE,GAAG,SAAS;AAAA,MACjD;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,sBAAsB,KAAK;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,YAAqC;AACtD,QAAI,KAAK,OAAO,aAAa,UAAU;AACrC,aAAO,KAAK,mBAAmB,UAAU;AAAA,IAC3C,OAAO;AACL,aAAO,KAAK,mBAAmB,UAAU;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,MAAc,mBAAmB,YAAqC;AACpE,QAAI,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,uBAAuB;AAE1D,UAAM,EAAE,KAAK,IAAI,MAAM,KAAK,QAAQ,MAAM,cAAc;AAAA,MACtD,OAAO,KAAK,OAAO;AAAA,MACnB,MAAM,KAAK,OAAO;AAAA,MAClB,QAAQ;AAAA,QACN,KAAK;AAAA,QACL,cAAc;AAAA,MAChB;AAAA,MACA,QAAQ,CAAC,QAAQ,gBAAgB,cAAc;AAAA,IACjD,CAAC;AAED,WAAO,KAAK,GAAG,SAAS;AAAA,EAC1B;AAAA,EAEA,MAAc,mBAAmB,YAAqC;AACpE,UAAM,UAAU;AAAA,MACd,iBAAiB,KAAK,OAAO;AAAA,MAC7B,gBAAgB;AAAA,IAClB;AACA,UAAM,cAAc,mBAAmB,GAAG,KAAK,OAAO,KAAK,IAAI,KAAK,OAAO,IAAI,EAAE;AAEjF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,KAAK,OAAO,SAAS,oBAAoB,WAAW;AAAA,MACvD;AAAA,QACE,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,KAAK;AAAA,UACL,aAAa;AAAA,UACb,uBAAuB;AAAA,UACvB,iBAAiB;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,KAAK,GAAG,SAAS;AAAA,EAC1B;AACF;;;ACrYA,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,gBAAAC,qBAAoB;AAoC7B,IAAM,qBAAgD;AAAA,EACpD,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASf,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASd,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASpB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUxB,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUtB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUd,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUf,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASvB;AAEO,IAAM,yBAAN,cAAqCA,cAAa;AAAA,EAC/C,SAAkC,oBAAI,IAAI;AAAA,EAC1C,gBAA0C,oBAAI,IAAI;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACE,IACA,WACA,WACA,cACA;AACA,UAAM;AACN,SAAK,KAAK;AACV,SAAK,YAAY;AACjB,SAAK,YAAY;AACjB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,mBAAmB;AACzB,QAAI,KAAK,UAAU,aAAa,aAAa;AAC3C,aAAO,IAAI,iBAAiB;AAAA,QAC1B,QAAQ,KAAK,UAAU;AAAA,QACvB,OAAO,KAAK,UAAU,SAAS;AAAA,MACjC,CAAC;AAAA,IACH;AACA,WAAO,IAAI,cAAc;AAAA,MACvB,QAAQ,KAAK,UAAU;AAAA,MACvB,OAAO,KAAK,UAAU,SAAS;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,MAAiB,cAA+B;AAC/D,UAAM,UAAU,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC;AAErC,UAAM,eAAe,gBAAgB,mBAAmB,IAAI;AAE5D,UAAM,QAAQ,IAAI,WAAW;AAAA,MAC3B,KAAK,KAAK,iBAAiB;AAAA,MAC3B,OAAO,KAAK,aAAa,SAAS;AAAA,MAClC,eAAe;AAAA,MACf,cAAc,GAAG,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQ/B,CAAC;AAED,SAAK,OAAO,IAAI,SAAS,KAAK;AAE9B,UAAM,SAAsB;AAAA,MAC1B,IAAI;AAAA,MACJ;AAAA,MACA,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AACA,SAAK,cAAc,IAAI,SAAS,MAAM;AAEtC,SAAK,KAAK,iBAAiB,MAAM;AAEjC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,SAAiB,WAAkC;AACrE,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AACrC,UAAM,SAAS,KAAK,cAAc,IAAI,OAAO;AAE7C,QAAI,CAAC,SAAS,CAAC,QAAQ;AACrB,YAAM,IAAI,MAAM,SAAS,OAAO,YAAY;AAAA,IAC9C;AAEA,WAAO,SAAS;AAChB,WAAO,YAAY,oBAAI,KAAK;AAC5B,WAAO,WAAW;AAClB,SAAK,KAAK,iBAAiB,MAAM;AAEjC,QAAI;AACF,YAAM,SAAS,MAAM,MAAM;AAAA,QACzB,2BAA2B,SAAS;AAAA,MACtC;AAEA,aAAO,SAAS;AAChB,aAAO,cAAc,oBAAI,KAAK;AAC9B,aAAO,WAAW;AAElB,WAAK,KAAK,mBAAmB,EAAE,GAAG,QAAQ,OAAO,CAAC;AAAA,IAEpD,SAAS,OAAY;AACnB,aAAO,SAAS;AAChB,aAAO,cAAc,oBAAI,KAAK;AAE9B,WAAK,KAAK,gBAAgB,EAAE,GAAG,QAAQ,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,WAAmB,OAAoC;AAC7E,UAAM,aAAa,SAAS;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,WAAW,WAAW,IAAI,UAAQ,KAAK,iBAAiB,IAAI,CAAC;AAEnE,eAAW,WAAW,UAAU;AAC9B,YAAM,KAAK,cAAc,SAAS,SAAS;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,WAAkC;AACvD,UAAM,gBAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,KAAK,kBAAkB,WAAW,aAAa;AAAA,EACvD;AAAA,EAEA,eAAe,SAA0C;AACvD,WAAO,KAAK,cAAc,IAAI,OAAO;AAAA,EACvC;AAAA,EAEA,iBAAgC;AAC9B,WAAO,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAAA,EAC/C;AAAA,EAEA,UAAU,SAAuB;AAC/B,UAAM,SAAS,KAAK,cAAc,IAAI,OAAO;AAC7C,QAAI,UAAU,OAAO,WAAW,WAAW;AACzC,aAAO,SAAS;AAChB,aAAO,cAAc,oBAAI,KAAK;AAC9B,WAAK,KAAK,iBAAiB,MAAM;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,eAAW,CAAC,OAAO,KAAK,KAAK,QAAQ;AACnC,WAAK,UAAU,OAAO;AAAA,IACxB;AAAA,EACF;AACF;;;ACvQA,IAAM,iBAAkE;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMR,UAAU,CAAC,MAAM,QAAQ,WAAW,SAAS;AAAA,EAC/C;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOR,UAAU,CAAC,UAAU,cAAc,UAAU;AAAA,EAC/C;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQR,UAAU,CAAC,QAAQ,QAAQ,YAAY,WAAW,WAAW;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOR,UAAU,CAAC,QAAQ,SAAS,MAAM;AAAA,EACpC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQR,UAAU,CAAC,SAAS,OAAO,WAAW;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMR,UAAU,CAAC,QAAQ,SAAS,SAAS,MAAM;AAAA,EAC7C;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA,SAA6B,oBAAI,IAAI;AAAA,EAE7C,YAAY,IAAoB;AAC9B,SAAK,KAAK;AACV,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,aAAa;AACnB,UAAM,cAAc,KAAK,GAAG,UAAU,QAAQ;AAE9C,QAAI,aAAa;AACf,YAAM,SAAS,KAAK,MAAM,WAAW;AACrC,aAAO,QAAQ,WAAS,KAAK,OAAO,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,IAC1D,OAAO;AACL,qBAAe,QAAQ,WAAS;AAC9B,aAAK,YAAY,KAAK;AAAA,MACxB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,aAAa;AACnB,UAAM,cAAc,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AACnD,SAAK,GAAG,UAAU,UAAU,KAAK,UAAU,WAAW,CAAC;AAAA,EACzD;AAAA,EAEA,YAAY,MAA4D;AACtE,UAAM,QAAe;AAAA,MACnB,GAAG;AAAA,MACH,IAAI,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,MAClE,WAAW,oBAAI,KAAK;AAAA,MACpB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,OAAO,IAAI,MAAM,IAAI,KAAK;AAC/B,SAAK,WAAW;AAEhB,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,IAAY,SAAiE;AACvF,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,UAAiB;AAAA,MACrB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,WAAW,oBAAI,KAAK;AAAA,IACtB;AAEA,SAAK,OAAO,IAAI,IAAI,OAAO;AAC3B,SAAK,WAAW;AAEhB,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,IAAqB;AAC/B,UAAM,UAAU,KAAK,OAAO,OAAO,EAAE;AACrC,QAAI,SAAS;AACX,WAAK,WAAW;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,IAA+B;AACtC,WAAO,KAAK,OAAO,IAAI,EAAE;AAAA,EAC3B;AAAA,EAEA,eAAwB;AACtB,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,aAAa,EACtB,OAAO,OAAK,EAAE,OAAO,EACrB,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAC3C;AAAA,EAEA,gBAAgB,MAA8B;AAC5C,WAAO,KAAK,aAAa,EAAE,OAAO,OAAK,EAAE,SAAS,IAAI;AAAA,EACxD;AAAA,EAEA,oBAAoB,MAAuB;AACzC,UAAM,YAAY,KAAK,YAAY;AACnC,WAAO,KAAK,iBAAiB,EAAE;AAAA,MAAO,WACpC,MAAM,UAAU,KAAK,aAAW,UAAU,SAAS,QAAQ,YAAY,CAAC,CAAC;AAAA,IAC3E;AAAA,EACF;AAAA,EAEA,oBAAoB,QAAyB;AAC3C,QAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,UAAM,oBAAoB,OAAO;AAAA,MAAI,CAAC,OAAO,UAC3C,aAAa,QAAQ,CAAC,KAAK,MAAM,IAAI;AAAA,EAAK,MAAM,MAAM;AAAA,IACxD,EAAE,KAAK,MAAM;AAEb,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKT,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAIjB;AAAA,EAEA,YAAY,IAA0B;AACpC,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO,QAAO;AAEnB,WAAO,KAAK,YAAY,IAAI,EAAE,SAAS,CAAC,MAAM,QAAQ,CAAC;AAAA,EACzD;AAAA,EAEA,cAAc,YAA4B;AACxC,eAAW,QAAQ,CAAC,IAAI,UAAU;AAChC,YAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,UAAI,OAAO;AACT,cAAM,WAAW,QAAQ;AACzB,cAAM,YAAY,oBAAI,KAAK;AAAA,MAC7B;AAAA,IACF,CAAC;AACD,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,eAAuB;AACrB,WAAO,KAAK,UAAU,KAAK,aAAa,GAAG,MAAM,CAAC;AAAA,EACpD;AAAA,EAEA,aAAa,MAAsB;AACjC,UAAM,WAAW,KAAK,MAAM,IAAI;AAChC,QAAI,QAAQ;AAEZ,aAAS,QAAQ,WAAS;AACxB,YAAM,WAAW,KAAK,YAAY;AAAA,QAChC,MAAM,MAAM;AAAA,QACZ,aAAa,MAAM;AAAA,QACnB,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,UAAU,MAAM;AAAA,MAClB,CAAC;AACD,UAAI,SAAU;AAAA,IAChB,CAAC;AAED,WAAO;AAAA,EACT;AACF;;;AR3PO,IAAM,cAAN,cAA0BC,cAAa;AAAA,EACpC,QAA2B;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,eAAoC;AAAA,EACpC,YAAoB;AAAA,EACpB,YAAqB;AAAA,EACrB,aAAoC;AAAA;AAAA,EAGpC,cAAkC;AAAA,EAClC,oBAAmD;AAAA,EACnD;AAAA,EAER,YAAY,YAAqB;AAC/B,UAAM;AACN,SAAK,SAAS,IAAI,cAAc,UAAU;AAC1C,SAAK,KAAK,IAAI,eAAe,oBAAoB;AACjD,SAAK,eAAe,IAAI,aAAa,KAAK,EAAE;AAAA,EAC9C;AAAA,EAEQ,mBAAmB;AACzB,UAAM,MAAM,KAAK,OAAO,cAAc;AAEtC,YAAQ,IAAI,IAAI,UAAU;AAAA,MACxB,KAAK;AACH,eAAO,IAAIC,kBAAiB;AAAA,UAC1B,QAAQ,IAAI,IAAI,UAAU,QAAQ,IAAI;AAAA,UACtC,OAAO,IAAI,IAAI,SAAS;AAAA,QAC1B,CAAC;AAAA,MACH,KAAK;AAAA,MACL;AACE,eAAO,IAAIC,eAAc;AAAA,UACvB,QAAQ,IAAI,IAAI,UAAU,QAAQ,IAAI;AAAA,UACtC,OAAO,IAAI,IAAI,SAAS;AAAA,QAC1B,CAAC;AAAA,IACL;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,cAAyE,UAAU,aAAmB;AACrH,UAAM,MAAM,KAAK,OAAO,cAAc;AACtC,SAAK,YAAY,WAAW,KAAK,IAAI,CAAC;AAEtC,UAAM,KAAK,GAAG,cAAc,KAAK,WAAW;AAAA,MAC1C,QAAQ;AAAA,MACR,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,cAAc;AAAA,MACd,cAAc,cAAc,KAAK,UAAU,WAAW,IAAI;AAAA,IAC5D,CAAC;AAED,SAAK,eAAe,IAAI,aAAa,KAAK,IAAI,KAAK,SAAS;AAC5D,UAAM,cAAc,IAAI,YAAY,KAAK,IAAI,KAAK,WAAW,IAAI,UAAU,CAAC,CAAC;AAC7E,UAAM,cAAc,IAAI,YAAY,KAAK,IAAI,KAAK,SAAS;AAE3D,UAAM,WAAW;AAAA,MACf,GAAG,KAAK,aAAa,SAAS;AAAA,MAC9B,GAAG,YAAY,SAAS;AAAA,MACxB,GAAG,YAAY,SAAS;AAAA,IAC1B;AAEA,UAAM,MAAM,KAAK,iBAAiB;AAClC,UAAM,SAAS,IAAI,cAAc,EAAE,aAAa,GAAG,CAAC;AACpD,UAAM,SAAS,IAAI,OAAO,EAAE,UAAU,OAAO,CAAC;AAG9C,UAAM,gBAAgB,KAAK,aAAa,iBAAiB;AACzD,UAAM,cAAc,KAAK,aAAa,oBAAoB,aAAa;AAEvE,UAAM,cAAc;AAAA,MAClB,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA,eAAe,IAAI,MAAM;AAAA,MACzB,cAAc;AAAA;AAAA;AAAA,qDAGiC,IAAI,KAAK,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwB/D,WAAW;AAAA;AAAA;AAAA,IAGT;AAEA,SAAK,QAAQ,IAAIC,YAAW,aAAa,KAAK,MAAM;AAGpD,SAAK,oBAAoB,IAAI;AAAA,MAC3B,KAAK;AAAA,MACL,KAAK;AAAA,MACL,EAAE,UAAU,IAAI,IAAI,UAAU,QAAQ,IAAI,IAAI,UAAU,GAAG;AAAA,MAC3D,KAAK;AAAA,IACP;AAGA,SAAK,kBAAkB,GAAG,iBAAiB,CAAC,WAAwB,KAAK,KAAK,sBAAsB,MAAM,CAAC;AAC3G,SAAK,kBAAkB,GAAG,iBAAiB,CAAC,WAAwB,KAAK,KAAK,sBAAsB,MAAM,CAAC;AAC3G,SAAK,kBAAkB,GAAG,mBAAmB,CAAC,SAAc,KAAK,KAAK,wBAAwB,IAAI,CAAC;AACnG,SAAK,kBAAkB,GAAG,gBAAgB,CAAC,SAAc,KAAK,KAAK,qBAAqB,IAAI,CAAC;AAE7F,YAAQ,IAAI,6CAAwC,KAAK,SAAS,GAAG;AAAA,EACvE;AAAA,EAEA,MAAM,aAAa;AACjB,QAAI,CAAC,KAAK,OAAO;AACf,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,UAAM,MAAM,KAAK,OAAO,UAAU;AAClC,YAAQ,IAAI,uCAAgC,IAAI,KAAK,GAAG,EAAE;AAE1D,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,MAAO;AAAA,QAC/B,uCAAuC,IAAI,KAAK,GAAG;AAAA,MACrD;AAEA,WAAK,GAAG,cAAc,KAAK,WAAW;AAAA,QACpC,QAAQ;AAAA,QACR,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,CAAC;AAED,cAAQ,IAAI,kCAA6B,MAAM;AAC/C,aAAO;AAAA,IACT,SAAS,OAAY;AACnB,cAAQ,MAAM,yBAAoB,KAAK;AAEvC,WAAK,GAAG,cAAc,KAAK,WAAW;AAAA,QACpC,QAAQ;AAAA,QACR,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,CAAC;AAED,YAAM;AAAA,IACR,UAAE;AACA,UAAI,KAAK,cAAc;AACrB,cAAM,KAAK,aAAa,MAAM;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB;AACtB,QAAI,KAAK,WAAW;AAClB,cAAQ,IAAI,wCAA8B;AAC1C;AAAA,IACF;AAEA,SAAK,YAAY;AACjB,UAAM,MAAM,KAAK,OAAO,UAAU;AAElC,YAAQ,IAAI,oDAA6C;AACzD,YAAQ,IAAI,qBAAc,IAAI,KAAK,GAAG,EAAE;AACxC,YAAQ,IAAI,2BAAiB,IAAI,MAAM,UAAU,OAAO,IAAI,MAAM,aAAa,MAAO,EAAE,WAAW;AAGnG,UAAM,KAAK,iBAAiB;AAE5B,UAAM,UAAU,YAAY;AAC1B,UAAI,CAAC,KAAK,UAAW;AAErB,UAAI;AACF,cAAM,KAAK,WAAW;AAAA,MACxB,SAAS,OAAO;AACd,gBAAQ,MAAM,6CAA6C;AAAA,MAC7D;AAEA,UAAI,KAAK,WAAW;AAClB,aAAK,YAAY,WAAW,KAAK,IAAI,CAAC;AACtC,aAAK,QAAQ;AACb,aAAK,eAAe;AAEpB,aAAK,aAAa,WAAW,SAAS,IAAI,MAAM,UAAU;AAAA,MAC5D;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,EAChB;AAAA,EAEA,OAAO;AACL,YAAQ,IAAI,oCAA6B;AACzC,SAAK,YAAY;AAEjB,QAAI,KAAK,YAAY;AACnB,mBAAa,KAAK,UAAU;AAC5B,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,KAAK;AACtB,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,KAAK,mBAAmB;AAC1B,WAAK,kBAAkB,QAAQ;AAAA,IACjC;AAEA,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,mBAAmB;AAC/B,UAAM,MAAM,KAAK,OAAO,UAAU;AAGlC,QAAI,IAAI,QAAQ,SAAS,IAAI,QAAQ,SAAS,IAAI,QAAQ,MAAM;AAC9D,WAAK,cAAc,IAAI,YAAY;AAAA,QACjC,UAAU;AAAA,QACV,OAAO,IAAI,OAAO;AAAA,QAClB,OAAO,IAAI,OAAO;AAAA,QAClB,MAAM,IAAI,OAAO;AAAA,QACjB,QAAQ;AAAA,QACR,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH,WAES,KAAK,OAAO,IAAI,cAAc,KAAK,KAAK,OAAO,IAAI,gBAAgB,GAAG;AAC7E,YAAM,CAAC,OAAO,IAAI,KAAK,KAAK,OAAO,IAAI,gBAAgB,KAAK,IAAI,MAAM,GAAG;AACzE,WAAK,cAAc,IAAI,YAAY;AAAA,QACjC,UAAU;AAAA,QACV,OAAO,KAAK,OAAO,IAAI,cAAc,KAAK;AAAA,QAC1C;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,WAAW,KAAK,OAAO,IAAI,YAAY,KAAK;AAAA,MAC9C,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,aAAa;AAEpB,WAAK,YAAY,GAAG,SAAS,OAAO,UAAoB;AACtD,gBAAQ,IAAI,oDAA6C;AACzD,aAAK,KAAK,aAAa,KAAK;AAG5B,aAAK,YAAY,WAAW,KAAK,IAAI,CAAC;AACtC,aAAK,QAAQ;AACb,aAAK,eAAe;AACpB,cAAM,KAAK,WAAW;AAAA,MACxB,CAAC;AAGD,WAAK,YAAY,GAAG,oBAAoB,OAAO,UAAoB;AACjE,gBAAQ,IAAI,mDAA8C;AAC1D,aAAK,KAAK,wBAAwB,KAAK;AAGvC,aAAK,YAAY,WAAW,KAAK,IAAI,CAAC;AACtC,aAAK,QAAQ;AACb,aAAK,eAAe;AACpB,cAAM,KAAK,WAAW;AAAA,MACxB,CAAC;AAED,YAAM,KAAK,YAAY,MAAM;AAC7B,cAAQ,IAAI,sCAA+B,KAAK,cAAc,eAAe,MAAM,EAAE;AAAA,IACvF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,kBAAiC;AACrC,QAAI,CAAC,KAAK,mBAAmB;AAC3B,YAAM,KAAK,WAAW;AAAA,IACxB;AACA,UAAM,MAAM,KAAK,OAAO,UAAU;AAClC,UAAM,KAAK,kBAAmB,iBAAiB,IAAI,KAAK,GAAG;AAAA,EAC7D;AAAA,EAEA,MAAM,cAAc,MAAgC;AAClD,QAAI,CAAC,KAAK,mBAAmB;AAC3B,YAAM,KAAK,WAAW;AAAA,IACxB;AACA,UAAM,MAAM,KAAK,OAAO,UAAU;AAClC,UAAM,UAAU,KAAK,kBAAmB,iBAAiB,IAAI;AAC7D,UAAM,KAAK,kBAAmB,cAAc,SAAS,IAAI,KAAK,GAAG;AAAA,EACnE;AAAA,EAEA,wBAAuC;AACrC,WAAO,KAAK,mBAAmB,eAAe,KAAK,CAAC;AAAA,EACtD;AAAA;AAAA,EAGA,YAAqB;AACnB,WAAO,KAAK,aAAa,aAAa;AAAA,EACxC;AAAA,EAEA,YAAY,MAA4D;AACtE,WAAO,KAAK,aAAa,YAAY,IAAI;AAAA,EAC3C;AAAA,EAEA,YAAY,IAAY,SAAuC;AAC7D,WAAO,KAAK,aAAa,YAAY,IAAI,OAAO;AAAA,EAClD;AAAA,EAEA,YAAY,IAAqB;AAC/B,WAAO,KAAK,aAAa,YAAY,EAAE;AAAA,EACzC;AAAA,EAEA,YAAY,IAA0B;AACpC,WAAO,KAAK,aAAa,YAAY,EAAE;AAAA,EACzC;AAAA,EAEA,YAAY;AACV,WAAO;AAAA,MACL,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK,OAAO,UAAU;AAAA,MAC9B,mBAAmB,CAAC,CAAC,KAAK;AAAA,MAC1B,aAAa,KAAK,sBAAsB;AAAA,MACxC,QAAQ,KAAK,aAAa,iBAAiB,EAAE;AAAA,IAC/C;AAAA,EACF;AACF;","names":["ReActAgent","OpenAIAdapter","AnthropicAdapter","EventEmitter","mkdirSync","join","Octokit","EventEmitter","EventEmitter","AnthropicAdapter","OpenAIAdapter","ReActAgent"]}
package/dist/cli/index.js CHANGED
@@ -184,10 +184,9 @@ var OpenQADatabase = class {
184
184
  import { config as dotenvConfig } from "dotenv";
185
185
  dotenvConfig();
186
186
  var ConfigManager = class {
187
- db;
187
+ db = null;
188
188
  envConfig;
189
189
  constructor(dbPath) {
190
- this.db = new OpenQADatabase(dbPath || process.env.DB_PATH || "./data/openqa.db");
191
190
  this.envConfig = this.loadFromEnv();
192
191
  }
193
192
  loadFromEnv() {
@@ -227,8 +226,14 @@ var ConfigManager = class {
227
226
  }
228
227
  };
229
228
  }
229
+ getDB() {
230
+ if (!this.db) {
231
+ this.db = new OpenQADatabase("./data/openqa.json");
232
+ }
233
+ return this.db;
234
+ }
230
235
  async get(key) {
231
- const dbValue = await this.db.getConfig(key);
236
+ const dbValue = await this.getDB().getConfig(key);
232
237
  if (dbValue) return dbValue;
233
238
  const keys = key.split(".");
234
239
  let value = this.envConfig;
@@ -238,10 +243,10 @@ var ConfigManager = class {
238
243
  return value?.toString() || null;
239
244
  }
240
245
  async set(key, value) {
241
- await this.db.setConfig(key, value);
246
+ await this.getDB().setConfig(key, value);
242
247
  }
243
248
  async getAll() {
244
- const dbConfig = await this.db.getAllConfig();
249
+ const dbConfig = await this.getDB().getAllConfig();
245
250
  const merged = { ...this.envConfig };
246
251
  for (const [key, value] of Object.entries(dbConfig)) {
247
252
  const keys = key.split(".");
@@ -1670,7 +1675,7 @@ program.command("start").description("Start the OpenQA agent and web UI").option
1670
1675
  spinner.succeed(chalk.green("OpenQA started"));
1671
1676
  const agent = new OpenQAAgent();
1672
1677
  const config = new ConfigManager();
1673
- const cfg = config.getConfig();
1678
+ const cfg = config.getConfigSync();
1674
1679
  console.log(chalk.cyan("\n\u{1F4CA} OpenQA Status:"));
1675
1680
  console.log(chalk.white(` Agent: Running`));
1676
1681
  console.log(chalk.white(` Target: ${cfg.saas.url || "Not configured"}`));
@@ -1716,9 +1721,6 @@ program.command("stop").description("Stop the OpenQA agent").action(() => {
1716
1721
  }
1717
1722
  });
1718
1723
  program.command("status").description("Show OpenQA status").action(() => {
1719
- const config = new ConfigManager();
1720
- const cfg = config.getConfig();
1721
- const db = new OpenQADatabase(cfg.database.path);
1722
1724
  console.log(chalk.cyan.bold("\n\u{1F4CA} OpenQA Status\n"));
1723
1725
  if (existsSync(PID_FILE)) {
1724
1726
  const pid = readFileSync2(PID_FILE, "utf-8").trim();
@@ -1726,50 +1728,19 @@ program.command("status").description("Show OpenQA status").action(() => {
1726
1728
  process.kill(parseInt(pid), 0);
1727
1729
  console.log(chalk.green("\u2713 Agent: Running"));
1728
1730
  console.log(chalk.white(` PID: ${pid}`));
1731
+ console.log(chalk.yellow("\n\u{1F4CB} Detailed status temporarily disabled"));
1729
1732
  } catch {
1730
- console.log(chalk.red("\u2717 Agent: Stopped (stale PID file)"));
1733
+ console.log(chalk.red("\u2717 Agent: Not running (stale PID file)"));
1731
1734
  unlinkSync(PID_FILE);
1732
1735
  }
1733
1736
  } else {
1734
- console.log(chalk.red("\u2717 Agent: Stopped"));
1735
- }
1736
- console.log(chalk.cyan("\n\u{1F310} Web Interfaces:"));
1737
- console.log(chalk.white(` DevTools: http://localhost:${cfg.web.port}`));
1738
- console.log(chalk.white(` Kanban: http://localhost:${cfg.web.port}/kanban`));
1739
- console.log(chalk.white(` Config: http://localhost:${cfg.web.port}/config`));
1740
- console.log(chalk.cyan("\n\u2699\uFE0F Configuration:"));
1741
- console.log(chalk.white(` LLM Provider: ${cfg.llm.provider}`));
1742
- console.log(chalk.white(` Target SaaS: ${cfg.saas.url || "Not configured"}`));
1743
- console.log(chalk.white(` GitHub: ${cfg.github?.token ? "Configured" : "Not configured"}`));
1744
- console.log(chalk.white(` Test Interval: ${cfg.agent.intervalMs / 1e3 / 60} minutes`));
1745
- const sessions = db.getRecentSessions(5);
1746
- console.log(chalk.cyan(`
1747
- \u{1F4CB} Recent Sessions (${sessions.length}):`));
1748
- sessions.forEach((s) => {
1749
- const status = s.status === "completed" ? chalk.green("\u2713") : s.status === "failed" ? chalk.red("\u2717") : chalk.yellow("\u27F3");
1750
- console.log(chalk.white(` ${status} ${s.id} - ${s.bugs_found} bugs found`));
1751
- });
1752
- const bugs = db.getBugsByStatus("open");
1753
- console.log(chalk.cyan(`
1754
- \u{1F41B} Open Bugs: ${bugs.length}`));
1755
- const tickets = db.getKanbanTickets();
1756
- const byColumn = {
1757
- backlog: tickets.filter((t) => t.column === "backlog").length,
1758
- "to-do": tickets.filter((t) => t.column === "to-do").length,
1759
- "in-progress": tickets.filter((t) => t.column === "in-progress").length,
1760
- done: tickets.filter((t) => t.column === "done").length
1761
- };
1762
- console.log(chalk.cyan("\n\u{1F4CA} Kanban Board:"));
1763
- console.log(chalk.white(` Backlog: ${byColumn.backlog}`));
1764
- console.log(chalk.white(` To Do: ${byColumn["to-do"]}`));
1765
- console.log(chalk.white(` In Progress: ${byColumn["in-progress"]}`));
1766
- console.log(chalk.white(` Done: ${byColumn.done}`));
1767
- console.log("");
1737
+ console.log(chalk.yellow("\u2717 Agent: Not running"));
1738
+ }
1768
1739
  });
1769
1740
  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) => {
1770
1741
  const config = new ConfigManager();
1771
1742
  if (!action || action === "list") {
1772
- const cfg = config.getConfig();
1743
+ const cfg = config.getConfigSync();
1773
1744
  console.log(chalk.cyan.bold("\n\u2699\uFE0F OpenQA Configuration\n"));
1774
1745
  console.log(JSON.stringify(cfg, null, 2));
1775
1746
  console.log("");
@@ -1799,31 +1770,9 @@ program.command("config").description("Manage configuration").argument("[action]
1799
1770
  });
1800
1771
  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) => {
1801
1772
  const config = new ConfigManager();
1802
- const cfg = config.getConfig();
1773
+ const cfg = config.getConfigSync();
1803
1774
  const db = new OpenQADatabase(cfg.database.path);
1804
- const sessions = db.getRecentSessions(1);
1805
- if (sessions.length === 0) {
1806
- console.log(chalk.yellow("No sessions found"));
1807
- return;
1808
- }
1809
- const session = sessions[0];
1810
- const actions = db.getSessionActions(session.id);
1811
- console.log(chalk.cyan.bold(`
1812
- \u{1F4CB} Session Logs: ${session.id}
1813
- `));
1814
- console.log(chalk.white(`Status: ${session.status}`));
1815
- console.log(chalk.white(`Started: ${session.started_at}`));
1816
- console.log(chalk.white(`Actions: ${actions.length}
1817
- `));
1818
- const limit = parseInt(options.lines);
1819
- const displayActions = actions.slice(0, limit);
1820
- displayActions.forEach((action) => {
1821
- 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";
1822
- console.log(chalk.gray(`[${action.timestamp}]`), icon, chalk.white(action.description));
1823
- if (action.output) {
1824
- console.log(chalk.gray(` \u2192 ${action.output}`));
1825
- }
1826
- });
1827
- console.log("");
1775
+ console.log(chalk.yellow("Logs feature temporarily disabled"));
1776
+ return;
1828
1777
  });
1829
1778
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openqa/cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Autonomous QA testing agent powered by Orka.js",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",