ultra11y 2.22.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +223 -0
  3. package/docker/Dockerfile +7 -0
  4. package/docker/package.json +9 -0
  5. package/docker/runner.mjs +23 -0
  6. package/package.json +73 -0
  7. package/scripts/bench.mjs +151 -0
  8. package/scripts/build-act-corpus.mjs +143 -0
  9. package/scripts/build-adjudication.mjs +503 -0
  10. package/scripts/build-pack-rgaa.mjs +397 -0
  11. package/scripts/build-standards.mjs +548 -0
  12. package/scripts/copy-bundle.mjs +39 -0
  13. package/scripts/import-pack.mjs +107 -0
  14. package/scripts/sync-engine.mjs +84 -0
  15. package/scripts/sync-version.mjs +43 -0
  16. package/scripts/ultra11y.mjs +52739 -0
  17. package/scripts/vendor/act-testcases.json +12297 -0
  18. package/scripts/vendor/rgaa/SOURCE.json +8 -0
  19. package/scripts/vendor/rgaa/criteres.json +4144 -0
  20. package/scripts/vendor/rgaa/glossaire.json +480 -0
  21. package/scripts/vendor/wcag-2.2-fr.json +82 -0
  22. package/scripts/vendor/wcag-2.2-sc-universe.json +950 -0
  23. package/scripts/vendor/wcag-2.2-sc.json +574 -0
  24. package/scripts/verify-rgaa-source.mjs +126 -0
  25. package/scripts/verify-skill-bundle.mjs +91 -0
  26. package/skills/review-a11y/SKILL.md +123 -0
  27. package/skills/review-a11y/scripts/ultra11y.mjs +52739 -0
  28. package/skills/ultra11y/SKILL.md +292 -0
  29. package/skills/ultra11y/references/act.md +163 -0
  30. package/skills/ultra11y/references/adjudication.md +599 -0
  31. package/skills/ultra11y/references/audit.md +100 -0
  32. package/skills/ultra11y/references/authoring.md +37 -0
  33. package/skills/ultra11y/references/automation.md +113 -0
  34. package/skills/ultra11y/references/correction.md +41 -0
  35. package/skills/ultra11y/references/criteria.md +129 -0
  36. package/skills/ultra11y/references/cross-file.md +82 -0
  37. package/skills/ultra11y/references/dynamic.md +152 -0
  38. package/skills/ultra11y/references/false-positives.md +81 -0
  39. package/skills/ultra11y/references/fix.md +46 -0
  40. package/skills/ultra11y/references/focus-and-logic.md +64 -0
  41. package/skills/ultra11y/references/forbidden-patterns.md +61 -0
  42. package/skills/ultra11y/references/forms-and-errors.md +147 -0
  43. package/skills/ultra11y/references/guidance.md +55 -0
  44. package/skills/ultra11y/references/judgment.md +90 -0
  45. package/skills/ultra11y/references/media-and-motion.md +116 -0
  46. package/skills/ultra11y/references/methodology.md +72 -0
  47. package/skills/ultra11y/references/naming.md +117 -0
  48. package/skills/ultra11y/references/orchestration.md +44 -0
  49. package/skills/ultra11y/references/packs.md +193 -0
  50. package/skills/ultra11y/references/prd.md +104 -0
  51. package/skills/ultra11y/references/rendered.md +110 -0
  52. package/skills/ultra11y/references/scale.md +49 -0
  53. package/skills/ultra11y/references/standards.md +97 -0
  54. package/skills/ultra11y/references/structure.md +138 -0
  55. package/skills/ultra11y/references/verify.md +88 -0
  56. package/skills/ultra11y/references/widgets.md +106 -0
  57. package/skills/ultra11y/scripts/ultra11y.mjs +52739 -0
  58. package/src/act.ts +441 -0
  59. package/src/adjudicate.ts +630 -0
  60. package/src/aria.ts +230 -0
  61. package/src/audit.ts +396 -0
  62. package/src/auditor.ts +399 -0
  63. package/src/autofill.ts +102 -0
  64. package/src/axe-map.ts +294 -0
  65. package/src/baseline.ts +75 -0
  66. package/src/capture.ts +182 -0
  67. package/src/check.ts +243 -0
  68. package/src/cli.ts +1927 -0
  69. package/src/color.ts +102 -0
  70. package/src/config.ts +182 -0
  71. package/src/crawl.ts +75 -0
  72. package/src/criteria.ts +183 -0
  73. package/src/data/adjudication.json +770 -0
  74. package/src/data/guidance/rgaa.json +2395 -0
  75. package/src/data/standards/rgaa.glossary.json +478 -0
  76. package/src/data/standards/rgaa.json +3454 -0
  77. package/src/data/wcag-universe.json +530 -0
  78. package/src/data/wcag.json +1178 -0
  79. package/src/discover.ts +203 -0
  80. package/src/fix/codemods.ts +76 -0
  81. package/src/fix/diff.ts +64 -0
  82. package/src/fix/edits.ts +126 -0
  83. package/src/fix.ts +215 -0
  84. package/src/gh.ts +214 -0
  85. package/src/glob.ts +206 -0
  86. package/src/graph/build.ts +114 -0
  87. package/src/graph/engine-resolve.ts +0 -0
  88. package/src/graph/graph.ts +126 -0
  89. package/src/graph/imports.ts +359 -0
  90. package/src/graph/resolve.ts +73 -0
  91. package/src/graph/tsconfig.ts +113 -0
  92. package/src/grounding.ts +119 -0
  93. package/src/guidance/index.ts +45 -0
  94. package/src/guidance/types.ts +36 -0
  95. package/src/init.ts +113 -0
  96. package/src/mcp/handlers.ts +388 -0
  97. package/src/mcp/http.ts +260 -0
  98. package/src/mcp/prompts.ts +183 -0
  99. package/src/mcp/protocol.ts +187 -0
  100. package/src/mcp/resources.ts +136 -0
  101. package/src/mcp/server.ts +228 -0
  102. package/src/mcp/stdio.ts +119 -0
  103. package/src/mcp/tools.ts +347 -0
  104. package/src/messages.ts +1011 -0
  105. package/src/name.ts +174 -0
  106. package/src/orchestrate-templates.ts +231 -0
  107. package/src/orchestrate.ts +186 -0
  108. package/src/output.ts +108 -0
  109. package/src/pack.ts +187 -0
  110. package/src/parse/html.ts +258 -0
  111. package/src/parse/jsx-ast.ts +67 -0
  112. package/src/parse/jsx-bridge.ts +247 -0
  113. package/src/parse/jsx.ts +19 -0
  114. package/src/parse/source.ts +75 -0
  115. package/src/prd.ts +406 -0
  116. package/src/project-lock.ts +42 -0
  117. package/src/render.ts +307 -0
  118. package/src/report.ts +399 -0
  119. package/src/rules/colors.ts +125 -0
  120. package/src/rules/cross-registry.ts +264 -0
  121. package/src/rules/cross-rule.ts +83 -0
  122. package/src/rules/forms.ts +590 -0
  123. package/src/rules/frames.ts +33 -0
  124. package/src/rules/headings.ts +227 -0
  125. package/src/rules/images.ts +200 -0
  126. package/src/rules/links.ts +193 -0
  127. package/src/rules/mandatory.ts +173 -0
  128. package/src/rules/multimedia.ts +77 -0
  129. package/src/rules/navigation.ts +190 -0
  130. package/src/rules/presentation.ts +75 -0
  131. package/src/rules/registry.ts +57 -0
  132. package/src/rules/rule.ts +122 -0
  133. package/src/rules/scripts-aria.ts +636 -0
  134. package/src/rules/tables.ts +264 -0
  135. package/src/rules/timing.ts +55 -0
  136. package/src/sample.ts +176 -0
  137. package/src/scan-local.ts +866 -0
  138. package/src/scan.ts +538 -0
  139. package/src/standards/derive.ts +195 -0
  140. package/src/standards/index.ts +31 -0
  141. package/src/standards/pack-rules.ts +111 -0
  142. package/src/standards/pack.ts +81 -0
  143. package/src/standards/registry.ts +100 -0
  144. package/src/standards/types.ts +202 -0
  145. package/src/standards/validate.ts +544 -0
  146. package/src/standards/vocabulary.ts +75 -0
  147. package/src/types.ts +355 -0
  148. package/src/util.ts +32 -0
  149. package/src/vendor/codeindex-engine.d.mts +1009 -0
  150. package/src/vendor/codeindex-engine.mjs +13701 -0
  151. package/src/vendor/engine.meta.json +9 -0
  152. package/src/verify.ts +275 -0
  153. package/src/wcag.ts +128 -0
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ // Install-bundle gate: prove the repo is shaped so that `npx skills add
3
+ // maxgfr/<name>` installs WORKING skills — engine + references included, not
4
+ // just a lone SKILL.md.
5
+ //
6
+ // The `skills` CLI (skills.sh) early-returns the moment it sees a SKILL.md at
7
+ // the repository ROOT and then installs that file ALONE — the sibling
8
+ // scripts/ and references/ are dropped. A skill is only bundled whole when its
9
+ // SKILL.md lives in a SUBDIRECTORY (skills/<name>/). This script asserts that
10
+ // shape for EVERY skill under skills/ and that each embedded engine is
11
+ // byte-identical to the tested bundle.
12
+ //
13
+ // Run by CI and by `pnpm run verify:bundle`. Pure Node, no deps, no network.
14
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
15
+ import { dirname, join } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ // Claude Code matches skill descriptions at <=1024 chars; 1000 leaves a safety
19
+ // margin so a future edit can't silently cross the cap.
20
+ const DESC_MAX = 1000;
21
+
22
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
23
+ const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
24
+ const engine = `scripts/${pkg.name}.mjs`;
25
+ const errors = [];
26
+ const ok = (m) => console.log(` ok ${m}`);
27
+ const bad = (m) => {
28
+ errors.push(m);
29
+ console.log(` FAIL ${m}`);
30
+ };
31
+
32
+ // 1. No SKILL.md at the repo root (would make `skills add` install it alone).
33
+ existsSync(join(root, "SKILL.md"))
34
+ ? bad("a SKILL.md exists at the repo ROOT — `skills add` would install it alone, dropping the engine. Move it under skills/<name>/SKILL.md")
35
+ : ok("no root SKILL.md");
36
+
37
+ const rootEngine = join(root, engine);
38
+ if (!existsSync(rootEngine)) bad(`missing ${engine} at repo root — run \`pnpm run build\``);
39
+
40
+ const skillNames = readdirSync(join(root, "skills")).filter((d) => statSync(join(root, "skills", d)).isDirectory());
41
+ if (skillNames.length === 0) bad("skills/ contains no skill directory");
42
+
43
+ for (const name of skillNames) {
44
+ const skillDir = join(root, "skills", name);
45
+ console.log(`skill ${name}:`);
46
+
47
+ // 2. The packaged SKILL.md exists with valid, installable frontmatter.
48
+ const skillMd = join(skillDir, "SKILL.md");
49
+ if (!existsSync(skillMd)) {
50
+ bad(`missing skills/${name}/SKILL.md — the skill package has no SKILL.md`);
51
+ continue;
52
+ }
53
+ const raw = readFileSync(skillMd, "utf8");
54
+ const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
55
+ if (!fm) bad(`skills/${name}/SKILL.md has no frontmatter block`);
56
+ else {
57
+ ok("packaged SKILL.md present with frontmatter");
58
+ const nameLine = fm[1].match(/^name:\s*(.+)$/m)?.[1]?.trim();
59
+ nameLine === name ? ok(`frontmatter name "${name}" matches its directory`) : bad(`frontmatter name "${nameLine}" != skill directory "${name}"`);
60
+ const desc = fm[1].match(/^description:\s*(.+)$/m)?.[1]?.trim();
61
+ if (!desc) bad(`skills/${name}: frontmatter has no description`);
62
+ else {
63
+ const len = desc.replace(/^["']|["']$/g, "").length;
64
+ len <= DESC_MAX ? ok(`description ${len} chars (<= ${DESC_MAX} safety cap)`) : bad(`skills/${name}: description ${len} chars exceeds the ${DESC_MAX}-char safety cap (matcher limit is 1024)`);
65
+ }
66
+ }
67
+
68
+ // 3. Every references/*.md mentioned exists, and every file is mentioned.
69
+ const refsDir = join(skillDir, "references");
70
+ if (existsSync(refsDir)) {
71
+ const mentioned = new Set(raw.match(/references\/[a-z0-9-]+\.md/g) ?? []);
72
+ for (const ref of mentioned) existsSync(join(skillDir, ref)) ? ok(`mentioned ${ref} exists`) : bad(`skills/${name}: ${ref} is mentioned in SKILL.md but missing from the package`);
73
+ for (const f of readdirSync(refsDir).filter((f) => f.endsWith(".md"))) raw.includes(`references/${f}`) ? null : bad(`skills/${name}: references/${f} exists but SKILL.md never mentions it`);
74
+ ok(`references/ present (${readdirSync(refsDir).filter((f) => f.endsWith(".md")).length} playbooks)`);
75
+ }
76
+
77
+ // 4. The embedded engine is byte-identical to the committed root bundle.
78
+ const pkgEngine = join(skillDir, engine);
79
+ if (!existsSync(rootEngine)) continue; // already reported above
80
+ if (!existsSync(pkgEngine)) bad(`missing skills/${name}/${engine} — run \`node scripts/copy-bundle.mjs\``);
81
+ else
82
+ readFileSync(rootEngine).equals(readFileSync(pkgEngine))
83
+ ? ok(`embedded engine skills/${name}/${engine} is byte-identical to ${engine}`)
84
+ : bad(`skills/${name}/${engine} differs from ${engine} — run \`node scripts/copy-bundle.mjs\` and commit`);
85
+ }
86
+
87
+ if (errors.length) {
88
+ console.error(`\nverify-skill-bundle: ${errors.length} problem(s) — a published skill would not install correctly.`);
89
+ process.exit(1);
90
+ }
91
+ console.log(`\nverify-skill-bundle: ok — ${skillNames.map((n) => `skills/${n}/`).join(", ")} install as complete skills.`);
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: review-a11y
3
+ description: "Use to REVIEW code changes for accessibility — '/review-a11y', 'review my changes/PR/branch for a11y', 'accessibility review of this diff'. Scopes to exactly the code under change (staged files, working diff, or branch vs merge-base), runs the bundled install-free ultra11y engine (node scripts/ultra11y.mjs, no keys; static WCAG 2.2 AA checks tied to success criteria, cross-file JSX/TSX via --graph), then adds YOUR judgment: refute false positives (SFC/library-source findings are preliminary), decide alt relevance and link purpose, name the rendering criteria (contrast, focus, zoom) as residual risks — never invent a non-conformity. Output: a severity-ranked review (blocking → major → minor) with file:line, concrete fixes, residual risks and a one-line verdict, in the conversation's language (technical tokens stay in English). Companion of the ultra11y skill (full audits, reports, PRD, RGAA packs). Triggers: 'review a11y', 'a11y review', 'accessibility review'."
4
+ license: MIT
5
+ metadata:
6
+ version: 2.22.0
7
+ ---
8
+
9
+ # review-a11y — accessibility review of changed code
10
+
11
+ The review counterpart of the `ultra11y` skill: where `ultra11y` produces full audits and
12
+ compliance deliverables, **this skill reviews exactly the code under change** — a diff, a
13
+ branch, a PR — and reports like a code reviewer. Same division of labour: the
14
+ deterministic, install-free engine bundled with this skill does the *mechanical* work
15
+ (machine-checkable WCAG 2.2 AA non-conformities, each tied to a success criterion, cited
16
+ `file:line`), and **the AI agent** *adjudicates the judgment* — refute false positives, decide
17
+ alt relevance/link purpose/focus logic statically from the code, and route what needs a rendered
18
+ DOM to `scan`. A human is at most optional oversight.
19
+
20
+ **Engine resolution:** every command below is `node scripts/ultra11y.mjs …` where
21
+ `scripts/ultra11y.mjs` lives **next to this SKILL.md** (the engine ships inside the skill;
22
+ no install, no key). Run it with the reviewed project as the working directory. In the
23
+ ultra11y repository itself, the repo root's `scripts/ultra11y.mjs` is the same file.
24
+
25
+ > **Core rules** (shared with `ultra11y`):
26
+ > 1. **Never invent a non-conformity**: report only what the engine found or what you can
27
+ > see and cite in the code under review.
28
+ > 2. **Review the change, not the world**: findings outside the reviewed scope are noted in
29
+ > one line at most ("pre-existing, out of scope"), never mixed into the verdict.
30
+ > 3. **Residual is explicit, never silently conforming**: the *rendering* criteria (contrast,
31
+ > focus visibility, zoom/reflow, content-on-hover) are named as residual risks for the changed
32
+ > components — never asserted from source, resolved in the rendered page (`scan`). The
33
+ > *judgment* criteria (alt relevance, link purpose, reading order) the AI agent adjudicates
34
+ > from the code itself, recording a reason — no status without a justified verdict.
35
+ > 4. **Language**: write the review in the conversation's language, but technical tokens
36
+ > stay in English even in French prose — `aria-live` stays `aria-live` (never
37
+ > « région live »), same for `tabindex`, `alt`, `role="alert"`, landmark role names.
38
+
39
+ ## 1. Scope — review what changed
40
+
41
+ Pick the FIRST that applies (ask only when genuinely ambiguous):
42
+
43
+ ```
44
+ node scripts/ultra11y.mjs audit <files the user named> --jsx --json # explicit files
45
+ node scripts/ultra11y.mjs audit --staged --graph --json # staged snapshot (pre-commit review)
46
+ node scripts/ultra11y.mjs audit --changed --graph --json # working diff
47
+ node scripts/ultra11y.mjs audit --since origin/main --graph --json # the whole branch (PR review) — use the repo's default branch
48
+ ```
49
+
50
+ - Always pass `--graph` for JSX/TSX (real AST + cross-file rules: icon-only component used
51
+ without a name, anchor target defined in another file…); it also suppresses a class of
52
+ single-file false positives.
53
+ - Pass `--lang` matching the conversation so the engine's message/remediation strings are
54
+ in the review's language (unset, the CLI auto-detects — a fallback, not a substitute).
55
+ - Whole-repo review is an **audit**, not a review — offer the `ultra11y` skill instead.
56
+ - Test/story markup (`*.test.*`, `*.stories.*`, `__tests__/`) is excluded by default; name
57
+ such a file explicitly to include it, or pass `--no-default-excludes`.
58
+
59
+ ## 2. Judge — the engine's findings are candidates, not verdicts
60
+
61
+ For each finding (`--json` gives `criteria`, `severity`, `file:line`, `message`,
62
+ `remediation`):
63
+
64
+ - **Confirm the occurrence**: open the cited line; the offending element must really be
65
+ there in the change under review.
66
+ - **`preliminary: true` findings** (`.vue`/`.svelte`/`.astro` source, library components):
67
+ the template parser cannot see slots, conditionals or provide/inject wiring. Confirm
68
+ against the rendered DOM if captures exist (`.ultra11y/captures`, from the `ultra11y`
69
+ skill's `render --setup` harvester), otherwise report them as **provisional** with that
70
+ caveat — or refute them with evidence from the code.
71
+ - **Library-rendered JSX (DSFR, MUI…)**: a clean source review can still ship broken HTML
72
+ (false negatives) — say so explicitly when the change touches such components, and
73
+ recommend a rendered-DOM check (`scan`, or the `ultra11y` capture pipeline).
74
+ - **The judgment criteria are the AI agent's to adjudicate**: alt text relevance, link purpose
75
+ in context, visible label vs accessible name, keyboard/focus logic of the changed component
76
+ (read the full component source, not just the flagged line), recording a reason for each call.
77
+ - Refuting a finding requires **cited evidence** (the code that disproves it); silently
78
+ dropping findings is forbidden.
79
+
80
+ ## 3. Report — a review, not a compliance document
81
+
82
+ Render in the conversation's language (Core rule 4), grouped by severity:
83
+
84
+ ```
85
+ ## Accessibility review — <scope, e.g. branch feat/x vs main, 12 files>
86
+
87
+ ### 🔴 Blocking
88
+ - `src/components/Form.tsx:42` — **3.3.2 Labels or Instructions** — input has no
89
+ label and placeholder is its only hint → associate a real <label for>, keep the
90
+ placeholder as an example only.
91
+
92
+ ### 🟠 Major / 🟡 Minor
93
+ - …same shape…
94
+
95
+ ### Residual risks (rendering-dependent — resolve in the rendered page via scan)
96
+ - contrast of the new button variants (1.4.3), focus visibility on the custom menu (2.4.7)
97
+
98
+ ### Verdict
99
+ 1 blocking, 2 major to fix before merge; 2 provisional SFC findings to confirm on the
100
+ rendered DOM; residual risks listed above.
101
+ ```
102
+
103
+ - Keep the engine's `remediation` text as the base of each fix — it is already localized
104
+ and criterion-grounded.
105
+ - Pre-existing issues spotted in passing go in ONE final line, out of the verdict.
106
+
107
+ ## 4. After the review (opt-in)
108
+
109
+ - **Safe mechanical fixes**: `fix --staged --write --safe` (auto-applies the safe codemods
110
+ to staged files and re-stages them) or `node scripts/ultra11y.mjs fix <files> --write`;
111
+ dry-run without `--write`.
112
+ - **Formal deliverables** (dated report, auditor conformance blocks, PRD backlog, GitHub
113
+ issues, RGAA/country-standard vocabulary): that is the `ultra11y` skill — same engine,
114
+ same findings (`report`, `prd`, `check`/`verify` gates).
115
+ - **Make it automatic**: the `ultra11y` skill's `init --hook` installs a pre-commit gate
116
+ running this same staged review mechanically.
117
+
118
+ ## Do not
119
+
120
+ - Invent a non-conformity the engine did not find and you cannot cite.
121
+ - Assert contrast/focus/zoom from source — they are residual risks until rendered (resolve via `scan`).
122
+ - Mix pre-existing repo issues into the verdict on the change.
123
+ - Translate technical tokens in French prose (`aria-live`, never « région live »).