@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,187 @@
1
+ #!/bin/bash
2
+ # Tests for check_story_category.sh
3
+ # Verifies trait-based compliance enforcement
4
+
5
+ set -u
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ # Cluster A merge(2026-05-10):check_story_category.sh fold 進
9
+ # check_story_invariants.sh dispatcher R3。Test 走 dispatcher。
10
+ HOOK="$SCRIPT_DIR/../check_story_invariants.sh"
11
+ [ -x "$HOOK" ] || { echo "FATAL: hook not executable"; exit 1; }
12
+
13
+ PASS=0; FAIL=0; FAILED=""
14
+
15
+ setup_proj() {
16
+ TMP_PROJ=$(mktemp -d)
17
+ mkdir -p "$TMP_PROJ/src/design-system/components/Foo" "$TMP_PROJ/.claude/hooks"
18
+ echo 'log_hook_fire() { :; }' > "$TMP_PROJ/.claude/hooks/_log-fire.sh"
19
+ }
20
+ teardown_proj() { rm -rf "$TMP_PROJ"; }
21
+
22
+ run_hook() {
23
+ local content="$1"
24
+ local file_path="$2"
25
+ local payload
26
+ payload=$(jq -n \
27
+ --arg fp "$file_path" \
28
+ --arg ct "$content" \
29
+ '{tool_name:"Write", tool_input:{file_path:$fp, content:$ct}}')
30
+ STDOUT=$(echo "$payload" | bash "$HOOK" 2>&1)
31
+ EXIT=$?
32
+ }
33
+
34
+ # ── Test 1: no spec.md → silent pass ─────────────────────────────────────────
35
+ echo "Test 1: no spec.md → silent pass"
36
+ setup_proj
37
+ run_hook "export const Default = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
38
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
39
+ echo " PASS Test 1"; PASS=$((PASS+1))
40
+ else
41
+ echo " FAIL Test 1 (exit=$EXIT, output=${STDOUT:0:100})"
42
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 1"
43
+ fi
44
+ teardown_proj
45
+
46
+ # ── Test 2: spec without traits frontmatter → silent pass ────────────────────
47
+ echo "Test 2: spec without traits → silent pass"
48
+ setup_proj
49
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
50
+ # Foo
51
+ Some content.
52
+ EOF
53
+ run_hook "export const Default = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
54
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
55
+ echo " PASS Test 2"; PASS=$((PASS+1))
56
+ else
57
+ echo " FAIL Test 2 (exit=$EXIT, output=${STDOUT:0:100})"
58
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 2"
59
+ fi
60
+ teardown_proj
61
+
62
+ # ── Test 3: hasSizes trait + AllSizes present → pass ─────────────────────────
63
+ echo "Test 3: hasSizes + AllSizes present → pass"
64
+ setup_proj
65
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
66
+ ---
67
+ component: Foo
68
+ traits:
69
+ - hasSizes
70
+ - hasInteractiveStates
71
+ ---
72
+ # Foo
73
+ EOF
74
+ run_hook "export const Default = {};
75
+ export const AllSizes = {};
76
+ export const Disabled = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
77
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
78
+ echo " PASS Test 3"; PASS=$((PASS+1))
79
+ else
80
+ echo " FAIL Test 3 (exit=$EXIT, output=${STDOUT:0:200})"
81
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 3"
82
+ fi
83
+ teardown_proj
84
+
85
+ # ── Test 4: hasSizes trait + per-size split → BLOCK ──────────────────────────
86
+ echo "Test 4: hasSizes + Small/Medium/Large split → block P0"
87
+ setup_proj
88
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
89
+ ---
90
+ traits:
91
+ - hasSizes
92
+ ---
93
+ EOF
94
+ run_hook "export const Default = {};
95
+ export const Small = {};
96
+ export const Medium = {};
97
+ export const Large = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
98
+ if [ "$EXIT" = "2" ] && echo "$STDOUT" | grep -q "per-size split detected"; then
99
+ echo " PASS Test 4 per-size split blocked"; PASS=$((PASS+1))
100
+ else
101
+ echo " FAIL Test 4 (exit=$EXIT, output=${STDOUT:0:200})"
102
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 4"
103
+ fi
104
+ teardown_proj
105
+
106
+ # ── Test 5: isOverlay trait + no OpenSnapshot → BLOCK ────────────────────────
107
+ echo "Test 5: isOverlay + no OpenSnapshot → block P0"
108
+ setup_proj
109
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
110
+ ---
111
+ traits:
112
+ - isOverlay
113
+ ---
114
+ EOF
115
+ run_hook "export const Default = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
116
+ if [ "$EXIT" = "2" ] && echo "$STDOUT" | grep -q "isOverlay"; then
117
+ echo " PASS Test 5 overlay missing OpenSnapshot blocked"; PASS=$((PASS+1))
118
+ else
119
+ echo " FAIL Test 5 (exit=$EXIT, output=${STDOUT:0:200})"
120
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 5"
121
+ fi
122
+ teardown_proj
123
+
124
+ # ── Test 6: isOverlay + defaultOpen present → pass ───────────────────────────
125
+ echo "Test 6: isOverlay + defaultOpen=true present → pass"
126
+ setup_proj
127
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
128
+ ---
129
+ traits:
130
+ - isOverlay
131
+ ---
132
+ EOF
133
+ run_hook "export const Default = { args: { defaultOpen: true } };" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
134
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
135
+ echo " PASS Test 6 defaultOpen ✓ pass"; PASS=$((PASS+1))
136
+ else
137
+ echo " FAIL Test 6 (exit=$EXIT, output=${STDOUT:0:200})"
138
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 6"
139
+ fi
140
+ teardown_proj
141
+
142
+ # ── Test 7: rationale escape allowlist ──────────────────────────────────────
143
+ echo "Test 7: @story-trait-rationale escape → pass"
144
+ setup_proj
145
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
146
+ ---
147
+ traits:
148
+ - hasSizes
149
+ ---
150
+ EOF
151
+ run_hook "// @story-trait-rationale: experimental design exploration
152
+ export const Small = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.stories.tsx"
153
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
154
+ echo " PASS Test 7 rationale escape works"; PASS=$((PASS+1))
155
+ else
156
+ echo " FAIL Test 7 (exit=$EXIT, output=${STDOUT:0:200})"
157
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 7"
158
+ fi
159
+ teardown_proj
160
+
161
+ # ── Test 8: anatomy/principles stories skipped ──────────────────────────────
162
+ echo "Test 8: .anatomy.stories.tsx skipped(not subject to trait typology)"
163
+ setup_proj
164
+ cat > "$TMP_PROJ/src/design-system/components/Foo/foo.spec.md" <<EOF
165
+ ---
166
+ traits:
167
+ - hasSizes
168
+ ---
169
+ EOF
170
+ run_hook "export const Small = {};" "$TMP_PROJ/src/design-system/components/Foo/foo.anatomy.stories.tsx"
171
+ if [ "$EXIT" = "0" ] && [ -z "$STDOUT" ]; then
172
+ echo " PASS Test 8 anatomy stories exempted"; PASS=$((PASS+1))
173
+ else
174
+ echo " FAIL Test 8 (exit=$EXIT, output=${STDOUT:0:200})"
175
+ FAIL=$((FAIL+1)); FAILED="${FAILED}\n - Test 8"
176
+ fi
177
+ teardown_proj
178
+
179
+ # ── Summary ─────────────────────────────────────────────────────────────────
180
+ echo ""
181
+ echo "════════════════════════════════════════"
182
+ echo " Results: $PASS PASS, $FAIL FAIL"
183
+ echo "════════════════════════════════════════"
184
+ if [ "$FAIL" -gt 0 ]; then
185
+ printf "Failed:%b\n" "$FAILED"; exit 1
186
+ fi
187
+ exit 0
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # Smoke test for check_story_compile_drift.sh
3
+ set -u
4
+ HOOK="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/_story_compile_drift.sh"
5
+ [ -x "$HOOK" ] || { echo "FATAL: hook not exec"; exit 1; }
6
+ PASS=0; FAIL=0
7
+ run_hook() {
8
+ local payload=$(jq -n --arg fp "$1" --arg ct "$2" '{tool_name:"Write", tool_input:{file_path:$fp, content:$ct}}')
9
+ STDOUT=$(echo "$payload" | bash "$HOOK" 2>&1); EXIT=$?
10
+ }
11
+ echo "Test 1: non-matching file → silent skip"
12
+ run_hook "/tmp/random.txt" "x"
13
+ [ "$EXIT" = "0" ] && [ -z "$STDOUT" ] && { echo " PASS"; PASS=$((PASS+1)); } || { echo " FAIL exit=$EXIT out=${STDOUT:0:80}"; FAIL=$((FAIL+1)); }
14
+ echo "Results: $PASS PASS, $FAIL FAIL"
15
+ [ "$FAIL" -eq 0 ] || exit 1
@@ -0,0 +1,209 @@
1
+ #!/bin/bash
2
+ # Tests for check_story_invariants.sh(Cluster A merge dispatcher,2026-05-10)
3
+ #
4
+ # Hook 規則:Pre/PostToolUse + Edit|Write|MultiEdit + *.stories.tsx
5
+ # 內部 8 rule:
6
+ # R1 anatomy(PreToolUse;raw hand-craft item/table/loading/overlay/dismiss → exit 2)
7
+ # R2 slot_split(PreToolUse;WithStartIcon+WithEndIcon / Default+AllVariants 拆 → exit 2)
8
+ # R3 category(PreToolUse;trait-based — 需 spec.md frontmatter,本 test 不 cover)
9
+ # R4 title_canonical(PreToolUse;non-canonical English name: → P1 stderr warn only)
10
+ # R5 name_jargon(PostToolUse;reads disk;L<n> layer / canonical / 中英夾雜 jargon)
11
+ # R6 description_jargon(PostToolUse;TS generic in description: → stderr warn)
12
+ # R7 story_baseline_reference(PreToolUse;wrap Sidebar/ChromeHeader/DataTable 無 baseline marker → stderr warn)
13
+ # R8 story_archetype_registry(PreToolUse;讀 .claude/references/story-baseline-registry.json,warn-only)
14
+ #
15
+ # Test 重點:silent skip / 各 rule fire / allowlist marker escape。
16
+ # 不測 R3/R8(需 spec.md 或 registry 完整 fixture,scope 超 batch A)。
17
+
18
+ set -u
19
+
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ HOOK="$SCRIPT_DIR/../check_story_invariants.sh"
22
+
23
+ if [ ! -x "$HOOK" ]; then
24
+ echo "FATAL: hook not executable: $HOOK"
25
+ exit 1
26
+ fi
27
+
28
+ PASS=0
29
+ FAIL=0
30
+ FAILED_TESTS=""
31
+
32
+ TMP_DIR=$(mktemp -d)
33
+ trap 'rm -rf "$TMP_DIR"' EXIT
34
+
35
+ run_hook() {
36
+ local event="$1"; local tool="$2"; local file_path="$3"; local content="$4"
37
+ local payload
38
+ if [ "$tool" = "Edit" ]; then
39
+ payload=$(jq -n \
40
+ --arg ev "$event" --arg tn "$tool" --arg fp "$file_path" --arg c "$content" \
41
+ '{hook_event_name:$ev, tool_name:$tn, tool_input:{file_path:$fp, new_string:$c}}')
42
+ else
43
+ payload=$(jq -n \
44
+ --arg ev "$event" --arg tn "$tool" --arg fp "$file_path" --arg c "$content" \
45
+ '{hook_event_name:$ev, tool_name:$tn, tool_input:{file_path:$fp, content:$c}}')
46
+ fi
47
+ STDOUT=$(mktemp); STDERR=$(mktemp)
48
+ set +e
49
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
50
+ EXIT=$?
51
+ set -e
52
+ STDERR_TEXT=$(cat "$STDERR")
53
+ rm -f "$STDOUT" "$STDERR"
54
+ }
55
+
56
+ expect_pass_silent() {
57
+ local name="$1"
58
+ if [ "$EXIT" = "0" ] && [ -z "$STDERR_TEXT" ]; then
59
+ echo " PASS $name"; PASS=$((PASS+1))
60
+ else
61
+ echo " FAIL $name (expected silent, exit=$EXIT, stderr=$([ -n "$STDERR_TEXT" ] && echo non-empty || echo empty))"
62
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
63
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
64
+ fi
65
+ }
66
+
67
+ expect_block() {
68
+ local name="$1"; local needle="$2"
69
+ if [ "$EXIT" = "2" ] && echo "$STDERR_TEXT" | grep -qF "$needle"; then
70
+ echo " PASS $name"; PASS=$((PASS+1))
71
+ else
72
+ echo " FAIL $name (expected BLOCK exit=2 + '$needle', got exit=$EXIT)"
73
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
74
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
75
+ fi
76
+ }
77
+
78
+ expect_warn() {
79
+ local name="$1"; local needle="$2"
80
+ if [ "$EXIT" = "0" ] && echo "$STDERR_TEXT" | grep -qF "$needle"; then
81
+ echo " PASS $name"; PASS=$((PASS+1))
82
+ else
83
+ echo " FAIL $name (expected stderr warn '$needle', exit=$EXIT)"
84
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
85
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
86
+ fi
87
+ }
88
+
89
+ echo "=== check_story_invariants tests ==="
90
+
91
+ # 1. Non-stories file → skip
92
+ run_hook "PreToolUse" "Edit" "/foo/button.tsx" "<table>"
93
+ expect_pass_silent "1. non-stories.tsx → skip"
94
+
95
+ # 2. Wrong tool → skip
96
+ run_hook "PreToolUse" "Read" "/foo/button.stories.tsx" "<table>"
97
+ expect_pass_silent "2. tool=Read → skip"
98
+
99
+ # 3. R2 slot_split: WithStartIcon + WithEndIcon both → BLOCK exit 2
100
+ STORIES_BTN="/foo/my-project/packages/design-system/src/components/Button/button.stories.tsx"
101
+ run_hook "PreToolUse" "Write" "$STORIES_BTN" '
102
+ export const Default = { args: {} };
103
+ export const WithStartIcon = { args: { startIcon: <Icon /> } };
104
+ export const WithEndIcon = { args: { endIcon: <Icon /> } };
105
+ '
106
+ expect_block "3. R2 WithStartIcon + WithEndIcon → BLOCK" "WithStartIcon + WithEndIcon"
107
+
108
+ # 4. R2 slot_split: allow marker → silent
109
+ run_hook "PreToolUse" "Write" "$STORIES_BTN" '// @story-split-rationale: legacy showcase
110
+ export const Default = { args: {} };
111
+ export const WithStartIcon = { args: { startIcon: <Icon /> } };
112
+ export const WithEndIcon = { args: { endIcon: <Icon /> } };
113
+ '
114
+ expect_pass_silent "4. R2 with @story-split-rationale marker → silent"
115
+
116
+ # 5. R1 anatomy: raw <table> outside DataTable → BLOCK exit 2
117
+ run_hook "PreToolUse" "Write" "$STORIES_BTN" '
118
+ export const Default = () => (
119
+ <div>
120
+ <table>
121
+ <tr><td>x</td></tr>
122
+ </table>
123
+ </div>
124
+ );
125
+ '
126
+ expect_block "5. R1 raw <table> outside DataTable → BLOCK" "raw <table>"
127
+
128
+ # 6. R1 anatomy: allowlist @anatomy-exempt: → silent
129
+ run_hook "PreToolUse" "Write" "$STORIES_BTN" '// @anatomy-exempt: legacy demo with raw table
130
+ export const Default = () => (
131
+ <div>
132
+ <table>
133
+ <tr><td>x</td></tr>
134
+ </table>
135
+ </div>
136
+ );
137
+ '
138
+ expect_pass_silent "6. R1 @anatomy-exempt marker → silent"
139
+
140
+ # 7. Clean story (no violations) → silent
141
+ # Note: AllVariants alone(no Default)since hook flags `Default + AllVariants` as redundant
142
+ STORIES_CLEAN="/foo/my-project/packages/design-system/src/components/Foo/foo.stories.tsx"
143
+ run_hook "PreToolUse" "Write" "$STORIES_CLEAN" '
144
+ export const AllVariants = { args: {} };
145
+ export const Disabled = { args: { disabled: true } };
146
+ '
147
+ expect_pass_silent "7. clean story (AllVariants + Disabled, no anti-patterns) → silent"
148
+
149
+ # 8. R5 name_jargon (PostToolUse, reads disk): L<n> layer name → stderr warn
150
+ STORIES_DISK="$TMP_DIR/datatable.stories.tsx"
151
+ cat > "$STORIES_DISK" <<'EOF'
152
+ export const Default = {
153
+ name: 'L1 基本展示',
154
+ };
155
+ EOF
156
+ run_hook "PostToolUse" "Edit" "$STORIES_DISK" "(any update marker)"
157
+ # R5 emits 'L<n> layer 代號' warning via stderr-injected context;但實際 hook emit
158
+ # 是 jq stdout JSON,我們檢 STDERR 是否含 violation 或 stdout — 兩種任一即算 hit。
159
+ # 觀察 source:rule_name_jargon 用 jq -n stdout(不是 stderr)。改檢 STDOUT。
160
+ # 重跑 — 拿 stdout
161
+ payload=$(jq -n --arg ev "PostToolUse" --arg fp "$STORIES_DISK" \
162
+ '{hook_event_name:$ev, tool_name:"Edit", tool_input:{file_path:$fp, new_string:""}}')
163
+ STDOUT_PATH=$(mktemp); STDERR_PATH=$(mktemp)
164
+ set +e
165
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT_PATH" 2>"$STDERR_PATH"
166
+ EXIT=$?
167
+ set -e
168
+ STDOUT_TEXT=$(cat "$STDOUT_PATH")
169
+ STDERR_TEXT=$(cat "$STDERR_PATH")
170
+ rm -f "$STDOUT_PATH" "$STDERR_PATH"
171
+ if [ "$EXIT" = "0" ] && echo "$STDOUT_TEXT" | grep -q "L<n>"; then
172
+ echo " PASS 8. R5 PostToolUse L<n> layer name → stdout JSON warn"
173
+ PASS=$((PASS+1))
174
+ else
175
+ echo " FAIL 8. R5 PostToolUse L<n> layer name → expected stdout 'L<n>'"
176
+ echo " --- stdout ---"; echo "$STDOUT_TEXT" | sed 's/^/ /'
177
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'
178
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - 8. R5"
179
+ fi
180
+
181
+ # 9. R4 title_canonical: prop-leak syntax in name → P1 stderr warn (exit 0)
182
+ # Use prop/parameter leak pattern `(prop)` which matches `\([a-zA-Z]+\)` branch — robust on macOS BSD grep
183
+ # (pure English non-whitelisted depends on `[^\x00-\x7F]` regex semantics which vary)
184
+ run_hook "PreToolUse" "Write" "$STORIES_CLEAN" "
185
+ export const Default = {
186
+ name: 'Default (size=md)',
187
+ };
188
+ "
189
+ expect_warn "9. R4 prop-leak syntax in name → P1 warn" "R4 title_canonical"
190
+
191
+ # 10. R7 baseline reference: wrap <Sidebar> without baseline marker → stderr warn
192
+ # Use a path NOT in skip list (Sidebar/, DataTable/, etc are skipped self-family)
193
+ STORIES_APP="/foo/my-project/packages/design-system/src/components/AppShell/app-shell.stories.tsx"
194
+ run_hook "PreToolUse" "Write" "$STORIES_APP" '
195
+ export const Default = () => (
196
+ <Sidebar>
197
+ <SidebarHeader><span>Acme</span></SidebarHeader>
198
+ </Sidebar>
199
+ );
200
+ '
201
+ expect_warn "10. R7 wrap <Sidebar> no @story-baseline → stderr warn" "R7 story_baseline_reference"
202
+
203
+ echo ""
204
+ echo "=== Summary ==="
205
+ echo "Passed: $PASS / $((PASS + FAIL))"
206
+ if [ "$FAIL" -gt 0 ]; then
207
+ echo "Failed:$FAILED_TESTS"
208
+ exit 1
209
+ fi
@@ -0,0 +1,53 @@
1
+ #!/bin/bash
2
+ # Tests for check_story_name_jargon.sh
3
+ set -u
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # Cluster A merge(2026-05-10):check_story_name_jargon.sh fold 進
6
+ # check_story_invariants.sh dispatcher R5(PostToolUse)。Test 走 dispatcher。
7
+ HOOK="$SCRIPT_DIR/../check_story_invariants.sh"
8
+ [ -x "$HOOK" ] || { echo "FATAL: hook not executable"; exit 1; }
9
+ PASS=0; FAIL=0
10
+
11
+ setup() { TMP=$(mktemp -d); mkdir -p "$TMP/.claude/hooks"; echo 'log_hook_fire(){ :; }' > "$TMP/.claude/hooks/_log-fire.sh"; }
12
+ teardown() { rm -rf "$TMP"; }
13
+
14
+ run() {
15
+ STDOUT=$(echo "{\"tool_input\":{\"file_path\":\"$1\"}}" | bash "$HOOK" 2>&1)
16
+ EXIT=$?
17
+ }
18
+
19
+ # Test 1: non-stories file → silent
20
+ echo "Test 1: non-stories.tsx → silent"
21
+ setup
22
+ echo "export const x = {};" > "$TMP/foo.tsx"
23
+ run "$TMP/foo.tsx"
24
+ [ "$EXIT" = "0" ] && [ -z "$STDOUT" ] && { echo " PASS"; PASS=$((PASS+1)); } || { echo " FAIL"; FAIL=$((FAIL+1)); }
25
+ teardown
26
+
27
+ # Test 2: L<n> jargon → flag
28
+ echo "Test 2: 'L2 Selection' name → flagged"
29
+ setup
30
+ echo "export const X = { name: 'L2 Selection — foo' }" > "$TMP/test.stories.tsx"
31
+ run "$TMP/test.stories.tsx"
32
+ echo "$STDOUT" | grep -q "layer 代號" && { echo " PASS"; PASS=$((PASS+1)); } || { echo " FAIL: $STDOUT"; FAIL=$((FAIL+1)); }
33
+ teardown
34
+
35
+ # Test 3: 'canonical' in name → flag
36
+ echo "Test 3: 'canonical' name → flagged"
37
+ setup
38
+ echo "export const X = { name: '基本(canonical)' }" > "$TMP/test.stories.tsx"
39
+ run "$TMP/test.stories.tsx"
40
+ echo "$STDOUT" | grep -q "canonical" && { echo " PASS"; PASS=$((PASS+1)); } || { echo " FAIL"; FAIL=$((FAIL+1)); }
41
+ teardown
42
+
43
+ # Test 4: clean name → silent
44
+ echo "Test 4: 人話 name → silent"
45
+ setup
46
+ echo "export const X = { name: '基本' }" > "$TMP/test.stories.tsx"
47
+ run "$TMP/test.stories.tsx"
48
+ [ "$EXIT" = "0" ] && [ -z "$STDOUT" ] && { echo " PASS"; PASS=$((PASS+1)); } || { echo " FAIL: $STDOUT"; FAIL=$((FAIL+1)); }
49
+ teardown
50
+
51
+ echo ""
52
+ echo "── Summary: $PASS / $((PASS+FAIL)) passed ──"
53
+ [ "$FAIL" -eq 0 ] && echo "✅ All passed" || exit 1
@@ -0,0 +1,156 @@
1
+ #!/bin/bash
2
+ # Tests for check_story_slot_split.sh
3
+ #
4
+ # Drives PreToolUse Edit/Write payloads on stdin and verifies block vs pass
5
+ # for Manual story 拆分原則(.claude/rules/story-rules.md Polaris/Carbon idiom)。
6
+ #
7
+ # Usage: bash test_check_story_slot_split.sh
8
+
9
+ set -u
10
+
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ # Cluster A merge(2026-05-10):check_story_slot_split.sh fold 進
13
+ # check_story_invariants.sh dispatcher R2。Test 走 dispatcher。
14
+ HOOK="$SCRIPT_DIR/../check_story_invariants.sh"
15
+
16
+ if [ ! -x "$HOOK" ]; then
17
+ echo "FATAL: hook not executable: $HOOK"
18
+ exit 1
19
+ fi
20
+
21
+ PASS=0
22
+ FAIL=0
23
+ FAILED_TESTS=""
24
+
25
+ run_hook() {
26
+ local file_path="$1"
27
+ local content="$2"
28
+ local payload
29
+ payload=$(jq -n \
30
+ --arg fp "$file_path" \
31
+ --arg c "$content" \
32
+ '{tool_name: "Write", tool_input: {file_path: $fp, content: $c}}')
33
+
34
+ STDOUT=$(mktemp)
35
+ STDERR=$(mktemp)
36
+ set +e
37
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
38
+ EXIT=$?
39
+ set -e
40
+ STDOUT_TEXT=$(cat "$STDOUT")
41
+ STDERR_TEXT=$(cat "$STDERR")
42
+ rm -f "$STDOUT" "$STDERR"
43
+ }
44
+
45
+ expect_pass() {
46
+ local name="$1"
47
+ if [ "$EXIT" = "0" ]; then
48
+ echo " PASS $name"
49
+ PASS=$((PASS+1))
50
+ else
51
+ echo " FAIL $name (expected exit 0, got $EXIT)"
52
+ echo "$STDERR_TEXT" | sed 's/^/ /'
53
+ FAIL=$((FAIL+1))
54
+ FAILED_TESTS="${FAILED_TESTS}\n - $name"
55
+ fi
56
+ }
57
+
58
+ expect_block() {
59
+ local name="$1"
60
+ local needle="$2"
61
+ if [ "$EXIT" = "2" ] && echo "$STDERR_TEXT" | grep -qF "$needle"; then
62
+ echo " PASS $name"
63
+ PASS=$((PASS+1))
64
+ else
65
+ echo " FAIL $name (expected exit 2 + '$needle')"
66
+ echo "$STDERR_TEXT" | sed 's/^/ /'
67
+ FAIL=$((FAIL+1))
68
+ FAILED_TESTS="${FAILED_TESTS}\n - $name"
69
+ fi
70
+ }
71
+
72
+ # ── Test 1: WithStartIcon + WithEndIcon 拆兩 → block ─────────────────────────
73
+ echo "Test 1: WithStartIcon + WithEndIcon 同檔 → block"
74
+ read -r -d '' T1 <<'EOF' || true
75
+ export const WithStartIcon: Story = { args: { startIcon: Plus } }
76
+ export const WithEndIcon: Story = { args: { endIcon: ChevronDown } }
77
+ EOF
78
+ run_hook "/fake/chip.stories.tsx" "$T1"
79
+ expect_block "Test 1 WithStartIcon + WithEndIcon blocked" "WithStartIcon + WithEndIcon"
80
+
81
+ # ── Test 2: 只 WithIcon → pass ─────────────────────────────────────────────────
82
+ echo ""
83
+ echo "Test 2: 只 WithIcon → pass"
84
+ read -r -d '' T2 <<'EOF' || true
85
+ export const WithIcon: Story = { args: { startIcon: Plus, endIcon: ChevronDown } }
86
+ EOF
87
+ run_hook "/fake/chip.stories.tsx" "$T2"
88
+ expect_pass "Test 2 WithIcon alone passes"
89
+
90
+ # ── Test 3: Default + AllVariants → block ─────────────────────────────────────
91
+ echo ""
92
+ echo "Test 3: Default + AllVariants 同檔 → block"
93
+ read -r -d '' T3 <<'EOF' || true
94
+ export const Default: Story = { args: { variant: 'primary' } }
95
+ export const AllVariants: Story = { render: () => (<>...</>) }
96
+ EOF
97
+ run_hook "/fake/button.stories.tsx" "$T3"
98
+ expect_block "Test 3 Default + AllVariants blocked" "Default + AllVariants"
99
+
100
+ # ── Test 4: 只 AllVariants → pass ──────────────────────────────────────────────
101
+ echo ""
102
+ echo "Test 4: 只 AllVariants → pass"
103
+ read -r -d '' T4 <<'EOF' || true
104
+ export const AllVariants: Story = { render: () => (<>...</>) }
105
+ EOF
106
+ run_hook "/fake/button.stories.tsx" "$T4"
107
+ expect_pass "Test 4 AllVariants alone passes"
108
+
109
+ # ── Test 5: Primary + Secondary + Tertiary 拆三 → block ───────────────────────
110
+ echo ""
111
+ echo "Test 5: Primary + Secondary + Tertiary 拆細 → block"
112
+ read -r -d '' T5 <<'EOF' || true
113
+ export const Primary: Story = { args: { variant: 'primary' } }
114
+ export const Secondary: Story = { args: { variant: 'secondary' } }
115
+ export const Tertiary: Story = { args: { variant: 'tertiary' } }
116
+ EOF
117
+ run_hook "/fake/button.stories.tsx" "$T5"
118
+ expect_block "Test 5 Primary/Secondary/Tertiary split blocked" "拆細"
119
+
120
+ # ── Test 6: anatomy.stories.tsx 不在 scope → pass even with violation ─────────
121
+ echo ""
122
+ echo "Test 6: anatomy.stories.tsx out of scope → pass"
123
+ read -r -d '' T6 <<'EOF' || true
124
+ export const WithStartIcon: Story = { args: { startIcon: Plus } }
125
+ export const WithEndIcon: Story = { args: { endIcon: ChevronDown } }
126
+ EOF
127
+ run_hook "/fake/chip.anatomy.stories.tsx" "$T6"
128
+ expect_pass "Test 6 anatomy.stories.tsx out of scope"
129
+
130
+ # ── Test 7: allowlist // @story-split-rationale: → bypass ─────────────────────
131
+ echo ""
132
+ echo "Test 7: allowlist marker → bypass"
133
+ read -r -d '' T7 <<'EOF' || true
134
+ // @story-split-rationale: startIcon vs endIcon 教不同 visual rules due to specific composition
135
+ export const WithStartIcon: Story = { args: { startIcon: Plus } }
136
+ export const WithEndIcon: Story = { args: { endIcon: ChevronDown } }
137
+ EOF
138
+ run_hook "/fake/special.stories.tsx" "$T7"
139
+ expect_pass "Test 7 allowlist bypasses"
140
+
141
+ # ── Test 8: 非 stories.tsx 不在 scope → pass ──────────────────────────────────
142
+ echo ""
143
+ echo "Test 8: .tsx (non-stories) → pass"
144
+ run_hook "/fake/Button.tsx" "export const WithStartIcon = ... export const WithEndIcon = ..."
145
+ expect_pass "Test 8 non-stories out of scope"
146
+
147
+ # ── Summary ──────────────────────────────────────────────────────────────────
148
+ echo ""
149
+ echo "════════════════════════════════════════"
150
+ echo " Results: $PASS PASS, $FAIL FAIL"
151
+ echo "════════════════════════════════════════"
152
+ if [ "$FAIL" -gt 0 ]; then
153
+ printf "Failed tests:%b\n" "$FAILED_TESTS"
154
+ exit 1
155
+ fi
156
+ exit 0