codymaster 4.4.5 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +29 -14
  3. package/commands/demo.md +1 -1
  4. package/dist/context-bus.js +70 -0
  5. package/dist/context-db.js +265 -0
  6. package/dist/continuity.js +12 -0
  7. package/dist/file-watcher.js +79 -0
  8. package/dist/index.js +152 -1
  9. package/dist/l0-indexer.js +158 -0
  10. package/dist/mcp-context-server.js +400 -0
  11. package/dist/migrate-json-to-sqlite.js +126 -0
  12. package/dist/skill-chain.js +19 -3
  13. package/dist/token-budget.js +108 -0
  14. package/dist/uri-resolver.js +203 -0
  15. package/package.json +4 -1
  16. package/skills/_shared/helpers.md +50 -14
  17. package/skills/cm-autopilot/SKILL.md +29 -0
  18. package/skills/cm-autopilot/scripts/autopilot.py +190 -0
  19. package/skills/cm-continuity/SKILL.md +90 -28
  20. package/skills/cm-skill-chain/SKILL.md +47 -1
  21. package/skills/cm-start/SKILL.md +11 -2
  22. package/skills/boxme-git-config/SKILL.md +0 -56
  23. package/skills/boxme-local-dev/SKILL.md +0 -66
  24. package/skills/jobs-to-be-done/SKILL.md +0 -266
  25. package/skills/jobs-to-be-done/references/case-studies.md +0 -154
  26. package/skills/jobs-to-be-done/references/competitive-strategy.md +0 -280
  27. package/skills/jobs-to-be-done/references/diagnostics.md +0 -158
  28. package/skills/jobs-to-be-done/references/innovation-process.md +0 -392
  29. package/skills/jobs-to-be-done/references/organizational-change.md +0 -328
  30. package/skills/marketplace-report-crawler/SKILL.md +0 -176
  31. package/skills/marketplace-report-crawler/config/accounts.json +0 -41
  32. package/skills/marketplace-report-crawler/config/report-types.json +0 -422
  33. package/skills/marketplace-report-crawler/config/sessions.json +0 -3
  34. package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +0 -102
  35. package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +0 -114
  36. package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +0 -94
  37. package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +0 -272
  38. package/skills/marketplace-report-crawler/scripts/crawl-runner.js +0 -281
  39. package/skills/marketplace-report-crawler/scripts/session-check.sh +0 -72
  40. package/skills/marketplace-report-crawler/scripts/session-manager.sh +0 -349
  41. package/skills/marketplace-report-crawler/scripts/setup-folders.sh +0 -83
  42. package/skills/medical-research/SKILL.md +0 -194
  43. package/skills/medical-research/scripts/evidence_checker.py +0 -288
  44. package/skills/mom-test/SKILL.md +0 -267
  45. package/skills/mom-test/references/avoiding-bad-data.md +0 -221
  46. package/skills/mom-test/references/case-studies.md +0 -306
  47. package/skills/mom-test/references/commitment-advancement.md +0 -219
  48. package/skills/mom-test/references/finding-conversations.md +0 -251
  49. package/skills/mom-test/references/processing-learning.md +0 -256
  50. package/skills/mom-test/references/question-patterns.md +0 -198
  51. package/skills/pandasai-analytics/SKILL.md +0 -251
  52. package/skills/release-it/SKILL.md +0 -235
  53. package/skills/release-it/references/anti-patterns.md +0 -279
  54. package/skills/release-it/references/capacity-planning.md +0 -285
  55. package/skills/release-it/references/chaos-engineering.md +0 -325
  56. package/skills/release-it/references/deployment-strategies.md +0 -331
  57. package/skills/release-it/references/observability.md +0 -301
  58. package/skills/release-it/references/stability-patterns.md +0 -355
  59. package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +0 -37
  60. package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +0 -34
  61. package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +0 -51
  62. package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +0 -39
  63. package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +0 -52
  64. package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +0 -25
  65. package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +0 -31
  66. package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +0 -25
  67. package/skills/skill-creator-ultra/README.md +0 -1242
  68. package/skills/skill-creator-ultra/SKILL.md +0 -388
  69. package/skills/skill-creator-ultra/agents/analyzer.md +0 -274
  70. package/skills/skill-creator-ultra/agents/comparator.md +0 -202
  71. package/skills/skill-creator-ultra/agents/grader.md +0 -223
  72. package/skills/skill-creator-ultra/assets/eval_review.html +0 -146
  73. package/skills/skill-creator-ultra/eval-viewer/generate_review.py +0 -471
  74. package/skills/skill-creator-ultra/eval-viewer/viewer.html +0 -1325
  75. package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +0 -109
  76. package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +0 -116
  77. package/skills/skill-creator-ultra/examples/example_api_docs.md +0 -189
  78. package/skills/skill-creator-ultra/examples/example_db_migration.md +0 -253
  79. package/skills/skill-creator-ultra/examples/example_git_commit.md +0 -111
  80. package/skills/skill-creator-ultra/install.ps1 +0 -289
  81. package/skills/skill-creator-ultra/install.sh +0 -313
  82. package/skills/skill-creator-ultra/phases/phase1_interview.md +0 -202
  83. package/skills/skill-creator-ultra/phases/phase2_extract.md +0 -55
  84. package/skills/skill-creator-ultra/phases/phase3_detect.md +0 -57
  85. package/skills/skill-creator-ultra/phases/phase4_generate.md +0 -543
  86. package/skills/skill-creator-ultra/phases/phase5_test.md +0 -319
  87. package/skills/skill-creator-ultra/phases/phase6_eval.md +0 -301
  88. package/skills/skill-creator-ultra/phases/phase7_iterate.md +0 -103
  89. package/skills/skill-creator-ultra/phases/phase8_optimize.md +0 -113
  90. package/skills/skill-creator-ultra/resources/advanced_patterns.md +0 -499
  91. package/skills/skill-creator-ultra/resources/anti_patterns.md +0 -376
  92. package/skills/skill-creator-ultra/resources/blueprints.md +0 -498
  93. package/skills/skill-creator-ultra/resources/checklist.md +0 -243
  94. package/skills/skill-creator-ultra/resources/composition_cookbook.md +0 -291
  95. package/skills/skill-creator-ultra/resources/description_optimization.md +0 -90
  96. package/skills/skill-creator-ultra/resources/eval_guide.md +0 -133
  97. package/skills/skill-creator-ultra/resources/industry_questions.md +0 -189
  98. package/skills/skill-creator-ultra/resources/interview_questions.md +0 -200
  99. package/skills/skill-creator-ultra/resources/pattern_detection.md +0 -200
  100. package/skills/skill-creator-ultra/resources/prompt_engineering.md +0 -531
  101. package/skills/skill-creator-ultra/resources/schemas.md +0 -430
  102. package/skills/skill-creator-ultra/resources/script_integration.md +0 -593
  103. package/skills/skill-creator-ultra/resources/scripts_guide.md +0 -339
  104. package/skills/skill-creator-ultra/resources/skill_template.md +0 -124
  105. package/skills/skill-creator-ultra/resources/skill_writing_guide.md +0 -634
  106. package/skills/skill-creator-ultra/resources/versioning_guide.md +0 -193
  107. package/skills/skill-creator-ultra/scripts/ci_eval.py +0 -200
  108. package/skills/skill-creator-ultra/scripts/package_skill.py +0 -165
  109. package/skills/skill-creator-ultra/scripts/simulate_skill.py +0 -398
  110. package/skills/skill-creator-ultra/scripts/skill_audit.py +0 -611
  111. package/skills/skill-creator-ultra/scripts/skill_compare.py +0 -265
  112. package/skills/skill-creator-ultra/scripts/skill_export.py +0 -334
  113. package/skills/skill-creator-ultra/scripts/skill_scaffold.py +0 -403
  114. package/skills/skill-creator-ultra/scripts/skill_stats.py +0 -339
  115. package/skills/skill-creator-ultra/scripts/validate_skill.py +0 -411
  116. package/skills/tailwind-mastery/SKILL.md +0 -229
  117. package/skills/vercel-react-best-practices/AGENTS.md +0 -3373
  118. package/skills/vercel-react-best-practices/README.md +0 -123
  119. package/skills/vercel-react-best-practices/SKILL.md +0 -143
  120. package/skills/vercel-react-best-practices/rules/_sections.md +0 -46
  121. package/skills/vercel-react-best-practices/rules/_template.md +0 -28
  122. package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  123. package/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  124. package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  125. package/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  126. package/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  127. package/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  128. package/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  129. package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  130. package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  131. package/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  132. package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  133. package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  134. package/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  135. package/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  136. package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  137. package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  138. package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  139. package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  140. package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  141. package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  142. package/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  143. package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  144. package/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  145. package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  146. package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  147. package/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  148. package/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  149. package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  150. package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  151. package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  152. package/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  153. package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  154. package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  155. package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  156. package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  157. package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  158. package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  159. package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  160. package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  161. package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  162. package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  163. package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  164. package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  165. package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  166. package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  167. package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  168. package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  169. package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  170. package/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  171. package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  172. package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  173. package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  174. package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
  175. package/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  176. package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
  177. package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  178. package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  179. package/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  180. package/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  181. package/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  182. package/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  183. package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
  184. package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  185. package/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  186. package/skills/web-design-guidelines/SKILL.md +0 -39
