ultra11y 5.20.0 → 5.21.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.
@@ -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.20.0",
13
+ "version": "5.21.0",
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.20.0",
4
+ "version": "5.21.0",
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.20.0",
4
+ "version": "5.21.0",
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.20.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "5.21.0";
31
31
 
32
32
  const here = dirname(fileURLToPath(import.meta.url));
33
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra11y",
3
- "version": "5.20.0",
3
+ "version": "5.21.0",
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",
@@ -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.20.0";
9
+ var VERSION = "5.21.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -66779,7 +66779,7 @@ Usage:
66779
66779
  ultra11y hook --claude-code|--codex|--opencode (internal: the PreToolUse hook; payload on stdin)
66780
66780
  ultra11y install --claude-code | --codex | --opencode | --agents-md | --all [--project] [--dry-run] [--no-skills]
66781
66781
  ultra11y uninstall --claude-code | --codex | --opencode | --agents-md | --all [--project]
66782
- ultra11y status [--json] [--project] (doctor: which agents will run the review by themselves)
66782
+ ultra11y status [--json] [--project] [--browser [--cwd <dir>]] (doctor: which agents run the review; --browser asks whether the scan tier resolves here)
66783
66783
  ultra11y dev [--port <n>] [--root <dir>] [--standard <pack>] [--lang auto|en|fr] (dev side-car: live overlay + per-page dashboard)
66784
66784
  ultra11y dev --next [--port <n>] (write the Next overlay component, then wire one line into your layout)
66785
66785
 
@@ -67302,6 +67302,10 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
67302
67302
  "agents-md",
67303
67303
  "all",
67304
67304
  "project",
67305
+ // `status`: ALSO ask whether the browser tier resolves here — the question `scan --runtime
67306
+ // local` answers for itself, exposed so a caller (the GitHub Action) can branch on it
67307
+ // instead of re-deriving it in shell.
67308
+ "browser",
67305
67309
  "no-skills"
67306
67310
  ]);
67307
67311
  var KNOWN_FLAGS = /* @__PURE__ */ new Set([...VALUE_FLAGS2, ...BOOLEAN_FLAGS]);
@@ -68127,8 +68131,9 @@ function reportInstall(results, verb) {
68127
68131
  }
68128
68132
  function cmdStatus(p) {
68129
68133
  const rows = statusReport({ project: p.flags.project === true });
68134
+ const browser = p.flags.browser === true ? localTierStatus(typeof p.flags.cwd === "string" && p.flags.cwd ? p.flags.cwd : ".") : void 0;
68130
68135
  if (p.flags.json === true) {
68131
- console.log(JSON.stringify({ version: VERSION, targets: rows }, null, 2));
68136
+ console.log(JSON.stringify({ version: VERSION, targets: rows, ...browser ? { browser } : {} }, null, 2));
68132
68137
  return 0;
68133
68138
  }
68134
68139
  console.log(`ultra11y ${VERSION}`);
@@ -68136,6 +68141,11 @@ function cmdStatus(p) {
68136
68141
  console.log(` ${r.target.padEnd(12)} ${r.wired ? "wired " : "not wired"} ${r.path}`);
68137
68142
  if (r.note) console.log(` ${"".padEnd(12)} ${r.note}`);
68138
68143
  }
68144
+ if (browser) {
68145
+ console.log(
68146
+ ` ${"browser".padEnd(12)} ${browser.ok ? "available" : "unavailable"} ${browser.ok ? "@playwright/test + @axe-core/playwright" : browser.reason}`
68147
+ );
68148
+ }
68139
68149
  return 0;
68140
68150
  }
68141
68151
  function cmdCriteria(p) {
@@ -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.20.0
8
+ version: 5.21.0
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.20.0";
9
+ var VERSION = "5.21.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -66779,7 +66779,7 @@ Usage:
66779
66779
  ultra11y hook --claude-code|--codex|--opencode (internal: the PreToolUse hook; payload on stdin)
66780
66780
  ultra11y install --claude-code | --codex | --opencode | --agents-md | --all [--project] [--dry-run] [--no-skills]
66781
66781
  ultra11y uninstall --claude-code | --codex | --opencode | --agents-md | --all [--project]
66782
- ultra11y status [--json] [--project] (doctor: which agents will run the review by themselves)
66782
+ ultra11y status [--json] [--project] [--browser [--cwd <dir>]] (doctor: which agents run the review; --browser asks whether the scan tier resolves here)
66783
66783
  ultra11y dev [--port <n>] [--root <dir>] [--standard <pack>] [--lang auto|en|fr] (dev side-car: live overlay + per-page dashboard)
66784
66784
  ultra11y dev --next [--port <n>] (write the Next overlay component, then wire one line into your layout)
66785
66785
 
@@ -67302,6 +67302,10 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
67302
67302
  "agents-md",
67303
67303
  "all",
67304
67304
  "project",
67305
+ // `status`: ALSO ask whether the browser tier resolves here — the question `scan --runtime
67306
+ // local` answers for itself, exposed so a caller (the GitHub Action) can branch on it
67307
+ // instead of re-deriving it in shell.
67308
+ "browser",
67305
67309
  "no-skills"
67306
67310
  ]);
