cbrowser 18.73.2 → 18.73.4

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 (104) hide show
  1. package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
  2. package/dist/analysis/accessibility-empathy.js +88 -4
  3. package/dist/analysis/accessibility-empathy.js.map +1 -1
  4. package/dist/analysis/agent-ready-audit.d.ts.map +1 -1
  5. package/dist/analysis/agent-ready-audit.js +66 -5
  6. package/dist/analysis/agent-ready-audit.js.map +1 -1
  7. package/dist/analysis/page-understanding.d.ts.map +1 -1
  8. package/dist/analysis/page-understanding.js +77 -12
  9. package/dist/analysis/page-understanding.js.map +1 -1
  10. package/dist/analysis/webmcp-readiness.d.ts.map +1 -1
  11. package/dist/analysis/webmcp-readiness.js +18 -7
  12. package/dist/analysis/webmcp-readiness.js.map +1 -1
  13. package/dist/browser.d.ts +8 -0
  14. package/dist/browser.d.ts.map +1 -1
  15. package/dist/browser.js +93 -19
  16. package/dist/browser.js.map +1 -1
  17. package/dist/cli.js +12 -0
  18. package/dist/cli.js.map +1 -1
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +28 -1
  21. package/dist/config.js.map +1 -1
  22. package/dist/mcp-server-remote.d.ts +17 -1
  23. package/dist/mcp-server-remote.d.ts.map +1 -1
  24. package/dist/mcp-server-remote.js +22 -3
  25. package/dist/mcp-server-remote.js.map +1 -1
  26. package/dist/mcp-server.d.ts.map +1 -1
  27. package/dist/mcp-server.js +20 -0
  28. package/dist/mcp-server.js.map +1 -1
  29. package/dist/mcp-tools/base/analysis-tools.d.ts +1 -1
  30. package/dist/mcp-tools/base/analysis-tools.d.ts.map +1 -1
  31. package/dist/mcp-tools/base/analysis-tools.js +83 -10
  32. package/dist/mcp-tools/base/analysis-tools.js.map +1 -1
  33. package/dist/mcp-tools/base/assertion-tools.d.ts +1 -1
  34. package/dist/mcp-tools/base/assertion-tools.d.ts.map +1 -1
  35. package/dist/mcp-tools/base/assertion-tools.js +26 -3
  36. package/dist/mcp-tools/base/assertion-tools.js.map +1 -1
  37. package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
  38. package/dist/mcp-tools/base/audit-tools.js +85 -8
  39. package/dist/mcp-tools/base/audit-tools.js.map +1 -1
  40. package/dist/mcp-tools/base/browser-management-tools.d.ts +1 -1
  41. package/dist/mcp-tools/base/browser-management-tools.d.ts.map +1 -1
  42. package/dist/mcp-tools/base/browser-management-tools.js +66 -15
  43. package/dist/mcp-tools/base/browser-management-tools.js.map +1 -1
  44. package/dist/mcp-tools/base/browser-state-tools.d.ts.map +1 -1
  45. package/dist/mcp-tools/base/browser-state-tools.js +6 -1
  46. package/dist/mcp-tools/base/browser-state-tools.js.map +1 -1
  47. package/dist/mcp-tools/base/cognitive-tools.d.ts.map +1 -1
  48. package/dist/mcp-tools/base/cognitive-tools.js +103 -30
  49. package/dist/mcp-tools/base/cognitive-tools.js.map +1 -1
  50. package/dist/mcp-tools/base/extraction-tools.d.ts.map +1 -1
  51. package/dist/mcp-tools/base/extraction-tools.js +6 -0
  52. package/dist/mcp-tools/base/extraction-tools.js.map +1 -1
  53. package/dist/mcp-tools/base/interaction-tools.d.ts.map +1 -1
  54. package/dist/mcp-tools/base/interaction-tools.js +76 -11
  55. package/dist/mcp-tools/base/interaction-tools.js.map +1 -1
  56. package/dist/mcp-tools/base/session-tools.d.ts +1 -1
  57. package/dist/mcp-tools/base/session-tools.d.ts.map +1 -1
  58. package/dist/mcp-tools/base/session-tools.js +64 -7
  59. package/dist/mcp-tools/base/session-tools.js.map +1 -1
  60. package/dist/mcp-tools/base/site-knowledge-tools.d.ts.map +1 -1
  61. package/dist/mcp-tools/base/site-knowledge-tools.js +15 -1
  62. package/dist/mcp-tools/base/site-knowledge-tools.js.map +1 -1
  63. package/dist/mcp-tools/base/testing-tools.d.ts.map +1 -1
  64. package/dist/mcp-tools/base/testing-tools.js +20 -0
  65. package/dist/mcp-tools/base/testing-tools.js.map +1 -1
  66. package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
  67. package/dist/mcp-tools/base/visual-testing-tools.js +52 -23
  68. package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
  69. package/dist/mcp-tools/persona-creation-tools.d.ts.map +1 -1
  70. package/dist/mcp-tools/persona-creation-tools.js +18 -0
  71. package/dist/mcp-tools/persona-creation-tools.js.map +1 -1
  72. package/dist/mcp-tools/session-policy.d.ts +43 -0
  73. package/dist/mcp-tools/session-policy.d.ts.map +1 -0
  74. package/dist/mcp-tools/session-policy.js +54 -0
  75. package/dist/mcp-tools/session-policy.js.map +1 -0
  76. package/dist/performance/metrics.d.ts +0 -3
  77. package/dist/performance/metrics.d.ts.map +1 -1
  78. package/dist/performance/metrics.js +45 -1
  79. package/dist/performance/metrics.js.map +1 -1
  80. package/dist/personas.d.ts.map +1 -1
  81. package/dist/personas.js +38 -4
  82. package/dist/personas.js.map +1 -1
  83. package/dist/remediation/patch-generator.d.ts.map +1 -1
  84. package/dist/remediation/patch-generator.js +36 -2
  85. package/dist/remediation/patch-generator.js.map +1 -1
  86. package/dist/testing/coverage.d.ts +8 -0
  87. package/dist/testing/coverage.d.ts.map +1 -1
  88. package/dist/testing/coverage.js +12 -0
  89. package/dist/testing/coverage.js.map +1 -1
  90. package/dist/types.d.ts +33 -0
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/types.js.map +1 -1
  93. package/dist/visual/cognitive-transport.d.ts +15 -2
  94. package/dist/visual/cognitive-transport.d.ts.map +1 -1
  95. package/dist/visual/cognitive-transport.js +85 -31
  96. package/dist/visual/cognitive-transport.js.map +1 -1
  97. package/dist/visual/perceptual-transport.d.ts +8 -0
  98. package/dist/visual/perceptual-transport.d.ts.map +1 -1
  99. package/dist/visual/perceptual-transport.js +19 -0
  100. package/dist/visual/perceptual-transport.js.map +1 -1
  101. package/dist/visual/regression.d.ts.map +1 -1
  102. package/dist/visual/regression.js +76 -3
  103. package/dist/visual/regression.js.map +1 -1
  104. package/package.json +1 -1