@@ -1,411 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- validate_skill.py — Kiểm tra tính hợp lệ của file SKILL.md
4
-
5
- Sử dụng:
6
- python validate_skill.py /path/to/SKILL.md
7
- python validate_skill.py /path/to/skill-folder/
8
-
9
- Script sẽ kiểm tra:
10
- 1. YAML frontmatter có hợp lệ không
11
- 2. Có đầy đủ các section bắt buộc không (Goal, Instructions)
12
- 3. Có Examples không (khuyến khích mạnh)
13
- 4. Có Constraints không (khuyến khích)
14
- 5. Description có đủ chi tiết không
15
- 6. Cấu trúc thư mục có chuẩn không
16
- """
17
-
18
- import sys
19
- import os
20
- import re
21
- from pathlib import Path
22
-
23
-
24
- # ============================================================
25
- # CONSTANTS
26
- # ============================================================
27
-
28
- REQUIRED_SECTIONS = ['goal', 'instructions']
29
- RECOMMENDED_SECTIONS = ['examples', 'constraints']
30
- MIN_DESCRIPTION_LENGTH = 30 # Ký tự tối thiểu cho description
31
- MIN_DESCRIPTION_WORDS = 5 # Từ tối thiểu cho description
32
- MAX_SKILL_NAME_LENGTH = 50 # Ký tự tối đa cho tên skill
33
- VALID_SUBFOLDERS = {'scripts', 'resources', 'examples'}
34
-
35
-
36
- # ============================================================
37
- # COLOR OUTPUT (Windows + Unix compatible)
38
- # ============================================================
39
-
40
- class Colors:
41
- """ANSI color codes cho terminal output."""
42
- PASS = '\033[92m' # Green
43
- FAIL = '\033[91m' # Red
44
- WARN = '\033[93m' # Yellow
45
- INFO = '\033[96m' # Cyan
46
- BOLD = '\033[1m'
47
- RESET = '\033[0m'
48
-
49
- @staticmethod
50
- def enable_windows():
51
- """Bật ANSI colors cho Windows terminal."""
52
- if os.name == 'nt':
53
- try:
54
- import ctypes
55
- kernel32 = ctypes.windll.kernel32
56
- kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
57
- except Exception:
58
- pass
59
-
60
-
61
- def print_result(status, message):
62
- """In kết quả kiểm tra với màu sắc."""
63
- if status == 'PASS':
64
- icon = f"{Colors.PASS}✅ PASS{Colors.RESET}"
65
- elif status == 'FAIL':
66
- icon = f"{Colors.FAIL}❌ FAIL{Colors.RESET}"
67
- elif status == 'WARN':
68
- icon = f"{Colors.WARN}⚠️ WARN{Colors.RESET}"
69
- else:
70
- icon = f"{Colors.INFO}ℹ️ INFO{Colors.RESET}"
71
-
72
- print(f" {icon} {message}")
73
-
74
-
75
- # ============================================================
76
- # YAML FRONTMATTER PARSER
77
- # ============================================================
78
-
79
- def parse_frontmatter(content):
80
- """
81
- Trích xuất YAML frontmatter từ nội dung SKILL.md.
82
-
83
- Returns:
84
- tuple: (frontmatter_dict, body_content) hoặc (None, content) nếu không có frontmatter
85
- """
86
- # Tìm YAML frontmatter (giữa 2 dấu ---)
87
- pattern = r'^---\s*\n(.*?)\n---\s*\n(.*)$'
88
- match = re.match(pattern, content, re.DOTALL)
89
-
90
- if not match:
91
- return None, content
92
-
93
- yaml_content = match.group(1)
94
- body = match.group(2)
95
-
96
- # Parse YAML đơn giản (hỗ trợ multi-line block scalar `|` và `>`)
97
- frontmatter = {}
98
- lines = yaml_content.strip().split('\n')
99
- i = 0
100
- while i < len(lines):
101
- line = lines[i]
102
- stripped = line.strip()
103
- if ':' in stripped and not stripped.startswith('#'):
104
- key, _, value = stripped.partition(':')
105
- key = key.strip()
106
- value = value.strip().strip('"').strip("'")
107
-
108
- # Xử lý multi-line block scalar (| hoặc >)
109
- if value in ('|', '>', '|+', '|-', '>+', '>-'):
110
- multi_lines = []
111
- i += 1
112
- while i < len(lines):
113
- next_line = lines[i]
114
- # Dòng tiếp theo phải có indent (bắt đầu bằng space/tab)
115
- if next_line and (next_line[0] == ' ' or next_line[0] == '\t'):
116
- multi_lines.append(next_line.strip())
117
- i += 1
118
- else:
119
- break
120
- value = ' '.join(multi_lines)
121
-
122
- frontmatter[key] = value
123
- i += 1
124
-
125
- return frontmatter, body
126
-
127
-
128
- def find_sections(body):
129
- """
130
- Tìm tất cả heading sections (# Level 1) trong body.
131
- Bỏ qua headings nằm trong fenced code blocks (``` ... ```).
132
-
133
- Returns:
134
- dict: {section_name_lowercase: section_content}
135
- """
136
- sections = {}
137
- current_section = None
138
- current_content = []
139
- in_code_block = False
140
-
141
- for line in body.split('\n'):
142
- stripped = line.strip()
143
-
144
- # Phát hiện bắt đầu/kết thúc code block
145
- if stripped.startswith('```'):
146
- in_code_block = not in_code_block
147
- current_content.append(line)
148
- continue
149
-
150
- # Bỏ qua headings trong code block
151
- if in_code_block:
152
- current_content.append(line)
153
- continue
154
-
155
- # Tìm heading level 1 (# Title)
156
- heading_match = re.match(r'^#\s+(.+)$', stripped)
157
- if heading_match:
158
- # Lưu section trước
159
- if current_section:
160
- sections[current_section] = '\n'.join(current_content)
161
- current_section = heading_match.group(1).strip().lower()
162
- current_content = []
163
- else:
164
- current_content.append(line)
165
-
166
- # Lưu section cuối cùng
167
- if current_section:
168
- sections[current_section] = '\n'.join(current_content)
169
-
170
- return sections
171
-
172
-
173
- def count_examples(body):
174
- """Đếm số ví dụ (heading ## Ví dụ hoặc ## Example). Bỏ qua code blocks."""
175
- # Xóa nội dung trong code blocks trước khi đếm
176
- clean_body = re.sub(r'```.*?```', '', body, flags=re.DOTALL)
177
- pattern = r'^##\s+(?:Ví dụ|Example)\s*\d*'
178
- return len(re.findall(pattern, clean_body, re.MULTILINE | re.IGNORECASE))
179
-
180
-
181
- def count_constraints(body):
182
- """Đếm số constraint (dòng bắt đầu bằng - KHÔNG ĐƯỢC hoặc - LUÔN LUÔN)."""
183
- pattern = r'^[-*]\s*(?:KHÔNG ĐƯỢC|LUÔN LUÔN|NEVER|ALWAYS|🚫|⚠️)'
184
- return len(re.findall(pattern, body, re.MULTILINE | re.IGNORECASE))
185
-
186
-
187
- # ============================================================
188
- # VALIDATORS
189
- # ============================================================
190
-
191
- def validate_frontmatter(frontmatter):
192
- """Kiểm tra YAML frontmatter."""
193
- results = []
194
-
195
- if frontmatter is None:
196
- results.append(('FAIL', 'Không tìm thấy YAML frontmatter (--- đầu và cuối)'))
197
- return results, False
198
-
199
- results.append(('PASS', 'YAML frontmatter hợp lệ'))
200
-
201
- # Check description (BẮT BUỘC)
202
- desc = frontmatter.get('description', '')
203
- if not desc:
204
- results.append(('FAIL', 'Thiếu trường `description` — Đây là phần QUAN TRỌNG NHẤT'))
205
- elif len(desc) < MIN_DESCRIPTION_LENGTH:
206
- results.append(('WARN', f'Description quá ngắn ({len(desc)} ký tự) — Nên ≥{MIN_DESCRIPTION_LENGTH} ký tự'))
207
- elif len(desc.split()) < MIN_DESCRIPTION_WORDS:
208
- results.append(('WARN', f'Description quá ít từ ({len(desc.split())} từ) — Nên ≥{MIN_DESCRIPTION_WORDS} từ'))
209
- else:
210
- results.append(('PASS', f'Description đầy đủ ({len(desc)} ký tự, {len(desc.split())} từ)'))
211
-
212
- # Check name (TÙY CHỌN)
213
- name = frontmatter.get('name', '')
214
- if name:
215
- if ' ' in name or any(c.isupper() for c in name):
216
- results.append(('WARN', f'Tên skill `{name}` nên dùng kebab-case (vd: my-skill-name)'))
217
- elif len(name) > MAX_SKILL_NAME_LENGTH:
218
- results.append(('WARN', f'Tên skill quá dài ({len(name)} ký tự) — Nên ≤{MAX_SKILL_NAME_LENGTH}'))
219
- else:
220
- results.append(('PASS', f'Tên skill: `{name}` (hợp lệ)'))
221
- else:
222
- results.append(('INFO', 'Không có trường `name` — AI sẽ dùng tên thư mục'))
223
-
224
- return results, True
225
-
226
-
227
- def validate_sections(sections, body):
228
- """Kiểm tra các sections bắt buộc và khuyến khích."""
229
- results = []
230
-
231
- # Check required sections
232
- for section in REQUIRED_SECTIONS:
233
- found = any(section in key for key in sections.keys())
234
- if found:
235
- results.append(('PASS', f'Có section `# {section.title()}`'))
236
- else:
237
- results.append(('FAIL', f'Thiếu section bắt buộc `# {section.title()}`'))
238
-
239
- # Check recommended sections
240
- for section in RECOMMENDED_SECTIONS:
241
- found = any(section in key for key in sections.keys())
242
- if found:
243
- results.append(('PASS', f'Có section `# {section.title()}`'))
244
- else:
245
- results.append(('WARN', f'Thiếu section khuyến khích `# {section.title()}`'))
246
-
247
- # Check examples count
248
- example_count = count_examples(body)
249
- if example_count >= 2:
250
- results.append(('PASS', f'Có {example_count} ví dụ (đạt chuẩn ≥2)'))
251
- elif example_count == 1:
252
- results.append(('WARN', f'Chỉ có {example_count} ví dụ — Nên có ≥2 ví dụ để giảm hallucination'))
253
- else:
254
- results.append(('WARN', 'Không tìm thấy ví dụ nào — Rất khuyến khích thêm ≥2 ví dụ'))
255
-
256
- # Check constraints count
257
- constraint_count = count_constraints(body)
258
- if constraint_count >= 1:
259
- results.append(('PASS', f'Có {constraint_count} constraint(s)'))
260
- else:
261
- results.append(('WARN', 'Không tìm thấy constraint nào — Nên có ít nhất 1 quy tắc "KHÔNG ĐƯỢC"'))
262
-
263
- return results
264
-
265
-
266
- def validate_directory(skill_dir):
267
- """Kiểm tra cấu trúc thư mục skill."""
268
- results = []
269
- skill_path = Path(skill_dir)
270
-
271
- # Check SKILL.md exists
272
- skill_md = skill_path / 'SKILL.md'
273
- if skill_md.exists():
274
- results.append(('PASS', f'File `SKILL.md` tồn tại ({skill_md.stat().st_size} bytes)'))
275
- else:
276
- results.append(('FAIL', 'Không tìm thấy `SKILL.md` trong thư mục'))
277
- return results, None
278
-
279
- # Check subfolders
280
- for item in skill_path.iterdir():
281
- if item.is_dir():
282
- folder_name = item.name
283
- if folder_name in VALID_SUBFOLDERS:
284
- file_count = len(list(item.rglob('*')))
285
- results.append(('PASS', f'Thư mục `{folder_name}/` ({file_count} items)'))
286
- elif folder_name.startswith('.'):
287
- continue # Bỏ qua hidden folders
288
- else:
289
- results.append(('WARN', f'Thư mục `{folder_name}/` không phải chuẩn (scripts/resources/examples)'))
290
-
291
- return results, skill_md
292
-
293
-
294
- # ============================================================
295
- # MAIN
296
- # ============================================================
297
-
298
- def validate_skill(target_path):
299
- """Chạy toàn bộ kiểm tra cho skill."""
300
- Colors.enable_windows()
301
-
302
- target = Path(target_path)
303
- all_results = []
304
-
305
- print(f"\n{Colors.BOLD}{'='*60}{Colors.RESET}")
306
- print(f"{Colors.BOLD}🔍 SKILL VALIDATOR — Kiểm tra chất lượng AI Skill{Colors.RESET}")
307
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}")
308
- print(f"{Colors.INFO}📁 Target: {target.absolute()}{Colors.RESET}\n")
309
-
310
- # ---- Phần 1: Kiểm tra thư mục (nếu là folder) ----
311
- skill_md_path = None
312
-
313
- if target.is_dir():
314
- print(f"{Colors.BOLD}📂 Kiểm tra cấu trúc thư mục:{Colors.RESET}")
315
- dir_results, skill_md_path = validate_directory(target)
316
- all_results.extend(dir_results)
317
- for status, msg in dir_results:
318
- print_result(status, msg)
319
- print()
320
-
321
- if skill_md_path is None:
322
- print(f"\n{Colors.FAIL}💀 KHÔNG THỂ TIẾP TỤC — Thiếu SKILL.md{Colors.RESET}\n")
323
- return False
324
- elif target.is_file() and target.name == 'SKILL.md':
325
- skill_md_path = target
326
- else:
327
- print(f"{Colors.FAIL}❌ Target phải là thư mục skill hoặc file SKILL.md{Colors.RESET}")
328
- return False
329
-
330
- # ---- Phần 2: Đọc và parse SKILL.md ----
331
- try:
332
- content = skill_md_path.read_text(encoding='utf-8')
333
- except UnicodeDecodeError:
334
- content = skill_md_path.read_text(encoding='utf-8', errors='ignore')
335
-
336
- frontmatter, body = parse_frontmatter(content)
337
- sections = find_sections(body)
338
-
339
- # ---- Phần 3: Kiểm tra frontmatter ----
340
- print(f"{Colors.BOLD}📝 Kiểm tra YAML Frontmatter:{Colors.RESET}")
341
- fm_results, fm_valid = validate_frontmatter(frontmatter)
342
- all_results.extend(fm_results)
343
- for status, msg in fm_results:
344
- print_result(status, msg)
345
- print()
346
-
347
- # ---- Phần 4: Kiểm tra sections ----
348
- print(f"{Colors.BOLD}📋 Kiểm tra nội dung Sections:{Colors.RESET}")
349
- sec_results = validate_sections(sections, body)
350
- all_results.extend(sec_results)
351
- for status, msg in sec_results:
352
- print_result(status, msg)
353
- print()
354
-
355
- # ---- Phần 5: Thống kê ----
356
- total_lines = len(content.split('\n'))
357
- total_words = len(content.split())
358
-
359
- print(f"{Colors.BOLD}📊 Thống kê:{Colors.RESET}")
360
- print_result('INFO', f'Tổng: {total_lines} dòng, {total_words} từ, {len(content)} bytes')
361
- print_result('INFO', f'Sections tìm thấy: {", ".join(sections.keys()) if sections else "(không có)"}')
362
- print()
363
-
364
- # ---- Phần 6: Tổng kết ----
365
- fails = sum(1 for s, _ in all_results if s == 'FAIL')
366
- warns = sum(1 for s, _ in all_results if s == 'WARN')
367
- passes = sum(1 for s, _ in all_results if s == 'PASS')
368
-
369
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}")
370
- print(f"{Colors.BOLD}📋 KẾT QUẢ:{Colors.RESET}")
371
- print(f" {Colors.PASS}✅ PASS: {passes}{Colors.RESET}")
372
- print(f" {Colors.WARN}⚠️ WARN: {warns}{Colors.RESET}")
373
- print(f" {Colors.FAIL}❌ FAIL: {fails}{Colors.RESET}")
374
-
375
- if fails == 0 and warns == 0:
376
- print(f"\n {Colors.PASS}{Colors.BOLD}🎉 TUYỆT VỜI! Skill đạt chuẩn hoàn hảo!{Colors.RESET}")
377
- grade = 'A+'
378
- elif fails == 0 and warns <= 2:
379
- print(f"\n {Colors.PASS}{Colors.BOLD}👍 TỐT! Skill hợp lệ, có thể cải thiện thêm.{Colors.RESET}")
380
- grade = 'A'
381
- elif fails == 0:
382
- print(f"\n {Colors.WARN}{Colors.BOLD}⚠️ ĐẠT! Nhưng nên sửa các cảnh báo.{Colors.RESET}")
383
- grade = 'B'
384
- elif fails <= 2:
385
- print(f"\n {Colors.FAIL}{Colors.BOLD}❌ CHƯA ĐẠT! Cần sửa {fails} lỗi.{Colors.RESET}")
386
- grade = 'C'
387
- else:
388
- print(f"\n {Colors.FAIL}{Colors.BOLD}💀 KHÔNG ĐẠT! Cần sửa {fails} lỗi nghiêm trọng.{Colors.RESET}")
389
- grade = 'F'
390
-
391
- print(f"\n {Colors.BOLD}📊 Grade: {grade}{Colors.RESET}")
392
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}\n")
393
-
394
- return fails == 0
395
-
396
-
397
- if __name__ == '__main__':
398
- if len(sys.argv) < 2:
399
- print("Sử dụng: python validate_skill.py <path-to-SKILL.md-or-skill-folder>")
400
- print("Ví dụ: python validate_skill.py ./my-skill/")
401
- print(" python validate_skill.py ./my-skill/SKILL.md")
402
- sys.exit(1)
403
-
404
- target = sys.argv[1]
405
-
406
- if not os.path.exists(target):
407
- print(f"❌ Không tìm thấy: {target}")
408
- sys.exit(1)
409
-
410
- success = validate_skill(target)
411
- sys.exit(0 if success else 1)
@@ -1,229 +0,0 @@
1
- ---
2
- name: tailwind-mastery
3
- description: 'Master Tailwind CSS utilities, responsive design, and accessibility patterns. Use when the user mentions "Tailwind", "Tailwind CSS", "utility-first", "responsive design", "dark mode", "focus-visible", "motion-reduce", or "Tailwind v4". Covers utility patterns, layout, responsive design, components, accessibility, and performance. For React styling, see react-mastery. For design systems, see refactoring-ui.'
4
- license: MIT
5
- metadata:
6
- author: todyle
7
- version: "1.0.0"
8
- ---
9
-
10
- # Tailwind CSS Mastery Framework
11
-
12
- A comprehensive guide to building production UIs with Tailwind CSS utilities, responsive patterns, accessibility, and performance optimization. Apply these principles when styling web applications, building component libraries, implementing dark mode, or optimizing CSS output.
13
-
14
- ## Core Principle
15
-
16
- **Utility-first CSS means composing designs directly in HTML with small, single-purpose classes.** Instead of writing custom CSS for every component, you combine utilities (`flex`, `items-center`, `p-4`, `text-lg`) to build designs. This eliminates naming fatigue, CSS specificity wars, and dead CSS. Every class you see describes exactly what it does.
17
-
18
- **The foundation:** Tailwind works because most CSS is repeated — the same spacing, colors, and typography patterns appear throughout an application. Utilities express these patterns directly. The build tool strips unused classes, resulting in tiny production CSS. The key is working within Tailwind's design system (spacing scale, color palette, breakpoints) rather than escaping it with arbitrary values.
19
-
20
- ## Scoring
21
-
22
- **Goal: 10/10.** When reviewing Tailwind code, rate 0-10:
23
-
24
- - **9-10:** Mobile-first responsive, dark mode, focus-visible, motion-reduce, semantic color naming, consistent spacing scale
25
- - **7-8:** Good utility usage with minor issues (arbitrary values for scale values, missing dark mode, inconsistent spacing)
26
- - **5-6:** Working styles but overusing @apply, arbitrary values abundant, no responsive design
27
- - **3-4:** Tailwind as CSS-in-HTML (every value arbitrary), no dark mode, no accessibility
28
- - **1-2:** Fighting Tailwind with custom CSS, important! everywhere, no design system
29
-
30
- ## The Tailwind Mastery Framework
31
-
32
- Six disciplines for production Tailwind CSS:
33
-
34
- ### 1. Utility Patterns & Design System
35
-
36
- **Core concept:** Use Tailwind's design tokens (spacing scale, color palette, font sizes) instead of arbitrary values. The spacing scale (4px increments: `p-1`=4px, `p-2`=8px, `p-4`=16px) creates visual consistency. Extend the design system via `tailwind.config.js` for brand colors, not with arbitrary `[]` values.
37
-
38
- **Why it works:** Constraints breed consistency. When everyone uses `gap-4` instead of `gap-[15px]`, spacing is uniform across the entire application. The predefined scale means fewer design decisions and faster development. Custom theme values (`bg-primary`, `text-success`) encode brand semantics.
39
-
40
- **Key insights:**
41
- - Spacing scale: `p-1`=4px, `p-2`=8px, `p-4`=16px, `p-6`=24px, `p-8`=32px
42
- - Use scale values over arbitrary: `gap-6` not `gap-[23px]`
43
- - Color opacity: `bg-black/50` (50% opacity) instead of separate `opacity-50`
44
- - `space-y-4` for vertical lists — adds margin between children
45
- - `size-6` shorthand for equal width+height (Tailwind v4)
46
- - `shrink-0` shorthand (v4) instead of `flex-shrink-0`
47
- - Extend theme for brand colors: `bg-primary`, `text-cta`, `border-success`
48
- - `bg-linear-to-r` (v4) replaces `bg-gradient-to-r`
49
-
50
- **Code applications:**
51
-
52
- | Context | Pattern | Example |
53
- |---------|---------|---------|
54
- | **Spacing** | Scale values | `p-4 m-6 gap-8` |
55
- | **Color opacity** | Slash syntax | `bg-black/50 text-white/80` |
56
- | **List spacing** | space-y | `<div class="space-y-4">` |
57
- | **Brand color** | Theme extend | `bg-primary text-on-primary` |
58
- | **Square element** | size utility | `size-8` (= `h-8 w-8`) |
59
- | **Gradient** | bg-linear (v4) | `bg-linear-to-r from-blue-500 to-purple-500` |
60
-
61
- ### 2. Layout
62
-
63
- **Core concept:** Container with `max-w-7xl mx-auto` for content width. `flex` for one-dimensional, `grid` for two-dimensional layouts. Responsive padding `px-4 md:px-6 lg:px-8`. Container queries `@container` for component-level responsiveness.
64
-
65
- **Why it works:** `max-w-7xl mx-auto` prevents content from stretching to unreadable widths on large screens. `gap-*` replaces manual margins on grid/flex children, simplifying layout code. Container queries enable components to respond to their container size rather than the viewport — essential for reusable components.
66
-
67
- **Key insights:**
68
- - `max-w-7xl mx-auto px-4` for main content container
69
- - `flex items-center justify-between` — most common header pattern
70
- - `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6` for responsive grid
71
- - `gap-*` on flex/grid containers, not margins on children
72
- - Responsive padding: `px-4 sm:px-6 lg:px-8`
73
- - `@container` + `@lg:grid-cols-2` for component-level responsive (v3.2+)
74
- - Negative margins sparingly: `-mt-8` for intentional overlapping effects
75
-
76
- **Code applications:**
77
-
78
- | Context | Pattern | Example |
79
- |---------|---------|---------|
80
- | **Container** | max-w + padding | `<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">` |
81
- | **Flex row** | items-center | `<nav class="flex items-center justify-between h-16">` |
82
- | **Grid** | Responsive cols | `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">` |
83
- | **Container query** | @container | `<div class="@container"><div class="@lg:grid-cols-2">` |
84
-
85
- ### 3. Responsive Design
86
-
87
- **Core concept:** Mobile-first — write base styles for mobile, add breakpoints for larger screens via `sm:`, `md:`, `lg:`, `xl:`, `2xl:` prefixes. Test at all breakpoints: 320, 375, 768, 1024, 1280, 1536px. Use `hidden md:block` for visibility control.
88
-
89
- **Why it works:** Mobile-first ensures the smallest, most constrained screens get attention first. Adding complexity for larger screens is natural — hiding sidebar on mobile, showing it on desktop. This approach also results in smaller CSS because mobile styles don't need breakpoint prefixes.
90
-
91
- **Key insights:**
92
- - Base styles = mobile. Breakpoints add desktop enhancements
93
- - `text-sm md:text-base lg:text-lg` — progressive text sizing
94
- - `hidden md:flex` — hide on mobile, show on desktop
95
- - `flex-col md:flex-row` — stack on mobile, row on desktop
96
- - Test at 320px (smallest iPhone SE) — don't ignore small screens
97
- - `aspect-video` with `object-cover` for responsive media
98
- - `srcset` with `sizes` attribute for responsive images (HTML, not Tailwind)
99
-
100
- **Code applications:**
101
-
102
- | Context | Pattern | Example |
103
- |---------|---------|---------|
104
- | **Mobile-first** | Base + breakpoint | `<h1 class="text-2xl md:text-4xl lg:text-5xl">` |
105
- | **Show/hide** | hidden + display | `<nav class="hidden md:flex">` (mobile menu alternative) |
106
- | **Stack → row** | Direction change | `<div class="flex flex-col md:flex-row gap-4">` |
107
- | **Responsive image** | aspect + object | `<img class="aspect-video object-cover w-full rounded-xl">` |
108
- | **Responsive padding** | Breakpoint padding | `<main class="px-4 sm:px-6 lg:px-8">` |
109
-
110
- ### 4. Components
111
-
112
- **Core concept:** Buttons need consistent sizing (`px-4 py-2`), minimum touch targets on mobile (`min-h-[44px]`), loading states, and proper icon button labels. Cards use `rounded-lg shadow-md` with hover feedback. Forms need visible focus indicators (`focus:ring-2`), disabled states, and keyboard accessibility.
113
-
114
- **Why it works:** Consistency in component sizing creates visual rhythm. Touch targets of 44px minimum (Apple HIG standard) prevent frustrating tap misses on mobile. Focus indicators are essential for keyboard navigation and WCAG compliance. Interactive elements must provide feedback — hover, focus, active, disabled states.
115
-
116
- **Key insights:**
117
- - Buttons: `px-4 py-2 rounded-lg font-medium transition-colors`
118
- - Touch targets: `min-h-[44px] min-w-[44px]` on all interactive mobile elements
119
- - Loading button: `disabled + opacity-50 + spinner icon`
120
- - Cards: `rounded-2xl shadow-lg p-6 hover:shadow-xl transition-shadow`
121
- - Inputs: `h-10 w-full px-3 rounded-md border focus:ring-2 focus:ring-blue-500`
122
- - Disabled: `disabled:opacity-50 disabled:cursor-not-allowed`
123
- - Icon buttons: always include `aria-label`
124
-
125
- **Code applications:**
126
-
127
- | Context | Pattern | Example |
128
- |---------|---------|---------|
129
- | **Button** | Standard | `<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">` |
130
- | **Touch target** | Mobile minimum | `<button class="min-h-[44px] min-w-[44px]">` |
131
- | **Card** | Hover feedback | `<div class="rounded-2xl shadow-lg p-6 hover:shadow-xl transition-shadow">` |
132
- | **Input** | Focus ring | `<input class="h-10 px-3 rounded-md border focus:ring-2 focus:ring-blue-500">` |
133
- | **Disabled** | Opacity + cursor | `<button disabled class="disabled:opacity-50 disabled:cursor-not-allowed">` |
134
- | **Icon button** | aria-label | `<button aria-label="Close"><XIcon class="size-5"/></button>` |
135
-
136
- ### 5. Accessibility
137
-
138
- **Core concept:** `sr-only` for screen reader text, `focus-visible:ring-2` for keyboard-only focus indicators, `motion-reduce:animate-none` for motion sensitivity, semantic HTML always. Accessibility is not optional — it's a legal requirement in many jurisdictions.
139
-
140
- **Why it works:** `focus-visible` shows focus rings only for keyboard users (not mouse clicks), improving both aesthetics and accessibility. `motion-reduce` respects OS-level reduced motion preferences — essential for users with vestibular disorders. `sr-only` provides context to screen readers without affecting visual design.
141
-
142
- **Key insights:**
143
- - `sr-only` for text visible only to screen readers
144
- - `focus-visible:ring-2` instead of `focus:ring-2` — keyboard-only focus
145
- - `motion-reduce:animate-none` respects prefers-reduced-motion
146
- - `motion-reduce:transition-none` for transition-heavy components
147
- - Never `outline-none` without a replacement focus indicator
148
- - Always `aria-label` on icon-only buttons
149
- - Dark mode: `dark:bg-gray-900 dark:text-gray-100` — ensure sufficient contrast
150
- - SVG explicit dimensions: `<svg class="size-6" width="24" height="24">` to prevent layout shift
151
-
152
- **Code applications:**
153
-
154
- | Context | Pattern | Example |
155
- |---------|---------|---------|
156
- | **Screen reader** | sr-only | `<span class="sr-only">Close menu</span>` |
157
- | **Keyboard focus** | focus-visible | `<button class="focus-visible:ring-2 focus-visible:ring-blue-500">` |
158
- | **Reduced motion** | motion-reduce | `<div class="animate-pulse motion-reduce:animate-none">` |
159
- | **Dark mode** | dark: prefix | `<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">` |
160
- | **Icon a11y** | aria-label | `<button aria-label="Delete item"><TrashIcon class="size-5"/></button>` |
161
- | **SVG dims** | Explicit w/h | `<svg class="size-6" width="24" height="24">` |
162
-
163
- ### 6. Performance & Configuration
164
-
165
- **Core concept:** Configure `content` paths correctly so Tailwind can tree-shake unused classes. Avoid overusing `@apply` — it defeats the purpose of utility-first CSS. Use JIT mode (default in v3+) for development performance. Custom utilities in theme config for repeated one-off values.
166
-
167
- **Why it works:** Tailwind's production CSS is tiny because it only includes classes actually used in your source files. Incorrect `content` configuration results in either missing styles (too narrow) or bloated CSS (too broad). `@apply` creates abstraction layers that Tailwind's utility-first approach was designed to eliminate.
168
-
169
- **Key insights:**
170
- - `content: ['./src/**/*.{js,ts,jsx,tsx}']` — must cover all template files
171
- - `@apply` sparingly — prefer direct utilities in HTML/JSX
172
- - Custom utilities in `tailwind.config.js` for repeated arbitrary values
173
- - `@tailwindcss/forms` for consistent form element reset
174
- - `@tailwindcss/typography` (`prose`) for markdown/CMS content
175
- - Group and Peer for parent/sibling state: `group-hover:text-blue-500`
176
- - `peer-checked:bg-blue-100` for checkbox/radio state styling
177
-
178
- **Code applications:**
179
-
180
- | Context | Pattern | Example |
181
- |---------|---------|---------|
182
- | **Content config** | Glob patterns | `content: ['./src/**/*.{js,ts,jsx,tsx,html}']` |
183
- | **Custom utility** | Theme extend | `extend: { boxShadow: { card: '0 4px 20px rgba(0,0,0,.08)' } }` |
184
- | **Plugin** | Official | `plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')]` |
185
- | **Group hover** | Parent state | `<div class="group"><span class="group-hover:text-blue-500">` |
186
- | **Peer** | Sibling state | `<input class="peer"><label class="peer-checked:font-bold">` |
187
- | **Prose** | Typography | `<article class="prose prose-lg max-w-none dark:prose-invert">` |
188
-
189
- ## Common Mistakes
190
-
191
- | Mistake | Why It Fails | Fix |
192
- |---------|-------------|-----|
193
- | **Arbitrary values for scale values** | Inconsistent spacing/sizing | Use `p-4` not `p-[15px]` |
194
- | **Heavy @apply usage** | Creates CSS abstractions that defeat utility-first | Use utilities directly in HTML |
195
- | **No dark mode** | Poor UX in low-light, not respecting OS preference | Add `dark:` variants |
196
- | **outline-none without replacement** | Keyboard users can't see focus | `focus-visible:ring-2` |
197
- | **No motion-reduce** | Harms vestibular disorder users | `motion-reduce:animate-none` |
198
- | **Small touch targets** | Frustrating mobile experience | `min-h-[44px]` minimum |
199
- | **Missing content paths** | Styles missing in production | Verify all template file paths |
200
- | **Desktop-first approach** | Complex mobile overrides | Start with mobile, add `md:` `lg:` |
201
- | **bg-gradient-to in v4** | Deprecated syntax | Use `bg-linear-to-r` in Tailwind v4 |
202
- | **SVGs without explicit dimensions** | Layout shift before CSS loads | Add `width` and `height` attributes |
203
-
204
- ## Quick Diagnostic
205
-
206
- | Question | If No | Action |
207
- |----------|-------|--------|
208
- | Using Tailwind's spacing scale? | Inconsistent spacing | Replace arbitrary values with scale tokens |
209
- | Mobile-first responsive? | Complex overrides | Start with mobile base, add breakpoints |
210
- | Dark mode implemented? | Missing OS preference respect | Add `dark:` variants for all colors |
211
- | Focus indicators visible? | Keyboard a11y broken | Add `focus-visible:ring-2` |
212
- | Motion preferences respected? | A11y violation | Add `motion-reduce:` variants |
213
- | Touch targets ≥44px? | Mobile tap frustration | Add `min-h-[44px]` |
214
- | Content paths correct? | Missing production styles | Audit tailwind.config.js content |
215
- | Using semantic colors? | Hard to rebrand | Move to `bg-primary` theme tokens |
216
- | Icon buttons labeled? | Screen reader fails | Add `aria-label` to all icon buttons |
217
- | SVGs have explicit dimensions? | Layout shift | Add `width` and `height` attributes |
218
-
219
- ## Further Reading
220
-
221
- - [Tailwind CSS Documentation](https://tailwindcss.com/docs) — Official reference
222
- - [Tailwind CSS v4 Migration](https://tailwindcss.com/docs/upgrade-guide) — v3 to v4 changes
223
- - [Refactoring UI](https://www.refactoringui.com/) — Design principles from Tailwind creators
224
- - [@tailwindcss/typography](https://tailwindcss.com/docs/typography-plugin) — Prose styling
225
- - [Heroicons](https://heroicons.com/) — SVG icons from Tailwind Labs
226
-
227
- ## About
228
-
229
- This skill synthesizes patterns from Adam Wathan (Tailwind creator), Steve Schoger (Refactoring UI), and the Tailwind CSS community. For visual design principles, see refactoring-ui. For top-tier web design, see top-design. For React integration, see react-mastery.