67307
67311
  var KNOWN_FLAGS = /* @__PURE__ */ new Set([...VALUE_FLAGS2, ...BOOLEAN_FLAGS]);
@@ -68127,8 +68131,9 @@ function reportInstall(results, verb) {
68127
68131
  }
68128
68132
  function cmdStatus(p) {
68129
68133
  const rows = statusReport({ project: p.flags.project === true });
68134
+ const browser = p.flags.browser === true ? localTierStatus(typeof p.flags.cwd === "string" && p.flags.cwd ? p.flags.cwd : ".") : void 0;
68130
68135
  if (p.flags.json === true) {
68131
- console.log(JSON.stringify({ version: VERSION, targets: rows }, null, 2));
68136
+ console.log(JSON.stringify({ version: VERSION, targets: rows, ...browser ? { browser } : {} }, null, 2));
68132
68137
  return 0;
68133
68138
  }
68134
68139
  console.log(`ultra11y ${VERSION}`);
@@ -68136,6 +68141,11 @@ function cmdStatus(p) {
68136
68141
  console.log(` ${r.target.padEnd(12)} ${r.wired ? "wired " : "not wired"} ${r.path}`);
68137
68142
  if (r.note) console.log(` ${"".padEnd(12)} ${r.note}`);
68138
68143
  }
68144
+ if (browser) {
68145
+ console.log(
68146
+ ` ${"browser".padEnd(12)} ${browser.ok ? "available" : "unavailable"} ${browser.ok ? "@playwright/test + @axe-core/playwright" : browser.reason}`
68147
+ );
68148
+ }
68139
68149
  return 0;
68140
68150
  }
