cbrowser 7.2.0 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/analysis/bug-hunter.d.ts +32 -0
  2. package/dist/analysis/bug-hunter.d.ts.map +1 -0
  3. package/dist/analysis/bug-hunter.js +106 -0
  4. package/dist/analysis/bug-hunter.js.map +1 -0
  5. package/dist/analysis/chaos-testing.d.ts +41 -0
  6. package/dist/analysis/chaos-testing.d.ts.map +1 -0
  7. package/dist/analysis/chaos-testing.js +87 -0
  8. package/dist/analysis/chaos-testing.js.map +1 -0
  9. package/dist/analysis/index.d.ts +10 -0
  10. package/dist/analysis/index.d.ts.map +1 -0
  11. package/dist/analysis/index.js +26 -0
  12. package/dist/analysis/index.js.map +1 -0
  13. package/dist/analysis/natural-language.d.ts +43 -0
  14. package/dist/analysis/natural-language.d.ts.map +1 -0
  15. package/dist/analysis/natural-language.js +205 -0
  16. package/dist/analysis/natural-language.js.map +1 -0
  17. package/dist/analysis/persona-comparison.d.ts +31 -0
  18. package/dist/analysis/persona-comparison.d.ts.map +1 -0
  19. package/dist/analysis/persona-comparison.js +217 -0
  20. package/dist/analysis/persona-comparison.js.map +1 -0
  21. package/dist/browser.d.ts +1 -395
  22. package/dist/browser.d.ts.map +1 -1
  23. package/dist/browser.js +0 -4388
  24. package/dist/browser.js.map +1 -1
  25. package/dist/cli.js +198 -55
  26. package/dist/cli.js.map +1 -1
  27. package/dist/daemon.d.ts.map +1 -1
  28. package/dist/daemon.js +2 -1
  29. package/dist/daemon.js.map +1 -1
  30. package/dist/index.d.ts +4 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +9 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/performance/index.d.ts +7 -0
  35. package/dist/performance/index.d.ts.map +1 -0
  36. package/dist/performance/index.js +23 -0
  37. package/dist/performance/index.js.map +1 -0
  38. package/dist/performance/metrics.d.ts +49 -0
  39. package/dist/performance/metrics.d.ts.map +1 -0
  40. package/dist/performance/metrics.js +386 -0
  41. package/dist/performance/metrics.js.map +1 -0
  42. package/dist/testing/coverage.d.ts +39 -0
  43. package/dist/testing/coverage.d.ts.map +1 -0
  44. package/dist/testing/coverage.js +713 -0
  45. package/dist/testing/coverage.js.map +1 -0
  46. package/dist/testing/flaky-detection.d.ts +28 -0
  47. package/dist/testing/flaky-detection.d.ts.map +1 -0
  48. package/dist/testing/flaky-detection.js +332 -0
  49. package/dist/testing/flaky-detection.js.map +1 -0
  50. package/dist/testing/index.d.ts +10 -0
  51. package/dist/testing/index.d.ts.map +1 -0
  52. package/dist/testing/index.js +26 -0
  53. package/dist/testing/index.js.map +1 -0
  54. package/dist/testing/nl-test-suite.d.ts +70 -0
  55. package/dist/testing/nl-test-suite.d.ts.map +1 -0
  56. package/dist/testing/nl-test-suite.js +427 -0
  57. package/dist/testing/nl-test-suite.js.map +1 -0
  58. package/dist/testing/test-repair.d.ts +36 -0
  59. package/dist/testing/test-repair.d.ts.map +1 -0
  60. package/dist/testing/test-repair.js +528 -0
  61. package/dist/testing/test-repair.js.map +1 -0
  62. package/dist/types.d.ts +125 -0
  63. package/dist/types.d.ts.map +1 -1
  64. package/dist/visual/ab-comparison.d.ts +23 -0
  65. package/dist/visual/ab-comparison.d.ts.map +1 -0
  66. package/dist/visual/ab-comparison.js +366 -0
  67. package/dist/visual/ab-comparison.js.map +1 -0
  68. package/dist/visual/cross-browser.d.ts +41 -0
  69. package/dist/visual/cross-browser.d.ts.map +1 -0
  70. package/dist/visual/cross-browser.js +442 -0
  71. package/dist/visual/cross-browser.js.map +1 -0
  72. package/dist/visual/index.d.ts +10 -0
  73. package/dist/visual/index.d.ts.map +1 -0
  74. package/dist/visual/index.js +26 -0
  75. package/dist/visual/index.js.map +1 -0
  76. package/dist/visual/regression.d.ts +55 -0
  77. package/dist/visual/regression.d.ts.map +1 -0
  78. package/dist/visual/regression.js +616 -0
  79. package/dist/visual/regression.js.map +1 -0
  80. package/dist/visual/responsive.d.ts +27 -0
  81. package/dist/visual/responsive.d.ts.map +1 -0
  82. package/dist/visual/responsive.js +450 -0
  83. package/dist/visual/responsive.js.map +1 -0
  84. package/package.json +32 -3
