ultra11y 5.14.0 → 5.14.1

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.
@@ -10,7 +10,7 @@
10
10
  "name": "ultra11y",
11
11
  "source": "./",
12
12
  "description": "Automatic accessibility review of the code under change before every commit, push and pull request, plus full WCAG 2.2 AA / RGAA audits and conformance deliverables on demand.",
13
- "version": "5.14.0",
13
+ "version": "5.14.1",
14
14
  "author": { "name": "maxgfr" },
15
15
  "homepage": "https://github.com/maxgfr/ultra11y",
16
16
  "repository": "https://github.com/maxgfr/ultra11y",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ultra11y",
3
3
  "description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
4
- "version": "5.14.0",
4
+ "version": "5.14.1",
5
5
  "author": { "name": "maxgfr" },
6
6
  "homepage": "https://github.com/maxgfr/ultra11y",
7
7
  "repository": "https://github.com/maxgfr/ultra11y",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ultra11y",
3
3
  "description": "Accessibility for WCAG 2.2 AA and country standards (RGAA…): an automatic review of the code under change before every commit, push and pull request, plus full audits and conformance deliverables on demand.",
4
- "version": "5.14.0",
4
+ "version": "5.14.1",
5
5
  "author": { "name": "maxgfr", "url": "https://github.com/maxgfr" },
6
6
  "homepage": "https://github.com/maxgfr/ultra11y",
7
7
  "repository": "https://github.com/maxgfr/ultra11y",
@@ -27,7 +27,7 @@ import { fileURLToPath } from "node:url";
27
27
  // Ownership marker: `ultra11y install --opencode` refuses to overwrite a plugin file that
28
28
  // does not carry it, so a user's own ultra11y.js is never clobbered.
29
29
  const ULTRA11Y_OPENCODE_PLUGIN = "ULTRA11Y_OPENCODE_PLUGIN";
30
- const ULTRA11Y_PLUGIN_VERSION = "5.14.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.14.1";
31
31
 
32
32
  const here = dirname(fileURLToPath(import.meta.url));
33
33
 
