@diegovelasquezweb/a11y-engine 0.8.3 → 0.8.4

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @diegovelasquezweb/a11y-engine
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@diegovelasquezweb/a11y-engine)](https://www.npmjs.com/package/@diegovelasquezweb/a11y-engine)
4
+
3
5
  Accessibility automation engine for web applications. It orchestrates multi engine scanning, stack aware enrichment, and report generation for apps and services through a stable API.
4
6
 
5
7
  ## What it does
@@ -12,7 +14,7 @@ Accessibility automation engine for web applications. It orchestrates multi engi
12
14
  | **Fix intelligence** | Enriches each finding with WCAG mapping, fix code snippets, framework and CMS specific notes, UI library ownership hints, effort estimates, and persona impact |
13
15
  | **AI enrichment** | Optional Claude-powered analysis that adds contextual fix suggestions based on detected stack, repo structure, and finding patterns |
14
16
  | **Report generation** | Produces HTML dashboard, PDF compliance report, manual testing checklist, and Markdown remediation guide |
15
- | **Source code scanning** | Static regex analysis of project source for accessibility patterns that runtime engines cannot detect works with local paths or remote GitHub repos |
17
+ | **Source code scanning** | Static regex analysis of project source for accessibility patterns that runtime engines cannot detect. Works with local paths or remote GitHub repos |
16
18
 
17
19
  ## Installation
18
20
 
@@ -58,13 +60,13 @@ const payload = await runAudit({
58
60
  maxRoutes: 5,
59
61
  axeTags: ["wcag2a", "wcag2aa", "best-practice"],
60
62
  engines: { axe: true, cdp: true, pa11y: true },
61
- repoUrl: "https://github.com/owner/repo", // optional enables source pattern scan and stack detection from package.json
62
- githubToken: process.env.GH_TOKEN, // optional for private repos and higher GitHub API rate limits
63
+ repoUrl: "https://github.com/owner/repo", // optional, enables source pattern scan and stack detection
64
+ githubToken: process.env.GH_TOKEN, // optional, required for private repos
63
65
  ai: {
64
66
  enabled: true,
65
67
  apiKey: process.env.ANTHROPIC_API_KEY,
66
68
  githubToken: process.env.GH_TOKEN,
67
- systemPrompt: "Custom prompt...", // optional overrides default Claude system prompt
69
+ systemPrompt: "Custom prompt...", // optional, overrides default Claude system prompt
68
70
  },
69
71
  onProgress: (step, status, extra) => console.log(`${step}: ${status}`, extra),
70
72
  });
@@ -135,25 +137,7 @@ See [API Reference](docs/api-reference.md) for exact options and return types.
135
137
 
136
138
  ## CLI
137
139
 
138
- The package exposes an `a11y-audit` binary for terminal execution.
139
-
140
- ```bash
141
- # Basic scan
142
- pnpm exec a11y-audit --base-url https://example.com
143
-
144
- # With source code pattern scanning via GitHub API (no clone)
145
- pnpm exec a11y-audit --base-url https://example.com \
146
- --repo-url https://github.com/owner/repo \
147
- --github-token ghp_...
148
-
149
- # With AI enrichment (set ANTHROPIC_API_KEY env var)
150
- ANTHROPIC_API_KEY=sk-ant-... pnpm exec a11y-audit --base-url https://example.com
151
-
152
- # With custom AI system prompt
153
- AI_SYSTEM_PROMPT="You are..." ANTHROPIC_API_KEY=sk-ant-... pnpm exec a11y-audit --base-url https://example.com
154
- ```
155
-
156
- See the [CLI Handbook](docs/cli-handbook.md) for all flags and examples.
140
+ The package exposes an `a11y-audit` binary for terminal execution. See the [CLI Handbook](docs/cli-handbook.md) for all flags, env vars, and examples.
157
141
 
158
142
  ## AI enrichment
159
143
 
@@ -163,7 +147,7 @@ When `ANTHROPIC_API_KEY` is set, the engine runs a post-scan enrichment step tha
163
147
  - A production-quality code snippet in the correct framework syntax
164
148
  - Context-aware suggestions when repo source files are available
165
149
 
166
- AI output is stored in separate fields (`ai_fix_description`, `ai_fix_code`) the original engine fixes are always preserved. Findings improved by AI are flagged with `aiEnhanced: true`.
150
+ AI output is stored in separate fields (`ai_fix_description`, `ai_fix_code`). The original engine fixes are always preserved. Findings improved by AI are flagged with `aiEnhanced: true`.
167
151
 
168
152
  The system prompt is fully customizable via `options.ai.systemPrompt` (programmatic API) or the `AI_SYSTEM_PROMPT` env var (CLI).
169
153
 
@@ -4,174 +4,444 @@
4
4
 
5
5
  ---
6
6
 
7
- ## Core API
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Import](#import)
11
+ - [End-to-end example](#end-to-end-example)
12
+ - [Core API](#core-api)
13
+ - [runAudit](#runauditoptions)
14
+ - [getFindings](#getfindingsinput-options)
15
+ - [getOverview](#getoverviewfindings-payload)
16
+ - [Output API](#output-api)
17
+ - [getPDFReport](#getpdfreportpayload-options)
18
+ - [getHTMLReport](#gethtmlreportpayload-options)
19
+ - [getChecklist](#getchecklistoptions)
20
+ - [getRemediationGuide](#getremediationguidepayload-options)
21
+ - [getSourcePatterns](#getsourcepatternsprojdir-options)
22
+ - [Knowledge API](#knowledge-api)
23
+ - [getKnowledge](#getknowledgeoptions)
24
+ - [getScannerHelp](#getscannerhelpoptions)
25
+ - [getPersonaReference](#getpersonareferenceoptions)
26
+ - [getUiHelp](#getuihelpoptions)
27
+ - [getConformanceLevels](#getconformancelevelsoptions)
28
+ - [getWcagPrinciples](#getwcagprinciplesoptions)
29
+ - [getSeverityLevels](#getseveritylevelsoptions)
8
30
 
9
- ### `runAudit(options)`
31
+ ---
10
32
 
11
- Runs route discovery, runtime scan, merge, analyzer enrichment, and optional AI enrichment. Supports local project paths or remote GitHub repos for stack detection and source pattern scanning.
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install @diegovelasquezweb/a11y-engine
37
+ npx playwright install chromium
38
+ npx puppeteer browsers install chrome
39
+ ```
40
+
41
+ ## Import
42
+
43
+ All functions are named exports from the package root:
44
+
45
+ ```ts
46
+ import {
47
+ runAudit,
48
+ getFindings,
49
+ getOverview,
50
+ getPDFReport,
51
+ getHTMLReport,
52
+ getChecklist,
53
+ getRemediationGuide,
54
+ getSourcePatterns,
55
+ getKnowledge,
56
+ getScannerHelp,
57
+ getPersonaReference,
58
+ getUiHelp,
59
+ getConformanceLevels,
60
+ getWcagPrinciples,
61
+ getSeverityLevels,
62
+ } from "@diegovelasquezweb/a11y-engine";
63
+ ```
12
64
 
13
- `options` (`RunAuditOptions`):
65
+ ---
14
66
 
15
- | Option | Type |
16
- | :--- | :--- |
17
- | `baseUrl` | `string` |
18
- | `maxRoutes` | `number` |
19
- | `crawlDepth` | `number` |
20
- | `routes` | `string` |
21
- | `waitMs` | `number` |
22
- | `timeoutMs` | `number` |
23
- | `headless` | `boolean` |
24
- | `waitUntil` | `string` |
25
- | `colorScheme` | `string` |
26
- | `viewport` | `{ width: number; height: number }` |
27
- | `axeTags` | `string[]` |
28
- | `onlyRule` | `string` |
29
- | `excludeSelectors` | `string[]` |
30
- | `ignoreFindings` | `string[]` |
31
- | `framework` | `string` |
32
- | `projectDir` | `string` |
33
- | `repoUrl` | `string` |
34
- | `githubToken` | `string` |
35
- | `skipPatterns` | `boolean` |
36
- | `screenshotsDir` | `string` |
37
- | `engines` | `{ axe?: boolean; cdp?: boolean; pa11y?: boolean }` |
38
- | `ai` | `{ enabled?: boolean; apiKey?: string; githubToken?: string; model?: string; systemPrompt?: string }` — `systemPrompt` overrides the default Claude prompt when set |
39
- | `onProgress` | `(step: string, status: string, extra?: Record<string, unknown>) => void` |
40
-
41
- Progress steps emitted via `onProgress`:
42
-
43
- | Step | When |
67
+ ## End-to-end example
68
+
69
+ ```ts
70
+ import { runAudit, getFindings, getOverview } from "@diegovelasquezweb/a11y-engine";
71
+
72
+ // 1. Run the scan
73
+ const payload = await runAudit({
74
+ baseUrl: "https://example.com",
75
+ maxRoutes: 5,
76
+ engines: { axe: true, cdp: true, pa11y: true },
77
+ onProgress: (step, status) => console.log(`[${step}] ${status}`),
78
+ });
79
+
80
+ // 2. Get enriched findings
81
+ const findings = getFindings(payload);
82
+
83
+ // 3. Get compliance summary
84
+ const { score, scoreLabel, wcagStatus, totals, quickWins } = getOverview(findings, payload);
85
+
86
+ console.log(`Score: ${score}/100 (${scoreLabel})`);
87
+ console.log(`WCAG Status: ${wcagStatus}`);
88
+ console.log(`Critical: ${totals.Critical}, Serious: ${totals.Serious}`);
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Core API
94
+
95
+ ### `runAudit(options)`
96
+
97
+ Runs the full audit pipeline: route discovery → axe/CDP/pa11y scan → merge/dedup → analyzer enrichment → optional source pattern scanning → optional AI enrichment.
98
+
99
+ Returns a `ScanPayload` object consumed by all other functions.
100
+
101
+ **Options:**
102
+
103
+ | Option | Type | Default | Range / Values | Description |
104
+ | :--- | :--- | :--- | :--- | :--- |
105
+ | `baseUrl` | `string` | — | Required | Starting URL including protocol (`https://` or `http://`) |
106
+ | `maxRoutes` | `number` | `10` | 1 – 50 | Maximum unique pages to discover and scan |
107
+ | `crawlDepth` | `number` | `2` | 1 – 3 | BFS link-follow depth from `baseUrl`. Has no effect when `routes` is set |
108
+ | `routes` | `string` | — | CSV paths | Explicit paths to scan (e.g. `"/,/about,/contact"`). Overrides auto-discovery entirely |
109
+ | `waitUntil` | `string` | `"domcontentloaded"` | `"domcontentloaded"` \| `"load"` \| `"networkidle"` | Page load strategy. Use `"networkidle"` for SPAs that render after `DOMContentLoaded` |
110
+ | `waitMs` | `number` | `2000` | 0 – 10000 | Fixed delay (ms) after page load before engines run |
111
+ | `timeoutMs` | `number` | `30000` | 5000 – 120000 | Network timeout per page (ms) |
112
+ | `headless` | `boolean` | `true` | — | Set `false` to open a visible browser for debugging |
113
+ | `viewport` | `object` | `{ width: 1280, height: 800 }` | width: 320–2560, height: 320–2560 | Browser viewport dimensions in pixels |
114
+ | `colorScheme` | `string` | `"light"` | `"light"` \| `"dark"` | Emulates `prefers-color-scheme` media query |
115
+ | `engines` | `object` | all `true` | `{ axe?, cdp?, pa11y? }` | Which engines to run. At least one must be enabled |
116
+ | `axeTags` | `string[]` | WCAG 2.x A+AA | See below | axe-core rule tag filter. Also determines pa11y standard |
117
+ | `onlyRule` | `string` | — | axe rule ID | Run a single axe rule only (e.g. `"color-contrast"`) |
118
+ | `ignoreFindings` | `string[]` | — | axe rule IDs | Suppress specific rules from output entirely |
119
+ | `excludeSelectors` | `string[]` | — | CSS selectors | Skip elements matching these selectors during axe scan |
120
+ | `framework` | `string` | auto-detected | See below | Override framework detection for fix notes and source boundaries |
121
+ | `projectDir` | `string` | — | local path | Local project source directory. Enables source pattern scanning and package.json stack detection |
122
+ | `repoUrl` | `string` | — | GitHub URL | Remote repo URL. Enables source pattern scanning via GitHub API — no clone required |
123
+ | `githubToken` | `string` | — | GitHub PAT | Increases GitHub API rate limit from 60 to 5,000 req/hr. Required for private repos |
124
+ | `skipPatterns` | `boolean` | `false` | — | Disable source pattern scanning even when `projectDir` or `repoUrl` is set |
125
+ | `screenshotsDir` | `string` | `.audit/screenshots` | dir path | Directory where element screenshots are saved |
126
+ | `ai.enabled` | `boolean` | `false` | — | Enable Claude AI enrichment for Critical and Serious findings |
127
+ | `ai.apiKey` | `string` | — | Anthropic API key | Required when `ai.enabled` is `true` |
128
+ | `ai.githubToken` | `string` | — | GitHub PAT | Used to fetch source files from the repo for AI context |
129
+ | `ai.model` | `string` | `"claude-haiku-4-5-20251001"` | Anthropic model ID | Claude model to use |
130
+ | `ai.systemPrompt` | `string` | Built-in prompt | — | Overrides the default Claude system prompt for the entire scan |
131
+ | `onProgress` | `function` | — | — | Callback fired at each pipeline step |
132
+
133
+ **`axeTags` common values:**
134
+
135
+ | Tag | Covers |
44
136
  | :--- | :--- |
45
- | `page` | Always page load |
46
- | `axe` | Always axe-core scan |
47
- | `cdp` | Always CDP accessibility tree check |
48
- | `pa11y` | Always pa11y HTML CodeSniffer scan |
49
- | `merge` | Always finding deduplication |
50
- | `intelligence` | Always enrichment and WCAG mapping |
51
- | `repo` | When `repoUrl` is set |
52
- | `patterns` | When source scanning is active |
53
- | `ai` | When AI enrichment is configured |
137
+ | `wcag2a` | WCAG 2.0 Level A |
138
+ | `wcag2aa` | WCAG 2.0 Level AA |
139
+ | `wcag21a` | WCAG 2.1 Level A additions |
140
+ | `wcag21aa` | WCAG 2.1 Level AA additions |
141
+ | `wcag22a` | WCAG 2.2 Level A additions |
142
+ | `wcag22aa` | WCAG 2.2 Level AA additions |
143
+ | `wcag2aaa` | WCAG 2.0 Level AAA |
144
+ | `best-practice` | Non-WCAG best practices |
145
+
146
+ **Supported `framework` values:** `nextjs`, `gatsby`, `react`, `nuxt`, `vue`, `angular`, `astro`, `svelte`, `remix`, `shopify`, `wordpress`, `drupal`
147
+
148
+ **`onProgress` callback:**
149
+
150
+ ```ts
151
+ onProgress: (step, status, extra) => {
152
+ // step: "page" | "axe" | "cdp" | "pa11y" | "merge" | "intelligence" | "repo" | "patterns" | "ai"
153
+ // status: "running" | "done" | "error" | "skipped"
154
+ // extra: { found?: number, merged?: number, ... } — step-specific data
155
+ }
156
+ ```
157
+
158
+ ```ts
159
+ const payload = await runAudit({
160
+ baseUrl: "https://example.com",
161
+ maxRoutes: 5,
162
+ engines: { axe: true, cdp: true, pa11y: true },
163
+ repoUrl: "https://github.com/owner/repo",
164
+ githubToken: process.env.GH_TOKEN,
165
+ ai: { enabled: true, apiKey: process.env.ANTHROPIC_API_KEY },
166
+ onProgress: (step, status) => console.log(`[${step}] ${status}`),
167
+ });
168
+ ```
54
169
 
55
170
  Returns: `Promise<ScanPayload>`
56
171
 
57
- > **`ai_enriched_findings` fast path**: When AI enrichment runs, the engine appends `ai_enriched_findings` to the payload. `getFindings()` checks for this field first — if present, it returns the already-enriched findings directly without re-normalizing the raw `findings` array.
172
+ > **`ai_enriched_findings` fast path**: When AI enrichment runs, `getFindings()` uses `payload.ai_enriched_findings` directly instead of re-normalizing the raw findings array.
58
173
 
59
- ### `getFindings(input, options?)`
174
+ ---
60
175
 
61
- Normalizes and enriches findings and returns sorted enriched findings.
176
+ ### `getFindings(input, options?)`
62
177
 
63
- - `input`: `ScanPayload` from `runAudit`
64
- - `options` (`EnrichmentOptions`):
65
- - `screenshotUrlBuilder?: (rawPath: string) => string`
178
+ Normalizes raw scan results into enriched, UI-ready findings sorted by severity.
179
+
180
+ ```ts
181
+ import { getFindings } from "@diegovelasquezweb/a11y-engine";
182
+
183
+ const findings = getFindings(payload, {
184
+ // Optional: rewrite internal screenshot paths to app URLs
185
+ screenshotUrlBuilder: (rawPath) =>
186
+ `/api/scan/${scanId}/screenshot?path=${encodeURIComponent(rawPath)}`,
187
+ });
188
+
189
+ // findings[0] example:
190
+ // {
191
+ // id: "A11Y-001",
192
+ // ruleId: "color-contrast",
193
+ // title: "Elements must meet minimum color contrast ratio thresholds",
194
+ // severity: "Serious",
195
+ // wcag: "1.4.3",
196
+ // selector: ".hero-text",
197
+ // actual: "Element has insufficient color contrast of 2.5:1 ...",
198
+ // expected: "Text contrast ratio must be at least 4.5:1 ...",
199
+ // fixDescription: "Increase the foreground color contrast ...",
200
+ // fixCode: "/* Change #aaa to #767676 */",
201
+ // effort: "low",
202
+ // aiEnhanced: true, // present when AI ran
203
+ // aiFixDescription: "...", // Claude-generated (more specific)
204
+ // aiFixCode: "...", // Claude-generated code snippet
205
+ // }
206
+ ```
66
207
 
67
208
  Returns: `EnrichedFinding[]`
68
209
 
69
- ### `getOverview(findings, payload?)`
210
+ ---
70
211
 
71
- Computes totals, score, WCAG status, persona groups, quick wins, target URL, and detected stack.
212
+ ### `getOverview(findings, payload?)`
72
213
 
73
- - `findings`: `EnrichedFinding[]`
74
- - `payload`: `ScanPayload | null`
214
+ Computes the compliance score, WCAG status, severity totals, persona groups, and quick wins from enriched findings.
215
+
216
+ ```ts
217
+ import { getFindings, getOverview } from "@diegovelasquezweb/a11y-engine";
218
+
219
+ const findings = getFindings(payload);
220
+ const overview = getOverview(findings, payload);
221
+
222
+ // overview example:
223
+ // {
224
+ // score: 72, // 0–100. Formula: 100 - (Critical×15) - (Serious×5) - (Moderate×2) - (Minor×0.5)
225
+ // label: "Fair", // "Excellent" (90–100) | "Good" (75–89) | "Fair" (55–74) | "Poor" (35–54) | "Critical" (0–34)
226
+ // wcagStatus: "Fail", // "Pass" | "Conditional Pass" | "Fail"
227
+ // totals: { Critical: 1, Serious: 3, Moderate: 5, Minor: 2 },
228
+ // personaGroups: {
229
+ // screenReader: { count: 4, findings: [...] },
230
+ // keyboard: { count: 2, findings: [...] },
231
+ // vision: { count: 3, findings: [...] },
232
+ // cognitive: { count: 1, findings: [...] },
233
+ // },
234
+ // quickWins: [...], // top Critical/Serious findings with fix code ready
235
+ // targetUrl: "https://example.com",
236
+ // detectedStack: { framework: "nextjs", cms: null, uiLibraries: ["radix-ui"] },
237
+ // }
238
+ ```
75
239
 
76
240
  Returns: `AuditSummary`
77
241
 
242
+ ---
243
+
78
244
  ## Output API
79
245
 
80
246
  ### `getPDFReport(payload, options?)`
81
247
 
82
- - `payload`: `ScanPayload`
83
- - `options`: `ReportOptions`
84
- - `baseUrl?: string`
85
- - `target?: string`
248
+ Generates a formal A4 PDF compliance report.
249
+
250
+ ```ts
251
+ import { getPDFReport } from "@diegovelasquezweb/a11y-engine";
252
+
253
+ const { buffer, contentType } = await getPDFReport(payload, {
254
+ baseUrl: "https://example.com",
255
+ target: "WCAG 2.2 AA",
256
+ });
86
257
 
87
- Returns: `Promise<PDFReport>` (`{ buffer, contentType }`)
258
+ // In a Next.js API route:
259
+ return new Response(buffer, { headers: { "Content-Type": contentType } });
260
+ ```
261
+
262
+ Returns: `Promise<{ buffer: Buffer, contentType: string }>`
263
+
264
+ ---
88
265
 
89
266
  ### `getHTMLReport(payload, options?)`
90
267
 
91
- - `payload`: `ScanPayload`
92
- - `options`: `HTMLReportOptions`
93
- - `baseUrl?: string`
94
- - `target?: string`
95
- - `screenshotsDir?: string`
268
+ Generates an interactive HTML audit dashboard with finding cards, score gauge, and persona breakdown.
269
+
270
+ ```ts
271
+ import { getHTMLReport } from "@diegovelasquezweb/a11y-engine";
96
272
 
97
- Returns: `Promise<HTMLReport>` (`{ html, contentType }`)
273
+ const { html, contentType } = await getHTMLReport(payload, {
274
+ baseUrl: "https://example.com",
275
+ screenshotsDir: "/path/to/screenshots",
276
+ });
277
+ ```
278
+
279
+ Returns: `Promise<{ html: string, contentType: string }>`
280
+
281
+ ---
98
282
 
99
283
  ### `getChecklist(options?)`
100
284
 
101
- - `options`: `Pick<ReportOptions, "baseUrl">`
102
- - `baseUrl?: string`
285
+ Generates an interactive HTML manual testing checklist with 41 WCAG checks.
286
+
287
+ ```ts
288
+ import { getChecklist } from "@diegovelasquezweb/a11y-engine";
103
289
 
104
- Returns: `Promise<ChecklistReport>` (`{ html, contentType }`)
290
+ const { html, contentType } = await getChecklist({
291
+ baseUrl: "https://example.com",
292
+ });
293
+ ```
294
+
295
+ Returns: `Promise<{ html: string, contentType: string }>`
296
+
297
+ ---
105
298
 
106
299
  ### `getRemediationGuide(payload, options?)`
107
300
 
108
- - `payload`: `ScanPayload & { incomplete_findings?: unknown[] }`
109
- - `options`: `RemediationOptions`
110
- - `baseUrl?: string`
111
- - `target?: string`
112
- - `patternFindings?: Record<string, unknown> | null`
301
+ Generates a Markdown remediation guide optimized for AI agents and developers. Includes finding details, fix code, verify commands, and source pattern findings.
302
+
303
+ ```ts
304
+ import { getRemediationGuide } from "@diegovelasquezweb/a11y-engine";
305
+
306
+ const { markdown, contentType } = await getRemediationGuide(payload, {
307
+ baseUrl: "https://example.com",
308
+ patternFindings: payload.patternFindings ?? null,
309
+ });
113
310
 
114
- Returns: `Promise<RemediationGuide>` (`{ markdown, contentType }`)
311
+ // Write to disk or return as download
312
+ ```
313
+
314
+ Returns: `Promise<{ markdown: string, contentType: string }>`
315
+
316
+ ---
115
317
 
116
318
  ### `getSourcePatterns(projectDir, options?)`
117
319
 
118
- - `projectDir`: `string`
119
- - `options`: `SourcePatternOptions`
120
- - `framework?: string`
121
- - `onlyPattern?: string`
320
+ Scans a local project directory for source code accessibility patterns that runtime engines cannot detect.
321
+
322
+ ```ts
323
+ import { getSourcePatterns } from "@diegovelasquezweb/a11y-engine";
324
+
325
+ const result = await getSourcePatterns("./", {
326
+ framework: "nextjs", // optional — scopes scan to framework source dirs
327
+ onlyPattern: "placeholder-only-label", // optional — run a single pattern
328
+ });
329
+
330
+ // result example:
331
+ // {
332
+ // findings: [
333
+ // {
334
+ // id: "PAT-a1b2c3",
335
+ // pattern_id: "placeholder-only-label",
336
+ // title: "Input uses placeholder as its only label",
337
+ // severity: "Critical",
338
+ // status: "confirmed",
339
+ // file: "src/components/SearchBar.tsx",
340
+ // line: 12,
341
+ // match: ' <input placeholder="Search..." />',
342
+ // context: "...",
343
+ // fix_description: "Add an aria-label or visible <label> element",
344
+ // }
345
+ // ],
346
+ // summary: { total: 3, confirmed: 2, potential: 1 }
347
+ // }
348
+ ```
122
349
 
123
350
  Returns: `Promise<SourcePatternResult>`
124
351
 
352
+ ---
353
+
125
354
  ## Knowledge API
126
355
 
356
+ These functions expose engine-owned content for UIs and agents to render. All accept an optional `{ locale?: string }` option (default: `"en"`).
357
+
358
+ ### `getKnowledge(options?)`
359
+
360
+ Returns the full knowledge pack — combines all knowledge functions into one call. Useful for pre-loading UI help content.
361
+
362
+ ```ts
363
+ import { getKnowledge } from "@diegovelasquezweb/a11y-engine";
364
+
365
+ const knowledge = getKnowledge({ locale: "en" });
366
+
367
+ // knowledge.scanner → scan options help and engine descriptions
368
+ // knowledge.personas → persona labels, icons, descriptions
369
+ // knowledge.concepts → UI concept definitions
370
+ // knowledge.glossary → accessibility glossary
371
+ // knowledge.conformanceLevels → WCAG A/AA/AAA definitions with axe tags
372
+ // knowledge.wcagPrinciples → the 4 WCAG principles
373
+ // knowledge.severityLevels → Critical/Serious/Moderate/Minor definitions
374
+ ```
375
+
376
+ Returns: `EngineKnowledge`
377
+
378
+ ---
379
+
127
380
  ### `getScannerHelp(options?)`
128
381
 
129
- - `options`: `KnowledgeOptions`
130
- - `locale?: string`
382
+ Returns scan option descriptions, allowed values, and engine metadata — used to render Advanced Settings UI.
131
383
 
132
- Returns: `ScannerHelp` (`{ locale, version, title, engines, options }`)
384
+ ```ts
385
+ const help = getScannerHelp();
386
+ // help.engines → [{ id: "axe", label: "axe-core", description: "..." }, ...]
387
+ // help.options → [{ id: "maxRoutes", label: "Max Routes", type: "number", ... }, ...]
388
+ ```
389
+
390
+ ---
133
391
 
134
392
  ### `getPersonaReference(options?)`
135
393
 
136
- - `options`: `KnowledgeOptions`
137
- - `locale?: string`
394
+ Returns persona labels, descriptions, and disability group definitions.
138
395
 
139
- Returns: `PersonaReference` (`{ locale, version, personas }`)
396
+ ```ts
397
+ const ref = getPersonaReference();
398
+ // ref.personas → [{ id: "screenReader", label: "Screen Readers", icon: "...", description: "..." }, ...]
399
+ ```
400
+
401
+ ---
140
402
 
141
403
  ### `getUiHelp(options?)`
142
404
 
143
- - `options`: `KnowledgeOptions`
144
- - `locale?: string`
405
+ Returns shared concept definitions and a glossary of accessibility terms.
145
406
 
146
- Returns: `UiHelp` (`{ locale, version, concepts, glossary }`)
407
+ ```ts
408
+ const ui = getUiHelp();
409
+ // ui.concepts → { wcag: "...", aria: "...", ... }
410
+ // ui.glossary → [{ term: "ARIA", definition: "..." }, ...]
411
+ ```
147
412
 
148
- ### `getConformanceLevels(options?)`
413
+ ---
149
414
 
150
- - `options`: `KnowledgeOptions`
151
- - `locale?: string`
415
+ ### `getConformanceLevels(options?)`
152
416
 
153
- Returns: `ConformanceLevelsResult` (`{ locale, version, conformanceLevels }`)
417
+ Returns WCAG conformance level definitions with their corresponding axe-core tag sets.
154
418
 
155
- ### `getWcagPrinciples(options?)`
419
+ ```ts
420
+ const { conformanceLevels } = getConformanceLevels();
421
+ // conformanceLevels[0] → { id: "AA", label: "WCAG 2.2 AA", axeTags: ["wcag2a", "wcag2aa", ...] }
422
+ ```
156
423
 
157
- - `options`: `KnowledgeOptions`
158
- - `locale?: string`
424
+ ---
159
425
 
160
- Returns: `WcagPrinciplesResult` (`{ locale, version, wcagPrinciples }`)
426
+ ### `getWcagPrinciples(options?)`
161
427
 
162
- ### `getSeverityLevels(options?)`
428
+ Returns the four WCAG principles (Perceivable, Operable, Understandable, Robust) with criterion prefix patterns.
163
429
 
164
- - `options`: `KnowledgeOptions`
165
- - `locale?: string`
430
+ ```ts
431
+ const { wcagPrinciples } = getWcagPrinciples();
432
+ // wcagPrinciples[0] → { id: "perceivable", label: "Perceivable", prefix: "1.", description: "..." }
433
+ ```
166
434
 
167
- Returns: `SeverityLevelsResult` (`{ locale, version, severityLevels }`)
435
+ ---
168
436
 
169
- ### `getKnowledge(options?)`
437
+ ### `getSeverityLevels(options?)`
170
438
 
171
- - `options`: `KnowledgeOptions`
172
- - `locale?: string`
439
+ Returns severity level definitions with labels, descriptions, and ordering.
173
440
 
174
- Returns: `EngineKnowledge` (`{ locale, version, scanner, personas, concepts, glossary, docs, conformanceLevels, wcagPrinciples, severityLevels }`)
441
+ ```ts
442
+ const { severityLevels } = getSeverityLevels();
443
+ // severityLevels[0] → { id: "Critical", label: "Critical", order: 0, description: "..." }
444
+ ```
175
445
 
176
446
  ---
177
447
 
@@ -4,6 +4,14 @@
4
4
 
5
5
  ---
6
6
 
7
+ ## Table of Contents
8
+
9
+ - [Source Modules](#1-source-modules)
10
+ - [Asset Modules](#2-asset-modules)
11
+ - [Test Suite](#3-test-suite)
12
+
13
+ ---
14
+
7
15
  This document is the current technical inventory of the engine package.
8
16
 
9
17
  ## 1) Source Modules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegovelasquezweb/a11y-engine",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "WCAG 2.2 accessibility audit engine — scanner, analyzer, and report builders",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/ai/claude.mjs CHANGED
@@ -25,18 +25,10 @@ const MAX_AI_FINDINGS = 20; // cap to control cost
25
25
  * @param {object} context
26
26
  * @returns {string}
27
27
  */
28
- function buildSystemPrompt(context) {
29
- const { framework, cms, uiLibraries } = context.stack || {};
30
-
31
- let stackInfo = "";
32
- if (framework) stackInfo += `Framework: ${framework}\n`;
33
- if (cms) stackInfo += `CMS: ${cms}\n`;
34
- if (uiLibraries?.length) stackInfo += `UI Libraries: ${uiLibraries.join(", ")}\n`;
35
-
36
- return `You are an expert web accessibility engineer specializing in WCAG 2.2 AA remediation.
28
+ export const DEFAULT_AI_SYSTEM_PROMPT = `You are an expert web accessibility engineer specializing in WCAG 2.2 AA remediation.
37
29
 
38
30
  Your task is to provide a developer-friendly AI hint for each accessibility finding — something MORE USEFUL than the generic automated fix already provided.
39
- ${stackInfo ? `\nProject context:\n${stackInfo}` : ""}
31
+
40
32
  For each finding, provide:
41
33
  1. fixDescription: A 2-3 sentence explanation that goes BEYOND the generic fix. Explain WHY this matters for real users, WHAT specifically to look for in the codebase, and HOW to verify the fix works. Be specific to the selector and actual violation data provided.
42
34
  2. fixCode: A ready-to-use, production-quality code snippet in the correct syntax for the stack. Do NOT copy the existing fix code — write a BETTER, more complete example that a developer can use directly.
@@ -48,6 +40,20 @@ Rules:
48
40
  - Reference the actual selector or element from the finding when possible
49
41
  - If the violation data contains specific values (colors, ratios, labels), use them in your response
50
42
  - Respond in JSON only — no markdown, no explanation outside the JSON structure`;
43
+
44
+ function buildSystemPrompt(context) {
45
+ const { framework, cms, uiLibraries } = context.stack || {};
46
+
47
+ let stackInfo = "";
48
+ if (framework) stackInfo += `Framework: ${framework}\n`;
49
+ if (cms) stackInfo += `CMS: ${cms}\n`;
50
+ if (uiLibraries?.length) stackInfo += `UI Libraries: ${uiLibraries.join(", ")}\n`;
51
+
52
+ const base = DEFAULT_AI_SYSTEM_PROMPT;
53
+ return stackInfo ? base.replace(
54
+ "For each finding, provide:",
55
+ `Project context:\n${stackInfo}\nFor each finding, provide:`
56
+ ) : base;
51
57
  }
52
58
 
53
59
  /**
package/src/index.d.mts CHANGED
@@ -403,15 +403,6 @@ export interface RunAuditOptions {
403
403
  onProgress?: (step: string, status: string, extra?: Record<string, unknown>) => void;
404
404
  }
405
405
 
406
- export interface AiOptions {
407
- enabled?: boolean;
408
- apiKey?: string;
409
- githubToken?: string;
410
- model?: string;
411
- }
412
-
413
-
414
-
415
406
 
416
407
 
417
408
  export interface EnrichmentOptions {
@@ -471,3 +462,21 @@ export function getWcagPrinciples(options?: KnowledgeOptions): WcagPrinciplesRes
471
462
  export function getSeverityLevels(options?: KnowledgeOptions): SeverityLevelsResult;
472
463
 
473
464
  export function getKnowledge(options?: KnowledgeOptions): EngineKnowledge;
465
+
466
+ export const DEFAULT_AI_SYSTEM_PROMPT: string;
467
+
468
+ export interface ViewportPreset {
469
+ label: string;
470
+ width: number;
471
+ height: number;
472
+ }
473
+
474
+ export const VIEWPORT_PRESETS: ViewportPreset[];
475
+
476
+ export interface AiOptions {
477
+ enabled?: boolean;
478
+ apiKey?: string;
479
+ githubToken?: string;
480
+ model?: string;
481
+ systemPrompt?: string;
482
+ }
package/src/index.mjs CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { ASSET_PATHS, loadAssetJson } from "./core/asset-loader.mjs";
8
+ export { DEFAULT_AI_SYSTEM_PROMPT } from "./ai/claude.mjs";
8
9
 
9
10
  // ---------------------------------------------------------------------------
10
11
  // Lazy-loaded asset cache
@@ -238,7 +239,7 @@ export function getFindings(input, options = {}) {
238
239
  recommendedFix: finding.recommended_fix,
239
240
  evidence: finding.evidence,
240
241
  totalInstances: finding.total_instances,
241
- effort: finding.effort,
242
+ effort: finding.effort ?? (finding.fix_code ? "low" : "high"),
242
243
  relatedRules: finding.related_rules,
243
244
  screenshotPath: finding.screenshot_path,
244
245
  falsePositiveRisk: finding.false_positive_risk,
@@ -583,6 +584,13 @@ export function getSeverityLevels(options = {}) {
583
584
  };
584
585
  }
585
586
 
587
+ export const VIEWPORT_PRESETS = [
588
+ { label: "Desktop", width: 1280, height: 800 },
589
+ { label: "Laptop", width: 1440, height: 900 },
590
+ { label: "Tablet", width: 768, height: 1024 },
591
+ { label: "Mobile", width: 375, height: 812 },
592
+ ];
593
+
586
594
  export function getKnowledge(options = {}) {
587
595
  const scanner = getScannerHelp(options);
588
596
  const personas = getPersonaReference(options);