package/dist/cli.js CHANGED
@@ -7,6 +7,14 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const browser_js_1 = require("./browser.js");
10
+ // Analysis module imports
11
+ const index_js_1 = require("./analysis/index.js");
12
+ // Testing module imports
13
+ const index_js_2 = require("./testing/index.js");
14
+ // Performance module imports
15
+ const index_js_3 = require("./performance/index.js");
16
+ // Visual module imports
17
+ const index_js_4 = require("./visual/index.js");
10
18
  const personas_js_1 = require("./personas.js");
11
19
  const types_js_1 = require("./types.js");
12
20
  const mcp_server_js_1 = require("./mcp-server.js");
@@ -14,7 +22,7 @@ const daemon_js_1 = require("./daemon.js");
14
22
  function showHelp() {
15
23
  console.log(`
16
24
  ╔══════════════════════════════════════════════════════════════════════════════╗
17
- ā•‘ CBrowser CLI v7.2.0 ā•‘
25
+ ā•‘ CBrowser CLI v7.4.0 ā•‘
18
26
  ā•‘ AI-powered browser automation with cross-browser visual testing ā•‘
19
27
  ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
20
28
 
@@ -232,7 +240,7 @@ AI VISUAL REGRESSION (v7.0.0)
232
240
  ai-visual show <name> Show baseline details
233
241
  ai-visual delete <name> Delete a baseline
234
242
 
235
- CROSS-BROWSER VISUAL TESTING (v7.2.0)
243
+ CROSS-BROWSER VISUAL TESTING (v7.3.0)
236
244
  cross-browser <url> Compare visual rendering across browsers
237
245
  --browsers <list> Browsers to test: chromium,firefox,webkit (default: all)
238
246
  --width <n> Viewport width (default: 1920)
@@ -258,7 +266,7 @@ CROSS-BROWSER VISUAL TESTING (v7.2.0)
258
266
  "options": { "browsers": ["chromium", "firefox"] }
259
267
  }
260
268
 
261
- RESPONSIVE VISUAL TESTING (v7.2.0)
269
+ RESPONSIVE VISUAL TESTING (v7.3.0)
262
270
  responsive <url> Test visual rendering across viewport sizes
263
271
  --viewports <list> Viewports to test (default: mobile,tablet,desktop)
264
272
  --wait <ms> Wait before screenshot (ms)
@@ -290,6 +298,36 @@ RESPONSIVE VISUAL TESTING (v7.2.0)
290
298
  desktop-sm (1280x800) desktop (1440x900) desktop-lg (1920x1080)
291
299
  desktop-xl (2560x1440)
292
300
 
301
+ A/B VISUAL COMPARISON (v7.3.0)
302
+ ab <urlA> <urlB> Compare two URLs visually
303
+ --label-a <name> Label for URL A (default: "Version A")
304
+ --label-b <name> Label for URL B (default: "Version B")
305
+ --width <n> Viewport width (default: 1920)
306
+ --height <n> Viewport height (default: 1080)
307
+ --wait <ms> Wait before screenshot (ms)
308
+ --wait-for <selector> Wait for selector before screenshot
309
+ --sensitivity <level> Comparison sensitivity: low, medium, high
310
+ --html Generate HTML report
311
+ --output <file> Save JSON report to file
312
+ Examples:
313
+ cbrowser ab "https://staging.example.com" "https://example.com"
314
+ cbrowser ab "https://old.site.com" "https://new.site.com" --label-a "Old Design" --label-b "New Design"
315
+ cbrowser ab "https://site-a.com" "https://site-b.com" --html --output comparison.html
316
+
317
+ ab suite <file.json> Run A/B comparison suite
318
+ --html Generate HTML report
319
+ --output <file> Save JSON report to file
320
+
321
+ Suite file format:
322
+ {
323
+ "name": "Staging vs Production",
324
+ "pairs": [
325
+ { "urlA": "https://staging.example.com", "urlB": "https://example.com", "name": "Homepage" },
326
+ { "urlA": "https://staging.example.com/about", "urlB": "https://example.com/about", "name": "About" }
327
+ ],
328
+ "options": { "sensitivity": "medium" }
329
+ }
330
+
293
331
  ACCESSIBILITY (v2.5.0)
294
332
  a11y audit Run WCAG accessibility audit
295
333
  --url <url> Navigate to URL first
@@ -1274,7 +1312,7 @@ async function main() {
1274
1312
  const concurrency = options.concurrency
1275
1313
  ? parseInt(options.concurrency)
1276
1314
  : 3;
1277
- const comparison = await (0, browser_js_1.comparePersonas)({
1315
+ const comparison = await (0, index_js_1.comparePersonas)({
1278
1316
  startUrl,
1279
1317
  goal,
1280
1318
  personas: personaNames,
@@ -1282,7 +1320,7 @@ async function main() {
1282
1320
  headless,
1283
1321
  });
1284
1322
  // Print formatted report
1285
- const report = (0, browser_js_1.formatComparisonReport)(comparison);
1323
+ const report = (0, index_js_1.formatComparisonReport)(comparison);
1286
1324
  console.log(report);
1287
1325
  // Save JSON output if requested
1288
1326
  if (options.output) {
@@ -1990,7 +2028,7 @@ async function main() {
1990
2028
  }
1991
2029
  console.log(`šŸ“ø Capturing visual baseline: ${options.name}`);
1992
2030
  console.log(` URL: ${url}`);
1993
- const baseline = await (0, browser_js_1.captureVisualBaseline)(url, options.name, {
2031
+ const baseline = await (0, index_js_4.captureVisualBaseline)(url, options.name, {
1994
2032
  selector: options.selector,
1995
2033
  device: options.device,
1996
2034
  viewport: options.width || options.height ? {
@@ -2021,13 +2059,13 @@ async function main() {
2021
2059
  console.log(`\nšŸ” Running AI visual regression test...`);
2022
2060
  console.log(` URL: ${url}`);
2023
2061
  console.log(` Baseline: ${baselineName}\n`);
2024
- const result = await (0, browser_js_1.runVisualRegression)(url, baselineName, {
2062
+ const result = await (0, index_js_4.runVisualRegression)(url, baselineName, {
2025
2063
  threshold: options.threshold ? parseFloat(options.threshold) : 0.9,
2026
2064
  sensitivity: options.sensitivity || "medium",
2027
2065
  generateDiff: true,
2028
2066
  });
2029
2067
  // Print report
2030
- console.log((0, browser_js_1.formatVisualRegressionReport)(result));
2068
+ console.log((0, index_js_4.formatVisualRegressionReport)(result));
2031
2069
  // Save JSON output if requested
2032
2070
  if (options.output && !options.html) {
2033
2071
  const fs = await import("fs");
@@ -2052,7 +2090,7 @@ async function main() {
2052
2090
  duration: result.duration,
2053
2091
  timestamp: new Date().toISOString(),
2054
2092
  };
2055
- const htmlReport = (0, browser_js_1.generateVisualRegressionHtmlReport)(suiteResult);
2093
+ const htmlReport = (0, index_js_4.generateVisualRegressionHtmlReport)(suiteResult);
2056
2094
  const outputPath = options.output || `visual-regression-${baselineName}-${Date.now()}.html`;
2057
2095
  fs.writeFileSync(outputPath, htmlReport);
2058
2096
  console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
@@ -2078,7 +2116,7 @@ async function main() {
2078
2116
  }
2079
2117
  const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
2080
2118
  console.log(`\nšŸ” Running visual regression suite: ${suite.name}`);
2081
- const result = await (0, browser_js_1.runVisualRegressionSuite)(suite, {
2119
+ const result = await (0, index_js_4.runVisualRegressionSuite)(suite, {
2082
2120
  threshold: options.threshold ? parseFloat(options.threshold) : 0.9,
2083
2121
  });
2084
2122
  // Save outputs
@@ -2087,7 +2125,7 @@ async function main() {
2087
2125
  console.log(`šŸ“„ JSON report saved to: ${options.output}`);
2088
2126
  }
2089
2127
  if (options.html) {
2090
- const htmlReport = (0, browser_js_1.generateVisualRegressionHtmlReport)(result);
2128
+ const htmlReport = (0, index_js_4.generateVisualRegressionHtmlReport)(result);
2091
2129
  const outputPath = options.output || `visual-suite-${Date.now()}.html`;
2092
2130
  fs.writeFileSync(outputPath, htmlReport);
2093
2131
  console.log(`šŸ“„ HTML report saved to: ${outputPath}`);
@@ -2098,7 +2136,7 @@ async function main() {
2098
2136
  break;
2099
2137
  }
2100
2138
  case "list": {
2101
- const baselines = (0, browser_js_1.listVisualBaselines)();
2139
+ const baselines = (0, index_js_4.listVisualBaselines)();
2102
2140
  if (baselines.length === 0) {
2103
2141
  console.log("\nNo AI visual baselines saved.\n");
2104
2142
  console.log("Capture one with:");
@@ -2126,7 +2164,7 @@ async function main() {
2126
2164
  console.error("Usage: cbrowser ai-visual show <name>");
2127
2165
  process.exit(1);
2128
2166
  }
2129
- const baseline = (0, browser_js_1.getVisualBaseline)(name);
2167
+ const baseline = (0, index_js_4.getVisualBaseline)(name);
2130
2168
  if (!baseline) {
2131
2169
  console.error(`Baseline not found: ${name}`);
2132
2170
  process.exit(1);
@@ -2153,7 +2191,7 @@ async function main() {
2153
2191
  console.error("Usage: cbrowser ai-visual delete <name>");
2154
2192
  process.exit(1);
2155
2193
  }
2156
- if ((0, browser_js_1.deleteVisualBaseline)(name)) {
2194
+ if ((0, index_js_4.deleteVisualBaseline)(name)) {
2157
2195
  console.log(`āœ… Baseline deleted: ${name}`);
2158
2196
  }
2159
2197
  else {
@@ -2174,7 +2212,7 @@ async function main() {
2174
2212
  break;
2175
2213
  }
2176
2214
  // =========================================================================
2177
- // Cross-Browser Visual Testing (v7.2.0)
2215
+ // Cross-Browser Visual Testing (v7.3.0)
2178
2216
  // =========================================================================
2179
2217
  case "cross-browser": {
2180
2218
  const subcommand = args[0];
@@ -2193,14 +2231,14 @@ async function main() {
2193
2231
  process.exit(1);
2194
2232
  }
2195
2233
  const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
2196
- const result = await (0, browser_js_1.runCrossBrowserSuite)(suite);
2234
+ const result = await (0, index_js_4.runCrossBrowserSuite)(suite);
2197
2235
  // Save outputs
2198
2236
  if (options.output && !options.html) {
2199
2237
  fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
2200
2238
  console.log(`\nšŸ“„ JSON report saved to: ${options.output}`);
2201
2239
  }
2202
2240
  if (options.html) {
2203
- const htmlReport = (0, browser_js_1.generateCrossBrowserHtmlReport)(result);
2241
+ const htmlReport = (0, index_js_4.generateCrossBrowserHtmlReport)(result);
2204
2242
  const outputPath = options.output || `cross-browser-${Date.now()}.html`;
2205
2243
  fs.writeFileSync(outputPath, htmlReport);
2206
2244
  console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
@@ -2233,7 +2271,7 @@ async function main() {
2233
2271
  const browsers = options.browsers
2234
2272
  ? options.browsers.split(",")
2235
2273
  : undefined;
2236
- const result = await (0, browser_js_1.runCrossBrowserTest)(url, {
2274
+ const result = await (0, index_js_4.runCrossBrowserTest)(url, {
2237
2275
  browsers,
2238
2276
  viewport: options.width || options.height ? {
2239
2277
  width: parseInt(options.width) || 1920,
@@ -2244,7 +2282,7 @@ async function main() {
2244
2282
  sensitivity: options.sensitivity,
2245
2283
  });
2246
2284
  // Print report
2247
- console.log("\n" + (0, browser_js_1.formatCrossBrowserReport)(result));
2285
+ console.log("\n" + (0, index_js_4.formatCrossBrowserReport)(result));
2248
2286
  // Save outputs
2249
2287
  const fs = await import("fs");
2250
2288
  if (options.output && !options.html) {
@@ -2264,7 +2302,7 @@ async function main() {
2264
2302
  duration: result.duration,
2265
2303
  timestamp: result.timestamp,
2266
2304
  };
2267
- const htmlReport = (0, browser_js_1.generateCrossBrowserHtmlReport)(suiteResult);
2305
+ const htmlReport = (0, index_js_4.generateCrossBrowserHtmlReport)(suiteResult);
2268
2306
  const outputPath = options.output || `cross-browser-${Date.now()}.html`;
2269
2307
  fs.writeFileSync(outputPath, htmlReport);
2270
2308
  console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
@@ -2276,13 +2314,13 @@ async function main() {
2276
2314
  break;
2277
2315
  }
2278
2316
  // =========================================================================
2279
- // Responsive Visual Testing (v7.2.0)
2317
+ // Responsive Visual Testing (v7.3.0)
2280
2318
  // =========================================================================
2281
2319
  case "responsive": {
2282
2320
  const subcommand = args[0];
2283
2321
  if (subcommand === "viewports") {
2284
2322
  // List viewport presets
2285
- const presets = (0, browser_js_1.listViewportPresets)();
2323
+ const presets = (0, index_js_4.listViewportPresets)();
2286
2324
  console.log("\nšŸ“± Available Viewport Presets\n");
2287
2325
  console.log("─".repeat(60));
2288
2326
  const byType = {
@@ -2318,14 +2356,14 @@ async function main() {
2318
2356
  process.exit(1);
2319
2357
  }
2320
2358
  const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
2321
- const result = await (0, browser_js_1.runResponsiveSuite)(suite);
2359
+ const result = await (0, index_js_4.runResponsiveSuite)(suite);
2322
2360
  // Save outputs
2323
2361
  if (options.output && !options.html) {
2324
2362
  fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
2325
2363
  console.log(`\nšŸ“„ JSON report saved to: ${options.output}`);
2326
2364
  }
2327
2365
  if (options.html) {
2328
- const htmlReport = (0, browser_js_1.generateResponsiveHtmlReport)(result);
2366
+ const htmlReport = (0, index_js_4.generateResponsiveHtmlReport)(result);
2329
2367
  const outputPath = options.output || `responsive-${Date.now()}.html`;
2330
2368
  fs.writeFileSync(outputPath, htmlReport);
2331
2369
  console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
@@ -2361,14 +2399,14 @@ async function main() {
2361
2399
  const viewports = options.viewports
2362
2400
  ? options.viewports.split(",")
2363
2401
  : undefined;
2364
- const result = await (0, browser_js_1.runResponsiveTest)(url, {
2402
+ const result = await (0, index_js_4.runResponsiveTest)(url, {
2365
2403
  viewports,
2366
2404
  waitBeforeCapture: options.wait ? parseInt(options.wait) : undefined,
2367
2405
  waitForSelector: options["wait-for"],
2368
2406
  sensitivity: options.sensitivity,
2369
2407
  });
2370
2408
  // Print report
2371
- console.log("\n" + (0, browser_js_1.formatResponsiveReport)(result));
2409
+ console.log("\n" + (0, index_js_4.formatResponsiveReport)(result));
2372
2410
  // Save outputs
2373
2411
  const fs = await import("fs");
2374
2412
  if (options.output && !options.html) {
@@ -2390,7 +2428,7 @@ async function main() {
2390
2428
  duration: result.duration,
2391
2429
  timestamp: result.timestamp,
2392
2430
  };
2393
- const htmlReport = (0, browser_js_1.generateResponsiveHtmlReport)(suiteResult);
2431
+ const htmlReport = (0, index_js_4.generateResponsiveHtmlReport)(suiteResult);
2394
2432
  const outputPath = options.output || `responsive-${Date.now()}.html`;
2395
2433
  fs.writeFileSync(outputPath, htmlReport);
2396
2434
  console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
@@ -2402,6 +2440,111 @@ async function main() {
2402
2440
  break;
2403
2441
  }
2404
2442
  // =========================================================================
2443
+ // A/B Visual Comparison (v7.3.0)
2444
+ // =========================================================================
2445
+ case "ab": {
2446
+ const subcommand = args[0];
2447
+ if (subcommand === "suite") {
2448
+ // A/B suite
2449
+ const suiteFile = args[1];
2450
+ if (!suiteFile) {
2451
+ console.error("Usage: cbrowser ab suite <file.json> [options]");
2452
+ console.error(" --html Generate HTML report");
2453
+ console.error(" --output <file> Save report to file");
2454
+ process.exit(1);
2455
+ }
2456
+ const fs = await import("fs");
2457
+ if (!fs.existsSync(suiteFile)) {
2458
+ console.error(`Suite file not found: ${suiteFile}`);
2459
+ process.exit(1);
2460
+ }
2461
+ const suite = JSON.parse(fs.readFileSync(suiteFile, "utf-8"));
2462
+ const result = await (0, index_js_4.runABSuite)(suite);
2463
+ // Save outputs
2464
+ if (options.output && !options.html) {
2465
+ fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
2466
+ console.log(`\nšŸ“„ JSON report saved to: ${options.output}`);
2467
+ }
2468
+ if (options.html) {
2469
+ const htmlReport = (0, index_js_4.generateABHtmlReport)(result);
2470
+ const outputPath = options.output || `ab-comparison-${Date.now()}.html`;
2471
+ fs.writeFileSync(outputPath, htmlReport);
2472
+ console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
2473
+ }
2474
+ // Summary
2475
+ console.log(`\n${"═".repeat(60)}`);
2476
+ console.log(` Results: ${result.summary.identical} identical, ${result.summary.similar} similar, ${result.summary.different} different, ${result.summary.veryDifferent} very different`);
2477
+ console.log(`${"═".repeat(60)}\n`);
2478
+ if (result.summary.veryDifferent > 0) {
2479
+ process.exit(1);
2480
+ }
2481
+ }
2482
+ else {
2483
+ // Single A/B comparison: ab <urlA> <urlB>
2484
+ const urlA = args[0];
2485
+ const urlB = args[1];
2486
+ if (!urlA || !urlB || urlA.startsWith("--") || urlB.startsWith("--")) {
2487
+ console.error("Usage: cbrowser ab <urlA> <urlB> [options]");
2488
+ console.error(" cbrowser ab suite <file.json>");
2489
+ console.error("\nOptions:");
2490
+ console.error(" --label-a <name> Label for URL A (default: 'Version A')");
2491
+ console.error(" --label-b <name> Label for URL B (default: 'Version B')");
2492
+ console.error(" --width <n> Viewport width (default: 1920)");
2493
+ console.error(" --height <n> Viewport height (default: 1080)");
2494
+ console.error(" --wait <ms> Wait before screenshot");
2495
+ console.error(" --wait-for <sel> Wait for selector");
2496
+ console.error(" --sensitivity <l> low, medium, high");
2497
+ console.error(" --html Generate HTML report");
2498
+ console.error(" --output <file> Save report");
2499
+ process.exit(1);
2500
+ }
2501
+ const result = await (0, index_js_4.runABComparison)(urlA, urlB, {
2502
+ labels: options["label-a"] || options["label-b"] ? {
2503
+ a: options["label-a"] || "Version A",
2504
+ b: options["label-b"] || "Version B",
2505
+ } : undefined,
2506
+ viewport: options.width || options.height ? {
2507
+ width: parseInt(options.width) || 1920,
2508
+ height: parseInt(options.height) || 1080,
2509
+ } : undefined,
2510
+ waitBeforeCapture: options.wait ? parseInt(options.wait) : undefined,
2511
+ waitForSelector: options["wait-for"],
2512
+ sensitivity: options.sensitivity,
2513
+ });
2514
+ // Print report
2515
+ console.log("\n" + (0, index_js_4.formatABReport)(result));
2516
+ // Save outputs
2517
+ const fs = await import("fs");
2518
+ if (options.output && !options.html) {
2519
+ fs.writeFileSync(options.output, JSON.stringify(result, null, 2));
2520
+ console.log(`\nšŸ“„ JSON report saved to: ${options.output}`);
2521
+ }
2522
+ if (options.html) {
2523
+ const suiteResult = {
2524
+ suite: { name: "Single Comparison", pairs: [{ urlA, urlB }] },
2525
+ results: [result],
2526
+ summary: {
2527
+ total: 1,
2528
+ identical: result.overallStatus === "identical" ? 1 : 0,
2529
+ similar: result.overallStatus === "similar" ? 1 : 0,
2530
+ different: result.overallStatus === "different" ? 1 : 0,
2531
+ veryDifferent: result.overallStatus === "very_different" ? 1 : 0,
2532
+ },
2533
+ duration: result.duration,
2534
+ timestamp: result.timestamp,
2535
+ };
2536
+ const htmlReport = (0, index_js_4.generateABHtmlReport)(suiteResult);
2537
+ const outputPath = options.output || `ab-comparison-${Date.now()}.html`;
2538
+ fs.writeFileSync(outputPath, htmlReport);
2539
+ console.log(`\nšŸ“„ HTML report saved to: ${outputPath}`);
2540
+ }
2541
+ if (result.overallStatus === "very_different") {
2542
+ process.exit(1);
2543
+ }
2544
+ }
2545
+ break;
2546
+ }
2547
+ // =========================================================================
2405
2548
  // Accessibility (Tier 2)
2406
2549
  // =========================================================================
2407
2550
  case "a11y": {
@@ -2781,7 +2924,7 @@ async function main() {
2781
2924
  process.exit(1);
2782
2925
  }
2783
2926
  console.log(`\nšŸ—£ļø Executing: "${nlCommand}"\n`);
2784
- const result = await (0, browser_js_1.executeNaturalLanguage)(browser, nlCommand);
2927
+ const result = await (0, index_js_1.executeNaturalLanguage)(browser, nlCommand);
2785
2928
  if (result.success) {
2786
2929
  console.log(`āœ“ Action: ${result.action}`);
2787
2930
  if (result.result && typeof result.result === "object") {
@@ -2817,7 +2960,7 @@ async function main() {
2817
2960
  const commands = content.split("\n").filter(line => line.trim() && !line.trim().startsWith("#"));
2818
2961
  console.log(`\nšŸ“œ Executing script: ${scriptFile}`);
2819
2962
  console.log(` Commands: ${commands.length}\n`);
2820
- const results = await (0, browser_js_1.executeNaturalLanguageScript)(browser, commands);
2963
+ const results = await (0, index_js_1.executeNaturalLanguageScript)(browser, commands);
2821
2964
  for (const r of results) {
2822
2965
  if (r.success) {
2823
2966
  console.log(`āœ“ ${r.command}`);
@@ -2853,7 +2996,7 @@ async function main() {
2853
2996
  switch (subcommand) {
2854
2997
  case "find": {
2855
2998
  console.log(`\n🧠 Finding element: "${intent}"\n`);
2856
- const result = await (0, browser_js_1.findElementByIntent)(browser, intent);
2999
+ const result = await (0, index_js_1.findElementByIntent)(browser, intent);
2857
3000
  if (result) {
2858
3001
  console.log(`āœ“ Found element`);
2859
3002
  console.log(` Selector: ${result.selector}`);
@@ -2868,7 +3011,7 @@ async function main() {
2868
3011
  }
2869
3012
  case "click": {
2870
3013
  console.log(`\n🧠 Finding and clicking: "${intent}"\n`);
2871
- const result = await (0, browser_js_1.findElementByIntent)(browser, intent);
3014
+ const result = await (0, index_js_1.findElementByIntent)(browser, intent);
2872
3015
  if (result) {
2873
3016
  console.log(`āœ“ Found: ${result.description}`);
2874
3017
  await browser.click(result.selector);
@@ -2900,7 +3043,7 @@ async function main() {
2900
3043
  console.log(` URL: ${url}`);
2901
3044
  console.log(` Max pages: ${maxPages}`);
2902
3045
  console.log(` Timeout: ${timeout}ms\n`);
2903
- const result = await (0, browser_js_1.huntBugs)(browser, url, { maxPages, timeout });
3046
+ const result = await (0, index_js_1.huntBugs)(browser, url, { maxPages, timeout });
2904
3047
  console.log(`šŸ“Š Bug Hunt Results:\n`);
2905
3048
  console.log(` Pages visited: ${result.pagesVisited}`);
2906
3049
  console.log(` Duration: ${result.duration}ms`);
@@ -2937,7 +3080,7 @@ async function main() {
2937
3080
  console.log(`\nšŸ”€ Cross-Browser Diff`);
2938
3081
  console.log(` URL: ${url}`);
2939
3082
  console.log(` Browsers: ${browserList.join(", ")}\n`);
2940
- const result = await (0, browser_js_1.crossBrowserDiff)(url, [...browserList]);
3083
+ const result = await (0, index_js_4.crossBrowserDiff)(url, [...browserList]);
2941
3084
  console.log(`šŸ“Š Results:\n`);
2942
3085
  console.log(` Metrics:`);
2943
3086
  for (const [browser, metrics] of Object.entries(result.metrics)) {
@@ -2985,7 +3128,7 @@ async function main() {
2985
3128
  console.log(` URL: ${url}`);
2986
3129
  console.log(` Chaos config:`, chaosConfig);
2987
3130
  console.log("");
2988
- const result = await (0, browser_js_1.runChaosTest)(browser, url, chaosConfig);
3131
+ const result = await (0, index_js_1.runChaosTest)(browser, url, chaosConfig);
2989
3132
  console.log(`šŸ“Š Results:\n`);
2990
3133
  console.log(` Passed: ${result.passed ? "āœ… Yes" : "āŒ No"}`);
2991
3134
  console.log(` Duration: ${result.duration}ms`);
@@ -3039,7 +3182,7 @@ async function main() {
3039
3182
  const steps = inlineTest.split(";").map(s => s.trim()).filter(s => s);
3040
3183
  const testCase = {
3041
3184
  name: "Inline Test",
3042
- steps: steps.map(s => (0, browser_js_1.parseNLInstruction)(s)),
3185
+ steps: steps.map(s => (0, index_js_2.parseNLInstruction)(s)),
3043
3186
  };
3044
3187
  suite = { name: "Inline Suite", tests: [testCase] };
3045
3188
  }
@@ -3052,7 +3195,7 @@ async function main() {
3052
3195
  }
3053
3196
  const content = fs.readFileSync(filepath, "utf-8");
3054
3197
  const suiteName = filepath.split("/").pop()?.replace(/\.[^.]+$/, "") || "Test Suite";
3055
- suite = (0, browser_js_1.parseNLTestSuite)(content, suiteName);
3198
+ suite = (0, index_js_2.parseNLTestSuite)(content, suiteName);
3056
3199
  }
3057
3200
  console.log(`\nšŸ“ Parsed ${suite.tests.length} test(s) from ${inlineTest ? "inline" : filepath}`);
3058
3201
  for (const test of suite.tests) {
@@ -3064,9 +3207,9 @@ async function main() {
3064
3207
  screenshotOnFailure: options["screenshot-on-failure"] !== false,
3065
3208
  headless,
3066
3209
  };
3067
- const result = await (0, browser_js_1.runNLTestSuite)(suite, suiteOptions);
3210
+ const result = await (0, index_js_2.runNLTestSuite)(suite, suiteOptions);
3068
3211
  // Print formatted report
3069
- const report = (0, browser_js_1.formatNLTestReport)(result);
3212
+ const report = (0, index_js_2.formatNLTestReport)(result);
3070
3213
  console.log(report);
3071
3214
  // Save JSON output if requested
3072
3215
  if (options.output) {
@@ -3115,7 +3258,7 @@ async function main() {
3115
3258
  }
3116
3259
  const content = fs.readFileSync(filepath, "utf-8");
3117
3260
  const suiteName = filepath.split("/").pop()?.replace(/\.[^.]+$/, "") || "Test Suite";
3118
- const suite = (0, browser_js_1.parseNLTestSuite)(content, suiteName);
3261
+ const suite = (0, index_js_2.parseNLTestSuite)(content, suiteName);
3119
3262
  console.log(`\nšŸ“ Parsed ${suite.tests.length} test(s) from ${filepath}`);
3120
3263
  for (const test of suite.tests) {
3121
3264
  console.log(` - ${test.name}: ${test.steps.length} steps`);
@@ -3126,9 +3269,9 @@ async function main() {
3126
3269
  verifyRepairs: options.verify === true,
3127
3270
  maxRetries: options.retries ? parseInt(options.retries) : 3,
3128
3271
  };
3129
- const result = await (0, browser_js_1.repairTestSuite)(suite, repairOptions);
3272
+ const result = await (0, index_js_2.repairTestSuite)(suite, repairOptions);
3130
3273
  // Print formatted report
3131
- const report = (0, browser_js_1.formatRepairReport)(result);
3274
+ const report = (0, index_js_2.formatRepairReport)(result);
3132
3275
  console.log(report);
3133
3276
  // Save JSON report if requested
3134
3277
  if (options.json) {
@@ -3139,7 +3282,7 @@ async function main() {
3139
3282
  if (options.output && repairOptions.autoApply) {
3140
3283
  const repairedContent = [];
3141
3284
  for (const testResult of result.testResults) {
3142
- repairedContent.push((0, browser_js_1.exportRepairedTest)(testResult));
3285
+ repairedContent.push((0, index_js_2.exportRepairedTest)(testResult));
3143
3286
  repairedContent.push("");
3144
3287
  }
3145
3288
  fs.writeFileSync(options.output, repairedContent.join("\n"));
@@ -3179,7 +3322,7 @@ async function main() {
3179
3322
  }
3180
3323
  const content = fs.readFileSync(filepath, "utf-8");
3181
3324
  const suiteName = filepath.split("/").pop()?.replace(/\.[^.]+$/, "") || "Test Suite";
3182
- const suite = (0, browser_js_1.parseNLTestSuite)(content, suiteName);
3325
+ const suite = (0, index_js_2.parseNLTestSuite)(content, suiteName);
3183
3326
  console.log(`\nšŸ“ Parsed ${suite.tests.length} test(s) from ${filepath}`);
3184
3327
  for (const test of suite.tests) {
3185
3328
  console.log(` - ${test.name}: ${test.steps.length} steps`);
@@ -3190,9 +3333,9 @@ async function main() {
3190
3333
  flakinessThreshold: options.threshold ? parseInt(options.threshold) : 20,
3191
3334
  delayBetweenRuns: options.delay ? parseInt(options.delay) : 500,
3192
3335
  };
3193
- const result = await (0, browser_js_1.detectFlakyTests)(suite, flakyOptions);
3336
+ const result = await (0, index_js_2.detectFlakyTests)(suite, flakyOptions);
3194
3337
  // Print formatted report
3195
- const report = (0, browser_js_1.formatFlakyTestReport)(result);
3338
+ const report = (0, index_js_2.formatFlakyTestReport)(result);
3196
3339
  console.log(report);
3197
3340
  // Save JSON report if requested
3198
3341
  if (options.output) {
@@ -3225,7 +3368,7 @@ async function main() {
3225
3368
  runs: options.runs ? parseInt(options.runs) : 3,
3226
3369
  };
3227
3370
  console.log(` Running ${baselineOptions.runs} measurement(s)...`);
3228
- const baseline = await (0, browser_js_1.capturePerformanceBaseline)(url, baselineOptions);
3371
+ const baseline = await (0, index_js_3.capturePerformanceBaseline)(url, baselineOptions);
3229
3372
  console.log(`\nāœ… Baseline saved: ${baseline.name}`);
3230
3373
  console.log(` ID: ${baseline.id}`);
3231
3374
  console.log(` URL: ${baseline.url}`);
@@ -3252,7 +3395,7 @@ async function main() {
3252
3395
  break;
3253
3396
  }
3254
3397
  case "list": {
3255
- const baselines = (0, browser_js_1.listPerformanceBaselines)();
3398
+ const baselines = (0, index_js_3.listPerformanceBaselines)();
3256
3399
  if (baselines.length === 0) {
3257
3400
  console.log("\nšŸ“Š No performance baselines saved yet.");
3258
3401
  console.log(" Use: cbrowser perf-baseline save <url> --name <name>");
@@ -3277,7 +3420,7 @@ async function main() {
3277
3420
  console.error("Usage: cbrowser perf-baseline show <name|id>");
3278
3421
  process.exit(1);
3279
3422
  }
3280
- const baseline = (0, browser_js_1.loadPerformanceBaseline)(name);
3423
+ const baseline = (0, index_js_3.loadPerformanceBaseline)(name);
3281
3424
  if (!baseline) {
3282
3425
  console.error(`Baseline not found: ${name}`);
3283
3426
  process.exit(1);
@@ -3299,7 +3442,7 @@ async function main() {
3299
3442
  console.error("Usage: cbrowser perf-baseline delete <name|id>");
3300
3443
  process.exit(1);
3301
3444
  }
3302
- const deleted = (0, browser_js_1.deletePerformanceBaseline)(name);
3445
+ const deleted = (0, index_js_3.deletePerformanceBaseline)(name);
3303
3446
  if (deleted) {
3304
3447
  console.log(`\nāœ… Deleted baseline: ${name}`);
3305
3448
  }
@@ -3360,9 +3503,9 @@ async function main() {
3360
3503
  thresholds: Object.keys(thresholds).length > 0 ? thresholds : undefined,
3361
3504
  };
3362
3505
  try {
3363
- const result = await (0, browser_js_1.detectPerformanceRegression)(url, baselineName, regressionOptions);
3506
+ const result = await (0, index_js_3.detectPerformanceRegression)(url, baselineName, regressionOptions);
3364
3507
  // Print formatted report
3365
- const report = (0, browser_js_1.formatPerformanceRegressionReport)(result);
3508
+ const report = (0, index_js_3.formatPerformanceRegressionReport)(result);
3366
3509
  console.log("\n" + report);
3367
3510
  // Save JSON report if requested
3368
3511
  const fs = await import("fs");
@@ -3428,7 +3571,7 @@ async function main() {
3428
3571
  maxPages: 50, // Quick mode
3429
3572
  minCoverage: 50,
3430
3573
  };
3431
- const result = await (0, browser_js_1.generateCoverageMap)(url, testFiles, coverageOptions);
3574
+ const result = await (0, index_js_2.generateCoverageMap)(url, testFiles, coverageOptions);
3432
3575
  // Show only gaps
3433
3576
  console.log(`\nšŸ•³ļø Coverage Gaps (${result.gaps.length} found):\n`);
3434
3577
  const priorityEmoji = { critical: "🚨", high: "šŸ”“", medium: "🟔", low: "🟢" };
@@ -3474,10 +3617,10 @@ async function main() {
3474
3617
  else {
3475
3618
  console.log(` Crawling site (max ${coverageOptions.maxPages} pages)...`);
3476
3619
  }
3477
- const result = await (0, browser_js_1.generateCoverageMap)(url, testFiles, coverageOptions);
3620
+ const result = await (0, index_js_2.generateCoverageMap)(url, testFiles, coverageOptions);
3478
3621
  // Output format
3479
3622
  if (options.html) {
3480
- const htmlReport = (0, browser_js_1.generateCoverageHtmlReport)(result);
3623
+ const htmlReport = (0, index_js_2.generateCoverageHtmlReport)(result);
3481
3624
  const outputPath = options.output || "coverage-report.html";
3482
3625
  fs.writeFileSync(outputPath, htmlReport);
3483
3626
  console.log(`\nāœ… HTML report saved: ${outputPath}`);
@@ -3488,7 +3631,7 @@ async function main() {
3488
3631
  }
3489
3632
  else {
3490
3633
  // Print text report
3491
- const report = (0, browser_js_1.formatCoverageReport)(result);
3634
+ const report = (0, index_js_2.formatCoverageReport)(result);
3492
3635
  console.log(report);
3493
3636
  if (options.output) {
3494
3637
  fs.writeFileSync(options.output, report);