@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,612 @@
1
+ #!/bin/bash
2
+ # check_story_invariants.sh — Cluster A merge dispatcher(2026-05-10)
3
+ #
4
+ # Per codex review red-light + Q-9 (a) inline merge with rule functions:
5
+ # Merges 5 stories.tsx hooks into 1 mega dispatcher with 5 internal rule fn:
6
+ # R1 anatomy(原 lib/check_story_anatomy.sh,PreToolUse Edit|Write|MultiEdit)
7
+ # R2 slot_split(原 lib/check_story_slot_split.sh,Pre)
8
+ # R3 category(原 lib/check_story_category.sh,Pre)
9
+ # R4 title_canonical(原 check_story_title_canonical.sh,Pre)
10
+ # R5 name_jargon(原 lib/check_story_name_jargon.sh,Post — reads disk)
11
+ #
12
+ # Layer A own 撞 codex Q-9:codex 默認「6 → 1」忽略 event type 異質 —
13
+ # compile_drift 是 component tsx + spec.md scope,不適合 merge,留 standalone。
14
+ # 實際:5 stories.tsx hooks → 1 dispatcher(file count -4,34 → 30)。
15
+ #
16
+ # Event branching:
17
+ # - PreToolUse:R1 + R2 + R3 + R4(check incoming new content)
18
+ # - PostToolUse:R5(reads from disk after write)
19
+ # settings.json registers same script to both events on Edit|Write|MultiEdit matcher。
20
+ #
21
+ # Allowlist markers preserved 1-to-1:
22
+ # R1: @anatomy-exempt: / @anatomy-exempt-next
23
+ # R2: @story-split-rationale:
24
+ # R3: @story-trait-rationale:
25
+ # R4: @story-name-canonical-allow:
26
+ # R5(no allowlist,reads disk;jargon catch is broad warning)
27
+
28
+ source "$(dirname "$0")/_log-fire.sh" 2>/dev/null && log_hook_fire
29
+
30
+ set -uo pipefail
31
+
32
+ INPUT=$(cat 2>/dev/null || echo "{}")
33
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // ""' 2>/dev/null)
34
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""' 2>/dev/null)
35
+ EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // ""' 2>/dev/null)
36
+
37
+ # Common filters
38
+ case "$TOOL" in Edit|Write|MultiEdit) ;; *) exit 0 ;; esac
39
+ case "$FILE_PATH" in *.stories.tsx) ;; *) exit 0 ;; esac
40
+
41
+ NEW_CONTENT=""
42
+ if [ "$EVENT" != "PostToolUse" ]; then
43
+ NEW_CONTENT=$(echo "$INPUT" | jq -r '
44
+ (.tool_input.content // "") + "\n" +
45
+ (.tool_input.new_string // "") + "\n" +
46
+ ([.tool_input.edits[]? | .new_string] | join("\n"))
47
+ ' 2>/dev/null || echo "")
48
+ fi
49
+
50
+ WORST=0
51
+ record_worst() { local lvl=$1; [ "$lvl" -gt "$WORST" ] && WORST=$lvl; }
52
+
53
+ # ─────────────────────────────────────────────────────────────────────────────
54
+ # R1 — anatomy(PreToolUse,block raw JSX should consume DS canonical)
55
+ # ─────────────────────────────────────────────────────────────────────────────
56
+ rule_anatomy() {
57
+ [ "$EVENT" = "PostToolUse" ] && return 0
58
+ [ -z "${NEW_CONTENT//[[:space:]]/}" ] && return 0
59
+
60
+ # File-level allowlist
61
+ FIRST_LINES=$(printf '%s\n' "$NEW_CONTENT" | sed -n '1,3p')
62
+ echo "$FIRST_LINES" | grep -qE '//[[:space:]]*@anatomy-exempt:' && return 0
63
+ if [ -f "$FILE_PATH" ]; then
64
+ ON_DISK=$(sed -n '1,3p' "$FILE_PATH" 2>/dev/null || true)
65
+ echo "$ON_DISK" | grep -qE '//[[:space:]]*@anatomy-exempt:' && return 0
66
+ fi
67
+
68
+ TMP=$(mktemp); trap "rm -f $TMP" RETURN
69
+ printf '%s\n' "$NEW_CONTENT" > "$TMP"
70
+
71
+ local violations=""
72
+ local skip_next=0
73
+ local row=0
74
+ local line
75
+ while IFS= read -r line || [ -n "$line" ]; do
76
+ row=$((row+1))
77
+ if [ "$skip_next" = "1" ]; then skip_next=0; continue; fi
78
+ if echo "$line" | grep -qE '//[[:space:]]*@anatomy-exempt-next|\{/\*[[:space:]]*@anatomy-exempt-next'; then
79
+ skip_next=1; continue
80
+ fi
81
+ # A.1 raw item-anatomy row
82
+ if echo "$line" | grep -qE '<div[^>]*className="[^"]*\bflex\b[^"]*\bitems-center\b[^"]*"[^>]*>[[:space:]]*<[A-Z]'; then
83
+ first_tag=$(echo "$line" | grep -oE '<div[^>]*className="[^"]*\bflex\b[^"]*\bitems-center\b[^"]*"[^>]*>[[:space:]]*<[A-Z][a-zA-Z]*' | grep -oE '<[A-Z][a-zA-Z]*$' | head -1)
84
+ case "$first_tag" in
85
+ "<MenuItem"|"<ItemIcon"|"<ItemAvatar"|"<ItemLabel"|"<ItemSuffix"|"<ItemInlineAction"|"<ItemPrefix"|"<ItemContent"|"<Field"|"<FieldWrapper"|"<Empty"|"<Card"|"<Coachmark"|"<Dialog"|"<Sheet"|"<Popover"|"<HoverCard"|"<DataTable"|"<FileItem") ;;
86
+ *)
87
+ violations="${violations}
88
+ [A.1 hand-craft item-anatomy] ${FILE_PATH}:${row}
89
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
90
+ 改用 <MenuItem> + slot components" ;;
91
+ esac
92
+ fi
93
+ # A.2 raw <table> outside DataTable dir
94
+ if ! echo "$FILE_PATH" | grep -qE '/DataTable/'; then
95
+ if echo "$line" | grep -qE '<table\b'; then
96
+ violations="${violations}
97
+ [A.2 raw <table>] ${FILE_PATH}:${row}
98
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
99
+ 改用 <DataTable columns={...} data={...} />"
100
+ fi
101
+ fi
102
+ # A.3 hand-craft full-surface loading
103
+ if echo "$line" | grep -qE '<div[^>]*className="[^"]*\babsolute\b[^"]*\binset-0\b[^"]*\bflex\b'; then
104
+ lookahead=$(sed -n "$((row+1)),$((row+4))p" "$TMP" 2>/dev/null || true)
105
+ if echo "$line $lookahead" | grep -qE '\bCircularProgress\b'; then
106
+ violations="${violations}
107
+ [A.3 hand-craft loading] ${FILE_PATH}:${row}
108
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
109
+ 改用 <Empty icon={<CircularProgress />} description=\"...\" />"
110
+ fi
111
+ fi
112
+ # A.4 hand-craft field control
113
+ if echo "$line" | grep -qE '<input\b[^>]*className="[^"]*\bh-field-'; then
114
+ violations="${violations}
115
+ [A.4 hand-craft field] ${FILE_PATH}:${row}
116
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
117
+ 改用 <Input> / <NumberInput> / <Select> / <Combobox>"
118
+ fi
119
+ # B dismiss via label Button
120
+ if echo "$line" | grep -qE '<Button\b[^>]*>[[:space:]]*(關閉|Close|Dismiss|取消|Cancel)[[:space:]]*</Button>'; then
121
+ start=$((row-4)); [ $start -lt 1 ] && start=1
122
+ end=$((row+4))
123
+ ctx=$(sed -n "${start},${end}p" "$TMP" 2>/dev/null || true)
124
+ if echo "$ctx" | grep -qE 'onClose\b|onDismiss\b|<(Dialog|Sheet|Popover|Coachmark|Surface)Header\b|setOpen\(false\)|dismiss'; then
125
+ violations="${violations}
126
+ [B dismiss via label] ${FILE_PATH}:${row}
127
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
128
+ 改用 iconOnly X Button"
129
+ fi
130
+ fi
131
+ # C hand-crafted overlay
132
+ if echo "$line" | grep -qE '<div[^>]*className="[^"]*\babsolute\b[^"]*(bg-|shadow-|border)'; then
133
+ end=$((row+6))
134
+ lookahead=$(sed -n "${row},${end}p" "$TMP" 2>/dev/null || true)
135
+ if echo "$lookahead" | grep -qE 'onClose\b|onDismiss\b|setOpen\(false\)'; then
136
+ violations="${violations}
137
+ [C hand-craft overlay] ${FILE_PATH}:${row}
138
+ > $(echo "$line" | sed 's/^[[:space:]]*//' | cut -c1-120)
139
+ 改用 <Popover> / <HoverCard> / <Tooltip> / <Dialog>"
140
+ fi
141
+ fi
142
+ done < "$TMP"
143
+
144
+ if [ -n "$violations" ]; then
145
+ {
146
+ echo ""
147
+ echo "╔═══ R1 anatomy — stories hand-craft 違規 ═══"
148
+ printf '%s\n' "$violations"
149
+ echo "豁免:檔首 // @anatomy-exempt: <reason> 整檔 OR // @anatomy-exempt-next 單行"
150
+ } >&2
151
+ record_worst 2
152
+ fi
153
+ }
154
+
155
+ # ─────────────────────────────────────────────────────────────────────────────
156
+ # R2 — slot_split(PreToolUse,manual story 拆分原則)
157
+ # ─────────────────────────────────────────────────────────────────────────────
158
+ rule_slot_split() {
159
+ [ "$EVENT" = "PostToolUse" ] && return 0
160
+ case "$FILE_PATH" in *anatomy.stories.tsx|*principles.stories.tsx) return 0 ;; esac
161
+
162
+ # Allowlist
163
+ FIRST_LINES=$(printf '%s\n' "$NEW_CONTENT" | sed -n '1,5p')
164
+ echo "$FIRST_LINES" | grep -qE '//[[:space:]]*@story-split-rationale:' && return 0
165
+ if [ -f "$FILE_PATH" ]; then
166
+ DISK=$(sed -n '1,5p' "$FILE_PATH" 2>/dev/null || true)
167
+ echo "$DISK" | grep -qE '//[[:space:]]*@story-split-rationale:' && return 0
168
+ fi
169
+
170
+ local violations=""
171
+ local FULL="$NEW_CONTENT"
172
+ HAS_START=$(echo "$FULL" | grep -cE 'export const WithStartIcon\b' || true)
173
+ HAS_END=$(echo "$FULL" | grep -cE 'export const WithEndIcon\b' || true)
174
+ if [ "${HAS_START:-0}" -gt 0 ] && [ "${HAS_END:-0}" -gt 0 ]; then
175
+ violations="${violations}
176
+ [反 pattern] WithStartIcon + WithEndIcon 拆兩 story → 合併 WithIcon"
177
+ fi
178
+ HAS_DEFAULT=$(echo "$FULL" | grep -cE 'export const Default\b' || true)
179
+ HAS_ALL_VAR=$(echo "$FULL" | grep -cE 'export const AllVariants\b' || true)
180
+ if [ "${HAS_DEFAULT:-0}" -gt 0 ] && [ "${HAS_ALL_VAR:-0}" -gt 0 ]; then
181
+ violations="${violations}
182
+ [反 pattern] Default + AllVariants 同檔 → AllVariants 已 cover default"
183
+ fi
184
+ PRIM=$(echo "$FULL" | grep -cE 'export const (Primary|Secondary|Tertiary)\b' || true)
185
+ if [ "${PRIM:-0}" -ge 2 ]; then
186
+ violations="${violations}
187
+ [反 pattern] 多 variant stories 拆細 → 合併 AllVariants 對照 grid"
188
+ fi
189
+ if echo "$FULL" | grep -qE '^export const Variants(\b|:|\s|=)'; then
190
+ violations="${violations}
191
+ [命名漂移] Variants → AllVariants"
192
+ fi
193
+ if echo "$FULL" | grep -qE '^export const Basic(\b|:|\s|=)'; then
194
+ violations="${violations}
195
+ [命名漂移] Basic → Default"
196
+ fi
197
+ if echo "$FULL" | grep -qE '^export const (DisabledState|DisabledGroup)(\b|:|\s|=)'; then
198
+ violations="${violations}
199
+ [命名漂移] DisabledState/Group → Disabled"
200
+ fi
201
+ if echo "$FULL" | grep -qE '^export const SizeVariants(\b|:|\s|=)'; then
202
+ violations="${violations}
203
+ [命名漂移] SizeVariants → AllSizes"
204
+ fi
205
+ if echo "$FULL" | grep -qE '^export const [^a-zA-Z_$]'; then
206
+ violations="${violations}
207
+ [命名漂移] export const 中文名 → 用 PascalCase 英文,中文寫 \`name: '...'\`"
208
+ fi
209
+
210
+ if [ -n "$violations" ]; then
211
+ {
212
+ echo ""
213
+ echo "╔═══ R2 slot_split — manual story 拆分違規 ═══"
214
+ printf '%s\n' "$violations"
215
+ echo "豁免:檔首 // @story-split-rationale: <reason>"
216
+ } >&2
217
+ record_worst 2
218
+ fi
219
+ }
220
+
221
+ # ─────────────────────────────────────────────────────────────────────────────
222
+ # R3 — category(trait-based check from spec.md frontmatter)
223
+ # ─────────────────────────────────────────────────────────────────────────────
224
+ rule_category() {
225
+ [ "$EVENT" = "PostToolUse" ] && return 0
226
+ case "$FILE_PATH" in *anatomy.stories.tsx|*principles.stories.tsx) return 0 ;; esac
227
+
228
+ # Allowlist — check new content AND disk (align with R4 behavior)
229
+ echo "$NEW_CONTENT" | grep -q "@story-trait-rationale:" && return 0
230
+ if [ -f "$FILE_PATH" ]; then
231
+ DISK_HEAD=$(sed -n '1,5p' "$FILE_PATH" 2>/dev/null || true)
232
+ echo "$DISK_HEAD" | grep -q '@story-trait-rationale:' && return 0
233
+ fi
234
+
235
+ COMP_DIR=$(dirname "$FILE_PATH")
236
+ SPEC_FILE=""
237
+ for c in "$COMP_DIR"/*.spec.md; do
238
+ [ -f "$c" ] && SPEC_FILE="$c" && break
239
+ done
240
+ [ -z "$SPEC_FILE" ] && return 0
241
+
242
+ TRAITS=""
243
+ if head -30 "$SPEC_FILE" | grep -q "^traits:"; then
244
+ TRAITS=$(awk '/^traits:/{i=1;next} i&&/^ - /{sub(/^ - /,"");print;next} i&&!/^ /{i=0}' "$SPEC_FILE" | tr '\n' ' ')
245
+ fi
246
+ [ -z "$TRAITS" ] && return 0
247
+
248
+ EXISTING=""
249
+ [ -f "$FILE_PATH" ] && EXISTING=$(cat "$FILE_PATH" 2>/dev/null || echo "")
250
+ FULL="${EXISTING}
251
+ ${NEW_CONTENT}"
252
+ EXPORTS=$(echo "$FULL" | grep -oE "^export const [A-Z][a-zA-Z]+" | awk '{print $3}' | sort -u)
253
+
254
+ has_present() { echo "$EXPORTS" | grep -qE "^${1}$"; }
255
+ has_contains() { echo "$EXPORTS" | grep -qE "${1}"; }
256
+
257
+ local violations=""
258
+ if ! has_present "Default" && ! has_present "AllVariants"; then
259
+ violations="${violations}
260
+ • [P1 warn] missing Default/AllVariants story"
261
+ fi
262
+ for trait in $TRAITS; do
263
+ case "$trait" in
264
+ hasSizes)
265
+ if ! has_present "AllSizes"; then
266
+ if echo "$EXPORTS" | grep -qE "^(Small|Medium|Large|SizeSm|SizeMd|SizeLg)$"; then
267
+ violations="${violations}
268
+ • [P0] hasSizes → per-size split,merge AllSizes"
269
+ else
270
+ violations="${violations}
271
+ • [P0] hasSizes → missing AllSizes"
272
+ fi
273
+ fi ;;
274
+ hasInteractiveStates)
275
+ has_contains "(Disabled|States|Modes)" || violations="${violations}
276
+ • [P0] hasInteractiveStates → missing Disabled/States/Modes" ;;
277
+ isOverlay)
278
+ if ! has_present "OpenSnapshot" && ! echo "$FULL" | grep -qE "(defaultOpen|useState\(true\))"; then
279
+ violations="${violations}
280
+ • [P0] isOverlay → missing OpenSnapshot/defaultOpen"
281
+ fi ;;
282
+ isInputLike)
283
+ has_present "WithError" || has_present "ErrorState" || violations="${violations}
284
+ • [P0] isInputLike → missing WithError" ;;
285
+ isSelectionMulti)
286
+ has_present "VerticalGroup" || has_present "Group" || violations="${violations}
287
+ • [P0] isSelectionMulti → missing VerticalGroup/Group" ;;
288
+ esac
289
+ done
290
+
291
+ if [ -n "$violations" ]; then
292
+ if echo "$violations" | grep -q "\[P0\]"; then
293
+ {
294
+ echo ""
295
+ echo "╔═══ R3 category — trait compliance 違規 ═══"
296
+ echo " Component: $(basename "$COMP_DIR") / Traits: $TRAITS"
297
+ printf '%s' "$violations"
298
+ echo ""
299
+ echo "豁免:檔首 // @story-trait-rationale: <reason>"
300
+ } >&2
301
+ record_worst 2
302
+ else
303
+ echo "⚠️ R3 trait warn:$violations" >&2
304
+ fi
305
+ fi
306
+ }
307
+
308
+ # ─────────────────────────────────────────────────────────────────────────────
309
+ # R4 — title_canonical(non-canonical English-only `name:` 字段)
310
+ # ─────────────────────────────────────────────────────────────────────────────
311
+ rule_title_canonical() {
312
+ [ "$EVENT" = "PostToolUse" ] && return 0
313
+ case "$FILE_PATH" in *anatomy.stories.tsx|*principles.stories.tsx) return 0 ;; esac
314
+
315
+ # Allowlist
316
+ FIRST_LINES=$(printf '%s\n' "$NEW_CONTENT" | sed -n '1,5p')
317
+ echo "$FIRST_LINES" | grep -q '@story-name-canonical-allow:' && return 0
318
+ if [ -f "$FILE_PATH" ]; then
319
+ DISK=$(sed -n '1,5p' "$FILE_PATH" 2>/dev/null || true)
320
+ echo "$DISK" | grep -q '@story-name-canonical-allow:' && return 0
321
+ fi
322
+
323
+ WHITELIST='^(Default|Display|Anatomy|Overview|Inspector|ColorMatrix|SizeMatrix|StateBehavior|Accessibility|All[A-Z][a-z]+|Loading|Empty|Disabled|Error|Hover|Focus|Active|Pressed|FocusVisible)$'
324
+ VIOLATIONS=$(printf '%s' "$NEW_CONTENT" | grep -oE "name:[[:space:]]*['\"][^'\"]*['\"]" | sed -E "s/name:[[:space:]]*['\"]([^'\"]*)['\"]/\1/" | while IFS= read -r name; do
325
+ [ -z "$name" ] && continue
326
+ if echo "$name" | grep -qE '\([a-zA-Z]+\)|=[a-zA-Z]'; then
327
+ echo " - \"$name\" [leak: prop/parameter syntax]"; continue
328
+ fi
329
+ if echo "$name" | LC_ALL=C grep -qE '[^\x00-\x7F]'; then continue; fi
330
+ if echo "$name" | grep -qE "$WHITELIST"; then continue; fi
331
+ echo " - \"$name\" [pure English]"
332
+ done)
333
+
334
+ if [ -n "$VIOLATIONS" ]; then
335
+ {
336
+ echo ""
337
+ echo "╔═══ R4 title_canonical — non-canonical English `name:` ═══"
338
+ echo "[P1 WARN] ${FILE_PATH}"
339
+ printf '%s\n' "$VIOLATIONS"
340
+ echo "豁免:檔首 // @story-name-canonical-allow: <reason>"
341
+ } >&2
342
+ # P1 warn:not block
343
+ fi
344
+ }
345
+
346
+ # ─────────────────────────────────────────────────────────────────────────────
347
+ # R5 — name_jargon(PostToolUse,reads from disk)
348
+ # ─────────────────────────────────────────────────────────────────────────────
349
+ rule_name_jargon() {
350
+ [ "$EVENT" != "PostToolUse" ] && return 0
351
+ [ ! -f "$FILE_PATH" ] && return 0
352
+
353
+ local violations=""
354
+ LAYER_HITS=$(grep -nE "name:\s*['\"][^'\"]*\bL[0-9]\b" "$FILE_PATH" 2>/dev/null | head -5)
355
+ [ -n "$LAYER_HITS" ] && violations="${violations}
356
+ ⚠️ story name 含 L<n> layer 代號:
357
+ ${LAYER_HITS}
358
+ → 改人話描述"
359
+
360
+ CANON_HITS=$(grep -nE "name:\s*['\"][^'\"]*\bcanonical\b" "$FILE_PATH" 2>/dev/null | head -5)
361
+ [ -n "$CANON_HITS" ] && violations="${violations}
362
+ ⚠️ story name 含 'canonical' spec 內部術語:
363
+ ${CANON_HITS}
364
+ → 移除 canonical 後綴"
365
+
366
+ SPEC_HITS=$(grep -nE "name:\s*['\"][^'\"]*\(spec\b" "$FILE_PATH" 2>/dev/null | head -3)
367
+ [ -n "$SPEC_HITS" ] && violations="${violations}
368
+ ⚠️ story name 引用 spec:
369
+ ${SPEC_HITS}"
370
+
371
+ # R5.5(2026-05-17 升級補 gap):中英夾雜 detection — common-word 應中文化
372
+ # 對齊 story-rules.md「name: 必中文人話」+ M10 proactive scan。
373
+ # Exempt list:framework / brand / DS API value names(中英並列習慣保留英)
374
+ # Python single-file 一次掃整檔(grep regex 對 unicode + word-boundary 在 macOS bash 不穩)
375
+ MIXED_HITS=$(python3 -c "
376
+ import re, sys
377
+ EXEMPT = re.compile(r'\b(cva|Radix|Polaris|Material|Atlassian|Carbon|Ant|Apple|MUI|TanStack|shadcn|Recharts|cmdk|dnd-kit|TypeScript|JavaScript|API|UI|UX|Jira|Stripe|Notion|Figma|Linear|GitHub|Gmail|Dropbox|Slack|Spotify|Discord|VS Code|Sketch|Storybook|Tailwind|onChange|onClick|ARIA|WCAG|FAQ|HSL|CSS|HTML|DOM|DS|F[1-9]|FAB|RWD|MVP|Token|Mode|Variant|Slot|Size|Field|Input|Button|Avatar|Badge|Chip|Tag|Subtle|Solid|Range|Multiple|Single|primary|secondary|tertiary|hover|focus|active|disabled|invalid|readonly|drag|drop|inline|block|naked|bare|fixed|absolute|sticky|null|true|false|Dialog|Sheet|Drawer|Popover|HoverCard|Tooltip|Toast|Notice|Alert|Combobox|Select|MultiSelect|SelectMenu|DropdownMenu|Menu|MenuItem|Sidebar|TreeView|Tabs|Tab|Accordion|Collapsible|Breadcrumb|Pagination|Stepper|Steps|DataTable|FileItem|FileUpload|FileViewer|PeoplePicker|NameCard|OverflowIndicator|Checkbox|Radio|RadioGroup|CheckboxGroup|Switch|SegmentedControl|Slider|Rating|NumberInput|TextArea|SearchBox|DatePicker|TimePicker|DateGrid|Calendar|Carousel|Skeleton|CircularProgress|ProgressBar|LinearProgress|Empty|ScrollArea|AspectRatio|Separator|Toolbar|Header|SurfaceHeader|ChromeHeader|DialogHeader|SheetHeader|PopoverHeader|SidebarHeader|TabsList|TabsTrigger|TabsContent|ColorMatrix|SizeMatrix|StateBehavior|Accessibility|Anatomy|Overview|Inspector|Usage|Default|withTabs|asChild)\b', re.I)
378
+ COMMON_JARGON = re.compile(r'\b(row|overlay|per-row|tree-table|chrome|offcanvas|flow|tag|tab|panel|sheet|popup)\b', re.I)
379
+ with open('$FILE_PATH') as f:
380
+ for lineno, line in enumerate(f, 1):
381
+ m = re.search(r\"name:\s*['\\\"]([^'\\\"]+)['\\\"]\", line)
382
+ if not m: continue
383
+ name = m.group(1)
384
+ if not (re.search(r'[a-zA-Z]', name) and re.search(r'[\u4e00-\u9fff]', name)):
385
+ continue
386
+ stripped = EXEMPT.sub('', name)
387
+ if COMMON_JARGON.search(stripped):
388
+ print(f'{lineno}: {name}')
389
+ " 2>/dev/null | head -10)
390
+ [ -n "$MIXED_HITS" ] && violations="${violations}
391
+ ⚠️ story name 中英夾雜(common-word jargon 應中文化):
392
+ ${MIXED_HITS}
393
+ → row→列 / overlay→浮層 / per-row→逐列 / tree-table→樹狀表格 / chrome→框架 / offcanvas→抽屜收合 / flow→流程 / tag→標籤"
394
+
395
+ if [ -n "$violations" ]; then
396
+ CTX=$(printf 'R5 name jargon:%b' "$violations")
397
+ jq -n --arg ctx "$CTX" '{
398
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: $ctx }
399
+ }'
400
+ fi
401
+ }
402
+
403
+ # ─────────────────────────────────────────────────────────────────────────────
404
+ # R6 — description_jargon(PostToolUse,reads disk — scans `description:` block)
405
+ # ─────────────────────────────────────────────────────────────────────────────
406
+ # 對齊 user 2026-05-11 糾正:CellErrors 描述出現 `Record<rowId:colId, string | string[]>`
407
+ # = 純 programmer jargon,不該在 stakeholder-facing story 描述。對齊 mindset #4「範例必
408
+ # 真實業務場景」。Scope:只看 `展示` 層的 stories(.stories.tsx),排除 anatomy /
409
+ # principles 因為那些是 dev-facing spec stories,props matrix 用 TS 簽名 OK。
410
+ rule_description_jargon() {
411
+ [ "$EVENT" != "PostToolUse" ] && return 0
412
+ [ ! -f "$FILE_PATH" ] && return 0
413
+ # Skip anatomy / principles stories(dev-facing)
414
+ case "$FILE_PATH" in
415
+ *.anatomy.stories.tsx|*.principles.stories.tsx) return 0 ;;
416
+ esac
417
+
418
+ # Extract `description:` blocks(Storybook docs.description.{component,story})
419
+ # Pattern conservative:catch backtick / quoted string lines after `description:` containing TS generics
420
+ local violations=""
421
+
422
+ # TS generic jargon in description string literals
423
+ local TS_GENERIC_HITS=$(awk '
424
+ /description[[:space:]]*:/ { in_desc=1; row=NR; next }
425
+ in_desc && /^[[:space:]]*\}/ { in_desc=0 }
426
+ in_desc && /Record[[:space:]]*</ { print NR": "$0; in_desc=2 }
427
+ in_desc && /Partial[[:space:]]*</ { print NR": "$0; in_desc=2 }
428
+ in_desc && /Promise[[:space:]]*</ { print NR": "$0; in_desc=2 }
429
+ in_desc && /Awaited[[:space:]]*</ { print NR": "$0; in_desc=2 }
430
+ in_desc && /Array[[:space:]]*</ { print NR": "$0; in_desc=2 }
431
+ in_desc && /ReactNode/ { print NR": "$0; in_desc=2 }
432
+ in_desc && /string[[:space:]]*\|[[:space:]]*string\[\]/ { print NR": "$0; in_desc=2 }
433
+ in_desc && /string[[:space:]]*\|[[:space:]]*number/ { print NR": "$0; in_desc=2 }
434
+ ' "$FILE_PATH" 2>/dev/null | head -5)
435
+
436
+ [ -n "$TS_GENERIC_HITS" ] && violations="${violations}
437
+ ⚠️ story description 含 TS generic / type-signature jargon(stakeholder-facing 應人話業務場景):
438
+ ${TS_GENERIC_HITS}
439
+ → 改寫成業務情境描述,避免 Record<...> / string | string[] / ReactNode 等 API 簽名"
440
+
441
+ # Bare prop name in backticks inside description(e.g., \`onSelect\`, \`maxItems\`)
442
+ # 這類 prop ref 在 anatomy story OK,展示 story 該描述「做什麼」不是「prop 叫什麼」
443
+ local PROP_REF_HITS=$(awk '
444
+ /description[[:space:]]*:/ { in_desc=1; next }
445
+ in_desc && /^[[:space:]]*\}/ { in_desc=0 }
446
+ in_desc && /`(on[A-Z]|enable[A-Z]|max[A-Z]|allow[A-Z]|use[A-Z]|set[A-Z])[a-zA-Z]+`/ { print NR": "$0 }
447
+ ' "$FILE_PATH" 2>/dev/null | head -3)
448
+
449
+ [ -n "$PROP_REF_HITS" ] && violations="${violations}
450
+ ⚠️ story description 直接引用 prop 名(不該以 API 字典 思維寫描述):
451
+ ${PROP_REF_HITS}
452
+ → 改寫成「使用者看到什麼 / 業務情境是什麼」"
453
+
454
+ if [ -n "$violations" ]; then
455
+ CTX=$(printf 'R6 description jargon:%b\n豁免:檔首 // @description-jargon-allow: <reason>' "$violations")
456
+ # Check allowlist marker
457
+ if head -3 "$FILE_PATH" | grep -qE '//[[:space:]]*@description-jargon-allow:'; then
458
+ return 0
459
+ fi
460
+ jq -n --arg ctx "$CTX" '{
461
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: $ctx }
462
+ }'
463
+ fi
464
+ }
465
+
466
+ # R7 — story_baseline_reference(PreToolUse Write/Edit,2026-05-20 codify per codex anti-drift D2)
467
+ # 偵測 stories.tsx wrap 既有 primitive(<Sidebar> / <ChromeHeader> / <DataTable> 等)但跡證顯示
468
+ # simplified mock(無 import 該 family helper / 無 @story-baseline marker)— stderr warn drift。
469
+ # Anti-pattern 錨例:AppShell story 用 <Sidebar> 但 <SidebarHeader><span>name</span> 取代既有 WorkspaceBrand。
470
+
471
+ rule_story_baseline_reference() {
472
+ case "$TOOL" in
473
+ Write|Edit) ;;
474
+ *) return 0 ;;
475
+ esac
476
+
477
+ case "$FILE_PATH" in
478
+ *.stories.tsx) ;;
479
+ *) return 0 ;;
480
+ esac
481
+
482
+ # 跳 same-file:Sidebar / ChromeHeader / DataTable 自己的 stories 不檢查
483
+ case "$FILE_PATH" in
484
+ */Sidebar/*|*/DataTable/*|*/header-canonical/*|*/Dialog/*|*/Sheet/*|*/Popover/*) return 0 ;;
485
+ esac
486
+
487
+ # 抓寫入內容
488
+ local CONTENT=""
489
+ if [ "$TOOL" = "Write" ]; then
490
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // ""')
491
+ else
492
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""')
493
+ fi
494
+
495
+ # 偵測 wrap 既有 primitive 但無 baseline marker
496
+ if echo "$CONTENT" | grep -qE '<(Sidebar|ChromeHeader|DataTable|Dialog|Sheet)\b'; then
497
+ # 檢 @story-baseline marker(現有檔 OR 新內容)
498
+ local HAS_BASELINE=0
499
+ if [ -f "$FILE_PATH" ] && head -10 "$FILE_PATH" 2>/dev/null | grep -qE '@story-baseline:'; then
500
+ HAS_BASELINE=1
501
+ fi
502
+ if echo "$CONTENT" | head -10 | grep -qE '@story-baseline:'; then
503
+ HAS_BASELINE=1
504
+ fi
505
+
506
+ if [ "$HAS_BASELINE" -eq 0 ]; then
507
+ echo "⚠️ R7 story_baseline_reference 違規:" >&2
508
+ echo " $FILE_PATH wrap <Sidebar|ChromeHeader|DataTable|Dialog|Sheet>" >&2
509
+ echo " 但檔頭無 \`// @story-baseline: <path>#<StoryName>\` cite reference。" >&2
510
+ echo "" >&2
511
+ echo " 寫 stories wrap 既有 primitive 必先 grep family 完整佈局 story" >&2
512
+ echo " (eg. sidebar.stories IconCollapse / data-table.stories WithBulkActions)" >&2
513
+ echo " Read 其 helper(WorkspaceBrand / MAIN_NAV / PageContent / toolbar)當 baseline。" >&2
514
+ echo " 詳 .claude/rules/story-rules.md 「Production-grade composition fidelity」 +" >&2
515
+ echo " .claude/skills/story-writing/SKILL.md Phase 0 +" >&2
516
+ echo " memory/feedback_story_baseline_reference.md" >&2
517
+ fi
518
+
519
+ # 偵測明顯 simplified mock anti-pattern
520
+ if echo "$CONTENT" | grep -qE '<SidebarHeader>[[:space:]]*<span'; then
521
+ echo "❌ R7 anti-pattern:<SidebarHeader><span> — 應 wrap WorkspaceBrand-like ItemAvatar block(per sidebar.stories IconCollapse baseline)" >&2
522
+ fi
523
+ if echo "$CONTENT" | grep -qE '<SidebarMenuButton>[^<]*<[A-Z][a-zA-Z]+ className="size-'; then
524
+ echo "❌ R7 anti-pattern:<SidebarMenuButton><Icon className=\"size-N\"> — 應用 startIcon prop + tooltip prop(per sidebar.stories MAIN_NAV map)" >&2
525
+ fi
526
+ if echo "$CONTENT" | grep -qE '<ChromeHeader>[^<]*<span className="[^"]*flex-1'; then
527
+ echo "❌ R7 anti-pattern:<ChromeHeader><span flex-1> — 應 SidebarTrigger + h1 緊鄰 gap-2(per sidebar.stories PageContent baseline)" >&2
528
+ fi
529
+ fi
530
+ }
531
+
532
+ # R8 — story_archetype_registry(PreToolUse Write/Edit,2026-05-20 codify per M35 + codex Layer B D4)
533
+ # Registry-driven nearest same-purpose canonical enforce。讀
534
+ # `.claude/references/story-baseline-registry.json` antiPatterns regex,逐條 scan 寫入內容。
535
+ # Severity=block → record_worst 2;severity=warn → stderr only。Allowlist
536
+ # `// @story-baseline-allow: <reason>` 整檔豁免。
537
+ # Ship as warn mode first(2026-05-20),確認 zero existing violation 才升 P0 BLOCKER。
538
+
539
+ rule_story_archetype_registry() {
540
+ case "$TOOL" in
541
+ Write|Edit) ;;
542
+ *) return 0 ;;
543
+ esac
544
+
545
+ case "$FILE_PATH" in
546
+ *.stories.tsx) ;;
547
+ *) return 0 ;;
548
+ esac
549
+
550
+ # Skip self-family
551
+ case "$FILE_PATH" in
552
+ */Sidebar/*|*/DataTable/*|*/header-canonical/*|*/Dialog/*|*/Sheet/*|*/Popover/*) return 0 ;;
553
+ esac
554
+
555
+ local REGISTRY=".claude/references/story-baseline-registry.json"
556
+ [ -f "$REGISTRY" ] || return 0
557
+
558
+ local CONTENT=""
559
+ if [ "$TOOL" = "Write" ]; then
560
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // ""')
561
+ else
562
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.new_string // ""')
563
+ fi
564
+
565
+ # Allow override
566
+ if echo "$CONTENT" | head -10 | grep -qE '@story-baseline-allow:'; then
567
+ return 0
568
+ fi
569
+
570
+ # Read antiPatterns regex from registry(per component)
571
+ # Iterate Sidebar/DataTable/ChromeHeader components
572
+ local COMPONENTS="Sidebar DataTable ChromeHeader"
573
+ for COMP in $COMPONENTS; do
574
+ # Only check if file wraps this component
575
+ if ! echo "$CONTENT" | grep -qE "<${COMP}\\b"; then
576
+ continue
577
+ fi
578
+
579
+ # Read antiPatterns regex list(P0 block only — warn ship later)
580
+ local PATTERNS
581
+ PATTERNS=$(jq -r --arg c "$COMP" '.components[$c].antiPatterns[]? | select(.severity == "block") | .regex' "$REGISTRY" 2>/dev/null)
582
+ [ -z "$PATTERNS" ] && continue
583
+
584
+ while IFS= read -r PATTERN; do
585
+ [ -z "$PATTERN" ] && continue
586
+ if echo "$CONTENT" | grep -qE "$PATTERN"; then
587
+ echo "⚠️ R8 story_archetype_registry violation:" >&2
588
+ echo " $FILE_PATH wrap <$COMP> matches anti-pattern:" >&2
589
+ echo " regex: $PATTERN" >&2
590
+ echo " per registry: .claude/references/story-baseline-registry.json#components.$COMP.antiPatterns" >&2
591
+ echo "" >&2
592
+ echo " 修法:Read baseline story + helpers,抄 production archetype。" >&2
593
+ echo " 或加 \`// @story-baseline-allow: <reason>\` 檔頭豁免(audit-logged)。" >&2
594
+ echo " 詳 .claude/rules/meta-patterns.md M35 + memory/feedback_nearest_same_purpose_canonical.md" >&2
595
+ # Ship as warn first(2026-05-20):not record_worst 2,exit 0
596
+ # Future:zero existing violation → 改 record_worst 2 升 P0 BLOCKER
597
+ fi
598
+ done <<< "$PATTERNS"
599
+ done
600
+ }
601
+
602
+ # ─── Run rules ───
603
+ rule_anatomy
604
+ rule_slot_split
605
+ rule_category
606
+ rule_title_canonical
607
+ rule_name_jargon
608
+ rule_description_jargon
609
+ rule_story_baseline_reference
610
+ rule_story_archetype_registry
611
+
612
+ exit $WORST