cbrowser 18.82.2 → 19.0.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 (53) hide show
  1. package/README.md +42 -3
  2. package/dist/analysis/accessibility-empathy.d.ts +43 -0
  3. package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
  4. package/dist/analysis/accessibility-empathy.js +65 -0
  5. package/dist/analysis/accessibility-empathy.js.map +1 -1
  6. package/dist/analysis/agent-ready-audit.d.ts +44 -1
  7. package/dist/analysis/agent-ready-audit.d.ts.map +1 -1
  8. package/dist/analysis/agent-ready-audit.js +100 -40
  9. package/dist/analysis/agent-ready-audit.js.map +1 -1
  10. package/dist/analysis/bug-hunter.d.ts +11 -1
  11. package/dist/analysis/bug-hunter.d.ts.map +1 -1
  12. package/dist/analysis/bug-hunter.js +44 -6
  13. package/dist/analysis/bug-hunter.js.map +1 -1
  14. package/dist/analysis/competitive-benchmark.d.ts +49 -1
  15. package/dist/analysis/competitive-benchmark.d.ts.map +1 -1
  16. package/dist/analysis/competitive-benchmark.js +138 -14
  17. package/dist/analysis/competitive-benchmark.js.map +1 -1
  18. package/dist/browser.d.ts.map +1 -1
  19. package/dist/browser.js +5 -2
  20. package/dist/browser.js.map +1 -1
  21. package/dist/cli.js +5 -5
  22. package/dist/cli.js.map +1 -1
  23. package/dist/mcp-tools/base/analysis-tools.d.ts.map +1 -1
  24. package/dist/mcp-tools/base/analysis-tools.js +7 -1
  25. package/dist/mcp-tools/base/analysis-tools.js.map +1 -1
  26. package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
  27. package/dist/mcp-tools/base/audit-tools.js +10 -0
  28. package/dist/mcp-tools/base/audit-tools.js.map +1 -1
  29. package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
  30. package/dist/mcp-tools/base/visual-testing-tools.js +29 -1
  31. package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
  32. package/dist/remediation/patch-generator.js +2 -2
  33. package/dist/remediation/patch-generator.js.map +1 -1
  34. package/dist/types.d.ts +80 -5
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js.map +1 -1
  37. package/dist/visual/attention-quality.d.ts +32 -0
  38. package/dist/visual/attention-quality.d.ts.map +1 -1
  39. package/dist/visual/attention-quality.js +41 -1
  40. package/dist/visual/attention-quality.js.map +1 -1
  41. package/dist/visual/freeze-animations.d.ts +71 -0
  42. package/dist/visual/freeze-animations.d.ts.map +1 -0
  43. package/dist/visual/freeze-animations.js +111 -0
  44. package/dist/visual/freeze-animations.js.map +1 -0
  45. package/dist/visual/llm-relevance.d.ts +6 -0
  46. package/dist/visual/llm-relevance.d.ts.map +1 -1
  47. package/dist/visual/llm-relevance.js +42 -1
  48. package/dist/visual/llm-relevance.js.map +1 -1
  49. package/dist/visual/persona-context.d.ts +18 -0
  50. package/dist/visual/persona-context.d.ts.map +1 -1
  51. package/dist/visual/persona-context.js +6 -0
  52. package/dist/visual/persona-context.js.map +1 -1
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -128,7 +128,7 @@ Five tools to make your site ready for the AI agent era:
128
128
 
129
129
  | Tool | What It Does |
130
130
  |------|-------------|
131
- | `agent_ready_audit` | Score site on findability, stability, accessibility, semantics (A-F grade) |
131
+ | `agent_ready_audit` | Score site on findability, stability, agent-perceivability, semantics (A-F grade) |
132
132
  | `ai_benchmark` | Compare AI-friendliness across competitor URLs |
133
133
  | `webmcp_ready_audit` | Audit MCP server for WebMCP compatibility |
134
134
  | `remediation_patches` | Generate actionable code fixes for audit findings |