68141
68151
  function cmdCriteria(p) {
@@ -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.20.0
7
+ version: 5.21.0
8
8
  ---
9
9
 
10
10
  # ultra11y — audit WCAG 2.2 AA and write accessible markup
@@ -367,6 +367,42 @@ crawl is never a job that merely looks hung.
367
367
  served HTML, and a listing that links a source file makes the browser start a download instead
368
368
  of a navigation — which stops the scan.
369
369
 
370
+ ### The browser tier comes with the action now (`browser`)
371
+
372
+ The tier does not travel with the action, and that used to be a silent hole. `scan --runtime
373
+ local` resolves `@playwright/test` + `@axe-core/playwright` from the audited project first and
374
+ from ultra11y's own install second — and consumed as `uses: maxgfr/ultra11y@v5`, that second
375
+ anchor is a checkout with **no `node_modules` beside it**. So a repository that did not pin
376
+ Playwright itself resolved nothing, degraded to Docker, and lost every rendering criterion:
377
+ contrast, zoom, reflow, text spacing. The `urls` input meanwhile promised "a Chromium binary
378
+ for the Playwright that ships with ultra11y". It did not ship.
379
+
380
+ `browser: auto` (the default) closes it: the action asks the engine whether the tier resolves
381
+ (`status --browser`, the same function `scan` acts on — never a shell re-derivation), and only
382
+ if it does not, installs the two packages **pinned to the action's own manifest** plus a
383
+ Chromium binary into `$RUNNER_TEMP`, then points `--cwd` there. `install` skips the question;
384
+ `off` restores the old behaviour.
385
+
386
+ Three things it deliberately does:
387
+
388
+ - **Leaves a project that pins its own Playwright alone.** Two copies in one process hand out
389
+ `Page` objects the other one's fixtures do not recognise.
390
+ - **Installs into a scratch prefix, never into your tree.** Installing a named package while
391
+ omitting dev dependencies installs *nothing* when that package is already in the target's own
392
+ devDependencies — npm answers "up to date" — which is how this repository's own CI once ran
393
+ with no tier at all. A directory that declares nothing cannot be hit by it.
394
+ - **Never fails the job.** A tier it could not build is a `::warning::` and a scan that degrades
395
+ exactly as it did before; a missing optional capability must not turn into a red build.
396
+
397
+ Cache the download to make it free after the first run:
398
+
399
+ ```yaml
400
+ - uses: actions/cache@v4
401
+ with:
402
+ path: ~/.cache/ms-playwright
403
+ key: ms-playwright-${{ runner.os }}
404
+ ```
405
+
370
406
  Every scanned page is also **persisted as a snapshot** and folded into the audit
371
407
  (`snapshot: 'false'` opts out). That is not a nicety: a page known only by its URL cannot earn
372
408
  a conforming verdict — the static rules never ran against its DOM — so without it the per-page
@@ -23,6 +23,11 @@ content on hover (1.4.13), target size (2.5.8). The dynamic tier decides them by
23
23
  |---|---|
24
24
  | ultra11y as an npm dependency (`ultra11y/playwright`, `pnpm exec ultra11y`) | **come with it** — they are its own `dependencies`. Nothing to install. |
25
25
  | the standalone skill bundle (`node scripts/ultra11y.mjs` from an installed skill) | **must be in the audited project**, reachable from `--cwd`. An installed skill is a directory of files with no `node_modules` beside it, so the second anchor finds nothing there. |
26
+ | the **GitHub Action** (`uses: maxgfr/ultra11y@vN`) | **the action installs them for you** (`browser: auto`, the default) into the runner temp directory, plus a Chromium binary, and points `--cwd` at it. Same blind spot as the skill bundle — the action is a checkout with no `node_modules` — but here it is closed rather than documented. A repository that pins its own Playwright is left alone. |
27
+
28
+ Which of those you are in is answerable: `status --browser [--cwd <dir>]` asks the very
29
+ function `scan --runtime local` acts on, and reports `ok` plus, when it is not, WHICH package
30
+ or binary is missing. That is what the action branches on, rather than re-deriving it.
26
31
 
27
32
  Either way, a project that installs them itself wins: `--cwd` is tried first, which is what a
28
33
  repository with its own pinned Playwright wants. When neither anchor resolves, `auto` degrades
@@ -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.20.0";
9
+ var VERSION = "5.21.0";
10
10
  var SCHEMA_VERSION = 2;
11
11
  var INAPPLICABLE_STATUS = "C";
12
12
 
@@ -66779,7 +66779,7 @@ Usage:
66779
66779
  ultra11y hook --claude-code|--codex|--opencode (internal: the PreToolUse hook; payload on stdin)
66780
66780
  ultra11y install --claude-code | --codex | --opencode | --agents-md | --all [--project] [--dry-run] [--no-skills]
66781
66781
  ultra11y uninstall --claude-code | --codex | --opencode | --agents-md | --all [--project]
66782
- ultra11y status [--json] [--project] (doctor: which agents will run the review by themselves)
66782
+ ultra11y status [--json] [--project] [--browser [--cwd <dir>]] (doctor: which agents run the review; --browser asks whether the scan tier resolves here)
66783
66783
  ultra11y dev [--port <n>] [--root <dir>] [--standard <pack>] [--lang auto|en|fr] (dev side-car: live overlay + per-page dashboard)
66784
66784
  ultra11y dev --next [--port <n>] (write the Next overlay component, then wire one line into your layout)
66785
66785
 
@@ -67302,6 +67302,10 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
67302
67302
  "agents-md",
67303
67303
  "all",
67304
67304
  "project",
67305
+ // `status`: ALSO ask whether the browser tier resolves here — the question `scan --runtime
67306
+ // local` answers for itself, exposed so a caller (the GitHub Action) can branch on it
67307
+ // instead of re-deriving it in shell.
67308
+ "browser",
67305
67309
  "no-skills"
67306
67310
  ]);
67307
67311
  var KNOWN_FLAGS = /* @__PURE__ */ new Set([...VALUE_FLAGS2, ...BOOLEAN_FLAGS]);
@@ -68127,8 +68131,9 @@ function reportInstall(results, verb) {
68127
68131
  }
68128
68132
  function cmdStatus(p) {
68129
68133
  const rows = statusReport({ project: p.flags.project === true });
68134
+ const browser = p.flags.browser === true ? localTierStatus(typeof p.flags.cwd === "string" && p.flags.cwd ? p.flags.cwd : ".") : void 0;
68130
68135
  if (p.flags.json === true) {
68131
- console.log(JSON.stringify({ version: VERSION, targets: rows }, null, 2));
68136
+ console.log(JSON.stringify({ version: VERSION, targets: rows, ...browser ? { browser } : {} }, null, 2));
68132
68137
  return 0;
68133
68138
  }
68134
68139
  console.log(`ultra11y ${VERSION}`);
@@ -68136,6 +68141,11 @@ function cmdStatus(p) {
68136
68141
  console.log(` ${r.target.padEnd(12)} ${r.wired ? "wired " : "not wired"} ${r.path}`);
68137
68142
  if (r.note) console.log(` ${"".padEnd(12)} ${r.note}`);
68138
68143
  }
68144
+ if (browser) {
68145
+ console.log(
68146
+ ` ${"browser".padEnd(12)} ${browser.ok ? "available" : "unavailable"} ${browser.ok ? "@playwright/test + @axe-core/playwright" : browser.reason}`
68147
+ );
68148
+ }
68139
68149
  return 0;
68140
68150
  }
