@jahia/agentic 0.4.1 → 0.5.1

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 (178) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/antigravity/.agents/rules/jahia.md +51 -0
  3. package/dist/antigravity/.agents/skills/jahia-cnd-author/SKILL.md +94 -0
  4. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
  5. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
  6. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
  7. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
  8. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
  9. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
  10. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
  11. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
  12. package/dist/antigravity/.agents/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
  13. package/dist/antigravity/.agents/skills/jahia-dev-accessibility/SKILL.md +11 -0
  14. package/dist/antigravity/.agents/skills/jahia-dev-build-component/SKILL.md +133 -0
  15. package/dist/antigravity/.agents/skills/jahia-dev-create-page-template/SKILL.md +341 -0
  16. package/dist/antigravity/.agents/skills/jahia-dev-create-template-set/SKILL.md +205 -0
  17. package/dist/antigravity/.agents/skills/jahia-dev-create-view/SKILL.md +896 -0
  18. package/dist/antigravity/.agents/skills/jahia-dev-debug/SKILL.md +176 -0
  19. package/dist/antigravity/.agents/skills/jahia-dev-import-from/SKILL.md +244 -0
  20. package/dist/antigravity/.agents/skills/jahia-dev-jexperience/SKILL.md +269 -0
  21. package/dist/antigravity/.agents/skills/jahia-dev-ops/SKILL.md +50 -0
  22. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/docker.md +151 -0
  23. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/monitoring.md +195 -0
  24. package/dist/antigravity/.agents/skills/jahia-dev-ops/references/provisioning.md +269 -0
  25. package/dist/antigravity/.agents/skills/jahia-dev-properties/SKILL.md +147 -0
  26. package/dist/antigravity/.agents/skills/jahia-dev-properties/references/all-properties.md +231 -0
  27. package/dist/antigravity/.agents/skills/jahia-dev-query-content/SKILL.md +204 -0
  28. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/SKILL.md +79 -0
  29. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/scripts/check-cnd.d.mts +13 -0
  30. package/dist/antigravity/.agents/skills/jahia-dev-review-cnd/scripts/check-cnd.mjs +198 -0
  31. package/dist/antigravity/.agents/skills/jahia-dev-screenshot/SKILL.md +177 -0
  32. package/dist/antigravity/.agents/skills/jahia-dev-start-local/SKILL.md +121 -0
  33. package/dist/antigravity/.agents/skills/jahia-jcr-sql2/SKILL.md +257 -0
  34. package/dist/antigravity/.agents/skills/jahia-review/SKILL.md +63 -0
  35. package/dist/{claude/.claude/skills/jahia-dev-review → antigravity/.agents/skills/jahia-review-code}/SKILL.md +3 -3
  36. package/dist/antigravity/.agents/skills/jahia-review-site/SKILL.md +52 -0
  37. package/dist/antigravity/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  38. package/dist/antigravity/AGENTS.md +62 -0
  39. package/dist/claude/.claude/rules/jahia.md +1 -1
  40. package/dist/claude/.claude/skills/jahia-dev-build-component/SKILL.md +2 -2
  41. package/dist/claude/.claude/skills/jahia-dev-create-view/SKILL.md +2 -2
  42. package/dist/claude/.claude/skills/jahia-dev-import-from/SKILL.md +1 -1
  43. package/dist/claude/.claude/skills/jahia-dev-properties/SKILL.md +1 -1
  44. package/dist/claude/.claude/skills/jahia-dev-query-content/SKILL.md +1 -1
  45. package/dist/claude/.claude/skills/jahia-jcr-sql2/SKILL.md +1 -2
  46. package/dist/claude/.claude/skills/jahia-review/SKILL.md +63 -0
  47. package/dist/{copilot/.agents/skills/jahia-dev-review → claude/.claude/skills/jahia-review-code}/SKILL.md +3 -3
  48. package/dist/claude/.claude/skills/jahia-review-site/SKILL.md +52 -0
  49. package/dist/claude/.claude/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  50. package/dist/claude/.mcp.json +11 -0
  51. package/dist/claude/CLAUDE.md +2 -2
  52. package/dist/codex/.agents/skills/jahia-dev-build-component/SKILL.md +2 -2
  53. package/dist/codex/.agents/skills/jahia-dev-create-view/SKILL.md +2 -2
  54. package/dist/codex/.agents/skills/jahia-dev-import-from/SKILL.md +1 -1
  55. package/dist/codex/.agents/skills/jahia-dev-properties/SKILL.md +1 -1
  56. package/dist/codex/.agents/skills/jahia-dev-query-content/SKILL.md +1 -1
  57. package/dist/codex/.agents/skills/jahia-jcr-sql2/SKILL.md +1 -2
  58. package/dist/codex/.agents/skills/jahia-review/SKILL.md +63 -0
  59. package/dist/{cursor/.agents/skills/jahia-dev-review → codex/.agents/skills/jahia-review-code}/SKILL.md +3 -3
  60. package/dist/codex/.agents/skills/jahia-review-site/SKILL.md +52 -0
  61. package/dist/codex/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  62. package/dist/codex/AGENTS.md +2 -2
  63. package/dist/copilot/.agents/skills/jahia-dev-build-component/SKILL.md +2 -2
  64. package/dist/copilot/.agents/skills/jahia-dev-create-view/SKILL.md +2 -2
  65. package/dist/copilot/.agents/skills/jahia-dev-import-from/SKILL.md +1 -1
  66. package/dist/copilot/.agents/skills/jahia-dev-properties/SKILL.md +1 -1
  67. package/dist/copilot/.agents/skills/jahia-dev-query-content/SKILL.md +1 -1
  68. package/dist/copilot/.agents/skills/jahia-jcr-sql2/SKILL.md +1 -2
  69. package/dist/copilot/.agents/skills/jahia-review/SKILL.md +63 -0
  70. package/dist/{codex/.agents/skills/jahia-dev-review → copilot/.agents/skills/jahia-review-code}/SKILL.md +3 -3
  71. package/dist/copilot/.agents/skills/jahia-review-site/SKILL.md +52 -0
  72. package/dist/copilot/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  73. package/dist/copilot/AGENTS.md +2 -2
  74. package/dist/cursor/.agents/skills/jahia-dev-build-component/SKILL.md +2 -2
  75. package/dist/cursor/.agents/skills/jahia-dev-create-view/SKILL.md +2 -2
  76. package/dist/cursor/.agents/skills/jahia-dev-import-from/SKILL.md +1 -1
  77. package/dist/cursor/.agents/skills/jahia-dev-properties/SKILL.md +1 -1
  78. package/dist/cursor/.agents/skills/jahia-dev-query-content/SKILL.md +1 -1
  79. package/dist/cursor/.agents/skills/jahia-jcr-sql2/SKILL.md +1 -2
  80. package/dist/cursor/.agents/skills/jahia-review/SKILL.md +63 -0
  81. package/dist/cursor/.agents/skills/jahia-review-code/SKILL.md +228 -0
  82. package/dist/cursor/.agents/skills/jahia-review-site/SKILL.md +52 -0
  83. package/dist/cursor/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  84. package/dist/cursor/.cursor/mcp.json +11 -0
  85. package/dist/cursor/.cursor/rules/jahia.mdc +1 -1
  86. package/dist/gemini/.agents/skills/jahia-dev-build-component/SKILL.md +2 -2
  87. package/dist/gemini/.agents/skills/jahia-dev-create-view/SKILL.md +2 -2
  88. package/dist/gemini/.agents/skills/jahia-dev-import-from/SKILL.md +1 -1
  89. package/dist/gemini/.agents/skills/jahia-dev-properties/SKILL.md +1 -1
  90. package/dist/gemini/.agents/skills/jahia-dev-query-content/SKILL.md +1 -1
  91. package/dist/gemini/.agents/skills/jahia-jcr-sql2/SKILL.md +1 -2
  92. package/dist/gemini/.agents/skills/jahia-review/SKILL.md +63 -0
  93. package/dist/gemini/.agents/skills/jahia-review-code/SKILL.md +228 -0
  94. package/dist/gemini/.agents/skills/jahia-review-site/SKILL.md +52 -0
  95. package/dist/gemini/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  96. package/dist/gemini/.gemini/settings.json +10 -0
  97. package/dist/gemini/AGENTS.md +2 -2
  98. package/dist/index.js +14 -2
  99. package/dist/kiro/.kiro/settings/mcp.json +10 -0
  100. package/dist/kiro/.kiro/skills/jahia-cnd-author/SKILL.md +94 -0
  101. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-area-types.md +55 -0
  102. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-authoring-experience.md +92 -0
  103. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-child-nodes.md +74 -0
  104. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-jahia-mixins.md +510 -0
  105. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-modeling-decisions.md +87 -0
  106. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-numbers-dates.md +92 -0
  107. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-string-selectors.md +133 -0
  108. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/cnd-syntax.md +119 -0
  109. package/dist/kiro/.kiro/skills/jahia-cnd-author/references/types-ts-mapping.md +73 -0
  110. package/dist/kiro/.kiro/skills/jahia-dev-accessibility/SKILL.md +11 -0
  111. package/dist/kiro/.kiro/skills/jahia-dev-build-component/SKILL.md +133 -0
  112. package/dist/kiro/.kiro/skills/jahia-dev-create-page-template/SKILL.md +341 -0
  113. package/dist/kiro/.kiro/skills/jahia-dev-create-template-set/SKILL.md +205 -0
  114. package/dist/kiro/.kiro/skills/jahia-dev-create-view/SKILL.md +896 -0
  115. package/dist/kiro/.kiro/skills/jahia-dev-debug/SKILL.md +176 -0
  116. package/dist/kiro/.kiro/skills/jahia-dev-import-from/SKILL.md +244 -0
  117. package/dist/kiro/.kiro/skills/jahia-dev-jexperience/SKILL.md +269 -0
  118. package/dist/kiro/.kiro/skills/jahia-dev-ops/SKILL.md +50 -0
  119. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/docker.md +151 -0
  120. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/monitoring.md +195 -0
  121. package/dist/kiro/.kiro/skills/jahia-dev-ops/references/provisioning.md +269 -0
  122. package/dist/kiro/.kiro/skills/jahia-dev-properties/SKILL.md +147 -0
  123. package/dist/kiro/.kiro/skills/jahia-dev-properties/references/all-properties.md +231 -0
  124. package/dist/kiro/.kiro/skills/jahia-dev-query-content/SKILL.md +204 -0
  125. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/SKILL.md +79 -0
  126. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/scripts/check-cnd.d.mts +13 -0
  127. package/dist/kiro/.kiro/skills/jahia-dev-review-cnd/scripts/check-cnd.mjs +198 -0
  128. package/dist/kiro/.kiro/skills/jahia-dev-screenshot/SKILL.md +177 -0
  129. package/dist/kiro/.kiro/skills/jahia-dev-start-local/SKILL.md +121 -0
  130. package/dist/kiro/.kiro/skills/jahia-jcr-sql2/SKILL.md +257 -0
  131. package/dist/kiro/.kiro/skills/jahia-review/SKILL.md +63 -0
  132. package/dist/kiro/.kiro/skills/jahia-review-code/SKILL.md +228 -0
  133. package/dist/kiro/.kiro/skills/jahia-review-site/SKILL.md +52 -0
  134. package/dist/kiro/.kiro/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  135. package/dist/kiro/.kiro/steering/jahia.md +55 -0
  136. package/dist/kiro/AGENTS.md +62 -0
  137. package/dist/opencode/.agents/skills/jahia-dev-build-component/SKILL.md +2 -2
  138. package/dist/opencode/.agents/skills/jahia-dev-create-view/SKILL.md +2 -2
  139. package/dist/opencode/.agents/skills/jahia-dev-import-from/SKILL.md +1 -1
  140. package/dist/opencode/.agents/skills/jahia-dev-properties/SKILL.md +1 -1
  141. package/dist/opencode/.agents/skills/jahia-dev-query-content/SKILL.md +1 -1
  142. package/dist/opencode/.agents/skills/jahia-jcr-sql2/SKILL.md +1 -2
  143. package/dist/opencode/.agents/skills/jahia-review/SKILL.md +63 -0
  144. package/dist/opencode/.agents/skills/jahia-review-code/SKILL.md +228 -0
  145. package/dist/opencode/.agents/skills/jahia-review-site/SKILL.md +52 -0
  146. package/dist/opencode/.agents/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  147. package/dist/opencode/AGENTS.md +2 -2
  148. package/dist/opencode/opencode.json +12 -0
  149. package/dist/windsurf/.windsurf/rules/jahia.md +1 -1
  150. package/dist/windsurf/.windsurf/skills/jahia-dev-build-component/SKILL.md +2 -2
  151. package/dist/windsurf/.windsurf/skills/jahia-dev-create-view/SKILL.md +2 -2
  152. package/dist/windsurf/.windsurf/skills/jahia-dev-import-from/SKILL.md +1 -1
  153. package/dist/windsurf/.windsurf/skills/jahia-dev-properties/SKILL.md +1 -1
  154. package/dist/windsurf/.windsurf/skills/jahia-dev-query-content/SKILL.md +1 -1
  155. package/dist/windsurf/.windsurf/skills/jahia-jcr-sql2/SKILL.md +1 -2
  156. package/dist/windsurf/.windsurf/skills/jahia-review/SKILL.md +63 -0
  157. package/dist/windsurf/.windsurf/skills/jahia-review-code/SKILL.md +228 -0
  158. package/dist/windsurf/.windsurf/skills/jahia-review-site/SKILL.md +52 -0
  159. package/dist/windsurf/.windsurf/skills/jahia-review-site/scripts/review-pages.mjs +74 -0
  160. package/dist/windsurf/AGENTS.md +2 -2
  161. package/package.json +1 -1
  162. package/dist/claude/.claude/skills/jahia-dev-site-review/SKILL.md +0 -70
  163. package/dist/claude/.claude/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  164. package/dist/codex/.agents/skills/jahia-dev-site-review/SKILL.md +0 -70
  165. package/dist/codex/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  166. package/dist/copilot/.agents/skills/jahia-dev-site-review/SKILL.md +0 -70
  167. package/dist/copilot/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  168. package/dist/cursor/.agents/skills/jahia-dev-site-review/SKILL.md +0 -70
  169. package/dist/cursor/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  170. package/dist/gemini/.agents/skills/jahia-dev-review/SKILL.md +0 -228
  171. package/dist/gemini/.agents/skills/jahia-dev-site-review/SKILL.md +0 -70
  172. package/dist/gemini/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  173. package/dist/opencode/.agents/skills/jahia-dev-review/SKILL.md +0 -228
  174. package/dist/opencode/.agents/skills/jahia-dev-site-review/SKILL.md +0 -70
  175. package/dist/opencode/.agents/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
  176. package/dist/windsurf/.windsurf/skills/jahia-dev-review/SKILL.md +0 -228
  177. package/dist/windsurf/.windsurf/skills/jahia-dev-site-review/SKILL.md +0 -70
  178. package/dist/windsurf/.windsurf/skills/jahia-dev-site-review/scripts/review-pages.mjs +0 -85
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env node
2
- // Runs a11y (axe-core) + SEO checks on every URL in pages.json.
3
- // Exits 1 if any page has critical/serious a11y violations or missing SEO basics.
4
- import { chromium } from "playwright";
5
- import { AxeBuilder } from "@axe-core/playwright";
6
- import { readFileSync } from "fs";
7
-
8
- const IMPACTS = { minor: 0.1, moderate: 0.25, serious: 0.5, critical: 1 };
9
-
10
- const urls = JSON.parse(readFileSync("pages.json", "utf-8"));
11
- const browser = await chromium.launch({ args: ["--no-sandbox"] });
12
- const context = await browser.newContext();
13
- const page = await context.newPage();
14
-
15
- const results = [];
16
-
17
- for (const url of urls) {
18
- process.stdout.write(`\nChecking ${url} … `);
19
- await page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
20
-
21
- // A11y
22
- const axe = await new AxeBuilder({ page })
23
- .withTags(["wcag2a", "wcag2aa", "wcag21aa"])
24
- .analyze();
25
-
26
- const a11yScore = Math.exp(
27
- -axe.violations.reduce((t, v) => t + (IMPACTS[v.impact] ?? 0), 0),
28
- );
29
-
30
- // SEO
31
- const title = await page.title();
32
- const metaDesc = await page
33
- .$eval('meta[name="description"]', el => el.getAttribute("content"))
34
- .catch(() => null);
35
- const h1s = await page.$$eval("h1", els => els.map(e => e.textContent?.trim()));
36
- const imgsMissingAlt = await page.$$eval(
37
- "img",
38
- els => els.filter(e => !e.getAttribute("alt")).map(e => e.outerHTML.slice(0, 80)),
39
- );
40
-
41
- const seoIssues = [];
42
- if (!title) seoIssues.push("missing <title>");
43
- if (!metaDesc) seoIssues.push("missing <meta name=description>");
44
- if (h1s.length === 0) seoIssues.push("no <h1>");
45
- if (h1s.length > 1) seoIssues.push(`${h1s.length} <h1> elements (must be exactly 1)`);
46
- if (imgsMissingAlt.length > 0)
47
- seoIssues.push(`${imgsMissingAlt.length} <img> missing alt attribute`);
48
-
49
- process.stdout.write(`a11y=${a11yScore.toFixed(3)}\n`);
50
- results.push({ url, a11yScore, violations: axe.violations, seoIssues });
51
- }
52
-
53
- await browser.close();
54
-
55
- // ── Report ──────────────────────────────────────────────────────────────────
56
- let failed = false;
57
-
58
- for (const r of results) {
59
- const critical = r.violations.filter(v => v.impact === "critical" || v.impact === "serious");
60
- const pageOk = critical.length === 0 && r.seoIssues.length === 0;
61
- if (!pageOk) failed = true;
62
-
63
- console.log(`\n${"─".repeat(70)}`);
64
- console.log(`${pageOk ? "✅" : "❌"} ${r.url}`);
65
- console.log(` A11y score : ${r.a11yScore.toFixed(3)} (1.0 = perfect)`);
66
-
67
- for (const v of r.violations) {
68
- const marker = v.impact === "critical" || v.impact === "serious" ? "🔴" : "🟡";
69
- console.log(` ${marker} [${v.impact}] ${v.id} — ${v.description} (${v.nodes.length} node${v.nodes.length !== 1 ? "s" : ""})`);
70
- for (const node of v.nodes.slice(0, 3)) {
71
- console.log(` ${node.html.slice(0, 100)}`);
72
- }
73
- }
74
-
75
- for (const issue of r.seoIssues) {
76
- console.log(` 🔍 SEO: ${issue}`);
77
- }
78
- }
79
-
80
- console.log(`\n${"═".repeat(70)}`);
81
- const avg = results.reduce((t, r) => t + r.a11yScore, 0) / results.length;
82
- console.log(`Average a11y score: ${avg.toFixed(3)}`);
83
- console.log(failed ? "\n❌ FAIL — fix the issues above, redeploy, and re-run." : "\n✅ PASS");
84
-
85
- process.exit(failed ? 1 : 0);
@@ -1,70 +0,0 @@
1
- ---
2
- name: jahia-dev-site-review
3
- description: Scores live pages for accessibility (WCAG 2.1 AA via axe-core) and SEO (title, meta description, h1, alt). Use after deploying to get a pass/fail signal with per-violation detail before completing development.
4
- allowed-tools: Bash, Read, Write, Edit
5
- ---
6
-
7
- # Skill: jahia-dev-site-review
8
-
9
- Runs automated a11y and SEO checks against every URL in `pages.json`. Reports a numeric score per page, lists violations by severity, and exits non-zero on any critical/serious a11y violation or missing SEO baseline.
10
-
11
- **A11y scoring:** `Math.exp(-Σ impact_weights)` where `critical=1, serious=0.5, moderate=0.25, minor=0.1`. Score of 1.0 = perfect; 0.607 = one serious violation.
12
-
13
- ---
14
-
15
- ## Step 1 — Ensure tooling is installed
16
-
17
- ```bash
18
- node -e "require('@axe-core/playwright'); require('playwright')" 2>/dev/null || \
19
- npm install --no-save @axe-core/playwright playwright && npx playwright install chromium --with-deps
20
- ```
21
-
22
- ---
23
-
24
- ## Step 2 — Run the review
25
-
26
- ```bash
27
- SCRIPT=$(find .claude .agents -name "review-pages.mjs" 2>/dev/null | head -1)
28
- node "$SCRIPT" 2>&1 | tee /tmp/site-review.txt
29
- ```
30
-
31
- ---
32
-
33
- ## Step 3 — Interpret and fix
34
-
35
- The script exits 1 if any page has:
36
- - A `🔴 [critical]` or `🔴 [serious]` a11y violation
37
- - A `🔍 SEO` issue (missing title, meta description, h1, or img alt)
38
-
39
- `🟡 [moderate]` and `🟡 [minor]` violations are reported but do not fail the run — fix them for a higher score.
40
-
41
- **Common violations and where to fix them:**
42
-
43
- | Violation | Fix location |
44
- |---|---|
45
- | `landmark-*` empty nav or footer | Page template — ensure `<nav>` has inline content, `<footer>` has fallback text |
46
- | `page-has-heading-one` | Page template — add `<h1>{title}</h1>` |
47
- | `image-alt` | Component `.server.tsx` — use `imageAlt \|\| title \|\| 'Image'` |
48
- | `color-contrast` | Component `.module.css` — check foreground/background ratio ≥ 4.5:1 |
49
- | `heading-order` | Component — components start at `<h2>`, sub-items at `<h3>` |
50
- | Missing `<title>` | Page template `<head>` |
51
- | Missing meta description | Page template `<head>` — add `<meta name="description" content={…} />` |
52
- | Multiple `<h1>` | Remove `<h1>` from components; only the template renders one |
53
-
54
- After fixing, redeploy and re-run:
55
-
56
- ```bash
57
- yarn build && yarn jahia-deploy
58
- node "$SCRIPT"
59
- ```
60
-
61
- Iterate until the script exits 0.
62
-
63
- ---
64
-
65
- ## Validation checklist
66
- - [ ] Script exits 0 (no critical/serious violations, no SEO issues)
67
- - [ ] Average a11y score ≥ 0.8
68
- - [ ] Every page has a unique, non-empty `<title>`
69
- - [ ] Every page has `<meta name="description">`
70
- - [ ] Every page has exactly one `<h1>`
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env node
2
- // Runs a11y (axe-core) + SEO checks on every URL in pages.json.
3
- // Exits 1 if any page has critical/serious a11y violations or missing SEO basics.
4
- import { chromium } from "playwright";
5
- import { AxeBuilder } from "@axe-core/playwright";
6
- import { readFileSync } from "fs";
7
-
8
- const IMPACTS = { minor: 0.1, moderate: 0.25, serious: 0.5, critical: 1 };
9
-
10
- const urls = JSON.parse(readFileSync("pages.json", "utf-8"));
11
- const browser = await chromium.launch({ args: ["--no-sandbox"] });
12
- const context = await browser.newContext();
13
- const page = await context.newPage();
14
-
15
- const results = [];
16
-
17
- for (const url of urls) {
18
- process.stdout.write(`\nChecking ${url} … `);
19
- await page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
20
-
21
- // A11y
22
- const axe = await new AxeBuilder({ page })
23
- .withTags(["wcag2a", "wcag2aa", "wcag21aa"])
24
- .analyze();
25
-
26
- const a11yScore = Math.exp(
27
- -axe.violations.reduce((t, v) => t + (IMPACTS[v.impact] ?? 0), 0),
28
- );
29
-
30
- // SEO
31
- const title = await page.title();
32
- const metaDesc = await page
33
- .$eval('meta[name="description"]', el => el.getAttribute("content"))
34
- .catch(() => null);
35
- const h1s = await page.$$eval("h1", els => els.map(e => e.textContent?.trim()));
36
- const imgsMissingAlt = await page.$$eval(
37
- "img",
38
- els => els.filter(e => !e.getAttribute("alt")).map(e => e.outerHTML.slice(0, 80)),
39
- );
40
-
41
- const seoIssues = [];
42
- if (!title) seoIssues.push("missing <title>");
43
- if (!metaDesc) seoIssues.push("missing <meta name=description>");
44
- if (h1s.length === 0) seoIssues.push("no <h1>");
45
- if (h1s.length > 1) seoIssues.push(`${h1s.length} <h1> elements (must be exactly 1)`);
46
- if (imgsMissingAlt.length > 0)
47
- seoIssues.push(`${imgsMissingAlt.length} <img> missing alt attribute`);
48
-
49
- process.stdout.write(`a11y=${a11yScore.toFixed(3)}\n`);
50
- results.push({ url, a11yScore, violations: axe.violations, seoIssues });
51
- }
52
-
53
- await browser.close();
54
-
55
- // ── Report ──────────────────────────────────────────────────────────────────
56
- let failed = false;
57
-
58
- for (const r of results) {
59
- const critical = r.violations.filter(v => v.impact === "critical" || v.impact === "serious");
60
- const pageOk = critical.length === 0 && r.seoIssues.length === 0;
61
- if (!pageOk) failed = true;
62
-
63
- console.log(`\n${"─".repeat(70)}`);
64
- console.log(`${pageOk ? "✅" : "❌"} ${r.url}`);
65
- console.log(` A11y score : ${r.a11yScore.toFixed(3)} (1.0 = perfect)`);
66
-
67
- for (const v of r.violations) {
68
- const marker = v.impact === "critical" || v.impact === "serious" ? "🔴" : "🟡";
69
- console.log(` ${marker} [${v.impact}] ${v.id} — ${v.description} (${v.nodes.length} node${v.nodes.length !== 1 ? "s" : ""})`);
70
- for (const node of v.nodes.slice(0, 3)) {
71
- console.log(` ${node.html.slice(0, 100)}`);
72
- }
73
- }
74
-
75
- for (const issue of r.seoIssues) {
76
- console.log(` 🔍 SEO: ${issue}`);
77
- }
78
- }
79
-
80
- console.log(`\n${"═".repeat(70)}`);
81
- const avg = results.reduce((t, r) => t + r.a11yScore, 0) / results.length;
82
- console.log(`Average a11y score: ${avg.toFixed(3)}`);
83
- console.log(failed ? "\n❌ FAIL — fix the issues above, redeploy, and re-run." : "\n✅ PASS");
84
-
85
- process.exit(failed ? 1 : 0);
@@ -1,70 +0,0 @@
1
- ---
2
- name: jahia-dev-site-review
3
- description: Scores live pages for accessibility (WCAG 2.1 AA via axe-core) and SEO (title, meta description, h1, alt). Use after deploying to get a pass/fail signal with per-violation detail before completing development.
4
- allowed-tools: Bash, Read, Write, Edit
5
- ---
6
-
7
- # Skill: jahia-dev-site-review
8
-
9
- Runs automated a11y and SEO checks against every URL in `pages.json`. Reports a numeric score per page, lists violations by severity, and exits non-zero on any critical/serious a11y violation or missing SEO baseline.
10
-
11
- **A11y scoring:** `Math.exp(-Σ impact_weights)` where `critical=1, serious=0.5, moderate=0.25, minor=0.1`. Score of 1.0 = perfect; 0.607 = one serious violation.
12
-
13
- ---
14
-
15
- ## Step 1 — Ensure tooling is installed
16
-
17
- ```bash
18
- node -e "require('@axe-core/playwright'); require('playwright')" 2>/dev/null || \
19
- npm install --no-save @axe-core/playwright playwright && npx playwright install chromium --with-deps
20
- ```
21
-
22
- ---
23
-
24
- ## Step 2 — Run the review
25
-
26
- ```bash
27
- SCRIPT=$(find .claude .agents -name "review-pages.mjs" 2>/dev/null | head -1)
28
- node "$SCRIPT" 2>&1 | tee /tmp/site-review.txt
29
- ```
30
-
31
- ---
32
-
33
- ## Step 3 — Interpret and fix
34
-
35
- The script exits 1 if any page has:
36
- - A `🔴 [critical]` or `🔴 [serious]` a11y violation
37
- - A `🔍 SEO` issue (missing title, meta description, h1, or img alt)
38
-
39
- `🟡 [moderate]` and `🟡 [minor]` violations are reported but do not fail the run — fix them for a higher score.
40
-
41
- **Common violations and where to fix them:**
42
-
43
- | Violation | Fix location |
44
- |---|---|
45
- | `landmark-*` empty nav or footer | Page template — ensure `<nav>` has inline content, `<footer>` has fallback text |
46
- | `page-has-heading-one` | Page template — add `<h1>{title}</h1>` |
47
- | `image-alt` | Component `.server.tsx` — use `imageAlt \|\| title \|\| 'Image'` |
48
- | `color-contrast` | Component `.module.css` — check foreground/background ratio ≥ 4.5:1 |
49
- | `heading-order` | Component — components start at `<h2>`, sub-items at `<h3>` |
50
- | Missing `<title>` | Page template `<head>` |
51
- | Missing meta description | Page template `<head>` — add `<meta name="description" content={…} />` |
52
- | Multiple `<h1>` | Remove `<h1>` from components; only the template renders one |
53
-
54
- After fixing, redeploy and re-run:
55
-
56
- ```bash
57
- yarn build && yarn jahia-deploy
58
- node "$SCRIPT"
59
- ```
60
-
61
- Iterate until the script exits 0.
62
-
63
- ---
64
-
65
- ## Validation checklist
66
- - [ ] Script exits 0 (no critical/serious violations, no SEO issues)
67
- - [ ] Average a11y score ≥ 0.8
68
- - [ ] Every page has a unique, non-empty `<title>`
69
- - [ ] Every page has `<meta name="description">`
70
- - [ ] Every page has exactly one `<h1>`
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env node
2
- // Runs a11y (axe-core) + SEO checks on every URL in pages.json.
3
- // Exits 1 if any page has critical/serious a11y violations or missing SEO basics.
4
- import { chromium } from "playwright";
5
- import { AxeBuilder } from "@axe-core/playwright";
6
- import { readFileSync } from "fs";
7
-
8
- const IMPACTS = { minor: 0.1, moderate: 0.25, serious: 0.5, critical: 1 };
9
-
10
- const urls = JSON.parse(readFileSync("pages.json", "utf-8"));
11
- const browser = await chromium.launch({ args: ["--no-sandbox"] });
12
- const context = await browser.newContext();
13
- const page = await context.newPage();
14
-
15
- const results = [];
16
-
17
- for (const url of urls) {
18
- process.stdout.write(`\nChecking ${url} … `);
19
- await page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
20
-
21
- // A11y
22
- const axe = await new AxeBuilder({ page })
23
- .withTags(["wcag2a", "wcag2aa", "wcag21aa"])
24
- .analyze();
25
-
26
- const a11yScore = Math.exp(
27
- -axe.violations.reduce((t, v) => t + (IMPACTS[v.impact] ?? 0), 0),
28
- );
29
-
30
- // SEO
31
- const title = await page.title();
32
- const metaDesc = await page
33
- .$eval('meta[name="description"]', el => el.getAttribute("content"))
34
- .catch(() => null);
35
- const h1s = await page.$$eval("h1", els => els.map(e => e.textContent?.trim()));
36
- const imgsMissingAlt = await page.$$eval(
37
- "img",
38
- els => els.filter(e => !e.getAttribute("alt")).map(e => e.outerHTML.slice(0, 80)),
39
- );
40
-
41
- const seoIssues = [];
42
- if (!title) seoIssues.push("missing <title>");
43
- if (!metaDesc) seoIssues.push("missing <meta name=description>");
44
- if (h1s.length === 0) seoIssues.push("no <h1>");
45
- if (h1s.length > 1) seoIssues.push(`${h1s.length} <h1> elements (must be exactly 1)`);
46
- if (imgsMissingAlt.length > 0)
47
- seoIssues.push(`${imgsMissingAlt.length} <img> missing alt attribute`);
48
-
49
- process.stdout.write(`a11y=${a11yScore.toFixed(3)}\n`);
50
- results.push({ url, a11yScore, violations: axe.violations, seoIssues });
51
- }
52
-
53
- await browser.close();
54
-
55
- // ── Report ──────────────────────────────────────────────────────────────────
56
- let failed = false;
57
-
58
- for (const r of results) {
59
- const critical = r.violations.filter(v => v.impact === "critical" || v.impact === "serious");
60
- const pageOk = critical.length === 0 && r.seoIssues.length === 0;
61
- if (!pageOk) failed = true;
62
-
63
- console.log(`\n${"─".repeat(70)}`);
64
- console.log(`${pageOk ? "✅" : "❌"} ${r.url}`);
65
- console.log(` A11y score : ${r.a11yScore.toFixed(3)} (1.0 = perfect)`);
66
-
67
- for (const v of r.violations) {
68
- const marker = v.impact === "critical" || v.impact === "serious" ? "🔴" : "🟡";
69
- console.log(` ${marker} [${v.impact}] ${v.id} — ${v.description} (${v.nodes.length} node${v.nodes.length !== 1 ? "s" : ""})`);
70
- for (const node of v.nodes.slice(0, 3)) {
71
- console.log(` ${node.html.slice(0, 100)}`);
72
- }
73
- }
74
-
75
- for (const issue of r.seoIssues) {
76
- console.log(` 🔍 SEO: ${issue}`);
77
- }
78
- }
79
-
80
- console.log(`\n${"═".repeat(70)}`);
81
- const avg = results.reduce((t, r) => t + r.a11yScore, 0) / results.length;
82
- console.log(`Average a11y score: ${avg.toFixed(3)}`);
83
- console.log(failed ? "\n❌ FAIL — fix the issues above, redeploy, and re-run." : "\n✅ PASS");
84
-
85
- process.exit(failed ? 1 : 0);
@@ -1,70 +0,0 @@
1
- ---
2
- name: jahia-dev-site-review
3
- description: Scores live pages for accessibility (WCAG 2.1 AA via axe-core) and SEO (title, meta description, h1, alt). Use after deploying to get a pass/fail signal with per-violation detail before completing development.
4
- allowed-tools: Bash, Read, Write, Edit
5
- ---
6
-
7
- # Skill: jahia-dev-site-review
8
-
9
- Runs automated a11y and SEO checks against every URL in `pages.json`. Reports a numeric score per page, lists violations by severity, and exits non-zero on any critical/serious a11y violation or missing SEO baseline.
10
-
11
- **A11y scoring:** `Math.exp(-Σ impact_weights)` where `critical=1, serious=0.5, moderate=0.25, minor=0.1`. Score of 1.0 = perfect; 0.607 = one serious violation.
12
-
13
- ---
14
-
15
- ## Step 1 — Ensure tooling is installed
16
-
17
- ```bash
18
- node -e "require('@axe-core/playwright'); require('playwright')" 2>/dev/null || \
19
- npm install --no-save @axe-core/playwright playwright && npx playwright install chromium --with-deps
20
- ```
21
-
22
- ---
23
-
24
- ## Step 2 — Run the review
25
-
26
- ```bash
27
- SCRIPT=$(find .claude .agents -name "review-pages.mjs" 2>/dev/null | head -1)
28
- node "$SCRIPT" 2>&1 | tee /tmp/site-review.txt
29
- ```
30
-
31
- ---
32
-
33
- ## Step 3 — Interpret and fix
34
-
35
- The script exits 1 if any page has:
36
- - A `🔴 [critical]` or `🔴 [serious]` a11y violation
37
- - A `🔍 SEO` issue (missing title, meta description, h1, or img alt)
38
-
39
- `🟡 [moderate]` and `🟡 [minor]` violations are reported but do not fail the run — fix them for a higher score.
40
-
41
- **Common violations and where to fix them:**
42
-
43
- | Violation | Fix location |
44
- |---|---|
45
- | `landmark-*` empty nav or footer | Page template — ensure `<nav>` has inline content, `<footer>` has fallback text |
46
- | `page-has-heading-one` | Page template — add `<h1>{title}</h1>` |
47
- | `image-alt` | Component `.server.tsx` — use `imageAlt \|\| title \|\| 'Image'` |
48
- | `color-contrast` | Component `.module.css` — check foreground/background ratio ≥ 4.5:1 |
49
- | `heading-order` | Component — components start at `<h2>`, sub-items at `<h3>` |
50
- | Missing `<title>` | Page template `<head>` |
51
- | Missing meta description | Page template `<head>` — add `<meta name="description" content={…} />` |
52
- | Multiple `<h1>` | Remove `<h1>` from components; only the template renders one |
53
-
54
- After fixing, redeploy and re-run:
55
-
56
- ```bash
57
- yarn build && yarn jahia-deploy
58
- node "$SCRIPT"
59
- ```
60
-
61
- Iterate until the script exits 0.
62
-
63
- ---
64
-
65
- ## Validation checklist
66
- - [ ] Script exits 0 (no critical/serious violations, no SEO issues)
67
- - [ ] Average a11y score ≥ 0.8
68
- - [ ] Every page has a unique, non-empty `<title>`
69
- - [ ] Every page has `<meta name="description">`
70
- - [ ] Every page has exactly one `<h1>`
@@ -1,85 +0,0 @@
1
- #!/usr/bin/env node
2
- // Runs a11y (axe-core) + SEO checks on every URL in pages.json.
3
- // Exits 1 if any page has critical/serious a11y violations or missing SEO basics.
4
- import { chromium } from "playwright";
5
- import { AxeBuilder } from "@axe-core/playwright";
6
- import { readFileSync } from "fs";
7
-
8
- const IMPACTS = { minor: 0.1, moderate: 0.25, serious: 0.5, critical: 1 };
9
-
10
- const urls = JSON.parse(readFileSync("pages.json", "utf-8"));
11
- const browser = await chromium.launch({ args: ["--no-sandbox"] });
12
- const context = await browser.newContext();
13
- const page = await context.newPage();
14
-
15
- const results = [];
16
-
17
- for (const url of urls) {
18
- process.stdout.write(`\nChecking ${url} … `);
19
- await page.goto(url, { waitUntil: "networkidle", timeout: 30_000 });
20
-
21
- // A11y
22
- const axe = await new AxeBuilder({ page })
23
- .withTags(["wcag2a", "wcag2aa", "wcag21aa"])
24
- .analyze();
25
-
26
- const a11yScore = Math.exp(
27
- -axe.violations.reduce((t, v) => t + (IMPACTS[v.impact] ?? 0), 0),
28
- );
29
-
30
- // SEO
31
- const title = await page.title();
32
- const metaDesc = await page
33
- .$eval('meta[name="description"]', el => el.getAttribute("content"))
34
- .catch(() => null);
35
- const h1s = await page.$$eval("h1", els => els.map(e => e.textContent?.trim()));
36
- const imgsMissingAlt = await page.$$eval(
37
- "img",
38
- els => els.filter(e => !e.getAttribute("alt")).map(e => e.outerHTML.slice(0, 80)),
39
- );
40
-
41
- const seoIssues = [];
42
- if (!title) seoIssues.push("missing <title>");
43
- if (!metaDesc) seoIssues.push("missing <meta name=description>");
44
- if (h1s.length === 0) seoIssues.push("no <h1>");
45
- if (h1s.length > 1) seoIssues.push(`${h1s.length} <h1> elements (must be exactly 1)`);
46
- if (imgsMissingAlt.length > 0)
47
- seoIssues.push(`${imgsMissingAlt.length} <img> missing alt attribute`);
48
-
49
- process.stdout.write(`a11y=${a11yScore.toFixed(3)}\n`);
50
- results.push({ url, a11yScore, violations: axe.violations, seoIssues });
51
- }
52
-
53
- await browser.close();
54
-
55
- // ── Report ──────────────────────────────────────────────────────────────────
56
- let failed = false;
57
-
58
- for (const r of results) {
59
- const critical = r.violations.filter(v => v.impact === "critical" || v.impact === "serious");
60
- const pageOk = critical.length === 0 && r.seoIssues.length === 0;
61
- if (!pageOk) failed = true;
62
-
63
- console.log(`\n${"─".repeat(70)}`);
64
- console.log(`${pageOk ? "✅" : "❌"} ${r.url}`);
65
- console.log(` A11y score : ${r.a11yScore.toFixed(3)} (1.0 = perfect)`);
66
-
67
- for (const v of r.violations) {
68
- const marker = v.impact === "critical" || v.impact === "serious" ? "🔴" : "🟡";
69
- console.log(` ${marker} [${v.impact}] ${v.id} — ${v.description} (${v.nodes.length} node${v.nodes.length !== 1 ? "s" : ""})`);
70
- for (const node of v.nodes.slice(0, 3)) {
71
- console.log(` ${node.html.slice(0, 100)}`);
72
- }
73
- }
74
-
75
- for (const issue of r.seoIssues) {
76
- console.log(` 🔍 SEO: ${issue}`);
77
- }
78
- }
79
-
80
- console.log(`\n${"═".repeat(70)}`);
81
- const avg = results.reduce((t, r) => t + r.a11yScore, 0) / results.length;
82
- console.log(`Average a11y score: ${avg.toFixed(3)}`);
83
- console.log(failed ? "\n❌ FAIL — fix the issues above, redeploy, and re-run." : "\n✅ PASS");
84
-
85
- process.exit(failed ? 1 : 0);