a11y-loop 0.1.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.
- package/LICENSE +22 -0
- package/README.md +409 -0
- package/THIRD-PARTY-NOTICES.md +32 -0
- package/package.json +51 -0
- package/skill/a11y-loop/SKILL.md +332 -0
- package/skill/a11y-loop/evals/evals.json +168 -0
- package/skill/a11y-loop/evals/trigger-evals.json +20 -0
- package/skill/a11y-loop/references/ai-failure-modes.md +272 -0
- package/skill/a11y-loop/references/apg-patterns.md +264 -0
- package/skill/a11y-loop/references/manual-testing.md +224 -0
- package/skill/a11y-loop/references/wcag22-quick-ref.md +224 -0
- package/src/cli.js +207 -0
- package/src/commands/audit.js +125 -0
- package/src/commands/contrast.js +141 -0
- package/src/commands/diff.js +65 -0
- package/src/lib/axe-runner.js +400 -0
- package/src/lib/browser-utils.js +221 -0
- package/src/lib/checks/dialog.js +341 -0
- package/src/lib/checks/div-button.js +87 -0
- package/src/lib/checks/focus-visible.js +296 -0
- package/src/lib/checks/keyboard.js +235 -0
- package/src/lib/checks/link-text.js +83 -0
- package/src/lib/checks/reduced-motion.js +139 -0
- package/src/lib/checks/reflow.js +101 -0
- package/src/lib/checks/target-size.js +128 -0
- package/src/lib/contrast-math.js +189 -0
- package/src/lib/diff.js +118 -0
- package/src/lib/finding.js +164 -0
- package/src/lib/fingerprint.js +0 -0
- package/src/lib/format/checklist.js +281 -0
- package/src/lib/format/human.js +175 -0
- package/src/lib/format/json.js +139 -0
- package/src/lib/format/sarif.js +111 -0
- package/src/lib/serve.js +189 -0
- package/src/lib/suggest-color.js +169 -0
- package/src/lib/wcag-map.js +271 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chan Meng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
<!-- AGENT-FIRST NOTICE -->
|
|
2
|
+
> [!IMPORTANT]
|
|
3
|
+
> ### ๐ค Read this with your AI agent โ don't read it by hand.
|
|
4
|
+
> This repo is written agent-first. Point Claude Code, GitHub Copilot, Cursor, or any agent at it:
|
|
5
|
+
> *"Read the README and AGENTS.md, then help me run / extend this."*
|
|
6
|
+
> Structure + [`AGENTS.md`](AGENTS.md) are optimized for agent comprehension.
|
|
7
|
+
<!-- /AGENT-FIRST NOTICE -->
|
|
8
|
+
|
|
9
|
+
<div align="center"><a name="readme-top"></a>
|
|
10
|
+
|
|
11
|
+
# ๐ a11y-loop
|
|
12
|
+
|
|
13
|
+
### Write accessible UI by default. Verify it in a real browser. Say exactly what you couldn't check.
|
|
14
|
+
|
|
15
|
+
a11y-loop makes AI coding agents write accessible UI by default, then proves what it can prove
|
|
16
|
+
with a real browser audit across the states it built โ and tells you exactly what it could not
|
|
17
|
+
check.
|
|
18
|
+
|
|
19
|
+
[Demo GIF][demo-link] ยท [SKILL.md][docs-link] ยท [Benchmark](evals/benchmark-results.md) ยท [Changelog](CHANGELOG.md) ยท [Report Bug](https://github.com/ChanMeng666/a11y-loop/issues) ยท [Request Feature](https://github.com/ChanMeng666/a11y-loop/issues)
|
|
20
|
+
|
|
21
|
+
<!-- SHIELD GROUP -->
|
|
22
|
+
|
|
23
|
+
[](LICENSE)
|
|
24
|
+
[](https://github.com/ChanMeng666/a11y-loop/graphs/contributors)
|
|
25
|
+
[](https://github.com/ChanMeng666/a11y-loop/network/members)
|
|
26
|
+
[](https://github.com/ChanMeng666/a11y-loop/stargazers)
|
|
27
|
+
[](https://github.com/ChanMeng666/a11y-loop/issues)
|
|
28
|
+
[](https://github.com/sponsors/ChanMeng666)
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<details>
|
|
39
|
+
<summary><kbd>๐ Table of Contents</kbd></summary>
|
|
40
|
+
|
|
41
|
+
- [๐ Introduction](#-introduction)
|
|
42
|
+
- [๐ฌ Demo](#-demo)
|
|
43
|
+
- [โจ Key Features](#-key-features)
|
|
44
|
+
- [๐ Honest Coverage](#-honest-coverage)
|
|
45
|
+
- [๐ Benchmark](#-benchmark)
|
|
46
|
+
- [๐ ๏ธ Tech Stack](#-tech-stack)
|
|
47
|
+
- [๐๏ธ Architecture](#-architecture)
|
|
48
|
+
- [๐ Getting Started](#-getting-started)
|
|
49
|
+
- [โ๏ธ Using it in CI](#-using-it-in-ci)
|
|
50
|
+
- [๐ Usage Guide](#-usage-guide)
|
|
51
|
+
- [โจ๏ธ Development](#-development)
|
|
52
|
+
- [๐ค Contributing](#-contributing)
|
|
53
|
+
- [โค๏ธ Sponsor](#-sponsor)
|
|
54
|
+
- [๐ License](#-license)
|
|
55
|
+
- [๐โโ๏ธ Author](#-author)
|
|
56
|
+
|
|
57
|
+
</details>
|
|
58
|
+
|
|
59
|
+
## ๐ Introduction
|
|
60
|
+
|
|
61
|
+
AI coding agents write inaccessible UI by default โ 84% of AI-generated web pages carry
|
|
62
|
+
accessibility issues (W4A'24), and telling the model to "be accessible" barely moves that number:
|
|
63
|
+
accessibility-oriented prompts have measured a *slightly higher* violation rate than
|
|
64
|
+
accessibility-agnostic ones (W4A'25, 17.32% vs. 15.93%). Instructions alone are not the fix.
|
|
65
|
+
|
|
66
|
+
a11y-loop is two things working together:
|
|
67
|
+
|
|
68
|
+
1. **An Agent Skill** โ standing generation rules (semantic HTML first, ARIA discipline, APG
|
|
69
|
+
keyboard contracts, labels, focus visibility, AA contrast in light and dark, reduced motion,
|
|
70
|
+
24ร24 targets) that apply while the agent is writing UI code.
|
|
71
|
+
2. **A Node CLI** (`a11y-loop audit` / `contrast --fix` / `diff`) that verifies the result in a
|
|
72
|
+
real browser, feeds failures back to the agent to fix, and re-audits until the loop converges.
|
|
73
|
+
|
|
74
|
+
The skill follows the open [Agent Skills](https://agentskills.io/specification) standard, so the
|
|
75
|
+
same `SKILL.md` is portable across 40+ clients โ Claude Code, Cursor, GitHub Copilot, Codex,
|
|
76
|
+
Gemini CLI, and more โ not just one vendor's agent. The CLI runs the same checks standalone in CI
|
|
77
|
+
or any other pipeline.
|
|
78
|
+
|
|
79
|
+
It was built for the **My Life My Voice** accessibility challenge, run by a disability
|
|
80
|
+
organization in Aotearoa New Zealand, where the NZ Government Web Accessibility Standard 1.2 has
|
|
81
|
+
mandated WCAG 2.2 AA since 17 March 2025. The idea: give AI coding agents a way to build
|
|
82
|
+
accessibility in from the start, instead of treating it as a compliance afterthought bolted on
|
|
83
|
+
after the fact. a11y-loop has no affiliation with My Life My Voice or the NZ government beyond
|
|
84
|
+
having been built for that challenge.
|
|
85
|
+
|
|
86
|
+
**What this is not.** a11y-loop does not claim compliance, does not guarantee accessibility, and
|
|
87
|
+
does not replace manual testing or testing with assistive technology. A clean report means "no
|
|
88
|
+
automatically detectable failures" โ see [Honest Coverage](#-honest-coverage) below for exactly
|
|
89
|
+
what that does and doesn't cover.
|
|
90
|
+
|
|
91
|
+
## ๐ฌ Demo
|
|
92
|
+
|
|
93
|
+

|
|
94
|
+
|
|
95
|
+
The demo page ([`demo/before/`](demo/before)) is a fictional conference site seeded with
|
|
96
|
+
**163 detectable failures** spanning the WebAIM Million's top six failure classes plus the
|
|
97
|
+
failure modes documented for LLM-generated UI: clickable divs, hidden focus indicators, skipped
|
|
98
|
+
heading levels, broken ARIA references, and ignored `prefers-reduced-motion`. Running the loop
|
|
99
|
+
against it converges on [`demo/after/`](demo/after) โ **0 violations** โ and
|
|
100
|
+
`a11y-loop diff --before demo/before/report.json --after demo/after/report.json` reports:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Converged: all 163 violations fixed, none introduced
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`FIXED` / `NEW` / `REMAINING` status per finding, matched by stable fingerprint (rule + selector +
|
|
107
|
+
WCAG success criterion), is what makes that verdict checkable rather than asserted โ see
|
|
108
|
+
[`demo/before/VIOLATIONS.md`](demo/before/VIOLATIONS.md) and
|
|
109
|
+
[`demo/after/FIXES.md`](demo/after/FIXES.md) for the finding-by-finding record.
|
|
110
|
+
|
|
111
|
+
## โจ Key Features
|
|
112
|
+
|
|
113
|
+
`1` **Five rendering passes per audit** โ default (1280ร720), dark mode, forced-colors mode,
|
|
114
|
+
reduced-motion, and a 320ร256 reflow viewport (the WCAG-sanctioned 400% zoom equivalent for
|
|
115
|
+
SC 1.4.10) โ because most real failures only show up under a specific rendering condition, not on
|
|
116
|
+
a single default-viewport load.
|
|
117
|
+
|
|
118
|
+
`2` **Checks axe-core can't run** โ tab order, focus visibility (including focus-ring contrast),
|
|
119
|
+
dialog focus trap / Escape / focus-return, target size (24ร24 CSS px, SC 2.5.8), reduced-motion
|
|
120
|
+
effectiveness, ambiguous link text, div-as-button, and positive `tabindex`. These sit alongside
|
|
121
|
+
axe-core, not instead of it.
|
|
122
|
+
|
|
123
|
+
`3` **State coverage, not just page-load** โ `--interact` drives the states an agent just built
|
|
124
|
+
(a modal opened, a menu expanded, a form in its error state) through the same five passes, because
|
|
125
|
+
axe running once on page load finds nothing in a dialog that only misbehaves once it's open.
|
|
126
|
+
|
|
127
|
+
`4` **Stable fingerprints power regression detection** โ `a11y-loop diff` matches findings across
|
|
128
|
+
two reports by rule + selector + WCAG success criterion and classifies each as FIXED, NEW
|
|
129
|
+
(a regression โ this fails the command even if the total count went down), or REMAINING.
|
|
130
|
+
|
|
131
|
+
`5` **Structured, honest output** โ JSON is the primary format: every finding carries its WCAG
|
|
132
|
+
success criterion, ACT rule ID where one exists, and a provenance block (axe-core version, browser,
|
|
133
|
+
URL, viewport, timestamp, states exercised). SARIF v2.1 is available as a secondary format with
|
|
134
|
+
[a documented limitation](#-honest-coverage) rather than a silent gap. A generated manual-review
|
|
135
|
+
checklist, scoped to what was actually built, ships with every run.
|
|
136
|
+
|
|
137
|
+
`6` **Exit codes are the loop's contract** โ `0` no violations / threshold met / no regression,
|
|
138
|
+
`1` violations found / regression introduced, `2` tool error โ so a CI pipeline or an agent's own
|
|
139
|
+
control flow can branch on the result without parsing prose.
|
|
140
|
+
|
|
141
|
+
`7` **`contrast --fix`** โ checks a foreground/background pair against WCAG 2.x (1.4.3: 4.5:1
|
|
142
|
+
normal text / 3:1 large text; 1.4.11: 3:1 for UI components) and, on failure, suggests passing
|
|
143
|
+
colors in both directions (lighter and darker) in OKLCh, so a fix stays close to the original hue
|
|
144
|
+
instead of jumping to black or white.
|
|
145
|
+
|
|
146
|
+
`8` **Portable as an Agent Skill** โ plain `SKILL.md` + `references/`, no proprietary format, works
|
|
147
|
+
in any client implementing the open Agent Skills standard, not only Claude Code.
|
|
148
|
+
|
|
149
|
+
## ๐ Honest Coverage
|
|
150
|
+
|
|
151
|
+
Automated accessibility testing has a real, bounded scope, and a11y-loop says so in every report
|
|
152
|
+
rather than implying otherwise:
|
|
153
|
+
|
|
154
|
+
- Deque's own research puts automated coverage at **~57% of accessibility issues by volume**
|
|
155
|
+
across a 13,000+ page / ~300,000 issue study โ but only **~31% of WCAG 2.2 AA success criteria**
|
|
156
|
+
have *any* automated rule at all, and only **~13% are reliably automatable** end-to-end.
|
|
157
|
+
- **A clean a11y-loop report means "no automatically detectable failures were found" โ it is
|
|
158
|
+
never a conformance or compliance claim**, and the tool will not tell you your app is
|
|
159
|
+
accessible, compliant, or free of legal risk. No single score is ever produced.
|
|
160
|
+
- Every run emits a **generated manual-review checklist**, scoped to the components actually
|
|
161
|
+
built, naming the criteria that need a human and/or assistive-technology testing (screen reader
|
|
162
|
+
behavior, descriptive quality of alt text and link text, logical reading order, caption/media
|
|
163
|
+
alternative accuracy, cognitive accessibility) โ the direct inverse of "no manual testing
|
|
164
|
+
needed."
|
|
165
|
+
- axe-core's own `incomplete` results are surfaced as `needsReview`, not suppressed. See
|
|
166
|
+
`evals/benchmark-results.md` for a live example of two such findings being investigated and
|
|
167
|
+
resolved rather than dismissed.
|
|
168
|
+
- **SARIF caveat, stated honestly:** GitHub Code Scanning only displays SARIF results that carry a
|
|
169
|
+
file-path location. a11y-loop's findings are located by rendered URL + CSS selector, which
|
|
170
|
+
Code Scanning drops on ingestion โ a naive upload produces an empty Code Scanning view. SARIF
|
|
171
|
+
output is provided for the Azure DevOps SARIF viewer, the VS Code SARIF extension, and other
|
|
172
|
+
SARIF-consuming tooling; the JSON report remains the primary, complete format.
|
|
173
|
+
- Findings are tagged with the **lowest WCAG version** that contains them (2.0 / 2.1 / 2.2), so you
|
|
174
|
+
can filter to the subset a given jurisdiction actually enforces โ e.g. US ADA Title II and
|
|
175
|
+
Section 508 to the 2.0/2.1 AA subset, EU EN 301 549 to 2.1 AA (moving to 2.2 AA around October
|
|
176
|
+
2026), NZ and UK to the full 2.2 AA set.
|
|
177
|
+
|
|
178
|
+
## ๐ Benchmark
|
|
179
|
+
|
|
180
|
+
A small, illustrative comparison in [`evals/benchmark-results.md`](evals/benchmark-results.md):
|
|
181
|
+
the same six UI components, built by the same model (Claude Sonnet 5, as a Claude Code subagent),
|
|
182
|
+
once with no accessibility guidance and once following the skill and running the audit loop to
|
|
183
|
+
convergence.
|
|
184
|
+
|
|
185
|
+
- **Baseline (no guidance): 35 violations across 6 components.** With the skill, **1 violation on
|
|
186
|
+
first generation** โ before any audit ran.
|
|
187
|
+
- **After the loop: 0 violations**, at an average of **1.67 completed audit iterations** per
|
|
188
|
+
component.
|
|
189
|
+
|
|
190
|
+
Read this with its stated caveats: **N = 6 components, a single run per condition, one model
|
|
191
|
+
family, and the audits are produced by a11y-loop's own engine** (mitigated, not eliminated, by
|
|
192
|
+
every finding being grounded in axe-core, a third-party rules engine) โ a small, self-audited
|
|
193
|
+
illustration of the effect's shape, not a controlled study or a precise effect size.
|
|
194
|
+
|
|
195
|
+
## ๐ ๏ธ Tech Stack
|
|
196
|
+
|
|
197
|
+
- **Runtime:** Node.js โฅ 20, ESM (`"type": "module"`)
|
|
198
|
+
- **Browser automation:** [Playwright](https://playwright.dev/) (Chromium)
|
|
199
|
+
- **Accessibility engine:** [axe-core](https://github.com/dequelabs/axe-core) via
|
|
200
|
+
`@axe-core/playwright` (MPL-2.0 โ see [`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md))
|
|
201
|
+
- **Color math:** [culori](https://github.com/Evercoder/culori) (OKLCh contrast fixes)
|
|
202
|
+
- **Focus order:** [tabbable](https://github.com/focus-trap/tabbable)
|
|
203
|
+
- **SARIF conversion:** [axe-sarif-converter](https://github.com/microsoft/axe-sarif-converter)
|
|
204
|
+
- **Agent integration:** the open [Agent Skills](https://agentskills.io/specification) standard โ
|
|
205
|
+
`SKILL.md` + `references/`, no client-proprietary format
|
|
206
|
+
- **Tests:** the built-in `node --test` runner, 337+ tests across unit and integration suites,
|
|
207
|
+
including an 18-fixture seeded-violation matrix, a demo end-to-end run, and a forced-colors
|
|
208
|
+
gradient regression test
|
|
209
|
+
|
|
210
|
+
## ๐๏ธ Architecture
|
|
211
|
+
|
|
212
|
+
<details>
|
|
213
|
+
<summary><kbd>System overview</kbd></summary>
|
|
214
|
+
|
|
215
|
+
```mermaid
|
|
216
|
+
graph TD
|
|
217
|
+
A["Agent Skill<br/>skill/a11y-loop/SKILL.md + references/"] -->|standing generation rules| B["Agent writes UI code<br/>HTML / JSX / Vue / Svelte / Astro / CSS"]
|
|
218
|
+
B --> C["a11y-loop CLI"]
|
|
219
|
+
C --> D["audit<br/>5 passes: default, dark,<br/>forced-colors, reduced-motion, 320px reflow"]
|
|
220
|
+
C --> E["contrast --fix<br/>WCAG 2.x + OKLCh suggestions"]
|
|
221
|
+
C --> F["diff<br/>FIXED / NEW / REMAINING"]
|
|
222
|
+
D --> G["Playwright + Chromium"]
|
|
223
|
+
G --> H["axe-core"]
|
|
224
|
+
G --> I["a11y-loop's own checks<br/>focus, dialog trap, target size,<br/>reduced motion, link text, div-button"]
|
|
225
|
+
D -->|--interact| J["Drive built states:<br/>modal open, menu expanded, form error"]
|
|
226
|
+
H --> K["JSON report<br/>WCAG SC + ACT IDs + provenance"]
|
|
227
|
+
I --> K
|
|
228
|
+
J --> K
|
|
229
|
+
K --> L["SARIF v2.1<br/>(secondary format)"]
|
|
230
|
+
K --> M["Manual-review checklist"]
|
|
231
|
+
K -->|violations found| B
|
|
232
|
+
F --> K
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
</details>
|
|
236
|
+
|
|
237
|
+
The loop, in words: the skill sets standing rules while the agent writes UI; `a11y-loop audit`
|
|
238
|
+
verifies the rendered result across five passes plus any built interaction states; violations feed
|
|
239
|
+
back to the agent to fix; `a11y-loop diff` confirms convergence without new regressions; the JSON
|
|
240
|
+
report (and its manual-review checklist) is the artifact of record, with SARIF offered as a
|
|
241
|
+
secondary format for tools that consume it.
|
|
242
|
+
|
|
243
|
+
## ๐ Getting Started
|
|
244
|
+
|
|
245
|
+
### Prerequisites
|
|
246
|
+
|
|
247
|
+
- Node.js โฅ 20
|
|
248
|
+
- A Chromium install for Playwright (installed in the steps below)
|
|
249
|
+
|
|
250
|
+
### Installation
|
|
251
|
+
|
|
252
|
+
**Not yet published to npm and this repo has no GitHub remote yet** โ install from a local clone
|
|
253
|
+
for now:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Clone and install
|
|
257
|
+
git clone https://github.com/ChanMeng666/a11y-loop.git
|
|
258
|
+
cd a11y-loop
|
|
259
|
+
npm install
|
|
260
|
+
|
|
261
|
+
# Install the Chromium build Playwright needs for audits
|
|
262
|
+
npx playwright install chromium
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Once published, the intended install is `npx a11y-loop <command>` with no local setup at all โ
|
|
266
|
+
that comes after the first npm publish.
|
|
267
|
+
|
|
268
|
+
If you keep browser binaries off the system drive, set `PLAYWRIGHT_BROWSERS_PATH` before running
|
|
269
|
+
`npx playwright install chromium` (and before running the test suite, which launches the same
|
|
270
|
+
browser) โ e.g. `PLAYWRIGHT_BROWSERS_PATH=D:\playwright-browsers`.
|
|
271
|
+
|
|
272
|
+
### Installing the Agent Skill
|
|
273
|
+
|
|
274
|
+
Copy the skill directory into any Agent Skills-compatible client:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
# Personal, all projects (Claude Code and other clients that read ~/.claude/skills)
|
|
278
|
+
cp -r skill/a11y-loop ~/.claude/skills/a11y-loop
|
|
279
|
+
|
|
280
|
+
# Or project-scoped
|
|
281
|
+
cp -r skill/a11y-loop .claude/skills/a11y-loop
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Any client implementing the [Agent Skills specification](https://agentskills.io/specification)
|
|
285
|
+
can load it the same way โ Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI, and more.
|
|
286
|
+
|
|
287
|
+
## โ๏ธ Using it in CI
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
a11y-loop audit http://localhost:3000 --json --out report.json
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
exits `1` if any violation is found (`2` on a tool error such as a missing browser), so a build
|
|
294
|
+
step can gate on it directly:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
a11y-loop audit http://localhost:3000 --json --out report.json || exit 1
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`a11y-loop diff --before base.json --after head.json` in a PR check turns that into a regression
|
|
301
|
+
gate: it fails only on genuinely `NEW` violations, so a PR that fixes ten and introduces none
|
|
302
|
+
passes even though the raw count changed.
|
|
303
|
+
|
|
304
|
+
## ๐ Usage Guide
|
|
305
|
+
|
|
306
|
+
### Basic Usage
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Audit a running page (five passes: default, dark, forced-colors, reduced-motion, reflow)
|
|
310
|
+
a11y-loop audit http://localhost:3000
|
|
311
|
+
|
|
312
|
+
# Audit an HTML file (served locally, never over file://)
|
|
313
|
+
a11y-loop audit --file ./dist/index.html
|
|
314
|
+
|
|
315
|
+
# Audit an HTML fragment directly โ the usual entry point for an agent mid-generation
|
|
316
|
+
a11y-loop audit --html "<button class=\"icon-btn\"><svg .../></button>"
|
|
317
|
+
|
|
318
|
+
# Audit an interactive state (e.g. a modal after it opens)
|
|
319
|
+
a11y-loop audit http://localhost:3000 --interact ./states/modal-open.mjs
|
|
320
|
+
|
|
321
|
+
# Check a color pair against WCAG 2.x and get OKLCh fix suggestions
|
|
322
|
+
a11y-loop contrast "#767676" "#ffffff" --fix
|
|
323
|
+
|
|
324
|
+
# Compare two audit reports for regressions
|
|
325
|
+
a11y-loop diff --before base.json --after head.json
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Advanced Configuration
|
|
329
|
+
|
|
330
|
+
| Flag | Applies to | Effect |
|
|
331
|
+
|---|---|---|
|
|
332
|
+
| `--json` | audit, contrast | machine-readable output on stdout |
|
|
333
|
+
| `--out <path>` | audit | write the JSON report to a file |
|
|
334
|
+
| `--sarif <path>` | audit | also write SARIF v2.1 (see [Honest Coverage](#-honest-coverage)) |
|
|
335
|
+
| `--interact <path.mjs>` | audit | export `const states = { name: async (page) => {} }` to drive built states |
|
|
336
|
+
| `--headed` | audit | run a visible browser, for debugging |
|
|
337
|
+
| `--no-best-practice` | audit | omit axe best-practice rules (never blocking either way) |
|
|
338
|
+
| `--quiet` | audit | one-line summary only |
|
|
339
|
+
| `--large` | contrast | large-scale text thresholds (โฅ24px, or โฅ18.5px bold) |
|
|
340
|
+
| `--ui` | contrast | non-text / UI component threshold, 3:1, SC 1.4.11 |
|
|
341
|
+
| `--fix` | contrast | suggest passing colors, lighter and darker, in OKLCh |
|
|
342
|
+
|
|
343
|
+
Run `a11y-loop --help` for the full, current reference.
|
|
344
|
+
|
|
345
|
+
## โจ๏ธ Development
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
npm install
|
|
349
|
+
npx playwright install chromium # once, or after a Playwright version bump
|
|
350
|
+
|
|
351
|
+
npm test # full suite
|
|
352
|
+
npm run test:unit # unit tests only
|
|
353
|
+
npm run test:integration # integration tests only (drives real Chromium)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
See [`AGENTS.md`](AGENTS.md) for AI-agent-oriented project conventions, the fixture-manifest
|
|
357
|
+
testing pattern, and the loop discipline expected when touching `demo/` or other UI.
|
|
358
|
+
|
|
359
|
+
## ๐ค Contributing
|
|
360
|
+
|
|
361
|
+
Contributions make the open-source community an amazing place to learn and create. Please read the
|
|
362
|
+
[Contributing Guide](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md) before you start,
|
|
363
|
+
and use the provided issue / pull-request templates.
|
|
364
|
+
|
|
365
|
+
## โค๏ธ Sponsor
|
|
366
|
+
|
|
367
|
+
If this project helps you, please consider supporting its development:
|
|
368
|
+
|
|
369
|
+
[](https://github.com/sponsors/ChanMeng666)
|
|
370
|
+
[](https://buymeacoffee.com/chanmeng66u)
|
|
371
|
+
|
|
372
|
+
For questions and help, see [SUPPORT.md](SUPPORT.md). For security issues, see [SECURITY.md](SECURITY.md).
|
|
373
|
+
|
|
374
|
+
## ๐ License
|
|
375
|
+
|
|
376
|
+
This project is released under the [MIT](LICENSE) license. axe-core, a dependency this project
|
|
377
|
+
uses to run its checks, is separately licensed under MPL-2.0 โ see
|
|
378
|
+
[`THIRD-PARTY-NOTICES.md`](THIRD-PARTY-NOTICES.md) for full attribution.
|
|
379
|
+
|
|
380
|
+
## ๐โโ๏ธ Author
|
|
381
|
+
|
|
382
|
+
**Chan Meng**
|
|
383
|
+
|
|
384
|
+
[](mailto:chanmeng.dev@gmail.com)
|
|
385
|
+
[](https://github.com/ChanMeng666)
|
|
386
|
+
|
|
387
|
+
<div align="right">
|
|
388
|
+
|
|
389
|
+
[](#readme-top)
|
|
390
|
+
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
[demo-link]: docs/demo.gif
|
|
394
|
+
[docs-link]: skill/a11y-loop/SKILL.md
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
<!-- CHAN MENG PERSONAL BRAND -->
|
|
399
|
+
<div align="center">
|
|
400
|
+
<a href="https://github.com/ChanMeng666" target="_blank">
|
|
401
|
+
<img src="./.github/brand/chan-meng-logo.svg" alt="Chan Meng" width="160" />
|
|
402
|
+
</a>
|
|
403
|
+
|
|
404
|
+
<p><strong>Chan Meng</strong><br/>Need a custom app like this one? I build them โ let's talk.</p>
|
|
405
|
+
|
|
406
|
+
<a href="mailto:chanmeng.dev@gmail.com"><img src="https://img.shields.io/badge/Email-chanmeng.dev@gmail.com-EA4335?style=flat-square&logo=gmail&logoColor=white" alt="Email Chan Meng"/></a>
|
|
407
|
+
<a href="https://github.com/ChanMeng666"><img src="https://img.shields.io/badge/GitHub-ChanMeng666-181717?style=flat-square&logo=github&logoColor=white" alt="Chan Meng on GitHub"/></a>
|
|
408
|
+
</div>
|
|
409
|
+
<!-- /CHAN MENG PERSONAL BRAND -->
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
a11y-loop is MIT-licensed. It depends on and gratefully acknowledges the following third-party software:
|
|
4
|
+
|
|
5
|
+
## axe-core (and @axe-core/playwright)
|
|
6
|
+
|
|
7
|
+
- Copyright Deque Systems, Inc.
|
|
8
|
+
- License: **Mozilla Public License 2.0 (MPL-2.0)**
|
|
9
|
+
- Source: https://github.com/dequelabs/axe-core
|
|
10
|
+
- axe-core is the rules engine behind `a11y-loop audit`. When a11y-loop runs, `@axe-core/playwright` injects the axe-core script into the audited page. axe-core is used as an unmodified npm dependency; its source is available at the URL above. Per MPL-2.0, the axe-core files remain under MPL-2.0; this notice tells you where to obtain them.
|
|
11
|
+
|
|
12
|
+
## Playwright
|
|
13
|
+
|
|
14
|
+
- Copyright Microsoft Corporation
|
|
15
|
+
- License: Apache-2.0
|
|
16
|
+
- Source: https://github.com/microsoft/playwright
|
|
17
|
+
|
|
18
|
+
## culori
|
|
19
|
+
|
|
20
|
+
- License: MIT
|
|
21
|
+
- Source: https://github.com/Evercoder/culori
|
|
22
|
+
|
|
23
|
+
## tabbable
|
|
24
|
+
|
|
25
|
+
- License: MIT
|
|
26
|
+
- Source: https://github.com/focus-trap/tabbable
|
|
27
|
+
|
|
28
|
+
## axe-sarif-converter
|
|
29
|
+
|
|
30
|
+
- Copyright Microsoft Corporation
|
|
31
|
+
- License: MIT
|
|
32
|
+
- Source: https://github.com/microsoft/axe-sarif-converter
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "a11y-loop",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Makes AI coding agents write accessible UI by default, then proves what it can prove with a real browser audit across the states they built โ and tells you exactly what it could not check.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"a11y-loop": "src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "node --test",
|
|
14
|
+
"test:unit": "node --test \"test/unit/*.test.js\"",
|
|
15
|
+
"test:integration": "node --test \"test/integration/*.test.js\""
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"accessibility",
|
|
19
|
+
"a11y",
|
|
20
|
+
"wcag",
|
|
21
|
+
"axe-core",
|
|
22
|
+
"playwright",
|
|
23
|
+
"ai-agents",
|
|
24
|
+
"agent-skills",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"audit",
|
|
27
|
+
"contrast"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "Chan Meng <chanmeng.dev@gmail.com> (https://github.com/ChanMeng666)",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/ChanMeng666/a11y-loop.git"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/ChanMeng666/a11y-loop#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/ChanMeng666/a11y-loop/issues"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"src/",
|
|
41
|
+
"skill/",
|
|
42
|
+
"THIRD-PARTY-NOTICES.md"
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@axe-core/playwright": "^4.12.1",
|
|
46
|
+
"axe-sarif-converter": "^3.1.0",
|
|
47
|
+
"culori": "^4.0.2",
|
|
48
|
+
"playwright": "^1.62.0",
|
|
49
|
+
"tabbable": "^6.5.0"
|
|
50
|
+
}
|
|
51
|
+
}
|