cbrowser 8.7.3 → 8.9.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 (62) hide show
  1. package/README.md +9 -2
  2. package/dist/analysis/bug-hunter.js +1 -4
  3. package/dist/analysis/bug-hunter.js.map +1 -1
  4. package/dist/analysis/chaos-testing.js +4 -8
  5. package/dist/analysis/chaos-testing.js.map +1 -1
  6. package/dist/analysis/index.js +4 -20
  7. package/dist/analysis/index.js.map +1 -1
  8. package/dist/analysis/natural-language.js +4 -10
  9. package/dist/analysis/natural-language.js.map +1 -1
  10. package/dist/analysis/persona-comparison.js +6 -10
  11. package/dist/analysis/persona-comparison.js.map +1 -1
  12. package/dist/browser.d.ts +50 -0
  13. package/dist/browser.d.ts.map +1 -1
  14. package/dist/browser.js +665 -131
  15. package/dist/browser.js.map +1 -1
  16. package/dist/cli.js +138 -131
  17. package/dist/cli.js.map +1 -1
  18. package/dist/cognitive/index.js +29 -40
  19. package/dist/cognitive/index.js.map +1 -1
  20. package/dist/config.js +50 -61
  21. package/dist/config.js.map +1 -1
  22. package/dist/daemon.js +28 -37
  23. package/dist/daemon.js.map +1 -1
  24. package/dist/index.js +10 -40
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp-server-remote.js +153 -156
  27. package/dist/mcp-server-remote.js.map +1 -1
  28. package/dist/mcp-server.js +146 -149
  29. package/dist/mcp-server.js.map +1 -1
  30. package/dist/performance/index.js +1 -17
  31. package/dist/performance/index.js.map +1 -1
  32. package/dist/performance/metrics.js +30 -39
  33. package/dist/performance/metrics.js.map +1 -1
  34. package/dist/personas.js +32 -46
  35. package/dist/personas.js.map +1 -1
  36. package/dist/testing/coverage.js +13 -23
  37. package/dist/testing/coverage.js.map +1 -1
  38. package/dist/testing/flaky-detection.js +4 -8
  39. package/dist/testing/flaky-detection.js.map +1 -1
  40. package/dist/testing/index.js +4 -20
  41. package/dist/testing/index.js.map +1 -1
  42. package/dist/testing/nl-test-suite.js +11 -19
  43. package/dist/testing/nl-test-suite.js.map +1 -1
  44. package/dist/testing/test-repair.js +9 -15
  45. package/dist/testing/test-repair.js.map +1 -1
  46. package/dist/types.js +3 -6
  47. package/dist/types.js.map +1 -1
  48. package/dist/version.d.ts +9 -0
  49. package/dist/version.d.ts.map +1 -0
  50. package/dist/version.js +60 -0
  51. package/dist/version.js.map +1 -0
  52. package/dist/visual/ab-comparison.js +16 -22
  53. package/dist/visual/ab-comparison.js.map +1 -1
  54. package/dist/visual/cross-browser.js +17 -24
  55. package/dist/visual/cross-browser.js.map +1 -1
  56. package/dist/visual/index.js +4 -20
  57. package/dist/visual/index.js.map +1 -1
  58. package/dist/visual/regression.js +46 -58
  59. package/dist/visual/regression.js.map +1 -1
  60. package/dist/visual/responsive.js +22 -29
  61. package/dist/visual/responsive.js.map +1 -1
  62. package/package.json +2 -1
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
2
  /**
4
3
  * CBrowser Remote MCP Server
5
4
  *
@@ -23,33 +22,31 @@
23
22
  * AUTH0_AUDIENCE - API audience/identifier (e.g., 'https://cbrowser-mcp.wyldfyre.ai')
24
23
  * AUTH0_CLIENT_ID - Optional: Client ID for static registration
25
24
  */
26
- Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.startRemoteMcpServer = startRemoteMcpServer;
28
- const node_http_1 = require("node:http");
29
- const node_crypto_1 = require("node:crypto");
30
- const jose_1 = require("jose");
31
- const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
32
- const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
33
- const zod_1 = require("zod");
34
- const browser_js_1 = require("./browser.js");
35
- const config_js_1 = require("./config.js");
25
+ import { createServer } from "node:http";
26
+ import { randomUUID } from "node:crypto";
27
+ import { createRemoteJWKSet, jwtVerify } from "jose";
28
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
29
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
30
+ import { z } from "zod";
31
+ import { CBrowser } from "./browser.js";
32
+ import { ensureDirectories, getStatusInfo } from "./config.js";
36
33
  // Visual module imports
37
- const index_js_1 = require("./visual/index.js");
34
+ import { runVisualRegression, runCrossBrowserTest, runResponsiveTest, runABComparison, crossBrowserDiff, captureVisualBaseline, listVisualBaselines, } from "./visual/index.js";
38
35
  // Testing module imports
39
- const index_js_2 = require("./testing/index.js");
36
+ import { runNLTestSuite, parseNLTestSuite, dryRunNLTestSuite, repairTest, detectFlakyTests, generateCoverageMap, } from "./testing/index.js";
40
37
  // Analysis module imports
41
- const index_js_3 = require("./analysis/index.js");
38
+ import { huntBugs, runChaosTest, comparePersonas, findElementByIntent, } from "./analysis/index.js";
42
39
  // Persona imports for cognitive journey
43
- const personas_js_1 = require("./personas.js");
40
+ import { getPersona, listPersonas, getCognitiveProfile, createCognitivePersona, } from "./personas.js";
44
41
  // Performance module imports