@@ -595,14 +595,20 @@ async function runAxe(page, mode) {
595
595
  if (mode === false) return void 0;
596
596
  const demanded = mode === true;
597
597
  let AxeBuilder;
598
- try {
599
- const req = createRequire2(join(process.cwd(), "package.json"));
600
- const mod = req("@axe-core/playwright");
601
- AxeBuilder = mod.default ?? mod;
602
- } catch (e) {
598
+ let lastError;
599
+ for (const from of [join(process.cwd(), "package.json"), import.meta.url]) {
600
+ try {
601
+ const mod = createRequire2(from)("@axe-core/playwright");
602
+ AxeBuilder = mod.default ?? mod;
603
+ break;
604
+ } catch (e) {
605
+ lastError = e;
606
+ }
607
+ }
608
+ if (!AxeBuilder) {
603
609
  if (demanded) {
604
610
  console.warn(
605
- `ultra11y: axe was requested but @axe-core/playwright could not be resolved from ${process.cwd()} \u2014 ${e instanceof Error ? e.message : String(e)}. Install it, or set \`axe: false\`. The criteria axe decides stay to assess.`
611
+ `ultra11y: axe was requested but @axe-core/playwright could not be resolved from ${process.cwd()} nor from this package \u2014 ${lastError instanceof Error ? lastError.message : String(lastError)}. Install it, or set \`axe: false\`. The criteria axe decides stay to assess.`
606
612
  );
607
613
  }
608
614
  return void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra11y",
3
- "version": "5.14.0",
3
+ "version": "5.14.1",
4
4
  "description": "Audit HTML/CSS/JSX against WCAG 2.2 AA and produce a dated compliance report, or author/review accessible markup (native-HTML-first). A skills.sh agent skill: an install-free static engine (bundled, no npm install) plus the agent's judgment, with check/verify gates against hallucinated non-conformities, and pluggable in-repo standards packs (RGAA France first; Section 508 & EN 301 549 next).",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.33.0",
@@ -48,6 +48,7 @@
48
48
  "test:watch": "vitest",
49
49
  "test:coverage": "vitest run --coverage",
50
50
  "test:perf": "vitest run --config vitest.perf.config.ts",
51
+ "test:browser": "vitest run --config vitest.browser.config.ts",
51
52
  "bench": "node scripts/bench.mjs",
52
53
  "typecheck": "tsc --noEmit",
53
54
  "lint": "biome ci .",
@@ -81,7 +82,9 @@
81
82
  "htmlparser2": "^12.0.0"
82
83
  },
83
84
  "devDependencies": {
85
+ "@axe-core/playwright": "^4.13.0",
84
86
  "@biomejs/biome": "^2.5.1",
87
+ "@playwright/test": "^1.62.1",
85
88
  "@semantic-release/changelog": "^6.0.3",
86
89
  "@semantic-release/exec": "^7.1.0",
87
90
  "@semantic-release/git": "^10.0.1",
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
6
6
  import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
7
7
 
8
8
  // src/types.ts
9
- var VERSION = "5.14.0";
9
+ var VERSION = "5.14.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -59694,7 +59694,9 @@ function localAvailable(cwd) {
59694
59694
  const req = createRequire(resolve12(cwd, "package.json"));
59695
59695
  req.resolve(PW_SPEC);
59696
59696
  req.resolve(AXE_SPEC);
59697
- return true;
59697
+ const pw = req(PW_SPEC);
59698
+ const bin = pw.chromium?.executablePath?.();
59699
+ return typeof bin !== "string" || bin.length === 0 ? true : existsSync24(bin);
59698
59700
  } catch {
59699
59701
  return false;
59700
59702
  }
@@ -5,7 +5,7 @@ when_to_use: "Invoke WITHOUT being asked whenever changed front-end code should
5
5
  allowed-tools: Bash(node ${CLAUDE_SKILL_DIR}/scripts/ultra11y.mjs *), Read, Grep, Glob
6
6
  license: MIT
7
7
  metadata:
8
- version: 5.14.0
8
+ version: 5.14.1
9
9
  ---
10
10
 
11
11
  # review-a11y — accessibility review of changed code
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
6
6
  import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
7
7
 
8
8
  // src/types.ts
9
- var VERSION = "5.14.0";
9
+ var VERSION = "5.14.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -59694,7 +59694,9 @@ function localAvailable(cwd) {
59694
59694
  const req = createRequire(resolve12(cwd, "package.json"));
59695
59695
  req.resolve(PW_SPEC);
59696
59696
  req.resolve(AXE_SPEC);
59697
- return true;
59697
+ const pw = req(PW_SPEC);
59698
+ const bin = pw.chromium?.executablePath?.();
59699
+ return typeof bin !== "string" || bin.length === 0 ? true : existsSync24(bin);
59698
59700
  } catch {
59699
59701
  return false;
59700
59702
  }
@@ -4,7 +4,7 @@ description: "Use to AUDIT existing HTML/CSS/JSX against WCAG 2.2 AA accessibili
4
4
  when_to_use: "Invoke when the user asks for an accessibility AUDIT or a formal deliverable: audit a repo, site or page against WCAG 2.2 AA or a country standard (RGAA, Section 508, EN 301 549); produce a dated conformance report, a criterion grid, a PRD backlog, or tickets (GitHub/GitLab/Jira); author accessible markup from scratch; wire the repo gate (init --hook/--ci) or a rendered-DOM capture pipeline. For a review of the code UNDER CHANGE (diff, branch, PR), use the `review-a11y` skill instead."
5
5
  license: MIT
6
6
  metadata:
7
- version: 5.14.0
7
+ version: 5.14.1
8
8
  ---
9
9
 
10
10
  # ultra11y — audit WCAG 2.2 AA and write accessible markup
@@ -6,7 +6,7 @@ import { join as join51, relative as relative5, resolve as resolve16, sep as sep
6
6
  import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL3 } from "url";
7
7
 
8
8
  // src/types.ts
9
- var VERSION = "5.14.0";
9
+ var VERSION = "5.14.1";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -59694,7 +59694,9 @@ function localAvailable(cwd) {
59694
59694
  const req = createRequire(resolve12(cwd, "package.json"));
59695
59695
  req.resolve(PW_SPEC);
59696
59696
  req.resolve(AXE_SPEC);
59697
- return true;
59697
+ const pw = req(PW_SPEC);
59698
+ const bin = pw.chromium?.executablePath?.();
59699
+ return typeof bin !== "string" || bin.length === 0 ? true : existsSync24(bin);
59698
59700
  } catch {
59699
59701
  return false;
59700
59702
  }
@@ -90,15 +90,27 @@ async function runAxe(page: PlaywrightPage, mode: boolean | "auto" | undefined):
90
90
  const demanded = mode === true;
91
91
  // biome-ignore lint/suspicious/noExplicitAny: the builder's shape is axe's, which is not a dependency here
92
92
  let AxeBuilder: any;
93
- try {
94
- const req = createRequire(join(process.cwd(), "package.json"));
95
- const mod = req("@axe-core/playwright");
96
- AxeBuilder = mod.default ?? mod;
97
- } catch (e) {
93
+ // PROJECT FIRST, then relative to this module — the same order the Playwright fixture above
94
+ // and `scan --runtime local` use, and for the same reason: module-relative alone works for an
95
+ // ordinary `node_modules/ultra11y` install but yields nothing whenever the package is linked,
96
+ // pnpm-hoisted elsewhere, or in a monorepo. Anchoring on the cwd ALONE is just as wrong in the
97
+ // other direction — a suite that changes directory to write its snapshot then resolves nothing
98
+ // at all, and the pass evaporates silently because the default is `auto`.
99
+ let lastError: unknown;
100
+ for (const from of [join(process.cwd(), "package.json"), import.meta.url]) {
101
+ try {
102
+ const mod = createRequire(from)("@axe-core/playwright");
103
+ AxeBuilder = mod.default ?? mod;
104
+ break;
105
+ } catch (e) {
106
+ lastError = e;
107
+ }
108
+ }
109
+ if (!AxeBuilder) {
98
110
  if (demanded) {
99
111
  console.warn(
100
- `ultra11y: axe was requested but @axe-core/playwright could not be resolved from ${process.cwd()} — ${
101
- e instanceof Error ? e.message : String(e)
112
+ `ultra11y: axe was requested but @axe-core/playwright could not be resolved from ${process.cwd()} nor from this package — ${
113
+ lastError instanceof Error ? lastError.message : String(lastError)
102
114
  }. Install it, or set \`axe: false\`. The criteria axe decides stay to assess.`,
103
115
  );
104
116
  }
package/src/scan-local.ts CHANGED
@@ -59,14 +59,29 @@ interface LocalDeps {
59
59
  const PW_SPEC = "@playwright/test";
60
60
  const AXE_SPEC = "@axe-core/playwright";
61
61
 
62
- /** Resolvable WITHOUT loading (cheap auto-detection): @playwright/test + @axe-core/playwright
63
- * both resolve from `--cwd`. */
62
+ /** Is the LOCAL tier actually usable from `cwd`? Drives `runtime: auto`.
63
+ *
64
+ * Both packages must resolve — and the browser BINARY must be on disk. The second half is not
65
+ * belt-and-braces: `npm i @playwright/test` installs the package, `npx playwright install`
66
+ * installs the browsers, and the two are separate steps that CI images routinely do only one
67
+ * of. Resolution alone therefore says "local is available" on a machine that cannot launch
68
+ * anything, and `auto` — whose whole contract is to degrade to Docker when the local tier is
69
+ * not there — instead picks it and dies on the launch.
70
+ *
71
+ * Measured on this repository the day Playwright became a devDependency: three `--runtime
72
+ * local` tests and the action's own crawl job switched themselves on in jobs that install no
73
+ * browser, and failed rather than degrading. `executablePath()` is a pure path computation, so
74
+ * this stays cheap: no launch, no download, one `stat`. */
64
75
  export function localAvailable(cwd: string): boolean {
65
76
  try {
66
77
  const req = createRequire(resolve(cwd, "package.json"));
67
78
  req.resolve(PW_SPEC);
68
79
  req.resolve(AXE_SPEC);
69
- return true;
80
+ const pw = req(PW_SPEC) as { chromium?: { executablePath?: () => string } };
81
+ const bin = pw.chromium?.executablePath?.();
82
+ // No path at all ⇒ a Playwright that cannot tell us; treat as available and let the launch
83
+ // report its own failure, rather than refusing a tier that might work.
84
+ return typeof bin !== "string" || bin.length === 0 ? true : existsSync(bin);
70
85
  } catch {
71
86
  return false;
72
87
  }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Single source of truth for shared types + the embedded version. sync-version.mjs
2
2
  // rewrites VERSION at release time (kept in lockstep with package.json + SKILL.md).
3
- export const VERSION = "5.14.0";
3
+ export const VERSION = "5.14.1";
4
4
  export const SCHEMA_VERSION = 2;
5
5
 
6
6
  // Lang = the UI FRAME's language — the `L` localization tables each module (report,