@diegovelasquezweb/a11y-engine 0.7.4 → 0.7.6
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/package.json +1 -1
- package/src/ai/enrich.mjs +69 -0
- package/src/cli/audit.mjs +8 -0
package/package.json
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file enrich.mjs
|
|
4
|
+
* @description CLI script that reads a11y-findings.json, enriches Critical/Serious
|
|
5
|
+
* findings using the Claude AI module, and writes the result back.
|
|
6
|
+
* Runs as a child process from audit.mjs after the analyzer step.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { log, getInternalPath, writeJson } from "../core/utils.mjs";
|
|
11
|
+
import { enrichWithAI } from "./claude.mjs";
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
log.warn("No ANTHROPIC_API_KEY found — skipping AI enrichment.");
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const findingsPath = getInternalPath("a11y-findings.json");
|
|
21
|
+
|
|
22
|
+
let payload;
|
|
23
|
+
try {
|
|
24
|
+
const { readFileSync } = await import("node:fs");
|
|
25
|
+
payload = JSON.parse(readFileSync(findingsPath, "utf-8"));
|
|
26
|
+
} catch (err) {
|
|
27
|
+
log.warn(`Could not read findings file — skipping AI enrichment: ${err.message}`);
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const findings = payload.findings ?? [];
|
|
32
|
+
if (findings.length === 0) {
|
|
33
|
+
log.info("No findings to enrich.");
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const stack = payload.metadata?.projectContext ?? {};
|
|
38
|
+
const repoUrl = process.env.A11Y_REPO_URL || payload.metadata?.repoUrl || null;
|
|
39
|
+
const githubToken = process.env.GH_TOKEN || undefined;
|
|
40
|
+
|
|
41
|
+
log.info(`AI enrichment: processing up to 20 Critical/Serious findings...`);
|
|
42
|
+
|
|
43
|
+
const enriched = await enrichWithAI(findings, { stack, repoUrl }, {
|
|
44
|
+
enabled: true,
|
|
45
|
+
apiKey,
|
|
46
|
+
githubToken,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const enrichedWithFlag = enriched.map((f, i) => {
|
|
50
|
+
const original = findings[i];
|
|
51
|
+
const wasImproved = original && (
|
|
52
|
+
f.fixDescription !== original.fixDescription ||
|
|
53
|
+
f.fixCode !== original.fixCode
|
|
54
|
+
);
|
|
55
|
+
return wasImproved ? { ...f, aiEnhanced: true } : f;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
writeJson(findingsPath, { ...payload, findings: enrichedWithFlag });
|
|
59
|
+
|
|
60
|
+
const improved = enrichedWithFlag.filter((f) => f.aiEnhanced).length;
|
|
61
|
+
log.success(`AI enrichment complete. ${improved} finding(s) improved.`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
65
|
+
main().catch((err) => {
|
|
66
|
+
log.warn(`AI enrichment failed (non-fatal): ${err.message}`);
|
|
67
|
+
process.exit(0); // non-fatal — never block the pipeline
|
|
68
|
+
});
|
|
69
|
+
}
|
package/src/cli/audit.mjs
CHANGED
|
@@ -294,6 +294,14 @@ async function main() {
|
|
|
294
294
|
if (resolvedFramework) analyzerArgs.push("--framework", resolvedFramework);
|
|
295
295
|
await runScript("../enrichment/analyzer.mjs", analyzerArgs);
|
|
296
296
|
|
|
297
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
298
|
+
await runScript("../ai/enrich.mjs", [], {
|
|
299
|
+
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
|
|
300
|
+
...(repoUrl ? { A11Y_REPO_URL: repoUrl } : {}),
|
|
301
|
+
...(githubToken ? { GH_TOKEN: githubToken } : {}),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
297
305
|
if ((projectDir || repoUrl) && !skipPatterns) {
|
|
298
306
|
const patternArgs = [];
|
|
299
307
|
if (projectDir) {
|