@@ -299,9 +299,36 @@ npx cbrowser competitive-benchmark \
299
299
 
300
300
  ---
301
301
 
302
+ ## Upgrading to 19.0.0
303
+
304
+ One breaking change: the agent-ready **accessibility** axis is now
305
+ **agentPerceivability**, and three deprecated aliases are removed.
306
+
307
+ | removed | use instead |
308
+ |---|---|
309
+ | `score.accessibility` | `score.agentPerceivability` |
310
+ | `summary.dynamicContentCount` | `summary.deferredLoadingPatterns` |
311
+ | `comparison.bestAccessibility` | `comparison.bestAgentPerceivability` |
312
+ | issue `category: "accessibility"` | `category: "agentPerceivability"` |
313
+
314
+ All three replacements have carried identical values since 18.82.0, so if you
315
+ upgraded within that range you can switch keys before upgrading and take this
316
+ release with no further change.
317
+
318
+ The rename is not cosmetic. That axis measures whether a *machine* can perceive
319
+ your elements — ARIA present, elements carry text. It is **not** a WCAG
320
+ conformance score, and it returned 100 on a page where `empathy_audit` found two
321
+ WCAG violations. Both numbers were right; calling one of them "accessibility" was
322
+ not. Run `empathy_audit` for conformance, and expect the two to differ.
323
+
324
+ On input, `category: "accessibility"` is still accepted and scores identically, so
325
+ tools that *send* issues need not change immediately. Tools that *read* scores do.
326
+
327
+ ---
328
+
302
329
  ## Geo Proxy
303
330
 
304
- Test from 12 global regions via residential proxies:
331
+ Test from 10 global regions via residential proxies:
305
332
 
306
333
  ```bash
307
334
  npx cbrowser cognitive-journey \
@@ -311,7 +338,19 @@ npx cbrowser cognitive-journey \
311
338
  --geo-region uk
312
339
  ```
313
340
 
314
- **Regions:** `us-west`, `us-east`, `us-central`, `uk`, `germany`, `france`, `japan`, `australia`, `brazil`, `india`, `canada`, `singapore`
341
+ **Regions:** `us-west`, `us-east`, `us-central`, `uk`, `germany`, `france`, `japan`, `australia`, `canada`, `brazil`
342
+
343
+ Geo routing needs your own residential-proxy credentials — the package ships the
344
+ mechanism and no keys. Set `IPROYAL_USERNAME` / `IPROYAL_PASSWORD`, or place a
345
+ `geo-proxy.json` at `~/.cbrowser/`. Without either, `--geo-region` fails loudly
346
+ rather than silently running from your own IP.
347
+
348
+ A `geo-proxy.json` may define additional regions; they merge over the ten above.
349
+
350
+ > **Corrected 2026-08-11.** This section previously advertised 12 regions
351
+ > including `india` and `singapore`. Those are not in the shipped defaults and
352
+ > resolve to nothing on a clean install — they existed only in a local config
353
+ > file on one machine. Advertising them was a claim the package could not keep.
315
354
 
316
355
  ---
317
356
 
@@ -4,6 +4,49 @@
4
4
  * Learn more at https://cbrowser.ai - MIT License
5
5
  */
6
6
  import type { EmpathyAuditResult, EmpathyAuditOptions } from "../types.js";
