@qijenchen/design-system 0.1.0-beta.10 → 0.1.0-beta.13

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 (307) hide show
  1. package/CLAUDE.md +201 -0
  2. package/README.md +7 -15
  3. package/cli-init.mjs +90 -0
  4. package/ds-canonical/commands/README.md +26 -0
  5. package/ds-canonical/commands/gov-status.md +79 -0
  6. package/ds-canonical/hooks/README.md +145 -0
  7. package/ds-canonical/hooks/_log-fire.sh +44 -0
  8. package/ds-canonical/hooks/block_prototype_imports.py +111 -0
  9. package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
  10. package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
  11. package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
  12. package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
  13. package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
  14. package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
  15. package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
  16. package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
  17. package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
  18. package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
  19. package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
  20. package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
  21. package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
  22. package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
  23. package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
  24. package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
  25. package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
  26. package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
  27. package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
  28. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
  29. package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
  30. package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
  31. package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
  32. package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
  33. package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
  34. package/ds-canonical/hooks/check_story_invariants.sh +612 -0
  35. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
  36. package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
  37. package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
  38. package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
  39. package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
  40. package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
  41. package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
  42. package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
  43. package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
  44. package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
  45. package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
  46. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
  47. package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
  48. package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
  49. package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
  50. package/ds-canonical/hooks/log_governance_fires.sh +50 -0
  51. package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
  52. package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
  53. package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
  54. package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
  55. package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
  56. package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
  57. package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
  58. package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
  59. package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
  60. package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
  61. package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
  62. package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
  63. package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
  64. package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
  65. package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
  66. package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
  67. package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
  68. package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
  69. package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
  70. package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
  71. package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
  72. package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
  73. package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
  74. package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
  75. package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
  76. package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
  77. package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
  78. package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
  79. package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
  80. package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
  81. package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
  82. package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
  83. package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
  84. package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
  85. package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
  86. package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
  87. package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
  88. package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
  89. package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
  90. package/ds-canonical/hooks/stop_self_audit.sh +450 -0
  91. package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
  92. package/ds-canonical/hooks/tests/run-all.sh +76 -0
  93. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
  94. package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
  95. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
  96. package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
  97. package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
  98. package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
  99. package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
  100. package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
  101. package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
  102. package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
  103. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
  104. package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
  105. package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
  106. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
  107. package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
  108. package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
  109. package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
  110. package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
  111. package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
  112. package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
  113. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
  114. package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
  115. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
  116. package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
  117. package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
  118. package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
  119. package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
  120. package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
  121. package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
  122. package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
  123. package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
  124. package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
  125. package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
  126. package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
  127. package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
  128. package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
  129. package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
  130. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
  131. package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
  132. package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
  133. package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
  134. package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
  135. package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
  136. package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
  137. package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
  138. package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
  139. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
  140. package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
  141. package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
  142. package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
  143. package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
  144. package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
  145. package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
  146. package/ds-canonical/references/README.md +43 -0
  147. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
  148. package/ds-canonical/references/build-ui-canonicals.md +69 -0
  149. package/ds-canonical/references/cva-patterns.md +41 -0
  150. package/ds-canonical/references/drag-canonical.md +331 -0
  151. package/ds-canonical/references/item-anatomy-recipe.md +225 -0
  152. package/ds-canonical/references/naming-conventions.md +56 -0
  153. package/ds-canonical/references/principle-dim-map.json +515 -0
  154. package/ds-canonical/references/props-naming.md +45 -0
  155. package/ds-canonical/references/spec-rules.md +58 -0
  156. package/ds-canonical/references/ssot-consultation.md +63 -0
  157. package/ds-canonical/references/ssot-index.md +40 -0
  158. package/ds-canonical/references/story-baseline-registry.json +79 -0
  159. package/ds-canonical/references/structural-token-retention.md +42 -0
  160. package/ds-canonical/references/tailwind-gotchas.md +87 -0
  161. package/ds-canonical/references/ui-dev-rules.md +60 -0
  162. package/ds-canonical/rules/README.md +34 -0
  163. package/ds-canonical/rules/meta-patterns.md +87 -0
  164. package/ds-canonical/rules/self-verify.md +53 -0
  165. package/ds-canonical/rules/spec-rules.md +25 -0
  166. package/ds-canonical/rules/story-rules.md +56 -0
  167. package/ds-canonical/rules/ui-development.md +87 -0
  168. package/ds-canonical/skills/README.md +88 -0
  169. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
  170. package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
  171. package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
  172. package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
  173. package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
  174. package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
  175. package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
  176. package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
  177. package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
  178. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
  179. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
  180. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
  181. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
  182. package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
  183. package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
  184. package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
  185. package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  186. package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
  187. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
  188. package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
  189. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
  190. package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
  191. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
  192. package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
  193. package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
  194. package/ds-canonical/skills/governance-health/SKILL.md +146 -0
  195. package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
  196. package/ds-canonical/skills/new-component/SKILL.md +170 -0
  197. package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
  198. package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
  199. package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
  200. package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
  201. package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
  202. package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
  203. package/ds-canonical/skills/propose-options/SKILL.md +177 -0
  204. package/ds-canonical/skills/prototype/SKILL.md +244 -0
  205. package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
  206. package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
  207. package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
  208. package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
  209. package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
  210. package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
  211. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
  212. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
  213. package/ds-canonical/skills/story-writing/SKILL.md +122 -0
  214. package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
  215. package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
  216. package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
  217. package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
  218. package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
  219. package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
  220. package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
  221. package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
  222. package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
  223. package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  224. package/package.json +9 -5
  225. package/src/components/Accordion/accordion.spec.md +114 -0
  226. package/src/components/Alert/alert.spec.md +197 -0
  227. package/src/components/AppShell/app-shell.spec.md +331 -0
  228. package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
  229. package/src/components/Avatar/avatar.spec.md +329 -0
  230. package/src/components/Badge/badge.spec.md +380 -0
  231. package/src/components/Breadcrumb/breadcrumb.spec.md +257 -0
  232. package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
  233. package/src/components/Button/button.spec.md +460 -0
  234. package/src/components/Calendar/calendar.spec.md +242 -0
  235. package/src/components/Carousel/carousel.spec.md +253 -0
  236. package/src/components/Chart/chart.spec.md +155 -0
  237. package/src/components/Checkbox/checkbox.spec.md +344 -0
  238. package/src/components/Chip/chip.spec.md +237 -0
  239. package/src/components/CircularProgress/circular-progress.spec.md +268 -0
  240. package/src/components/Coachmark/coachmark.spec.md +230 -0
  241. package/src/components/Combobox/combobox.spec.md +180 -0
  242. package/src/components/Command/command.spec.md +171 -0
  243. package/src/components/DataTable/data-table.spec.md +525 -0
  244. package/src/components/DateGrid/date-grid.spec.md +215 -0
  245. package/src/components/DatePicker/date-picker.spec.md +334 -0
  246. package/src/components/DescriptionList/description-list.spec.md +214 -0
  247. package/src/components/Dialog/dialog.spec.md +202 -0
  248. package/src/components/DropdownMenu/dropdown-menu.spec.md +250 -0
  249. package/src/components/Empty/empty.spec.md +214 -0
  250. package/src/components/Field/field-controls.spec.md +338 -0
  251. package/src/components/Field/field.spec.md +438 -0
  252. package/src/components/Field/form-validation.spec.md +152 -0
  253. package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
  254. package/src/components/FileItem/file-item.spec.md +467 -0
  255. package/src/components/FileUpload/file-upload.spec.md +123 -0
  256. package/src/components/FileViewer/file-viewer.spec.md +373 -0
  257. package/src/components/HoverCard/hover-card.spec.md +157 -0
  258. package/src/components/Input/input.spec.md +193 -0
  259. package/src/components/LinkInput/link-input.spec.md +130 -0
  260. package/src/components/Menu/menu-item.spec.md +290 -0
  261. package/src/components/NameCard/name-card.spec.md +171 -0
  262. package/src/components/Notice/notice.spec.md +149 -0
  263. package/src/components/NumberInput/number-input.spec.md +126 -0
  264. package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
  265. package/src/components/PeoplePicker/people-picker.spec.md +263 -0
  266. package/src/components/Popover/popover.spec.md +198 -0
  267. package/src/components/ProgressBar/progress-bar.spec.md +232 -0
  268. package/src/components/RadioGroup/radio-group.spec.md +141 -0
  269. package/src/components/Rating/rating.spec.md +208 -0
  270. package/src/components/ScrollArea/scroll-area.spec.md +145 -0
  271. package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
  272. package/src/components/Select/select.spec.md +299 -0
  273. package/src/components/SelectMenu/select-menu.spec.md +220 -0
  274. package/src/components/SelectionControl/selection-item.spec.md +128 -0
  275. package/src/components/Separator/separator.spec.md +109 -0
  276. package/src/components/Sheet/sheet.spec.md +148 -0
  277. package/src/components/Sidebar/sidebar.spec.md +713 -0
  278. package/src/components/Skeleton/skeleton.spec.md +104 -0
  279. package/src/components/Slider/slider.spec.md +353 -0
  280. package/src/components/Steps/steps.spec.md +465 -0
  281. package/src/components/Switch/switch.spec.md +215 -0
  282. package/src/components/Tabs/tabs.spec.md +314 -0
  283. package/src/components/Tag/tag.spec.md +282 -0
  284. package/src/components/Textarea/textarea.spec.md +151 -0
  285. package/src/components/TimePicker/time-picker.spec.md +279 -0
  286. package/src/components/Toast/toast.spec.md +177 -0
  287. package/src/components/Tooltip/tooltip.spec.md +139 -0
  288. package/src/components/TreeView/tree-view.spec.md +374 -0
  289. package/src/patterns/action-bar/action-bar.spec.md +458 -0
  290. package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
  291. package/src/patterns/element-anatomy/inline-action.spec.md +315 -0
  292. package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
  293. package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
  294. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
  295. package/src/patterns/overlay-surface/overlay-surface.spec.md +428 -0
  296. package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
  297. package/src/tokens/color/color.spec.md +804 -0
  298. package/src/tokens/density/density.spec.md +127 -0
  299. package/src/tokens/elevation/elevation.spec.md +81 -0
  300. package/src/tokens/layoutSpace/layoutSpace.spec.md +314 -0
  301. package/src/tokens/motion/motion.spec.md +97 -0
  302. package/src/tokens/opacity/opacity.spec.md +78 -0
  303. package/src/tokens/orphan-tokens.spec.md +117 -0
  304. package/src/tokens/radius/radius.spec.md +123 -0
  305. package/src/tokens/typography/typography.spec.md +202 -0
  306. package/src/tokens/uiSize/uiSize.spec.md +438 -0
  307. package/src/styles/preset.css +0 -31
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook for Edit/Write on component .tsx:
3
+ # When a change touches cva() defaultVariants, grep for 3-way consistency across
4
+ # spec.md + docblock + anatomy.stories.tsx and warn if any disagree on the default.
5
+ #
6
+ # Prevents the SegmentedControl bug class: cva says 'md', spec/docblock/anatomy say
7
+ # 'sm ★default' — silently drifts until audit catches it.
8
+ #
9
+ # Exit: 0 + stdout JSON additionalContext (non-blocking warning)
10
+
11
+ # Per-hook fire logging(enables /knowledge-prune D2 dead-hook detection)
12
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
13
+
14
+ set -euo pipefail
15
+
16
+ INPUT=$(cat)
17
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""')
18
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
19
+
20
+ case "$TOOL" in
21
+ Edit|Write|MultiEdit) ;;
22
+ *) exit 0 ;;
23
+ esac
24
+
25
+ # Only target component .tsx files (not stories, not specs)
26
+ if ! echo "$FILE_PATH" | grep -qE 'packages/design-system/src/components/[^/]+/[^/]+\.tsx$'; then
27
+ exit 0
28
+ fi
29
+ echo "$FILE_PATH" | grep -qE '\.stories\.tsx$' && exit 0
30
+
31
+ # Only fire if the file actually contains defaultVariants (post-edit state)
32
+ [ -f "$FILE_PATH" ] || exit 0
33
+ grep -q "defaultVariants" "$FILE_PATH" || exit 0
34
+
35
+ # Diff-aware: only fire if this edit actually touched cva / defaultVariants content.
36
+ # Extract old_string + new_string (Edit / MultiEdit) or content (Write) — if none
37
+ # mention cva(, defaultVariants, or variants: , skip noise.
38
+ DIFF_TEXT=$(echo "$INPUT" | jq -r '
39
+ (.tool_input.old_string // "") + "\n" +
40
+ (.tool_input.new_string // "") + "\n" +
41
+ (.tool_input.content // "") + "\n" +
42
+ ([.tool_input.edits[]? | (.old_string + "\n" + .new_string + "\n")] | join(""))
43
+ ' 2>/dev/null || echo "")
44
+ if [ -n "$DIFF_TEXT" ] && ! echo "$DIFF_TEXT" | grep -qE 'cva\(|defaultVariants|variants:[[:space:]]*\{'; then
45
+ exit 0
46
+ fi
47
+
48
+ COMP_DIR=$(dirname "$FILE_PATH")
49
+ COMP_NAME=$(basename "$COMP_DIR")
50
+ SPEC_FILE="$COMP_DIR/$(basename "$FILE_PATH" .tsx).spec.md"
51
+ ANATOMY_FILE="$COMP_DIR/$(basename "$FILE_PATH" .tsx).anatomy.stories.tsx"
52
+
53
+ # Extract default values from each source (best-effort grep; signal not proof)
54
+ CVA_DEFAULTS=$(grep -A5 "defaultVariants" "$FILE_PATH" 2>/dev/null | grep -E "(size|variant|state):" | head -3 | tr -d ' "' | sed 's/,$//' || echo "")
55
+ SPEC_DEFAULTS=""
56
+ [ -f "$SPEC_FILE" ] && SPEC_DEFAULTS=$(grep -E "★|預設|default" "$SPEC_FILE" 2>/dev/null | head -5 || echo "")
57
+ ANATOMY_DEFAULTS=""
58
+ [ -f "$ANATOMY_FILE" ] && ANATOMY_DEFAULTS=$(grep -E "★|default|defaultVariants" "$ANATOMY_FILE" 2>/dev/null | head -5 || echo "")
59
+
60
+ WARNING="⚠️ $COMP_NAME cva/defaultVariants touched — verify 3-way sync: tsx cva ↔ spec.md default markers ↔ anatomy SIZE_SPECS. Ref: SegmentedControl drift bug. Grep \"★|預設|default\" in $COMP_DIR/."
61
+
62
+ # Escape for JSON via jq
63
+ ESCAPED=$(printf '%s' "$WARNING" | jq -Rs .)
64
+
65
+ cat <<EOJSON
66
+ {"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":$ESCAPED}}
67
+ EOJSON
68
+
69
+ exit 0
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+ # _governance_coverage_check.sh — PostToolUse helper:
3
+ # 偵測 governance file edit(meta-patterns / spec.md frontmatter / hook / SKILL / rules)
4
+ # → 跑 audit-preflight.mjs --check 比 baseline 是否新增 coverage gap
5
+ # → 有 gap → stderr inject 警告:user 必補 audit dim or 撤原則
6
+ #
7
+ # 對應 SSOT:
8
+ # - memory/feedback_audit_preflight_全盤查.md(2026-05-15 codified)
9
+ # - design-system-audit/SKILL.md Phase 0.5 invariant
10
+ # - user 原話「確保現在和未來都會自動涵蓋,當有新的準則就務必更新設計系統進階稽核的內容」
11
+ #
12
+ # 由 post_edit_dispatcher.sh orchestrate,non-standalone hook(不算 hook count)
13
+
14
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
15
+
16
+ FILE_PATH=$(jq -r '.tool_input.file_path // empty')
17
+ [ -z "$FILE_PATH" ] && exit 0
18
+
19
+ # Governance file scope:M-rule / spec.md frontmatter / hook check / SKILL / rules
20
+ GOV_RE='(meta-patterns\.md|/spec\.md$|check_.*\.sh$|/SKILL\.md$|\.claude/rules/.*\.md$|CLAUDE\.md$)'
21
+ echo "$FILE_PATH" | grep -qE "$GOV_RE" || exit 0
22
+
23
+ # Pre-check audit-preflight 存在
24
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
25
+ PREFLIGHT="$PROJECT_DIR/scripts/audit-preflight.mjs"
26
+ [ -f "$PREFLIGHT" ] || exit 0
27
+
28
+ # 跑 preflight check mode(silent;exit 1 if gap)
29
+ PREFLIGHT_OUT=$(cd "$PROJECT_DIR" && node scripts/audit-preflight.mjs --check 2>&1)
30
+ PREFLIGHT_EXIT=$?
31
+
32
+ if [ "$PREFLIGHT_EXIT" -eq 1 ]; then
33
+ TODAY=$(date +%Y-%m-%d)
34
+ LOG_FILE="$PROJECT_DIR/.claude/logs/audit-preflight-${TODAY}.json"
35
+ GAP_COUNT=0
36
+ GAP_SAMPLE=""
37
+ if [ -f "$LOG_FILE" ]; then
38
+ GAP_COUNT=$(jq -r '.coverageGaps // 0' "$LOG_FILE" 2>/dev/null || echo 0)
39
+ GAP_SAMPLE=$(jq -r '.gaps[:3] | .[]' "$LOG_FILE" 2>/dev/null | head -3 | tr '\n' ',' | sed 's/,$//')
40
+ fi
41
+
42
+ ADDITIONAL_CONTEXT="⚠️ Governance coverage gap(audit-preflight): ${FILE_PATH##*/} edit 後 ${GAP_COUNT} 原則無 audit dim cover(包含: ${GAP_SAMPLE})。若新加入的原則 → 必補 audit dim 進 design-system-audit/SKILL.md。若既有 false-positive(heuristic 不準)→ sub-agent semantic verify。SSOT: memory/feedback_audit_preflight_全盤查.md"
43
+
44
+ jq -n --arg ctx "$ADDITIONAL_CONTEXT" '{
45
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: $ctx }
46
+ }'
47
+ fi
48
+
49
+ exit 0
@@ -0,0 +1,163 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook: flag hardcoded user-facing strings in DS component tsx
3
+ # (CJK ≥ 3 chars or English ≥ 8 chars that look like sentence-case labels).
4
+ #
5
+ # Rationale(CLAUDE.md # Internationalization / 24-checklist #13 gap):
6
+ # DS primitive 的文案若 hardcode,consumer 換語言 / A/B test label 時要 forkDS。
7
+ # 正確路線:prop 接收 + `loadingText` / `emptyText` 等 slot,或走 i18n 層。
8
+ #
9
+ # Scope:
10
+ # - ONLY packages/design-system/src/components/**/*.tsx(primitives)
11
+ # - ONLY patterns/ 如果出現 user-facing string
12
+ # - SKIP stories.tsx(stories 用真實 Jira/Stripe 範例 = 刻意)
13
+ # - SKIP spec.md / anatomy
14
+ #
15
+ # Whitelist(不 flag):
16
+ # - 註解 // /* */
17
+ # - `aria-label` / `title` 等 a11y prop 若無對應 prop 可接收 → 仍 flag(warn 改成 prop)
18
+ # - 標示 `// i18n-allow: {rationale}` 該行白名單
19
+ #
20
+ # WARN-style, 不 block.
21
+
22
+ # Per-hook fire logging(enables /knowledge-prune D2 dead-hook detection)
23
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
24
+
25
+ FILE_PATH=$(jq -r '.tool_input.file_path // empty')
26
+
27
+ # Scope: only design-system components/patterns .tsx
28
+ if ! echo "$FILE_PATH" | grep -qE 'packages/design-system/src/(components|patterns)/.*\.tsx$'; then
29
+ exit 0
30
+ fi
31
+ if echo "$FILE_PATH" | grep -qE '\.(stories|principles|anatomy\.stories)\.tsx$'; then
32
+ exit 0
33
+ fi
34
+ if [ ! -f "$FILE_PATH" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ # Detect hardcoded user-facing CJK / English labels via perl oneliner
39
+ # (macOS-portable: perl is always present; grep -P / pcregrep / rg 不一定有)
40
+ #
41
+ # Perl logic(per line):
42
+ # 1. 跳過 `// ...` 單行註解(但不影響行內其他 content 判斷 — 我們直接跳整行簡化)
43
+ # 2. 跳過 `/* ... */` 一行註解
44
+ # 3. 跳過該行含 `i18n-allow` 白名單標記
45
+ # 4. 對剩餘行偵測 JSX 文字節點 `>...<` 或字串字面量 `"..."` / `'...'`
46
+ # 內含 ≥ 3 個 CJK 字元(\p{Han} / \p{Hiragana} / \p{Katakana} / \p{Hangul})
47
+ # 5. English:narrow detection,僅當 JSX 文字節點或屬性值含 ≥ 2 個 sentence-case 詞
48
+ #
49
+ # Output: "line_num:matched_snippet"(每 file 最多 5 條)
50
+
51
+ VIOLATIONS=""
52
+
53
+ CJK_HITS=$(perl -CSD -ne '
54
+ BEGIN {
55
+ our $jsdoc = 0; our $console_open = 0; our $jsx_comment = 0;
56
+ our $allow_pending = 0; our $allow_depth = 0;
57
+ }
58
+ # ── block-level i18n-allow:上一行有 `// i18n-allow-block` 或
59
+ # `// i18n-allow`(單獨 comment 行)→ 標記下一個 `{...}` 區塊整個 skip ──
60
+ if (m{^\s*(?://|/\*+)\s*i18n-allow(-block)?\b}) { $allow_pending = 1; next }
61
+ if ($allow_pending && m{[\{\[]}) {
62
+ $allow_pending = 0;
63
+ my $opens = () = /[\{\[]/g; my $closes = () = /[\}\]]/g;
64
+ $allow_depth = $opens - $closes;
65
+ next if $allow_depth > 0; # only enter block if net positive opens
66
+ }
67
+ if ($allow_depth > 0) {
68
+ my $opens = () = /[\{\[]/g; my $closes = () = /[\}\]]/g;
69
+ $allow_depth += $opens - $closes;
70
+ next;
71
+ }
72
+ # ── JSDoc block(多行 /** ... */)── stateful ──
73
+ if (!$jsdoc && m{/\*\*}) { $jsdoc = 1 }
74
+ if ($jsdoc) {
75
+ if (m{\*/}) { $jsdoc = 0 }
76
+ next;
77
+ }
78
+ # ── JSX block comment(多行 {/* ... */})── stateful ──
79
+ if (!$jsx_comment && m{\{/\*}) { $jsx_comment = 1 }
80
+ if ($jsx_comment) {
81
+ if (m{\*/\s*\}}) { $jsx_comment = 0 }
82
+ next;
83
+ }
84
+ # ── Line-level 註解 skip ──────────────
85
+ next if m{^\s*//}; # single-line comment
86
+ next if m{^\s*/\*.*\*/\s*$}; # single-line block comment
87
+ next if m{^\s*\*}; # stray JSDoc line
88
+ next if m{i18n-allow};
89
+ # ── strip trailing `//` comments(naïve:不處理 URL 等 string 內 `//`)─
90
+ # Fix FP:`code() // CJK comment` 被誤匹配 comment 內的 CJK
91
+ # 注意:不能用 `[^\x27"]` 限制,comment 內可能有 `"` 被 CJK 夾住
92
+ # 簡單策略 — `//` 後到 EOL 全 strip(string 內的 `//` 罕見 → 可接受 FP trade)
93
+ $_ =~ s{\s+//.*$}{};
94
+ # ── dev-only console.* / throw new Error() multi-line — stateful ─
95
+ # 這些是 DS internal dev / developer-facing diagnostics,consumer 看不到
96
+ if (!$console_open && m{(console\.(warn|error|log|info|debug)|throw\s+new\s+(Error|TypeError|RangeError))\s*\(}) {
97
+ $console_open = 1;
98
+ if (m{\)\s*[;,]?\s*$}) { $console_open = 0 }
99
+ next;
100
+ }
101
+ if ($console_open) {
102
+ if (m{\)\s*[;,]?\s*$}) { $console_open = 0 }
103
+ next;
104
+ }
105
+ # ── DS-internal metadata keys(designer-facing,非 end-user-facing)──
106
+ # 典型:buttonMeta / componentMeta / story args 的 `purpose:` / `description:` / `rationale:` / `when:` / `dont:` / `note:` / `text:`(stories)
107
+ # 匹配「行內任何位置出現 `{metadata_key}: "..."`」:如 `primary: { purpose: "..." }` 的 purpose
108
+ next if m{\b(purpose|description|rationale|when|dont|note|tip|detail|explanation|summary)\s*:\s*[\x27"]};
109
+ # ── JSX text node or string literal with CJK ≥ 3 ─
110
+ if (m{([>"\047])([^<"\047]*?[\p{Han}\p{Hiragana}\p{Katakana}\p{Hangul}]{3,}[^<"\047]*?)([<"\047])}) {
111
+ my $snippet = $2;
112
+ $snippet =~ s/^\s+|\s+$//g;
113
+ $snippet = substr($snippet, 0, 80) . "…" if length($snippet) > 80;
114
+ print "$.:$snippet\n";
115
+ }
116
+ ' "$FILE_PATH" 2>/dev/null | head -5)
117
+
118
+ if [ -n "$CJK_HITS" ]; then
119
+ VIOLATIONS="${VIOLATIONS}\n⚠️ Hardcoded CJK strings in DS primitive(consumer 換語言要 fork 元件):\n${CJK_HITS}\n 修法:改成 prop 接收(e.g. \`loadingText / emptyText / label\` slot)。若確實 DS 層預設(如 internal debug),在該行末加 \`// i18n-allow: {rationale}\` 白名單。"
120
+ fi
121
+
122
+ # English sentence-case labels — narrow detection
123
+ ENG_HITS=$(perl -CSD -ne '
124
+ BEGIN { our $allow_pending = 0; our $allow_depth = 0; }
125
+ # ── block-level i18n-allow(同 CJK block)─
126
+ if (m{^\s*(?://|/\*+)\s*i18n-allow(-block)?\b}) { $allow_pending = 1; next }
127
+ if ($allow_pending && m{[\{\[]}) {
128
+ $allow_pending = 0;
129
+ my $opens = () = /[\{\[]/g; my $closes = () = /[\}\]]/g;
130
+ $allow_depth = $opens - $closes;
131
+ next if $allow_depth > 0; # only enter block if net positive opens
132
+ }
133
+ if ($allow_depth > 0) {
134
+ my $opens = () = /[\{\[]/g; my $closes = () = /[\}\]]/g;
135
+ $allow_depth += $opens - $closes;
136
+ next;
137
+ }
138
+ # ── 註解 skip(line-level)─────────────────────
139
+ next if m{^\s*//};
140
+ next if m{^\s*/\*.*\*/\s*$};
141
+ next if m{^\s*\*};
142
+ next if m{^\s*/\*\*?\s*$};
143
+ next if m{i18n-allow};
144
+ next if m{console\.(warn|error|log|info|debug)\s*\(};
145
+ next if m{className=|aria-label=|data-\w+=|href=|key=};
146
+ if (m{>([A-Z][a-z]+ [a-z]+(?: [a-z]+)+)<} || m{[\"\047]([A-Z][a-z]+ [a-z]+(?: [a-z]+)+)[\"\047]}) {
147
+ print "$.:$1\n";
148
+ }
149
+ ' "$FILE_PATH" 2>/dev/null | head -3)
150
+
151
+ if [ -n "$ENG_HITS" ]; then
152
+ VIOLATIONS="${VIOLATIONS}\n⚠️ Hardcoded English sentence-case labels:\n${ENG_HITS}\n 若是 user-facing label,改 prop 接收;若是 internal,加 \`// i18n-allow\` 白名單。"
153
+ fi
154
+
155
+ # ── Emit warning if any violation ────────────────────────────────────────────
156
+ if [ -n "$VIOLATIONS" ]; then
157
+ ESCAPED=$(printf "%b" "$VIOLATIONS" | jq -Rs .)
158
+ cat <<EOJSON
159
+ {"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"i18n hygiene 檢查(24-checklist #13 gap):${ESCAPED}\n\nDS primitive 應 prop-driven,hardcoded 文案讓 consumer 換語言時要 fork。"}}
160
+ EOJSON
161
+ fi
162
+
163
+ exit 0
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook: detect layoutSpace canonical violations in stories / showcase tsx.
3
+ #
4
+ # Catches typical block-vs-inline gap mistakes per layoutSpace.spec.md:
5
+ # 1. Hardcoded mt-N / mb-N / pt-N / pb-N (4/6/8) instead of tokens — should use --layout-space-*
6
+ # 2. gap-tight on a flex column form with all-inline elements (should be loose per rule 3)
7
+ # 3. block element (DataTable / Textarea / Editor) followed by mt-tight on next sibling
8
+ # (block → 容器底 / chrome band 應該 loose,規則 4)
9
+ #
10
+ # Scope: design-system stories.tsx + app/ + explorations/ (consumer-side layout).
11
+ # WARN-style (not BLOCK): emit additionalContext so AI reads and can fix.
12
+
13
+ # Per-hook fire logging
14
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
15
+
16
+ FILE_PATH=$(jq -r '.tool_input.file_path // empty')
17
+
18
+ # Scope: only stories.tsx + app code (not core component .tsx — they own their own internal padding)
19
+ if ! echo "$FILE_PATH" | grep -qE '(\.stories\.tsx$|src/app/.*\.tsx$|src/explorations/.*\.tsx$)'; then
20
+ exit 0
21
+ fi
22
+ if [ ! -f "$FILE_PATH" ]; then
23
+ exit 0
24
+ fi
25
+
26
+ VIOLATIONS=""
27
+
28
+ # ── Check 1: hardcoded mt-N / mb-N adjacent to <DataTable / Textarea / Editor> ──
29
+ # Block elements need loose bottom/top gap; tight is rule violation.
30
+ # Pattern: <DataTable...>...</...> followed by <Alert / BulkActionBar / div with mt-tight>
31
+ BLOCK_TIGHT_HITS=$(grep -nE "(mt|mb)-\[var\(--layout-space-tight\)\]" "$FILE_PATH" 2>/dev/null | head -5)
32
+ if [ -n "$BLOCK_TIGHT_HITS" ]; then
33
+ # Only flag if file ALSO contains block elements (DataTable / Textarea / Editor / CodeBlock)
34
+ if grep -qE '<(DataTable|Textarea|Editor|CodeBlock)' "$FILE_PATH" 2>/dev/null; then
35
+ VIOLATIONS="${VIOLATIONS}\n⚠️ tight margin near block element(可能違反規則 4:block → 容器底 / chrome band = loose):\n${BLOCK_TIGHT_HITS}\n → 確認該位置:block 旁邊應 loose;只有 block ↔ block 緊鄰且都在 form 內才用 tight。"
36
+ fi
37
+ fi
38
+
39
+ # ── Check 3: gap-tight on flex column form with all-inline (likely violation)──
40
+ # 規則 3:inline ↔ inline = loose,不是 tight
41
+ GAP_TIGHT_FLEX=$(grep -nE 'flex-col\s+gap-\[var\(--layout-space-tight\)\]' "$FILE_PATH" 2>/dev/null | head -3)
42
+ if [ -n "$GAP_TIGHT_FLEX" ]; then
43
+ VIOLATIONS="${VIOLATIONS}\n⚠️ flex-col gap-tight(若內容全是 inline 元件就違反規則 3:inline ↔ inline 應 loose):\n${GAP_TIGHT_FLEX}\n → 確認 form 內含 block(Table/Textarea/Editor)?有 → 保留 tight 合規;全 inline → 改 loose。"
44
+ fi
45
+
46
+ if [ -n "$VIOLATIONS" ]; then
47
+ ADDITIONAL_CONTEXT=$(printf '⚠️ layoutSpace canonical 提醒(tokens/layoutSpace/layoutSpace.spec.md):%b' "$VIOLATIONS")
48
+ jq -n --arg ctx "$ADDITIONAL_CONTEXT" '{
49
+ hookSpecificOutput: {
50
+ hookEventName: "PostToolUse",
51
+ additionalContext: $ctx
52
+ }
53
+ }'
54
+ fi
55
+
56
+ exit 0
@@ -0,0 +1,141 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook: detect hand-crafted overlay chrome violating mindset #2.
3
+ #
4
+ # Catches: <div className="...px-[var(--layout-space-loose)]...border-(b|t) border-divider">
5
+ # in stories.tsx / DataTable helper.tsx / app code — pattern means consumer self-rendered
6
+ # overlay header/footer chrome instead of consuming SurfaceHeader / SurfaceBody / SurfaceFooter
7
+ # (or PopoverHeader / DialogHeader / SheetHeader).
8
+ #
9
+ # Why block: canonical primitives bundle padding + border + close X (Popover) + autofocus +
10
+ # typography (PopoverTitle text-body font-medium). Self-rendering bypasses these = mindset #2
11
+ # violation + silently breaks alignment / close X 一致性。
12
+ #
13
+ # 對齊 patterns/overlay-surface/overlay-surface.spec.md「Consumer rule」+
14
+ # components/Popover/popover.tsx:72「所有 PopoverHeader 一律附右上 X」canonical。
15
+ #
16
+ # Escape hatch:add `// overlay-handcraft-allow: <reason>` on prev/same line for intentional cases
17
+ # (e.g. non-overlay panel that just borrows the layout-space token).
18
+ #
19
+ # WARN-style (additionalContext) — AI reads + fixes next iteration.
20
+
21
+ # Per-hook fire logging
22
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
23
+
24
+ FILE_PATH=$(jq -r '.tool_input.file_path // empty')
25
+
26
+ # Scope: tsx files (stories, components, patterns, app, explorations)
27
+ if ! echo "$FILE_PATH" | grep -qE '\.tsx$'; then
28
+ exit 0
29
+ fi
30
+ # Skip spec.md / anatomy stories (different context)
31
+ if echo "$FILE_PATH" | grep -qE '(\.spec\.md$|\.anatomy\.stories\.tsx$|\.principles\.stories\.tsx$)'; then
32
+ exit 0
33
+ fi
34
+ if [ ! -f "$FILE_PATH" ]; then
35
+ exit 0
36
+ fi
37
+
38
+ # Pattern: <div className="...px-[var(--layout-space-loose)]...border-(b|t) border-divider...">
39
+ PATTERN='<div className="[^"]*px-\[var\(--layout-space-loose\)\][^"]*border-(b|t) border-divider'
40
+ HITS=$(grep -nE "$PATTERN" "$FILE_PATH" 2>/dev/null | head -5)
41
+
42
+ if [ -n "$HITS" ]; then
43
+ # filter out lines with allowlist comment
44
+ FILTERED=""
45
+ while IFS= read -r line; do
46
+ line_num=$(echo "$line" | cut -d: -f1)
47
+ [ -z "$line_num" ] && continue
48
+ # check current line + previous line for allowlist
49
+ prev_line=$(sed -n "$((line_num-1))p" "$FILE_PATH" 2>/dev/null)
50
+ cur_line=$(sed -n "${line_num}p" "$FILE_PATH" 2>/dev/null)
51
+ if echo "$prev_line $cur_line" | grep -q 'overlay-handcraft-allow:'; then
52
+ continue
53
+ fi
54
+ FILTERED="${FILTERED}${line}\n"
55
+ done <<< "$HITS"
56
+
57
+ if [ -n "$FILTERED" ]; then
58
+ VIOLATIONS="${VIOLATIONS}\n⚠️ Hand-crafted overlay chrome detected(自刻 overlay 結構違 mindset #2):\n${FILTERED}\n → 改用 primitive:\n Popover content → PopoverHeader / PopoverBody / PopoverFooter / PopoverTitle\n Dialog content → DialogHeader / DialogBody / DialogFooter / DialogTitle\n Generic overlay panel → SurfaceHeader / SurfaceBody / SurfaceFooter (overlay-surface)\n Why:canonical 自帶 padding token + border + close X(Popover)+ autofocus + title typography。\n Escape hatch:加 \`// overlay-handcraft-allow: <reason>\` 在同/前行。"
59
+ fi
60
+ fi
61
+
62
+ # ── Check 2.5: Raw row handcraft (px-loose + py + rounded-md + hover:bg-neutral-hover) ──
63
+ # Pattern:`<div className="...flex...gap-2 px-loose py-1.5 rounded-md hover:bg-neutral-hover">`
64
+ # = 自刻 MenuItem-like row 違反 mindset #2(MenuItem primitive 自帶這些 + size canonical + a11y)
65
+ ROW_PATTERN='<div className="[^"]*flex[^"]*gap-[12][^"]*px-\[var\(--layout-space-loose\)\][^"]*hover:bg-neutral-hover[^"]*rounded'
66
+ ROW_HITS=$(grep -nE "$ROW_PATTERN" "$FILE_PATH" 2>/dev/null | head -3)
67
+ if [ -n "$ROW_HITS" ] && ! grep -qE 'menu-item-handcraft-allow:' "$FILE_PATH" 2>/dev/null; then
68
+ VIOLATIONS="${VIOLATIONS}\n⚠️ 自刻 row(MenuItem-like)違反 mindset #2:\n${ROW_HITS}\n → 改用 <MenuItem startIcon={...} endContent={...} disabled={...}>label</MenuItem>\n Why:MenuItem 自帶 SelectionItem py 公式 + size canonical + a11y(role=option, aria-disabled, aria-selected) + cursor-not-allowed disabled。\n Escape hatch:加 \`// menu-item-handcraft-allow: <reason>\` 在檔頭。"
69
+ fi
70
+
71
+ # ── Check 2: Raw <Checkbox> count > 1 not in <CheckboxGroup> ──
72
+ # 同 root cause(自刻 SelectionItem 包 Checkbox 而非消費 CheckboxGroup primitive)。
73
+ # 對齊 checkbox.spec.md「群組模式(CheckboxGroup)」canonical line 225:
74
+ # 多選 Checkbox 必包 <CheckboxGroup>(zero-gap canonical + Context 隔離 + a11y group)。
75
+ CB_COUNT=$(grep -c '<Checkbox\b' "$FILE_PATH" 2>/dev/null | head -1 || echo 0)
76
+ CBG_COUNT=$(grep -c '<CheckboxGroup\b' "$FILE_PATH" 2>/dev/null | head -1 || echo 0)
77
+ CB_COUNT=${CB_COUNT:-0}
78
+ CBG_COUNT=${CBG_COUNT:-0}
79
+ if [ "$CB_COUNT" -ge 2 ] && [ "$CBG_COUNT" -eq 0 ]; then
80
+ CB_HITS=$(grep -nE '<Checkbox\b' "$FILE_PATH" 2>/dev/null | head -3)
81
+ # allowlist: same-line or prev-line has // checkbox-group-allow:
82
+ if ! grep -qE 'checkbox-group-allow:' "$FILE_PATH" 2>/dev/null; then
83
+ VIOLATIONS="${VIOLATIONS}\n⚠️ 多個 raw <Checkbox> 未包 <CheckboxGroup>(${CB_COUNT} hits)— 違反 checkbox.spec.md 群組 canonical:\n${CB_HITS}\n → 改用 <CheckboxGroup><Checkbox label=\"...\" />...</CheckboxGroup>\n Why:CheckboxGroup 自帶 zero-gap canonical(SelectionItem py 公式)+ Context 隔離 fieldCtx + a11y group;raw 自刻 wrapper 違 mindset #2。\n Escape hatch:加 \`// checkbox-group-allow: <reason>\` 在檔頭。"
84
+ fi
85
+ fi
86
+
87
+ # ── Check 5: Same-row consistency 違反(同 row 混 ItemInlineActionButton + Button iconOnly)──
88
+ # 對齊 inline-action.spec.md L152「Same-row consistency rule:同 action row 所有 icon action 必同一類」。
89
+ # Pattern:同檔出現 <ItemInlineActionButton 與 <Button.*iconOnly,且非 menu primitive impl(menu 內 Button 為合法 chrome)。
90
+ HAS_INLINE=$(grep -c '<ItemInlineActionButton' "$FILE_PATH" 2>/dev/null | head -1)
91
+ HAS_BTN_ICON=$(grep -cE '<Button[^>]*iconOnly' "$FILE_PATH" 2>/dev/null | head -1)
92
+ HAS_INLINE=${HAS_INLINE:-0}
93
+ HAS_BTN_ICON=${HAS_BTN_ICON:-0}
94
+ IS_MENU_PRIMITIVE2=$(echo "$FILE_PATH" | grep -cE '(DropdownMenu|SelectMenu|Combobox|Menu)/.*\.tsx$' | head -1)
95
+ IS_MENU_PRIMITIVE2=${IS_MENU_PRIMITIVE2:-0}
96
+ if [ "$HAS_INLINE" -ge 1 ] && [ "$HAS_BTN_ICON" -ge 1 ] && [ "$IS_MENU_PRIMITIVE2" -eq 0 ]; then
97
+ if ! grep -qE 'same-row-mixed-allow:' "$FILE_PATH" 2>/dev/null; then
98
+ VIOLATIONS="${VIOLATIONS}\n⚠️ 同檔混用 <ItemInlineActionButton>(${HAS_INLINE}) + <Button.*iconOnly>(${HAS_BTN_ICON}):\n → 違反 inline-action.spec.md L152 Same-row consistency rule(同 row icon action 必同一類)。\n → Box size 不一致(InlineAction 16+18 vs Button text sm 28)會 gap 斷裂。\n → 修法:row 內 icon action 全 ItemInlineActionButton(對齊 size=md / 16+18 hover bg)。\n Escape hatch:加 \`// same-row-mixed-allow: <reason>\` 在檔頭(若 chrome corner action group 跟 row 不同 row,可分開)。"
99
+ fi
100
+ fi
101
+
102
+ # ── Check 4: Panel-style Popover + MenuItem co-occur(2026-04-29) ──
103
+ # Pattern:同檔出現 <PopoverHeader> 且 <MenuItem>(不是 DropdownMenu / SelectMenu primitive 自身)
104
+ # → panel-style popover 不該硬塞 menu specialization。MenuItem 預設 `px-3` 不對齊 panel chrome
105
+ # `loose`,且 startIcon 色彩無 override → 該用視覺 primitive(ItemPrefix/ItemLabel/ItemSuffix)自組。
106
+ HAS_POP_HEADER=$(grep -c '<PopoverHeader' "$FILE_PATH" 2>/dev/null | head -1)
107
+ HAS_MENU_ITEM=$(grep -c '<MenuItem\b' "$FILE_PATH" 2>/dev/null | head -1)
108
+ HAS_POP_HEADER=${HAS_POP_HEADER:-0}
109
+ HAS_MENU_ITEM=${HAS_MENU_ITEM:-0}
110
+ # Skip:DropdownMenu/SelectMenu primitive impl 本身(他們 import MenuItem 是合法 menu-style)
111
+ IS_MENU_PRIMITIVE=$(echo "$FILE_PATH" | grep -cE '(DropdownMenu|SelectMenu|Combobox)/.*\.tsx$' | head -1)
112
+ IS_MENU_PRIMITIVE=${IS_MENU_PRIMITIVE:-0}
113
+ if [ "$HAS_POP_HEADER" -ge 1 ] && [ "$HAS_MENU_ITEM" -ge 1 ] && [ "$IS_MENU_PRIMITIVE" -eq 0 ]; then
114
+ if ! grep -qE 'panel-menuitem-allow:' "$FILE_PATH" 2>/dev/null; then
115
+ VIOLATIONS="${VIOLATIONS}\n⚠️ Panel-style Popover(<PopoverHeader>)+ <MenuItem> 同檔(${HAS_MENU_ITEM} hits):\n → MenuItem 是 menu specialization(px-3 menu-style + icon 色繼承),不適 panel chrome loose。\n → 改用視覺 primitive 自組:ItemPrefix + ItemLabel + ItemSuffix(item-anatomy.tsx)+ ROW_PADDING_BY_SIZE.md\n Why:panel-style 需對齊 chrome \`loose\` + utility chrome icon color(neutral-7 / fg-muted),MenuItem 兩處 workaround = 錯 layer。\n Escape hatch:加 \`// panel-menuitem-allow: <reason>\` 在檔頭。"
116
+ fi
117
+ fi
118
+
119
+ # ── Check 6: Overlay body 重新引入 flush / 等價 boolean variant(2026-05-01)──
120
+ # 對齊 patterns/overlay-surface/overlay-surface.spec.md「List-as-region in overlay body」。
121
+ # 2026-05-01 移除 flush(rationale:Material/Atlassian/Mantine/shadcn 主流不做 universal LayoutBody flush;
122
+ # variant 不解決底層脆弱 — 加 1 row search/banner 就破功)。
123
+ # 防止未來 silent re-introduction:DialogBody / SheetBody / PopoverBody tsx 內出現
124
+ # `flush?: boolean` / `flush = false` / `naked?: boolean` / `bare?: boolean` / `noPadding?: boolean` 同類 boolean 變體。
125
+ # Scope:`components/(Dialog|Sheet|Popover)/*.tsx`(非 stories)。
126
+ IS_OVERLAY_BODY_TSX=$(echo "$FILE_PATH" | grep -cE 'components/(Dialog|Sheet|Popover)/[^/]+\.tsx$' | head -1)
127
+ IS_OVERLAY_BODY_TSX=${IS_OVERLAY_BODY_TSX:-0}
128
+ if [ "$IS_OVERLAY_BODY_TSX" -ge 1 ] && ! echo "$FILE_PATH" | grep -qE '\.stories\.tsx$'; then
129
+ STRIPPED_PROPS_PATTERN='(flush|naked|bare|stripped|unpadded|noPadding|paddingless)\??:\s*boolean'
130
+ STRIPPED_HITS=$(grep -nE "$STRIPPED_PROPS_PATTERN" "$FILE_PATH" 2>/dev/null | head -3)
131
+ if [ -n "$STRIPPED_HITS" ] && ! grep -qE 'overlay-body-stripped-variant-allow:' "$FILE_PATH" 2>/dev/null; then
132
+ VIOLATIONS="${VIOLATIONS}\n⚠️ Overlay body 重新引入 stripped-padding boolean variant(2026-05-01 已移除):\n${STRIPPED_HITS}\n → list-as-region in overlay body canonical = consumer 用 className override:\n <DialogBody className=\"!px-0 !pt-0 !pb-0\"><div className=\"py-2\">{items}</div></DialogBody>\n Why removed:Material/Atlassian/Mantine/shadcn 主流不做 universal LayoutBody flush;\n variant 不解決底層脆弱(加 1 row search/banner 就破功)+ 把 1 surface decision 拆兩 API。\n 詳 overlay-surface.spec.md「List-as-region in overlay body」+ memory feedback_layout_v6_canonical.md\n Escape hatch:加 \`// overlay-body-stripped-variant-allow: <reason>\` 在檔頭(必含 ≥3 家世界級對照 + multi-row hold 保證)。"
133
+ fi
134
+ fi
135
+
136
+ if [ -n "$VIOLATIONS" ]; then
137
+ ESCAPED=$(printf "%b" "$VIOLATIONS" | jq -Rs .)
138
+ cat <<EOJSON
139
+ {"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"Primitive consumption 檢查發現違規:${ESCAPED}"}}
140
+ EOJSON
141
+ fi
@@ -0,0 +1,42 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook: catch sparse PersonData literals that violate name-card.spec「DS-wide 預設展示一致 canonical」.
3
+ #
4
+ # Per name-card.spec.md:
5
+ # 所有 PersonData 來源(table seller / picker member / dialog reviewer)展示 NameCard 時
6
+ # description / status / statusMessage / fields 4 個 section 預設都應提供
7
+ # sparse `{ name, avatarUrl }` 資料 = bug,違反一致呈現
8
+ #
9
+ # Detects literal `{ name: '...', avatar(Url)?: '...' }` with NO other PersonData fields.
10
+
11
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
12
+
13
+ FILE_PATH=$(jq -r '.tool_input.file_path // empty')
14
+
15
+ if ! echo "$FILE_PATH" | grep -qE '\.(tsx|stories\.tsx)$'; then
16
+ exit 0
17
+ fi
18
+ if [ ! -f "$FILE_PATH" ]; then
19
+ exit 0
20
+ fi
21
+
22
+ # Skip the canonical sources(NameCard / Avatar / person-display 自身)
23
+ if echo "$FILE_PATH" | grep -qE '(NameCard|Avatar|person-display|avatar\.spec)'; then
24
+ exit 0
25
+ fi
26
+
27
+ # Match `{ name: '...', avatarUrl?: '...' }` with no other PersonData fields on same line.
28
+ # A "rich" PersonData usually spans multiple lines OR has description/status/statusMessage/fields.
29
+ # Heuristic: single-line literal with only name + avatarUrl(no other PersonData props on same line).
30
+ SPARSE_HITS=$(grep -nE "\{\s*name:\s*['\"][^'\"]+['\"],\s*avatar(Url)?:\s*['\"][^'\"]+['\"]\s*\}" "$FILE_PATH" 2>/dev/null | head -5)
31
+
32
+ if [ -n "$SPARSE_HITS" ]; then
33
+ ADDITIONAL_CONTEXT=$(printf 'Sparse PersonData literal(違反 name-card.spec「DS-wide 預設展示一致 canonical」):\n%s\n → 補上 description / status / statusMessage / fields 4 sections,讓 NameCard hover 展示資訊量一致' "$SPARSE_HITS")
34
+ jq -n --arg ctx "$ADDITIONAL_CONTEXT" '{
35
+ hookSpecificOutput: {
36
+ hookEventName: "PostToolUse",
37
+ additionalContext: $ctx
38
+ }
39
+ }'
40
+ fi
41
+
42
+ exit 0
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # PreToolUse Edit/Write: 改過 tsx componentMeta / spec frontmatter 時,
3
+ # 自動跑 compile-stories --check 偵測 drift。
4
+ #
5
+ # 對齊 Story Auto-Compile Phase 4 — stories canonical 從 spec+tsx 機械產,
6
+ # key 不齊 = canonical drift,該修。本 hook 是 write-time early warning
7
+ # (git commit 前),讓 AI / user 立刻看到 drift 而非 audit 時才發現。
8
+
9
+ # Per-hook fire logging(enables /knowledge-prune D2 dead-hook detection)
10
+ source "$(dirname "$0")/../_log-fire.sh" 2>/dev/null && log_hook_fire
11
+
12
+ set -euo pipefail
13
+
14
+ INPUT=$(cat)
15
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
16
+
17
+ [ -z "$FILE_PATH" ] && exit 0
18
+
19
+ # Only trigger on component tsx / spec.md writes
20
+ case "$FILE_PATH" in
21
+ */design-system/components/*.tsx) ;;
22
+ */design-system/components/*.spec.md) ;;
23
+ *) exit 0 ;;
24
+ esac
25
+
26
+ # Extract component name from path
27
+ COMP_NAME=$(echo "$FILE_PATH" | grep -oE 'components/[^/]+/' | head -1 | sed 's|components/||' | sed 's|/||')
28
+ [ -z "$COMP_NAME" ] && exit 0
29
+
30
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
31
+ COMPILE_SCRIPT="$PROJECT_DIR/scripts/compile-stories.mjs"
32
+
33
+ # Skip if compile script not yet built(graceful for pre-Phase-4 state)
34
+ [ ! -f "$COMPILE_SCRIPT" ] && exit 0
35
+
36
+ # Run drift check(quiet mode)
37
+ cd "$PROJECT_DIR" || exit 0
38
+ OUTPUT=$(node "$COMPILE_SCRIPT" "$COMP_NAME" --check 2>&1 || true)
39
+
40
+ # Check if drift detected(exit 1 or has 「spec/tsx canonical drift」 in output)
41
+ if echo "$OUTPUT" | grep -qE "spec/tsx canonical drift|spec-only|tsx-only"; then
42
+ MSG="📐 Story canonical drift detected in ${COMP_NAME}:\n\n${OUTPUT}\n\nFix tsx componentMeta export 或 spec frontmatter 讓 keys 對齊。"
43
+ ESCAPED=$(printf '%s' "$MSG" | jq -Rs .)
44
+ printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":%s}}\n' "$ESCAPED"
45
+ fi
46
+
47
+ # Skip graceful(migration 未做的元件)不報
48
+ exit 0