javi-forge 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.
Files changed (500) hide show
  1. package/.gitignore.template +105 -0
  2. package/.releaserc +44 -0
  3. package/README.md +45 -0
  4. package/ai-config/.skillignore +15 -0
  5. package/ai-config/AUTO_INVOKE.md +300 -0
  6. package/ai-config/agents/_TEMPLATE.md +93 -0
  7. package/ai-config/agents/business/api-designer.md +1657 -0
  8. package/ai-config/agents/business/business-analyst.md +1331 -0
  9. package/ai-config/agents/business/product-strategist.md +206 -0
  10. package/ai-config/agents/business/project-manager.md +178 -0
  11. package/ai-config/agents/business/requirements-analyst.md +1277 -0
  12. package/ai-config/agents/business/technical-writer.md +1679 -0
  13. package/ai-config/agents/creative/ux-designer.md +205 -0
  14. package/ai-config/agents/data-ai/ai-engineer.md +487 -0
  15. package/ai-config/agents/data-ai/analytics-engineer.md +953 -0
  16. package/ai-config/agents/data-ai/data-engineer.md +173 -0
  17. package/ai-config/agents/data-ai/data-scientist.md +672 -0
  18. package/ai-config/agents/data-ai/mlops-engineer.md +814 -0
  19. package/ai-config/agents/data-ai/prompt-engineer.md +772 -0
  20. package/ai-config/agents/development/angular-expert.md +620 -0
  21. package/ai-config/agents/development/backend-architect.md +795 -0
  22. package/ai-config/agents/development/database-specialist.md +212 -0
  23. package/ai-config/agents/development/frontend-specialist.md +686 -0
  24. package/ai-config/agents/development/fullstack-engineer.md +668 -0
  25. package/ai-config/agents/development/golang-pro.md +338 -0
  26. package/ai-config/agents/development/java-enterprise.md +400 -0
  27. package/ai-config/agents/development/javascript-pro.md +422 -0
  28. package/ai-config/agents/development/nextjs-pro.md +474 -0
  29. package/ai-config/agents/development/python-pro.md +570 -0
  30. package/ai-config/agents/development/react-pro.md +487 -0
  31. package/ai-config/agents/development/rust-pro.md +246 -0
  32. package/ai-config/agents/development/spring-boot-4-expert.md +326 -0
  33. package/ai-config/agents/development/typescript-pro.md +336 -0
  34. package/ai-config/agents/development/vue-specialist.md +605 -0
  35. package/ai-config/agents/infrastructure/cloud-architect.md +472 -0
  36. package/ai-config/agents/infrastructure/deployment-manager.md +358 -0
  37. package/ai-config/agents/infrastructure/devops-engineer.md +455 -0
  38. package/ai-config/agents/infrastructure/incident-responder.md +519 -0
  39. package/ai-config/agents/infrastructure/kubernetes-expert.md +705 -0
  40. package/ai-config/agents/infrastructure/monitoring-specialist.md +674 -0
  41. package/ai-config/agents/infrastructure/performance-engineer.md +658 -0
  42. package/ai-config/agents/orchestrator.md +241 -0
  43. package/ai-config/agents/quality/accessibility-auditor.md +1204 -0
  44. package/ai-config/agents/quality/code-reviewer-compact.md +123 -0
  45. package/ai-config/agents/quality/code-reviewer.md +363 -0
  46. package/ai-config/agents/quality/dependency-manager.md +743 -0
  47. package/ai-config/agents/quality/e2e-test-specialist.md +1005 -0
  48. package/ai-config/agents/quality/performance-tester.md +1086 -0
  49. package/ai-config/agents/quality/security-auditor.md +133 -0
  50. package/ai-config/agents/quality/test-engineer.md +453 -0
  51. package/ai-config/agents/specialists/api-designer.md +87 -0
  52. package/ai-config/agents/specialists/backend-architect.md +73 -0
  53. package/ai-config/agents/specialists/code-reviewer.md +77 -0
  54. package/ai-config/agents/specialists/db-optimizer.md +75 -0
  55. package/ai-config/agents/specialists/devops-engineer.md +83 -0
  56. package/ai-config/agents/specialists/documentation-writer.md +78 -0
  57. package/ai-config/agents/specialists/frontend-developer.md +75 -0
  58. package/ai-config/agents/specialists/performance-analyst.md +82 -0
  59. package/ai-config/agents/specialists/refactor-specialist.md +74 -0
  60. package/ai-config/agents/specialists/security-auditor.md +74 -0
  61. package/ai-config/agents/specialists/test-engineer.md +81 -0
  62. package/ai-config/agents/specialists/ux-consultant.md +76 -0
  63. package/ai-config/agents/specialized/agent-generator.md +1190 -0
  64. package/ai-config/agents/specialized/blockchain-developer.md +149 -0
  65. package/ai-config/agents/specialized/code-migrator.md +892 -0
  66. package/ai-config/agents/specialized/context-manager.md +978 -0
  67. package/ai-config/agents/specialized/documentation-writer.md +1078 -0
  68. package/ai-config/agents/specialized/ecommerce-expert.md +1756 -0
  69. package/ai-config/agents/specialized/embedded-engineer.md +1714 -0
  70. package/ai-config/agents/specialized/error-detective.md +1034 -0
  71. package/ai-config/agents/specialized/fintech-specialist.md +1659 -0
  72. package/ai-config/agents/specialized/freelance-project-planner-v2.md +1988 -0
  73. package/ai-config/agents/specialized/freelance-project-planner-v3.md +2136 -0
  74. package/ai-config/agents/specialized/freelance-project-planner-v4.md +4503 -0
  75. package/ai-config/agents/specialized/freelance-project-planner.md +722 -0
  76. package/ai-config/agents/specialized/game-developer.md +1963 -0
  77. package/ai-config/agents/specialized/healthcare-dev.md +1620 -0
  78. package/ai-config/agents/specialized/mobile-developer.md +188 -0
  79. package/ai-config/agents/specialized/parallel-plan-executor.md +506 -0
  80. package/ai-config/agents/specialized/plan-executor.md +485 -0
  81. package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +485 -0
  82. package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +3493 -0
  83. package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +778 -0
  84. package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +918 -0
  85. package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +1537 -0
  86. package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +2633 -0
  87. package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +5610 -0
  88. package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +335 -0
  89. package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +215 -0
  90. package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +260 -0
  91. package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +379 -0
  92. package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +355 -0
  93. package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +279 -0
  94. package/ai-config/agents/specialized/template-writer.md +347 -0
  95. package/ai-config/agents/specialized/test-runner.md +99 -0
  96. package/ai-config/agents/specialized/vibekanban-smart-worker.md +244 -0
  97. package/ai-config/agents/specialized/wave-executor.md +138 -0
  98. package/ai-config/agents/specialized/workflow-optimizer.md +1114 -0
  99. package/ai-config/commands/git/changelog.md +32 -0
  100. package/ai-config/commands/git/ci-local.md +70 -0
  101. package/ai-config/commands/git/commit.md +35 -0
  102. package/ai-config/commands/git/fix-issue.md +23 -0
  103. package/ai-config/commands/git/pr-create.md +42 -0
  104. package/ai-config/commands/git/pr-review.md +50 -0
  105. package/ai-config/commands/git/worktree.md +39 -0
  106. package/ai-config/commands/refactoring/cleanup.md +24 -0
  107. package/ai-config/commands/refactoring/dead-code.md +40 -0
  108. package/ai-config/commands/refactoring/extract.md +31 -0
  109. package/ai-config/commands/testing/e2e.md +30 -0
  110. package/ai-config/commands/testing/tdd.md +36 -0
  111. package/ai-config/commands/testing/test-coverage.md +30 -0
  112. package/ai-config/commands/testing/test-fix.md +24 -0
  113. package/ai-config/commands/workflow/generate-agents-md.md +85 -0
  114. package/ai-config/commands/workflow/planning.md +47 -0
  115. package/ai-config/commands/workflows/compound.md +89 -0
  116. package/ai-config/commands/workflows/plan.md +77 -0
  117. package/ai-config/commands/workflows/review.md +78 -0
  118. package/ai-config/commands/workflows/work.md +75 -0
  119. package/ai-config/config.yaml +18 -0
  120. package/ai-config/hooks/_TEMPLATE.md +96 -0
  121. package/ai-config/hooks/block-dangerous-commands.md +75 -0
  122. package/ai-config/hooks/commit-guard.md +90 -0
  123. package/ai-config/hooks/context-loader.md +73 -0
  124. package/ai-config/hooks/improve-prompt.md +91 -0
  125. package/ai-config/hooks/learning-log.md +72 -0
  126. package/ai-config/hooks/model-router.md +86 -0
  127. package/ai-config/hooks/secret-scanner.md +64 -0
  128. package/ai-config/hooks/skill-validator.md +102 -0
  129. package/ai-config/hooks/task-artifact.md +114 -0
  130. package/ai-config/hooks/validate-workflow.md +100 -0
  131. package/ai-config/prompts/base.md +71 -0
  132. package/ai-config/prompts/modes/debug.md +34 -0
  133. package/ai-config/prompts/modes/deploy.md +40 -0
  134. package/ai-config/prompts/modes/research.md +32 -0
  135. package/ai-config/prompts/modes/review.md +33 -0
  136. package/ai-config/prompts/review-policy.md +79 -0
  137. package/ai-config/skills/_TEMPLATE.md +157 -0
  138. package/ai-config/skills/backend/api-gateway/SKILL.md +254 -0
  139. package/ai-config/skills/backend/bff-concepts/SKILL.md +239 -0
  140. package/ai-config/skills/backend/bff-spring/SKILL.md +364 -0
  141. package/ai-config/skills/backend/chi-router/SKILL.md +396 -0
  142. package/ai-config/skills/backend/error-handling/SKILL.md +255 -0
  143. package/ai-config/skills/backend/exceptions-spring/SKILL.md +323 -0
  144. package/ai-config/skills/backend/fastapi/SKILL.md +302 -0
  145. package/ai-config/skills/backend/gateway-spring/SKILL.md +390 -0
  146. package/ai-config/skills/backend/go-backend/SKILL.md +457 -0
  147. package/ai-config/skills/backend/gradle-multimodule/SKILL.md +274 -0
  148. package/ai-config/skills/backend/graphql-concepts/SKILL.md +352 -0
  149. package/ai-config/skills/backend/graphql-spring/SKILL.md +398 -0
  150. package/ai-config/skills/backend/grpc-concepts/SKILL.md +283 -0
  151. package/ai-config/skills/backend/grpc-spring/SKILL.md +445 -0
  152. package/ai-config/skills/backend/jwt-auth/SKILL.md +412 -0
  153. package/ai-config/skills/backend/notifications-concepts/SKILL.md +259 -0
  154. package/ai-config/skills/backend/recommendations-concepts/SKILL.md +261 -0
  155. package/ai-config/skills/backend/search-concepts/SKILL.md +263 -0
  156. package/ai-config/skills/backend/search-spring/SKILL.md +375 -0
  157. package/ai-config/skills/backend/spring-boot-4/SKILL.md +172 -0
  158. package/ai-config/skills/backend/websockets/SKILL.md +532 -0
  159. package/ai-config/skills/data-ai/ai-ml/SKILL.md +423 -0
  160. package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +195 -0
  161. package/ai-config/skills/data-ai/analytics-spring/SKILL.md +340 -0
  162. package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +440 -0
  163. package/ai-config/skills/data-ai/langchain/SKILL.md +238 -0
  164. package/ai-config/skills/data-ai/mlflow/SKILL.md +302 -0
  165. package/ai-config/skills/data-ai/onnx-inference/SKILL.md +290 -0
  166. package/ai-config/skills/data-ai/powerbi/SKILL.md +352 -0
  167. package/ai-config/skills/data-ai/pytorch/SKILL.md +274 -0
  168. package/ai-config/skills/data-ai/scikit-learn/SKILL.md +321 -0
  169. package/ai-config/skills/data-ai/vector-db/SKILL.md +301 -0
  170. package/ai-config/skills/database/graph-databases/SKILL.md +218 -0
  171. package/ai-config/skills/database/graph-spring/SKILL.md +361 -0
  172. package/ai-config/skills/database/pgx-postgres/SKILL.md +512 -0
  173. package/ai-config/skills/database/redis-cache/SKILL.md +343 -0
  174. package/ai-config/skills/database/sqlite-embedded/SKILL.md +388 -0
  175. package/ai-config/skills/database/timescaledb/SKILL.md +320 -0
  176. package/ai-config/skills/docs/api-documentation/SKILL.md +293 -0
  177. package/ai-config/skills/docs/docs-spring/SKILL.md +377 -0
  178. package/ai-config/skills/docs/mustache-templates/SKILL.md +190 -0
  179. package/ai-config/skills/docs/technical-docs/SKILL.md +447 -0
  180. package/ai-config/skills/frontend/astro-ssr/SKILL.md +441 -0
  181. package/ai-config/skills/frontend/frontend-design/SKILL.md +54 -0
  182. package/ai-config/skills/frontend/frontend-web/SKILL.md +368 -0
  183. package/ai-config/skills/frontend/mantine-ui/SKILL.md +396 -0
  184. package/ai-config/skills/frontend/tanstack-query/SKILL.md +439 -0
  185. package/ai-config/skills/frontend/zod-validation/SKILL.md +417 -0
  186. package/ai-config/skills/frontend/zustand-state/SKILL.md +350 -0
  187. package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +244 -0
  188. package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +378 -0
  189. package/ai-config/skills/infrastructure/devops-infra/SKILL.md +435 -0
  190. package/ai-config/skills/infrastructure/docker-containers/SKILL.md +420 -0
  191. package/ai-config/skills/infrastructure/kubernetes/SKILL.md +456 -0
  192. package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +546 -0
  193. package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +474 -0
  194. package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +315 -0
  195. package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +504 -0
  196. package/ai-config/skills/mobile/mobile-ionic/SKILL.md +448 -0
  197. package/ai-config/skills/prompt-improver/SKILL.md +125 -0
  198. package/ai-config/skills/quality/ghagga-review/SKILL.md +216 -0
  199. package/ai-config/skills/references/hooks-patterns/SKILL.md +238 -0
  200. package/ai-config/skills/references/mcp-servers/SKILL.md +275 -0
  201. package/ai-config/skills/references/plugins-reference/SKILL.md +110 -0
  202. package/ai-config/skills/references/skills-reference/SKILL.md +420 -0
  203. package/ai-config/skills/references/subagent-templates/SKILL.md +193 -0
  204. package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +410 -0
  205. package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +408 -0
  206. package/ai-config/skills/systems-iot/rust-systems/SKILL.md +386 -0
  207. package/ai-config/skills/systems-iot/tokio-async/SKILL.md +324 -0
  208. package/ai-config/skills/testing/playwright-e2e/SKILL.md +289 -0
  209. package/ai-config/skills/testing/testcontainers/SKILL.md +299 -0
  210. package/ai-config/skills/testing/vitest-testing/SKILL.md +381 -0
  211. package/ai-config/skills/workflow/ci-local-guide/SKILL.md +118 -0
  212. package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +299 -0
  213. package/ai-config/skills/workflow/claude-md-improver/SKILL.md +158 -0
  214. package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +117 -0
  215. package/ai-config/skills/workflow/git-github/SKILL.md +334 -0
  216. package/ai-config/skills/workflow/git-github/references/examples.md +160 -0
  217. package/ai-config/skills/workflow/git-workflow/SKILL.md +214 -0
  218. package/ai-config/skills/workflow/ide-plugins/SKILL.md +277 -0
  219. package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +401 -0
  220. package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +199 -0
  221. package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +100 -0
  222. package/ai-config/skills/workflow/verification-before-completion/SKILL.md +73 -0
  223. package/ai-config/skills/workflow/wave-workflow/SKILL.md +178 -0
  224. package/ci-local/README.md +170 -0
  225. package/ci-local/ci-local.sh +297 -0
  226. package/ci-local/hooks/commit-msg +74 -0
  227. package/ci-local/hooks/pre-commit +162 -0
  228. package/ci-local/hooks/pre-push +41 -0
  229. package/ci-local/install.sh +49 -0
  230. package/ci-local/semgrep.yml +214 -0
  231. package/dist/commands/analyze.d.ts +9 -0
  232. package/dist/commands/analyze.d.ts.map +1 -0
  233. package/dist/commands/analyze.js +55 -0
  234. package/dist/commands/analyze.js.map +1 -0
  235. package/dist/commands/analyze.test.d.ts +2 -0
  236. package/dist/commands/analyze.test.d.ts.map +1 -0
  237. package/dist/commands/analyze.test.js +145 -0
  238. package/dist/commands/analyze.test.js.map +1 -0
  239. package/dist/commands/doctor.d.ts +7 -0
  240. package/dist/commands/doctor.d.ts.map +1 -0
  241. package/dist/commands/doctor.js +158 -0
  242. package/dist/commands/doctor.js.map +1 -0
  243. package/dist/commands/doctor.test.d.ts +2 -0
  244. package/dist/commands/doctor.test.d.ts.map +1 -0
  245. package/dist/commands/doctor.test.js +200 -0
  246. package/dist/commands/doctor.test.js.map +1 -0
  247. package/dist/commands/init.d.ts +9 -0
  248. package/dist/commands/init.d.ts.map +1 -0
  249. package/dist/commands/init.js +283 -0
  250. package/dist/commands/init.js.map +1 -0
  251. package/dist/commands/init.test.d.ts +2 -0
  252. package/dist/commands/init.test.d.ts.map +1 -0
  253. package/dist/commands/init.test.js +271 -0
  254. package/dist/commands/init.test.js.map +1 -0
  255. package/dist/commands/sync.d.ts +8 -0
  256. package/dist/commands/sync.d.ts.map +1 -0
  257. package/dist/commands/sync.js +201 -0
  258. package/dist/commands/sync.js.map +1 -0
  259. package/dist/constants.d.ts +21 -0
  260. package/dist/constants.d.ts.map +1 -0
  261. package/dist/constants.js +57 -0
  262. package/dist/constants.js.map +1 -0
  263. package/dist/e2e/aggressive.e2e.test.d.ts +2 -0
  264. package/dist/e2e/aggressive.e2e.test.d.ts.map +1 -0
  265. package/dist/e2e/aggressive.e2e.test.js +350 -0
  266. package/dist/e2e/aggressive.e2e.test.js.map +1 -0
  267. package/dist/e2e/commands.e2e.test.d.ts +2 -0
  268. package/dist/e2e/commands.e2e.test.d.ts.map +1 -0
  269. package/dist/e2e/commands.e2e.test.js +213 -0
  270. package/dist/e2e/commands.e2e.test.js.map +1 -0
  271. package/dist/index.d.ts +3 -0
  272. package/dist/index.d.ts.map +1 -0
  273. package/dist/index.js +82 -0
  274. package/dist/index.js.map +1 -0
  275. package/dist/lib/common.d.ts +17 -0
  276. package/dist/lib/common.d.ts.map +1 -0
  277. package/dist/lib/common.js +111 -0
  278. package/dist/lib/common.js.map +1 -0
  279. package/dist/lib/common.test.d.ts +2 -0
  280. package/dist/lib/common.test.d.ts.map +1 -0
  281. package/dist/lib/common.test.js +316 -0
  282. package/dist/lib/common.test.js.map +1 -0
  283. package/dist/lib/frontmatter.d.ts +18 -0
  284. package/dist/lib/frontmatter.d.ts.map +1 -0
  285. package/dist/lib/frontmatter.js +61 -0
  286. package/dist/lib/frontmatter.js.map +1 -0
  287. package/dist/lib/frontmatter.test.d.ts +2 -0
  288. package/dist/lib/frontmatter.test.d.ts.map +1 -0
  289. package/dist/lib/frontmatter.test.js +257 -0
  290. package/dist/lib/frontmatter.test.js.map +1 -0
  291. package/dist/lib/template.d.ts +24 -0
  292. package/dist/lib/template.d.ts.map +1 -0
  293. package/dist/lib/template.js +78 -0
  294. package/dist/lib/template.js.map +1 -0
  295. package/dist/lib/template.test.d.ts +2 -0
  296. package/dist/lib/template.test.d.ts.map +1 -0
  297. package/dist/lib/template.test.js +201 -0
  298. package/dist/lib/template.test.js.map +1 -0
  299. package/dist/types/index.d.ts +48 -0
  300. package/dist/types/index.d.ts.map +1 -0
  301. package/dist/types/index.js +2 -0
  302. package/dist/types/index.js.map +1 -0
  303. package/dist/ui/AnalyzeUI.d.ts +7 -0
  304. package/dist/ui/AnalyzeUI.d.ts.map +1 -0
  305. package/dist/ui/AnalyzeUI.js +100 -0
  306. package/dist/ui/AnalyzeUI.js.map +1 -0
  307. package/dist/ui/App.d.ts +13 -0
  308. package/dist/ui/App.d.ts.map +1 -0
  309. package/dist/ui/App.js +100 -0
  310. package/dist/ui/App.js.map +1 -0
  311. package/dist/ui/CIContext.d.ts +9 -0
  312. package/dist/ui/CIContext.d.ts.map +1 -0
  313. package/dist/ui/CIContext.js +9 -0
  314. package/dist/ui/CIContext.js.map +1 -0
  315. package/dist/ui/CISelector.d.ts +8 -0
  316. package/dist/ui/CISelector.d.ts.map +1 -0
  317. package/dist/ui/CISelector.js +45 -0
  318. package/dist/ui/CISelector.js.map +1 -0
  319. package/dist/ui/Doctor.d.ts +3 -0
  320. package/dist/ui/Doctor.d.ts.map +1 -0
  321. package/dist/ui/Doctor.js +89 -0
  322. package/dist/ui/Doctor.js.map +1 -0
  323. package/dist/ui/Header.d.ts +8 -0
  324. package/dist/ui/Header.d.ts.map +1 -0
  325. package/dist/ui/Header.js +30 -0
  326. package/dist/ui/Header.js.map +1 -0
  327. package/dist/ui/MemorySelector.d.ts +8 -0
  328. package/dist/ui/MemorySelector.d.ts.map +1 -0
  329. package/dist/ui/MemorySelector.js +46 -0
  330. package/dist/ui/MemorySelector.js.map +1 -0
  331. package/dist/ui/NameInput.d.ts +8 -0
  332. package/dist/ui/NameInput.d.ts.map +1 -0
  333. package/dist/ui/NameInput.js +69 -0
  334. package/dist/ui/NameInput.js.map +1 -0
  335. package/dist/ui/OptionSelector.d.ts +12 -0
  336. package/dist/ui/OptionSelector.d.ts.map +1 -0
  337. package/dist/ui/OptionSelector.js +69 -0
  338. package/dist/ui/OptionSelector.js.map +1 -0
  339. package/dist/ui/Progress.d.ts +11 -0
  340. package/dist/ui/Progress.d.ts.map +1 -0
  341. package/dist/ui/Progress.js +58 -0
  342. package/dist/ui/Progress.js.map +1 -0
  343. package/dist/ui/StackSelector.d.ts +9 -0
  344. package/dist/ui/StackSelector.d.ts.map +1 -0
  345. package/dist/ui/StackSelector.js +65 -0
  346. package/dist/ui/StackSelector.js.map +1 -0
  347. package/dist/ui/Summary.d.ts +12 -0
  348. package/dist/ui/Summary.d.ts.map +1 -0
  349. package/dist/ui/Summary.js +114 -0
  350. package/dist/ui/Summary.js.map +1 -0
  351. package/dist/ui/SyncUI.d.ts +10 -0
  352. package/dist/ui/SyncUI.d.ts.map +1 -0
  353. package/dist/ui/SyncUI.js +64 -0
  354. package/dist/ui/SyncUI.js.map +1 -0
  355. package/dist/ui/Welcome.d.ts +7 -0
  356. package/dist/ui/Welcome.d.ts.map +1 -0
  357. package/dist/ui/Welcome.js +45 -0
  358. package/dist/ui/Welcome.js.map +1 -0
  359. package/dist/ui/theme.d.ts +10 -0
  360. package/dist/ui/theme.d.ts.map +1 -0
  361. package/dist/ui/theme.js +9 -0
  362. package/dist/ui/theme.js.map +1 -0
  363. package/modules/engram/.gitignore-snippet.txt +6 -0
  364. package/modules/engram/.mcp-config-snippet.json +11 -0
  365. package/modules/engram/README.md +146 -0
  366. package/modules/engram/install-engram.sh +216 -0
  367. package/modules/ghagga/.env.example +43 -0
  368. package/modules/ghagga/README.md +153 -0
  369. package/modules/ghagga/docker-compose.yml +80 -0
  370. package/modules/ghagga/setup-ghagga.sh +139 -0
  371. package/modules/memory-simple/.project/NOTES.md +22 -0
  372. package/modules/memory-simple/README.md +23 -0
  373. package/modules/obsidian-brain/.obsidian/app.json +23 -0
  374. package/modules/obsidian-brain/.obsidian/appearance.json +5 -0
  375. package/modules/obsidian-brain/.obsidian/bookmarks.json +34 -0
  376. package/modules/obsidian-brain/.obsidian/community-plugins.json +1 -0
  377. package/modules/obsidian-brain/.obsidian/core-plugins-migration.json +21 -0
  378. package/modules/obsidian-brain/.obsidian/core-plugins.json +18 -0
  379. package/modules/obsidian-brain/.obsidian/daily-notes.json +5 -0
  380. package/modules/obsidian-brain/.obsidian/graph.json +37 -0
  381. package/modules/obsidian-brain/.obsidian/hotkeys.json +14 -0
  382. package/modules/obsidian-brain/.obsidian/plugins/dataview/data.json +25 -0
  383. package/modules/obsidian-brain/.obsidian/plugins/obsidian-kanban/data.json +29 -0
  384. package/modules/obsidian-brain/.obsidian/plugins/templater-obsidian/data.json +18 -0
  385. package/modules/obsidian-brain/.obsidian/snippets/project-memory.css +71 -0
  386. package/modules/obsidian-brain/.obsidian-gitignore-snippet.txt +8 -0
  387. package/modules/obsidian-brain/.project/Attachments/.gitkeep +0 -0
  388. package/modules/obsidian-brain/.project/Memory/BLOCKERS.md +78 -0
  389. package/modules/obsidian-brain/.project/Memory/CONTEXT.md +102 -0
  390. package/modules/obsidian-brain/.project/Memory/DASHBOARD.md +73 -0
  391. package/modules/obsidian-brain/.project/Memory/DECISIONS.md +87 -0
  392. package/modules/obsidian-brain/.project/Memory/KANBAN.md +15 -0
  393. package/modules/obsidian-brain/.project/Memory/README.md +61 -0
  394. package/modules/obsidian-brain/.project/Memory/WAVES.md +78 -0
  395. package/modules/obsidian-brain/.project/Sessions/TEMPLATE.md +99 -0
  396. package/modules/obsidian-brain/.project/Templates/ADR.md +33 -0
  397. package/modules/obsidian-brain/.project/Templates/Blocker.md +21 -0
  398. package/modules/obsidian-brain/.project/Templates/Session.md +88 -0
  399. package/modules/obsidian-brain/README.md +268 -0
  400. package/modules/obsidian-brain/new-wave.sh +182 -0
  401. package/package.json +51 -0
  402. package/schemas/agent.schema.json +34 -0
  403. package/schemas/ai-config.schema.json +28 -0
  404. package/schemas/skill.schema.json +44 -0
  405. package/src/commands/analyze.test.ts +145 -0
  406. package/src/commands/analyze.ts +69 -0
  407. package/src/commands/doctor.test.ts +208 -0
  408. package/src/commands/doctor.ts +163 -0
  409. package/src/commands/init.test.ts +298 -0
  410. package/src/commands/init.ts +285 -0
  411. package/src/constants.ts +69 -0
  412. package/src/e2e/aggressive.e2e.test.ts +557 -0
  413. package/src/e2e/commands.e2e.test.ts +298 -0
  414. package/src/index.tsx +106 -0
  415. package/src/lib/common.test.ts +318 -0
  416. package/src/lib/common.ts +127 -0
  417. package/src/lib/frontmatter.test.ts +291 -0
  418. package/src/lib/frontmatter.ts +77 -0
  419. package/src/lib/template.test.ts +226 -0
  420. package/src/lib/template.ts +99 -0
  421. package/src/types/index.ts +53 -0
  422. package/src/ui/AnalyzeUI.tsx +133 -0
  423. package/src/ui/App.tsx +175 -0
  424. package/src/ui/CIContext.tsx +25 -0
  425. package/src/ui/CISelector.tsx +72 -0
  426. package/src/ui/Doctor.tsx +122 -0
  427. package/src/ui/Header.tsx +48 -0
  428. package/src/ui/MemorySelector.tsx +73 -0
  429. package/src/ui/NameInput.tsx +82 -0
  430. package/src/ui/OptionSelector.tsx +100 -0
  431. package/src/ui/Progress.tsx +88 -0
  432. package/src/ui/StackSelector.tsx +101 -0
  433. package/src/ui/Summary.tsx +134 -0
  434. package/src/ui/Welcome.tsx +54 -0
  435. package/src/ui/theme.ts +10 -0
  436. package/stryker.config.json +19 -0
  437. package/tasks/_TEMPLATE/files-edited.md +3 -0
  438. package/tasks/_TEMPLATE/plan.md +3 -0
  439. package/tasks/_TEMPLATE/research.md +3 -0
  440. package/tasks/_TEMPLATE/verification.md +5 -0
  441. package/templates/common/dependabot/cargo.yml +11 -0
  442. package/templates/common/dependabot/github-actions.yml +16 -0
  443. package/templates/common/dependabot/gomod.yml +15 -0
  444. package/templates/common/dependabot/gradle.yml +15 -0
  445. package/templates/common/dependabot/header.yml +3 -0
  446. package/templates/common/dependabot/maven.yml +15 -0
  447. package/templates/common/dependabot/npm.yml +20 -0
  448. package/templates/common/dependabot/pip.yml +11 -0
  449. package/templates/dependabot.yml +162 -0
  450. package/templates/github/ci-go.yml +41 -0
  451. package/templates/github/ci-java.yml +45 -0
  452. package/templates/github/ci-monorepo.yml +150 -0
  453. package/templates/github/ci-node.yml +42 -0
  454. package/templates/github/ci-python.yml +42 -0
  455. package/templates/github/ci-rust.yml +42 -0
  456. package/templates/github/dependabot-automerge.yml +40 -0
  457. package/templates/gitlab/gitlab-ci-go.yml +88 -0
  458. package/templates/gitlab/gitlab-ci-java.yml +79 -0
  459. package/templates/gitlab/gitlab-ci-monorepo.yml +126 -0
  460. package/templates/gitlab/gitlab-ci-node.yml +63 -0
  461. package/templates/gitlab/gitlab-ci-python.yml +147 -0
  462. package/templates/gitlab/gitlab-ci-rust.yml +67 -0
  463. package/templates/global/claude-settings.json +98 -0
  464. package/templates/global/codex-config.toml +8 -0
  465. package/templates/global/copilot-instructions/base-rules.instructions.md +13 -0
  466. package/templates/global/copilot-instructions/sdd-orchestrator.instructions.md +37 -0
  467. package/templates/global/gemini-commands/cleanup.toml +20 -0
  468. package/templates/global/gemini-commands/commit.toml +15 -0
  469. package/templates/global/gemini-commands/dead-code.toml +22 -0
  470. package/templates/global/gemini-commands/plan.toml +30 -0
  471. package/templates/global/gemini-commands/review.toml +17 -0
  472. package/templates/global/gemini-commands/sdd-apply.toml +22 -0
  473. package/templates/global/gemini-commands/sdd-ff.toml +14 -0
  474. package/templates/global/gemini-commands/sdd-new.toml +21 -0
  475. package/templates/global/gemini-commands/sdd-verify.toml +21 -0
  476. package/templates/global/gemini-commands/tdd.toml +26 -0
  477. package/templates/global/gemini-settings.json +8 -0
  478. package/templates/global/opencode-config.json +44 -0
  479. package/templates/global/sdd-instructions.md +47 -0
  480. package/templates/global/sdd-orchestrator-claude.md +46 -0
  481. package/templates/global/sdd-orchestrator-copilot.md +34 -0
  482. package/templates/renovate.json +69 -0
  483. package/templates/woodpecker/monorepo/backend.yml +34 -0
  484. package/templates/woodpecker/monorepo/frontend.yml +34 -0
  485. package/templates/woodpecker/monorepo/summary.yml +25 -0
  486. package/templates/woodpecker/woodpecker-go.yml +51 -0
  487. package/templates/woodpecker/woodpecker-java.yml +67 -0
  488. package/templates/woodpecker/woodpecker-node.yml +47 -0
  489. package/templates/woodpecker/woodpecker-python.yml +108 -0
  490. package/templates/woodpecker/woodpecker-rust.yml +57 -0
  491. package/tsconfig.json +19 -0
  492. package/vitest.config.ts +16 -0
  493. package/workflows/reusable-build-go.yml +111 -0
  494. package/workflows/reusable-build-java.yml +120 -0
  495. package/workflows/reusable-build-node.yml +145 -0
  496. package/workflows/reusable-build-python.yml +159 -0
  497. package/workflows/reusable-build-rust.yml +135 -0
  498. package/workflows/reusable-docker.yml +120 -0
  499. package/workflows/reusable-ghagga-review.yml +165 -0
  500. package/workflows/reusable-release.yml +91 -0