68141
68151
  function cmdCriteria(p) {
package/src/cli.ts CHANGED
@@ -143,7 +143,7 @@ Usage:
143
143
  ultra11y hook --claude-code|--codex|--opencode (internal: the PreToolUse hook; payload on stdin)
144
144
  ultra11y install --claude-code | --codex | --opencode | --agents-md | --all [--project] [--dry-run] [--no-skills]
145
145
  ultra11y uninstall --claude-code | --codex | --opencode | --agents-md | --all [--project]
146
- ultra11y status [--json] [--project] (doctor: which agents will run the review by themselves)
146
+ ultra11y status [--json] [--project] [--browser [--cwd <dir>]] (doctor: which agents run the review; --browser asks whether the scan tier resolves here)
147
147
  ultra11y dev [--port <n>] [--root <dir>] [--standard <pack>] [--lang auto|en|fr] (dev side-car: live overlay + per-page dashboard)
148
148
  ultra11y dev --next [--port <n>] (write the Next overlay component, then wire one line into your layout)
149
149
 
@@ -683,6 +683,10 @@ const BOOLEAN_FLAGS = new Set([
683
683
  "agents-md",
684
684
  "all",
685
685
  "project",
686
+ // `status`: ALSO ask whether the browser tier resolves here — the question `scan --runtime
687
+ // local` answers for itself, exposed so a caller (the GitHub Action) can branch on it
688
+ // instead of re-deriving it in shell.
689
+ "browser",
686
690
  "no-skills",
687
691
  ]);
688
692
  const KNOWN_FLAGS: ReadonlySet<string> = new Set<string>([...VALUE_FLAGS, ...BOOLEAN_FLAGS]);
@@ -1871,8 +1875,17 @@ function reportInstall(results: ReturnType<typeof installForTargets>, verb: stri
1871
1875
  * is otherwise invisible until a commit that should have been stopped goes through. */
1872
1876
  function cmdStatus(p: ParsedArgs): number {
1873
1877
  const rows = statusReport({ project: p.flags.project === true });
1878
+ // --browser: CAN THE SCAN TIER RUN HERE? Asked of the engine, answered by the very function
1879
+ // `scan --runtime local` acts on (`localTierStatus`), so a caller that branches on this
1880
+ // cannot end up disagreeing with the command it is branching for. A second implementation
1881
+ // of "does Playwright resolve?" — in a shell script, say — is a second answer.
1882
+ //
1883
+ // Opt-in, because resolving two packages and stat-ing a browser binary is work the harness
1884
+ // doctor has no reason to do. Exit code stays 0 either way: this is a QUESTION, and a doctor
1885
+ // that exits non-zero is one nobody can put in an `if`.
1886
+ const browser = p.flags.browser === true ? localTierStatus(typeof p.flags.cwd === "string" && p.flags.cwd ? p.flags.cwd : ".") : undefined;
1874
1887
  if (p.flags.json === true) {
1875
- console.log(JSON.stringify({ version: VERSION, targets: rows }, null, 2));
1888
+ console.log(JSON.stringify({ version: VERSION, targets: rows, ...(browser ? { browser } : {}) }, null, 2));
1876
1889
  return 0;
1877
1890
  }
1878
1891
  console.log(`ultra11y ${VERSION}`);
@@ -1880,6 +1893,11 @@ function cmdStatus(p: ParsedArgs): number {
1880
1893
  console.log(` ${r.target.padEnd(12)} ${r.wired ? "wired " : "not wired"} ${r.path}`);
1881
1894
  if (r.note) console.log(` ${"".padEnd(12)} ${r.note}`);
1882
1895
  }
1896
+ if (browser) {
1897
+ console.log(
1898
+ ` ${"browser".padEnd(12)} ${browser.ok ? "available" : "unavailable"} ${browser.ok ? "@playwright/test + @axe-core/playwright" : browser.reason}`,
1899
+ );
1900
+ }
1883
1901
  return 0;
1884
1902
  }
1885
1903
 
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.20.0";
3
+ export const VERSION = "5.21.0";
4
4
  export const SCHEMA_VERSION = 2;
5
5
 
6
6
  // Lang = the UI FRAME's language — the `L` localization tables each module (report,