45
- const index_js_4 = require("./performance/index.js");
46
- // Version constant - keep in sync with package.json
47
- const VERSION = "8.7.0";
42
+ import { capturePerformanceBaseline, detectPerformanceRegression, listPerformanceBaselines, } from "./performance/index.js";
43
+ // Version from package.json - single source of truth
44
+ import { VERSION } from "./version.js";
48
45
  // Shared browser instance
49
46
  let browser = null;
50
47
  async function getBrowser() {
51
48
  if (!browser) {
52
- browser = new browser_js_1.CBrowser({
49
+ browser = new CBrowser({
53
50
  headless: true,
54
51
  persistent: true,
55
52
  });
@@ -76,7 +73,7 @@ function getAuth0Config() {
76
73
  domain,
77
74
  audience,
78
75
  clientId: process.env.AUTH0_CLIENT_ID,
79
- jwks: (0, jose_1.createRemoteJWKSet)(new URL(`https://${domain}/.well-known/jwks.json`)),
76
+ jwks: createRemoteJWKSet(new URL(`https://${domain}/.well-known/jwks.json`)),
80
77
  };
81
78
  }
82
79
  return auth0Config;
@@ -99,7 +96,7 @@ async function validateAuth0Token(token) {
99
96
  // If it's a proper JWT (3 parts), validate locally
100
97
  if (tokenParts.length === 3) {
101
98
  try {
102
- const { payload } = await (0, jose_1.jwtVerify)(token, config.jwks, {
99
+ const { payload } = await jwtVerify(token, config.jwks, {
103
100
  issuer: `https://${config.domain}/`,
104
101
  audience: config.audience,
105
102
  });
@@ -255,7 +252,7 @@ function configureMcpTools(server) {
255
252
  // Navigation Tools
256
253
  // =========================================================================
257
254
  server.tool("navigate", "Navigate to a URL and take a screenshot", {
258
- url: zod_1.z.string().url().describe("The URL to navigate to"),
255
+ url: z.string().url().describe("The URL to navigate to"),
259
256
  }, async ({ url }) => {
260
257
  const b = await getBrowser();
261
258
  const result = await b.navigate(url);
@@ -278,9 +275,9 @@ function configureMcpTools(server) {
278
275
  // Interaction Tools
279
276
  // =========================================================================
280
277
  server.tool("click", "Click an element on the page using text, selector, or description. Use verbose=true for detailed debug info on failure.", {
281
- selector: zod_1.z.string().describe("Element to click (text content, CSS selector, or description)"),
282
- force: zod_1.z.boolean().optional().describe("Bypass safety checks for destructive actions"),
283
- verbose: zod_1.z.boolean().optional().describe("Return available elements and AI suggestions on failure"),
278
+ selector: z.string().describe("Element to click (text content, CSS selector, or description)"),
279
+ force: z.boolean().optional().describe("Bypass safety checks for destructive actions"),
280
+ verbose: z.boolean().optional().describe("Return available elements and AI suggestions on failure"),
284
281
  }, async ({ selector, force, verbose }) => {
285
282
  const b = await getBrowser();
286
283
  const result = await b.click(selector, { force, verbose });
@@ -302,9 +299,9 @@ function configureMcpTools(server) {
302
299
  };
303
300
  });
304
301
  server.tool("smart_click", "Click with auto-retry and self-healing selectors", {
305
- selector: zod_1.z.string().describe("Element to click"),
306
- maxRetries: zod_1.z.number().optional().default(3).describe("Maximum retry attempts"),
307
- dismissOverlays: zod_1.z.boolean().optional().default(false).describe("Dismiss overlays before clicking"),
302
+ selector: z.string().describe("Element to click"),
303
+ maxRetries: z.number().optional().default(3).describe("Maximum retry attempts"),
304
+ dismissOverlays: z.boolean().optional().default(false).describe("Dismiss overlays before clicking"),
308
305
  }, async ({ selector, maxRetries, dismissOverlays }) => {
309
306
  const b = await getBrowser();
310
307
  const result = await b.smartClick(selector, { maxRetries, dismissOverlays });
@@ -324,8 +321,8 @@ function configureMcpTools(server) {
324
321
  };
325
322
  });
326
323
  server.tool("dismiss_overlay", "Detect and dismiss modal overlays (cookie consent, age verification, newsletter popups). Constitutional Yellow zone.", {
327
- type: zod_1.z.enum(["auto", "cookie", "age-verify", "newsletter", "custom"]).optional().default("auto").describe("Overlay type to detect"),
328
- customSelector: zod_1.z.string().optional().describe("Custom CSS selector for overlay close button"),
324
+ type: z.enum(["auto", "cookie", "age-verify", "newsletter", "custom"]).optional().default("auto").describe("Overlay type to detect"),
325
+ customSelector: z.string().optional().describe("Custom CSS selector for overlay close button"),
329
326
  }, async ({ type, customSelector }) => {
330
327
  const b = await getBrowser();
331
328
  const result = await b.dismissOverlay({ type, customSelector });
@@ -345,9 +342,9 @@ function configureMcpTools(server) {
345
342
  };
346
343
  });
347
344
  server.tool("fill", "Fill a form field with text. Use verbose=true for detailed debug info on failure.", {
348
- selector: zod_1.z.string().describe("Input field to fill (name, placeholder, label, or selector)"),
349
- value: zod_1.z.string().describe("Value to enter"),
350
- verbose: zod_1.z.boolean().optional().describe("Return available inputs and AI suggestions on failure"),
345
+ selector: z.string().describe("Input field to fill (name, placeholder, label, or selector)"),
346
+ value: z.string().describe("Value to enter"),
347
+ verbose: z.boolean().optional().describe("Return available inputs and AI suggestions on failure"),
351
348
  }, async ({ selector, value, verbose }) => {
352
349
  const b = await getBrowser();
353
350
  const result = await b.fill(selector, value, { verbose });
@@ -371,7 +368,7 @@ function configureMcpTools(server) {
371
368
  // Extraction Tools
372
369
  // =========================================================================
373
370
  server.tool("screenshot", "Take a screenshot of the current page", {
374
- path: zod_1.z.string().optional().describe("Optional path to save the screenshot"),
371
+ path: z.string().optional().describe("Optional path to save the screenshot"),
375
372
  }, async ({ path }) => {
376
373
  const b = await getBrowser();
377
374
  const file = await b.screenshot(path);
@@ -385,7 +382,7 @@ function configureMcpTools(server) {
385
382
  };
386
383
  });
387
384
  server.tool("extract", "Extract data from the page", {
388
- what: zod_1.z.enum(["links", "headings", "forms", "images", "text"]).describe("What to extract"),
385
+ what: z.enum(["links", "headings", "forms", "images", "text"]).describe("What to extract"),
389
386
  }, async ({ what }) => {
390
387
  const b = await getBrowser();
391
388
  const result = await b.extract(what);
@@ -402,7 +399,7 @@ function configureMcpTools(server) {
402
399
  // Assertion Tools
403
400
  // =========================================================================
404
401
  server.tool("assert", "Assert a condition using natural language", {
405
- assertion: zod_1.z.string().describe("Natural language assertion like \"page contains 'Welcome'\" or \"title is 'Home'\""),
402
+ assertion: z.string().describe("Natural language assertion like \"page contains 'Welcome'\" or \"title is 'Home'\""),
406
403
  }, async ({ assertion }) => {
407
404
  const b = await getBrowser();
408
405
  const result = await b.assert(assertion);
@@ -444,7 +441,7 @@ function configureMcpTools(server) {
444
441
  };
445
442
  });
446
443
  server.tool("generate_tests", "Generate test scenarios for a page", {
447
- url: zod_1.z.string().url().optional().describe("URL to analyze (uses current page if not provided)"),
444
+ url: z.string().url().optional().describe("URL to analyze (uses current page if not provided)"),
448
445
  }, async ({ url }) => {
449
446
  const b = await getBrowser();
450
447
  const result = await b.generateTests(url);
@@ -468,7 +465,7 @@ function configureMcpTools(server) {
468
465
  // Session Tools
469
466
  // =========================================================================
470
467
  server.tool("save_session", "Save browser session (cookies, storage) for later use", {
471
- name: zod_1.z.string().describe("Name for the saved session"),
468
+ name: z.string().describe("Name for the saved session"),
472
469
  }, async ({ name }) => {
473
470
  const b = await getBrowser();
474
471
  await b.saveSession(name);
@@ -482,7 +479,7 @@ function configureMcpTools(server) {
482
479
  };
483
480
  });
484
481
  server.tool("load_session", "Load a previously saved session", {
485
- name: zod_1.z.string().describe("Name of the session to load"),
482
+ name: z.string().describe("Name of the session to load"),
486
483
  }, async ({ name }) => {
487
484
  const b = await getBrowser();
488
485
  const loaded = await b.loadSession(name);
@@ -508,7 +505,7 @@ function configureMcpTools(server) {
508
505
  };
509
506
  });
510
507
  server.tool("delete_session", "Delete a saved session by name", {
511
- name: zod_1.z.string().describe("Name of the session to delete"),
508
+ name: z.string().describe("Name of the session to delete"),
512
509
  }, async ({ name }) => {
513
510
  const b = await getBrowser();
514
511
  const deleted = b.deleteSession(name);
@@ -540,10 +537,10 @@ function configureMcpTools(server) {
540
537
  // Visual Testing Tools (v7.0.0+)
541
538
  // =========================================================================
542
539
  server.tool("visual_baseline", "Capture a visual baseline for a URL", {
543
- url: zod_1.z.string().url().describe("URL to capture baseline for"),
544
- name: zod_1.z.string().describe("Name for the baseline"),
540
+ url: z.string().url().describe("URL to capture baseline for"),
541
+ name: z.string().describe("Name for the baseline"),
545
542
  }, async ({ url, name }) => {
546
- const result = await (0, index_js_1.captureVisualBaseline)(url, name, {});
543
+ const result = await captureVisualBaseline(url, name, {});
547
544
  return {
548
545
  content: [
549
546
  {
@@ -559,10 +556,10 @@ function configureMcpTools(server) {
559
556
  };
560
557
  });
561
558
  server.tool("visual_regression", "Run AI visual regression test against a baseline", {
562
- url: zod_1.z.string().url().describe("URL to test"),
563
- baselineName: zod_1.z.string().describe("Name of baseline to compare against"),
559
+ url: z.string().url().describe("URL to test"),
560
+ baselineName: z.string().describe("Name of baseline to compare against"),
564
561
  }, async ({ url, baselineName }) => {
565
- const result = await (0, index_js_1.runVisualRegression)(url, baselineName);
562
+ const result = await runVisualRegression(url, baselineName);
566
563
  return {
567
564
  content: [
568
565
  {
@@ -578,10 +575,10 @@ function configureMcpTools(server) {
578
575
  };
579
576
  });
580
577
  server.tool("cross_browser_test", "Test page rendering across multiple browsers", {
581
- url: zod_1.z.string().url().describe("URL to test"),
582
- browsers: zod_1.z.array(zod_1.z.enum(["chromium", "firefox", "webkit"])).optional().describe("Browsers to test"),
578
+ url: z.string().url().describe("URL to test"),
579
+ browsers: z.array(z.enum(["chromium", "firefox", "webkit"])).optional().describe("Browsers to test"),
583
580
  }, async ({ url, browsers }) => {
584
- const result = await (0, index_js_1.runCrossBrowserTest)(url, { browsers });
581
+ const result = await runCrossBrowserTest(url, { browsers });
585
582
  return {
586
583
  content: [
587
584
  {
@@ -601,10 +598,10 @@ function configureMcpTools(server) {
601
598
  };
602
599
  });
603
600
  server.tool("cross_browser_diff", "Quick diff of page metrics across browsers", {
604
- url: zod_1.z.string().url().describe("URL to compare"),
605
- browsers: zod_1.z.array(zod_1.z.enum(["chromium", "firefox", "webkit"])).optional().describe("Browsers to compare"),
601
+ url: z.string().url().describe("URL to compare"),
602
+ browsers: z.array(z.enum(["chromium", "firefox", "webkit"])).optional().describe("Browsers to compare"),
606
603
  }, async ({ url, browsers }) => {
607
- const result = await (0, index_js_1.crossBrowserDiff)(url, browsers);
604
+ const result = await crossBrowserDiff(url, browsers);
608
605
  return {
609
606
  content: [
610
607
  {
@@ -623,10 +620,10 @@ function configureMcpTools(server) {
623
620
  };
624
621
  });
625
622
  server.tool("responsive_test", "Test page across different viewport sizes", {
626
- url: zod_1.z.string().url().describe("URL to test"),
627
- viewports: zod_1.z.array(zod_1.z.string()).optional().describe("Viewport presets (mobile, tablet, desktop, etc.)"),
623
+ url: z.string().url().describe("URL to test"),
624
+ viewports: z.array(z.string()).optional().describe("Viewport presets (mobile, tablet, desktop, etc.)"),
628
625
  }, async ({ url, viewports }) => {
629
- const result = await (0, index_js_1.runResponsiveTest)(url, { viewports });
626
+ const result = await runResponsiveTest(url, { viewports });
630
627
  return {
631
628
  content: [
632
629
  {
@@ -642,13 +639,13 @@ function configureMcpTools(server) {
642
639
  };
643
640
  });
644
641
  server.tool("ab_comparison", "Compare two URLs visually (staging vs production)", {
645
- urlA: zod_1.z.string().url().describe("First URL (e.g., staging)"),
646
- urlB: zod_1.z.string().url().describe("Second URL (e.g., production)"),
647
- labelA: zod_1.z.string().optional().describe("Label for first URL"),
648
- labelB: zod_1.z.string().optional().describe("Label for second URL"),
642
+ urlA: z.string().url().describe("First URL (e.g., staging)"),
643
+ urlB: z.string().url().describe("Second URL (e.g., production)"),
644
+ labelA: z.string().optional().describe("Label for first URL"),
645
+ labelB: z.string().optional().describe("Label for second URL"),
649
646
  }, async ({ urlA, urlB, labelA, labelB }) => {
650
647
  const labels = labelA && labelB ? { a: labelA, b: labelB } : undefined;
651
- const result = await (0, index_js_1.runABComparison)(urlA, urlB, { labels });
648
+ const result = await runABComparison(urlA, urlB, { labels });
652
649
  return {
653
650
  content: [
654
651
  {
@@ -667,9 +664,9 @@ function configureMcpTools(server) {
667
664
  // Testing Tools (v6.0.0+)
668
665
  // =========================================================================
669
666
  server.tool("nl_test_file", "Run natural language test suite from a file. Returns step-level results with enriched error info, partial matches, and suggestions.", {
670
- filepath: zod_1.z.string().describe("Path to the test file"),
671
- dryRun: zod_1.z.boolean().optional().describe("Parse and display steps without executing"),
672
- fuzzyMatch: zod_1.z.boolean().optional().describe("Use case-insensitive fuzzy matching for assertions"),
667
+ filepath: z.string().describe("Path to the test file"),
668
+ dryRun: z.boolean().optional().describe("Parse and display steps without executing"),
669
+ fuzzyMatch: z.boolean().optional().describe("Use case-insensitive fuzzy matching for assertions"),
673
670
  }, async ({ filepath, dryRun, fuzzyMatch }) => {
674
671
  const fs = await import("fs");
675
672
  if (!fs.existsSync(filepath)) {
@@ -677,12 +674,12 @@ function configureMcpTools(server) {
677
674
  }
678
675
  const fileContent = fs.readFileSync(filepath, "utf-8");
679
676
  const suiteName = filepath.split("/").pop()?.replace(/\.[^.]+$/, "") || "Test Suite";
680
- const suite = (0, index_js_2.parseNLTestSuite)(fileContent, suiteName);
677
+ const suite = parseNLTestSuite(fileContent, suiteName);
681
678
  if (dryRun) {
682
- const dryResult = (0, index_js_2.dryRunNLTestSuite)(suite);
679
+ const dryResult = dryRunNLTestSuite(suite);
683
680
  return { content: [{ type: "text", text: JSON.stringify(dryResult, null, 2) }] };
684
681
  }
685
- const result = await (0, index_js_2.runNLTestSuite)(suite, { fuzzyMatch: fuzzyMatch || false });
682
+ const result = await runNLTestSuite(suite, { fuzzyMatch: fuzzyMatch || false });
686
683
  return {
687
684
  content: [
688
685
  {
@@ -715,17 +712,17 @@ function configureMcpTools(server) {
715
712
  };
716
713
  });
717
714
  server.tool("nl_test_inline", "Run natural language tests from inline content. Returns step-level results with enriched error info, partial matches, and suggestions.", {
718
- content: zod_1.z.string().describe("Test content with instructions like 'go to https://...' and 'click login'"),
719
- name: zod_1.z.string().optional().describe("Name for the test suite"),
720
- dryRun: zod_1.z.boolean().optional().describe("Parse and display steps without executing"),
721
- fuzzyMatch: zod_1.z.boolean().optional().describe("Use case-insensitive fuzzy matching for assertions"),
715
+ content: z.string().describe("Test content with instructions like 'go to https://...' and 'click login'"),
716
+ name: z.string().optional().describe("Name for the test suite"),
717
+ dryRun: z.boolean().optional().describe("Parse and display steps without executing"),
718
+ fuzzyMatch: z.boolean().optional().describe("Use case-insensitive fuzzy matching for assertions"),
722
719
  }, async ({ content, name, dryRun, fuzzyMatch }) => {
723
- const suite = (0, index_js_2.parseNLTestSuite)(content, name || "Inline Test");
720
+ const suite = parseNLTestSuite(content, name || "Inline Test");
724
721
  if (dryRun) {
725
- const dryResult = (0, index_js_2.dryRunNLTestSuite)(suite);
722
+ const dryResult = dryRunNLTestSuite(suite);
726
723
  return { content: [{ type: "text", text: JSON.stringify(dryResult, null, 2) }] };
727
724
  }
728
- const result = await (0, index_js_2.runNLTestSuite)(suite, { fuzzyMatch: fuzzyMatch || false });
725
+ const result = await runNLTestSuite(suite, { fuzzyMatch: fuzzyMatch || false });
729
726
  return {
730
727
  content: [
731
728
  {
@@ -758,9 +755,9 @@ function configureMcpTools(server) {
758
755
  };
759
756
  });
760
757
  server.tool("repair_test", "AI-powered test repair for broken tests", {
761
- testName: zod_1.z.string().describe("Name for the test"),
762
- steps: zod_1.z.array(zod_1.z.string()).describe("Test step instructions"),
763
- autoApply: zod_1.z.boolean().optional().describe("Automatically apply repairs"),
758
+ testName: z.string().describe("Name for the test"),
759
+ steps: z.array(z.string()).describe("Test step instructions"),
760
+ autoApply: z.boolean().optional().describe("Automatically apply repairs"),
764
761
  }, async ({ testName, steps, autoApply }) => {
765
762
  const testCase = {
766
763
  name: testName,
@@ -769,7 +766,7 @@ function configureMcpTools(server) {
769
766
  action: "unknown",
770
767
  })),
771
768
  };
772
- const result = await (0, index_js_2.repairTest)(testCase, { autoApply: autoApply || false });
769
+ const result = await repairTest(testCase, { autoApply: autoApply || false });
773
770
  return {
774
771
  content: [
775
772
  {
@@ -790,12 +787,12 @@ function configureMcpTools(server) {
790
787
  };
791
788
  });
792
789
  server.tool("detect_flaky_tests", "Detect flaky/unreliable tests by running multiple times", {
793
- testContent: zod_1.z.string().describe("Test content to analyze"),
794
- runs: zod_1.z.number().optional().default(5).describe("Number of times to run each test"),
795
- threshold: zod_1.z.number().optional().default(20).describe("Flakiness threshold percentage"),
790
+ testContent: z.string().describe("Test content to analyze"),
791
+ runs: z.number().optional().default(5).describe("Number of times to run each test"),
792
+ threshold: z.number().optional().default(20).describe("Flakiness threshold percentage"),
796
793
  }, async ({ testContent, runs, threshold }) => {
797
- const suite = (0, index_js_2.parseNLTestSuite)(testContent, "Flaky Test Analysis");
798
- const result = await (0, index_js_2.detectFlakyTests)(suite, { runs, flakinessThreshold: threshold });
794
+ const suite = parseNLTestSuite(testContent, "Flaky Test Analysis");
795
+ const result = await detectFlakyTests(suite, { runs, flakinessThreshold: threshold });
799
796
  return {
800
797
  content: [
801
798
  {
@@ -819,11 +816,11 @@ function configureMcpTools(server) {
819
816
  };
820
817
  });
821
818
  server.tool("coverage_map", "Generate test coverage map for a site", {
822
- baseUrl: zod_1.z.string().url().describe("Base URL to analyze"),
823
- testFiles: zod_1.z.array(zod_1.z.string()).describe("Array of test file paths"),
824
- maxPages: zod_1.z.number().optional().default(100).describe("Maximum pages to crawl"),
819
+ baseUrl: z.string().url().describe("Base URL to analyze"),
820
+ testFiles: z.array(z.string()).describe("Array of test file paths"),
821
+ maxPages: z.number().optional().default(100).describe("Maximum pages to crawl"),
825
822
  }, async ({ baseUrl, testFiles, maxPages }) => {
826
- const result = await (0, index_js_2.generateCoverageMap)(baseUrl, testFiles, { maxPages });
823
+ const result = await generateCoverageMap(baseUrl, testFiles, { maxPages });
827
824
  return {
828
825
  content: [
829
826
  {
@@ -847,12 +844,12 @@ function configureMcpTools(server) {
847
844
  // Analysis Tools (v4.0.0+)
848
845
  // =========================================================================
849
846
  server.tool("hunt_bugs", "Autonomous bug hunting - crawl and find issues. Returns bugs with severity, selector, and actionable recommendation for each issue found.", {
850
- url: zod_1.z.string().url().describe("Starting URL to hunt from"),
851
- maxPages: zod_1.z.number().optional().default(10).describe("Maximum pages to visit"),
852
- timeout: zod_1.z.number().optional().default(60000).describe("Timeout in milliseconds"),
847
+ url: z.string().url().describe("Starting URL to hunt from"),
848
+ maxPages: z.number().optional().default(10).describe("Maximum pages to visit"),
849
+ timeout: z.number().optional().default(60000).describe("Timeout in milliseconds"),
853
850
  }, async ({ url, maxPages, timeout }) => {
854
851
  const b = await getBrowser();
855
- const result = await (0, index_js_3.huntBugs)(b, url, { maxPages, timeout });
852
+ const result = await huntBugs(b, url, { maxPages, timeout });
856
853
  return {
857
854
  content: [
858
855
  {
@@ -875,13 +872,13 @@ function configureMcpTools(server) {
875
872
  };
876
873
  });
877
874
  server.tool("chaos_test", "Inject failures and test resilience", {
878
- url: zod_1.z.string().url().describe("URL to test"),
879
- networkLatency: zod_1.z.number().optional().describe("Simulate network latency (ms)"),
880
- offline: zod_1.z.boolean().optional().describe("Simulate offline mode"),
881
- blockUrls: zod_1.z.array(zod_1.z.string()).optional().describe("URL patterns to block"),
875
+ url: z.string().url().describe("URL to test"),
876
+ networkLatency: z.number().optional().describe("Simulate network latency (ms)"),
877
+ offline: z.boolean().optional().describe("Simulate offline mode"),
878
+ blockUrls: z.array(z.string()).optional().describe("URL patterns to block"),
882
879
  }, async ({ url, networkLatency, offline, blockUrls }) => {
883
880
  const b = await getBrowser();
884
- const result = await (0, index_js_3.runChaosTest)(b, url, { networkLatency, offline, blockUrls });
881
+ const result = await runChaosTest(b, url, { networkLatency, offline, blockUrls });
885
882
  return {
886
883
  content: [
887
884
  {
@@ -896,11 +893,11 @@ function configureMcpTools(server) {
896
893
  };
897
894
  });
898
895
  server.tool("compare_personas", "Compare how different user personas experience a journey", {
899
- url: zod_1.z.string().url().describe("Starting URL"),
900
- goal: zod_1.z.string().describe("Goal to accomplish"),
901
- personas: zod_1.z.array(zod_1.z.string()).describe("Persona names to compare"),
896
+ url: z.string().url().describe("Starting URL"),
897
+ goal: z.string().describe("Goal to accomplish"),
898
+ personas: z.array(z.string()).describe("Persona names to compare"),
902
899
  }, async ({ url, goal, personas }) => {
903
- const result = await (0, index_js_3.comparePersonas)({
900
+ const result = await comparePersonas({
904
901
  startUrl: url,
905
902
  goal,
906
903
  personas,
@@ -920,11 +917,11 @@ function configureMcpTools(server) {
920
917
  };
921
918
  });
922
919
  server.tool("find_element_by_intent", "AI-powered semantic element finding with ARIA-first selector strategy. Prioritizes aria-label > role > semantic HTML > ID > name > class. Returns selectorType, accessibilityScore (0-1), and alternatives. Use verbose=true for enriched failure responses.", {
923
- intent: zod_1.z.string().describe("Natural language description like 'the cheapest product' or 'login form'"),
924
- verbose: zod_1.z.boolean().optional().describe("Include alternative matches with confidence scores and AI suggestions"),
920
+ intent: z.string().describe("Natural language description like 'the cheapest product' or 'login form'"),
921
+ verbose: z.boolean().optional().describe("Include alternative matches with confidence scores and AI suggestions"),
925
922
  }, async ({ intent, verbose }) => {
926
923
  const b = await getBrowser();
927
- const result = await (0, index_js_3.findElementByIntent)(b, intent, { verbose });
924
+ const result = await findElementByIntent(b, intent, { verbose });
928
925
  if (result && result.confidence > 0) {
929
926
  return {
930
927
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -938,25 +935,25 @@ function configureMcpTools(server) {
938
935
  // Cognitive Simulation Tools (v8.3.0)
939
936
  // =========================================================================
940
937
  server.tool("cognitive_journey_init", "Initialize a cognitive user journey simulation. Returns the persona's cognitive profile, initial state, and abandonment thresholds. The actual simulation is driven by the LLM using browser tools (navigate, click, fill, screenshot) while tracking cognitive state.", {
941
- persona: zod_1.z.string().describe("Persona name (e.g., 'first-timer', 'elderly-user', 'power-user') or custom description"),
942
- goal: zod_1.z.string().describe("What the simulated user is trying to accomplish"),
943
- startUrl: zod_1.z.string().url().describe("Starting URL for the journey"),
944
- customTraits: zod_1.z.object({
945
- patience: zod_1.z.number().min(0).max(1).optional(),
946
- riskTolerance: zod_1.z.number().min(0).max(1).optional(),
947
- comprehension: zod_1.z.number().min(0).max(1).optional(),
948
- persistence: zod_1.z.number().min(0).max(1).optional(),
949
- curiosity: zod_1.z.number().min(0).max(1).optional(),
950
- workingMemory: zod_1.z.number().min(0).max(1).optional(),
951
- readingTendency: zod_1.z.number().min(0).max(1).optional(),
938
+ persona: z.string().describe("Persona name (e.g., 'first-timer', 'elderly-user', 'power-user') or custom description"),
939
+ goal: z.string().describe("What the simulated user is trying to accomplish"),
940
+ startUrl: z.string().url().describe("Starting URL for the journey"),
941
+ customTraits: z.object({
942
+ patience: z.number().min(0).max(1).optional(),
943
+ riskTolerance: z.number().min(0).max(1).optional(),
944
+ comprehension: z.number().min(0).max(1).optional(),
945
+ persistence: z.number().min(0).max(1).optional(),
946
+ curiosity: z.number().min(0).max(1).optional(),
947
+ workingMemory: z.number().min(0).max(1).optional(),
948
+ readingTendency: z.number().min(0).max(1).optional(),
952
949
  }).optional().describe("Override specific cognitive traits"),
953
950
  }, async ({ persona: personaName, goal, startUrl, customTraits }) => {
954
951
  // Get or create persona
955
- const existingPersona = (0, personas_js_1.getPersona)(personaName);
952
+ const existingPersona = getPersona(personaName);
956
953
  let personaObj;
957
954
  if (!existingPersona) {
958
955
  // Create from description
959
- personaObj = (0, personas_js_1.createCognitivePersona)(personaName, personaName, customTraits || {});
956
+ personaObj = createCognitivePersona(personaName, personaName, customTraits || {});
960
957
  }
961
958
  else if (customTraits) {
962
959
  // Merge custom traits with defaults
@@ -982,7 +979,7 @@ function configureMcpTools(server) {
982
979
  personaObj = existingPersona;
983
980
  }
984
981
  // Get cognitive profile
985
- const profile = (0, personas_js_1.getCognitiveProfile)(personaObj);
982
+ const profile = getCognitiveProfile(personaObj);
986
983
  // Initial cognitive state
987
984
  const initialState = {
988
985
  patienceRemaining: 1.0,
@@ -1070,27 +1067,27 @@ Begin the simulation now. Narrate your thoughts as this persona.
1070
1067
  };
1071
1068
  });
1072
1069
  server.tool("cognitive_journey_update_state", "Update the cognitive state during a journey simulation. Call this after each action to track mental state.", {
1073
- currentState: zod_1.z.object({
1074
- patienceRemaining: zod_1.z.number(),
1075
- confusionLevel: zod_1.z.number(),
1076
- frustrationLevel: zod_1.z.number(),
1077
- goalProgress: zod_1.z.number(),
1078
- confidenceLevel: zod_1.z.number(),
1079
- currentMood: zod_1.z.enum(["neutral", "hopeful", "confused", "frustrated", "defeated", "relieved"]),
1080
- stepCount: zod_1.z.number(),
1081
- timeElapsed: zod_1.z.number(),
1070
+ currentState: z.object({
1071
+ patienceRemaining: z.number(),
1072
+ confusionLevel: z.number(),
1073
+ frustrationLevel: z.number(),
1074
+ goalProgress: z.number(),
1075
+ confidenceLevel: z.number(),
1076
+ currentMood: z.enum(["neutral", "hopeful", "confused", "frustrated", "defeated", "relieved"]),
1077
+ stepCount: z.number(),
1078
+ timeElapsed: z.number(),
1082
1079
  }).describe("Current cognitive state"),
1083
- actionResult: zod_1.z.object({
1084
- success: zod_1.z.boolean(),
1085
- wasConfusing: zod_1.z.boolean().optional(),
1086
- progressMade: zod_1.z.boolean().optional(),
1087
- wentBack: zod_1.z.boolean().optional(),
1080
+ actionResult: z.object({
1081
+ success: z.boolean(),
1082
+ wasConfusing: z.boolean().optional(),
1083
+ progressMade: z.boolean().optional(),
1084
+ wentBack: z.boolean().optional(),
1088
1085
  }).describe("Result of the last action"),
1089
- personaTraits: zod_1.z.object({
1090
- patience: zod_1.z.number(),
1091
- riskTolerance: zod_1.z.number(),
1092
- comprehension: zod_1.z.number(),
1093
- persistence: zod_1.z.number(),
1086
+ personaTraits: z.object({
1087
+ patience: z.number(),
1088
+ riskTolerance: z.number(),
1089
+ comprehension: z.number(),
1090
+ persistence: z.number(),
1094
1091
  }).describe("Persona traits affecting state changes"),
1095
1092
  }, async ({ currentState, actionResult, personaTraits }) => {
1096
1093
  // Calculate new state based on action result
@@ -1180,12 +1177,12 @@ Begin the simulation now. Narrate your thoughts as this persona.
1180
1177
  };
1181
1178
  });
1182
1179
  server.tool("list_cognitive_personas", "List all available personas with their cognitive traits", {}, async () => {
1183
- const names = (0, personas_js_1.listPersonas)();
1180
+ const names = listPersonas();
1184
1181
  const personas = names.map(name => {
1185
- const p = (0, personas_js_1.getPersona)(name);
1182
+ const p = getPersona(name);
1186
1183
  if (!p)
1187
1184
  return null;
1188
- const profile = (0, personas_js_1.getCognitiveProfile)(p);
1185
+ const profile = getCognitiveProfile(p);
1189
1186
  return {
1190
1187
  name: p.name,
1191
1188
  description: p.description,
@@ -1208,11 +1205,11 @@ Begin the simulation now. Narrate your thoughts as this persona.
1208
1205
  // Performance Tools (v6.4.0+)
1209
1206
  // =========================================================================
1210
1207
  server.tool("perf_baseline", "Capture performance baseline for a URL", {
1211
- url: zod_1.z.string().url().describe("URL to capture baseline for"),
1212
- name: zod_1.z.string().describe("Name for the baseline"),
1213
- runs: zod_1.z.number().optional().default(3).describe("Number of runs to average"),
1208
+ url: z.string().url().describe("URL to capture baseline for"),
1209
+ name: z.string().describe("Name for the baseline"),
1210
+ runs: z.number().optional().default(3).describe("Number of runs to average"),
1214
1211
  }, async ({ url, name, runs }) => {
1215
- const result = await (0, index_js_4.capturePerformanceBaseline)(url, { name, runs });
1212
+ const result = await capturePerformanceBaseline(url, { name, runs });
1216
1213
  return {
1217
1214
  content: [
1218
1215
  {
@@ -1230,12 +1227,12 @@ Begin the simulation now. Narrate your thoughts as this persona.
1230
1227
  };
1231
1228
  });
1232
1229
  server.tool("perf_regression", "Detect performance regression against baseline with configurable sensitivity. Uses dual thresholds: both percentage AND absolute change must be exceeded. Profiles: strict (CI/CD, FCP 10%/50ms), normal (default, FCP 20%/100ms), lenient (dev, FCP 30%/200ms). Sub-50ms FCP variations ignored by default.", {
1233
- url: zod_1.z.string().url().describe("URL to test"),
1234
- baselineName: zod_1.z.string().describe("Name of baseline to compare against"),
1235
- sensitivity: zod_1.z.enum(["strict", "normal", "lenient"]).optional().default("normal").describe("Sensitivity profile: strict (CI/CD), normal (default), lenient (development)"),
1236
- thresholdLcp: zod_1.z.number().optional().describe("Override LCP threshold percentage"),
1230
+ url: z.string().url().describe("URL to test"),
1231
+ baselineName: z.string().describe("Name of baseline to compare against"),
1232
+ sensitivity: z.enum(["strict", "normal", "lenient"]).optional().default("normal").describe("Sensitivity profile: strict (CI/CD), normal (default), lenient (development)"),
1233
+ thresholdLcp: z.number().optional().describe("Override LCP threshold percentage"),
1237
1234
  }, async ({ url, baselineName, sensitivity, thresholdLcp }) => {
1238
- const result = await (0, index_js_4.detectPerformanceRegression)(url, baselineName, {
1235
+ const result = await detectPerformanceRegression(url, baselineName, {
1239
1236
  sensitivity,
1240
1237
  thresholds: thresholdLcp ? { lcp: thresholdLcp } : undefined,
1241
1238
  });
@@ -1256,8 +1253,8 @@ Begin the simulation now. Narrate your thoughts as this persona.
1256
1253
  };
1257
1254
  });
1258
1255
  server.tool("list_baselines", "List all saved baselines (visual and performance)", {}, async () => {
1259
- const visualBaselines = await (0, index_js_1.listVisualBaselines)();
1260
- const perfBaselines = await (0, index_js_4.listPerformanceBaselines)();
1256
+ const visualBaselines = await listVisualBaselines();
1257
+ const perfBaselines = await listPerformanceBaselines();
1261
1258
  return {
1262
1259
  content: [
1263
1260
  {
@@ -1272,7 +1269,7 @@ Begin the simulation now. Narrate your thoughts as this persona.
1272
1269
  });
1273
1270
  // Diagnostics
1274
1271
  server.tool("status", "Get CBrowser environment status and diagnostics including data directories, installed browsers, configuration, and self-healing cache statistics", {}, async () => {
1275
- const info = await (0, config_js_1.getStatusInfo)(VERSION);
1272
+ const info = await getStatusInfo(VERSION);
1276
1273
  return {
1277
1274
  content: [
1278
1275
  {
@@ -1287,7 +1284,7 @@ Begin the simulation now. Narrate your thoughts as this persona.
1287
1284
  * Create a configured MCP server instance
1288
1285
  */
1289
1286
  function createMcpServer() {
1290
- const server = new mcp_js_1.McpServer({
1287
+ const server = new McpServer({
1291
1288
  name: "cbrowser",
1292
1289
  version: VERSION,
1293
1290
  });
@@ -1330,9 +1327,9 @@ async function handleMcpRequest(req, res, transport) {
1330
1327
  /**
1331
1328
  * Start the remote HTTP MCP server
1332
1329
  */
1333
- async function startRemoteMcpServer() {
1330
+ export async function startRemoteMcpServer() {
1334
1331
  // Auto-initialize all data directories on server start
1335
- (0, config_js_1.ensureDirectories)();
1332
+ ensureDirectories();
1336
1333
  const port = parseInt(process.env.PORT || "3000", 10);
1337
1334
  const host = process.env.HOST || "0.0.0.0";
1338
1335
  const sessionMode = process.env.MCP_SESSION_MODE || "stateless";
@@ -1351,7 +1348,7 @@ async function startRemoteMcpServer() {
1351
1348
  console.log(` - Auth0 OAuth: enabled (${auth0?.domain})`);
1352
1349
  }
1353
1350
  console.log(`Listening on ${host}:${port}`);
1354
- const httpServer = (0, node_http_1.createServer)(async (req, res) => {
1351
+ const httpServer = createServer(async (req, res) => {
1355
1352
  const url = new URL(req.url || "/", `http://${req.headers.host}`);
1356
1353
  // CORS headers for all responses
1357
1354
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -1435,8 +1432,8 @@ async function startRemoteMcpServer() {
1435
1432
  }
1436
1433
  else {
1437
1434
  // Create new transport
1438
- transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
1439
- sessionIdGenerator: sessionMode === "stateful" ? () => (0, node_crypto_1.randomUUID)() : undefined,
1435
+ transport = new StreamableHTTPServerTransport({
1436
+ sessionIdGenerator: sessionMode === "stateful" ? () => randomUUID() : undefined,
1440
1437
  });
1441
1438
  // Create and connect server
1442
1439
  const server = createMcpServer();