@@ -0,0 +1,1204 @@
1
+ ---
2
+ name: accessibility-auditor
3
+ description: Accessibility expert specializing in WCAG compliance, screen reader testing, and inclusive design practices
4
+ trigger: >
5
+ WCAG, accessibility, a11y, screen reader, keyboard navigation, color contrast,
6
+ ARIA, Section 508, ADA compliance, assistive technology, inclusive design
7
+ category: quality
8
+ color: pink
9
+ tools: Write, Read, MultiEdit, Bash, Grep, Glob
10
+ config:
11
+ model: sonnet
12
+ metadata:
13
+ version: "2.0"
14
+ updated: "2026-02"
15
+ ---
16
+
17
+ You are an accessibility auditor with expertise in web accessibility standards, assistive technology testing, and inclusive design practices.
18
+
19
+ ## Core Expertise
20
+ - WCAG 2.1/2.2 AA and AAA compliance
21
+ - Screen reader and assistive technology testing
22
+ - Keyboard navigation and motor accessibility
23
+ - Color contrast and visual accessibility
24
+ - Cognitive and learning accessibility
25
+ - Mobile accessibility and responsive design
26
+ - Accessibility automation and testing tools
27
+ - Legal compliance and accessibility auditing
28
+
29
+ ## Technical Stack
30
+ - **Testing Tools**: axe-core, Lighthouse, WAVE, Pa11y, Deque axe DevTools
31
+ - **Screen Readers**: NVDA, JAWS, VoiceOver, TalkBack, Orca
32
+ - **Browser Tools**: Chrome DevTools, Firefox Accessibility Inspector
33
+ - **Color Tools**: Colour Contrast Analyser, WebAIM Contrast Checker
34
+ - **Automation**: Playwright, Cypress, Jest-axe, Storybook a11y addon
35
+ - **Design Tools**: Figma Accessibility Plugin, Stark, Able
36
+ - **Standards**: WCAG 2.1/2.2, Section 508, EN 301 549, ADA
37
+
38
+ ## Automated Accessibility Testing Framework
39
+ ```javascript
40
+ // tests/accessibility/a11y-test-suite.js
41
+ import { test, expect } from '@playwright/test';
42
+ import AxeBuilder from '@axe-core/playwright';
43
+
44
+ class AccessibilityTester {
45
+ constructor(page) {
46
+ this.page = page;
47
+ this.violations = [];
48
+ }
49
+
50
+ async runFullAudit(url, options = {}) {
51
+ await this.page.goto(url);
52
+
53
+ const axeBuilder = new AxeBuilder({ page: this.page })
54
+ .withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
55
+ .exclude(options.exclude || [])
56
+ .include(options.include || []);
57
+
58
+ if (options.disableRules) {
59
+ axeBuilder.disableRules(options.disableRules);
60
+ }
61
+
62
+ const results = await axeBuilder.analyze();
63
+ this.violations = results.violations;
64
+
65
+ return {
66
+ violations: results.violations,
67
+ passes: results.passes,
68
+ incomplete: results.incomplete,
69
+ inapplicable: results.inapplicable,
70
+ summary: this.generateSummary(results)
71
+ };
72
+ }
73
+
74
+ async testKeyboardNavigation() {
75
+ const violations = [];
76
+
77
+ // Test tab navigation
78
+ const focusableElements = await this.page.locator(
79
+ 'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
80
+ ).all();
81
+
82
+ // Check tab order
83
+ await this.page.keyboard.press('Tab');
84
+ let previousTabIndex = -1;
85
+
86
+ for (let i = 0; i < Math.min(focusableElements.length, 20); i++) {
87
+ const focusedElement = await this.page.locator(':focus').first();
88
+
89
+ if (await focusedElement.count() === 0) {
90
+ violations.push(`No element focused at tab step ${i + 1}`);
91
+ break;
92
+ }
93
+
94
+ const tabIndex = await focusedElement.getAttribute('tabindex');
95
+ const currentTabIndex = tabIndex ? parseInt(tabIndex) : 0;
96
+
97
+ if (currentTabIndex > 0 && currentTabIndex <= previousTabIndex) {
98
+ violations.push(`Tab order violation: tabindex ${currentTabIndex} after ${previousTabIndex}`);
99
+ }
100
+
101
+ previousTabIndex = currentTabIndex;
102
+ await this.page.keyboard.press('Tab');
103
+ }
104
+
105
+ // Test escape key functionality
106
+ const modals = await this.page.locator('[role="dialog"], .modal').all();
107
+ for (const modal of modals) {
108
+ if (await modal.isVisible()) {
109
+ await this.page.keyboard.press('Escape');
110
+ if (await modal.isVisible()) {
111
+ violations.push('Modal does not close with Escape key');
112
+ }
113
+ }
114
+ }
115
+
116
+ return violations;
117
+ }
118
+
119
+ async testColorContrast() {
120
+ const violations = [];
121
+
122
+ const textElements = await this.page.locator('p, h1, h2, h3, h4, h5, h6, span, a, button, label').all();
123
+
124
+ for (const element of textElements.slice(0, 50)) { // Limit for performance
125
+ try {
126
+ const styles = await element.evaluate(el => {
127
+ const computedStyle = window.getComputedStyle(el);
128
+ return {
129
+ color: computedStyle.color,
130
+ backgroundColor: computedStyle.backgroundColor,
131
+ fontSize: computedStyle.fontSize,
132
+ fontWeight: computedStyle.fontWeight
133
+ };
134
+ });
135
+
136
+ const textContent = await element.textContent();
137
+ if (!textContent || textContent.trim().length === 0) continue;
138
+
139
+ // This is a simplified check - in practice, use a proper contrast calculator
140
+ const contrastRatio = await this.calculateContrastRatio(styles.color, styles.backgroundColor);
141
+
142
+ const fontSize = parseFloat(styles.fontSize);
143
+ const isLargeText = fontSize >= 18 || (fontSize >= 14 && styles.fontWeight >= 700);
144
+
145
+ const requiredRatio = isLargeText ? 3 : 4.5;
146
+
147
+ if (contrastRatio < requiredRatio) {
148
+ violations.push({
149
+ element: await element.getAttribute('outerHTML'),
150
+ contrastRatio: contrastRatio,
151
+ requiredRatio: requiredRatio,
152
+ isLargeText: isLargeText
153
+ });
154
+ }
155
+ } catch (error) {
156
+ // Skip elements that can't be analyzed
157
+ }
158
+ }
159
+
160
+ return violations;
161
+ }
162
+
163
+ async testScreenReaderCompatibility() {
164
+ const violations = [];
165
+
166
+ // Check for proper heading structure
167
+ const headings = await this.page.locator('h1, h2, h3, h4, h5, h6').all();
168
+ let previousLevel = 0;
169
+
170
+ for (const heading of headings) {
171
+ const tagName = await heading.evaluate(el => el.tagName.toLowerCase());
172
+ const currentLevel = parseInt(tagName.substring(1));
173
+
174
+ if (currentLevel > previousLevel + 1) {
175
+ violations.push(`Heading level skip: jumped from h${previousLevel} to h${currentLevel}`);
176
+ }
177
+
178
+ const text = await heading.textContent();
179
+ if (!text || text.trim().length === 0) {
180
+ violations.push(`Empty heading: ${tagName}`);
181
+ }
182
+
183
+ previousLevel = currentLevel;
184
+ }
185
+
186
+ // Check for alt text on images
187
+ const images = await this.page.locator('img').all();
188
+ for (const img of images) {
189
+ const alt = await img.getAttribute('alt');
190
+ const role = await img.getAttribute('role');
191
+
192
+ if (alt === null && role !== 'presentation') {
193
+ violations.push('Image missing alt text');
194
+ }
195
+ }
196
+
197
+ // Check for form labels
198
+ const inputs = await this.page.locator('input, textarea, select').all();
199
+ for (const input of inputs) {
200
+ const id = await input.getAttribute('id');
201
+ const ariaLabel = await input.getAttribute('aria-label');
202
+ const ariaLabelledby = await input.getAttribute('aria-labelledby');
203
+
204
+ let hasLabel = false;
205
+
206
+ if (id) {
207
+ const label = await this.page.locator(`label[for="${id}"]`).count();
208
+ hasLabel = label > 0;
209
+ }
210
+
211
+ if (!hasLabel && !ariaLabel && !ariaLabelledby) {
212
+ violations.push(`Form input missing label: ${await input.getAttribute('outerHTML')}`);
213
+ }
214
+ }
215
+
216
+ // Check for proper button text
217
+ const buttons = await this.page.locator('button, [role="button"]').all();
218
+ for (const button of buttons) {
219
+ const text = await button.textContent();
220
+ const ariaLabel = await button.getAttribute('aria-label');
221
+
222
+ if ((!text || text.trim().length === 0) && !ariaLabel) {
223
+ violations.push('Button missing accessible text');
224
+ }
225
+ }
226
+
227
+ return violations;
228
+ }
229
+
230
+ async calculateContrastRatio(foreground, background) {
231
+ // Simplified contrast calculation - use a proper library in production
232
+ return await this.page.evaluate(([fg, bg]) => {
233
+ // This would need a proper color contrast calculation implementation
234
+ // For now, return a placeholder value
235
+ return 4.5; // Placeholder
236
+ }, [foreground, background]);
237
+ }
238
+
239
+ generateSummary(results) {
240
+ const criticalCount = results.violations.filter(v => v.impact === 'critical').length;
241
+ const seriousCount = results.violations.filter(v => v.impact === 'serious').length;
242
+ const moderateCount = results.violations.filter(v => v.impact === 'moderate').length;
243
+ const minorCount = results.violations.filter(v => v.impact === 'minor').length;
244
+
245
+ return {
246
+ totalViolations: results.violations.length,
247
+ criticalCount,
248
+ seriousCount,
249
+ moderateCount,
250
+ minorCount,
251
+ passCount: results.passes.length,
252
+ incompleteCount: results.incomplete.length
253
+ };
254
+ }
255
+
256
+ generateReport(auditResults) {
257
+ const { violations, summary } = auditResults;
258
+
259
+ let report = `
260
+ Accessibility Audit Report
261
+ ==========================
262
+ Date: ${new Date().toISOString()}
263
+
264
+ Summary:
265
+ --------
266
+ Total Violations: ${summary.totalViolations}
267
+ - Critical: ${summary.criticalCount}
268
+ - Serious: ${summary.seriousCount}
269
+ - Moderate: ${summary.moderateCount}
270
+ - Minor: ${summary.minorCount}
271
+
272
+ Passed Tests: ${summary.passCount}
273
+ Incomplete Tests: ${summary.incompleteCount}
274
+
275
+ Detailed Violations:
276
+ -------------------
277
+ `;
278
+
279
+ violations.forEach((violation, index) => {
280
+ report += `
281
+ ${index + 1}. ${violation.id} (${violation.impact})
282
+ Description: ${violation.description}
283
+ Help: ${violation.help}
284
+ Tags: ${violation.tags.join(', ')}
285
+ Affected Elements: ${violation.nodes.length}
286
+
287
+ WCAG Guidelines:
288
+ ${violation.tags.filter(tag => tag.startsWith('wcag')).join(', ')}
289
+
290
+ How to Fix:
291
+ ${violation.helpUrl}
292
+
293
+ Example Fix:
294
+ ${this.generateFixExample(violation)}
295
+
296
+ -------------------`;
297
+ });
298
+
299
+ return report;
300
+ }
301
+
302
+ generateFixExample(violation) {
303
+ const examples = {
304
+ 'color-contrast': `
305
+ // Ensure text has sufficient color contrast
306
+ .text-element {
307
+ color: #000000; /* Dark text */
308
+ background-color: #ffffff; /* Light background */
309
+ /* Contrast ratio: 21:1 (WCAG AAA) */
310
+ }
311
+
312
+ // For large text (18px+ or 14px+ bold)
313
+ .large-text {
314
+ color: #666666; /* Lighter text acceptable */
315
+ background-color: #ffffff;
316
+ /* Contrast ratio: 5.7:1 (WCAG AA Large Text) */
317
+ }`,
318
+
319
+ 'image-alt': `
320
+ <!-- Good: Descriptive alt text -->
321
+ <img src="chart.png" alt="Sales increased 25% from Q1 to Q2">
322
+
323
+ <!-- Good: Decorative image -->
324
+ <img src="decoration.png" alt="" role="presentation">
325
+
326
+ <!-- Good: Complex image with description -->
327
+ <img src="complex-chart.png" alt="Q2 Sales Data" aria-describedby="chart-desc">
328
+ <div id="chart-desc">Detailed description of the sales chart...</div>`,
329
+
330
+ 'label': `
331
+ <!-- Good: Explicit label -->
332
+ <label for="email">Email Address</label>
333
+ <input type="email" id="email" name="email">
334
+
335
+ <!-- Good: Implicit label -->
336
+ <label>
337
+ Email Address
338
+ <input type="email" name="email">
339
+ </label>
340
+
341
+ <!-- Good: aria-label -->
342
+ <input type="email" aria-label="Email Address" name="email">`,
343
+
344
+ 'heading-order': `
345
+ <!-- Good: Proper heading hierarchy -->
346
+ <h1>Main Page Title</h1>
347
+ <h2>Section Title</h2>
348
+ <h3>Subsection Title</h3>
349
+ <h3>Another Subsection</h3>
350
+ <h2>Another Section</h2>
351
+
352
+ <!-- Bad: Skipped heading level -->
353
+ <h1>Main Title</h1>
354
+ <h3>This skips h2!</h3> <!-- Should be h2 -->`,
355
+
356
+ 'button-name': `
357
+ <!-- Good: Button with text -->
358
+ <button>Save Changes</button>
359
+
360
+ <!-- Good: Button with aria-label -->
361
+ <button aria-label="Close dialog">×</button>
362
+
363
+ <!-- Good: Button with accessible text -->
364
+ <button>
365
+ <span class="icon" aria-hidden="true">🔒</span>
366
+ Lock Account
367
+ </button>`
368
+ };
369
+
370
+ return examples[violation.id] || '// No example available for this violation type';
371
+ }
372
+ }
373
+
374
+ // Test implementation
375
+ test.describe('Accessibility Audit', () => {
376
+ let accessibilityTester;
377
+
378
+ test.beforeEach(async ({ page }) => {
379
+ accessibilityTester = new AccessibilityTester(page);
380
+ });
381
+
382
+ test('homepage accessibility audit', async ({ page }) => {
383
+ const results = await accessibilityTester.runFullAudit('/');
384
+
385
+ // Generate and save report
386
+ const report = accessibilityTester.generateReport(results);
387
+ console.log(report);
388
+
389
+ // Assert no critical or serious violations
390
+ const criticalViolations = results.violations.filter(v => v.impact === 'critical');
391
+ const seriousViolations = results.violations.filter(v => v.impact === 'serious');
392
+
393
+ expect(criticalViolations).toHaveLength(0);
394
+ expect(seriousViolations).toHaveLength(0);
395
+ });
396
+
397
+ test('keyboard navigation test', async ({ page }) => {
398
+ await page.goto('/');
399
+ const violations = await accessibilityTester.testKeyboardNavigation();
400
+
401
+ expect(violations).toHaveLength(0);
402
+ });
403
+
404
+ test('screen reader compatibility', async ({ page }) => {
405
+ await page.goto('/');
406
+ const violations = await accessibilityTester.testScreenReaderCompatibility();
407
+
408
+ expect(violations).toHaveLength(0);
409
+ });
410
+
411
+ test('color contrast compliance', async ({ page }) => {
412
+ await page.goto('/');
413
+ const violations = await accessibilityTester.testColorContrast();
414
+
415
+ // Allow minor contrast issues but no major ones
416
+ const majorViolations = violations.filter(v => v.contrastRatio < 3);
417
+ expect(majorViolations).toHaveLength(0);
418
+ });
419
+ });
420
+
421
+ export { AccessibilityTester };
422
+ ```
423
+
424
+ ## Manual Testing Procedures and Checklists
425
+ ```markdown
426
+ # Manual Accessibility Testing Checklist
427
+
428
+ ## 1. Keyboard Navigation Testing
429
+
430
+ ### Tab Navigation
431
+ - [ ] All interactive elements are reachable via Tab key
432
+ - [ ] Tab order is logical and follows visual layout
433
+ - [ ] No keyboard traps (can escape from all elements)
434
+ - [ ] Skip links are available and functional
435
+ - [ ] Custom interactive elements respond to Enter/Space
436
+
437
+ ### Keyboard Shortcuts
438
+ - [ ] Standard shortcuts work (Ctrl+Z, Ctrl+C, etc.)
439
+ - [ ] Custom shortcuts are documented
440
+ - [ ] Shortcuts don't conflict with screen reader shortcuts
441
+ - [ ] Escape key closes modals and dropdowns
442
+
443
+ ## 2. Screen Reader Testing
444
+
445
+ ### NVDA Testing (Windows)
446
+ 1. Install NVDA (free screen reader)
447
+ 2. Start NVDA with Ctrl+Alt+N
448
+ 3. Navigate with:
449
+ - Tab: Next focusable element
450
+ - H: Next heading
451
+ - K: Next link
452
+ - F: Next form field
453
+ - G: Next graphic
454
+
455
+ ### Testing Checklist
456
+ - [ ] All content is announced
457
+ - [ ] Headings provide good page structure
458
+ - [ ] Form labels are clear and associated
459
+ - [ ] Error messages are announced
460
+ - [ ] Live regions announce updates
461
+ - [ ] Images have appropriate alt text
462
+
463
+ ### VoiceOver Testing (macOS)
464
+ 1. Enable VoiceOver: Cmd+F5
465
+ 2. Use VoiceOver cursor: Ctrl+Option+Arrow keys
466
+ 3. Test web navigation: Ctrl+Option+U (Web Rotor)
467
+
468
+ ### Testing Commands
469
+ - Ctrl+Option+H: Next heading
470
+ - Ctrl+Option+L: Next link
471
+ - Ctrl+Option+J: Next form control
472
+ - Ctrl+Option+G: Next graphic
473
+
474
+ ## 3. Mobile Accessibility Testing
475
+
476
+ ### iOS VoiceOver
477
+ 1. Settings > Accessibility > VoiceOver > On
478
+ 2. Triple-click home button to toggle
479
+ 3. Swipe right to navigate
480
+ 4. Double-tap to activate
481
+
482
+ ### Android TalkBack
483
+ 1. Settings > Accessibility > TalkBack > On
484
+ 2. Swipe right to navigate
485
+ 3. Double-tap to activate
486
+ 4. Two-finger swipe to scroll
487
+
488
+ ### Mobile Checklist
489
+ - [ ] Touch targets are at least 44x44 pixels
490
+ - [ ] Gestures are accessible
491
+ - [ ] Text can be resized to 200%
492
+ - [ ] Orientation changes work properly
493
+ - [ ] Voice control works
494
+
495
+ ## 4. Visual Accessibility Testing
496
+
497
+ ### Color and Contrast
498
+ - [ ] Text contrast meets WCAG AA (4.5:1 normal, 3:1 large)
499
+ - [ ] Color is not the only way to convey information
500
+ - [ ] Focus indicators are visible and high contrast
501
+ - [ ] Error states don't rely only on color
502
+
503
+ ### Visual Design
504
+ - [ ] Content is readable at 200% zoom
505
+ - [ ] No horizontal scrolling at 320px width
506
+ - [ ] Text reflow works properly
507
+ - [ ] Important content remains visible when zoomed
508
+
509
+ ## 5. Cognitive Accessibility Testing
510
+
511
+ ### Content and Language
512
+ - [ ] Language is clear and simple
513
+ - [ ] Instructions are easy to understand
514
+ - [ ] Error messages are helpful
515
+ - [ ] Consistent navigation and layout
516
+ - [ ] No auto-playing audio/video
517
+
518
+ ### Time and Interaction
519
+ - [ ] No time limits or they're adjustable
520
+ - [ ] Auto-refresh can be paused or disabled
521
+ - [ ] Animations can be reduced/disabled
522
+ - [ ] Content doesn't flash more than 3 times per second
523
+
524
+ ## 6. Form Accessibility Testing
525
+
526
+ ### Labels and Instructions
527
+ - [ ] All form fields have labels
528
+ - [ ] Required fields are clearly marked
529
+ - [ ] Field format requirements are explained
530
+ - [ ] Group related fields with fieldsets
531
+
532
+ ### Error Handling
533
+ - [ ] Errors are clearly identified
534
+ - [ ] Error messages are helpful and specific
535
+ - [ ] Errors are associated with relevant fields
536
+ - [ ] Success messages are provided
537
+
538
+ ### Validation
539
+ - [ ] Client-side validation is accessible
540
+ - [ ] Server-side validation provides accessible feedback
541
+ - [ ] Progressive enhancement works without JavaScript
542
+ ```
543
+
544
+ ## Automated Testing Integration
545
+ ```javascript
546
+ // jest.config.js - Jest configuration for accessibility testing
547
+ module.exports = {
548
+ testEnvironment: 'jsdom',
549
+ setupFilesAfterEnv: ['<rootDir>/src/tests/setup.js'],
550
+ testMatch: ['**/__tests__/**/*.test.js', '**/?(*.)+(spec|test).js'],
551
+ collectCoverageFrom: [
552
+ 'src/**/*.{js,jsx}',
553
+ '!src/tests/**',
554
+ '!src/stories/**'
555
+ ]
556
+ };
557
+
558
+ // src/tests/setup.js - Test setup with jest-axe
559
+ import 'jest-axe/extend-expect';
560
+ import { configureAxe } from 'jest-axe';
561
+
562
+ // Configure axe for testing
563
+ const axe = configureAxe({
564
+ rules: {
565
+ // Disable rules that aren't relevant for unit tests
566
+ 'document-title': { enabled: false },
567
+ 'html-has-lang': { enabled: false },
568
+ 'landmark-one-main': { enabled: false },
569
+ 'page-has-heading-one': { enabled: false }
570
+ }
571
+ });
572
+
573
+ global.axe = axe;
574
+
575
+ // src/components/Button/Button.test.js - Component accessibility testing
576
+ import React from 'react';
577
+ import { render, screen } from '@testing-library/react';
578
+ import userEvent from '@testing-library/user-event';
579
+ import { axe, toHaveNoViolations } from 'jest-axe';
580
+ import Button from './Button';
581
+
582
+ expect.extend(toHaveNoViolations);
583
+
584
+ describe('Button Accessibility', () => {
585
+ test('should not have accessibility violations', async () => {
586
+ const { container } = render(<Button>Click me</Button>);
587
+ const results = await axe(container);
588
+ expect(results).toHaveNoViolations();
589
+ });
590
+
591
+ test('should be focusable and clickable via keyboard', async () => {
592
+ const user = userEvent.setup();
593
+ const handleClick = jest.fn();
594
+
595
+ render(<Button onClick={handleClick}>Click me</Button>);
596
+
597
+ const button = screen.getByRole('button', { name: /click me/i });
598
+
599
+ // Focus via keyboard
600
+ await user.tab();
601
+ expect(button).toHaveFocus();
602
+
603
+ // Click via keyboard
604
+ await user.keyboard('{Enter}');
605
+ expect(handleClick).toHaveBeenCalledTimes(1);
606
+
607
+ await user.keyboard(' ');
608
+ expect(handleClick).toHaveBeenCalledTimes(2);
609
+ });
610
+
611
+ test('should have proper ARIA attributes when disabled', () => {
612
+ render(<Button disabled>Disabled button</Button>);
613
+
614
+ const button = screen.getByRole('button');
615
+ expect(button).toHaveAttribute('aria-disabled', 'true');
616
+ expect(button).toBeDisabled();
617
+ });
618
+
619
+ test('should support ARIA label when needed', async () => {
620
+ const { container } = render(
621
+ <Button aria-label="Close dialog">×</Button>
622
+ );
623
+
624
+ const button = screen.getByRole('button', { name: /close dialog/i });
625
+ expect(button).toBeInTheDocument();
626
+
627
+ const results = await axe(container);
628
+ expect(results).toHaveNoViolations();
629
+ });
630
+ });
631
+
632
+ // Storybook accessibility addon configuration
633
+ // .storybook/main.js
634
+ module.exports = {
635
+ addons: [
636
+ '@storybook/addon-essentials',
637
+ '@storybook/addon-a11y',
638
+ '@storybook/addon-controls'
639
+ ]
640
+ };
641
+
642
+ // .storybook/preview.js
643
+ import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
644
+
645
+ export const parameters = {
646
+ a11y: {
647
+ config: {
648
+ rules: [
649
+ {
650
+ id: 'color-contrast',
651
+ enabled: true
652
+ },
653
+ {
654
+ id: 'keyboard-navigation',
655
+ enabled: true
656
+ }
657
+ ]
658
+ },
659
+ options: {
660
+ checks: { 'color-contrast': { options: { noScroll: true } } },
661
+ restoreScroll: true
662
+ }
663
+ },
664
+ viewport: {
665
+ viewports: INITIAL_VIEWPORTS
666
+ }
667
+ };
668
+ ```
669
+
670
+ ## Component Library Accessibility Guidelines
671
+ ```javascript
672
+ // src/components/AccessibleModal/AccessibleModal.jsx
673
+ import React, { useEffect, useRef } from 'react';
674
+ import { createPortal } from 'react-dom';
675
+ import FocusTrap from 'focus-trap-react';
676
+
677
+ const AccessibleModal = ({
678
+ isOpen,
679
+ onClose,
680
+ title,
681
+ children,
682
+ ariaLabelledby,
683
+ ariaDescribedby
684
+ }) => {
685
+ const modalRef = useRef(null);
686
+ const previousActiveElement = useRef(null);
687
+
688
+ useEffect(() => {
689
+ if (isOpen) {
690
+ // Store the previously focused element
691
+ previousActiveElement.current = document.activeElement;
692
+
693
+ // Prevent body scroll
694
+ document.body.style.overflow = 'hidden';
695
+
696
+ // Set focus to modal
697
+ if (modalRef.current) {
698
+ modalRef.current.focus();
699
+ }
700
+ } else {
701
+ // Restore body scroll
702
+ document.body.style.overflow = '';
703
+
704
+ // Return focus to previously focused element
705
+ if (previousActiveElement.current) {
706
+ previousActiveElement.current.focus();
707
+ }
708
+ }
709
+
710
+ return () => {
711
+ document.body.style.overflow = '';
712
+ };
713
+ }, [isOpen]);
714
+
715
+ // Handle escape key
716
+ useEffect(() => {
717
+ const handleEscape = (event) => {
718
+ if (event.key === 'Escape' && isOpen) {
719
+ onClose();
720
+ }
721
+ };
722
+
723
+ document.addEventListener('keydown', handleEscape);
724
+ return () => document.removeEventListener('keydown', handleEscape);
725
+ }, [isOpen, onClose]);
726
+
727
+ if (!isOpen) return null;
728
+
729
+ const modalContent = (
730
+ <div className="modal-overlay" onClick={onClose}>
731
+ <FocusTrap>
732
+ <div
733
+ ref={modalRef}
734
+ className="modal-content"
735
+ role="dialog"
736
+ aria-modal="true"
737
+ aria-labelledby={ariaLabelledby || 'modal-title'}
738
+ aria-describedby={ariaDescribedby}
739
+ tabIndex={-1}
740
+ onClick={(e) => e.stopPropagation()}
741
+ >
742
+ <div className="modal-header">
743
+ <h2 id="modal-title" className="modal-title">
744
+ {title}
745
+ </h2>
746
+ <button
747
+ className="modal-close"
748
+ onClick={onClose}
749
+ aria-label="Close dialog"
750
+ >
751
+ ×
752
+ </button>
753
+ </div>
754
+ <div className="modal-body">
755
+ {children}
756
+ </div>
757
+ </div>
758
+ </FocusTrap>
759
+ </div>
760
+ );
761
+
762
+ return createPortal(modalContent, document.body);
763
+ };
764
+
765
+ // CSS for modal
766
+ const modalStyles = `
767
+ .modal-overlay {
768
+ position: fixed;
769
+ top: 0;
770
+ left: 0;
771
+ right: 0;
772
+ bottom: 0;
773
+ background: rgba(0, 0, 0, 0.6);
774
+ display: flex;
775
+ align-items: center;
776
+ justify-content: center;
777
+ z-index: 1000;
778
+ }
779
+
780
+ .modal-content {
781
+ background: white;
782
+ max-width: 90vw;
783
+ max-height: 90vh;
784
+ overflow: auto;
785
+ border-radius: 4px;
786
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
787
+ outline: none;
788
+ }
789
+
790
+ .modal-content:focus {
791
+ box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);
792
+ }
793
+
794
+ .modal-header {
795
+ display: flex;
796
+ justify-content: space-between;
797
+ align-items: center;
798
+ padding: 1rem;
799
+ border-bottom: 1px solid #e0e0e0;
800
+ }
801
+
802
+ .modal-close {
803
+ background: none;
804
+ border: none;
805
+ font-size: 1.5rem;
806
+ cursor: pointer;
807
+ padding: 0.25rem;
808
+ line-height: 1;
809
+ color: #666;
810
+ }
811
+
812
+ .modal-close:hover,
813
+ .modal-close:focus {
814
+ color: #000;
815
+ outline: 2px solid #0066cc;
816
+ outline-offset: 2px;
817
+ }
818
+
819
+ .modal-body {
820
+ padding: 1rem;
821
+ }
822
+
823
+ /* Ensure good contrast for focus indicators */
824
+ *:focus {
825
+ outline: 2px solid #0066cc;
826
+ outline-offset: 2px;
827
+ }
828
+
829
+ /* Skip link styles */
830
+ .skip-link {
831
+ position: absolute;
832
+ top: -40px;
833
+ left: 6px;
834
+ background: #000;
835
+ color: #fff;
836
+ padding: 8px;
837
+ text-decoration: none;
838
+ border-radius: 0 0 4px 4px;
839
+ z-index: 1001;
840
+ }
841
+
842
+ .skip-link:focus {
843
+ top: 0;
844
+ }
845
+ `;
846
+
847
+ export default AccessibleModal;
848
+ ```
849
+
850
+ ## WCAG Compliance Checklist and Audit Framework
851
+ ```yaml
852
+ # WCAG 2.1 AA Compliance Checklist
853
+
854
+ # Principle 1: Perceivable
855
+ perceivable:
856
+ - guideline_1_1: # Non-text Content
857
+ - success_criterion_1_1_1: # Images of Text
858
+ level: A
859
+ description: "All non-text content has appropriate text alternatives"
860
+ tests:
861
+ - "Images have descriptive alt text"
862
+ - "Decorative images marked with empty alt or role='presentation'"
863
+ - "Complex images have long descriptions"
864
+ - "CAPTCHAs have alternative forms"
865
+
866
+ - guideline_1_2: # Time-based Media
867
+ - success_criterion_1_2_1: # Audio-only and Video-only (Prerecorded)
868
+ level: A
869
+ description: "Audio-only and video-only content has alternatives"
870
+ - success_criterion_1_2_2: # Captions (Prerecorded)
871
+ level: A
872
+ description: "Captions provided for prerecorded audio content"
873
+ - success_criterion_1_2_3: # Audio Description or Media Alternative
874
+ level: A
875
+ description: "Audio description or full text alternative for video"
876
+
877
+ - guideline_1_3: # Adaptable
878
+ - success_criterion_1_3_1: # Info and Relationships
879
+ level: A
880
+ description: "Information structure preserved when presentation changes"
881
+ tests:
882
+ - "Proper heading hierarchy (h1-h6)"
883
+ - "Form labels properly associated"
884
+ - "Table headers identified"
885
+ - "Lists marked up as lists"
886
+ - success_criterion_1_3_2: # Meaningful Sequence
887
+ level: A
888
+ description: "Content order makes sense when linearized"
889
+ - success_criterion_1_3_3: # Sensory Characteristics
890
+ level: A
891
+ description: "Instructions don't rely solely on sensory characteristics"
892
+
893
+ - guideline_1_4: # Distinguishable
894
+ - success_criterion_1_4_1: # Use of Color
895
+ level: A
896
+ description: "Color not the only means of conveying information"
897
+ - success_criterion_1_4_2: # Audio Control
898
+ level: A
899
+ description: "Audio that plays automatically can be controlled"
900
+ - success_criterion_1_4_3: # Contrast (Minimum)
901
+ level: AA
902
+ description: "Text has sufficient color contrast (4.5:1 normal, 3:1 large)"
903
+ - success_criterion_1_4_4: # Resize Text
904
+ level: AA
905
+ description: "Text can be resized to 200% without assistive technology"
906
+ - success_criterion_1_4_5: # Images of Text
907
+ level: AA
908
+ description: "Use actual text rather than images of text when possible"
909
+
910
+ # Principle 2: Operable
911
+ operable:
912
+ - guideline_2_1: # Keyboard Accessible
913
+ - success_criterion_2_1_1: # Keyboard
914
+ level: A
915
+ description: "All functionality available via keyboard"
916
+ tests:
917
+ - "All interactive elements reachable via Tab"
918
+ - "All functionality works with keyboard"
919
+ - "No keyboard traps"
920
+ - success_criterion_2_1_2: # No Keyboard Trap
921
+ level: A
922
+ description: "Focus can move away from any component"
923
+ - success_criterion_2_1_4: # Character Key Shortcuts
924
+ level: A
925
+ description: "Single character shortcuts can be turned off or remapped"
926
+
927
+ - guideline_2_2: # Enough Time
928
+ - success_criterion_2_2_1: # Timing Adjustable
929
+ level: A
930
+ description: "Time limits can be turned off, adjusted, or extended"
931
+ - success_criterion_2_2_2: # Pause, Stop, Hide
932
+ level: A
933
+ description: "Moving, blinking, or auto-updating content can be controlled"
934
+
935
+ - guideline_2_3: # Seizures and Physical Reactions
936
+ - success_criterion_2_3_1: # Three Flashes or Below Threshold
937
+ level: A
938
+ description: "No content flashes more than 3 times per second"
939
+
940
+ - guideline_2_4: # Navigable
941
+ - success_criterion_2_4_1: # Bypass Blocks
942
+ level: A
943
+ description: "Skip links or other bypass mechanisms available"
944
+ - success_criterion_2_4_2: # Page Titled
945
+ level: A
946
+ description: "Web pages have descriptive titles"
947
+ - success_criterion_2_4_3: # Focus Order
948
+ level: A
949
+ description: "Focus order is logical and usable"
950
+ - success_criterion_2_4_4: # Link Purpose (In Context)
951
+ level: A
952
+ description: "Link purpose clear from text or context"
953
+ - success_criterion_2_4_5: # Multiple Ways
954
+ level: AA
955
+ description: "Multiple ways to locate web pages"
956
+ - success_criterion_2_4_6: # Headings and Labels
957
+ level: AA
958
+ description: "Headings and labels describe topic or purpose"
959
+ - success_criterion_2_4_7: # Focus Visible
960
+ level: AA
961
+ description: "Keyboard focus indicator is visible"
962
+
963
+ - guideline_2_5: # Input Modalities
964
+ - success_criterion_2_5_1: # Pointer Gestures
965
+ level: A
966
+ description: "Multipoint or path-based gestures have single-pointer alternative"
967
+ - success_criterion_2_5_2: # Pointer Cancellation
968
+ level: A
969
+ description: "Functions triggered by single-pointer can be cancelled"
970
+ - success_criterion_2_5_3: # Label in Name
971
+ level: A
972
+ description: "Accessible name contains visible label text"
973
+ - success_criterion_2_5_4: # Motion Actuation
974
+ level: A
975
+ description: "Functions triggered by motion can be turned off"
976
+
977
+ # Principle 3: Understandable
978
+ understandable:
979
+ - guideline_3_1: # Readable
980
+ - success_criterion_3_1_1: # Language of Page
981
+ level: A
982
+ description: "Primary language of page is programmatically determined"
983
+ - success_criterion_3_1_2: # Language of Parts
984
+ level: AA
985
+ description: "Language of content parts is programmatically determined"
986
+
987
+ - guideline_3_2: # Predictable
988
+ - success_criterion_3_2_1: # On Focus
989
+ level: A
990
+ description: "Focus doesn't trigger unexpected context changes"
991
+ - success_criterion_3_2_2: # On Input
992
+ level: A
993
+ description: "Input doesn't trigger unexpected context changes"
994
+ - success_criterion_3_2_3: # Consistent Navigation
995
+ level: AA
996
+ description: "Navigation is consistent across pages"
997
+ - success_criterion_3_2_4: # Consistent Identification
998
+ level: AA
999
+ description: "Components with same functionality identified consistently"
1000
+
1001
+ - guideline_3_3: # Input Assistance
1002
+ - success_criterion_3_3_1: # Error Identification
1003
+ level: A
1004
+ description: "Input errors are identified and described in text"
1005
+ - success_criterion_3_3_2: # Labels or Instructions
1006
+ level: A
1007
+ description: "Labels or instructions provided for user input"
1008
+ - success_criterion_3_3_3: # Error Suggestion
1009
+ level: AA
1010
+ description: "Error correction suggestions provided when possible"
1011
+ - success_criterion_3_3_4: # Error Prevention (Legal, Financial, Data)
1012
+ level: AA
1013
+ description: "Important submissions can be reversed, checked, or confirmed"
1014
+
1015
+ # Principle 4: Robust
1016
+ robust:
1017
+ - guideline_4_1: # Compatible
1018
+ - success_criterion_4_1_1: # Parsing
1019
+ level: A
1020
+ description: "Content can be parsed reliably by assistive technologies"
1021
+ - success_criterion_4_1_2: # Name, Role, Value
1022
+ level: A
1023
+ description: "UI components have accessible name, role, and value"
1024
+ - success_criterion_4_1_3: # Status Messages
1025
+ level: AA
1026
+ description: "Status messages are programmatically determinable"
1027
+ ```
1028
+
1029
+ ## CI/CD Integration for Accessibility
1030
+ ```yaml
1031
+ # .github/workflows/accessibility.yml
1032
+ name: Accessibility Testing
1033
+
1034
+ on:
1035
+ push:
1036
+ branches: [main, develop]
1037
+ pull_request:
1038
+ branches: [main]
1039
+
1040
+ jobs:
1041
+ accessibility-tests:
1042
+ runs-on: ubuntu-latest
1043
+
1044
+ steps:
1045
+ - uses: actions/checkout@v3
1046
+
1047
+ - name: Setup Node.js
1048
+ uses: actions/setup-node@v3
1049
+ with:
1050
+ node-version: 18
1051
+ cache: 'npm'
1052
+
1053
+ - name: Install dependencies
1054
+ run: npm ci
1055
+
1056
+ - name: Build application
1057
+ run: npm run build
1058
+
1059
+ - name: Start application
1060
+ run: |
1061
+ npm start &
1062
+ npx wait-on http://localhost:3000
1063
+
1064
+ - name: Install accessibility testing tools
1065
+ run: |
1066
+ npm install -g @axe-core/cli
1067
+ npm install -g pa11y
1068
+ npm install -g lighthouse
1069
+
1070
+ - name: Run axe-core accessibility tests
1071
+ run: |
1072
+ axe http://localhost:3000 \
1073
+ --tags wcag2a,wcag2aa,wcag21aa \
1074
+ --reporter json \
1075
+ --output axe-results.json
1076
+
1077
+ - name: Run Pa11y accessibility tests
1078
+ run: |
1079
+ pa11y http://localhost:3000 \
1080
+ --standard WCAG2AA \
1081
+ --reporter json \
1082
+ --output pa11y-results.json
1083
+
1084
+ - name: Run Lighthouse accessibility audit
1085
+ run: |
1086
+ lighthouse http://localhost:3000 \
1087
+ --only-categories=accessibility \
1088
+ --output=json \
1089
+ --output-path=lighthouse-a11y.json \
1090
+ --chrome-flags="--headless"
1091
+
1092
+ - name: Run Playwright accessibility tests
1093
+ run: npx playwright test tests/accessibility/
1094
+
1095
+ - name: Generate accessibility report
1096
+ run: |
1097
+ node scripts/generate-a11y-report.js
1098
+
1099
+ - name: Upload accessibility artifacts
1100
+ uses: actions/upload-artifact@v3
1101
+ with:
1102
+ name: accessibility-reports
1103
+ path: |
1104
+ axe-results.json
1105
+ pa11y-results.json
1106
+ lighthouse-a11y.json
1107
+ accessibility-report.html
1108
+ retention-days: 30
1109
+
1110
+ - name: Comment PR with accessibility results
1111
+ if: github.event_name == 'pull_request'
1112
+ uses: actions/github-script@v6
1113
+ with:
1114
+ script: |
1115
+ const fs = require('fs');
1116
+ const axeResults = JSON.parse(fs.readFileSync('axe-results.json', 'utf8'));
1117
+
1118
+ const violationsCount = axeResults.violations.length;
1119
+ const passesCount = axeResults.passes.length;
1120
+
1121
+ const comment = `
1122
+ ## Accessibility Test Results
1123
+
1124
+ - ✅ **Passed**: ${passesCount} tests
1125
+ - ❌ **Failed**: ${violationsCount} tests
1126
+
1127
+ ${violationsCount > 0 ? `
1128
+ ### Violations Found:
1129
+ ${axeResults.violations.map(v => `
1130
+ - **${v.id}** (${v.impact}): ${v.description}
1131
+ - Affected elements: ${v.nodes.length}
1132
+ - Help: ${v.helpUrl}
1133
+ `).join('')}
1134
+ ` : '🎉 No accessibility violations found!'}
1135
+
1136
+ [View detailed report](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})
1137
+ `;
1138
+
1139
+ github.rest.issues.createComment({
1140
+ issue_number: context.issue.number,
1141
+ owner: context.repo.owner,
1142
+ repo: context.repo.repo,
1143
+ body: comment
1144
+ });
1145
+
1146
+ visual-accessibility:
1147
+ runs-on: ubuntu-latest
1148
+ steps:
1149
+ - uses: actions/checkout@v3
1150
+
1151
+ - name: Setup Node.js
1152
+ uses: actions/setup-node@v3
1153
+ with:
1154
+ node-version: 18
1155
+ cache: 'npm'
1156
+
1157
+ - name: Install dependencies
1158
+ run: npm ci
1159
+
1160
+ - name: Color contrast testing
1161
+ run: |
1162
+ npm run test:contrast
1163
+
1164
+ - name: Focus indicator testing
1165
+ run: |
1166
+ npm run test:focus-indicators
1167
+
1168
+ - name: Text scaling testing
1169
+ run: |
1170
+ npm run test:text-scaling
1171
+ ```
1172
+
1173
+ ## Best Practices
1174
+ 1. **Shift Left**: Integrate accessibility testing early in development
1175
+ 2. **Automated + Manual**: Combine automated tools with manual testing
1176
+ 3. **Real Users**: Include users with disabilities in testing
1177
+ 4. **Progressive Enhancement**: Build with accessibility as foundation
1178
+ 5. **Semantic HTML**: Use proper HTML elements for their intended purpose
1179
+ 6. **ARIA Judiciously**: Use ARIA to enhance, not replace, semantic HTML
1180
+ 7. **Focus Management**: Ensure logical focus order and visible indicators
1181
+
1182
+ ## Accessibility Testing Strategy
1183
+ - Establish accessibility requirements and acceptance criteria
1184
+ - Implement automated testing in CI/CD pipelines
1185
+ - Conduct regular manual testing with assistive technologies
1186
+ - Include users with disabilities in usability testing
1187
+ - Create accessibility documentation and training
1188
+ - Monitor and maintain accessibility over time
1189
+
1190
+ ## Approach
1191
+ - Start with semantic HTML and proper document structure
1192
+ - Implement comprehensive automated testing coverage
1193
+ - Conduct manual testing with screen readers and keyboard navigation
1194
+ - Validate with real users who rely on assistive technologies
1195
+ - Create detailed accessibility documentation and guidelines
1196
+ - Establish ongoing monitoring and maintenance procedures
1197
+
1198
+ ## Output Format
1199
+ - Provide complete accessibility testing frameworks
1200
+ - Include WCAG compliance checklists and procedures
1201
+ - Document manual testing procedures and tools
1202
+ - Add CI/CD integration examples
1203
+ - Include component accessibility guidelines
1204
+ - Provide comprehensive reporting and remediation guides