7
+ /**
8
+ * Drop barriers outside the viewport when the audit is viewport-scoped.
9
+ *
10
+ * `viewportOnly` existed and had exactly ONE consumer:
11
+ * `detectSmallTouchTargets`. The other ten detectors scanned the whole document
12
+ * regardless of scope, so `scope: "viewport"` filtered touch targets and nothing
13
+ * else.
14
+ *
15
+ * Measured on /docs/home at 1280x800: six `sensory` barriers at y=5638, seven
16
+ * screens below the fold, with x up to 2029 -- 749px past the right edge. All
17
+ * six were counted in `affectedElements`, charged as `missing_alt: -2.2`, and
18
+ * folded into `barrierOnlyScore`. The response even stamped each one
19
+ * `outsideScreenshot: true`: the geometry was computed, published, and not
20
+ * acted on.
21
+ *
22
+ * So every viewport-scoped empathy score published to date may carry demand
23
+ * from content the persona never saw. It is the mirror of the bug
24
+ * `cognitive_effort`'s scopeNote documents -- that one measured too little and
25
+ * said so; this one measured too much and said nothing.
26
+ *
27
+ * Filtered HERE, once, after every detector and before scoring, rather than in
28
+ * each detector. Eleven copies of a rule is how it came to be applied in one
29
+ * place, and adding a twelfth detector must not be able to reintroduce this.
30
+ *
31
+ * A barrier with no rect is KEPT. Page-level findings -- navigation item count,
32
+ * animation presence, reading level -- have no coordinates and are properties of
33
+ * the page rather than of a location on it. Dropping the unlocatable would trade
34
+ * this bug for its opposite. (2026-08-05)
35
+ */
36
+ export declare function filterBarriersToViewport<T extends {
37
+ rect?: {
38
+ x: number;
39
+ y: number;
40
+ width: number;
41
+ height: number;
42
+ };
43
+ }>(barriers: T[], viewport: {
44
+ width: number;
45
+ height: number;
46
+ }): {
47
+ kept: T[];
48
+ dropped: number;
49
+ };
7
50
  export declare function formatEmpathyAuditReport(result: EmpathyAuditResult): string;
8
51
  export declare function generateEmpathyAuditHtmlReport(result: EmpathyAuditResult): string;
9
52
  export declare function runEmpathyAudit(url: string, options: EmpathyAuditOptions): Promise<EmpathyAuditResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"accessibility-empathy.d.ts","sourceRoot":"","sources":["../../src/analysis/accessibility-empathy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmCH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EASpB,MAAM,aAAa,CAAC;AA0mErB,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAmF3E;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAkTjF;AAqJD,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA0Z7B"}
1
+ {"version":3,"file":"accessibility-empathy.d.ts","sourceRoot":"","sources":["../../src/analysis/accessibility-empathy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmCH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EASpB,MAAM,aAAa,CAAC;AAwJrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACnH,QAAQ,EAAE,CAAC,EAAE,EACb,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAWhC;AAy+DD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAmF3E;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAkTjF;AAqJD,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA+Z7B"}
@@ -106,6 +106,48 @@ function adjustSeverityForLevel(severity, barrierWcagLevel, auditLevel) {
106
106
  }
107
107
  return severity;
108
108
  }