@@ -5,15 +5,21 @@
5
5
  * @license MIT
6
6
  */
7
7
  import { z } from "zod";
8
+ import { refuseUnboundSession } from "../session-policy.js";
8
9
  import { findElementByIntent, runAIReadinessBenchmark } from "../../analysis/index.js";
9
10
  /**
10
11
  * Register analysis tools (4 tools: analyze_page, generate_tests, find_element_by_intent, ai_benchmark)
11
12
  */
12
- export function registerAnalysisTools(server, { getBrowser }) {
13
+ export function registerAnalysisTools(server, { getBrowser, getBrowserByToken }) {
13
14
  server.registerTool("analyze_page", {
14
15
  title: "Analyze Page Structure",
15
- description: "Analyze page structure for forms, buttons, links",
16
- inputSchema: {},
16
+ description: "Analyze page structure for forms, buttons, links. MUST pass _browserToken from a previous tool call to analyze the same page — without it a blank page is analyzed and every count comes back zero.",
17
+ inputSchema: {
18
+ // Took no arguments at all, so on the HTTP transport it always analysed a
19
+ // fresh blank page: 0 forms, 0 buttons, 0 links, hasLogin false. Reads as a
20
+ // real analysis of a sparse page rather than as an error. (2026-07-28)
21
+ _browserToken: z.string().optional().describe("Browser session token from a previous tool call"),
22
+ },
17
23
  annotations: {
18
24
  title: "Analyze Page Structure",
19
25
  readOnlyHint: true,
@@ -21,14 +27,29 @@ export function registerAnalysisTools(server, { getBrowser }) {
21
27
  idempotentHint: true,
22
28
  openWorldHint: false,
23
29
  },
24
- }, async () => {
25
- const b = await getBrowser();
30
+ }, async ({ _browserToken }) => {
31
+ // Reports on page structure, so a blank-page answer (0 forms, 0 buttons,
32
+ // 0 links) reads as a real finding rather than an error.
33
+ const unbound = refuseUnboundSession("analyze_page", { getBrowserByToken }, _browserToken);
34
+ if (unbound)
35
+ return unbound;
36
+ let b;
37
+ let token;
38
+ if (getBrowserByToken) {
39
+ const resolved = await getBrowserByToken(_browserToken);
40
+ b = resolved.browser;
41
+ token = resolved.token;
42
+ }
43
+ else {
44
+ b = await getBrowser();
45
+ }
26
46
  const analysis = await b.analyzePage();
27
47
  return {
28
48
  content: [
29
49
  {
30
50
  type: "text",
31
51
  text: JSON.stringify({
52
+ ...(token ? { _browserToken: token } : {}),
32
53
  title: analysis.title,
33
54
  forms: analysis.forms.length,
34
55
  buttons: analysis.buttons.length,
@@ -46,6 +67,10 @@ export function registerAnalysisTools(server, { getBrowser }) {
46
67
  description: "Generate test scenarios for a page",
47
68
  inputSchema: {
48
69
  url: z.string().url().optional().describe("URL to analyze (uses current page if not provided)"),
70
+ // "uses current page if not provided" was unreachable on the HTTP transport:
71
+ // omitting url fell back to a blank page, so the no-url branch generated
72
+ // tests for about:blank. (2026-07-28)
73
+ _browserToken: z.string().optional().describe("Browser session token from a previous tool call — required when url is omitted"),
49
74
  },
50
75
  annotations: {
51
76
  title: "Generate Test Cases",
@@ -54,20 +79,52 @@ export function registerAnalysisTools(server, { getBrowser }) {
54
79
  idempotentHint: true,
55
80
  openWorldHint: false,
56
81
  },
57
- }, async ({ url }) => {
58
- const b = await getBrowser();
82
+ }, async ({ url, _browserToken }) => {
83
+ // Only when it is being asked about "the current page". With an explicit
84
+ // url it navigates itself and needs no session.
85
+ if (!url) {
86
+ const unbound = refuseUnboundSession("generate_tests", { getBrowserByToken }, _browserToken);
87
+ if (unbound)
88
+ return unbound;
89
+ }
90
+ let b;
91
+ let token;
92
+ if (getBrowserByToken) {
93
+ const resolved = await getBrowserByToken(_browserToken);
94
+ b = resolved.browser;
95
+ token = resolved.token;
96
+ }
97
+ else {
98
+ b = await getBrowser();
99
+ }
59
100
  const result = await b.generateTests(url);
60
101
  return {
61
102
  content: [
62
103
  {
63
104
  type: "text",
64
105
  text: JSON.stringify({
106
+ ...(token ? { _browserToken: token } : {}),
65
107
  testsGenerated: result.tests.length,
108
+ // `steps` used to be t.steps.length — a bare count. A caller got
109
+ // "3 steps" with no way to see or run them, so there was no handoff
110
+ // into nl_test_inline / nl_test_file and the tool could only be
111
+ // read, not used. The step text and a runnable script were both
112
+ // already computed and then discarded. (2026-07-29)
66
113
  tests: result.tests.map(t => ({
67
114
  name: t.name,
68
115
  description: t.description,
69
- steps: t.steps.length,
116
+ stepCount: t.steps.length,
117
+ steps: t.steps.map(st => ({
118
+ action: st.action,
119
+ ...(st.target ? { target: st.target } : {}),
120
+ ...(st.value !== undefined ? { value: st.value } : {}),
121
+ description: st.description,
122
+ })),
123
+ assertions: t.assertions,
70
124
  })),
125
+ // Ready to paste straight into nl_test_inline.
126
+ cbrowserScript: result.cbrowserScript,
127
+ usage: "Pass cbrowserScript to nl_test_inline as `content`, or write it to a file and use nl_test_file.",
71
128
  }, null, 2),
72
129
  },
73
130
  ],
@@ -79,6 +136,11 @@ export function registerAnalysisTools(server, { getBrowser }) {
79
136
  inputSchema: {
80
137
  intent: z.string().describe("Natural language description like 'the cheapest product' or 'login form'"),
81
138
  verbose: z.boolean().optional().describe("Include alternative matches with confidence scores and AI suggestions"),
139
+ // Without this, the tool searched a blank browser on the HTTP transport and
140
+ // returned `confidence: 0, "No match found"` with empty alternatives — a
141
+ // plausible "nothing here" that is indistinguishable from a real miss.
142
+ // (2026-07-28)
143
+ _browserToken: z.string().optional().describe("Browser session token from a previous tool call"),
82
144
  },
83
145
  annotations: {
84
146
  title: "Find Element by Intent",
@@ -87,8 +149,19 @@ export function registerAnalysisTools(server, { getBrowser }) {
87
149
  idempotentHint: true,
88
150
  openWorldHint: false,
89
151
  },
90
- }, async ({ intent, verbose }) => {
91
- const b = await getBrowser();
152
+ }, async ({ intent, verbose, _browserToken }) => {
153
+ // Searches the page, so a blank-browser search returns "no match found"
154
+ // with confidence 0 — indistinguishable from a genuine miss.
155
+ const unbound = refuseUnboundSession("find_element_by_intent", { getBrowserByToken }, _browserToken);
156
+ if (unbound)
157
+ return unbound;
158
+ let b;
159
+ if (getBrowserByToken) {
160
+ b = (await getBrowserByToken(_browserToken)).browser;
161
+ }
162
+ else {
163
+ b = await getBrowser();
164
+ }
92
165
  const result = await findElementByIntent(b, intent, { verbose });
93
166
  if (result && result.confidence > 0) {
94
167
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-tools.js","sourceRoot":"","sources":["../../../src/mcp-tools/base/analysis-tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analysis-tools.js","sourceRoot":"","sources":["../../../src/mcp-tools/base/analysis-tools.ts"],"names":[],"mappings":"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"}
@@ -8,5 +8,5 @@ import type { McpServer, ToolRegistrationContext } from "../types.js";
8
8
  /**
9
9
  * Register assertion tools (1 tool: assert)
10
10
  */
11
- export declare function registerAssertionTools(server: McpServer, { getBrowser }: ToolRegistrationContext): void;
11
+ export declare function registerAssertionTools(server: McpServer, { getBrowser, getBrowserByToken }: ToolRegistrationContext): void;
12
12
  //# sourceMappingURL=assertion-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assertion-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/base/assertion-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtE;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,EAAE,UAAU,EAAE,EAAE,uBAAuB,GACtC,IAAI,CAgCN"}
1
+ {"version":3,"file":"assertion-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/base/assertion-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGtE;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE,uBAAuB,GACzD,IAAI,CAqDN"}
@@ -5,15 +5,22 @@
5
5
  * @license MIT
6
6
  */
7
7
  import { z } from "zod";
8
+ import { refuseUnboundSession } from "../session-policy.js";
8
9
  /**
9
10
  * Register assertion tools (1 tool: assert)
10
11
  */
11
- export function registerAssertionTools(server, { getBrowser }) {
12
+ export function registerAssertionTools(server, { getBrowser, getBrowserByToken }) {
12
13
  server.registerTool("assert", {
13
14
  title: "Assert Page State",
14
15
  description: "Assert a condition using natural language",
15
16
  inputSchema: {
16
17
  assertion: z.string().describe("Natural language assertion like \"page contains 'Welcome'\" or \"title is 'Home'\""),
18
+ // Without this, assert could not bind to the session navigate created on the
19
+ // HTTP transport: it asserted against a blank page and returned
20
+ // `passed:false, actual:""`. Worse than a crash — a NEGATIVE assertion
21
+ // ("page does not contain 'error'") then PASSED against nothing, so a whole
22
+ // suite could report green while testing an empty browser. (2026-07-28)
23
+ _browserToken: z.string().optional().describe("Browser session token from a previous tool call"),
17
24
  },
18
25
  annotations: {
19
26
  title: "Assert Page State",
@@ -22,8 +29,23 @@ export function registerAssertionTools(server, { getBrowser }) {
22
29
  idempotentHint: true,
23
30
  openWorldHint: false,
24
31
  },
25
- }, async ({ assertion }) => {
26
- const b = await getBrowser();
32
+ }, async ({ assertion, _browserToken }) => {
33
+ // Adding the token was only half the fix: omitting it entirely still
34
+ // asserted against a blank page and returned a confident verdict, with a
35
+ // fresh _browserToken attached that made it look session-backed.
36
+ const unbound = refuseUnboundSession("assert", { getBrowserByToken }, _browserToken);
37
+ if (unbound)
38
+ return unbound;
39
+ let b;
40
+ let token;
41
+ if (getBrowserByToken) {
42
+ const resolved = await getBrowserByToken(_browserToken);
43
+ b = resolved.browser;
44
+ token = resolved.token;
45
+ }
46
+ else {
47
+ b = await getBrowser();
48
+ }
27
49
  const result = await b.assert(assertion);
28
50
  return {
29
51
  content: [
@@ -34,6 +56,7 @@ export function registerAssertionTools(server, { getBrowser }) {
34
56
  message: result.message,
35
57
  actual: result.actual,
36
58
  expected: result.expected,
59
+ ...(token ? { _browserToken: token } : {}),
37
60
  }, null, 2),
38
61
  },
39
62
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"assertion-tools.js","sourceRoot":"","sources":["../../../src/mcp-tools/base/assertion-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,EAAE,UAAU,EAA2B;IAEvC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE;QAC5B,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,2CAA2C;QACxD,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;SACrH;QACD,WAAW,EAAE;YACX,KAAK,EAAE,mBAAmB;YAC1B,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACvB,MAAM,CAAC,GAAG,MAAM,UAAU,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;qBAC1B,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"assertion-tools.js","sourceRoot":"","sources":["../../../src/mcp-tools/base/assertion-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,EAAE,UAAU,EAAE,iBAAiB,EAA2B;IAE1D,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE;QAC5B,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,2CAA2C;QACxD,WAAW,EAAE;YACX,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;YACpH,6EAA6E;YAC7E,gEAAgE;YAChE,uEAAuE;YACvE,4EAA4E;YAC5E,wEAAwE;YACxE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;SACjG;QACD,WAAW,EAAE;YACX,KAAK,EAAE,mBAAmB;YAC1B,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE;QACtC,qEAAqE;QACrE,yEAAyE;QACzE,iEAAiE;QACjE,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,EAAE,EAAE,iBAAiB,EAAE,EAAE,aAAa,CAAC,CAAC;QACrF,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAE5B,IAAI,CAAC,CAAC;QACN,IAAI,KAAyB,CAAC;QAC9B,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;YACxD,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC;YACrB,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,CAAC,GAAG,MAAM,UAAU,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;wBACzB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC3C,EAAE,IAAI,EAAE,CAAC,CAAC;iBACZ;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"audit-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/base/audit-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAStE;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CA2jC7F"}
1
+ {"version":3,"file":"audit-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/base/audit-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAmCtE;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CA8mC7F"}
@@ -7,6 +7,34 @@
7
7
  import { z } from "zod";
8
8
  import { runAgentReadyAudit, runCompetitiveBenchmark, runEmpathyAudit, runWebMCPReadyAudit, } from "../../analysis/index.js";
9
9
  import { listAccessibilityPersonas } from "../../personas.js";
10
+ import { writeFileSync, mkdirSync, existsSync } from "fs";
11
+ import { join } from "path";
12
+ import { homedir } from "os";
13
+ /**
14
+ * Persist an audit screenshot and return its path.
15
+ *
16
+ * empathy_audit inlined base64 page screenshots, which routinely overflowed an
17
+ * MCP client's context and made the tool untestable through a normal client.
18
+ * Writing them out keeps the overlay data usable without carrying megabytes
19
+ * through the transport. Returns undefined rather than throwing if the write
20
+ * fails — a screenshot is not worth failing an audit over. (2026-07-29)
21
+ */
22
+ function writeAuditScreenshot(base64, persona) {
23
+ if (!base64)
24
+ return undefined;
25
+ try {
26
+ const dir = join(process.env.CBROWSER_DATA_DIR || join(homedir(), ".cbrowser"), "audit-screenshots");
27
+ if (!existsSync(dir))
28
+ mkdirSync(dir, { recursive: true });
29
+ const safe = String(persona || "persona").toLowerCase().replace(/[^a-z0-9-]+/g, "-");
30
+ const path = join(dir, `empathy-${safe}-${Date.now()}.png`);
31
+ writeFileSync(path, Buffer.from(base64, "base64"));
32
+ return path;
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ }
10
38
  /**
11
39
  * Register audit tools (4 tools + site_cognitive_assessment + visual_cognitive_story)
12
40
  */
@@ -92,6 +120,11 @@ export function registerAuditTools(server, context) {
92
120
  wcagLevel: z.enum(["A", "AA", "AAA"]).optional().default("AA").describe("WCAG conformance level"),
93
121
  maxSteps: z.number().optional().default(5).describe("Max cognitive journey steps (keep low for MCP)"),
94
122
  maxTime: z.number().optional().default(20).describe("Max time per persona in seconds"),
123
+ // Base64 page screenshots are large enough to blow an MCP client's context
124
+ // on a single call — every empathy_audit in the 18.73.3 test pass had to be
125
+ // read off disk instead. Off by default; images go to disk and their paths
126
+ // are returned. (2026-07-29)
127
+ includeScreenshots: z.boolean().optional().default(false).describe("Inline base64 page screenshots in the response. Off by default because they are large enough to overflow an MCP client's context; when off, screenshots are written to disk and screenshotPath is returned instead."),
95
128
  scope: z.enum(["viewport", "full_page"]).optional().default("viewport").describe("What to score: 'viewport' (first impression, above-the-fold only — default) or 'full_page' (scroll through entire page, all barriers). Use 'viewport' for landing page optimization; 'full_page' for WCAG compliance audits."),
96
129
  device: z.string().optional().describe("Device emulation: 'mobile', 'tablet', 'desktop', or specific device like 'iPhone 15', 'Pixel 7'. Essential for mobile WCAG audits — touch targets, viewport sizing, and responsive barriers differ significantly on mobile."),
97
130
  },
@@ -102,7 +135,7 @@ export function registerAuditTools(server, context) {
102
135
  idempotentHint: false,
103
136
  openWorldHint: true,
104
137
  },
105
- }, async ({ url, goal, disabilities, wcagLevel, maxSteps, maxTime, scope, device }) => {
138
+ }, async ({ url, goal, disabilities, wcagLevel, maxSteps, maxTime, scope, device, includeScreenshots }) => {
106
139
  try {
107
140
  // Auto-limit to 1 persona to avoid MCP client timeout on Claude.ai (~60s limit)
108
141
  const allPersonas = listAccessibilityPersonas();
@@ -140,11 +173,23 @@ export function registerAuditTools(server, context) {
140
173
  goalAchieved: r.goalAchieved,
141
174
  empathyScore: r.empathyScore,
142
175
  // v18.22.0: Added score context for transparency
176
+ // Whitelist projection: anything added to scoreContext upstream is
177
+ // invisible to the caller unless named here. The blend breakdown
178
+ // below is what lets the deductions reconcile to a score the
179
+ // caller can actually see. (2026-07-28)
143
180
  scoreContext: r.scoreContext ? {
144
181
  explanation: r.scoreContext.explanation,
145
182
  deductionsByType: r.scoreContext.deductionsByType,
183
+ totalBarrierDeduction: r.scoreContext.totalBarrierDeduction,
146
184
  frictionDeduction: r.scoreContext.frictionDeduction,
147
185
  goalDeduction: r.scoreContext.goalDeduction,
186
+ cognitiveOverloadPenalty: r.scoreContext.cognitiveOverloadPenalty,
187
+ appliedBarrierWeights: r.scoreContext.appliedBarrierWeights,
188
+ explainsScore: r.scoreContext.explainsScore,
189
+ barrierOnlyScore: r.scoreContext.barrierOnlyScore,
190
+ perceptualScore: r.scoreContext.perceptualScore,
191
+ blendWeights: r.scoreContext.blendWeights,
192
+ finalScore: r.scoreContext.finalScore,
148
193
  } : undefined,
149
194
  barrierTypeCount: uniqueTypes.size,
150
195
  barrierTypes: Array.from(uniqueTypes),
@@ -155,6 +200,10 @@ export function registerAuditTools(server, context) {
155
200
  empathyScoreBarrierOnly: r.empathyScoreBarrierOnly || undefined,
156
201
  // v18.27.0: Cognitive load estimation (optimal transport)
157
202
  cognitiveLoad: r.cognitiveLoad || undefined,
203
+ // Names the three different "cognitive load" numbers in this
204
+ // payload and what each measures. Same whitelist caveat as
205
+ // scoreContext above: set upstream, invisible unless named here.
206
+ cognitiveLoadReadings: r.cognitiveLoadReadings || undefined,
158
207
  // v18.28.0: Attention transport analysis (W₂ saliency)
159
208
  attentionAnalysis: r.attentionAnalysis || undefined,
160
209
  // v18.29.0: Journey validation — evidence, path, forensics
@@ -171,14 +220,42 @@ export function registerAuditTools(server, context) {
171
220
  // v18.60.0: Include per-result screenshots and element rects for WCAG overlay
172
221
  pageScreenshots: result.results?.map((r) => ({
173
222
  persona: r.persona,
174
- screenshot: r.pageScreenshot,
223
+ ...(includeScreenshots
224
+ ? { screenshot: r.pageScreenshot }
225
+ : {
226
+ screenshotPath: writeAuditScreenshot(r.pageScreenshot, r.persona),
227
+ screenshotNote: "Pass includeScreenshots:true to inline the base64 instead.",
228
+ }),
175
229
  viewportSize: r.viewportSize,
176
- barrierRects: r.barriers?.filter((b) => b.rect).map((b) => ({
177
- type: b.type, severity: b.severity, element: b.element,
178
- description: b.description, rect: b.rect,
179
- wcag: b.wcagCriteria,
180
- })),
181
- })).filter((s) => s.screenshot),
230
+ // Rects come from getBoundingClientRect with no scroll compensation,
231
+ // so they are VIEWPORT coordinates — which is correct here, because
232
+ // the screenshot above is captured with fullPage: false and these are
233
+ // meant to overlay it. Converting them to document coordinates would
234
+ // break that alignment.
235
+ //
236
+ // The real hazard is scope: "full_page", where the audit scrolls and
237
+ // rects captured at different offsets land in one list against a
238
+ // single viewport image; anything above the captured viewport then
239
+ // carries a negative y and would render off-canvas. Say which space
240
+ // these are in and flag the ones that fall outside the image rather
241
+ // than emitting silent negatives. (2026-07-28)
242
+ coordinateSpace: "viewport",
243
+ barrierRects: r.barriers?.filter((b) => b.rect).map((b) => {
244
+ const vp = r.viewportSize;
245
+ const outside = !!vp && !!b.rect && (b.rect.y + b.rect.height < 0 || b.rect.x + b.rect.width < 0 ||
246
+ b.rect.y > vp.height || b.rect.x > vp.width);
247
+ return {
248
+ type: b.type, severity: b.severity, element: b.element,
249
+ description: b.description, rect: b.rect,
250
+ wcag: b.wcagCriteria,
251
+ ...(outside ? { outsideScreenshot: true } : {}),
252
+ };
253
+ }),
254
+ // Keep entries that carry EITHER the inline image or a path to it.
255
+ // Filtering on `screenshot` alone silently dropped every entry once
256
+ // the default stopped inlining base64, taking the barrierRects with
257
+ // them. (2026-07-29)
258
+ })).filter((s) => s.screenshot || s.screenshotPath),
182
259
  };
183
260
  // Add guidance if we limited the request
184
261
  if (wasLimited) {