jdi-cli 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 (159) hide show
  1. package/AGENTS.md +209 -0
  2. package/ARCHITECTURE.md +210 -0
  3. package/COMMANDS.md +241 -0
  4. package/CREATE-EXAMPLE.md +385 -0
  5. package/CREATE.md +315 -0
  6. package/EXTENSION.md +141 -0
  7. package/LICENSE +21 -0
  8. package/MEMORY.md +471 -0
  9. package/PORTABILITY.md +438 -0
  10. package/README.md +789 -0
  11. package/bin/git-hooks/post-commit +16 -0
  12. package/bin/git-hooks/pre-commit +21 -0
  13. package/bin/jdi-build.ps1 +381 -0
  14. package/bin/jdi-build.sh +332 -0
  15. package/bin/jdi-doctor.ps1 +403 -0
  16. package/bin/jdi-doctor.sh +400 -0
  17. package/bin/jdi-install-caveman.ps1 +97 -0
  18. package/bin/jdi-install-caveman.sh +99 -0
  19. package/bin/jdi-install-playwright.ps1 +319 -0
  20. package/bin/jdi-install-playwright.sh +284 -0
  21. package/bin/jdi-install.ps1 +154 -0
  22. package/bin/jdi-install.sh +132 -0
  23. package/bin/jdi-uninstall.ps1 +309 -0
  24. package/bin/jdi-uninstall.sh +264 -0
  25. package/bin/jdi-update.ps1 +215 -0
  26. package/bin/jdi-update.sh +209 -0
  27. package/bin/jdi.js +460 -0
  28. package/bin/lib/jdi-monitor.ps1 +66 -0
  29. package/bin/lib/jdi-monitor.sh +74 -0
  30. package/bin/lib/jdi-truncate.ps1 +96 -0
  31. package/bin/lib/jdi-truncate.sh +99 -0
  32. package/bin/lib/ui.js +197 -0
  33. package/core/agents/jdi-adopter.md +465 -0
  34. package/core/agents/jdi-architect.md +894 -0
  35. package/core/agents/jdi-asker.md +153 -0
  36. package/core/agents/jdi-bootstrap.md +247 -0
  37. package/core/agents/jdi-planner.md +254 -0
  38. package/core/agents/jdi-researcher.md +303 -0
  39. package/core/commands/jdi-adopt.md +155 -0
  40. package/core/commands/jdi-bootstrap.md +81 -0
  41. package/core/commands/jdi-create.md +80 -0
  42. package/core/commands/jdi-discuss.md +80 -0
  43. package/core/commands/jdi-do.md +200 -0
  44. package/core/commands/jdi-loop.md +315 -0
  45. package/core/commands/jdi-new.md +131 -0
  46. package/core/commands/jdi-plan.md +73 -0
  47. package/core/commands/jdi-ship.md +146 -0
  48. package/core/commands/jdi-verify.md +159 -0
  49. package/core/skills/clean-code/SKILL.md +261 -0
  50. package/core/skills/dry/SKILL.md +150 -0
  51. package/core/skills/frontend-rules/SKILL.md +386 -0
  52. package/core/skills/frontend-validator/SKILL.md +567 -0
  53. package/core/skills/kiss/SKILL.md +178 -0
  54. package/core/skills/solid/SKILL.md +281 -0
  55. package/core/skills/yagni/SKILL.md +207 -0
  56. package/core/templates/agent.md +72 -0
  57. package/core/templates/doer-specialist.md +216 -0
  58. package/core/templates/reviewer-specialist.md +405 -0
  59. package/core/templates/skill.md +66 -0
  60. package/package.json +70 -0
  61. package/runtimes/antigravity/agents.md +74 -0
  62. package/runtimes/antigravity/skills/clean-code/SKILL.md +252 -0
  63. package/runtimes/antigravity/skills/dry/SKILL.md +141 -0
  64. package/runtimes/antigravity/skills/frontend-rules/SKILL.md +376 -0
  65. package/runtimes/antigravity/skills/frontend-validator/SKILL.md +559 -0
  66. package/runtimes/antigravity/skills/jdi-adopt/SKILL.md +155 -0
  67. package/runtimes/antigravity/skills/jdi-adopter/SKILL.md +436 -0
  68. package/runtimes/antigravity/skills/jdi-architect/SKILL.md +872 -0
  69. package/runtimes/antigravity/skills/jdi-asker/SKILL.md +125 -0
  70. package/runtimes/antigravity/skills/jdi-asker/references/context-template.md +34 -0
  71. package/runtimes/antigravity/skills/jdi-asker/references/decision-format.md +19 -0
  72. package/runtimes/antigravity/skills/jdi-asker/scripts/find_phase_dir.sh +25 -0
  73. package/runtimes/antigravity/skills/jdi-bootstrap/SKILL.md +81 -0
  74. package/runtimes/antigravity/skills/jdi-create/SKILL.md +80 -0
  75. package/runtimes/antigravity/skills/jdi-discuss/SKILL.md +80 -0
  76. package/runtimes/antigravity/skills/jdi-discuss/scripts/run_command.sh +62 -0
  77. package/runtimes/antigravity/skills/jdi-do/SKILL.md +200 -0
  78. package/runtimes/antigravity/skills/jdi-loop/SKILL.md +315 -0
  79. package/runtimes/antigravity/skills/jdi-new/SKILL.md +131 -0
  80. package/runtimes/antigravity/skills/jdi-plan/SKILL.md +73 -0
  81. package/runtimes/antigravity/skills/jdi-planner/SKILL.md +225 -0
  82. package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +274 -0
  83. package/runtimes/antigravity/skills/jdi-ship/SKILL.md +146 -0
  84. package/runtimes/antigravity/skills/jdi-verify/SKILL.md +159 -0
  85. package/runtimes/antigravity/skills/kiss/SKILL.md +169 -0
  86. package/runtimes/antigravity/skills/solid/SKILL.md +272 -0
  87. package/runtimes/antigravity/skills/yagni/SKILL.md +198 -0
  88. package/runtimes/claude/CLAUDE.md +91 -0
  89. package/runtimes/claude/agents/jdi-adopter.md +430 -0
  90. package/runtimes/claude/agents/jdi-architect.md +864 -0
  91. package/runtimes/claude/agents/jdi-asker.md +119 -0
  92. package/runtimes/claude/agents/jdi-bootstrap.md +213 -0
  93. package/runtimes/claude/agents/jdi-planner.md +221 -0
  94. package/runtimes/claude/agents/jdi-researcher.md +269 -0
  95. package/runtimes/claude/commands/jdi-adopt.md +155 -0
  96. package/runtimes/claude/commands/jdi-bootstrap.md +81 -0
  97. package/runtimes/claude/commands/jdi-create.md +80 -0
  98. package/runtimes/claude/commands/jdi-discuss.md +80 -0
  99. package/runtimes/claude/commands/jdi-do.md +200 -0
  100. package/runtimes/claude/commands/jdi-loop.md +315 -0
  101. package/runtimes/claude/commands/jdi-new.md +131 -0
  102. package/runtimes/claude/commands/jdi-plan.md +73 -0
  103. package/runtimes/claude/commands/jdi-ship.md +146 -0
  104. package/runtimes/claude/commands/jdi-verify.md +159 -0
  105. package/runtimes/claude/settings.example.json +132 -0
  106. package/runtimes/claude/skills/clean-code/SKILL.md +247 -0
  107. package/runtimes/claude/skills/dry/SKILL.md +136 -0
  108. package/runtimes/claude/skills/frontend-rules/SKILL.md +369 -0
  109. package/runtimes/claude/skills/frontend-validator/SKILL.md +553 -0
  110. package/runtimes/claude/skills/kiss/SKILL.md +164 -0
  111. package/runtimes/claude/skills/solid/SKILL.md +267 -0
  112. package/runtimes/claude/skills/yagni/SKILL.md +193 -0
  113. package/runtimes/copilot/agents/jdi-adopter.agent.md +430 -0
  114. package/runtimes/copilot/agents/jdi-architect.agent.md +864 -0
  115. package/runtimes/copilot/agents/jdi-asker.agent.md +119 -0
  116. package/runtimes/copilot/agents/jdi-bootstrap.agent.md +213 -0
  117. package/runtimes/copilot/agents/jdi-planner.agent.md +221 -0
  118. package/runtimes/copilot/agents/jdi-researcher.agent.md +269 -0
  119. package/runtimes/copilot/copilot-instructions.md +80 -0
  120. package/runtimes/copilot/prompts/jdi-adopt.prompt.md +155 -0
  121. package/runtimes/copilot/prompts/jdi-bootstrap.prompt.md +81 -0
  122. package/runtimes/copilot/prompts/jdi-create.prompt.md +80 -0
  123. package/runtimes/copilot/prompts/jdi-discuss.prompt.md +80 -0
  124. package/runtimes/copilot/prompts/jdi-do.prompt.md +200 -0
  125. package/runtimes/copilot/prompts/jdi-loop.prompt.md +315 -0
  126. package/runtimes/copilot/prompts/jdi-new.prompt.md +131 -0
  127. package/runtimes/copilot/prompts/jdi-plan.prompt.md +73 -0
  128. package/runtimes/copilot/prompts/jdi-ship.prompt.md +146 -0
  129. package/runtimes/copilot/prompts/jdi-verify.prompt.md +159 -0
  130. package/runtimes/opencode/AGENTS.md +87 -0
  131. package/runtimes/opencode/agents/jdi-adopter.md +434 -0
  132. package/runtimes/opencode/agents/jdi-architect.md +861 -0
  133. package/runtimes/opencode/agents/jdi-asker.md +123 -0
  134. package/runtimes/opencode/agents/jdi-bootstrap.md +217 -0
  135. package/runtimes/opencode/agents/jdi-planner.md +225 -0
  136. package/runtimes/opencode/agents/jdi-researcher.md +273 -0
  137. package/runtimes/opencode/commands/jdi-adopt.md +155 -0
  138. package/runtimes/opencode/commands/jdi-bootstrap.md +81 -0
  139. package/runtimes/opencode/commands/jdi-create.md +80 -0
  140. package/runtimes/opencode/commands/jdi-discuss.md +80 -0
  141. package/runtimes/opencode/commands/jdi-do.md +200 -0
  142. package/runtimes/opencode/commands/jdi-loop.md +315 -0
  143. package/runtimes/opencode/commands/jdi-new.md +131 -0
  144. package/runtimes/opencode/commands/jdi-plan.md +73 -0
  145. package/runtimes/opencode/commands/jdi-ship.md +146 -0
  146. package/runtimes/opencode/commands/jdi-verify.md +159 -0
  147. package/runtimes/opencode/opencode.example.jsonc +169 -0
  148. package/runtimes/opencode/skills/clean-code/SKILL.md +247 -0
  149. package/runtimes/opencode/skills/dry/SKILL.md +136 -0
  150. package/runtimes/opencode/skills/frontend-rules/SKILL.md +369 -0
  151. package/runtimes/opencode/skills/frontend-validator/SKILL.md +553 -0
  152. package/runtimes/opencode/skills/kiss/SKILL.md +164 -0
  153. package/runtimes/opencode/skills/solid/SKILL.md +267 -0
  154. package/runtimes/opencode/skills/yagni/SKILL.md +193 -0
  155. package/templates-jdi-folder/config.json +18 -0
  156. package/templates-jdi-folder/registry.md +31 -0
  157. package/templates-jdi-folder/reviewers.md +33 -0
  158. package/templates-jdi-folder/skills-registry.md +32 -0
  159. package/templates-jdi-folder/specialists.md +39 -0