109
+ /**
110
+ * Drop barriers outside the viewport when the audit is viewport-scoped.
111
+ *
112
+ * `viewportOnly` existed and had exactly ONE consumer:
113
+ * `detectSmallTouchTargets`. The other ten detectors scanned the whole document
114
+ * regardless of scope, so `scope: "viewport"` filtered touch targets and nothing
115
+ * else.
116
+ *
117
+ * Measured on /docs/home at 1280x800: six `sensory` barriers at y=5638, seven
118
+ * screens below the fold, with x up to 2029 -- 749px past the right edge. All
119
+ * six were counted in `affectedElements`, charged as `missing_alt: -2.2`, and
120
+ * folded into `barrierOnlyScore`. The response even stamped each one
121
+ * `outsideScreenshot: true`: the geometry was computed, published, and not
122
+ * acted on.
123
+ *
124
+ * So every viewport-scoped empathy score published to date may carry demand
125
+ * from content the persona never saw. It is the mirror of the bug
126
+ * `cognitive_effort`'s scopeNote documents -- that one measured too little and
127
+ * said so; this one measured too much and said nothing.
128
+ *
129
+ * Filtered HERE, once, after every detector and before scoring, rather than in
130
+ * each detector. Eleven copies of a rule is how it came to be applied in one
131
+ * place, and adding a twelfth detector must not be able to reintroduce this.
132
+ *
133
+ * A barrier with no rect is KEPT. Page-level findings -- navigation item count,
134
+ * animation presence, reading level -- have no coordinates and are properties of
135
+ * the page rather than of a location on it. Dropping the unlocatable would trade
136
+ * this bug for its opposite. (2026-08-05)
137
+ */
138
+ export function filterBarriersToViewport(barriers, viewport) {
139
+ const kept = barriers.filter((b) => {
140
+ if (!b.rect)
141
+ return true; // page-level finding, not a located one
142
+ const { x, y, width, height } = b.rect;
143
+ // Document coordinates, and a viewport-scoped audit never scrolls, so the
144
+ // visible band is y 0..height and x 0..width.
145
+ const intersectsY = y < viewport.height && y + height > 0;
146
+ const intersectsX = x < viewport.width && x + width > 0;
147
+ return intersectsY && intersectsX;
148
+ });
149
+ return { kept, dropped: barriers.length - kept.length };
150
+ }
109
151
  /**
110
152
  * Detect small touch targets that are hard for motor-impaired users
111
153
  * v10.10.0: Always detect touch target issues regardless of persona
@@ -1300,6 +1342,20 @@ async function simulateAccessibilityJourney(page, url, goal, persona, scope = "v
1300
1342
  await detectVisionBarriers(ctx);
1301
1343
  break;
1302
1344
  }
1345
+ // Scope is enforced HERE, once, rather than in each detector -- see
1346
+ // filterBarriersToViewport. Ten of the eleven detectors above never honoured
1347
+ // it, so a viewport audit was scoring content seven screens below the fold.
1348
+ if (ctx.viewportOnly) {
1349
+ const vp = await page.evaluate(() => ({
1350
+ width: window.innerWidth, height: window.innerHeight,
1351
+ })).catch(() => ({ width: 1280, height: 800 }));
1352
+ const { kept, dropped } = filterBarriersToViewport(ctx.barriers, vp);
1353
+ if (dropped > 0) {
1354
+ ctx.barriers.length = 0;
1355
+ ctx.barriers.push(...kept);
1356
+ ctx.outOfViewportDropped = dropped;
1357
+ }
1358
+ }
1303
1359
  // Use cognitive journey for realistic step tracking if API key available
1304
1360
  // v18.35.0: Add hard timeout to prevent MCP proxy disconnection (~60s limit on claude.ai)
1305
1361
  const journeyTimeoutMs = Math.min(maxTime * 1000, 45000); // Hard cap at 45s to leave margin
@@ -1599,6 +1655,10 @@ async function simulateAccessibilityJourney(page, url, goal, persona, scope = "v
1599
1655
  // Deprecated alias, one release only. See EmpathyPersonaResult.
1600
1656
  goalAchieved: noBlockingBarriers,
1601
1657
  barriers: ctx.barriers,
1658
+ // Surfaced, not kept internal: a filter whose effect is invisible cannot be
1659
+ // told apart from a filter that never ran, and that is exactly the defect
1660
+ // this closes.
1661
+ ...(ctx.outOfViewportDropped ? { outOfViewportBarriersDropped: ctx.outOfViewportDropped } : {}),
1602
1662
  frictionPoints: ctx.frictionPoints,
1603
1663
  // Filtered to the audit's conformance level, exactly as the top-level
1604
1664
  // allWcagViolations is (see the filter near the end of runEmpathyAudit).
@@ -2737,6 +2797,11 @@ export async function runEmpathyAudit(url, options) {
2737
2797
  topBarriers: deduplicatedBarriers, // v11.11.0: Deduplicated barriers grouped by type
2738
2798
  combinedRemediation,
2739
2799
  overallScore,
2800
+ // Summed from the per-persona audits: a filter whose effect is invisible is
2801
+ // indistinguishable from one that did not run.
2802
+ ...(results.reduce((n, r) => n + (r.outOfViewportBarriersDropped ?? 0), 0) > 0
2803
+ ? { outOfViewportBarriersDropped: results.reduce((n, r) => n + (r.outOfViewportBarriersDropped ?? 0), 0) }
2804
+ : {}),
2740
2805
  duration: Date.now() - startTime,
2741
2806
  };
2742
2807
  }