@_deep4wee/agent-lens 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/api/dsl.ts","../src/features/capture/capture.ts","../src/features/reporter/reporter.ts","../src/features/console-tracker/consoleTracker.ts","../src/shared/lib/playwrightLoader.ts","../src/shared/drivers/desktopDriver.ts","../src/features/mock-ipc/mockIpc.ts","../src/shared/lib/config.ts","../src/shared/drivers/previewDriver.ts","../src/shared/lib/processManager.ts","../src/features/runner/runner.ts","../src/features/snap/snap.ts","../src/app/cli.ts"],"sourcesContent":["import type { Page, BrowserContext } from 'playwright';\nimport type { ConsoleEntry } from '../../features/console-tracker/consoleTracker';\nimport type { MockIpcResponseType } from '../../features/mock-ipc/mockIpc';\n\nexport interface ViewportPreset {\n name: string;\n width: number;\n height: number;\n}\n\nexport const VIEWPORT_PRESETS = {\n /** Minimum supported window size (e.g., ) */\n MIN_SUPPORTED: { name: 'min-supported', width: 1024, height: 768 } as ViewportPreset,\n /** Standard default window size (e.g., ) */\n DEFAULT: { name: 'default', width: 1200, height: 800 } as ViewportPreset,\n /** Wide screen for checking grids and tables */\n WIDE: { name: 'wide', width: 1600, height: 900 } as ViewportPreset,\n /** Full HD */\n FULL_HD: { name: 'full-hd', width: 1920, height: 1080 } as ViewportPreset,\n};\n\nexport interface CaptureOptions {\n selector?: string;\n fullPage?: boolean;\n mask?: string[];\n}\n\nexport interface CaptureBurstOptions {\n /** Total duration of burst animation capture in milliseconds */\n durationMs: number;\n /** Interval between frames in milliseconds (default: 80ms) */\n intervalMs?: number;\n /** Restrict capture to a specific element */\n selector?: string;\n}\n\nexport interface SnapshotMetadata {\n index: number;\n name: string;\n fileName: string;\n filePath: string;\n relativeUri: string;\n viewport: { width: number; height: number };\n timestamp: string;\n isBurstFrame?: boolean;\n burstGroup?: string;\n frameIndex?: number;\n selector?: string;\n}\n\nexport interface TestContext {\n page: Page;\n context: BrowserContext;\n targetMode: 'desktop' | 'preview';\n currentViewport: { width: number; height: number };\n \n // --- Snapshots ---\n\n /** Capture a single high-quality snapshot of the window or element */\n capture: (name: string, options?: CaptureOptions) => Promise<SnapshotMetadata>;\n \n /** Capture a series of frames for animations (Framer Motion, modals, lists) */\n captureBurst: (name: string, options: CaptureBurstOptions) => Promise<SnapshotMetadata[]>;\n \n // --- Navigation ---\n\n /** \n * Dynamically navigate to another page during the test.\n * Example: await ctx.navigate('/settings');\n */\n navigate: (route: string) => Promise<void>;\n\n // --- Viewport ---\n\n /** Change window / viewport size */\n resize: (width: number, height: number) => Promise<void>;\n \n /** Set one of the standard presets (MIN_SUPPORTED, DEFAULT, WIDE) */\n setPreset: (preset: ViewportPreset) => Promise<void>;\n\n /** \n * Dynamically resize the window so it perfectly fits the specified element (or body).\n * Useful when an agent wants to test an isolated component without background clutter.\n */\n resizeToFit: (selector?: string, padding?: number) => Promise<void>;\n \n // --- Waiting ---\n\n /** Wait the specified amount of milliseconds */\n wait: (ms: number) => Promise<void>;\n \n /** Wait for the selector to appear in the DOM */\n waitForSelector: (selector: string, timeoutMs?: number) => Promise<void>;\n \n // --- Interaction ---\n\n /** Left-click the element */\n click: (selector: string) => Promise<void>;\n \n /** Right-click the element (Context Menu) */\n rightClick: (selector: string) => Promise<void>;\n \n /** Type text into an input field */\n type: (selector: string, text: string) => Promise<void>;\n \n /** Select an option in a <select> by its value */\n selectOption: (selector: string, value: string) => Promise<void>;\n \n /** Hover the cursor to check highlights / tooltips */\n hover: (selector: string) => Promise<void>;\n \n /** Scroll the element (or window) down by the specified number of pixels */\n scroll: (selector: string, deltaY: number) => Promise<void>;\n \n // --- Logging ---\n\n /** Log a step for the agent */\n log: (message: string) => void;\n\n // --- Mock IPC (preview mode only) ---\n\n /**\n * Set a mock response for an IPC action.\n * Changes the data returned by window.external.sendMessage in preview mode.\n * Ignored in desktop mode (IPC goes through real backend).\n *\n * Example:\n * await ctx.setMockIpc('GET_INSTANCES', [{ id: '...', name: 'Test' }]);\n * await ctx.setMockIpc('CREATE_INSTANCE', 'Some error', { type: 'ERROR' });\n */\n setMockIpc: (action: string, data: any, options?: { type?: MockIpcResponseType; delayMs?: number }) => Promise<void>;\n\n // --- Console Errors ---\n\n /** Return all intercepted console.error and pageerror logs */\n getConsoleErrors: () => ConsoleEntry[];\n\n /** Return all intercepted console.warn logs */\n getConsoleWarnings: () => ConsoleEntry[];\n\n /** Returns true if there are critical errors in the console */\n hasConsoleErrors: () => boolean;\n\n // --- DOM Assertions ---\n\n /** Get the visible text of a specific element */\n readText: (selector: string) => Promise<string | null>;\n \n /** Get ALL visible text on the page (useful for quick analysis without Vision) */\n getPageText: () => Promise<string>;\n \n /** Check if the element is visible on the screen */\n isVisible: (selector: string) => Promise<boolean>;\n\n /** Count the number of elements matching the selector */\n getElementCount: (selector: string) => Promise<number>;\n}\n\nexport interface VisualScenario {\n /** Unique scenario identifier (kebab-case) */\n id: string;\n /** Human-readable title for the report */\n title: string;\n /** Description of what is being tested */\n description?: string;\n /** Initial route to navigate to (e.g., '/instances', '/settings') */\n route?: string;\n /** List of viewport sizes to test */\n viewports?: ViewportPreset[];\n /**\n * Initial IPC mock data for preview mode.\n * Applied BEFORE navigation to the route.\n */\n mockIpc?: Array<{ action: string; data: any; type?: MockIpcResponseType; delayMs?: number }>;\n /**\n * Optional setup hook: executed before the browser navigates and scenario runs.\n * Ideal for preparing mock files, test directories, or initial state.\n */\n setup?: () => Promise<void> | void;\n /** The main body of the scenario */\n run: (ctx: TestContext) => Promise<void>;\n /**\n * Optional teardown hook: guaranteed to execute in finally, even if run() fails.\n * Ideal for cleaning up test artifacts, cache directories, or temporary state.\n */\n teardown?: () => Promise<void> | void;\n}\n\nexport function defineVisualTest(scenario: VisualScenario): VisualScenario {\n return scenario;\n}\n","import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Page } from 'playwright';\r\nimport type { CaptureOptions, CaptureBurstOptions, SnapshotMetadata } from '../../shared/api/dsl';\r\n\r\nexport class CaptureEngine {\r\n private outputDir: string;\r\n private currentStepIndex: number = 0;\r\n private recordedSnapshots: SnapshotMetadata[] = [];\r\n\r\n constructor(outputDir: string) {\r\n this.outputDir = outputDir;\r\n if (!fs.existsSync(this.outputDir)) {\r\n fs.mkdirSync(this.outputDir, { recursive: true });\r\n }\r\n }\r\n\r\n public getSnapshots(): SnapshotMetadata[] {\r\n return this.recordedSnapshots;\r\n }\r\n\r\n public getOutputDir(): string {\r\n return this.outputDir;\r\n }\r\n\r\n /**\r\n */\r\n public async takeSnapshot(\r\n page: Page,\r\n name: string,\r\n viewport: { width: number; height: number },\r\n options?: CaptureOptions\r\n ): Promise<SnapshotMetadata> {\r\n this.currentStepIndex += 1;\r\n const paddedIndex = String(this.currentStepIndex).padStart(2, '0');\r\n const sanitizedName = name.replace(/[^a-zA-Z0-9_\\-]/g, '_');\r\n const fileName = `${paddedIndex}_${sanitizedName}_${viewport.width}x${viewport.height}.png`;\r\n const filePath = path.join(this.outputDir, fileName);\r\n\r\n if (options?.selector) {\r\n const element = await page.waitForSelector(options.selector, { timeout: 5000 });\r\n await element.screenshot({ path: filePath });\r\n } else {\r\n await page.screenshot({ path: filePath, fullPage: options?.fullPage ?? false });\r\n }\r\n\r\n const metadata: SnapshotMetadata = {\r\n index: this.currentStepIndex,\r\n name,\r\n fileName,\r\n filePath,\r\n relativeUri: `./${fileName}`,\r\n viewport,\r\n timestamp: new Date().toISOString(),\r\n selector: options?.selector\r\n };\r\n\r\n this.recordedSnapshots.push(metadata);\r\n return metadata;\r\n }\r\n\r\n /**\r\n */\r\n public async takeBurst(\r\n page: Page,\r\n name: string,\r\n viewport: { width: number; height: number },\r\n options: CaptureBurstOptions\r\n ): Promise<SnapshotMetadata[]> {\r\n this.currentStepIndex += 1;\r\n const stepIndex = this.currentStepIndex;\r\n const paddedIndex = String(stepIndex).padStart(2, '0');\r\n const sanitizedName = name.replace(/[^a-zA-Z0-9_\\-]/g, '_');\r\n\r\n const duration = Math.max(options.durationMs, 50);\r\n const interval = Math.max(options.intervalMs ?? 80, 20);\r\n const totalFrames = Math.ceil(duration / interval);\r\n\r\n const burstSnapshots: SnapshotMetadata[] = [];\r\n const burstGroup = sanitizedName;\r\n\r\n for (let frame = 0; frame <= totalFrames; frame++) {\r\n const elapsedMs = frame * interval;\r\n const paddedFrame = String(frame + 1).padStart(2, '0');\r\n const fileName = `${paddedIndex}_burst_${sanitizedName}_f${paddedFrame}_${elapsedMs}ms.png`;\r\n const filePath = path.join(this.outputDir, fileName);\r\n\r\n if (options.selector) {\r\n const element = await page.$(options.selector);\r\n if (element) {\r\n await element.screenshot({ path: filePath });\r\n } else {\r\n await page.screenshot({ path: filePath });\r\n }\r\n } else {\r\n await page.screenshot({ path: filePath });\r\n }\r\n\r\n const meta: SnapshotMetadata = {\r\n index: stepIndex,\r\n name: `${name} (frame ${frame + 1}, +${elapsedMs}ms)`,\r\n fileName,\r\n filePath,\r\n relativeUri: `./${fileName}`,\r\n viewport,\r\n timestamp: new Date().toISOString(),\r\n isBurstFrame: true,\r\n burstGroup,\r\n frameIndex: frame + 1,\r\n selector: options.selector\r\n };\r\n\r\n burstSnapshots.push(meta);\r\n this.recordedSnapshots.push(meta);\r\n\r\n if (frame < totalFrames) {\r\n await new Promise((r) => setTimeout(r, interval));\r\n }\r\n }\r\n\r\n return burstSnapshots;\r\n }\r\n}\r\n","import fs from 'fs';\nimport path from 'path';\nimport type { SnapshotMetadata, VisualScenario } from '../../shared/api/dsl';\nimport type { ConsoleEntry } from './consoleTracker';\n\nexport interface ReportData {\n scenario: VisualScenario;\n snapshots: SnapshotMetadata[];\n consoleErrors: ConsoleEntry[];\n consoleWarnings: ConsoleEntry[];\n outputDir: string;\n targetMode: 'desktop' | 'preview';\n durationMs: number;\n}\n\nexport class VisualReporter {\n public static generateReport(data: ReportData): string {\n const {\n scenario,\n snapshots,\n consoleErrors,\n consoleWarnings,\n outputDir,\n targetMode,\n durationMs\n } = data;\n\n const manifestPath = path.join(outputDir, 'manifest.json');\n const reportPath = path.join(outputDir, 'report.md');\n\n const manifest = {\n scenarioId: scenario.id,\n title: scenario.title,\n description: scenario.description,\n targetMode,\n durationMs,\n totalSnapshots: snapshots.length,\n consoleErrors: consoleErrors.length,\n consoleWarnings: consoleWarnings.length,\n createdAt: new Date().toISOString(),\n snapshots,\n errors: consoleErrors,\n warnings: consoleWarnings\n };\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n const rows: string[] = [];\n \n const regularSnapshots = snapshots.filter((s) => !s.isBurstFrame);\n const burstGroups = new Map<string, SnapshotMetadata[]>();\n\n snapshots.filter((s) => s.isBurstFrame && s.burstGroup).forEach((s) => {\n const list = burstGroups.get(s.burstGroup!) || [];\n list.push(s);\n burstGroups.set(s.burstGroup!, list);\n });\n\n for (const snap of regularSnapshots) {\n const fileUri = `file:///${snap.filePath.replace(/\\\\/g, '/')}`;\n rows.push(\n `| **${String(snap.index).padStart(2, '0')}** | \\`${snap.viewport.width}x${snap.viewport.height}\\` | ${snap.name} | [${snap.fileName}](${fileUri}) |`\n );\n }\n\n let burstSections = '';\n if (burstGroups.size > 0) {\n burstSections += `\\n### šŸŽ¬ Animation Bursts\\n\\n`;\n for (const [group, frames] of burstGroups.entries()) {\n burstSections += `#### Animation: \\`${group}\\` (${frames.length} frames)\\n\\n`;\n burstSections += `| Frame | Viewport | File | Preview |\\n| :--- | :--- | :--- | :--- |\\n`;\n for (const frame of frames) {\n const fileUri = `file:///${frame.filePath.replace(/\\\\/g, '/')}`;\n burstSections += `| Frame ${frame.frameIndex} | \\`${frame.viewport.width}x${frame.viewport.height}\\` | [${frame.fileName}](${fileUri}) | ![](${fileUri}) |\\n`;\n }\n burstSections += `\\n`;\n }\n }\n\n const healthStatus = this.getHealthStatus(consoleErrors, consoleWarnings);\n let consoleSections = '';\n\n if (consoleErrors.length > 0) {\n consoleSections += `\\n## šŸ”“ Console Errors (${consoleErrors.length})\\n\\n`;\n consoleSections += `> [!CAUTION]\\n> Found **${consoleErrors.length}** JavaScript errors during the test. This might indicate broken components, missing data, or unhandled exceptions.\\n\\n`;\n consoleSections += `| # | Time | Error | URL |\\n| :-: | :--- | :--- | :--- |\\n`;\n consoleErrors.forEach((err, i) => {\n const time = err.timestamp.split('T')[1]?.slice(0, 8) || '';\n const text = err.text.replace(/\\|/g, '\\\\|').slice(0, 200);\n const url = err.url.replace(/\\|/g, '\\\\|');\n consoleSections += `| ${i + 1} | \\`${time}\\` | ${text} | \\`${url}\\` |\\n`;\n });\n\n const withStack = consoleErrors.filter(e => e.stack);\n if (withStack.length > 0) {\n consoleSections += `\\n<details>\\n<summary>šŸ“‹ Stack Traces (${withStack.length})</summary>\\n\\n`;\n withStack.forEach((err, i) => {\n consoleSections += `**Error ${i + 1}:** \\`${err.text.slice(0, 100)}\\`\\n\\`\\`\\`\\n${err.stack}\\n\\`\\`\\`\\n\\n`;\n });\n consoleSections += `</details>\\n`;\n }\n }\n\n if (consoleWarnings.length > 0) {\n consoleSections += `\\n## 🟔 Console Warnings (${consoleWarnings.length})\\n\\n`;\n consoleSections += `| # | Warning |\\n| :-: | :--- |\\n`;\n consoleWarnings.slice(0, 20).forEach((warn, i) => {\n const text = warn.text.replace(/\\|/g, '\\\\|').slice(0, 200);\n consoleSections += `| ${i + 1} | ${text} |\\n`;\n });\n if (consoleWarnings.length > 20) {\n consoleSections += `\\n*...and ${consoleWarnings.length - 20} more warnings (full list in manifest.json)*\\n`;\n }\n }\n\n const reportContent = `# šŸ“ø Visual Test Report: ${scenario.title}\n\n> **Scenario ID:** \\`${scenario.id}\\` \n> **Target Mode:** \\`${targetMode.toUpperCase()}\\` (${targetMode === 'desktop' ? 'Native Desktop App / WebView2' : 'Fast Web Preview'}) \n> **Execution Duration:** ${(durationMs / 1000).toFixed(2)} s \n> **Total Snapshots Captured:** ${snapshots.length} \n> **Health Status:** ${healthStatus} \n> **Artifacts Folder:** \\`${outputDir}\\`\n\n---\n\n## šŸ–¼ļø Primary Snapshot Overview\n\n| # | Viewport | Step Description | File Reference |\n| :-: | :--- | :--- | :--- |\n${rows.join('\\n')}\n\n${burstSections}\n${consoleSections}\n---\n\n## šŸ“‹ AI Agent Verification Checklist:\n- [ ] **Console Errors**: ${consoleErrors.length === 0 ? 'āœ… No errors found' : `āŒ ${consoleErrors.length} errors — MUST REVIEW`}\n- [ ] **Responsiveness at \\`1024x768\\`**: Elements do not overflow the screen, no unwanted horizontal scroll.\n- [ ] **Typography & Spacing**: Spacing matches the design system and layout grids.\n- [ ] **Color Palette & Theme**: Background tints and button accent colors match the concept.\n- [ ] **Component States**: Modals open centered, dropdowns do not overlap with other layers (z-index).\n- [ ] **Localization**: Verify that there are no raw i18n keys (text with dots like \\`sidebar.home\\` instead of \"Home\").\n\n`;\n\n fs.writeFileSync(reportPath, reportContent, 'utf-8');\n return reportPath;\n }\n\n private static getHealthStatus(errors: ConsoleEntry[], warnings: ConsoleEntry[]): string {\n if (errors.length === 0 && warnings.length === 0) {\n return 'āœ… Healthy — no errors or warnings';\n }\n if (errors.length === 0 && warnings.length > 0) {\n return `āš ļø Warnings (${warnings.length}) — no critical errors`;\n }\n return `āŒ ERRORS (${errors.length} errors, ${warnings.length} warnings) — requires attention`;\n }\n}\n","import type { Page, ConsoleMessage } from 'playwright';\r\n\r\nexport interface ConsoleEntry {\r\n level: 'error' | 'warning' | 'info' | 'log' | 'debug';\r\n text: string;\r\n url: string;\r\n timestamp: string;\r\n stack?: string;\r\n}\r\n\r\n/**\r\n *\r\n * const tracker = new ConsoleTracker();\r\n * tracker.attach(page);\r\n * // ... run scenario ...\r\n */\r\nexport class ConsoleTracker {\r\n private entries: ConsoleEntry[] = [];\r\n private attached = false;\r\n\r\n /**\r\n */\r\n public attach(page: Page): void {\r\n if (this.attached) return;\r\n this.attached = true;\r\n\r\n page.on('console', (msg: ConsoleMessage) => {\r\n const type = msg.type(); // 'log' | 'error' | 'warning' | 'info' | 'debug' | 'trace' | ...\r\n const level = this.mapConsoleType(type);\r\n\r\n const entry: ConsoleEntry = {\r\n level,\r\n text: msg.text(),\r\n url: page.url(),\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n this.entries.push(entry);\r\n\r\n if (level === 'error') {\r\n console.log(`šŸ”“ [Console ERROR] ${msg.text()}`);\r\n } else if (level === 'warning') {\r\n if (!this.isIgnoredWarning(msg.text())) {\r\n console.log(`🟔 [Console WARN] ${msg.text()}`);\r\n }\r\n }\r\n });\r\n\r\n page.on('pageerror', (error: Error) => {\r\n const entry: ConsoleEntry = {\r\n level: 'error',\r\n text: error.message,\r\n url: page.url(),\r\n timestamp: new Date().toISOString(),\r\n stack: error.stack\r\n };\r\n\r\n this.entries.push(entry);\r\n console.log(`šŸ’„ [Page ERROR] ${error.message}`);\r\n });\r\n }\r\n\r\n public getErrors(): ConsoleEntry[] {\r\n return this.entries.filter(e => e.level === 'error');\r\n }\r\n\r\n public getWarnings(): ConsoleEntry[] {\r\n return this.entries\r\n .filter(e => e.level === 'warning')\r\n .filter(e => !this.isIgnoredWarning(e.text));\r\n }\r\n\r\n public getAll(): ConsoleEntry[] {\r\n return [...this.entries];\r\n }\r\n\r\n public get errorCount(): number {\r\n return this.getErrors().length;\r\n }\r\n\r\n public get warningCount(): number {\r\n return this.getWarnings().length;\r\n }\r\n\r\n public get hasErrors(): boolean {\r\n return this.errorCount > 0;\r\n }\r\n\r\n public clear(): void {\r\n this.entries = [];\r\n }\r\n\r\n\r\n private mapConsoleType(type: string): ConsoleEntry['level'] {\r\n switch (type) {\r\n case 'error': return 'error';\r\n case 'warning': return 'warning';\r\n case 'info': return 'info';\r\n case 'debug': return 'debug';\r\n default: return 'log';\r\n }\r\n }\r\n\r\n /**\r\n */\r\n private isIgnoredWarning(text: string): boolean {\r\n const ignoredPatterns = [\r\n 'findDOMNode is deprecated',\r\n // Chromium DevTools\r\n 'DevTools',\r\n // Playwright injection\r\n '__playwright',\r\n '[vite]',\r\n // React 18 hydration warnings\r\n 'Extra attributes from the server',\r\n 'Download the React DevTools',\r\n ];\r\n return ignoredPatterns.some(pattern => text.includes(pattern));\r\n }\r\n}\r\n","import { chromium } from 'playwright';\r\n\r\nexport { chromium };\n","import { spawn, type ChildProcess } from 'child_process';\nimport http from 'http';\nimport path from 'path';\nimport fs from 'fs';\nimport type { Browser, BrowserContext, Page } from 'playwright';\nimport { chromium } from '../lib/playwrightLoader';\n\nexport interface DesktopDriverOptions {\n port?: number;\n executablePath?: string;\n autoLaunch?: boolean;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\n\nexport class DesktopDriver {\n private port: number;\n private executablePath?: string;\n private autoLaunch: boolean;\n private args: string[];\n private env: Record<string, string>;\n private cwd?: string;\n\n private childProcess: ChildProcess | null = null;\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private processStderr: string = '';\n private processExited: boolean = false;\n private exitCode: number | null = null;\n\n constructor(options?: DesktopDriverOptions) {\n this.port = options?.port || 9222;\n this.autoLaunch = options?.autoLaunch ?? true;\n this.executablePath = options?.executablePath;\n this.args = options?.args || [];\n this.env = options?.env || {};\n this.cwd = options?.cwd;\n }\n\n private async isPortAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {\n resolve(res.statusCode === 200);\n });\n req.on('error', () => resolve(false));\n req.setTimeout(800, () => {\n req.destroy();\n resolve(false);\n });\n });\n }\n\n private async waitForPort(timeoutMs: number = 25000): Promise<void> {\n const startTime = Date.now();\n while (Date.now() - startTime < timeoutMs) {\n if (this.processExited) {\n throw new Error(\n `[DesktopDriver] Process terminated prematurely with exit code ${this.exitCode}.\\nStderr: ${this.processStderr.trim() || '(none)'}`\n );\n }\n\n if (await this.isPortAvailable()) {\n return;\n }\n await new Promise((r) => setTimeout(r, 400));\n }\n throw new Error(\n `Timeout waiting for WebView2/Chromium CDP port ${this.port}. Last stderr:\\n${this.processStderr.trim() || '(no stderr output)'}`\n );\n }\n\n public async start(initialViewport = { width: 1200, height: 800 }): Promise<{ page: Page; context: BrowserContext; browser: Browser }> {\n const alreadyRunning = await this.isPortAvailable();\n\n if (!alreadyRunning) {\n if (!this.autoLaunch) {\n throw new Error(\n `App is not running on port ${this.port} and autoLaunch is false. Start app with WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=${this.port}`\n );\n }\n\n if (!this.executablePath) {\n throw new Error(\n `[DesktopDriver] No executablePath provided and nothing is running on port ${this.port}. Specify --exe=<path> in CLI or executablePath in config.`\n );\n }\n\n const resolvedExe = path.resolve(process.cwd(), this.executablePath);\n if (!fs.existsSync(resolvedExe)) {\n throw new Error(\n `[DesktopDriver] Desktop executable not found at: ${resolvedExe}. Please build your native project first.`\n );\n }\n\n console.log(`[DesktopDriver] Launching: ${resolvedExe}`);\n const mergedEnv = {\n ...process.env,\n ...this.env,\n WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: `--remote-debugging-port=${this.port}`\n };\n\n this.processStderr = '';\n this.processExited = false;\n this.exitCode = null;\n\n this.childProcess = spawn(resolvedExe, this.args, {\n env: mergedEnv,\n cwd: this.cwd || path.dirname(resolvedExe),\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: false\n });\n\n this.childProcess.stderr?.on('data', (chunk) => {\n this.processStderr += chunk.toString();\n });\n\n this.childProcess.on('exit', (code) => {\n this.processExited = true;\n this.exitCode = code;\n });\n\n this.childProcess.on('error', (err) => {\n console.error('[DesktopDriver] Failed to spawn process:', err);\n });\n\n console.log(`[DesktopDriver] Waiting for CDP debugging port on ${this.port}...`);\n await this.waitForPort();\n } else {\n console.log(`[DesktopDriver] Attached to already running process on port ${this.port}`);\n }\n\n console.log(`[DesktopDriver] Connecting Playwright CDP to http://127.0.0.1:${this.port}...`);\n this.browser = await chromium.connectOverCDP(`http://127.0.0.1:${this.port}`);\n \n const contexts = this.browser.contexts();\n this.context = contexts[0] || (await this.browser.newContext());\n\n const pages = this.context.pages();\n if (pages.length > 0) {\n this.page = pages[0];\n } else {\n this.page = await this.context.waitForEvent('page', { timeout: 10000 });\n }\n\n if (initialViewport) {\n await this.page.setViewportSize(initialViewport).catch(() => {});\n }\n\n return { page: this.page, context: this.context, browser: this.browser };\n }\n\n public async stop(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n this.browser = null;\n }\n\n if (this.childProcess && !this.childProcess.killed) {\n console.log('[DesktopDriver] Terminating spawned desktop process...');\n try {\n if (process.platform === 'win32' && this.childProcess.pid) {\n spawn('taskkill', ['/pid', String(this.childProcess.pid), '/T', '/F'], { stdio: 'ignore' });\n } else {\n this.childProcess.kill('SIGTERM');\n }\n } catch {\n // ignore\n }\n this.childProcess = null;\n }\n }\n}\n","/**\n * Generic Mock IPC Registry for Preview Mode\n * \n * Injects a global `window.__mockIpc` that web apps or mocked electron/tauri APIs can call.\n */\n\nexport type MockIpcResponseType = 'SUCCESS' | 'ERROR';\n\nexport interface MockIpcEntry {\n action: string;\n data: any;\n type?: MockIpcResponseType;\n delayMs?: number;\n}\n\nexport class MockIpcRegistry {\n private mocks = new Map<string, MockIpcEntry>();\n\n public set(action: string, data: any, options?: { type?: MockIpcResponseType; delayMs?: number }): void {\n this.mocks.set(action, {\n action,\n data,\n type: options?.type ?? 'SUCCESS',\n delayMs: options?.delayMs ?? 20\n });\n }\n\n public setBatch(entries: Array<{ action: string; data: any; type?: MockIpcResponseType; delayMs?: number }>): void {\n for (const entry of entries) {\n this.set(entry.action, entry.data, { type: entry.type, delayMs: entry.delayMs });\n }\n }\n\n public remove(action: string): void {\n this.mocks.delete(action);\n }\n\n public clear(): void {\n this.mocks.clear();\n }\n\n public get(action: string): MockIpcEntry | null {\n return this.mocks.get(action) ?? null;\n }\n\n public toSerializable(): Record<string, { data: any; type: string; delayMs: number }> {\n const result: Record<string, { data: any; type: string; delayMs: number }> = {};\n for (const [action, entry] of this.mocks.entries()) {\n result[action] = {\n data: entry.data,\n type: entry.type ?? 'SUCCESS',\n delayMs: entry.delayMs ?? 20\n };\n }\n return result;\n }\n\n public get size(): number {\n return this.mocks.size;\n }\n}\n\nexport function generateMockIpcScript(registry: MockIpcRegistry): string {\n const mocksJson = JSON.stringify(registry.toSerializable());\n\n return `\n (() => {\n const __mockTable = ${mocksJson};\n\n window.__visualRunnerMocks = __mockTable;\n\n // Generic IPC mock bridge for modern web applications\n window.__mockIpc = {\n invoke: (action, payload) => {\n return new Promise((resolve, reject) => {\n const mock = window.__visualRunnerMocks[action];\n\n if (mock) {\n setTimeout(() => {\n if (mock.type === 'ERROR') {\n reject(new Error(mock.data));\n } else {\n resolve(mock.data);\n }\n }, mock.delayMs || 20);\n } else {\n console.warn('[Mock IPC] No mock for action:', action, '— returning empty SUCCESS');\n setTimeout(() => resolve(null), 20);\n }\n });\n }\n };\n\n // Legacy fallback for generic window.external\n if (!window.external) {\n window.external = {};\n }\n \n window.external.sendMessage = (msg) => {\n try {\n const parsed = JSON.parse(msg);\n const action = parsed.Action || parsed.action;\n const id = parsed.Id || parsed.id;\n\n const mock = window.__visualRunnerMocks[action];\n\n if (mock) {\n const response = { Id: id, Type: mock.type || 'SUCCESS', Data: mock.data };\n setTimeout(() => {\n const cb = window.__mockCallback;\n if (cb) cb(JSON.stringify(response));\n }, mock.delayMs || 20);\n } else {\n setTimeout(() => {\n const cb = window.__mockCallback;\n if (cb) cb(JSON.stringify({ Id: id, Type: 'SUCCESS', Data: null }));\n }, 20);\n }\n } catch (e) {\n console.error('[Mock IPC] Failed to process legacy message:', e);\n }\n };\n\n window.external.receiveMessage = (callback) => {\n window.__mockCallback = callback;\n };\n\n console.log('[Visual Runner] Mock IPC bridge initialized with', Object.keys(window.__visualRunnerMocks).length, 'mocked actions');\n })();\n `;\n}\n","import fs from 'fs';\nimport path from 'path';\n\nexport interface AgentLensConfig {\n wwwroot?: string;\n scenarios?: string;\n outDir?: string;\n autoBuild?: boolean;\n buildCommand?: string;\n executablePath?: string;\n startCommand?: string;\n startCwd?: string;\n cleanArtifacts?: boolean;\n clean?: string[] | string;\n env?: Record<string, string>;\n url?: string;\n port?: number;\n mode?: 'desktop' | 'preview';\n headed?: boolean;\n detach?: boolean;\n}\n\n/**\n * Searches and loads agent-lens configuration from:\n * 1. agent-lens.json in cwd\n * 2. \"agentLens\" field in package.json\n */\nexport function loadConfig(cwd: string = process.cwd()): AgentLensConfig {\n // 1. Check agent-lens.json\n const configPath = path.join(cwd, 'agent-lens.json');\n if (fs.existsSync(configPath)) {\n try {\n const raw = fs.readFileSync(configPath, 'utf8');\n return JSON.parse(raw);\n } catch (e) {\n console.warn(`āš ļø Warning: Failed to parse agent-lens.json:`, e);\n }\n }\n\n // 2. Check package.json\n const pkgPath = path.join(cwd, 'package.json');\n if (fs.existsSync(pkgPath)) {\n try {\n const raw = fs.readFileSync(pkgPath, 'utf8');\n const pkg = JSON.parse(raw);\n if (pkg.agentLens && typeof pkg.agentLens === 'object') {\n return pkg.agentLens;\n }\n } catch {\n // Ignore package.json read errors\n }\n }\n\n return {};\n}\n\n/**\n * Automatically discovers wwwroot directories if none are provided.\n * Supports standard SPAs, full-stack monorepos, and hybrid desktop apps (Photino, WPF, Electron).\n */\nexport function resolveWwwrootDir(customPath?: string, cwd: string = process.cwd()): string {\n if (customPath) {\n return path.resolve(cwd, customPath);\n }\n\n // Common direct roots\n const standardDirs = [\n 'dist',\n 'build',\n 'wwwroot',\n 'Frontend/dist',\n 'frontend/dist',\n 'client/dist',\n 'web/dist',\n 'ui/dist'\n ];\n\n for (const rel of standardDirs) {\n const candidate = path.resolve(cwd, rel);\n if (fs.existsSync(candidate) && fs.existsSync(path.join(candidate, 'index.html'))) {\n return candidate;\n }\n }\n\n // Deep recursive search for **/wwwroot containing index.html (useful for .NET Photino/WebView2)\n const foundDeepWwwroot = findDeepIndexHtmlDir(cwd, 4);\n if (foundDeepWwwroot) {\n return foundDeepWwwroot;\n }\n\n // Fallback to first existing standard folder even if index.html is missing\n for (const rel of standardDirs) {\n const candidate = path.resolve(cwd, rel);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n\n return path.resolve(cwd, 'dist');\n}\n\n/**\n * Auto-detects frontend subdirectory in monorepos (e.g. Frontend/, client/, web/)\n * when root package.json does not have dev script.\n */\nexport function detectStartCwd(customCwd?: string, rootCwd: string = process.cwd()): string {\n if (customCwd) {\n return path.resolve(rootCwd, customCwd);\n }\n\n const subdirectories = ['Frontend', 'frontend', 'client', 'web', 'ui', 'app'];\n for (const sub of subdirectories) {\n const subPkg = path.join(rootCwd, sub, 'package.json');\n if (fs.existsSync(subPkg)) {\n try {\n const json = JSON.parse(fs.readFileSync(subPkg, 'utf8'));\n if (json.scripts && (json.scripts.dev || json.scripts.start || json.scripts.build)) {\n return path.join(rootCwd, sub);\n }\n } catch {\n // ignore\n }\n }\n }\n\n return rootCwd;\n}\n\nfunction findDeepIndexHtmlDir(dir: string, maxDepth: number, currentDepth: number = 0): string | null {\n if (currentDepth > maxDepth || !fs.existsSync(dir)) return null;\n\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'artifacts') {\n continue;\n }\n\n const subDir = path.join(dir, entry.name);\n if (entry.name === 'wwwroot' && fs.existsSync(path.join(subDir, 'index.html'))) {\n return subDir;\n }\n\n const found = findDeepIndexHtmlDir(subDir, maxDepth, currentDepth + 1);\n if (found) return found;\n }\n }\n } catch {\n return null;\n }\n\n return null;\n}\n","import http from 'http';\nimport fs from 'fs';\nimport path from 'path';\nimport type { Browser, BrowserContext, Page } from 'playwright';\nimport { chromium } from '../lib/playwrightLoader';\nimport { MockIpcRegistry, generateMockIpcScript } from '../../features/mock-ipc/mockIpc';\nimport { resolveWwwrootDir } from '../lib/config';\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf'\n};\n\nexport interface PreviewDriverOptions {\n wwwrootDir?: string;\n headed?: boolean;\n url?: string;\n}\n\nexport class PreviewDriver {\n private server: http.Server | null = null;\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private serverPort: number = 0;\n private options: PreviewDriverOptions;\n private _baseUrl: string = '';\n\n public readonly mockRegistry: MockIpcRegistry;\n\n constructor(options?: PreviewDriverOptions) {\n this.options = options || {};\n if (!this.options.url) {\n this.options.wwwrootDir = resolveWwwrootDir(this.options.wwwrootDir);\n }\n this.mockRegistry = new MockIpcRegistry();\n }\n\n public get baseUrl(): string {\n return this._baseUrl;\n }\n\n public async start(initialViewport = { width: 1200, height: 800 }): Promise<{ page: Page; context: BrowserContext; browser: Browser }> {\n let targetUrl = this.options.url;\n\n if (!targetUrl) {\n if (!fs.existsSync(this.options.wwwrootDir!)) {\n throw new Error(`Directory not found at: ${this.options.wwwrootDir}. Please build your frontend project first or pass --url=<url>.`);\n }\n\n await new Promise<void>((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n let reqUrl = req.url?.split('?')[0] || '/';\n if (reqUrl === '/') reqUrl = '/index.html';\n\n let safePath = path.normalize(path.join(this.options.wwwrootDir!, reqUrl));\n if (!safePath.startsWith(this.options.wwwrootDir!)) {\n res.writeHead(403);\n return res.end('Forbidden');\n }\n\n if (!fs.existsSync(safePath) || fs.statSync(safePath).isDirectory()) {\n // SPA fallback to index.html\n safePath = path.join(this.options.wwwrootDir!, 'index.html');\n }\n\n const ext = path.extname(safePath).toLowerCase();\n const contentType = MIME_TYPES[ext] || 'application/octet-stream';\n\n try {\n const content = fs.readFileSync(safePath);\n res.writeHead(200, { 'Content-Type': contentType });\n res.end(content);\n } catch (e: any) {\n res.writeHead(500);\n res.end(`Server error: ${e.message}`);\n }\n });\n\n this.server.listen(0, '127.0.0.1', () => {\n const addr = this.server?.address();\n if (typeof addr === 'object' && addr?.port) {\n this.serverPort = addr.port;\n this._baseUrl = `http://127.0.0.1:${this.serverPort}`;\n resolve();\n } else {\n reject(new Error('Failed to acquire port for static preview server'));\n }\n });\n });\n\n targetUrl = `${this._baseUrl}/index.html`;\n } else {\n this._baseUrl = targetUrl;\n console.log(`🌐 [PreviewDriver] Connecting directly to live URL: ${targetUrl}`);\n }\n\n this.browser = await chromium.launch({\n headless: !this.options.headed,\n args: ['--no-sandbox', '--disable-setuid-sandbox']\n });\n\n this.context = await this.browser.newContext({\n viewport: initialViewport,\n deviceScaleFactor: 1\n });\n\n if (this.mockRegistry.size > 0) {\n const mockScript = generateMockIpcScript(this.mockRegistry);\n await this.context.addInitScript(mockScript);\n }\n\n this.page = await this.context.newPage();\n await this.page.goto(targetUrl, { waitUntil: 'domcontentloaded' });\n\n return { page: this.page, context: this.context, browser: this.browser };\n }\n\n public async updateMockIpc(action: string, data: any, options?: { type?: string; delayMs?: number }): Promise<void> {\n if (!this.page) {\n throw new Error('PreviewDriver not started. Call start() first.');\n }\n\n this.mockRegistry.set(action, data, options as any);\n\n await this.page.evaluate(\n ({ action, mock }) => {\n if (!(window as any).__visualRunnerMocks) {\n (window as any).__visualRunnerMocks = {};\n }\n (window as any).__visualRunnerMocks[action] = mock;\n },\n {\n action,\n mock: {\n data,\n type: options?.type ?? 'SUCCESS',\n delayMs: options?.delayMs ?? 20\n }\n }\n );\n }\n\n public async stop(): Promise<void> {\n if (this.context) {\n await this.context.close().catch(() => {});\n this.context = null;\n }\n if (this.browser) {\n await this.browser.close().catch(() => {});\n this.browser = null;\n }\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server?.close(() => resolve());\n });\n this.server = null;\n }\n }\n}\n","import { spawn, type ChildProcess } from 'child_process';\nimport treeKill from 'tree-kill';\n\nexport interface ProcessManagerOptions {\n cwd?: string;\n env?: Record<string, string>;\n shell?: boolean;\n}\n\nexport class ProcessManager {\n private child: ChildProcess | null = null;\n private stderrOutput: string = '';\n private stdoutOutput: string = '';\n private hasExited: boolean = false;\n private exitCode: number | null = null;\n\n /**\n * Spawns a background process (e.g. dev server, backend, or app)\n */\n public async start(command: string, options?: ProcessManagerOptions): Promise<void> {\n this.stderrOutput = '';\n this.stdoutOutput = '';\n this.hasExited = false;\n this.exitCode = null;\n\n const cwd = options?.cwd || process.cwd();\n const env = { ...process.env, ...options?.env };\n\n console.log(`šŸš€ [ProcessManager] Starting command: \"${command}\" in ${cwd}`);\n\n this.child = spawn(command, {\n cwd,\n env,\n shell: options?.shell ?? true,\n stdio: ['ignore', 'pipe', 'pipe']\n });\n\n this.child.stdout?.on('data', (chunk) => {\n const str = chunk.toString();\n this.stdoutOutput += str;\n });\n\n this.child.stderr?.on('data', (chunk) => {\n const str = chunk.toString();\n this.stderrOutput += str;\n });\n\n this.child.on('exit', (code) => {\n this.hasExited = true;\n this.exitCode = code;\n });\n\n this.child.on('error', (err) => {\n console.error(`āŒ [ProcessManager] Failed to start command: \"${command}\":`, err.message);\n });\n }\n\n /**\n * Polls a URL until it starts responding or until timeout is reached.\n */\n public async waitForUrl(url: string, timeoutMs: number = 30000): Promise<void> {\n const startTime = Date.now();\n console.log(`ā³ [ProcessManager] Waiting for URL to become available: ${url} (timeout: ${timeoutMs / 1000}s)...`);\n\n while (Date.now() - startTime < timeoutMs) {\n if (this.hasExited && this.exitCode !== 0) {\n throw new Error(\n `[ProcessManager] Process exited prematurely with code ${this.exitCode}.\\nStderr:\\n${this.stderrOutput.trim() || '(no stderr)'}\\nStdout:\\n${this.stdoutOutput.slice(-500).trim()}`\n );\n }\n\n try {\n const response = await fetch(url, { method: 'GET', signal: AbortSignal.timeout(2000) });\n // Any HTTP response (even 404 or 500) means the server is listening!\n if (response.status) {\n console.log(`āœ… [ProcessManager] Server responded with status ${response.status} at ${url}`);\n return;\n }\n } catch {\n // Connection refused or timed out, retry\n }\n\n await new Promise((resolve) => setTimeout(resolve, 350));\n }\n\n throw new Error(\n `[ProcessManager] Timeout (${timeoutMs / 1000}s) waiting for server at ${url}.\\nLast stdout:\\n${this.stdoutOutput.slice(-500).trim()}\\nLast stderr:\\n${this.stderrOutput.trim()}`\n );\n }\n\n /**\n * Gracefully and forcefully kills the process and all its children.\n */\n public async stop(): Promise<void> {\n if (!this.child || !this.child.pid || this.hasExited) {\n this.child = null;\n return;\n }\n\n const pid = this.child.pid;\n console.log(`šŸ›‘ [ProcessManager] Terminating process tree (PID: ${pid})...`);\n\n await new Promise<void>((resolve) => {\n treeKill(pid, 'SIGKILL', (err) => {\n if (err) {\n // Fallback to taskkill on Windows if tree-kill hit permission issues\n if (process.platform === 'win32') {\n try {\n spawn('taskkill', ['/pid', String(pid), '/T', '/F'], { stdio: 'ignore' });\n } catch {\n // ignore\n }\n }\n }\n resolve();\n });\n });\n\n this.child = null;\n }\n}\n","import path from 'path';\r\nimport fs from 'fs';\r\nimport type { Page, BrowserContext } from 'playwright';\r\nimport {\r\n type VisualScenario,\r\n type TestContext,\r\n type ViewportPreset,\r\n VIEWPORT_PRESETS,\r\n type CaptureOptions,\r\n type CaptureBurstOptions\r\n} from '../../shared/api/dsl';\r\nimport { CaptureEngine } from '../capture/capture';\r\nimport { VisualReporter } from '../reporter/reporter';\r\nimport { ConsoleTracker } from '../console-tracker/consoleTracker';\r\nimport { DesktopDriver } from '../../shared/drivers/desktopDriver';\r\nimport { PreviewDriver } from '../../shared/drivers/previewDriver';\r\nimport { ProcessManager } from '../../shared/lib/processManager';\r\n\r\nexport interface RunOptions {\r\n scenario: VisualScenario;\r\n targetMode?: 'desktop' | 'preview';\r\n artifactsRoot?: string;\r\n autoLaunchDesktop?: boolean;\r\n port?: number;\r\n wwwrootDir?: string;\r\n executablePath?: string;\r\n desktopArgs?: string[];\r\n desktopEnv?: Record<string, string>;\r\n cleanPaths?: string[];\r\n url?: string;\r\n startCommand?: string;\r\n startCwd?: string;\r\n cleanArtifacts?: boolean;\r\n headed?: boolean;\r\n detach?: boolean;\r\n globalMocks?: any[];\r\n}\r\n\r\nexport interface RunResult {\r\n scenarioId: string;\r\n targetMode: 'desktop' | 'preview';\r\n success: boolean;\r\n totalSnapshots: number;\r\n consoleErrors: number;\r\n consoleWarnings: number;\r\n reportPath: string;\r\n artifactsDir: string;\r\n error?: string;\r\n}\r\n\r\nexport async function runVisualScenario(options: RunOptions): Promise<RunResult> {\r\n const { scenario } = options;\r\n const targetMode = options.targetMode || 'preview';\r\n const startTime = Date.now();\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\r\n const artifactsRoot = options.artifactsRoot || path.resolve(process.cwd(), 'artifacts');\r\n\r\n if (options.cleanArtifacts && fs.existsSync(artifactsRoot)) {\r\n console.log(`🧹 [Clean Artifacts] Purging previous artifact runs in ${artifactsRoot}...`);\r\n const entries = fs.readdirSync(artifactsRoot, { withFileTypes: true });\r\n for (const entry of entries) {\r\n fs.rmSync(path.join(artifactsRoot, entry.name), { recursive: true, force: true });\r\n }\r\n }\r\n\r\n const scenarioArtifactsDir = path.join(artifactsRoot, `${scenario.id}_${timestamp}`);\r\n \r\n if (!fs.existsSync(scenarioArtifactsDir)) {\r\n fs.mkdirSync(scenarioArtifactsDir, { recursive: true });\r\n }\r\n\r\n const captureEngine = new CaptureEngine(scenarioArtifactsDir);\r\n const consoleTracker = new ConsoleTracker();\r\n const defaultViewport = scenario.viewports?.[0] || VIEWPORT_PRESETS.DEFAULT;\r\n let currentViewport = { width: defaultViewport.width, height: defaultViewport.height };\r\n\r\n let desktopDriver: DesktopDriver | null = null;\r\n let previewDriver: PreviewDriver | null = null;\r\n let processManager: ProcessManager | null = null;\r\n\r\n try {\r\n let page: Page;\r\n let context: BrowserContext;\r\n\r\n console.log(`\\n========================================`);\r\n console.log(`šŸš€ Starting Visual Test: ${scenario.title}`);\r\n console.log(`šŸŽÆ Mode: ${targetMode.toUpperCase()}`);\r\n console.log(`šŸ“ Artifacts: ${scenarioArtifactsDir}`);\r\n console.log(`========================================\\n`);\r\n\r\n if (options.startCommand) {\r\n processManager = new ProcessManager();\r\n await processManager.start(options.startCommand, { cwd: options.startCwd });\r\n const waitTarget = options.url || 'http://localhost:5173';\r\n await processManager.waitForUrl(waitTarget);\r\n }\r\n\r\n if (typeof scenario.setup === 'function') {\r\n console.log(`šŸ”§ [Scenario Setup] Executing setup hook...`);\r\n await scenario.setup();\r\n }\r\n\r\n if (targetMode === 'desktop') {\r\n desktopDriver = new DesktopDriver({\r\n port: options.port || 9222,\r\n autoLaunch: options.autoLaunchDesktop ?? true,\r\n executablePath: options.executablePath,\r\n args: options.desktopArgs,\r\n env: options.desktopEnv\r\n });\r\n const res = await desktopDriver.start(currentViewport);\r\n page = res.page;\r\n context = res.context;\r\n } else {\r\n previewDriver = new PreviewDriver({\r\n wwwrootDir: options.wwwrootDir,\r\n url: options.url,\r\n headed: options.headed\r\n });\r\n\r\n // Apply declarative mockIpc from scenario and global mocks before start\r\n const mergedMocks = [...(options.globalMocks || []), ...(scenario.mockIpc || [])];\r\n if (mergedMocks.length > 0) {\r\n console.log(`šŸ“¦ [Mock IPC] Applying ${mergedMocks.length} mocks`);\r\n previewDriver.mockRegistry.setBatch(mergedMocks);\r\n }\r\n\r\n const res = await previewDriver.start(currentViewport);\r\n page = res.page;\r\n context = res.context;\r\n }\r\n\r\n // Attach console error interception\r\n consoleTracker.attach(page);\r\n console.log(`šŸ” [Console Tracker] Attached — errors and warnings will be captured\\n`);\r\n\r\n // Internal navigation function supporting live URLs and hash routing\r\n const doNavigate = async (route: string) => {\r\n if (route.startsWith('http://') || route.startsWith('https://')) {\r\n await page.goto(route, { waitUntil: 'domcontentloaded' });\r\n await page.waitForTimeout(300);\r\n return;\r\n }\r\n if (route.startsWith('#')) {\r\n await page.evaluate((r) => { window.location.hash = r; }, route);\r\n await page.waitForTimeout(300);\r\n return;\r\n }\r\n if (previewDriver?.baseUrl && options.url) {\r\n try {\r\n const fullUrl = new URL(route, previewDriver.baseUrl).toString();\r\n await page.goto(fullUrl, { waitUntil: 'domcontentloaded' });\r\n await page.waitForTimeout(300);\r\n return;\r\n } catch {\r\n // fallback to hash\r\n }\r\n }\r\n const routePath = route.startsWith('/') ? route : `/${route}`;\r\n await page.evaluate((r) => {\r\n if (window.location.hash !== undefined) {\r\n window.location.hash = r;\r\n }\r\n }, routePath);\r\n await page.waitForTimeout(300);\r\n };\r\n\r\n if (scenario.route) {\r\n console.log(`[Runner] Navigating to route: ${scenario.route}`);\r\n await doNavigate(scenario.route);\r\n }\r\n\r\n const ctx: TestContext = {\r\n page,\r\n context,\r\n targetMode,\r\n currentViewport,\r\n\r\n\r\n capture: async (name: string, opts?: CaptureOptions) => {\r\n console.log(`šŸ“ø [Snapshot] ${name} (${currentViewport.width}x${currentViewport.height})`);\r\n return await captureEngine.takeSnapshot(page, name, currentViewport, opts);\r\n },\r\n\r\n captureBurst: async (name: string, opts: CaptureBurstOptions) => {\r\n console.log(`šŸŽ¬ [Burst] ${name} (duration: ${opts.durationMs}ms, interval: ${opts.intervalMs ?? 80}ms)`);\r\n return await captureEngine.takeBurst(page, name, currentViewport, opts);\r\n },\r\n\r\n\r\n navigate: async (route: string) => {\r\n console.log(`🧭 [Navigate] ${route}`);\r\n await doNavigate(route);\r\n },\r\n\r\n // ─── Viewport ───\r\n\r\n resize: async (width: number, height: number) => {\r\n console.log(`šŸ“ [Resize] ${width}x${height}`);\r\n currentViewport = { width, height };\r\n ctx.currentViewport = currentViewport;\r\n await page.setViewportSize(currentViewport);\r\n await page.waitForTimeout(200);\r\n },\r\n\r\n setPreset: async (preset: ViewportPreset) => {\r\n console.log(`šŸ“ [Preset] ${preset.name} (${preset.width}x${preset.height})`);\r\n await ctx.resize(preset.width, preset.height);\r\n },\r\n\r\n resizeToFit: async (selector?: string, padding = 0) => {\r\n let boundingBox;\r\n if (selector) {\r\n const el = await page.$(selector);\r\n if (el) {\r\n boundingBox = await el.boundingBox();\r\n }\r\n } else {\r\n boundingBox = await page.evaluate(() => {\r\n return {\r\n width: document.documentElement.scrollWidth,\r\n height: document.documentElement.scrollHeight\r\n };\r\n });\r\n }\r\n\r\n if (boundingBox) {\r\n const newWidth = Math.ceil(boundingBox.width) + padding * 2;\r\n const newHeight = Math.ceil(boundingBox.height) + padding * 2;\r\n console.log(`šŸ“ [ResizeToFit] ${selector || 'body'} -> ${newWidth}x${newHeight}`);\r\n await ctx.resize(newWidth, newHeight);\r\n } else {\r\n console.log(`āš ļø [ResizeToFit] Element ${selector} not found or has no bounding box.`);\r\n }\r\n },\r\n\r\n\r\n wait: async (ms: number) => {\r\n await page.waitForTimeout(ms);\r\n },\r\n\r\n waitForSelector: async (selector: string, timeoutMs = 5000) => {\r\n await page.waitForSelector(selector, { timeout: timeoutMs });\r\n },\r\n\r\n\r\n click: async (selector: string) => {\r\n console.log(`šŸ–±ļø [Click] ${selector}`);\r\n await page.click(selector);\r\n },\r\n \r\n rightClick: async (selector: string) => {\r\n console.log(`šŸ–±ļø [RightClick] ${selector}`);\r\n await page.click(selector, { button: 'right' });\r\n },\r\n\r\n type: async (selector: string, text: string) => {\r\n console.log(`āŒØļø [Type] ${selector} -> \"${text}\"`);\r\n await page.fill(selector, text);\r\n },\r\n \r\n selectOption: async (selector: string, value: string) => {\r\n console.log(`āœ… [Select] ${selector} -> \"${value}\"`);\r\n await page.selectOption(selector, value);\r\n },\r\n\r\n hover: async (selector: string) => {\r\n console.log(`šŸ‘† [Hover] ${selector}`);\r\n await page.hover(selector);\r\n },\r\n \r\n scroll: async (selector: string, deltaY: number) => {\r\n console.log(`šŸ“œ [Scroll] ${selector} by ${deltaY}px`);\r\n await page.evaluate(({ sel, dY }) => {\r\n const el = document.querySelector(sel);\r\n if (el) {\r\n el.scrollTop += dY;\r\n } else {\r\n window.scrollBy(0, dY);\r\n }\r\n }, { sel: selector, dY: deltaY });\r\n await page.waitForTimeout(100);\r\n },\r\n\r\n\r\n log: (msg: string) => {\r\n console.log(`ā„¹ļø [Scenario] ${msg}`);\r\n },\r\n\r\n // ─── Mock IPC ───\r\n\r\n setMockIpc: async (action: string, data: any, mockOptions?) => {\r\n if (targetMode === 'desktop') {\r\n console.log(`āš ļø [Mock IPC] setMockIpc ignored in desktop mode (real backend handles IPC)`);\r\n return;\r\n }\r\n if (!previewDriver) {\r\n console.log(`āš ļø [Mock IPC] PreviewDriver not available`);\r\n return;\r\n }\r\n console.log(`šŸ“¦ [Mock IPC] Set ${action} -> ${typeof data === 'string' ? data : JSON.stringify(data).slice(0, 80)}...`);\r\n await previewDriver.updateMockIpc(action, data, mockOptions);\r\n },\r\n\r\n\r\n getConsoleErrors: () => consoleTracker.getErrors(),\r\n getConsoleWarnings: () => consoleTracker.getWarnings(),\r\n hasConsoleErrors: () => consoleTracker.hasErrors,\r\n\r\n // ─── DOM Assertions ───\r\n\r\n readText: async (selector: string): Promise<string | null> => {\r\n const text = await page.textContent(selector);\r\n return text ? text.trim() : null;\r\n },\r\n \r\n getPageText: async (): Promise<string> => {\r\n return await page.evaluate(() => document.body.innerText || '');\r\n },\r\n\r\n isVisible: async (selector: string) => {\r\n try {\r\n const element = await page.$(selector);\r\n if (!element) return false;\r\n return await element.isVisible();\r\n } catch {\r\n return false;\r\n }\r\n },\r\n\r\n getElementCount: async (selector: string) => {\r\n const elements = await page.$$(selector);\r\n return elements.length;\r\n }\r\n };\r\n\r\n await scenario.run(ctx);\r\n\r\n const durationMs = Date.now() - startTime;\r\n const snapshots = captureEngine.getSnapshots();\r\n const consoleErrors = consoleTracker.getErrors();\r\n const consoleWarnings = consoleTracker.getWarnings();\r\n\r\n if (consoleErrors.length > 0) {\r\n console.log(`\\nšŸ”“ Console Errors: ${consoleErrors.length}`);\r\n consoleErrors.forEach((err, i) => console.log(` ${i + 1}. ${err.text.slice(0, 120)}`));\r\n }\r\n if (consoleWarnings.length > 0) {\r\n console.log(`\\n🟔 Console Warnings: ${consoleWarnings.length}`);\r\n }\r\n\r\n const reportPath = VisualReporter.generateReport({\r\n scenario,\r\n snapshots,\r\n consoleErrors,\r\n consoleWarnings,\r\n outputDir: scenarioArtifactsDir,\r\n targetMode,\r\n durationMs\r\n });\r\n\r\n const syncLatest = (repPath: string, snaps: any[]) => {\r\n try {\r\n const latestDir = path.join(artifactsRoot, 'latest');\r\n if (fs.existsSync(latestDir)) {\r\n fs.rmSync(latestDir, { recursive: true, force: true });\r\n }\r\n fs.mkdirSync(latestDir, { recursive: true });\r\n fs.copyFileSync(repPath, path.join(latestDir, 'report.md'));\r\n const manifestSrc = path.join(scenarioArtifactsDir, 'manifest.json');\r\n if (fs.existsSync(manifestSrc)) {\r\n fs.copyFileSync(manifestSrc, path.join(latestDir, 'manifest.json'));\r\n }\r\n for (const snap of snaps) {\r\n if (snap.filePath && fs.existsSync(snap.filePath)) {\r\n fs.copyFileSync(snap.filePath, path.join(latestDir, snap.fileName));\r\n }\r\n }\r\n return path.join(latestDir, 'report.md');\r\n } catch {\r\n return undefined;\r\n }\r\n };\r\n\r\n const latestReport = syncLatest(reportPath, snapshots);\r\n\r\n console.log(`\\nāœ… Visual Test Completed Successfully!`);\r\n console.log(`šŸ“Š Captured Snapshots: ${snapshots.length}`);\r\n console.log(`šŸ”“ Console Errors: ${consoleErrors.length}`);\r\n console.log(`🟔 Console Warnings: ${consoleWarnings.length}`);\r\n console.log(`šŸ“„ Markdown Report: ${reportPath}`);\r\n if (latestReport) {\r\n console.log(`šŸ“Œ Latest Report: ${latestReport}`);\r\n }\r\n\r\n return {\r\n scenarioId: scenario.id,\r\n targetMode,\r\n success: true,\r\n totalSnapshots: snapshots.length,\r\n consoleErrors: consoleErrors.length,\r\n consoleWarnings: consoleWarnings.length,\r\n reportPath,\r\n artifactsDir: scenarioArtifactsDir\r\n };\r\n } catch (err: any) {\r\n console.error(`\\nāŒ Visual Test Failed: ${err.message}`);\r\n const durationMs = Date.now() - startTime;\r\n const snapshots = captureEngine.getSnapshots();\r\n const consoleErrors = consoleTracker.getErrors();\r\n const consoleWarnings = consoleTracker.getWarnings();\r\n\r\n const reportPath = VisualReporter.generateReport({\r\n scenario,\r\n snapshots,\r\n consoleErrors,\r\n consoleWarnings,\r\n outputDir: scenarioArtifactsDir,\r\n targetMode,\r\n durationMs\r\n });\r\n\r\n try {\r\n const latestDir = path.join(artifactsRoot, 'latest');\r\n if (fs.existsSync(latestDir)) {\r\n fs.rmSync(latestDir, { recursive: true, force: true });\r\n }\r\n fs.mkdirSync(latestDir, { recursive: true });\r\n fs.copyFileSync(reportPath, path.join(latestDir, 'report.md'));\r\n } catch {\r\n // ignore\r\n }\r\n\r\n return {\r\n scenarioId: scenario.id,\r\n targetMode,\r\n success: false,\r\n totalSnapshots: snapshots.length,\r\n consoleErrors: consoleErrors.length,\r\n consoleWarnings: consoleWarnings.length,\r\n reportPath,\r\n artifactsDir: scenarioArtifactsDir,\r\n error: err.message\r\n };\r\n } finally {\r\n // 1. Run scenario teardown hook (guaranteed cleanup)\r\n if (typeof scenario.teardown === 'function') {\r\n try {\r\n console.log(`🧹 [Scenario Teardown] Executing teardown hook...`);\r\n await scenario.teardown();\r\n } catch (teardownErr: any) {\r\n console.error(`āš ļø [Scenario Teardown] Error during teardown:`, teardownErr.message);\r\n }\r\n }\r\n\r\n // 2. Perform requested file and folder cleanups\r\n if (options.cleanPaths && options.cleanPaths.length > 0) {\r\n for (const cleanTarget of options.cleanPaths) {\r\n try {\r\n const resolvedCleanPath = path.resolve(process.cwd(), cleanTarget);\r\n if (fs.existsSync(resolvedCleanPath)) {\r\n console.log(`🧹 [Auto-Cleanup] Removing: ${resolvedCleanPath}`);\r\n fs.rmSync(resolvedCleanPath, { recursive: true, force: true });\r\n }\r\n } catch (cleanErr: any) {\r\n console.error(`āš ļø [Auto-Cleanup] Failed to remove ${cleanTarget}:`, cleanErr.message);\r\n }\r\n }\r\n }\r\n\r\n // 3. Stop running drivers unless detached\r\n if (!options.detach) {\r\n if (desktopDriver) await desktopDriver.stop();\r\n if (previewDriver) await previewDriver.stop();\r\n if (processManager) await processManager.stop();\r\n } else {\r\n console.log('šŸ”— [Runner] Detach mode active, leaving browser/app open.');\r\n }\r\n }\r\n}\r\n","import path from 'path';\nimport fs from 'fs';\nimport { runVisualScenario } from '../runner/runner';\nimport { defineVisualTest, VIEWPORT_PRESETS, type ViewportPreset } from '../../shared/api/dsl';\nimport { resolveWwwrootDir } from '../../shared/lib/config';\n\nexport interface SnapCliOptions {\n url?: string;\n start?: string;\n startCwd?: string;\n selector?: string;\n viewports?: string[];\n waitMs?: number;\n name?: string;\n clean?: string[];\n cleanArtifacts?: boolean;\n headed?: boolean;\n detach?: boolean;\n outDir?: string;\n mode?: 'desktop' | 'preview';\n exe?: string;\n port?: number;\n}\n\nconst PRESET_MAP: Record<string, ViewportPreset> = {\n default: VIEWPORT_PRESETS.DEFAULT,\n desktop: VIEWPORT_PRESETS.DEFAULT,\n min: VIEWPORT_PRESETS.MIN_SUPPORTED,\n 'min-supported': VIEWPORT_PRESETS.MIN_SUPPORTED,\n wide: VIEWPORT_PRESETS.WIDE,\n mobile: { name: 'mobile', width: 375, height: 667 },\n tablet: { name: 'tablet', width: 768, height: 1024 },\n 'full-hd': VIEWPORT_PRESETS.FULL_HD\n};\n\nfunction parseViewportPresets(raw?: string[]): ViewportPreset[] {\n if (!raw || raw.length === 0) {\n return [VIEWPORT_PRESETS.DEFAULT, PRESET_MAP.mobile];\n }\n\n const presets: ViewportPreset[] = [];\n for (const item of raw) {\n const lower = item.toLowerCase().trim();\n if (PRESET_MAP[lower]) {\n presets.push(PRESET_MAP[lower]);\n } else if (lower.includes('x')) {\n const [w, h] = lower.split('x').map((n) => parseInt(n, 10));\n if (!isNaN(w) && !isNaN(h)) {\n presets.push({ name: `${w}x${h}`, width: w, height: h });\n }\n }\n }\n\n return presets.length > 0 ? presets : [VIEWPORT_PRESETS.DEFAULT, PRESET_MAP.mobile];\n}\n\nasync function isPortResponding(url: string): Promise<boolean> {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(800) });\n return Boolean(res.status);\n } catch {\n return false;\n }\n}\n\nexport async function runQuickSnap(options: SnapCliOptions): Promise<boolean> {\n let targetUrl = options.url;\n let useStaticPreview = false;\n let wwwrootDir: string | undefined;\n\n // Smart URL/Server Resolution when neither --url nor --start is explicitly provided\n if (!targetUrl && !options.start) {\n if (await isPortResponding('http://localhost:5173')) {\n targetUrl = 'http://localhost:5173';\n console.log(`🌐 [Quick Snap] Detected active dev server on http://localhost:5173`);\n } else if (await isPortResponding('http://localhost:3000')) {\n targetUrl = 'http://localhost:3000';\n console.log(`🌐 [Quick Snap] Detected active dev server on http://localhost:3000`);\n } else {\n // Check for compiled static files (dist, build, wwwroot)\n const candidateDir = resolveWwwrootDir();\n if (fs.existsSync(candidateDir) && fs.existsSync(path.join(candidateDir, 'index.html'))) {\n useStaticPreview = true;\n wwwrootDir = candidateDir;\n console.log(`šŸ“¦ [Quick Snap] No active server found. Detected built static directory at \"${candidateDir}\". Launching static preview...`);\n } else {\n console.error(`\\nāŒ [Quick Snap] No active server found on http://localhost:5173 or :3000, and no static build found.`);\n console.log(`šŸ’” Suggested actions:`);\n console.log(` 1. Pass a start command: npx agent-lens snap --start=\"npm run dev\"`);\n console.log(` 2. Specify your URL: npx agent-lens snap --url=http://localhost:8080`);\n console.log(` 3. Build your static app: npm run build\\n`);\n return false;\n }\n }\n } else if (!targetUrl && options.start) {\n targetUrl = 'http://localhost:5173';\n }\n\n const waitMs = options.waitMs ?? 1000;\n const snapshotPrefix = options.name || 'quick_snap';\n const targetViewports = parseViewportPresets(options.viewports);\n\n console.log(`\\nšŸ“ø [Quick Snap] Preparing instant verification for: ${targetUrl || wwwrootDir}`);\n console.log(`šŸ“ [Quick Snap] Testing ${targetViewports.length} viewports: ${targetViewports.map((v) => `${v.name} (${v.width}x${v.height})`).join(', ')}`);\n if (options.selector) {\n console.log(`šŸŽÆ [Quick Snap] Focused element selector: \"${options.selector}\"`);\n }\n\n const snapScenario = defineVisualTest({\n id: 'quick-snap',\n title: `Quick Verification: ${targetUrl || 'Static Preview'}`,\n description: `One-shot automated snapshot and console health check`,\n route: targetUrl || '/',\n viewports: targetViewports,\n run: async (ctx) => {\n ctx.log(`Waiting ${waitMs}ms for page stabilization...`);\n await ctx.wait(waitMs);\n\n for (let i = 0; i < targetViewports.length; i++) {\n const vp = targetViewports[i];\n const stepNum = String(i + 1).padStart(2, '0');\n ctx.log(`Switching viewport to: ${vp.name} (${vp.width}x${vp.height})`);\n await ctx.setPreset(vp);\n await ctx.wait(200);\n await ctx.capture(`${stepNum}_${snapshotPrefix}_${vp.name}`);\n }\n\n if (options.selector) {\n ctx.log(`Focusing on selector: \"${options.selector}\"`);\n try {\n await ctx.setPreset(VIEWPORT_PRESETS.DEFAULT);\n await ctx.resizeToFit(options.selector, 15);\n await ctx.capture(`99_${snapshotPrefix}_element_focus`, { selector: options.selector });\n } catch (err: any) {\n ctx.log(`āš ļø Could not isolate selector \"${options.selector}\": ${err.message}`);\n }\n }\n\n const errors = ctx.getConsoleErrors();\n if (errors.length > 0) {\n ctx.log(`🚨 Caught ${errors.length} console errors during snap check!`);\n } else {\n ctx.log(`āœ… Clean run: No console errors detected.`);\n }\n }\n });\n\n const result = await runVisualScenario({\n scenario: snapScenario,\n targetMode: options.mode || 'preview',\n url: useStaticPreview ? undefined : targetUrl,\n wwwrootDir: useStaticPreview ? wwwrootDir : undefined,\n startCommand: options.start,\n startCwd: options.startCwd,\n executablePath: options.exe,\n cleanPaths: options.clean,\n cleanArtifacts: options.cleanArtifacts,\n port: options.port,\n headed: options.headed,\n detach: options.detach,\n artifactsRoot: options.outDir ? path.resolve(process.cwd(), options.outDir) : undefined\n });\n\n console.log(`\\n========================================`);\n console.log(`šŸ Quick Snap Finished!`);\n console.log(`šŸ“ø Snapshots: ${result.totalSnapshots}`);\n console.log(`šŸ”“ Console Errors: ${result.consoleErrors}`);\n console.log(`🟔 Console Warnings: ${result.consoleWarnings}`);\n console.log(`šŸ“„ Report: ${result.reportPath}`);\n console.log(`========================================\\n`);\n\n return result.success && result.consoleErrors === 0;\n}\n","#!/usr/bin/env node\nimport path from 'path';\nimport fs from 'fs';\nimport { runVisualScenario } from '../features/runner/runner';\nimport type { VisualScenario } from '../shared/api/dsl';\nimport { createJiti } from 'jiti';\nimport { loadConfig, resolveWwwrootDir, detectStartCwd } from '../shared/lib/config';\nimport { runQuickSnap } from '../features/snap/snap';\n\n// 1. Load config from agent-lens.json or package.json\nconst fileConfig = loadConfig();\n\n// 2. Parse CLI Arguments\nconst args = process.argv.slice(2);\n\n// Check subcommands\nif (args[0] === 'init') {\n initScenarioTemplate();\n process.exit(0);\n}\n\nconst isSnapCommand = args[0] === 'snap';\nconst effectiveArgs = isSnapCommand ? args.slice(1) : args;\n\nconst options: {\n scenario?: string;\n mode: 'desktop' | 'preview';\n all?: boolean;\n port: number;\n help?: boolean;\n headed?: boolean;\n detach?: boolean;\n build?: boolean | string;\n start?: string;\n startCwd?: string;\n cleanArtifacts?: boolean;\n url?: string;\n selector?: string;\n viewports?: string[];\n waitMs?: number;\n name?: string;\n exe?: string;\n clean?: string[];\n dir?: string;\n wwwroot?: string;\n outDir?: string;\n} = {\n mode: fileConfig.mode || 'preview',\n port: fileConfig.port || 9222,\n headed: fileConfig.headed ?? false,\n detach: fileConfig.detach ?? false,\n build: fileConfig.buildCommand || false,\n start: fileConfig.startCommand,\n startCwd: fileConfig.startCwd,\n cleanArtifacts: fileConfig.cleanArtifacts ?? false,\n url: fileConfig.url,\n exe: fileConfig.executablePath,\n clean: Array.isArray(fileConfig.clean) ? fileConfig.clean : (fileConfig.clean ? [fileConfig.clean] : undefined),\n dir: fileConfig.scenarios,\n wwwroot: fileConfig.wwwroot,\n outDir: fileConfig.outDir\n};\n\nfor (const arg of effectiveArgs) {\n if (arg === '--help' || arg === '-h') {\n options.help = true;\n } else if (arg.startsWith('--scenario=')) {\n options.scenario = arg.split('=')[1];\n } else if (arg === '--all') {\n options.all = true;\n } else if (arg.startsWith('--mode=')) {\n const mode = arg.split('=')[1].toLowerCase();\n if (mode === 'desktop' || mode === 'preview') {\n options.mode = mode as 'desktop' | 'preview';\n }\n } else if (arg.startsWith('--port=')) {\n options.port = parseInt(arg.split('=')[1], 10) || 9222;\n } else if (arg === '--headed') {\n options.headed = true;\n } else if (arg === '--detach') {\n options.detach = true;\n } else if (arg === '--build') {\n options.build = true;\n } else if (arg.startsWith('--build=')) {\n options.build = arg.slice('--build='.length);\n } else if (arg.startsWith('--start=')) {\n options.start = arg.slice('--start='.length);\n } else if (arg.startsWith('--start-cwd=') || arg.startsWith('--cwd=')) {\n options.startCwd = arg.split('=')[1];\n } else if (arg === '--clean-artifacts') {\n options.cleanArtifacts = true;\n } else if (arg.startsWith('--url=')) {\n options.url = arg.split('=')[1];\n } else if (arg.startsWith('--selector=')) {\n options.selector = arg.split('=')[1];\n } else if (arg.startsWith('--viewports=')) {\n options.viewports = arg.split('=')[1].split(',').map((v) => v.trim()).filter(Boolean);\n } else if (arg.startsWith('--wait=')) {\n options.waitMs = parseInt(arg.split('=')[1], 10);\n } else if (arg.startsWith('--name=')) {\n options.name = arg.split('=')[1];\n } else if (arg.startsWith('--exe=') || arg.startsWith('--executable=')) {\n options.exe = arg.split('=')[1];\n } else if (arg.startsWith('--clean=') || arg.startsWith('--cleanup=')) {\n const rawPaths = arg.split('=')[1];\n options.clean = rawPaths.split(',').map((p) => p.trim()).filter(Boolean);\n } else if (arg.startsWith('--dir=')) {\n options.dir = arg.split('=')[1];\n } else if (arg.startsWith('--wwwroot=')) {\n options.wwwroot = arg.split('=')[1];\n } else if (arg.startsWith('--outDir=') || arg.startsWith('--folder=')) {\n options.outDir = arg.split('=')[1];\n }\n}\n\n// Auto-detect startCwd if a start command was provided in a monorepo setup\nif (options.start && !options.startCwd) {\n options.startCwd = detectStartCwd(options.startCwd);\n}\n\nfunction printHelp() {\n console.log(`\nšŸ‘ļø AgentLens - Visual UI Self-Verification for AI Agents\n\nUsage:\n npx agent-lens snap [options] Instant one-shot visual & console check (no test files needed)\n npx agent-lens [options] Run scripted scenario tests from scenarios/\n npx agent-lens init Generate starter scenario template & mocks\n\nCommands:\n snap Take immediate multi-viewport screenshots of a URL & check console errors\n init Generate starter template in scenarios/template.scenario.ts and mocks.ts\n\nOptions:\n --url=<url> Target URL to test (e.g. http://localhost:5173 or http://localhost:3000)\n --start=\"<cmd>\" Launch dev server or backend process before testing (e.g. --start=\"npm run dev\")\n --start-cwd=<path> Directory to execute --start command in (e.g. --start-cwd=./Frontend)\n --clean-artifacts Purge previous test artifacts to prevent folder bloat\n --selector=<css> Target a specific element to focus on / resize-to-fit\n --viewports=<list> Comma-separated viewport presets (default: desktop,mobile; or 1200x800,375x667)\n --wait=<ms> Wait time in milliseconds after loading before snapshotting [default: 1000]\n --name=<prefix> Custom name prefix for captured snapshots [default: quick_snap]\n --scenario=<name> Run specific scenario by name (e.g. --scenario=smoke)\n --all Run all discovered scenarios\n --mode=<mode> Engine mode: 'preview' (Web/Vite/Live) or 'desktop' (WebView2/CDP) [default: preview]\n --exe=<path> Path to native executable for desktop mode (e.g. --exe=bin/MyApp.exe)\n --port=<port> CDP remote debugging port [default: 9222]\n --build[=<cmd>] Run build command before testing (e.g. --build=\"dotnet build\" or npm run build)\n --clean=<paths> Comma-separated paths to safely delete upon test exit (e.g. --clean=\"./temp,./cache\")\n --headed Show Chromium browser window\n --detach Keep browser/app open after finishing\n --dir=<path> Custom scenarios directory [default: scenarios]\n --wwwroot=<path> Custom directory for static fallback mode [default: dist]\n --folder=<path> Directory to save visual artifacts/reports (also --outDir)\n --help, -h Show this help message\n `);\n}\n\nfunction initScenarioTemplate() {\n const targetDir = path.resolve(process.cwd(), 'scenarios');\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n\n // 1. Generate template.scenario.ts\n const templatePath = path.join(targetDir, 'template.scenario.ts');\n if (!fs.existsSync(templatePath)) {\n const templateContent = `import { defineVisualTest, VIEWPORT_PRESETS } from 'agent-lens';\n\nexport default defineVisualTest({\n id: 'template-check',\n title: 'Basic UI Smoke & Responsiveness Check',\n route: '/',\n // Optional setup hook before test runs\n setup: async () => {\n // prepare test files or folders\n },\n run: async (ctx) => {\n ctx.log('Initial page render');\n await ctx.capture('01_initial_state');\n\n // Test adaptive layout\n await ctx.setPreset(VIEWPORT_PRESETS.MIN_SUPPORTED);\n await ctx.capture('02_compact_view');\n\n // Check for JavaScript / React runtime errors\n const errors = ctx.getConsoleErrors();\n if (errors.length > 0) {\n ctx.log(\\`āš ļø Warning: Caught \\${errors.length} console errors!\\`);\n }\n },\n // Optional teardown hook guaranteed to run on exit\n teardown: async () => {\n // clean up temporary test files or state\n }\n});\n`;\n fs.writeFileSync(templatePath, templateContent, 'utf8');\n console.log(`āœ… Starter scenario generated at: ${templatePath}`);\n } else {\n console.log(`ā„¹ļø Template already exists at: ${templatePath}`);\n }\n\n // 2. Generate starter mocks.ts to prevent root app crash\n const mocksPath = path.join(targetDir, 'mocks.ts');\n if (!fs.existsSync(mocksPath)) {\n const mocksContent = `/**\n * Global IPC & API Mocks\n * \n * Export an array of base mocks to satisfy root application state on boot.\n */\nexport default [\n { action: 'GET_PREFS', data: { theme: 'dark', language: 'en' } },\n { action: 'GET_USER_PROFILE', data: { id: 1, name: 'Agent', role: 'admin' } }\n];\n`;\n fs.writeFileSync(mocksPath, mocksContent, 'utf8');\n console.log(`āœ… Base global mocks generated at: ${mocksPath}`);\n }\n\n console.log(`šŸ‘‰ Run tests with: npx agent-lens --scenario=template --mode=preview`);\n}\n\nif (options.help) {\n printHelp();\n process.exit(0);\n}\n\nasync function findScenarios(dir: string, specificName?: string): Promise<string[]> {\n const results: string[] = [];\n if (!fs.existsSync(dir)) return results;\n\n const items = fs.readdirSync(dir, { withFileTypes: true });\n for (const item of items) {\n const fullPath = path.join(dir, item.name);\n if (item.isDirectory()) {\n results.push(...await findScenarios(fullPath, specificName));\n } else if (item.name.endsWith('.scenario.ts') || item.name.endsWith('.scenario.js')) {\n if (!specificName || item.name.startsWith(specificName)) {\n results.push(fullPath);\n }\n }\n }\n return results;\n}\n\nfunction resolveScenariosDirectory(customDir?: string): string {\n if (customDir) {\n return path.resolve(process.cwd(), customDir);\n }\n\n const candidates = [\n 'scenarios',\n 'tests/visual',\n 'tests/scenarios',\n 'test/scenarios',\n 'src/scenarios'\n ];\n\n for (const c of candidates) {\n const p = path.resolve(process.cwd(), c);\n if (fs.existsSync(p)) {\n return p;\n }\n }\n\n return path.resolve(process.cwd(), 'scenarios');\n}\n\nasync function main() {\n // 1. One-shot \"snap\" command execution\n if (isSnapCommand || (options.url && !options.scenario && !options.all)) {\n const snapSuccess = await runQuickSnap({\n url: options.url,\n start: options.start,\n startCwd: options.startCwd,\n selector: options.selector,\n viewports: options.viewports,\n waitMs: options.waitMs,\n name: options.name,\n clean: options.clean,\n cleanArtifacts: options.cleanArtifacts,\n headed: options.headed,\n detach: options.detach,\n outDir: options.outDir,\n mode: options.mode,\n exe: options.exe,\n port: options.port\n });\n\n process.exit(snapSuccess ? 0 : 1);\n }\n\n // 2. Scenario-based test execution\n if (!options.scenario && !options.all) {\n console.error('āŒ Please specify a scenario (--scenario=name), run --all, or use: npx agent-lens snap --url=http://localhost:5173');\n printHelp();\n process.exit(1);\n }\n\n const scenariosDir = resolveScenariosDirectory(options.dir);\n const scenarioPaths = await findScenarios(scenariosDir, options.scenario);\n\n if (scenarioPaths.length === 0) {\n console.error(`āŒ No scenarios found in ${scenariosDir}`);\n console.log(`šŸ’” Generate a template with: npx agent-lens init`);\n process.exit(1);\n }\n\n const shouldBuild = options.build || fileConfig.autoBuild;\n if (shouldBuild) {\n const buildCmd = typeof options.build === 'string'\n ? options.build\n : (fileConfig.buildCommand || 'npm run build');\n\n console.log(`\\nšŸ”Ø [Build] Running build process: \"${buildCmd}\"...`);\n const { execSync } = require('child_process');\n try {\n execSync(buildCmd, { stdio: 'inherit', cwd: options.startCwd || process.cwd() });\n } catch (e) {\n console.error(`āŒ Build failed: ${buildCmd}`);\n process.exit(1);\n }\n } else if (options.mode === 'preview' && !options.url && !options.start) {\n console.log(`āš ļø Warning: Running without --build or --url flag. Make sure your frontend is built!`);\n }\n\n console.log(`šŸ“‹ Found ${scenarioPaths.length} scenario(s) in: ${scenariosDir}`);\n\n // Initialize JITI for seamless TypeScript loading\n const jiti = createJiti(process.cwd());\n\n // Check for global mocks\n let globalMocks: any[] = [];\n const mockCandidates = [\n path.join(scenariosDir, 'mocks.ts'),\n path.join(scenariosDir, 'mocks.js'),\n path.join(process.cwd(), 'mocks.ts'),\n path.join(process.cwd(), 'mocks.js')\n ];\n\n for (const mocksPath of mockCandidates) {\n if (fs.existsSync(mocksPath)) {\n try {\n const m = await jiti.import(mocksPath) as any;\n globalMocks = m.default || m.mocks || [];\n console.log(`šŸŒ Loaded ${globalMocks.length} global mock(s) from ${path.basename(mocksPath)}`);\n break;\n } catch (err) {\n console.warn(`āš ļø Failed to load global mocks from ${mocksPath}:`, err);\n }\n }\n }\n\n let allSuccess = true;\n for (const scenarioPath of scenarioPaths) {\n try {\n const scenarioModule = await jiti.import(scenarioPath) as any;\n const scenario: VisualScenario = scenarioModule.default || scenarioModule.scenario;\n\n if (!scenario || typeof scenario.run !== 'function') {\n console.error(`āš ļø Skipped: file ${path.basename(scenarioPath)} does not export a VisualScenario object by default.`);\n continue;\n }\n\n const result = await runVisualScenario({\n scenario,\n targetMode: options.mode,\n url: options.url,\n startCommand: options.start,\n startCwd: options.startCwd,\n cleanArtifacts: options.cleanArtifacts,\n port: options.port,\n headed: options.headed,\n detach: options.detach,\n executablePath: options.exe,\n cleanPaths: options.clean,\n desktopEnv: fileConfig.env,\n wwwrootDir: options.wwwroot ? resolveWwwrootDir(options.wwwroot) : undefined,\n artifactsRoot: options.outDir ? path.resolve(process.cwd(), options.outDir) : undefined,\n globalMocks\n });\n\n if (!result.success) {\n allSuccess = false;\n }\n } catch (err: any) {\n console.error(`āŒ Failed to load scenario ${path.basename(scenarioPath)}:`, err);\n allSuccess = false;\n }\n }\n\n if (!allSuccess) {\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","http","fs","path","action","spawn","path","fs","path","fs","path","fs"]}
1
+ {"version":3,"sources":["../src/shared/api/dsl.ts","../src/features/capture/capture.ts","../src/features/reporter/reporter.ts","../src/features/console-tracker/consoleTracker.ts","../src/shared/lib/playwrightLoader.ts","../src/shared/drivers/desktopDriver.ts","../src/features/mock-ipc/mockIpc.ts","../src/shared/lib/config.ts","../src/shared/drivers/previewDriver.ts","../src/shared/lib/processManager.ts","../src/features/runner/runner.ts","../src/features/snap/snap.ts","../src/app/cli.ts"],"sourcesContent":["import type { Page, BrowserContext } from 'playwright';\nimport type { ConsoleEntry } from '../../features/console-tracker/consoleTracker';\nimport type { MockIpcResponseType } from '../../features/mock-ipc/mockIpc';\n\nexport interface ViewportPreset {\n name: string;\n width: number;\n height: number;\n}\n\nexport const VIEWPORT_PRESETS = {\n /** Minimum supported window size (e.g., ) */\n MIN_SUPPORTED: { name: 'min-supported', width: 1024, height: 768 } as ViewportPreset,\n /** Standard default window size (e.g., ) */\n DEFAULT: { name: 'default', width: 1200, height: 800 } as ViewportPreset,\n /** Wide screen for checking grids and tables */\n WIDE: { name: 'wide', width: 1600, height: 900 } as ViewportPreset,\n /** Full HD */\n FULL_HD: { name: 'full-hd', width: 1920, height: 1080 } as ViewportPreset,\n};\n\nexport interface MockRouteEntry {\n url: string;\n method?: string;\n status?: number;\n body: any;\n delayMs?: number;\n headers?: Record<string, string>;\n}\n\nexport interface CaptureOptions {\n selector?: string;\n fullPage?: boolean;\n mask?: string[];\n}\n \n\nexport interface CaptureBurstOptions {\n /** Total duration of burst animation capture in milliseconds */\n durationMs: number;\n /** Interval between frames in milliseconds (default: 80ms) */\n intervalMs?: number;\n /** Restrict capture to a specific element */\n selector?: string;\n}\n\nexport interface SnapshotMetadata {\n index: number;\n name: string;\n fileName: string;\n filePath: string;\n relativeUri: string;\n viewport: { width: number; height: number };\n timestamp: string;\n isBurstFrame?: boolean;\n burstGroup?: string;\n frameIndex?: number;\n selector?: string;\n}\n\nexport interface TestContext {\n page: Page;\n context: BrowserContext;\n targetMode: 'desktop' | 'preview';\n currentViewport: { width: number; height: number };\n \n // --- Snapshots ---\n\n /** Capture a single high-quality snapshot of the window or element */\n capture: (name: string, options?: CaptureOptions) => Promise<SnapshotMetadata>;\n \n /** Capture a series of frames for animations (Framer Motion, modals, lists) */\n captureBurst: (name: string, options: CaptureBurstOptions) => Promise<SnapshotMetadata[]>;\n \n // --- Navigation ---\n\n /** \n * Dynamically navigate to another page during the test.\n * Example: await ctx.navigate('/settings');\n */\n navigate: (route: string) => Promise<void>;\n\n // --- Viewport ---\n\n /** Change window / viewport size */\n resize: (width: number, height: number) => Promise<void>;\n \n /** Set one of the standard presets (MIN_SUPPORTED, DEFAULT, WIDE) */\n setPreset: (preset: ViewportPreset) => Promise<void>;\n\n /** \n * Dynamically resize the window so it perfectly fits the specified element (or body).\n * Useful when an agent wants to test an isolated component without background clutter.\n */\n resizeToFit: (selector?: string, padding?: number) => Promise<void>;\n \n // --- Waiting ---\n\n /** Wait the specified amount of milliseconds */\n wait: (ms: number) => Promise<void>;\n \n /** Wait for the selector to appear in the DOM */\n waitForSelector: (selector: string, timeoutMs?: number) => Promise<void>;\n \n // --- Interaction ---\n\n /** Left-click the element */\n click: (selector: string) => Promise<void>;\n \n /** Right-click the element (Context Menu) */\n rightClick: (selector: string) => Promise<void>;\n \n /** Type text into an input field */\n type: (selector: string, text: string) => Promise<void>;\n \n /** Select an option in a <select> by its value */\n selectOption: (selector: string, value: string) => Promise<void>;\n \n /** Hover the cursor to check highlights / tooltips */\n hover: (selector: string) => Promise<void>;\n \n /** Scroll the element (or window) down by the specified number of pixels */\n scroll: (selector: string, deltaY: number) => Promise<void>;\n \n // --- Logging ---\n\n /** Log a step for the agent */\n log: (message: string) => void;\n\n // --- Mock IPC & Network Routes (preview mode only) ---\n\n /**\n * Set a mock response for an IPC action.\n * Changes the data returned by window.__mockIpc.invoke or hybrid bridges in preview mode.\n * Ignored in desktop mode (IPC goes through real backend).\n */\n setMockIpc: (action: string, data: any, options?: { type?: MockIpcResponseType; delayMs?: number }) => Promise<void>;\n\n /**\n * Mock an HTTP REST or GraphQL network request in preview mode.\n * Intercepts fetch/axios calls matching the URL pattern and returns mock data.\n *\n * Example:\n * await ctx.setMockRoute('/api/user', { id: 1, name: 'Agent' });\n * await ctx.setMockRoute('**\\/api/items*', [], { status: 200, delayMs: 50 });\n */\n setMockRoute: (\n url: string,\n body: any,\n options?: { method?: string; status?: number; delayMs?: number; headers?: Record<string, string> }\n ) => Promise<void>;\n\n // --- Console Errors ---\n \n\n /** Return all intercepted console.error and pageerror logs */\n getConsoleErrors: () => ConsoleEntry[];\n\n /** Return all intercepted console.warn logs */\n getConsoleWarnings: () => ConsoleEntry[];\n\n /** Returns true if there are critical errors in the console */\n hasConsoleErrors: () => boolean;\n\n // --- DOM Assertions ---\n\n /** Get the visible text of a specific element */\n readText: (selector: string) => Promise<string | null>;\n \n /** Get ALL visible text on the page (useful for quick analysis without Vision) */\n getPageText: () => Promise<string>;\n \n /** Check if the element is visible on the screen */\n isVisible: (selector: string) => Promise<boolean>;\n\n /** Count the number of elements matching the selector */\n getElementCount: (selector: string) => Promise<number>;\n}\n\nexport interface VisualScenario {\n /** Unique scenario identifier (kebab-case) */\n id: string;\n /** Human-readable title for the report */\n title: string;\n /** Description of what is being tested */\n description?: string;\n /** Initial route to navigate to (e.g., '/instances', '/settings') */\n route?: string;\n /** List of viewport sizes to test */\n viewports?: ViewportPreset[];\n /**\n * Initial IPC mock data for preview mode.\n * Applied BEFORE navigation to the route.\n */\n mockIpc?: Array<{ action: string; data: any; type?: MockIpcResponseType; delayMs?: number }>;\n /**\n * Initial HTTP REST/GraphQL route mocks for preview mode.\n * Applied BEFORE navigation to the route.\n */\n mockRoutes?: MockRouteEntry[];\n /**\n * Optional setup hook: executed before the browser navigates and scenario runs.\n * Ideal for preparing mock files, test directories, or initial state.\n */\n \n setup?: () => Promise<void> | void;\n /** The main body of the scenario */\n run: (ctx: TestContext) => Promise<void>;\n /**\n * Optional teardown hook: guaranteed to execute in finally, even if run() fails.\n * Ideal for cleaning up test artifacts, cache directories, or temporary state.\n */\n teardown?: () => Promise<void> | void;\n}\n\nexport function defineVisualTest(scenario: VisualScenario): VisualScenario {\n return scenario;\n}\n","import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Page } from 'playwright';\r\nimport type { CaptureOptions, CaptureBurstOptions, SnapshotMetadata } from '../../shared/api/dsl';\r\n\r\nexport class CaptureEngine {\r\n private outputDir: string;\r\n private currentStepIndex: number = 0;\r\n private recordedSnapshots: SnapshotMetadata[] = [];\r\n\r\n constructor(outputDir: string) {\r\n this.outputDir = outputDir;\r\n if (!fs.existsSync(this.outputDir)) {\r\n fs.mkdirSync(this.outputDir, { recursive: true });\r\n }\r\n }\r\n\r\n public getSnapshots(): SnapshotMetadata[] {\r\n return this.recordedSnapshots;\r\n }\r\n\r\n public getOutputDir(): string {\r\n return this.outputDir;\r\n }\r\n\r\n /**\r\n */\r\n public async takeSnapshot(\r\n page: Page,\r\n name: string,\r\n viewport: { width: number; height: number },\r\n options?: CaptureOptions\r\n ): Promise<SnapshotMetadata> {\r\n this.currentStepIndex += 1;\r\n const paddedIndex = String(this.currentStepIndex).padStart(2, '0');\r\n const sanitizedName = name.replace(/[^a-zA-Z0-9_\\-]/g, '_');\r\n const fileName = `${paddedIndex}_${sanitizedName}_${viewport.width}x${viewport.height}.png`;\r\n const filePath = path.join(this.outputDir, fileName);\r\n\r\n if (options?.selector) {\r\n const element = await page.waitForSelector(options.selector, { timeout: 5000 });\r\n await element.screenshot({ path: filePath });\r\n } else {\r\n await page.screenshot({ path: filePath, fullPage: options?.fullPage ?? false });\r\n }\r\n\r\n const metadata: SnapshotMetadata = {\r\n index: this.currentStepIndex,\r\n name,\r\n fileName,\r\n filePath,\r\n relativeUri: `./${fileName}`,\r\n viewport,\r\n timestamp: new Date().toISOString(),\r\n selector: options?.selector\r\n };\r\n\r\n this.recordedSnapshots.push(metadata);\r\n return metadata;\r\n }\r\n\r\n /**\r\n */\r\n public async takeBurst(\r\n page: Page,\r\n name: string,\r\n viewport: { width: number; height: number },\r\n options: CaptureBurstOptions\r\n ): Promise<SnapshotMetadata[]> {\r\n this.currentStepIndex += 1;\r\n const stepIndex = this.currentStepIndex;\r\n const paddedIndex = String(stepIndex).padStart(2, '0');\r\n const sanitizedName = name.replace(/[^a-zA-Z0-9_\\-]/g, '_');\r\n\r\n const duration = Math.max(options.durationMs, 50);\r\n const interval = Math.max(options.intervalMs ?? 80, 20);\r\n const totalFrames = Math.ceil(duration / interval);\r\n\r\n const burstSnapshots: SnapshotMetadata[] = [];\r\n const burstGroup = sanitizedName;\r\n\r\n for (let frame = 0; frame <= totalFrames; frame++) {\r\n const elapsedMs = frame * interval;\r\n const paddedFrame = String(frame + 1).padStart(2, '0');\r\n const fileName = `${paddedIndex}_burst_${sanitizedName}_f${paddedFrame}_${elapsedMs}ms.png`;\r\n const filePath = path.join(this.outputDir, fileName);\r\n\r\n if (options.selector) {\r\n const element = await page.$(options.selector);\r\n if (element) {\r\n await element.screenshot({ path: filePath });\r\n } else {\r\n await page.screenshot({ path: filePath });\r\n }\r\n } else {\r\n await page.screenshot({ path: filePath });\r\n }\r\n\r\n const meta: SnapshotMetadata = {\r\n index: stepIndex,\r\n name: `${name} (frame ${frame + 1}, +${elapsedMs}ms)`,\r\n fileName,\r\n filePath,\r\n relativeUri: `./${fileName}`,\r\n viewport,\r\n timestamp: new Date().toISOString(),\r\n isBurstFrame: true,\r\n burstGroup,\r\n frameIndex: frame + 1,\r\n selector: options.selector\r\n };\r\n\r\n burstSnapshots.push(meta);\r\n this.recordedSnapshots.push(meta);\r\n\r\n if (frame < totalFrames) {\r\n await new Promise((r) => setTimeout(r, interval));\r\n }\r\n }\r\n\r\n return burstSnapshots;\r\n }\r\n}\r\n","import fs from 'fs';\nimport path from 'path';\nimport type { SnapshotMetadata, VisualScenario } from '../../shared/api/dsl';\nimport type { ConsoleEntry } from '../console-tracker/consoleTracker';\n\nexport interface ReportData {\n \n scenario: VisualScenario;\n snapshots: SnapshotMetadata[];\n consoleErrors: ConsoleEntry[];\n consoleWarnings: ConsoleEntry[];\n outputDir: string;\n targetMode: 'desktop' | 'preview';\n durationMs: number;\n}\n\nexport class VisualReporter {\n public static generateReport(data: ReportData): string {\n const {\n scenario,\n snapshots,\n consoleErrors,\n consoleWarnings,\n outputDir,\n targetMode,\n durationMs\n } = data;\n\n const manifestPath = path.join(outputDir, 'manifest.json');\n const reportPath = path.join(outputDir, 'report.md');\n\n const manifest = {\n scenarioId: scenario.id,\n title: scenario.title,\n description: scenario.description,\n targetMode,\n durationMs,\n totalSnapshots: snapshots.length,\n consoleErrors: consoleErrors.length,\n consoleWarnings: consoleWarnings.length,\n createdAt: new Date().toISOString(),\n snapshots,\n errors: consoleErrors,\n warnings: consoleWarnings\n };\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');\n\n const rows: string[] = [];\n \n const regularSnapshots = snapshots.filter((s) => !s.isBurstFrame);\n const burstGroups = new Map<string, SnapshotMetadata[]>();\n\n snapshots.filter((s) => s.isBurstFrame && s.burstGroup).forEach((s) => {\n const list = burstGroups.get(s.burstGroup!) || [];\n list.push(s);\n burstGroups.set(s.burstGroup!, list);\n });\n\n for (const snap of regularSnapshots) {\n const relativeLink = snap.relativeUri || `./${snap.fileName}`;\n rows.push(\n `| **${String(snap.index).padStart(2, '0')}** | \\`${snap.viewport.width}x${snap.viewport.height}\\` | ${snap.name} | [${snap.fileName}](${relativeLink}) |`\n );\n }\n\n let burstSections = '';\n if (burstGroups.size > 0) {\n burstSections += `\\n### šŸŽ¬ Animation Bursts\\n\\n`;\n for (const [group, frames] of burstGroups.entries()) {\n burstSections += `#### Animation: \\`${group}\\` (${frames.length} frames)\\n\\n`;\n burstSections += `| Frame | Viewport | File | Preview |\\n| :--- | :--- | :--- | :--- |\\n`;\n for (const frame of frames) {\n const relativeLink = frame.relativeUri || `./${frame.fileName}`;\n burstSections += `| Frame ${frame.frameIndex} | \\`${frame.viewport.width}x${frame.viewport.height}\\` | [${frame.fileName}](${relativeLink}) | ![](${relativeLink}) |\\n`;\n }\n burstSections += `\\n`;\n }\n }\n \n\n const healthStatus = this.getHealthStatus(consoleErrors, consoleWarnings);\n let consoleSections = '';\n\n if (consoleErrors.length > 0) {\n consoleSections += `\\n## šŸ”“ Console Errors (${consoleErrors.length})\\n\\n`;\n consoleSections += `> [!CAUTION]\\n> Found **${consoleErrors.length}** JavaScript errors during the test. This might indicate broken components, missing data, or unhandled exceptions.\\n\\n`;\n consoleSections += `| # | Time | Error | URL |\\n| :-: | :--- | :--- | :--- |\\n`;\n consoleErrors.forEach((err, i) => {\n const time = err.timestamp.split('T')[1]?.slice(0, 8) || '';\n const text = err.text.replace(/\\|/g, '\\\\|').slice(0, 200);\n const url = err.url.replace(/\\|/g, '\\\\|');\n consoleSections += `| ${i + 1} | \\`${time}\\` | ${text} | \\`${url}\\` |\\n`;\n });\n\n const withStack = consoleErrors.filter(e => e.stack);\n if (withStack.length > 0) {\n consoleSections += `\\n<details>\\n<summary>šŸ“‹ Stack Traces (${withStack.length})</summary>\\n\\n`;\n withStack.forEach((err, i) => {\n consoleSections += `**Error ${i + 1}:** \\`${err.text.slice(0, 100)}\\`\\n\\`\\`\\`\\n${err.stack}\\n\\`\\`\\`\\n\\n`;\n });\n consoleSections += `</details>\\n`;\n }\n }\n\n if (consoleWarnings.length > 0) {\n consoleSections += `\\n## 🟔 Console Warnings (${consoleWarnings.length})\\n\\n`;\n consoleSections += `| # | Warning |\\n| :-: | :--- |\\n`;\n consoleWarnings.slice(0, 20).forEach((warn, i) => {\n const text = warn.text.replace(/\\|/g, '\\\\|').slice(0, 200);\n consoleSections += `| ${i + 1} | ${text} |\\n`;\n });\n if (consoleWarnings.length > 20) {\n consoleSections += `\\n*...and ${consoleWarnings.length - 20} more warnings (full list in manifest.json)*\\n`;\n }\n }\n\n const reportContent = `# šŸ“ø Visual Test Report: ${scenario.title}\n\n> **Scenario ID:** \\`${scenario.id}\\` \n> **Target Mode:** \\`${targetMode.toUpperCase()}\\` (${targetMode === 'desktop' ? 'Native Desktop App / WebView2' : 'Fast Web Preview'}) \n> **Execution Duration:** ${(durationMs / 1000).toFixed(2)} s \n> **Total Snapshots Captured:** ${snapshots.length} \n> **Health Status:** ${healthStatus} \n> **Artifacts Folder:** \\`${outputDir}\\`\n\n---\n\n## šŸ–¼ļø Primary Snapshot Overview\n\n| # | Viewport | Step Description | File Reference |\n| :-: | :--- | :--- | :--- |\n${rows.join('\\n')}\n\n${burstSections}\n${consoleSections}\n---\n\n## šŸ“‹ AI Agent Verification Checklist:\n- [ ] **Console Errors**: ${consoleErrors.length === 0 ? 'āœ… No errors found' : `āŒ ${consoleErrors.length} errors — MUST REVIEW`}\n- [ ] **Visual Layout Check**: Inspect snapshots (e.g. view_image on \\`./01_${regularSnapshots[0]?.fileName || 'quick_snap'}\\`) for layout shifts or clipped elements.\n- [ ] **Responsiveness at \\`1024x768\\`**: Elements do not overflow the screen, no unwanted horizontal scroll.\n \n- [ ] **Typography & Spacing**: Spacing matches the design system and layout grids.\n- [ ] **Color Palette & Theme**: Background tints and button accent colors match the concept.\n- [ ] **Component States**: Modals open centered, dropdowns do not overlap with other layers (z-index).\n- [ ] **Localization**: Verify that there are no raw i18n keys (text with dots like \\`sidebar.home\\` instead of \"Home\").\n\n`;\n\n fs.writeFileSync(reportPath, reportContent, 'utf-8');\n return reportPath;\n }\n\n private static getHealthStatus(errors: ConsoleEntry[], warnings: ConsoleEntry[]): string {\n if (errors.length === 0 && warnings.length === 0) {\n return 'āœ… Healthy — no errors or warnings';\n }\n if (errors.length === 0 && warnings.length > 0) {\n return `āš ļø Warnings (${warnings.length}) — no critical errors`;\n }\n return `āŒ ERRORS (${errors.length} errors, ${warnings.length} warnings) — requires attention`;\n }\n}\n","import type { Page, ConsoleMessage } from 'playwright';\r\n\r\nexport interface ConsoleEntry {\r\n level: 'error' | 'warning' | 'info' | 'log' | 'debug';\r\n text: string;\r\n url: string;\r\n timestamp: string;\r\n stack?: string;\r\n}\r\n\r\nexport class ConsoleTracker {\r\n private entries: ConsoleEntry[] = [];\r\n private attached = false;\r\n\r\n public attach(page: Page): void {\r\n if (this.attached) return;\r\n this.attached = true;\r\n\r\n page.on('console', (msg: ConsoleMessage) => {\r\n const type = msg.type(); // 'log' | 'error' | 'warning' | 'info' | 'debug' | 'trace' | ...\r\n const level = this.mapConsoleType(type);\r\n\r\n const entry: ConsoleEntry = {\r\n level,\r\n text: msg.text(),\r\n url: page.url(),\r\n timestamp: new Date().toISOString()\r\n };\r\n\r\n this.entries.push(entry);\r\n\r\n if (level === 'error') {\r\n console.log(`šŸ”“ [Console ERROR] ${msg.text()}`);\r\n } else if (level === 'warning') {\r\n if (!this.isIgnoredWarning(msg.text())) {\r\n console.log(`🟔 [Console WARN] ${msg.text()}`);\r\n }\r\n }\r\n });\r\n\r\n page.on('pageerror', (error: Error) => {\r\n const entry: ConsoleEntry = {\r\n level: 'error',\r\n text: error.message,\r\n url: page.url(),\r\n timestamp: new Date().toISOString(),\r\n stack: error.stack\r\n };\r\n\r\n this.entries.push(entry);\r\n console.log(`šŸ’„ [Page ERROR] ${error.message}`);\r\n });\r\n }\r\n\r\n public getErrors(): ConsoleEntry[] {\r\n return this.entries.filter(e => e.level === 'error');\r\n }\r\n\r\n public getWarnings(): ConsoleEntry[] {\r\n return this.entries\r\n .filter(e => e.level === 'warning')\r\n .filter(e => !this.isIgnoredWarning(e.text));\r\n }\r\n\r\n public getAll(): ConsoleEntry[] {\r\n return [...this.entries];\r\n }\r\n\r\n public get errorCount(): number {\r\n return this.getErrors().length;\r\n }\r\n\r\n public get warningCount(): number {\r\n return this.getWarnings().length;\r\n }\r\n\r\n public get hasErrors(): boolean {\r\n return this.errorCount > 0;\r\n }\r\n\r\n public clear(): void {\r\n this.entries = [];\r\n }\r\n\r\n\r\n private mapConsoleType(type: string): ConsoleEntry['level'] {\r\n switch (type) {\r\n case 'error': return 'error';\r\n case 'warning': return 'warning';\r\n case 'info': return 'info';\r\n case 'debug': return 'debug';\r\n default: return 'log';\r\n }\r\n }\r\n\r\n\r\n private isIgnoredWarning(text: string): boolean {\r\n const ignoredPatterns = [\r\n 'findDOMNode is deprecated',\r\n // Chromium DevTools\r\n 'DevTools',\r\n // Playwright injection\r\n '__playwright',\r\n '[vite]',\r\n // React 18 hydration warnings\r\n 'Extra attributes from the server',\r\n 'Download the React DevTools',\r\n ];\r\n return ignoredPatterns.some(pattern => text.includes(pattern));\r\n }\r\n}\r\n","import { chromium as baseChromium, type ChromiumBrowser, type BrowserType } from 'playwright';\r\n\r\n/**\r\n * Safe Playwright Chromium loader that wraps browser initialization with helpful diagnostic messages.\r\n */\r\nexport const chromium: BrowserType<ChromiumBrowser> = new Proxy(baseChromium, {\r\n get(target, prop, receiver) {\r\n if (prop === 'launch') {\r\n return async (...args: Parameters<typeof baseChromium.launch>) => {\r\n try {\r\n return await target.launch(...args);\r\n } catch (err: any) {\r\n if (\r\n err.message?.includes(\"Executable doesn't exist\") ||\r\n err.message?.includes('playwright install') ||\r\n err.message?.includes('browser has not been downloaded')\r\n ) {\r\n console.error(\"\\nāŒ [AgentLens] Playwright Chromium browser binary is missing!\");\r\n console.error(\"šŸ‘‰ Please install it by running: npx playwright install chromium\\n\");\r\n }\r\n throw err;\r\n }\r\n };\r\n }\r\n const val = Reflect.get(target, prop, receiver);\r\n return typeof val === 'function' ? val.bind(target) : val;\r\n }\r\n});","import { spawn, type ChildProcess } from 'child_process';\nimport http from 'http';\nimport path from 'path';\nimport fs from 'fs';\nimport type { Browser, BrowserContext, Page } from 'playwright';\nimport { chromium } from '../lib/playwrightLoader';\nimport treeKill from 'tree-kill';\n\nexport interface DesktopDriverOptions {\n \n \n port?: number;\n executablePath?: string;\n autoLaunch?: boolean;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\n\nexport class DesktopDriver {\n private port: number;\n private executablePath?: string;\n private autoLaunch: boolean;\n private args: string[];\n private env: Record<string, string>;\n private cwd?: string;\n\n private childProcess: ChildProcess | null = null;\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private processStderr: string = '';\n private processExited: boolean = false;\n private exitCode: number | null = null;\n\n constructor(options?: DesktopDriverOptions) {\n this.port = options?.port || 9222;\n this.autoLaunch = options?.autoLaunch ?? true;\n this.executablePath = options?.executablePath;\n this.args = options?.args || [];\n this.env = options?.env || {};\n this.cwd = options?.cwd;\n }\n\n private async isPortAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {\n resolve(res.statusCode === 200);\n });\n req.on('error', () => resolve(false));\n req.setTimeout(800, () => {\n req.destroy();\n resolve(false);\n });\n });\n }\n\n private async waitForPort(timeoutMs: number = 25000): Promise<void> {\n const startTime = Date.now();\n while (Date.now() - startTime < timeoutMs) {\n if (this.processExited) {\n throw new Error(\n `[DesktopDriver] Process terminated prematurely with exit code ${this.exitCode}.\\nStderr: ${this.processStderr.trim() || '(none)'}`\n );\n }\n\n if (await this.isPortAvailable()) {\n return;\n }\n await new Promise((r) => setTimeout(r, 400));\n }\n throw new Error(\n `Timeout waiting for WebView2/Chromium CDP port ${this.port}. Last stderr:\\n${this.processStderr.trim() || '(no stderr output)'}`\n );\n }\n\n public async start(initialViewport = { width: 1200, height: 800 }): Promise<{ page: Page; context: BrowserContext; browser: Browser }> {\n const alreadyRunning = await this.isPortAvailable();\n\n if (!alreadyRunning) {\n if (!this.autoLaunch) {\n throw new Error(\n `App is not running on port ${this.port} and autoLaunch is false. Start app with WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=${this.port}`\n );\n }\n\n if (!this.executablePath) {\n throw new Error(\n `[DesktopDriver] No executablePath provided and nothing is running on port ${this.port}. Specify --exe=<path> in CLI or executablePath in config.`\n );\n }\n\n const resolvedExe = path.resolve(process.cwd(), this.executablePath);\n if (!fs.existsSync(resolvedExe)) {\n throw new Error(\n `[DesktopDriver] Desktop executable not found at: ${resolvedExe}. Please build your native project first.`\n );\n }\n\n console.log(`[DesktopDriver] Launching: ${resolvedExe}`);\n \n // Ensure remote debugging port is passed as CLI flag for Electron / Chromium binaries\n const finalArgs = [...this.args];\n const hasDebugPort = finalArgs.some((a) => a.startsWith('--remote-debugging-port='));\n if (!hasDebugPort) {\n finalArgs.push(`--remote-debugging-port=${this.port}`);\n }\n\n // Also set WebView2 environment variable for .NET / Photino Windows apps\n const mergedEnv = {\n ...process.env,\n ...this.env,\n WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: `--remote-debugging-port=${this.port}`\n };\n\n this.processStderr = '';\n this.processExited = false;\n this.exitCode = null;\n\n this.childProcess = spawn(resolvedExe, finalArgs, {\n env: mergedEnv,\n cwd: this.cwd || path.dirname(resolvedExe),\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: false\n });\n ;\n\n this.processStderr = '';\n this.processExited = false;\n this.exitCode = null;\n\n this.childProcess = spawn(resolvedExe, this.args, {\n env: mergedEnv,\n cwd: this.cwd || path.dirname(resolvedExe),\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: false\n });\n\n this.childProcess.stderr?.on('data', (chunk) => {\n this.processStderr += chunk.toString();\n });\n\n this.childProcess.on('exit', (code) => {\n this.processExited = true;\n this.exitCode = code;\n });\n\n this.childProcess.on('error', (err) => {\n console.error('[DesktopDriver] Failed to spawn process:', err);\n });\n\n console.log(`[DesktopDriver] Waiting for CDP debugging port on ${this.port}...`);\n await this.waitForPort();\n } else {\n console.log(`[DesktopDriver] Attached to already running process on port ${this.port}`);\n }\n\n console.log(`[DesktopDriver] Connecting Playwright CDP to http://127.0.0.1:${this.port}...`);\n this.browser = await chromium.connectOverCDP(`http://127.0.0.1:${this.port}`);\n \n const contexts = this.browser.contexts();\n this.context = contexts[0] || (await this.browser.newContext());\n\n const pages = this.context.pages();\n if (pages.length > 0) {\n this.page = pages[0];\n } else {\n this.page = await this.context.waitForEvent('page', { timeout: 10000 });\n }\n\n if (initialViewport) {\n await this.page.setViewportSize(initialViewport).catch(() => {});\n }\n\n return { page: this.page, context: this.context, browser: this.browser };\n }\n\n public async stop(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n this.browser = null;\n }\n\n if (this.childProcess && !this.childProcess.killed && this.childProcess.pid) {\n console.log('[DesktopDriver] Terminating spawned desktop process tree...');\n const pid = this.childProcess.pid;\n await new Promise<void>((resolve) => {\n treeKill(pid, 'SIGTERM', () => resolve());\n });\n this.childProcess = null;\n }\n \n }\n}\n","/**\n * Generic Mock IPC Registry for Preview Mode\n * \n * Injects a global `window.__mockIpc` that web apps or mocked electron/tauri APIs can call.\n */\n\nexport type MockIpcResponseType = 'SUCCESS' | 'ERROR';\n\nexport interface MockIpcEntry {\n action: string;\n data: any;\n type?: MockIpcResponseType;\n delayMs?: number;\n}\n\nexport class MockIpcRegistry {\n private mocks = new Map<string, MockIpcEntry>();\n\n public set(action: string, data: any, options?: { type?: MockIpcResponseType; delayMs?: number }): void {\n this.mocks.set(action, {\n action,\n data,\n type: options?.type ?? 'SUCCESS',\n delayMs: options?.delayMs ?? 20\n });\n }\n\n public setBatch(entries: Array<{ action: string; data: any; type?: MockIpcResponseType; delayMs?: number }>): void {\n for (const entry of entries) {\n this.set(entry.action, entry.data, { type: entry.type, delayMs: entry.delayMs });\n }\n }\n\n public remove(action: string): void {\n this.mocks.delete(action);\n }\n\n public clear(): void {\n this.mocks.clear();\n }\n\n public get(action: string): MockIpcEntry | null {\n return this.mocks.get(action) ?? null;\n }\n\n public toSerializable(): Record<string, { data: any; type: string; delayMs: number }> {\n const result: Record<string, { data: any; type: string; delayMs: number }> = {};\n for (const [action, entry] of this.mocks.entries()) {\n result[action] = {\n data: entry.data,\n type: entry.type ?? 'SUCCESS',\n delayMs: entry.delayMs ?? 20\n };\n }\n return result;\n }\n\n public get size(): number {\n return this.mocks.size;\n }\n}\n\nexport function generateMockIpcScript(registry: MockIpcRegistry): string {\n const mocksJson = JSON.stringify(registry.toSerializable());\n\n return `\n (() => {\n const __mockTable = ${mocksJson};\n\n window.__visualRunnerMocks = __mockTable;\n\n // Generic IPC mock bridge for modern web applications\n window.__mockIpc = {\n invoke: (action, payload) => {\n return new Promise((resolve, reject) => {\n const mock = window.__visualRunnerMocks[action];\n\n if (mock) {\n setTimeout(() => {\n if (mock.type === 'ERROR') {\n reject(new Error(mock.data));\n } else {\n resolve(mock.data);\n }\n }, mock.delayMs || 20);\n } else {\n console.warn('[Mock IPC] No mock for action:', action, '— returning empty SUCCESS');\n setTimeout(() => resolve(null), 20);\n }\n });\n }\n };\n\n // Safe fallback bridge for hybrid webviews (Photino / CEF / WebView2)\n try {\n if (!window.external) {\n (window as any).external = {};\n }\n (window.external as any).sendMessage = (msg) => {\n try {\n const parsed = typeof msg === 'string' ? JSON.parse(msg) : msg;\n const action = parsed.Action || parsed.action;\n const id = parsed.Id || parsed.id;\n const mock = (window as any).__visualRunnerMocks[action];\n\n if (mock) {\n const response = { Id: id, Type: mock.type || 'SUCCESS', Data: mock.data };\n setTimeout(() => {\n const cb = (window as any).__mockCallback;\n if (typeof cb === 'function') cb(JSON.stringify(response));\n }, mock.delayMs || 20);\n } else {\n setTimeout(() => {\n const cb = (window as any).__mockCallback;\n if (typeof cb === 'function') cb(JSON.stringify({ Id: id, Type: 'SUCCESS', Data: null }));\n }, 20);\n }\n } catch (e) {\n console.error('[Mock IPC] Failed to process message:', e);\n }\n };\n\n (window.external as any).receiveMessage = (callback) => {\n (window as any).__mockCallback = callback;\n };\n } catch {\n // Ignored if window.external is read-only in strict Chromium sandboxes\n }\n\n console.log('[Visual Runner] Mock IPC bridge initialized with', Object.keys((window as any).__visualRunnerMocks).length, 'mocked actions');\n })();\n \n `;\n}\n","import path from 'path';\nimport fs from 'fs';\n\nexport interface AgentLensConfigFile {\n mode?: 'desktop' | 'preview';\n port?: number;\n headed?: boolean;\n detach?: boolean;\n buildCommand?: string;\n autoBuild?: boolean;\n startCommand?: string;\n startCwd?: string;\n cleanArtifacts?: boolean;\n url?: string;\n executablePath?: string;\n clean?: string | string[];\n scenarios?: string;\n wwwroot?: string;\n outDir?: string;\n env?: Record<string, string>;\n}\n\nexport function loadConfig(cwd: string = process.cwd()): AgentLensConfigFile {\n const jsonConfigPath = path.join(cwd, 'agent-lens.json');\n if (fs.existsSync(jsonConfigPath)) {\n try {\n const raw = fs.readFileSync(jsonConfigPath, 'utf-8');\n return JSON.parse(raw);\n } catch (e: any) {\n console.warn(`āš ļø [Config] Failed to parse agent-lens.json: ${e.message}`);\n }\n }\n\n const packageJsonPath = path.join(cwd, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n try {\n const raw = fs.readFileSync(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(raw);\n if (pkg.agentLens && typeof pkg.agentLens === 'object') {\n return pkg.agentLens;\n }\n } catch {\n // ignore\n }\n }\n\n return {};\n}\n\nexport function detectStartCwd(providedCwd?: string): string | undefined {\n if (providedCwd) {\n const resolved = path.resolve(process.cwd(), providedCwd);\n if (fs.existsSync(resolved)) {\n return providedCwd;\n }\n }\n\n const rootPkgPath = path.join(process.cwd(), 'package.json');\n let rootHasDevScript = false;\n if (fs.existsSync(rootPkgPath)) {\n try {\n const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'));\n rootHasDevScript = Boolean(rootPkg.scripts?.dev || rootPkg.scripts?.start);\n } catch {\n // ignore\n }\n }\n\n if (rootHasDevScript) {\n return undefined;\n }\n\n const candidates = ['Frontend', 'frontend', 'client', 'web', 'ui', 'apps/web', 'src/frontend'];\n for (const candidate of candidates) {\n const candidatePkg = path.join(process.cwd(), candidate, 'package.json');\n if (fs.existsSync(candidatePkg)) {\n return `./${candidate}`;\n }\n }\n\n return undefined;\n}\n\nexport function resolveWwwrootDir(customDir?: string): string {\n if (customDir) {\n return path.resolve(process.cwd(), customDir);\n }\n\n const candidates = [\n 'dist',\n 'build',\n 'out',\n 'wwwroot',\n 'Frontend/dist',\n 'frontend/dist',\n 'client/dist'\n ];\n\n for (const c of candidates) {\n const candidatePath = path.resolve(process.cwd(), c);\n if (fs.existsSync(candidatePath) && fs.existsSync(path.join(candidatePath, 'index.html'))) {\n return candidatePath;\n }\n }\n\n for (const c of candidates) {\n const candidatePath = path.resolve(process.cwd(), c);\n if (fs.existsSync(candidatePath)) {\n return candidatePath;\n }\n }\n\n return path.resolve(process.cwd(), 'dist');\n}","import http from 'http';\nimport fs from 'fs';\nimport path from 'path';\nimport type { Browser, BrowserContext, Page } from 'playwright';\nimport { chromium } from '../lib/playwrightLoader';\nimport { MockIpcRegistry, generateMockIpcScript } from '../../features/mock-ipc/mockIpc';\nimport type { MockRouteEntry } from '../api/dsl';\nimport { resolveWwwrootDir } from '../lib/config';\n \n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf'\n};\n\nexport interface PreviewDriverOptions {\n wwwrootDir?: string;\n headed?: boolean;\n url?: string;\n}\n\nexport class PreviewDriver {\n private server: http.Server | null = null;\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private serverPort: number = 0;\n private options: PreviewDriverOptions;\n private _baseUrl: string = '';\n private initialRouteMocks: MockRouteEntry[] = [];\n\n public readonly mockRegistry: MockIpcRegistry;\n \n\n constructor(options?: PreviewDriverOptions) {\n this.options = options || {};\n if (!this.options.url) {\n this.options.wwwrootDir = resolveWwwrootDir(this.options.wwwrootDir);\n }\n this.mockRegistry = new MockIpcRegistry();\n }\n\n public get baseUrl(): string {\n return this._baseUrl;\n }\n\n public async start(initialViewport = { width: 1200, height: 800 }): Promise<{ page: Page; context: BrowserContext; browser: Browser }> {\n let targetUrl = this.options.url;\n\n if (!targetUrl) {\n if (!fs.existsSync(this.options.wwwrootDir!)) {\n throw new Error(`Directory not found at: ${this.options.wwwrootDir}. Please build your frontend project first or pass --url=<url>.`);\n }\n\n await new Promise<void>((resolve, reject) => {\n this.server = http.createServer((req, res) => {\n let reqUrl = req.url?.split('?')[0] || '/';\n if (reqUrl === '/') reqUrl = '/index.html';\n\n let safePath = path.normalize(path.join(this.options.wwwrootDir!, reqUrl));\n if (!safePath.startsWith(this.options.wwwrootDir!)) {\n res.writeHead(403);\n return res.end('Forbidden');\n }\n\n if (!fs.existsSync(safePath) || fs.statSync(safePath).isDirectory()) {\n // SPA fallback to index.html\n safePath = path.join(this.options.wwwrootDir!, 'index.html');\n }\n\n const ext = path.extname(safePath).toLowerCase();\n const contentType = MIME_TYPES[ext] || 'application/octet-stream';\n\n try {\n const content = fs.readFileSync(safePath);\n res.writeHead(200, { 'Content-Type': contentType });\n res.end(content);\n } catch (e: any) {\n res.writeHead(500);\n res.end(`Server error: ${e.message}`);\n }\n });\n\n this.server.listen(0, '127.0.0.1', () => {\n const addr = this.server?.address();\n if (typeof addr === 'object' && addr?.port) {\n this.serverPort = addr.port;\n this._baseUrl = `http://127.0.0.1:${this.serverPort}`;\n resolve();\n } else {\n reject(new Error('Failed to acquire port for static preview server'));\n }\n });\n });\n\n targetUrl = `${this._baseUrl}/index.html`;\n } else {\n this._baseUrl = targetUrl;\n console.log(`🌐 [PreviewDriver] Connecting directly to live URL: ${targetUrl}`);\n }\n\n this.browser = await chromium.launch({\n headless: !this.options.headed,\n args: ['--no-sandbox', '--disable-setuid-sandbox']\n });\n\n this.context = await this.browser.newContext({\n viewport: initialViewport,\n deviceScaleFactor: 1\n });\n\n if (this.mockRegistry.size > 0) {\n const mockScript = generateMockIpcScript(this.mockRegistry);\n await this.context.addInitScript(mockScript);\n }\n\n this.page = await this.context.newPage();\n\n if (this.initialRouteMocks.length > 0) {\n for (const entry of this.initialRouteMocks) {\n await this.addRouteMock(entry);\n }\n }\n\n await this.page.goto(targetUrl, { waitUntil: 'domcontentloaded' });\n\n return { page: this.page, context: this.context, browser: this.browser };\n }\n\n public async addRouteMock(entry: MockRouteEntry): Promise<void> {\n if (!this.page) {\n this.initialRouteMocks.push(entry);\n return;\n }\n\n await this.page.route(entry.url, async (route) => {\n const req = route.request();\n if (entry.method && req.method().toUpperCase() !== entry.method.toUpperCase()) {\n return route.continue();\n }\n\n if (entry.delayMs) {\n await new Promise((r) => setTimeout(r, entry.delayMs));\n }\n\n const isJson = typeof entry.body === 'object' && entry.body !== null;\n await route.fulfill({\n status: entry.status ?? 200,\n contentType: isJson ? 'application/json' : 'text/plain; charset=utf-8',\n body: isJson ? JSON.stringify(entry.body) : String(entry.body ?? ''),\n headers: entry.headers\n });\n });\n }\n\n public async setupRouteMocks(routes: MockRouteEntry[]): Promise<void> {\n for (const r of routes) {\n await this.addRouteMock(r);\n }\n }\n \n\n public async updateMockIpc(action: string, data: any, options?: { type?: string; delayMs?: number }): Promise<void> {\n if (!this.page) {\n throw new Error('PreviewDriver not started. Call start() first.');\n }\n\n this.mockRegistry.set(action, data, options as any);\n\n await this.page.evaluate(\n ({ action, mock }) => {\n if (!(window as any).__visualRunnerMocks) {\n (window as any).__visualRunnerMocks = {};\n }\n (window as any).__visualRunnerMocks[action] = mock;\n },\n {\n action,\n mock: {\n data,\n type: options?.type ?? 'SUCCESS',\n delayMs: options?.delayMs ?? 20\n }\n }\n );\n }\n\n public async stop(): Promise<void> {\n if (this.context) {\n await this.context.close().catch(() => {});\n this.context = null;\n }\n if (this.browser) {\n await this.browser.close().catch(() => {});\n this.browser = null;\n }\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server?.close(() => resolve());\n });\n this.server = null;\n }\n }\n}\n","import { spawn, type ChildProcess } from 'child_process';\nimport treeKill from 'tree-kill';\n\nexport interface ProcessStartOptions {\n \n cwd?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nexport class ProcessManager {\n private childProcess: ChildProcess | null = null;\n private isStopped = false;\n\n public async start(command: string, options?: ProcessStartOptions): Promise<void> {\n const cwd = options?.cwd || process.cwd();\n console.log(`šŸš€ [ProcessManager] Starting command: \"${command}\" in ${cwd}`);\n\n this.childProcess = spawn(command, {\n cwd,\n env: { ...process.env, ...options?.env },\n shell: true,\n stdio: ['ignore', 'pipe', 'pipe']\n });\n\n this.childProcess.stdout?.on('data', (chunk) => {\n const line = chunk.toString().trim();\n if (line) {\n // Subprocess stdout output handled silently unless needed\n }\n });\n\n this.childProcess.stderr?.on('data', (chunk) => {\n const line = chunk.toString().trim();\n if (line && !line.includes('ExperimentalWarning')) {\n // Forward warning if necessary\n }\n });\n\n this.childProcess.on('exit', (code, signal) => {\n if (!this.isStopped && code !== 0 && code !== null) {\n console.warn(`āš ļø [ProcessManager] Subprocess exited prematurely with code ${code}, signal ${signal}`);\n }\n });\n }\n\n public async waitForUrl(url: string, timeoutMs = 30000): Promise<boolean> {\n console.log(`ā³ [ProcessManager] Waiting for ${url} to respond...`);\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n if (this.childProcess && this.childProcess.exitCode !== null) {\n throw new Error(\n `[ProcessManager] Server process exited with code ${this.childProcess.exitCode} while waiting for ${url}`\n );\n }\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(1000) });\n if (response.status) {\n console.log(`āœ… [ProcessManager] Target ${url} is ready (status: ${response.status})!`);\n return true;\n }\n } catch {\n // Retry on connection refused or timeout\n }\n\n await new Promise((r) => setTimeout(r, 500));\n }\n\n throw new Error(`[ProcessManager] Timeout after ${timeoutMs}ms waiting for ${url} to respond.`);\n }\n\n public async stop(): Promise<void> {\n if (this.isStopped || !this.childProcess || !this.childProcess.pid) {\n return;\n }\n\n this.isStopped = true;\n const pid = this.childProcess.pid;\n console.log(`šŸ›‘ [ProcessManager] Terminating process tree for PID ${pid}...`);\n\n await new Promise<void>((resolve) => {\n treeKill(pid, 'SIGTERM', (err) => {\n if (err) {\n try {\n treeKill(pid, 'SIGKILL');\n } catch {\n // ignore\n }\n }\n resolve();\n });\n });\n\n this.childProcess = null;\n }\n}","import path from 'path';\r\nimport fs from 'fs';\r\nimport type { Page, BrowserContext } from 'playwright';\r\nimport {\r\n type VisualScenario,\r\n type TestContext,\r\n type ViewportPreset,\r\n VIEWPORT_PRESETS,\r\n type CaptureOptions,\r\n type CaptureBurstOptions\r\n} from '../../shared/api/dsl';\r\nimport { CaptureEngine } from '../capture/capture';\r\nimport { VisualReporter } from '../reporter/reporter';\r\nimport { ConsoleTracker } from '../console-tracker/consoleTracker';\r\nimport { DesktopDriver } from '../../shared/drivers/desktopDriver';\r\nimport { PreviewDriver } from '../../shared/drivers/previewDriver';\r\nimport { ProcessManager } from '../../shared/lib/processManager';\r\n\r\nexport interface RunOptions {\r\n scenario: VisualScenario;\r\n targetMode?: 'desktop' | 'preview';\r\n artifactsRoot?: string;\r\n autoLaunchDesktop?: boolean;\r\n port?: number;\r\n wwwrootDir?: string;\r\n executablePath?: string;\r\n desktopArgs?: string[];\r\n desktopEnv?: Record<string, string>;\r\n cleanPaths?: string[];\r\n url?: string;\r\n startCommand?: string;\r\n startCwd?: string;\r\n cleanArtifacts?: boolean;\r\n headed?: boolean;\r\n detach?: boolean;\r\n globalMocks?: any[];\r\n}\r\n\r\nexport interface RunResult {\r\n scenarioId: string;\r\n targetMode: 'desktop' | 'preview';\r\n success: boolean;\r\n totalSnapshots: number;\r\n consoleErrors: number;\r\n consoleWarnings: number;\r\n reportPath: string;\r\n artifactsDir: string;\r\n error?: string;\r\n}\r\n\r\nexport async function runVisualScenario(options: RunOptions): Promise<RunResult> {\r\n const { scenario } = options;\r\n const targetMode = options.targetMode || 'preview';\r\n const startTime = Date.now();\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\r\n const artifactsRoot = options.artifactsRoot || path.resolve(process.cwd(), 'artifacts');\r\n\r\n if (options.cleanArtifacts && fs.existsSync(artifactsRoot)) {\r\n console.log(`🧹 [Clean Artifacts] Purging previous artifact runs in ${artifactsRoot}...`);\r\n const entries = fs.readdirSync(artifactsRoot, { withFileTypes: true });\r\n for (const entry of entries) {\r\n fs.rmSync(path.join(artifactsRoot, entry.name), { recursive: true, force: true });\r\n }\r\n }\r\n\r\n const scenarioArtifactsDir = path.join(artifactsRoot, `${scenario.id}_${timestamp}`);\r\n \r\n if (!fs.existsSync(scenarioArtifactsDir)) {\r\n fs.mkdirSync(scenarioArtifactsDir, { recursive: true });\r\n }\r\n\r\n const captureEngine = new CaptureEngine(scenarioArtifactsDir);\r\n const consoleTracker = new ConsoleTracker();\r\n const defaultViewport = scenario.viewports?.[0] || VIEWPORT_PRESETS.DEFAULT;\r\n let currentViewport = { width: defaultViewport.width, height: defaultViewport.height };\r\n\r\n let desktopDriver: DesktopDriver | null = null;\r\n let previewDriver: PreviewDriver | null = null;\r\n let processManager: ProcessManager | null = null;\r\n\r\n try {\r\n let page: Page;\r\n let context: BrowserContext;\r\n\r\n console.log(`\\n========================================`);\r\n console.log(`šŸš€ Starting Visual Test: ${scenario.title}`);\r\n console.log(`šŸŽÆ Mode: ${targetMode.toUpperCase()}`);\r\n console.log(`šŸ“ Artifacts: ${scenarioArtifactsDir}`);\r\n console.log(`========================================\\n`);\r\n\r\n if (options.startCommand) {\r\n processManager = new ProcessManager();\r\n await processManager.start(options.startCommand, { cwd: options.startCwd });\r\n const waitTarget = options.url || 'http://localhost:5173';\r\n await processManager.waitForUrl(waitTarget);\r\n }\r\n\r\n if (typeof scenario.setup === 'function') {\r\n console.log(`šŸ”§ [Scenario Setup] Executing setup hook...`);\r\n await scenario.setup();\r\n }\r\n\r\n if (targetMode === 'desktop') {\r\n desktopDriver = new DesktopDriver({\r\n port: options.port || 9222,\r\n autoLaunch: options.autoLaunchDesktop ?? true,\r\n executablePath: options.executablePath,\r\n args: options.desktopArgs,\r\n env: options.desktopEnv\r\n });\r\n const res = await desktopDriver.start(currentViewport);\r\n page = res.page;\r\n context = res.context;\r\n } else {\r\n previewDriver = new PreviewDriver({\r\n wwwrootDir: options.wwwrootDir,\r\n url: options.url,\r\n headed: options.headed\r\n });\r\n\r\n // Apply declarative mockIpc from scenario and global mocks before start\r\n const mergedMocks = [...(options.globalMocks || []), ...(scenario.mockIpc || [])];\r\n if (mergedMocks.length > 0) {\r\n console.log(`šŸ“¦ [Mock IPC] Applying ${mergedMocks.length} mocks`);\r\n previewDriver.mockRegistry.setBatch(mergedMocks);\r\n }\r\n\r\n if (scenario.mockRoutes && scenario.mockRoutes.length > 0) {\r\n console.log(`🌐 [Mock Network] Queuing ${scenario.mockRoutes.length} route mock(s)`);\r\n await previewDriver.setupRouteMocks(scenario.mockRoutes);\r\n }\r\n\r\n const res = await previewDriver.start(currentViewport);\r\n page = res.page;\r\n context = res.context;\r\n\r\n if (scenario.mockRoutes && scenario.mockRoutes.length > 0) {\r\n await previewDriver.setupRouteMocks(scenario.mockRoutes);\r\n }\r\n }\r\n \r\n\r\n // Attach console error interception\r\n consoleTracker.attach(page);\r\n console.log(`šŸ” [Console Tracker] Attached — errors and warnings will be captured\\n`);\r\n\r\n // Internal navigation function supporting live URLs and hash routing\r\n const doNavigate = async (route: string) => {\r\n if (route.startsWith('http://') || route.startsWith('https://')) {\r\n await page.goto(route, { waitUntil: 'domcontentloaded' });\r\n await page.waitForTimeout(300);\r\n return;\r\n }\r\n if (route.startsWith('#')) {\r\n await page.evaluate((r) => { window.location.hash = r; }, route);\r\n await page.waitForTimeout(300);\r\n return;\r\n }\r\n if (previewDriver?.baseUrl && options.url) {\r\n try {\r\n const fullUrl = new URL(route, previewDriver.baseUrl).toString();\r\n await page.goto(fullUrl, { waitUntil: 'domcontentloaded' });\r\n await page.waitForTimeout(300);\r\n return;\r\n } catch {\r\n // fallback to hash\r\n }\r\n }\r\n const routePath = route.startsWith('/') ? route : `/${route}`;\r\n await page.evaluate((r) => {\r\n if (window.location.hash !== undefined) {\r\n window.location.hash = r;\r\n }\r\n }, routePath);\r\n await page.waitForTimeout(300);\r\n };\r\n\r\n if (scenario.route) {\r\n console.log(`[Runner] Navigating to route: ${scenario.route}`);\r\n await doNavigate(scenario.route);\r\n }\r\n\r\n const ctx: TestContext = {\r\n page,\r\n context,\r\n targetMode,\r\n currentViewport,\r\n\r\n\r\n capture: async (name: string, opts?: CaptureOptions) => {\r\n console.log(`šŸ“ø [Snapshot] ${name} (${currentViewport.width}x${currentViewport.height})`);\r\n return await captureEngine.takeSnapshot(page, name, currentViewport, opts);\r\n },\r\n\r\n captureBurst: async (name: string, opts: CaptureBurstOptions) => {\r\n console.log(`šŸŽ¬ [Burst] ${name} (duration: ${opts.durationMs}ms, interval: ${opts.intervalMs ?? 80}ms)`);\r\n return await captureEngine.takeBurst(page, name, currentViewport, opts);\r\n },\r\n\r\n\r\n navigate: async (route: string) => {\r\n console.log(`🧭 [Navigate] ${route}`);\r\n await doNavigate(route);\r\n },\r\n\r\n // ─── Viewport ───\r\n\r\n resize: async (width: number, height: number) => {\r\n console.log(`šŸ“ [Resize] ${width}x${height}`);\r\n currentViewport = { width, height };\r\n ctx.currentViewport = currentViewport;\r\n await page.setViewportSize(currentViewport);\r\n await page.waitForTimeout(200);\r\n },\r\n\r\n setPreset: async (preset: ViewportPreset) => {\r\n console.log(`šŸ“ [Preset] ${preset.name} (${preset.width}x${preset.height})`);\r\n await ctx.resize(preset.width, preset.height);\r\n },\r\n\r\n resizeToFit: async (selector?: string, padding = 0) => {\r\n let boundingBox;\r\n if (selector) {\r\n const el = await page.$(selector);\r\n if (el) {\r\n boundingBox = await el.boundingBox();\r\n }\r\n } else {\r\n boundingBox = await page.evaluate(() => {\r\n return {\r\n width: document.documentElement.scrollWidth,\r\n height: document.documentElement.scrollHeight\r\n };\r\n });\r\n }\r\n\r\n if (boundingBox) {\r\n const newWidth = Math.ceil(boundingBox.width) + padding * 2;\r\n const newHeight = Math.ceil(boundingBox.height) + padding * 2;\r\n console.log(`šŸ“ [ResizeToFit] ${selector || 'body'} -> ${newWidth}x${newHeight}`);\r\n await ctx.resize(newWidth, newHeight);\r\n } else {\r\n console.log(`āš ļø [ResizeToFit] Element ${selector} not found or has no bounding box.`);\r\n }\r\n },\r\n\r\n\r\n wait: async (ms: number) => {\r\n await page.waitForTimeout(ms);\r\n },\r\n\r\n waitForSelector: async (selector: string, timeoutMs = 5000) => {\r\n await page.waitForSelector(selector, { timeout: timeoutMs });\r\n },\r\n\r\n\r\n click: async (selector: string) => {\r\n console.log(`šŸ–±ļø [Click] ${selector}`);\r\n await page.click(selector);\r\n },\r\n \r\n rightClick: async (selector: string) => {\r\n console.log(`šŸ–±ļø [RightClick] ${selector}`);\r\n await page.click(selector, { button: 'right' });\r\n },\r\n\r\n type: async (selector: string, text: string) => {\r\n console.log(`āŒØļø [Type] ${selector} -> \"${text}\"`);\r\n await page.fill(selector, text);\r\n },\r\n \r\n selectOption: async (selector: string, value: string) => {\r\n console.log(`āœ… [Select] ${selector} -> \"${value}\"`);\r\n await page.selectOption(selector, value);\r\n },\r\n\r\n hover: async (selector: string) => {\r\n console.log(`šŸ‘† [Hover] ${selector}`);\r\n await page.hover(selector);\r\n },\r\n \r\n scroll: async (selector: string, deltaY: number) => {\r\n console.log(`šŸ“œ [Scroll] ${selector} by ${deltaY}px`);\r\n await page.evaluate(({ sel, dY }) => {\r\n const el = document.querySelector(sel);\r\n if (el) {\r\n el.scrollTop += dY;\r\n } else {\r\n window.scrollBy(0, dY);\r\n }\r\n }, { sel: selector, dY: deltaY });\r\n await page.waitForTimeout(100);\r\n },\r\n\r\n\r\n log: (msg: string) => {\r\n console.log(`ā„¹ļø [Scenario] ${msg}`);\r\n },\r\n\r\n // ─── Mock IPC ───\r\n\r\n setMockIpc: async (action: string, data: any, mockOptions?) => {\r\n if (targetMode === 'desktop') {\r\n console.log(`āš ļø [Mock IPC] setMockIpc ignored in desktop mode (real backend handles IPC)`);\r\n return;\r\n }\r\n if (!previewDriver) {\r\n console.log(`āš ļø [Mock IPC] PreviewDriver not available`);\r\n return;\r\n }\r\n console.log(`šŸ“¦ [Mock IPC] Set ${action} -> ${typeof data === 'string' ? data : JSON.stringify(data).slice(0, 80)}...`);\r\n await previewDriver.updateMockIpc(action, data, mockOptions);\r\n },\r\n\r\n setMockRoute: async (url: string, body: any, routeOptions?) => {\r\n if (targetMode === 'desktop') {\r\n console.log(`āš ļø [Mock Route] setMockRoute ignored in desktop mode`);\r\n return;\r\n }\r\n if (!previewDriver) {\r\n console.log(`āš ļø [Mock Route] PreviewDriver not available`);\r\n return;\r\n }\r\n console.log(`🌐 [Mock Route] Intercepting ${routeOptions?.method || 'ALL'} ${url} -> ${routeOptions?.status ?? 200}`);\r\n await previewDriver.addRouteMock({\r\n url,\r\n body,\r\n method: routeOptions?.method,\r\n status: routeOptions?.status,\r\n delayMs: routeOptions?.delayMs,\r\n headers: routeOptions?.headers\r\n });\r\n },\r\n\r\n\r\n getConsoleErrors: () => consoleTracker.getErrors(),\r\n \r\n getConsoleWarnings: () => consoleTracker.getWarnings(),\r\n hasConsoleErrors: () => consoleTracker.hasErrors,\r\n\r\n // ─── DOM Assertions ───\r\n\r\n readText: async (selector: string): Promise<string | null> => {\r\n const text = await page.textContent(selector);\r\n return text ? text.trim() : null;\r\n },\r\n \r\n getPageText: async (): Promise<string> => {\r\n return await page.evaluate(() => document.body.innerText || '');\r\n },\r\n\r\n isVisible: async (selector: string) => {\r\n try {\r\n const element = await page.$(selector);\r\n if (!element) return false;\r\n return await element.isVisible();\r\n } catch {\r\n return false;\r\n }\r\n },\r\n\r\n getElementCount: async (selector: string) => {\r\n const elements = await page.$$(selector);\r\n return elements.length;\r\n }\r\n };\r\n\r\n await scenario.run(ctx);\r\n\r\n const durationMs = Date.now() - startTime;\r\n const snapshots = captureEngine.getSnapshots();\r\n const consoleErrors = consoleTracker.getErrors();\r\n const consoleWarnings = consoleTracker.getWarnings();\r\n\r\n if (consoleErrors.length > 0) {\r\n console.log(`\\nšŸ”“ Console Errors: ${consoleErrors.length}`);\r\n consoleErrors.forEach((err, i) => console.log(` ${i + 1}. ${err.text.slice(0, 120)}`));\r\n }\r\n if (consoleWarnings.length > 0) {\r\n console.log(`\\n🟔 Console Warnings: ${consoleWarnings.length}`);\r\n }\r\n\r\n const reportPath = VisualReporter.generateReport({\r\n scenario,\r\n snapshots,\r\n consoleErrors,\r\n consoleWarnings,\r\n outputDir: scenarioArtifactsDir,\r\n targetMode,\r\n durationMs\r\n });\r\n\r\n const syncLatest = (repPath: string, snaps: any[]) => {\r\n try {\r\n const latestDir = path.join(artifactsRoot, 'latest');\r\n if (fs.existsSync(latestDir)) {\r\n fs.rmSync(latestDir, { recursive: true, force: true });\r\n }\r\n fs.mkdirSync(latestDir, { recursive: true });\r\n fs.copyFileSync(repPath, path.join(latestDir, 'report.md'));\r\n const manifestSrc = path.join(scenarioArtifactsDir, 'manifest.json');\r\n if (fs.existsSync(manifestSrc)) {\r\n fs.copyFileSync(manifestSrc, path.join(latestDir, 'manifest.json'));\r\n }\r\n for (const snap of snaps) {\r\n if (snap.filePath && fs.existsSync(snap.filePath)) {\r\n fs.copyFileSync(snap.filePath, path.join(latestDir, snap.fileName));\r\n }\r\n }\r\n return path.join(latestDir, 'report.md');\r\n } catch {\r\n return undefined;\r\n }\r\n };\r\n\r\n const latestReport = syncLatest(reportPath, snapshots);\r\n\r\n console.log(`\\nāœ… Visual Test Completed Successfully!`);\r\n console.log(`šŸ“Š Captured Snapshots: ${snapshots.length}`);\r\n console.log(`šŸ”“ Console Errors: ${consoleErrors.length}`);\r\n console.log(`🟔 Console Warnings: ${consoleWarnings.length}`);\r\n console.log(`šŸ“„ Markdown Report: ${reportPath}`);\r\n if (latestReport) {\r\n console.log(`šŸ“Œ Latest Report: ${latestReport}`);\r\n }\r\n\r\n return {\r\n scenarioId: scenario.id,\r\n targetMode,\r\n success: true,\r\n totalSnapshots: snapshots.length,\r\n consoleErrors: consoleErrors.length,\r\n consoleWarnings: consoleWarnings.length,\r\n reportPath,\r\n artifactsDir: scenarioArtifactsDir\r\n };\r\n } catch (err: any) {\r\n console.error(`\\nāŒ Visual Test Failed: ${err.message}`);\r\n const durationMs = Date.now() - startTime;\r\n const snapshots = captureEngine.getSnapshots();\r\n const consoleErrors = consoleTracker.getErrors();\r\n const consoleWarnings = consoleTracker.getWarnings();\r\n\r\n const reportPath = VisualReporter.generateReport({\r\n scenario,\r\n snapshots,\r\n consoleErrors,\r\n consoleWarnings,\r\n outputDir: scenarioArtifactsDir,\r\n targetMode,\r\n durationMs\r\n });\r\n\r\n try {\r\n const latestDir = path.join(artifactsRoot, 'latest');\r\n if (fs.existsSync(latestDir)) {\r\n fs.rmSync(latestDir, { recursive: true, force: true });\r\n }\r\n fs.mkdirSync(latestDir, { recursive: true });\r\n fs.copyFileSync(reportPath, path.join(latestDir, 'report.md'));\r\n } catch {\r\n // ignore\r\n }\r\n\r\n return {\r\n scenarioId: scenario.id,\r\n targetMode,\r\n success: false,\r\n totalSnapshots: snapshots.length,\r\n consoleErrors: consoleErrors.length,\r\n consoleWarnings: consoleWarnings.length,\r\n reportPath,\r\n artifactsDir: scenarioArtifactsDir,\r\n error: err.message\r\n };\r\n } finally {\r\n // 1. Run scenario teardown hook (guaranteed cleanup)\r\n if (typeof scenario.teardown === 'function') {\r\n try {\r\n console.log(`🧹 [Scenario Teardown] Executing teardown hook...`);\r\n await scenario.teardown();\r\n } catch (teardownErr: any) {\r\n console.error(`āš ļø [Scenario Teardown] Error during teardown:`, teardownErr.message);\r\n }\r\n }\r\n\r\n // 2. Perform requested file and folder cleanups\r\n if (options.cleanPaths && options.cleanPaths.length > 0) {\r\n for (const cleanTarget of options.cleanPaths) {\r\n try {\r\n const resolvedCleanPath = path.resolve(process.cwd(), cleanTarget);\r\n if (fs.existsSync(resolvedCleanPath)) {\r\n console.log(`🧹 [Auto-Cleanup] Removing: ${resolvedCleanPath}`);\r\n fs.rmSync(resolvedCleanPath, { recursive: true, force: true });\r\n }\r\n } catch (cleanErr: any) {\r\n console.error(`āš ļø [Auto-Cleanup] Failed to remove ${cleanTarget}:`, cleanErr.message);\r\n }\r\n }\r\n }\r\n\r\n // 3. Stop running drivers unless detached\r\n if (!options.detach) {\r\n if (desktopDriver) await desktopDriver.stop();\r\n if (previewDriver) await previewDriver.stop();\r\n if (processManager) await processManager.stop();\r\n } else {\r\n console.log('šŸ”— [Runner] Detach mode active, leaving browser/app open.');\r\n }\r\n }\r\n}\r\n","import path from 'path';\nimport fs from 'fs';\nimport { runVisualScenario } from '../runner/runner';\nimport { defineVisualTest, VIEWPORT_PRESETS, type ViewportPreset } from '../../shared/api/dsl';\nimport { resolveWwwrootDir } from '../../shared/lib/config';\n\nexport interface SnapCliOptions {\n url?: string;\n start?: string;\n startCwd?: string;\n selector?: string;\n viewports?: string[];\n waitMs?: number;\n name?: string;\n clean?: string[];\n cleanArtifacts?: boolean;\n headed?: boolean;\n detach?: boolean;\n outDir?: string;\n mode?: 'desktop' | 'preview';\n exe?: string;\n port?: number;\n}\n\nconst PRESET_MAP: Record<string, ViewportPreset> = {\n default: VIEWPORT_PRESETS.DEFAULT,\n desktop: VIEWPORT_PRESETS.DEFAULT,\n min: VIEWPORT_PRESETS.MIN_SUPPORTED,\n 'min-supported': VIEWPORT_PRESETS.MIN_SUPPORTED,\n wide: VIEWPORT_PRESETS.WIDE,\n mobile: { name: 'mobile', width: 375, height: 667 },\n tablet: { name: 'tablet', width: 768, height: 1024 },\n 'full-hd': VIEWPORT_PRESETS.FULL_HD\n};\n\nfunction parseViewportPresets(raw?: string[]): ViewportPreset[] {\n if (!raw || raw.length === 0) {\n return [VIEWPORT_PRESETS.DEFAULT, PRESET_MAP.mobile];\n }\n\n const presets: ViewportPreset[] = [];\n for (const item of raw) {\n const lower = item.toLowerCase().trim();\n if (PRESET_MAP[lower]) {\n presets.push(PRESET_MAP[lower]);\n } else if (lower.includes('x')) {\n const [w, h] = lower.split('x').map((n) => parseInt(n, 10));\n if (!isNaN(w) && !isNaN(h)) {\n presets.push({ name: `${w}x${h}`, width: w, height: h });\n }\n }\n }\n\n return presets.length > 0 ? presets : [VIEWPORT_PRESETS.DEFAULT, PRESET_MAP.mobile];\n}\n\nconst CANDIDATE_PORTS = [5173, 3000, 4321, 4200, 8080, 8000, 3001];\n\nasync function isPortResponding(url: string): Promise<boolean> {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(800) });\n return Boolean(res.status);\n } catch {\n return false;\n }\n}\n\nasync function detectActiveDevServer(): Promise<string | null> {\n for (const port of CANDIDATE_PORTS) {\n const url = `http://localhost:${port}`;\n if (await isPortResponding(url)) {\n return url;\n }\n }\n return null;\n}\n\nexport async function runQuickSnap(options: SnapCliOptions): Promise<boolean> {\n let targetUrl = options.url;\n let useStaticPreview = false;\n let wwwrootDir: string | undefined;\n\n // Smart URL/Server Resolution when neither --url nor --start is explicitly provided\n if (!targetUrl && !options.start) {\n const activeUrl = await detectActiveDevServer();\n if (activeUrl) {\n targetUrl = activeUrl;\n console.log(`🌐 [Quick Snap] Detected active dev server on ${targetUrl}`);\n } else {\n // Check for compiled static files (dist, build, wwwroot)\n const candidateDir = resolveWwwrootDir();\n if (fs.existsSync(candidateDir) && fs.existsSync(path.join(candidateDir, 'index.html'))) {\n useStaticPreview = true;\n wwwrootDir = candidateDir;\n console.log(`šŸ“¦ [Quick Snap] No active server found. Detected built static directory at \"${candidateDir}\". Launching static preview...`);\n } else {\n console.error(`\\nāŒ [Quick Snap] No active server found on common ports (${CANDIDATE_PORTS.join(', ')}), and no static build found.`);\n console.log(`šŸ’” Suggested actions:`);\n console.log(` 1. Pass a start command: npx agent-lens snap --start=\"npm run dev\"`);\n console.log(` 2. Specify your URL: npx agent-lens snap --url=http://localhost:8080`);\n console.log(` 3. Build your static app: npm run build\\n`);\n return false;\n }\n }\n } else if (!targetUrl && options.start) {\n targetUrl = 'http://localhost:5173';\n }\n \n\n const waitMs = options.waitMs ?? 1000;\n const snapshotPrefix = options.name || 'quick_snap';\n const targetViewports = parseViewportPresets(options.viewports);\n\n console.log(`\\nšŸ“ø [Quick Snap] Preparing instant verification for: ${targetUrl || wwwrootDir}`);\n console.log(`šŸ“ [Quick Snap] Testing ${targetViewports.length} viewports: ${targetViewports.map((v) => `${v.name} (${v.width}x${v.height})`).join(', ')}`);\n if (options.selector) {\n console.log(`šŸŽÆ [Quick Snap] Focused element selector: \"${options.selector}\"`);\n }\n\n const snapScenario = defineVisualTest({\n id: 'quick-snap',\n title: `Quick Verification: ${targetUrl || 'Static Preview'}`,\n description: `One-shot automated snapshot and console health check`,\n route: targetUrl || '/',\n viewports: targetViewports,\n run: async (ctx) => {\n ctx.log(`Waiting ${waitMs}ms for page stabilization...`);\n await ctx.wait(waitMs);\n\n for (let i = 0; i < targetViewports.length; i++) {\n const vp = targetViewports[i];\n const stepNum = String(i + 1).padStart(2, '0');\n ctx.log(`Switching viewport to: ${vp.name} (${vp.width}x${vp.height})`);\n await ctx.setPreset(vp);\n await ctx.wait(200);\n await ctx.capture(`${stepNum}_${snapshotPrefix}_${vp.name}`);\n }\n\n if (options.selector) {\n ctx.log(`Focusing on selector: \"${options.selector}\"`);\n try {\n await ctx.setPreset(VIEWPORT_PRESETS.DEFAULT);\n await ctx.resizeToFit(options.selector, 15);\n await ctx.capture(`99_${snapshotPrefix}_element_focus`, { selector: options.selector });\n } catch (err: any) {\n ctx.log(`āš ļø Could not isolate selector \"${options.selector}\": ${err.message}`);\n }\n }\n\n const errors = ctx.getConsoleErrors();\n if (errors.length > 0) {\n ctx.log(`🚨 Caught ${errors.length} console errors during snap check!`);\n } else {\n ctx.log(`āœ… Clean run: No console errors detected.`);\n }\n }\n });\n\n const result = await runVisualScenario({\n scenario: snapScenario,\n targetMode: options.mode || 'preview',\n url: useStaticPreview ? undefined : targetUrl,\n wwwrootDir: useStaticPreview ? wwwrootDir : undefined,\n startCommand: options.start,\n startCwd: options.startCwd,\n executablePath: options.exe,\n cleanPaths: options.clean,\n cleanArtifacts: options.cleanArtifacts,\n port: options.port,\n headed: options.headed,\n detach: options.detach,\n artifactsRoot: options.outDir ? path.resolve(process.cwd(), options.outDir) : undefined\n });\n\n console.log(`\\n========================================`);\n console.log(`šŸ Quick Snap Finished!`);\n console.log(`šŸ“ø Snapshots: ${result.totalSnapshots}`);\n console.log(`šŸ”“ Console Errors: ${result.consoleErrors}`);\n console.log(`🟔 Console Warnings: ${result.consoleWarnings}`);\n console.log(`šŸ“„ Report: ${result.reportPath}`);\n console.log(`========================================\\n`);\n\n return result.success && result.consoleErrors === 0;\n}\n","import path from 'path';\nimport fs from 'fs';\nimport { execSync } from 'child_process';\nimport { runVisualScenario } from '../features/runner/runner';\nimport type { VisualScenario } from '../shared/api/dsl';\nimport { createJiti } from 'jiti';\nimport { loadConfig, resolveWwwrootDir, detectStartCwd } from '../shared/lib/config';\nimport { runQuickSnap } from '../features/snap/snap';\n\n// Load config from agent-lens.json or package.json\nconst fileConfig = loadConfig();\n\n// Parse CLI Arguments\nconst args = process.argv.slice(2);\n\n// Check subcommands\nif (args[0] === 'init') {\n initScenarioTemplate();\n process.exit(0);\n}\n\nconst isSnapCommand = args[0] === 'snap';\nconst effectiveArgs = isSnapCommand ? args.slice(1) : args;\n\nconst options: {\n scenario?: string;\n mode: 'desktop' | 'preview';\n all?: boolean;\n port: number;\n help?: boolean;\n headed?: boolean;\n detach?: boolean;\n build?: boolean | string;\n start?: string;\n startCwd?: string;\n cleanArtifacts?: boolean;\n url?: string;\n selector?: string;\n viewports?: string[];\n waitMs?: number;\n name?: string;\n exe?: string;\n clean?: string[];\n dir?: string;\n wwwroot?: string;\n outDir?: string;\n} = {\n mode: fileConfig.mode || 'preview',\n port: fileConfig.port || 9222,\n headed: fileConfig.headed ?? false,\n detach: fileConfig.detach ?? false,\n build: fileConfig.buildCommand || false,\n start: fileConfig.startCommand,\n startCwd: fileConfig.startCwd,\n cleanArtifacts: fileConfig.cleanArtifacts ?? false,\n url: fileConfig.url,\n exe: fileConfig.executablePath,\n clean: Array.isArray(fileConfig.clean) ? fileConfig.clean : (fileConfig.clean ? [fileConfig.clean] : undefined),\n dir: fileConfig.scenarios,\n wwwroot: fileConfig.wwwroot,\n outDir: fileConfig.outDir\n};\n\nfor (const arg of effectiveArgs) {\n if (arg === '--help' || arg === '-h') {\n options.help = true;\n } else if (arg.startsWith('--scenario=')) {\n options.scenario = arg.split('=')[1];\n } else if (arg === '--all') {\n options.all = true;\n } else if (arg.startsWith('--mode=')) {\n const mode = arg.split('=')[1].toLowerCase();\n if (mode === 'desktop' || mode === 'preview') {\n options.mode = mode as 'desktop' | 'preview';\n }\n } else if (arg.startsWith('--port=')) {\n options.port = parseInt(arg.split('=')[1], 10) || 9222;\n } else if (arg === '--headed') {\n options.headed = true;\n } else if (arg === '--detach') {\n options.detach = true;\n } else if (arg === '--build') {\n options.build = true;\n } else if (arg.startsWith('--build=')) {\n options.build = arg.slice('--build='.length);\n } else if (arg.startsWith('--start=')) {\n options.start = arg.slice('--start='.length);\n } else if (arg.startsWith('--start-cwd=') || arg.startsWith('--cwd=')) {\n options.startCwd = arg.split('=')[1];\n } else if (arg === '--clean-artifacts') {\n options.cleanArtifacts = true;\n } else if (arg.startsWith('--url=')) {\n options.url = arg.split('=')[1];\n } else if (arg.startsWith('--selector=')) {\n options.selector = arg.split('=')[1];\n } else if (arg.startsWith('--viewports=')) {\n const raw = arg.slice('--viewports='.length);\n options.viewports = raw.split(',').map((v: string) => v.trim()).filter(Boolean);\n } else if (arg.startsWith('--wait=')) {\n options.waitMs = parseInt(arg.slice('--wait='.length), 10);\n } else if (arg.startsWith('--name=')) {\n options.name = arg.slice('--name='.length);\n } else if (arg.startsWith('--exe=')) {\n options.exe = arg.slice('--exe='.length);\n } else if (arg.startsWith('--executable=')) {\n options.exe = arg.slice('--executable='.length);\n } else if (arg.startsWith('--clean=') || arg.startsWith('--cleanup=')) {\n const prefix = arg.startsWith('--clean=') ? '--clean=' : '--cleanup=';\n const rawPaths = arg.slice(prefix.length);\n options.clean = rawPaths.split(',').map((p: string) => p.trim()).filter(Boolean);\n } else if (arg.startsWith('--dir=')) {\n options.dir = arg.split('=')[1];\n } else if (arg.startsWith('--wwwroot=')) {\n options.wwwroot = arg.split('=')[1];\n } else if (arg.startsWith('--outDir=') || arg.startsWith('--folder=')) {\n options.outDir = arg.split('=')[1];\n }\n}\n\n// Auto-detect startCwd if a start command was provided in a monorepo setup\nif (options.start && !options.startCwd) {\n options.startCwd = detectStartCwd(options.startCwd);\n}\n\nfunction printHelp() {\n console.log(`\nšŸ‘ļø AgentLens - Visual UI Self-Verification for AI Agents\n\nUsage:\n npx agent-lens snap [options] Instant one-shot visual & console check (no test files needed)\n npx agent-lens [options] Run scripted scenario tests from scenarios/\n npx agent-lens init Generate starter scenario template & mocks\n\nCommands:\n snap Take immediate multi-viewport screenshots of a URL & check console errors\n init Generate starter template in scenarios/template.scenario.ts and mocks.ts\n\nOptions:\n --url=<url> Target URL to test (e.g. http://localhost:5173 or http://localhost:3000)\n --start=\"<cmd>\" Launch dev server or backend process before testing (e.g. --start=\"npm run dev\")\n --start-cwd=<path> Directory to execute --start command in (e.g. --start-cwd=./Frontend)\n --clean-artifacts Purge previous test artifacts to prevent folder bloat\n --selector=<css> Target a specific element to focus on / resize-to-fit\n --viewports=<list> Comma-separated viewport presets (default: desktop,mobile; or 1200x800,375x667)\n --wait=<ms> Wait time in milliseconds after loading before snapshotting [default: 1000]\n --name=<prefix> Custom name prefix for captured snapshots [default: quick_snap]\n --scenario=<name> Run specific scenario by name (e.g. --scenario=smoke)\n --all Run all discovered scenarios\n --mode=<mode> Engine mode: 'preview' (Web/Vite/Live) or 'desktop' (WebView2/CDP) [default: preview]\n --exe=<path> Path to native executable for desktop mode (e.g. --exe=bin/MyApp.exe)\n --port=<port> CDP remote debugging port [default: 9222]\n --build[=<cmd>] Run build command before testing (e.g. --build=\"dotnet build\" or npm run build)\n --clean=<paths> Comma-separated paths to safely delete upon test exit (e.g. --clean=\"./temp,./cache\")\n --headed Show Chromium browser window\n --detach Keep browser/app open after finishing\n --dir=<path> Custom scenarios directory [default: scenarios]\n --wwwroot=<path> Custom directory for static fallback mode [default: dist]\n --folder=<path> Directory to save visual artifacts/reports (also --outDir)\n --help, -h Show this help message\n `);\n}\n\nfunction initScenarioTemplate() {\n const targetDir = path.resolve(process.cwd(), 'scenarios');\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n\n // 1. Generate template.scenario.ts\n const templatePath = path.join(targetDir, 'template.scenario.ts');\n if (!fs.existsSync(templatePath)) {\n const templateContent = `import { defineVisualTest, VIEWPORT_PRESETS } from 'agent-lens';\n\nexport default defineVisualTest({\n id: 'template-check',\n title: 'Basic UI Smoke & Responsiveness Check',\n route: '/',\n // Optional setup hook before test runs\n setup: async () => {\n // prepare test files or folders\n },\n run: async (ctx) => {\n ctx.log('Initial page render');\n await ctx.capture('01_initial_state');\n\n // Test adaptive layout\n await ctx.setPreset(VIEWPORT_PRESETS.MIN_SUPPORTED);\n await ctx.capture('02_compact_view');\n\n // Check for JavaScript / React runtime errors\n const errors = ctx.getConsoleErrors();\n if (errors.length > 0) {\n ctx.log(\\`āš ļø Warning: Caught \\${errors.length} console errors!\\`);\n }\n },\n // Optional teardown hook guaranteed to run on exit\n teardown: async () => {\n // clean up temporary test files or state\n }\n});\n`;\n fs.writeFileSync(templatePath, templateContent, 'utf8');\n console.log(`āœ… Starter scenario generated at: ${templatePath}`);\n } else {\n console.log(`ā„¹ļø Template already exists at: ${templatePath}`);\n }\n\n // Generate starter mocks.ts to prevent root app crash\n const mocksPath = path.join(targetDir, 'mocks.ts');\n if (!fs.existsSync(mocksPath)) {\n const mocksContent = `/**\n * Global IPC & API Mocks\n * \n * Export an array of base mocks to satisfy root application state on boot.\n */\nexport default [\n { action: 'GET_PREFS', data: { theme: 'dark', language: 'en' } },\n { action: 'GET_USER_PROFILE', data: { id: 1, name: 'Agent', role: 'admin' } }\n];\n`;\n fs.writeFileSync(mocksPath, mocksContent, 'utf8');\n console.log(`āœ… Base global mocks generated at: ${mocksPath}`);\n }\n\n console.log(`šŸ‘‰ Run tests with: npx agent-lens --scenario=template --mode=preview`);\n}\n\nif (options.help) {\n printHelp();\n process.exit(0);\n}\n\nasync function findScenarios(dir: string, specificName?: string): Promise<string[]> {\n const results: string[] = [];\n if (!fs.existsSync(dir)) return results;\n\n const items = fs.readdirSync(dir, { withFileTypes: true });\n for (const item of items) {\n const fullPath = path.join(dir, item.name);\n if (item.isDirectory()) {\n results.push(...await findScenarios(fullPath, specificName));\n } else if (item.name.endsWith('.scenario.ts') || item.name.endsWith('.scenario.js')) {\n if (!specificName || item.name.startsWith(specificName)) {\n results.push(fullPath);\n }\n }\n }\n return results;\n}\n\nfunction resolveScenariosDirectory(customDir?: string): string {\n if (customDir) {\n return path.resolve(process.cwd(), customDir);\n }\n\n const candidates = [\n 'scenarios',\n 'tests/visual',\n 'tests/scenarios',\n 'test/scenarios',\n 'src/scenarios'\n ];\n\n for (const c of candidates) {\n const p = path.resolve(process.cwd(), c);\n if (fs.existsSync(p)) {\n return p;\n }\n }\n\n return path.resolve(process.cwd(), 'scenarios');\n}\n\nasync function main() {\n // One-shot \"snap\" command execution\n if (isSnapCommand || (options.url && !options.scenario && !options.all)) {\n const snapSuccess = await runQuickSnap({\n url: options.url,\n start: options.start,\n startCwd: options.startCwd,\n selector: options.selector,\n viewports: options.viewports,\n waitMs: options.waitMs,\n name: options.name,\n clean: options.clean,\n cleanArtifacts: options.cleanArtifacts,\n headed: options.headed,\n detach: options.detach,\n outDir: options.outDir,\n mode: options.mode,\n exe: options.exe,\n port: options.port\n });\n\n process.exit(snapSuccess ? 0 : 1);\n }\n\n // 2. Scenario-based test execution\n if (!options.scenario && !options.all) {\n console.error('āŒ Please specify a scenario (--scenario=name), run --all, or use: npx agent-lens snap --url=http://localhost:5173');\n printHelp();\n process.exit(1);\n }\n\n const scenariosDir = resolveScenariosDirectory(options.dir);\n const scenarioPaths = await findScenarios(scenariosDir, options.scenario);\n\n if (scenarioPaths.length === 0) {\n console.error(`āŒ No scenarios found in ${scenariosDir}`);\n console.log(`šŸ’” Generate a template with: npx agent-lens init`);\n process.exit(1);\n }\n\n const shouldBuild = options.build || fileConfig.autoBuild;\n if (shouldBuild) {\n const buildCmd = typeof options.build === 'string'\n ? options.build\n : (fileConfig.buildCommand || 'npm run build');\n\n console.log(`\\nšŸ”Ø [Build] Running build process: \"${buildCmd}\"...`);\n try {\n execSync(buildCmd, { stdio: 'inherit', cwd: options.startCwd || process.cwd() });\n } catch (e) {\n console.error(`āŒ Build failed: ${buildCmd}`);\n process.exit(1);\n }\n } else if (options.mode === 'preview' && !options.url && !options.start) {\n console.log(`āš ļø Warning: Running without --build or --url flag. Make sure your frontend is built!`);\n }\n\n console.log(`šŸ“‹ Found ${scenarioPaths.length} scenario(s) in: ${scenariosDir}`);\n\n // Initialize JITI for seamless TypeScript loading\n const jiti = createJiti(process.cwd());\n\n // Check for global mocks\n let globalMocks: any[] = [];\n const mockCandidates = [\n path.join(scenariosDir, 'mocks.ts'),\n path.join(scenariosDir, 'mocks.js'),\n path.join(process.cwd(), 'mocks.ts'),\n path.join(process.cwd(), 'mocks.js')\n ];\n\n for (const mocksPath of mockCandidates) {\n if (fs.existsSync(mocksPath)) {\n try {\n const m = await jiti.import(mocksPath) as any;\n globalMocks = m.default || m.mocks || [];\n console.log(`šŸŒ Loaded ${globalMocks.length} global mock(s) from ${path.basename(mocksPath)}`);\n break;\n } catch (err) {\n console.warn(`āš ļø Failed to load global mocks from ${mocksPath}:`, err);\n }\n }\n }\n\n let allSuccess = true;\n for (const scenarioPath of scenarioPaths) {\n try {\n const scenarioModule = await jiti.import(scenarioPath) as any;\n const scenario: VisualScenario = scenarioModule.default || scenarioModule.scenario;\n\n if (!scenario || typeof scenario.run !== 'function') {\n console.error(`āš ļø Skipped: file ${path.basename(scenarioPath)} does not export a VisualScenario object by default.`);\n continue;\n }\n\n const result = await runVisualScenario({\n scenario,\n targetMode: options.mode,\n url: options.url,\n startCommand: options.start,\n startCwd: options.startCwd,\n cleanArtifacts: options.cleanArtifacts,\n port: options.port,\n headed: options.headed,\n detach: options.detach,\n executablePath: options.exe,\n cleanPaths: options.clean,\n desktopEnv: fileConfig.env,\n wwwrootDir: options.wwwroot ? resolveWwwrootDir(options.wwwroot) : undefined,\n artifactsRoot: options.outDir ? path.resolve(process.cwd(), options.outDir) : undefined,\n globalMocks\n });\n\n if (!result.success) {\n allSuccess = false;\n }\n } catch (err: any) {\n console.error(`āŒ Failed to load scenario ${path.basename(scenarioPath)}:`, err);\n allSuccess = false;\n }\n }\n\n if (!allSuccess) {\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n"],"mappings":"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","names":["fs","path","path","fs","path","fs","http","fs","path","action","spawn","treeKill","path","fs","path","fs","path","fs"]}