@@ -0,0 +1,369 @@
1
+ ---
2
+ name: frontend-rules
3
+ description: Universal UI/UX and accessibility rules for any web interface. Framework-agnostic - works for React, Vue, Svelte, Solid, Angular, Blazor, Razor, Twig, Jinja, ERB, Blade, and any template engine. Based on WCAG 2.2 AA, Nielsen heuristics, Material/Apple HIG.
4
+ ---
5
+
6
+ # Skill: jdi-frontend-rules
7
+
8
+ UI/UX standards that CANNOT be violated - regardless of stack. Concepts > syntax. Works for SPA, SSR, MPA, hybrid, any template engine.
9
+
10
+ ## When to apply
11
+
12
+ Whenever code touches a visible human interface:
13
+
14
+ - Files `.tsx, .jsx, .vue, .svelte, .astro, .qwik, .solid` (JS-based components)
15
+ - Files `.razor, .cshtml` (Blazor / Razor Pages / MVC)
16
+ - Files `.html, .twig, .jinja, .j2, .erb, .blade.php, .hbs, .liquid, .mustache, .ejs, .pug` (template engines)
17
+ - CSS/Tailwind/SCSS/Less affecting layout, contrast, focus, or accessibility
18
+ - ARIA / semantic HTML in any language
19
+
20
+ Does NOT apply to: API-only backends, CLI tools, services without UI.
21
+
22
+ ## Universal rules (hard gates)
23
+
24
+ ### 1. Accessibility - WCAG 2.2 level AA
25
+
26
+ All mandatory. Violation = BLOCK on review.
27
+
28
+ - **Color contrast**:
29
+ - Normal text: minimum 4.5:1 against background
30
+ - Large text (18pt+ or 14pt+ bold): minimum 3:1
31
+ - UI components and graphics: minimum 3:1
32
+ - Verify in hover/focus/disabled states too
33
+ - **Visible focus**: never `outline: none` or `outline: 0` without a replacement. Focus must be perceptible in strong light and on a cheap monitor. `:focus-visible` is the standard
34
+ - **Keyboard navigation**: 100% of interactions reachable via keyboard. Tab follows logical visual order. No trap (modal without Esc, dropdown without Escape/arrows)
35
+ - **Semantic HTML first**:
36
+ - `<button>` for action (even if styled as a link)
37
+ - `<a href>` for navigation (even if styled as a button)
38
+ - `<form>` for forms (Enter submits, native validation works)
39
+ - Headings in order (`h1` -> `h2` -> `h3`, no level skipping)
40
+ - `<nav>, <main>, <header>, <footer>, <aside>, <section>, <article>` when appropriate
41
+ - `<ul>/<ol>` for lists, not repeated `<div>`
42
+ - **ARIA when needed**:
43
+ - Icon-only button: `aria-label="descriptive action"`
44
+ - Form error: `role="alert"` or `aria-live="assertive"`
45
+ - Loading region: `aria-busy="true"` + `aria-live="polite"`
46
+ - Toggle/expand: `aria-expanded="true|false"` + `aria-controls`
47
+ - Modal: `role="dialog"` + `aria-modal="true"` + `aria-labelledby`
48
+ - Tooltip: `aria-describedby`
49
+ - ARIA NEVER REPLACES semantic HTML. ARIA only complements
50
+ - **Skip link**: first tab order offers "Skip to main content"
51
+ - **Minimum touch target**: 44x44 CSS px (Apple HIG / WCAG 2.5.5). Increase on mobile with `padding`, not margin
52
+ - **Color is not the only indicator**:
53
+ - Red error needs icon OR explicit text
54
+ - Colored link needs underline OR different visual weight
55
+ - Active nav state needs border/weight, not just color
56
+ - Color blindness affects 8% of men. Always color + shape + text
57
+ - **Form labels**: every `<input>, <textarea>, <select>` with:
58
+ - Associated `<label htmlFor="id">`, OR
59
+ - `aria-label="..."`, OR
60
+ - `aria-labelledby="id-of-another-element"`
61
+ - Placeholder DOES NOT count as label (disappears when user types)
62
+ - **Associated error**: field error connected via `aria-describedby="error-id"`. Error text has matching `id`
63
+ - **Language**: `<html lang="pt-BR">` declared. Without this screen reader reads English for pt-BR text
64
+ - **prefers-reduced-motion**: respect. Animations should disable via `@media (prefers-reduced-motion: reduce)`
65
+
66
+ ### 2. Mandatory states on every UI surface
67
+
68
+ Every screen/component that loads or mutates data must cover all 5:
69
+
70
+ - **Loading**:
71
+ - Skeleton with shape matching real content (avoids layout shift)
72
+ - OR spinner/progress if shape unpredictable
73
+ - Visible minimum 200ms (avoids flash that flickers)
74
+ - Maximum 10s without extra feedback - after that explain "almost there" or offer cancel
75
+ - **Empty**:
76
+ - Never empty screen. Always message + icon + actionable CTA
77
+ - Text orients next step: "Create your first X by clicking Y"
78
+ - Don't confuse empty with error (empty is success, error is failure)
79
+ - **Error**:
80
+ - Specific message: what failed + how to fix
81
+ - NEVER "Something went wrong" / "Unexpected error" as final message to user
82
+ - Visible recovery action: retry, go back, contact support
83
+ - Inline validation errors + general message if needed
84
+ - **Success**:
85
+ - Visible confirmation - toast is OK for non-destructive actions
86
+ - Destructive action (delete, transfer) needs undo OR prior confirmation
87
+ - Toast disappears in 4-6s; destructive actions with undo have 5-10s
88
+ - **Disabled**:
89
+ - ALWAYS with visible reason: tooltip, helper text, or hint
90
+ - Silent disabled = bug ("why can't I click?")
91
+ - Consider alternative: don't disable, let click and show specific error
92
+
93
+ ### 3. Feedback timing - Nielsen heuristics
94
+
95
+ - **< 100ms**: feels instant. No indicator needed
96
+ - **100ms to 1s**: acceptable without indicator. Cursor may change to waiting
97
+ - **1s to 10s**: progress indicator required. Spinner or bar
98
+ - **> 10s**: progress + estimated time OR allow cancel
99
+ - **Indeterminate and > 30s**: offer background notification, free up UI
100
+ - **Optimistic UI**: like/save/toggle - update UI immediately, rollback if it fails
101
+
102
+ ### 4. Forms - universal patterns
103
+
104
+ - **Validation**:
105
+ - On blur for individual field (after user leaves field)
106
+ - On submit for general validation
107
+ - On change ONLY for positive feedback (e.g., password strength)
108
+ - NEVER on keypress for error ("missing character") - tiring
109
+ - **Inline errors**: next to/below the wrong field, WITH optional general top-of-form message. Never just top
110
+ - **Required**:
111
+ - Red asterisk is NOT enough - add text "(required)" or a clear mark before submit
112
+ - Indicate required at design time, not after the error
113
+ - Modern alternative: mark optionals ("Phone (optional)")
114
+ - **Autocomplete**: correct `autocomplete` attribute: `email, current-password, new-password, name, given-name, family-name, tel, postal-code, etc`. Enables browser autofill
115
+ - **Inputmode + type**:
116
+ - `type="email"` shows keyboard with @ on mobile
117
+ - `inputmode="numeric"` for OTP/PIN/ZIP
118
+ - `type="tel"` for phone
119
+ - `type="url"` for URL
120
+ - `type="date"` for date (with fallback if browser doesn't support)
121
+ - **Submit**:
122
+ - DO NOT disable button before user tries - teaches wrong and hides cause
123
+ - Disable ONLY during in-flight request (avoids double submit)
124
+ - Loading state on the button (text + inline spinner)
125
+ - **Password**:
126
+ - "Show password" toggle (eye icon)
127
+ - Always force HTTPS - never send password in plain HTTP
128
+ - Show requirements before user types (8+ chars, etc)
129
+ - **Destructive confirmation**:
130
+ - Irreversible actions (delete account, drop data) require typing name/word or explicit checkbox
131
+ - Plain "are you sure?" modal is insufficient for truly destructive action
132
+
133
+ ### 5. Navigation
134
+
135
+ - **Current location**: active nav highlighted (weight + color + indicator). Breadcrumbs in deep hierarchy
136
+ - **Browser back button**: respect history. Modal doesn't use `pushState` without reason. Single-page nav uses router that emits real history
137
+ - **Custom 404**: friendly page with search or sitemap, not blank screen
138
+ - **Logo links home**: universal convention
139
+ - **Search**: if app has search, keyboard shortcut `/` or `Ctrl+K` (convention)
140
+
141
+ ### 6. Responsive - mobile-first
142
+
143
+ - **Design starts at 320px** and grows - not the other way around
144
+ - **Breakpoints based on content**, not devices: point where layout breaks, not "iPhone 12"
145
+ - **No horizontal scroll on mobile** (except intentional carousel). Audit with viewport 375px
146
+ - **Touch-friendly spacing**: minimum 8px between clickable targets
147
+ - **Hover-only is bad on mobile**: anything needing hover needs fallback (long press, tap to reveal)
148
+ - **Density**: mobile needs more space than desktop for the same legibility
149
+
150
+ ### 7. UX performance - Core Web Vitals
151
+
152
+ - **CLS < 0.1** (Cumulative Layout Shift):
153
+ - `width` + `height` on every `<img>` (avoids jump on load)
154
+ - `font-display: swap` with metric-compatible fallback
155
+ - Reserve space for ads/embeds/skeletons
156
+ - **LCP < 2.5s** (Largest Contentful Paint):
157
+ - Optimized hero image (WebP/AVIF + responsive `srcset`)
158
+ - Critical CSS inline
159
+ - Preload critical resource (`<link rel="preload">`)
160
+ - **INP < 200ms** (Interaction to Next Paint):
161
+ - No heavy JS blocking main thread during interaction
162
+ - Debounce on input handlers
163
+ - Web Workers for heavy computation
164
+ - **TTFB < 800ms** (Time To First Byte):
165
+ - Static cache, CDN, lazy loading
166
+ - **Optimistic UI**: already mentioned - update immediately
167
+
168
+ ### 8. Visual hierarchy
169
+
170
+ - **1 primary action per view**. Multiple = paralyzed decision (Hicks Law)
171
+ - **Secondary visually smaller**: ghost, outline, or link
172
+ - **Whitespace separates groups** - no little box (border) for everything
173
+ - **Fixed spacing scale**: 4/8/16/24/32/48/64 (multiples of 4 or 8). No `margin: 13px`
174
+ - **Type scale**: max 5-6 sizes in the entire app. More than that = visual chaos
175
+ - **Color palette**:
176
+ - 60-30-10 rule: 60% neutral (background), 30% complementary, 10% accent (CTA)
177
+ - Max 1 brand color + 1 or 2 accents
178
+ - States (success/warn/error) are a separate palette
179
+ - **Alignment**: every element aligned to a grid - not "eyeball"
180
+
181
+ ### 9. i18n + l10n
182
+
183
+ - **Zero hardcoded string in markup**. Always a translation key
184
+ - JSX/TSX: don't write pt-BR text directly, use `t("key")` or equivalent
185
+ - Templates: use translate tag (`{% trans %}`, `<t>`, `@Localize`)
186
+ - HTML: separate content from markup
187
+ - **RTL ready** (Arabic, Hebrew):
188
+ - Logical properties: `margin-inline-start` instead of `margin-left`
189
+ - `padding-block` instead of `padding-top`
190
+ - `text-align: start/end` instead of `left/right`
191
+ - `dir="auto"` on fields accepting input in any language
192
+ - **Format by locale**:
193
+ - Dates: `Intl.DateTimeFormat` or backend equivalent
194
+ - Numbers: `Intl.NumberFormat`
195
+ - Currency: never hardcoded "$" - currency comes from locale + value
196
+ - **Pluralization**: ICU MessageFormat or equivalent. Languages have 1, 2, 3+ or more forms (Russian has 4)
197
+
198
+ ### 10. UI security - overlap with general rules
199
+
200
+ - **Tokens NEVER in localStorage/sessionStorage**:
201
+ - Vulnerable to XSS. Any malicious script reads everything
202
+ - Safe pattern: httpOnly cookie + SameSite=Strict
203
+ - Token in memory with refresh via cookie is OK for SPAs
204
+ - **Strict CSP**:
205
+ - `script-src 'self'` at minimum - no `unsafe-inline`, no `unsafe-eval`
206
+ - `frame-ancestors 'none'` or whitelist - prevents clickjacking
207
+ - **HTTPS only**:
208
+ - Redirect HTTP -> HTTPS on the server
209
+ - HSTS header with `includeSubDomains`
210
+ - No mixed content (HTTP on HTTPS page)
211
+ - **CSRF**:
212
+ - CSRF token on every form with authenticated side-effect
213
+ - SameSite=Strict cookie helps but isn't enough
214
+ - **External links**:
215
+ - `target="_blank"` ALWAYS with `rel="noopener noreferrer"` (prevents tabnabbing)
216
+ - **dangerouslySetInnerHTML / v-html / @Html.Raw**:
217
+ - Never with user input without sanitization (DOMPurify or backend sanitizer)
218
+ - Prefer semantic parsing (markdown -> AST -> render)
219
+ - **External form action**: never accept a user-controllable `action` URL
220
+
221
+ ## Anti-patterns - BLOCK list for reviewer
222
+
223
+ Each item below is automatic violation. Reviewer marks BLOCK + cites rule.
224
+
225
+ | Anti-pattern | Why it is BLOCK |
226
+ |---|---|
227
+ | Button that looks like a link / link that looks like a button | Confuses mental model, violates convention |
228
+ | `<div onclick>` instead of `<button>` | No keyboard, no ARIA, no semantics |
229
+ | `<a href="#">` or `<a href="javascript:">` for action | Becomes a destinationless link - use `<button>` |
230
+ | Modal without Esc close | Keyboard trap - WCAG 2.1.2 |
231
+ | Modal without visible close button | Same reason |
232
+ | Infinite spinner without timeout/fallback | User doesn't know if it's stuck |
233
+ | Auto-play media with sound | WCAG 1.4.2 |
234
+ | Toast as ONLY confirmation of destructive action | Toast disappears - destructive needs persistent |
235
+ | Disabled state without visible reason | "Why doesn't it work?" - UX bug |
236
+ | Generic error "Something went wrong" | Not actionable |
237
+ | Color as ONLY state indicator | Color blindness - WCAG 1.4.1 |
238
+ | Required marked ONLY by color (red border) | Same reason |
239
+ | Required shown ONLY after submit | User didn't know it was required |
240
+ | Form without `<label>` or `aria-label` | WCAG 3.3.2 |
241
+ | Placeholder replacing label | Disappears when user types - WCAG 3.3.2 |
242
+ | Heading skip (h1 -> h3 without h2) | WCAG 1.3.1 |
243
+ | `<img>` without `alt` | WCAG 1.1.1 |
244
+ | `<img alt="image">` or redundant alt "image of X" | Good alt describes content, not media |
245
+ | Text over image without overlay/guaranteed contrast | WCAG 1.4.3 |
246
+ | Animation > 400ms on direct interaction | Perceived as slow |
247
+ | `prefers-reduced-motion` ignored | WCAG 2.3.3 |
248
+ | Outline removed without replacement | WCAG 2.4.7 |
249
+ | Arbitrary positive `tabindex` (`tabindex="5"`) | Breaks natural order - only use 0 and -1 |
250
+ | `lang` absent on `<html>` | Screen reader pronounces wrong |
251
+ | Form action or href with direct user input | Risk of XSS/open redirect |
252
+ | `localStorage.setItem('token', ...)` or similar for credential | XSS risk - use httpOnly cookie |
253
+
254
+ ## Procedure (use by agent)
255
+
256
+ ### Doer (write/edit)
257
+
258
+ #### Step 1: Detect type of change
259
+ If task touches UI files, load checklist in mind before writing.
260
+
261
+ #### Step 2: For each new component/template
262
+ Apply the checklist of rules 1-10. In particular:
263
+ - Does it cover the 5 states (loading/empty/error/success/disabled)?
264
+ - Semantic HTML first?
265
+ - Visible focus maintained?
266
+ - Contrast OK in light/dark states?
267
+ - Strings via i18n key?
268
+
269
+ #### Step 3: When in architectural doubt
270
+ Consult references:
271
+ - Full WCAG: `references/wcag-checklist.md`
272
+ - States: `references/state-coverage.md`
273
+ - Forms: `references/forms-patterns.md`
274
+ - Anti-patterns explained: `references/anti-patterns.md`
275
+
276
+ ### Reviewer (gate 5)
277
+
278
+ #### Step 1: For each modified file in frontend
279
+ Run specific greps based on the type:
280
+
281
+ **JSX/TSX/Vue/Svelte:**
282
+ ```bash
283
+ # Button without aria-label and without inner text
284
+ grep -RnE '<button[^>]*>(\s*<[^>]+/?>\s*)+</button>' src/
285
+
286
+ # Input without label
287
+ grep -RnE '<input(?![^>]*aria-label)(?![^>]*id=)' src/
288
+
289
+ # href="#" for action
290
+ grep -RnE 'href="#"' src/
291
+
292
+ # localStorage with token
293
+ grep -RnE 'localStorage\.(set|get)Item.*[Tt]oken' src/
294
+
295
+ # Outline removed
296
+ grep -RnE 'outline\s*:\s*(none|0)' src/
297
+ ```
298
+
299
+ **Server-side templates (Razor/Twig/Blade/ERB/Jinja):**
300
+ Similar greps adapted to the syntax.
301
+
302
+ #### Step 2: Classify
303
+ - Match on violation listed in the table above -> BLOCK
304
+ - Suspicious pattern but not certain -> WARN
305
+ - No match -> PASS on gate 5
306
+
307
+ ## Expected inputs
308
+
309
+ - Path of the modified file
310
+ - Diff or complete content of the file
311
+
312
+ ## Outputs
313
+
314
+ Does NOT produce its own file. Modifies the parent agent's judgement:
315
+ - Doer chooses NOT to introduce a violation - writes correct code from the start
316
+ - Reviewer marks BLOCK/WARN with rule cited
317
+
318
+ ## References
319
+
320
+ - `references/wcag-checklist.md` - WCAG 2.2 AA expanded with code examples
321
+ - `references/state-coverage.md` - Patterns for loading/empty/error/success/disabled across engines
322
+ - `references/forms-patterns.md` - Universal patterns for form validation and UX
323
+ - `references/anti-patterns.md` - Gallery of anti-patterns with wrong example + fix
324
+
325
+ ## Anti-patterns of this skill
326
+
327
+ - Applying only to JS stacks - rules work for any template engine
328
+ - Making a rule framework-specific (e.g., "use React.useState") - skill is agnostic
329
+ - Replacing human design code review - skill covers the technically broken, not the aesthetically mediocre
330
+ - Blocking MVP for minor a11y - severity matters, minor is INFO/WARN
331
+
332
+ ## Examples
333
+
334
+ ### Example 1: Doer receives task "add delete button to ItemCard"
335
+
336
+ Applies skill before writing:
337
+ - Destructive action needs: explicit confirmation, focus returns to origin button after modal closes, descriptive label (`aria-label="Delete item Order #123"`), undo if possible
338
+ - Loading state during request
339
+ - Error state with retry
340
+ - Success state with undo (5s timer)
341
+ - Use `<button>`, not `<a>` or `<div>`
342
+ - Tab order: button -> modal opens -> modal buttons navigable -> Esc closes -> focus returns
343
+
344
+ Code written comes out compliant.
345
+
346
+ ### Example 2: Reviewer finds `<input>` without label
347
+
348
+ Marks gate 5 as BLOCK:
349
+ ```
350
+ [BLOCK] src/components/LoginForm.tsx:42
351
+ Rule: Forms - Form labels (WCAG 1.3.1, 3.3.2)
352
+ Violation: <input type="email" /> without <label>, aria-label, or aria-labelledby
353
+ Fix: <label htmlFor="email">Email</label><input id="email" type="email" />
354
+ ```
355
+
356
+ ### Example 3: Reviewer finds `localStorage.setItem('access_token', token)`
357
+
358
+ Marks gate 5 as BLOCK:
359
+ ```
360
+ [BLOCK] src/auth/store.ts:18
361
+ Rule: UI Security - Tokens in storage
362
+ Violation: localStorage.setItem with authentication token
363
+ Why: vulnerable to XSS - any malicious script on the page reads the token
364
+ Fix: backend sets httpOnly cookie SameSite=Strict; frontend doesn't touch token
365
+ ```
366
+
367
+ ### Example 4: Backend-only API (Python FastAPI)
368
+
369
+ Skill is not loaded. PROJECT.md has `frontend.has_frontend: false`. Nothing happens.