/** * ABE — Autonomous Bug Explorer * Entry point: wires all components together and starts exploration. * * Usage: * npm run explore -- --url http://localhost:3000 --output ./reports * ts-node src/index.ts http://localhost:3000 */ import { ExplorationEngine } from './core/ExplorationEngine'; import { StateGraph } from './core/StateGraph'; import { FileLogger } from './core/Logger'; import { PlaywrightAgent } from './plugins/agents/PlaywrightAgent'; import { ScreenshotCollector } from './plugins/collectors/ScreenshotCollector'; import { NetworkCollector } from './plugins/collectors/NetworkCollector'; import { DOMSnapshotCollector } from './plugins/collectors/DOMSnapshotCollector'; import { JSONExporter } from './plugins/exporters/JSONExporter'; import { MarkdownExporter } from './plugins/exporters/MarkdownExporter'; import { PlaywrightReproducer } from './plugins/reproducers/PlaywrightReproducer'; // ─── Parse CLI arguments ───────────────────────────────────────────────────── function parseArgs(): { url: string; outputDir: string; seed: number; maxSteps: number } { const args = process.argv.slice(2); let url = 'http://localhost:3000'; let outputDir = './reports'; let seed = 42; let maxSteps = 100; for (let i = 0; i < args.length; i++) { if (args[i] === '--url' && args[i + 1]) url = args[++i]; else if (args[i] === '--output' && args[i + 1]) outputDir = args[++i]; else if (args[i] === '--seed' && args[i + 1]) seed = parseInt(args[++i], 10); else if (args[i] === '--max-steps' && args[i + 1]) maxSteps = parseInt(args[++i], 10); else if (!args[i].startsWith('--')) url = args[i]; } return { url, outputDir, seed, maxSteps }; } // ─── Main ───────────────────────────────────────────────────────────────────── async function main(): Promise { const { url, outputDir, seed, maxSteps } = parseArgs(); const sessionId = `${new Date().toISOString().replace(/[:.]/g, '-')}_seed${seed}`; const logger = new FileLogger('./logs', sessionId); const graph = new StateGraph(); const agent = new PlaywrightAgent({ seed, headless: true, logger }); const collectors = [ new ScreenshotCollector(outputDir), new NetworkCollector(), new DOMSnapshotCollector(outputDir), ]; const exporters = [ new JSONExporter(url), new MarkdownExporter(), ]; const reproducer = new PlaywrightReproducer(); const engine = new ExplorationEngine({ graph, agent, collectors, exporters, reproducer, logger, seed, url, maxSteps, outputDir, }); console.log(`[ABE] Starting exploration of ${url} (seed=${seed}, maxSteps=${maxSteps})`); try { const result = await engine.run(); console.log(`[ABE] Exploration complete.`); console.log(` States visited : ${result.statesVisited}`); console.log(` Anomalies found: ${result.anomaliesFound}`); if (result.anomaliesFound > 0) { console.log(` Reports saved to: ${outputDir}/`); } } catch (err) { console.error('[ABE] Fatal error:', err); process.exit(1); } } main();