ultra11y 3.0.0 → 4.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.
@@ -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": "3.0.0",
13
+ "version": "4.0.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": "3.0.0",
4
+ "version": "4.0.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": "3.0.0",
4
+ "version": "4.0.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 = "3.0.0";
30
+ const ULTRA11Y_PLUGIN_VERSION = "4.0.0";
31
31
 
32
32
  const here = dirname(fileURLToPath(import.meta.url));
33
33
 
package/README.md CHANGED
@@ -125,7 +125,7 @@ claude mcp add ultra11y -- npx -y ultra11y mcp
125
125
  **As a GitHub Action** — audits the PR diff and, optionally, the served pages:
126
126
 
127
127
  ```yaml
128
- - uses: maxgfr/ultra11y@v2
128
+ - uses: maxgfr/ultra11y@v3
129
129
  with: { since: auto, standard: rgaa, fail-on: blocking }
130
130
  ```
131
131
 
@@ -429,7 +429,8 @@ Releases are cut automatically by **semantic-release** on push to `main` (GitHub
429
429
  npm publish via OIDC trusted publishing, plus the moving `v2` major tag). The version bump is
430
430
  decided by **Conventional Commits**: a commit whose subject carries no `feat:`/`fix:` prefix
431
431
  is analysed as *no release*, so a change that must ship needs at least one conventional commit
432
- in the range — otherwise `@v2` and npm keep serving the previous version while `main` moves on.
432
+ in the range — otherwise the major alias and npm keep serving the previous version while `main`
433
+ moves on.
433
434
 
434
435
  ## Data & licensing
435
436
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultra11y",
3
- "version": "3.0.0",
3
+ "version": "4.0.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",
@@ -7,15 +7,22 @@
7
7
  // script produces — the same reproducibility contract the engine bundle is held to.
8
8
  //
9
9
  // The mark is an eye (the action's own branding icon), drawn as a filled lens with a pupil on
10
- // the purple the action already declares. Written with a hand-rolled PNG encoder because the
11
- // repo has no image dependency and is not about to grow one for four small files.
10
+ // the purple the action already declares. The PNG encoder is the engine's own
11
+ // (`src/pixel.ts`), imported through Node's type-stripping — the repo has no image dependency
12
+ // and is not about to grow one for four small files.
13
+ //
14
+ // That import runs both ways: because these four icons are committed, `--check` re-encodes
15
+ // them and proves `encodePng` still emits the exact bytes it emitted when they were drawn.
16
+ // A decode/encode round-trip could only prove the pair is self-consistent; this proves the
17
+ // encoder is PNG-correct against files a browser accepts. Keep `src/pixel.ts` a leaf (one
18
+ // runtime import, `node:zlib`) or this import stops resolving.
12
19
  //
13
20
  // node scripts/build-extension-icons.mjs # write
14
21
  // node scripts/build-extension-icons.mjs --check # fail if the committed files differ
15
- import { deflateSync } from "node:zlib";
16
22
  import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
17
23
  import { dirname, join } from "node:path";
18
24
  import { fileURLToPath } from "node:url";
25
+ import { encodePng } from "../src/pixel.ts";
19
26
 
20
27
  const OUT = join(dirname(fileURLToPath(import.meta.url)), "..", "extension", "icons");
21
28
  const SIZES = [16, 32, 48, 128];
@@ -24,45 +31,6 @@ const SIZES = [16, 32, 48, 128];
24
31
  const BG = [107, 70, 193]; // #6b46c1
25
32
  const FG = [255, 255, 255];
26
33
 
27
- function crc32(buf) {
28
- let c = ~0;
29
- for (const b of buf) {
30
- c ^= b;
31
- for (let i = 0; i < 8; i++) c = (c >>> 1) ^ (0xedb88320 & -(c & 1));
32
- }
33
- return ~c >>> 0;
34
- }
35
-
36
- function chunk(type, data) {
37
- const len = Buffer.alloc(4);
38
- len.writeUInt32BE(data.length);
39
- const body = Buffer.concat([Buffer.from(type, "latin1"), data]);
40
- const crc = Buffer.alloc(4);
41
- crc.writeUInt32BE(crc32(body));
42
- return Buffer.concat([len, body, crc]);
43
- }
44
-
45
- /** An RGBA pixel buffer → a PNG. Colour type 6, 8-bit, one filter byte per row. */
46
- function png(size, rgba) {
47
- const raw = Buffer.alloc(size * (size * 4 + 1));
48
- for (let y = 0; y < size; y++) {
49
- raw[y * (size * 4 + 1)] = 0; // filter: none — the images are tiny, filtering buys nothing
50
- rgba.copy(raw, y * (size * 4 + 1) + 1, y * size * 4, (y + 1) * size * 4);
51
- }
52
- const ihdr = Buffer.alloc(13);
53
- ihdr.writeUInt32BE(size, 0);
54
- ihdr.writeUInt32BE(size, 4);
55
- ihdr[8] = 8; // bit depth
56
- ihdr[9] = 6; // RGBA
57
- return Buffer.concat([
58
- Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
59
- chunk("IHDR", ihdr),
60
- // level 9 so the bytes are a function of the pixels alone, not of zlib's default tuning.
61
- chunk("IDAT", deflateSync(raw, { level: 9 })),
62
- chunk("IEND", Buffer.alloc(0)),
63
- ]);
64
- }
65
-
66
34
  /** The eye mark, supersampled 4× so the curves do not alias at 16px. */
67
35
  function draw(size) {
68
36
  const S = 4;
@@ -118,7 +86,7 @@ mkdirSync(OUT, { recursive: true });
118
86
  let stale = [];
119
87
  for (const size of SIZES) {
120
88
  const file = join(OUT, `icon-${size}.png`);
121
- const bytes = png(size, draw(size));
89
+ const bytes = encodePng({ width: size, height: size, data: draw(size) });
122
90
  if (check) {
123
91
  let current = null;
124
92
  try {