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