@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,201 @@
1
+ #!/bin/bash
2
+ # Tests for check_solo_workflow.sh(M28,2026-05-08 codified)
3
+ #
4
+ # Hook 規則(PreToolUse,Bash + mcp__github__create_pull_request + mcp__github__merge_pull_request):
5
+ # R1. `git checkout -b claude/X` 第 2 次 in same session → BLOCK exit 2
6
+ # (1st creation OK,record to TRACK_FILE)
7
+ # R2. `gh pr create` / `gh api -X POST .../pulls` / mcp__github__create_pull_request → BLOCK exit 2
8
+ # (read-only `gh api .../pulls/N/comments` 不 block)
9
+ # R3. `git push ... main` / mcp__github__merge_pull_request 無 user "push" trigger → BLOCK exit 2
10
+ # (transcript 含 push/OK/合 main keyword → silent pass)
11
+ # Override:CLAUDE_BYPASS_SOLO_WORKFLOW=1 → silent (audit-logged)。
12
+ # Non-Bash non-MCP / 非觸發 command → silent。
13
+
14
+ set -u
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ HOOK="$SCRIPT_DIR/../check_solo_workflow.sh"
18
+
19
+ if [ ! -x "$HOOK" ]; then
20
+ echo "FATAL: hook not executable: $HOOK"
21
+ exit 1
22
+ fi
23
+
24
+ PASS=0
25
+ FAIL=0
26
+ FAILED_TESTS=""
27
+
28
+ TMP_DIR=$(mktemp -d)
29
+ trap 'rm -rf "$TMP_DIR"' EXIT
30
+
31
+ # Override CLAUDE_PROJECT_DIR so TRACK_FILE / BYPASS_LOG land in TMP_DIR
32
+ # (避免污染 repo .claude/logs/)
33
+ export CLAUDE_PROJECT_DIR="$TMP_DIR"
34
+ mkdir -p "$TMP_DIR/.claude/logs"
35
+ TRACK_FILE="$TMP_DIR/.claude/logs/session-branch-track.jsonl"
36
+
37
+ build_transcript() {
38
+ local path="$1"; shift
39
+ : > "$path"
40
+ for msg in "$@"; do
41
+ jq -n --arg t "$msg" \
42
+ '{type:"user", message:{role:"user", content:$t}}' >> "$path"
43
+ done
44
+ }
45
+
46
+ run_hook_bash() {
47
+ local cmd="$1"; local session="${2:-sess-1}"; local transcript="${3:-}"
48
+ local payload
49
+ if [ -n "$transcript" ]; then
50
+ payload=$(jq -n \
51
+ --arg c "$cmd" --arg s "$session" --arg tp "$transcript" \
52
+ '{tool_name:"Bash", session_id:$s, transcript_path:$tp, tool_input:{command:$c}}')
53
+ else
54
+ payload=$(jq -n \
55
+ --arg c "$cmd" --arg s "$session" \
56
+ '{tool_name:"Bash", session_id:$s, tool_input:{command:$c}}')
57
+ fi
58
+ STDOUT=$(mktemp); STDERR=$(mktemp)
59
+ set +e
60
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
61
+ EXIT=$?
62
+ set -e
63
+ STDERR_TEXT=$(cat "$STDERR")
64
+ rm -f "$STDOUT" "$STDERR"
65
+ }
66
+
67
+ run_hook_mcp() {
68
+ local tool="$1"; local transcript="${2:-}"
69
+ local payload
70
+ if [ -n "$transcript" ]; then
71
+ payload=$(jq -n --arg t "$tool" --arg tp "$transcript" \
72
+ '{tool_name:$t, transcript_path:$tp, tool_input:{}}')
73
+ else
74
+ payload=$(jq -n --arg t "$tool" \
75
+ '{tool_name:$t, tool_input:{}}')
76
+ fi
77
+ STDOUT=$(mktemp); STDERR=$(mktemp)
78
+ set +e
79
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
80
+ EXIT=$?
81
+ set -e
82
+ STDERR_TEXT=$(cat "$STDERR")
83
+ rm -f "$STDOUT" "$STDERR"
84
+ }
85
+
86
+ expect_pass_silent() {
87
+ local name="$1"
88
+ if [ "$EXIT" = "0" ] && [ -z "$STDERR_TEXT" ]; then
89
+ echo " PASS $name"; PASS=$((PASS+1))
90
+ else
91
+ echo " FAIL $name (expected silent, exit=$EXIT, stderr=$([ -n "$STDERR_TEXT" ] && echo non-empty || echo empty))"
92
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
93
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
94
+ fi
95
+ }
96
+
97
+ expect_block() {
98
+ local name="$1"; local needle="$2"
99
+ if [ "$EXIT" = "2" ] && echo "$STDERR_TEXT" | grep -qF "$needle"; then
100
+ echo " PASS $name"; PASS=$((PASS+1))
101
+ else
102
+ echo " FAIL $name (expected BLOCK exit=2 + '$needle', got exit=$EXIT)"
103
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
104
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
105
+ fi
106
+ }
107
+
108
+ echo "=== check_solo_workflow tests ==="
109
+
110
+ TX_NO_TRIGGER="$TMP_DIR/tx_no_trigger.jsonl"
111
+ build_transcript "$TX_NO_TRIGGER" \
112
+ "請幫我看一下" \
113
+ "改個 padding" \
114
+ "audit 一下" \
115
+ "謝謝" \
116
+ "再 review"
117
+
118
+ TX_PUSH_TRIGGER="$TMP_DIR/tx_push_trigger.jsonl"
119
+ build_transcript "$TX_PUSH_TRIGGER" \
120
+ "請改" \
121
+ "OK 看起來不錯" \
122
+ "可以 push 了" \
123
+ "合進去" \
124
+ "謝謝"
125
+
126
+ # 1. Non-Bash / Non-MCP tool → silent
127
+ payload_other=$(jq -n '{tool_name:"Read", tool_input:{file_path:"/a"}}')
128
+ STDOUT=$(mktemp); STDERR=$(mktemp)
129
+ set +e
130
+ printf '%s' "$payload_other" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
131
+ EXIT=$?
132
+ set -e
133
+ STDERR_TEXT=$(cat "$STDERR")
134
+ rm -f "$STDOUT" "$STDERR"
135
+ expect_pass_silent "1. tool=Read → skip"
136
+
137
+ # 2. Non-trigger Bash command → silent
138
+ run_hook_bash "ls -la"
139
+ expect_pass_silent "2. innocuous bash → silent"
140
+
141
+ # 3. R1: First `git checkout -b claude/foo` for session → silent + record
142
+ rm -f "$TRACK_FILE"
143
+ run_hook_bash "git checkout -b claude/foo" "sess-A"
144
+ expect_pass_silent "3. R1 first claude/foo branch → silent (recorded)"
145
+
146
+ # 4. R1: Second different branch in SAME session → BLOCK
147
+ # (TRACK_FILE has sess-A → claude/foo from test 3)
148
+ run_hook_bash "git checkout -b claude/bar" "sess-A"
149
+ expect_block "4. R1 second branch same session → BLOCK" "R1 BLOCKER"
150
+
151
+ # 5. R1: Same branch name reuse in same session → silent (EXISTING == NEW_BRANCH)
152
+ # Hook 邏輯:已存在 + 同 branch 名 → 不 block (跳 if 條件)。
153
+ run_hook_bash "git checkout -b claude/foo" "sess-A"
154
+ expect_pass_silent "5. R1 same branch reuse same session → silent"
155
+
156
+ # 6. R2: gh pr create → BLOCK
157
+ run_hook_bash "gh pr create --title 'x' --body 'y'"
158
+ expect_block "6. R2 gh pr create → BLOCK" "R2 BLOCKER"
159
+
160
+ # 7. R2: read-only gh api pulls/N/comments → silent (allow read collab)
161
+ run_hook_bash "gh api repos/foo/bar/pulls/123/comments"
162
+ expect_pass_silent "7. R2 read-only gh api .../comments → silent"
163
+
164
+ # 8. R2: gh api -X POST pulls → BLOCK (write method)
165
+ run_hook_bash "gh api -X POST repos/foo/bar/pulls -f title=x"
166
+ expect_block "8. R2 gh api -X POST pulls → BLOCK" "R2 BLOCKER"
167
+
168
+ # 9. R3: git push origin main + no trigger transcript → BLOCK
169
+ run_hook_bash "git push origin main" "sess-B" "$TX_NO_TRIGGER"
170
+ expect_block "9. R3 push main no trigger → BLOCK" "R3 BLOCKER"
171
+
172
+ # 10. R3: git push origin main + trigger transcript → silent
173
+ run_hook_bash "git push origin main" "sess-C" "$TX_PUSH_TRIGGER"
174
+ expect_pass_silent "10. R3 push main + push trigger → silent"
175
+
176
+ # 11. MCP create_pull_request → BLOCK
177
+ run_hook_mcp "mcp__github__create_pull_request"
178
+ expect_block "11. MCP create_pull_request → BLOCK" "R2 BLOCKER"
179
+
180
+ # 12. MCP merge_pull_request + no trigger → BLOCK
181
+ run_hook_mcp "mcp__github__merge_pull_request" "$TX_NO_TRIGGER"
182
+ expect_block "12. MCP merge no trigger → BLOCK" "R3 BLOCKER"
183
+
184
+ # 13. CLAUDE_BYPASS_SOLO_WORKFLOW=1 override → silent
185
+ payload_bypass=$(jq -n '{tool_name:"Bash", session_id:"sess-X", tool_input:{command:"gh pr create"}}')
186
+ STDOUT=$(mktemp); STDERR=$(mktemp)
187
+ set +e
188
+ printf '%s' "$payload_bypass" | CLAUDE_BYPASS_SOLO_WORKFLOW=1 bash "$HOOK" >"$STDOUT" 2>"$STDERR"
189
+ EXIT=$?
190
+ set -e
191
+ STDERR_TEXT=$(cat "$STDERR")
192
+ rm -f "$STDOUT" "$STDERR"
193
+ expect_pass_silent "13. CLAUDE_BYPASS_SOLO_WORKFLOW=1 override → silent"
194
+
195
+ echo ""
196
+ echo "=== Summary ==="
197
+ echo "Passed: $PASS / $((PASS + FAIL))"
198
+ if [ "$FAIL" -gt 0 ]; then
199
+ echo "Failed:$FAILED_TESTS"
200
+ exit 1
201
+ fi
@@ -0,0 +1,135 @@
1
+ #!/bin/bash
2
+ # Tests for check_spec_class_drift.sh(Audit Dim 53,2026-05-17 ship)
3
+ #
4
+ # Hook 規則:Edit/Write/MultiEdit 對 packages/design-system/src/components/*/[a-z-]*.spec.md
5
+ # 偵測 spec.md 寫「固定/寫死/硬寫 h-NN」但對應 tsx 已 migrate to var(--chrome-header-height)
6
+ # token → stderr P1 warn(不 block;exit 0)。
7
+ #
8
+ # Allow escape:NEW_CONTENT 含 `@spec-class-drift-allow:` → silent。
9
+ # 非 spec.md / tsx 不存在 → silent。
10
+
11
+ set -u
12
+
13
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ HOOK="$SCRIPT_DIR/../check_spec_class_drift.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
+ TMP_DIR=$(mktemp -d)
26
+ trap 'rm -rf "$TMP_DIR"' EXIT
27
+
28
+ # Build a fake DS component dir with spec.md + tsx pair in TMP_DIR
29
+ # so hook's `TSX_PATH="${FILE_PATH%.spec.md}.tsx"` resolves correctly。
30
+ build_pair() {
31
+ local comp_name="$1"
32
+ local tsx_content="$2"
33
+ mkdir -p "$TMP_DIR/packages/design-system/src/components/$comp_name"
34
+ printf '%s' "$tsx_content" > "$TMP_DIR/packages/design-system/src/components/$comp_name/${comp_name}.tsx"
35
+ echo "$TMP_DIR/packages/design-system/src/components/$comp_name/${comp_name}.spec.md"
36
+ }
37
+
38
+ run_hook() {
39
+ local tool="$1"
40
+ local file_path="$2"
41
+ local content="$3"
42
+ local payload
43
+ if [ "$tool" = "Edit" ]; then
44
+ payload=$(jq -n --arg tn "$tool" --arg fp "$file_path" --arg c "$content" \
45
+ '{tool_name: $tn, tool_input: {file_path: $fp, new_string: $c}}')
46
+ else
47
+ payload=$(jq -n --arg tn "$tool" --arg fp "$file_path" --arg c "$content" \
48
+ '{tool_name: $tn, tool_input: {file_path: $fp, content: $c}}')
49
+ fi
50
+ STDOUT=$(mktemp); STDERR=$(mktemp)
51
+ set +e
52
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
53
+ EXIT=$?
54
+ set -e
55
+ STDERR_TEXT=$(cat "$STDERR")
56
+ rm -f "$STDOUT" "$STDERR"
57
+ }
58
+
59
+ expect_pass_silent() {
60
+ local name="$1"
61
+ if [ "$EXIT" = "0" ] && [ -z "$STDERR_TEXT" ]; then
62
+ echo " PASS $name"; PASS=$((PASS+1))
63
+ else
64
+ echo " FAIL $name (expected silent, exit=$EXIT, stderr=$([ -n "$STDERR_TEXT" ] && echo non-empty || echo empty))"
65
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
66
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
67
+ fi
68
+ }
69
+
70
+ expect_warn() {
71
+ local name="$1"; local needle="$2"
72
+ if [ "$EXIT" = "0" ] && echo "$STDERR_TEXT" | grep -qF "$needle"; then
73
+ echo " PASS $name"; PASS=$((PASS+1))
74
+ else
75
+ echo " FAIL $name (expected warn '$needle', exit=$EXIT)"
76
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
77
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
78
+ fi
79
+ }
80
+
81
+ echo "=== check_spec_class_drift tests ==="
82
+
83
+ # 1. Non-spec file (tsx) → skip silent
84
+ run_hook "Edit" "$TMP_DIR/some.tsx" "any content"
85
+ expect_pass_silent "1. non-spec.md file → skip"
86
+
87
+ # 2. Non-DS path spec.md → skip silent
88
+ run_hook "Edit" "/some/random/path/foo.spec.md" "固定 h-14"
89
+ expect_pass_silent "2. spec.md outside DS components/ → skip"
90
+
91
+ # 3. DS spec.md but no sibling tsx → skip silent
92
+ SPEC_PATH="$TMP_DIR/packages/design-system/src/components/orphan/orphan.spec.md"
93
+ mkdir -p "$(dirname "$SPEC_PATH")"
94
+ run_hook "Edit" "$SPEC_PATH" "固定 h-14 寫死"
95
+ expect_pass_silent "3. spec.md without sibling tsx → skip"
96
+
97
+ # 4. spec 寫「固定 h-14」+ tsx 已消費 chrome-header-height token → P1 warn
98
+ SPEC_PATH=$(build_pair "drifty" "
99
+ export const Drifty = () => (
100
+ <div className=\"h-[var(--chrome-header-height)]\">...</div>
101
+ );
102
+ ")
103
+ run_hook "Edit" "$SPEC_PATH" "header 高度固定 h-14,不可改"
104
+ expect_warn "4. spec '固定 h-14' + tsx token → warn" "SPEC-CODE REVERSE DRIFT"
105
+
106
+ # 5. spec 寫「寫死 h-12」+ tsx 不含 h-12 → P1 warn (phrase mismatch pattern 1)
107
+ SPEC_PATH=$(build_pair "noclass" "
108
+ export const NoClass = () => (
109
+ <div className=\"h-[var(--chrome-header-height)]\">...</div>
110
+ );
111
+ ")
112
+ run_hook "Edit" "$SPEC_PATH" "container 寫死 h-12 處理"
113
+ expect_warn "5. spec '寫死 h-12' + tsx 不含 h-12 → warn" "SPEC-CODE REVERSE DRIFT"
114
+
115
+ # 6. spec 寫「固定 h-14」+ allow marker → silent
116
+ SPEC_PATH=$(build_pair "allowed" "
117
+ export const Allowed = () => (
118
+ <div className=\"h-[var(--chrome-header-height)]\">...</div>
119
+ );
120
+ ")
121
+ run_hook "Edit" "$SPEC_PATH" "// @spec-class-drift-allow: known legacy doc
122
+ header 高度固定 h-14"
123
+ expect_pass_silent "6. spec with @spec-class-drift-allow: marker → silent"
124
+
125
+ # 7. Wrong tool (Read) → skip
126
+ run_hook "Read" "$SPEC_PATH" "固定 h-14"
127
+ expect_pass_silent "7. tool=Read → skip"
128
+
129
+ echo ""
130
+ echo "=== Summary ==="
131
+ echo "Passed: $PASS / $((PASS + FAIL))"
132
+ if [ "$FAIL" -gt 0 ]; then
133
+ echo "Failed:$FAILED_TESTS"
134
+ exit 1
135
+ fi
@@ -0,0 +1,197 @@
1
+ #!/bin/bash
2
+ # Tests for check_story_anatomy.sh
3
+ #
4
+ # Runs 5 scenarios by crafting PreToolUse JSON payloads on stdin and checking
5
+ # the hook's exit code (0 = pass / 2 = block) + stderr output.
6
+ #
7
+ # Usage: bash test_check_story_anatomy.sh
8
+
9
+ set -u
10
+
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ # Cluster A merge(2026-05-10):check_story_anatomy.sh 已 fold 進
13
+ # check_story_invariants.sh dispatcher R1。本 test 改 call dispatcher,
14
+ # dispatcher 會跑 5 rule(R1 anatomy + R2-R5),anatomy 違反時 R1 fire 攔截。
15
+ HOOK="$SCRIPT_DIR/../check_story_invariants.sh"
16
+
17
+ if [ ! -x "$HOOK" ]; then
18
+ echo "FATAL: hook not executable: $HOOK"
19
+ exit 1
20
+ fi
21
+
22
+ PASS=0
23
+ FAIL=0
24
+ FAILED_TESTS=""
25
+
26
+ # ── Helpers ──────────────────────────────────────────────────────────────────
27
+
28
+ # run_hook <file_path> <content> → emits JSON payload and runs hook
29
+ # Captures exit code in $EXIT, stderr in $STDERR, stdout in $STDOUT
30
+ run_hook() {
31
+ local file_path="$1"
32
+ local content="$2"
33
+ local tool="${3:-Write}"
34
+
35
+ local payload
36
+ payload=$(jq -n \
37
+ --arg tool "$tool" \
38
+ --arg fp "$file_path" \
39
+ --arg c "$content" \
40
+ '{tool_name: $tool, tool_input: {file_path: $fp, content: $c}}')
41
+
42
+ STDOUT=$(mktemp)
43
+ STDERR=$(mktemp)
44
+ set +e
45
+ printf '%s' "$payload" | bash "$HOOK" >"$STDOUT" 2>"$STDERR"
46
+ EXIT=$?
47
+ set -e
48
+ STDOUT_TEXT=$(cat "$STDOUT")
49
+ STDERR_TEXT=$(cat "$STDERR")
50
+ rm -f "$STDOUT" "$STDERR"
51
+ }
52
+
53
+ expect_pass() {
54
+ local name="$1"
55
+ if [ "$EXIT" = "0" ]; then
56
+ echo " PASS $name"
57
+ PASS=$((PASS+1))
58
+ else
59
+ echo " FAIL $name (expected exit 0, got $EXIT)"
60
+ echo " --- stderr ---"
61
+ echo "$STDERR_TEXT" | sed 's/^/ /'
62
+ echo " --- end stderr ---"
63
+ FAIL=$((FAIL+1))
64
+ FAILED_TESTS="${FAILED_TESTS}\n - $name"
65
+ fi
66
+ }
67
+
68
+ expect_block() {
69
+ local name="$1"
70
+ local needle="$2"
71
+ if [ "$EXIT" = "2" ]; then
72
+ if echo "$STDERR_TEXT" | grep -qF "$needle"; then
73
+ echo " PASS $name"
74
+ PASS=$((PASS+1))
75
+ else
76
+ echo " FAIL $name (exit 2 OK but stderr missing '$needle')"
77
+ echo " --- stderr ---"
78
+ echo "$STDERR_TEXT" | sed 's/^/ /'
79
+ echo " --- end stderr ---"
80
+ FAIL=$((FAIL+1))
81
+ FAILED_TESTS="${FAILED_TESTS}\n - $name"
82
+ fi
83
+ else
84
+ echo " FAIL $name (expected exit 2, got $EXIT)"
85
+ echo " --- stderr ---"
86
+ echo "$STDERR_TEXT" | sed 's/^/ /'
87
+ echo " --- end stderr ---"
88
+ FAIL=$((FAIL+1))
89
+ FAILED_TESTS="${FAILED_TESTS}\n - $name"
90
+ fi
91
+ }
92
+
93
+ # ── Test 1: Normal story using <MenuItem> → pass ─────────────────────────────
94
+ echo "Test 1: normal <MenuItem> usage → pass"
95
+ read -r -d '' T1_CONTENT <<'EOF' || true
96
+ import { MenuItem, ItemIcon, ItemLabel } from '@/design-system/patterns/element-anatomy/item-anatomy'
97
+ import { Folder } from 'lucide-react'
98
+
99
+ export const Default = {
100
+ render: () => (
101
+ <MenuItem>
102
+ <ItemIcon icon={Folder} />
103
+ <ItemLabel>專案檔案</ItemLabel>
104
+ </MenuItem>
105
+ ),
106
+ }
107
+ EOF
108
+ run_hook "/fake/src/design-system/components/Menu/menu.stories.tsx" "$T1_CONTENT"
109
+ expect_pass "Test 1 normal MenuItem usage passes"
110
+
111
+ # ── Test 2: hand-craft raw row → block ───────────────────────────────────────
112
+ echo ""
113
+ echo "Test 2: raw <div flex items-center><Icon/> → block"
114
+ read -r -d '' T2_CONTENT <<'EOF' || true
115
+ import { Folder } from 'lucide-react'
116
+
117
+ export const Default = {
118
+ render: () => (
119
+ <div className="flex items-center gap-2 px-3 py-2"><Folder className="size-4" />
120
+ <span>專案檔案</span>
121
+ </div>
122
+ ),
123
+ }
124
+ EOF
125
+ run_hook "/fake/src/design-system/components/Menu/menu.stories.tsx" "$T2_CONTENT"
126
+ expect_block "Test 2 raw item-anatomy row is blocked" "A.1"
127
+
128
+ # ── Test 3: dismiss via label Button → block ─────────────────────────────────
129
+ echo ""
130
+ echo "Test 3: <Button>關閉</Button> under onClose context → block"
131
+ read -r -d '' T3_CONTENT <<'EOF' || true
132
+ import { Dialog, DialogHeader } from '@/design-system/components/Dialog/dialog'
133
+ import { Button } from '@/design-system/components/Button/button'
134
+
135
+ export const Default = {
136
+ render: ({ onClose }: { onClose: () => void }) => (
137
+ <Dialog>
138
+ <DialogHeader>
139
+ <h2>確認送出</h2>
140
+ <Button onClick={onClose}>關閉</Button>
141
+ </DialogHeader>
142
+ </Dialog>
143
+ ),
144
+ }
145
+ EOF
146
+ run_hook "/fake/src/design-system/components/Dialog/dialog.stories.tsx" "$T3_CONTENT"
147
+ expect_block "Test 3 dismiss via label Button is blocked" "B dismiss via label Button"
148
+
149
+ # ── Test 4: file-level allowlist → bypass ────────────────────────────────────
150
+ echo ""
151
+ echo "Test 4: file-level // @anatomy-exempt marker → pass even with violation"
152
+ read -r -d '' T4_CONTENT <<'EOF' || true
153
+ // @anatomy-exempt: teaching raw primitive — anatomy docs show internals
154
+ import { Folder } from 'lucide-react'
155
+
156
+ export const Anatomy = {
157
+ render: () => (
158
+ <div className="flex items-center gap-2"><Folder className="size-4" />
159
+ <span>anatomy demo</span>
160
+ </div>
161
+ ),
162
+ }
163
+ EOF
164
+ run_hook "/fake/src/design-system/components/Menu/menu.stories.tsx" "$T4_CONTENT"
165
+ expect_pass "Test 4 file-level exempt bypasses hook"
166
+
167
+ # ── Test 5: per-line allowlist → only that line skipped, next violation blocks ──
168
+ echo ""
169
+ echo "Test 5: // @anatomy-exempt-next skips only the following line"
170
+ # First sub-test: the exempted line is clean, hook should still block on a
171
+ # NEW violation later in the file.
172
+ read -r -d '' T5_CONTENT <<'EOF' || true
173
+ import { Folder } from 'lucide-react'
174
+
175
+ export const Demo = {
176
+ render: () => (
177
+ <>
178
+ {/* @anatomy-exempt-next */}
179
+ <div className="flex items-center gap-2"><Folder className="size-4" /><span>exempt</span></div>
180
+ <div className="flex items-center gap-2"><Folder className="size-4" /><span>NOT exempt</span></div>
181
+ </>
182
+ ),
183
+ }
184
+ EOF
185
+ run_hook "/fake/src/design-system/components/Menu/menu.stories.tsx" "$T5_CONTENT"
186
+ expect_block "Test 5 per-line exempt skips one line but next violation still blocks" "A.1"
187
+
188
+ # ── Summary ──────────────────────────────────────────────────────────────────
189
+ echo ""
190
+ echo "════════════════════════════════════════"
191
+ echo " Results: $PASS PASS, $FAIL FAIL"
192
+ echo "════════════════════════════════════════"
193
+ if [ "$FAIL" -gt 0 ]; then
194
+ printf "Failed tests:%b\n" "$FAILED_TESTS"
195
+ exit 1
196
+ fi
197
+ exit 0