universal-dev-standards 6.8.0 → 6.9.0

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 (194) hide show
  1. package/bin/uds.js +12 -2
  2. package/bundled/ai/standards/acceptance-criteria-traceability.ai.yaml +14 -2
  3. package/bundled/ai/standards/adr-standards.ai.yaml +14 -2
  4. package/bundled/ai/standards/code-review.ai.yaml +13 -3
  5. package/bundled/ai/standards/commit-message.ai.yaml +8 -4
  6. package/bundled/ai/standards/deferred-item-exit.ai.yaml +225 -0
  7. package/bundled/ai/standards/feature-discovery-standards.ai.yaml +14 -2
  8. package/bundled/ai/standards/governance-layer.ai.yaml +128 -2
  9. package/bundled/ai/standards/logging.ai.yaml +2 -2
  10. package/bundled/ai/standards/retrospective-standards.ai.yaml +14 -2
  11. package/bundled/ai/standards/reverse-engineering-standards.ai.yaml +73 -2
  12. package/bundled/ai/standards/security-standards.ai.yaml +2 -2
  13. package/bundled/ai/standards/spec-driven-development.ai.yaml +14 -2
  14. package/bundled/ai/standards/tech-debt-standards.ai.yaml +87 -3
  15. package/bundled/ai/standards/turn-completion-integrity.ai.yaml +131 -0
  16. package/bundled/core/acceptance-criteria-traceability.md +5 -2
  17. package/bundled/core/adr-standards.md +26 -2
  18. package/bundled/core/code-review-checklist.md +5 -2
  19. package/bundled/core/context-aware-loading.md +1 -1
  20. package/bundled/core/deferred-item-exit.md +254 -0
  21. package/bundled/core/feature-discovery-standards.md +5 -1
  22. package/bundled/core/governance-layer.md +114 -2
  23. package/bundled/core/retrospective-standards.md +4 -2
  24. package/bundled/core/reverse-engineering-standards.md +81 -2
  25. package/bundled/core/spec-driven-development.md +8 -2
  26. package/bundled/core/tech-debt-standards.md +67 -8
  27. package/bundled/core/turn-completion-integrity.md +196 -0
  28. package/bundled/hooks/check-dangerous-cmd.mjs +60 -0
  29. package/bundled/hooks/check-logging-standard.mjs +59 -0
  30. package/bundled/hooks/check-turn-completion.mjs +233 -0
  31. package/bundled/hooks/inject-standards.mjs +183 -0
  32. package/bundled/hooks/telemetry-wrapper.mjs +77 -0
  33. package/bundled/hooks/turn-completion/detect.mjs +99 -0
  34. package/bundled/hooks/turn-completion/locales/en.mjs +159 -0
  35. package/bundled/hooks/turn-completion/locales/zh-TW.mjs +166 -0
  36. package/bundled/hooks/validate-commit-msg.mjs +104 -0
  37. package/bundled/locales/zh-CN/CHANGELOG.md +47 -3
  38. package/bundled/locales/zh-CN/CLAUDE.md +1 -1
  39. package/bundled/locales/zh-CN/README.md +2 -2
  40. package/bundled/locales/zh-CN/SECURITY.md +1 -1
  41. package/bundled/locales/zh-CN/core/adr-standards.md +1 -1
  42. package/bundled/locales/zh-CN/core/governance-layer.md +118 -6
  43. package/bundled/locales/zh-CN/core/retrospective-standards.md +1 -1
  44. package/bundled/locales/zh-CN/core/tech-debt-standards.md +71 -4
  45. package/bundled/locales/zh-CN/core/turn-completion-integrity.md +190 -0
  46. package/bundled/locales/zh-CN/docs/CHEATSHEET.md +8 -1
  47. package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +29 -68
  48. package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +25 -15
  49. package/bundled/locales/zh-CN/docs/USAGE-MODES-COMPARISON.md +1 -2
  50. package/bundled/locales/zh-CN/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  51. package/bundled/locales/zh-CN/integrations/google-antigravity/README.md +3 -3
  52. package/bundled/locales/zh-CN/skills/atdd-assistant/SKILL.md +2 -0
  53. package/bundled/locales/zh-CN/skills/bdd-assistant/SKILL.md +2 -0
  54. package/bundled/locales/zh-CN/skills/brainstorm-assistant/SKILL.md +22 -12
  55. package/bundled/locales/zh-CN/skills/brainstorm-assistant/guide.md +12 -9
  56. package/bundled/locales/zh-CN/skills/code-review-assistant/SKILL.md +1 -0
  57. package/bundled/locales/zh-CN/skills/commands/brainstorm.md +17 -13
  58. package/bundled/locales/zh-CN/skills/commands/config.md +0 -1
  59. package/bundled/locales/zh-CN/skills/commands/init.md +1 -2
  60. package/bundled/locales/zh-CN/skills/commit-standards/SKILL.md +2 -0
  61. package/bundled/locales/zh-CN/skills/contract-test-assistant/SKILL.md +1 -0
  62. package/bundled/locales/zh-CN/skills/dev-methodology/SKILL.md +2 -0
  63. package/bundled/locales/zh-CN/skills/observability-assistant/SKILL.md +1 -0
  64. package/bundled/locales/zh-CN/skills/project-structure-guide/SKILL.md +1 -0
  65. package/bundled/locales/zh-CN/skills/release-standards/SKILL.md +3 -0
  66. package/bundled/locales/zh-CN/skills/requirement-assistant/SKILL.md +2 -0
  67. package/bundled/locales/zh-CN/skills/reverse-engineer/SKILL.md +3 -0
  68. package/bundled/locales/zh-CN/skills/runbook-assistant/SKILL.md +1 -0
  69. package/bundled/locales/zh-CN/skills/slo-assistant/SKILL.md +1 -0
  70. package/bundled/locales/zh-CN/skills/tdd-assistant/SKILL.md +2 -0
  71. package/bundled/locales/zh-TW/CHANGELOG.md +47 -3
  72. package/bundled/locales/zh-TW/CLAUDE.md +1 -1
  73. package/bundled/locales/zh-TW/README.md +2 -2
  74. package/bundled/locales/zh-TW/SECURITY.md +1 -1
  75. package/bundled/locales/zh-TW/core/acceptance-criteria-traceability.md +2 -0
  76. package/bundled/locales/zh-TW/core/adr-standards.md +26 -5
  77. package/bundled/locales/zh-TW/core/code-review-checklist.md +2 -0
  78. package/bundled/locales/zh-TW/core/container-image-standards.md +2 -2
  79. package/bundled/locales/zh-TW/core/contract-testing-standards.md +2 -2
  80. package/bundled/locales/zh-TW/core/cross-flow-regression.md +8 -7
  81. package/bundled/locales/zh-TW/core/data-contract.md +2 -2
  82. package/bundled/locales/zh-TW/core/data-migration-testing.md +2 -2
  83. package/bundled/locales/zh-TW/core/data-pipeline.md +2 -2
  84. package/bundled/locales/zh-TW/core/deferred-item-exit.md +251 -0
  85. package/bundled/locales/zh-TW/core/documentation-writing-standards.md +228 -3
  86. package/bundled/locales/zh-TW/core/full-coverage-testing.md +15 -2
  87. package/bundled/locales/zh-TW/core/governance-layer.md +118 -5
  88. package/bundled/locales/zh-TW/core/iac-design-principles.md +2 -2
  89. package/bundled/locales/zh-TW/core/incident-response.md +2 -2
  90. package/bundled/locales/zh-TW/core/model-provenance.md +4 -2
  91. package/bundled/locales/zh-TW/core/pii-classification.md +42 -6
  92. package/bundled/locales/zh-TW/core/prd-standards.md +4 -2
  93. package/bundled/locales/zh-TW/core/product-metrics-standards.md +4 -2
  94. package/bundled/locales/zh-TW/core/release-readiness-gate.md +2 -2
  95. package/bundled/locales/zh-TW/core/resource-cost-boundary.md +2 -2
  96. package/bundled/locales/zh-TW/core/retrospective-standards.md +5 -3
  97. package/bundled/locales/zh-TW/core/reverse-engineering-standards.md +83 -5
  98. package/bundled/locales/zh-TW/core/runbook.md +2 -2
  99. package/bundled/locales/zh-TW/core/schema-evolution.md +2 -2
  100. package/bundled/locales/zh-TW/core/secret-management-standards.md +2 -2
  101. package/bundled/locales/zh-TW/core/slo-sli.md +2 -2
  102. package/bundled/locales/zh-TW/core/spec-driven-development.md +2 -0
  103. package/bundled/locales/zh-TW/core/tech-debt-standards.md +71 -4
  104. package/bundled/locales/zh-TW/core/turn-completion-integrity.md +190 -0
  105. package/bundled/locales/zh-TW/core/user-journey-testing.md +2 -2
  106. package/bundled/locales/zh-TW/core/user-story-mapping.md +2 -2
  107. package/bundled/locales/zh-TW/core/verification-oracle.md +2 -2
  108. package/bundled/locales/zh-TW/docs/CHEATSHEET.md +8 -1
  109. package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +29 -68
  110. package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +25 -15
  111. package/bundled/locales/zh-TW/docs/USAGE-MODES-COMPARISON.md +1 -2
  112. package/bundled/locales/zh-TW/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  113. package/bundled/locales/zh-TW/integrations/google-antigravity/README.md +3 -3
  114. package/bundled/locales/zh-TW/skills/adr-assistant/SKILL.md +1 -1
  115. package/bundled/locales/zh-TW/skills/atdd-assistant/SKILL.md +2 -0
  116. package/bundled/locales/zh-TW/skills/bdd-assistant/SKILL.md +2 -0
  117. package/bundled/locales/zh-TW/skills/brainstorm-assistant/SKILL.md +22 -12
  118. package/bundled/locales/zh-TW/skills/brainstorm-assistant/guide.md +12 -9
  119. package/bundled/locales/zh-TW/skills/code-review-assistant/SKILL.md +1 -0
  120. package/bundled/locales/zh-TW/skills/commands/brainstorm.md +17 -13
  121. package/bundled/locales/zh-TW/skills/commands/config.md +0 -1
  122. package/bundled/locales/zh-TW/skills/commands/init.md +1 -2
  123. package/bundled/locales/zh-TW/skills/commit-standards/SKILL.md +2 -0
  124. package/bundled/locales/zh-TW/skills/contract-test-assistant/SKILL.md +2 -1
  125. package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +2 -0
  126. package/bundled/locales/zh-TW/skills/dev-workflow-guide/SKILL.md +1 -1
  127. package/bundled/locales/zh-TW/skills/knowledge-graph/guide.md +2 -2
  128. package/bundled/locales/zh-TW/skills/migration-assistant/SKILL.md +1 -1
  129. package/bundled/locales/zh-TW/skills/observability-assistant/SKILL.md +1 -0
  130. package/bundled/locales/zh-TW/skills/project-discovery/SKILL.md +1 -0
  131. package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +1 -0
  132. package/bundled/locales/zh-TW/skills/release-standards/SKILL.md +3 -0
  133. package/bundled/locales/zh-TW/skills/requirement-assistant/SKILL.md +2 -0
  134. package/bundled/locales/zh-TW/skills/reverse-engineer/SKILL.md +3 -0
  135. package/bundled/locales/zh-TW/skills/runbook-assistant/SKILL.md +1 -0
  136. package/bundled/locales/zh-TW/skills/slo-assistant/SKILL.md +1 -0
  137. package/bundled/locales/zh-TW/skills/tdd-assistant/SKILL.md +2 -0
  138. package/bundled/skills/atdd-assistant/SKILL.md +2 -0
  139. package/bundled/skills/bdd-assistant/SKILL.md +2 -0
  140. package/bundled/skills/brainstorm-assistant/SKILL.md +31 -13
  141. package/bundled/skills/brainstorm-assistant/guide.md +9 -6
  142. package/bundled/skills/code-review-assistant/SKILL.md +1 -0
  143. package/bundled/skills/commands/brainstorm.md +12 -9
  144. package/bundled/skills/commands/config.md +0 -1
  145. package/bundled/skills/commands/init.md +2 -3
  146. package/bundled/skills/commit-standards/SKILL.md +2 -0
  147. package/bundled/skills/contract-test-assistant/SKILL.md +1 -0
  148. package/bundled/skills/dev-methodology/SKILL.md +4 -0
  149. package/bundled/skills/observability-assistant/SKILL.md +1 -0
  150. package/bundled/skills/project-discovery/SKILL.md +1 -0
  151. package/bundled/skills/project-structure-guide/SKILL.md +1 -0
  152. package/bundled/skills/release-standards/SKILL.md +3 -0
  153. package/bundled/skills/requirement-assistant/SKILL.md +2 -0
  154. package/bundled/skills/reverse-engineer/SKILL.md +3 -0
  155. package/bundled/skills/runbook-assistant/SKILL.md +1 -0
  156. package/bundled/skills/slo-assistant/SKILL.md +1 -0
  157. package/bundled/skills/tdd-assistant/SKILL.md +2 -0
  158. package/bundled/templates/.ai-context.yaml.template +194 -0
  159. package/bundled/templates/CLAUDE.md.template +145 -0
  160. package/bundled/templates/DESIGN.md +237 -0
  161. package/bundled/templates/SKILL-BRIEF-TEMPLATE.md +57 -0
  162. package/bundled/templates/SKILL-CANDIDATES.md +39 -0
  163. package/bundled/templates/gates/check-error-exit.mjs +309 -0
  164. package/bundled/templates/mcp-config.json +10 -0
  165. package/bundled/templates/methodology-template.yaml +209 -0
  166. package/bundled/templates/migration-template.md +408 -0
  167. package/bundled/templates/requirement-checklist.md +410 -0
  168. package/bundled/templates/requirement-document-template.md +591 -0
  169. package/bundled/templates/requirement-template.md +881 -0
  170. package/bundled/templates/reverse-spec-template.md +409 -0
  171. package/bundled/templates/test-case-template.md +74 -0
  172. package/bundled/templates/test-plan-template.md +74 -0
  173. package/package.json +7 -5
  174. package/src/commands/audit.js +82 -0
  175. package/src/commands/check.js +66 -10
  176. package/src/commands/init.js +161 -16
  177. package/src/commands/update.js +286 -14
  178. package/src/compilers/claude-code-compiler.js +4 -1
  179. package/src/config/ai-agent-paths.js +62 -17
  180. package/src/core/constants.js +42 -11
  181. package/src/core/manifest.js +201 -3
  182. package/src/core/paths.js +2 -2
  183. package/src/i18n/messages.js +6 -29
  184. package/src/installers/hooks-installer.js +167 -75
  185. package/src/installers/integration-installer.js +9 -5
  186. package/src/prompts/init.js +14 -14
  187. package/src/utils/detector.js +21 -1
  188. package/src/utils/effect-boundary.js +1093 -0
  189. package/src/utils/hasher.js +166 -1
  190. package/src/utils/hook-stats.js +1 -1
  191. package/src/utils/integration-generator.js +79 -1
  192. package/src/utils/reference-sync.js +4 -1
  193. package/src/utils/yaml-generator.js +51 -9
  194. package/standards-registry.json +31 -8
@@ -0,0 +1,237 @@
1
+ # DESIGN.md — [專案名稱] 前端設計規格
2
+
3
+ > **版本**: 1.0.0
4
+ > **更新日期**: YYYY-MM-DD
5
+ > **標準依據**: UDS `frontend-design-standards` v1.0.0
6
+ >
7
+ > **說明**: 本文件是給 AI Agent 和人類開發者讀的設計規格書。
8
+ > 請填寫所有 9 個段落(`<!-- FILL: ... -->` 標記的地方)並移除所有注釋說明。
9
+ > 建立後將本文件放置在專案根目錄,與 README.md 同層。
10
+
11
+ ---
12
+
13
+ ## 1. Visual Theme & Mood
14
+
15
+ <!-- FILL: 定義整體視覺風格與情感基調。這是 AI Agent 生成 UI 時的最高層次約束。 -->
16
+ <!-- 範例:
17
+ - **Theme**: Minimal, professional, data-dense
18
+ - **Mood**: Calm, focused, trustworthy
19
+ - **Inspiration**: Linear app, Stripe dashboard
20
+ - **Dark Mode**: Primary (dark-first design)
21
+ -->
22
+
23
+ - **Theme**: [填入一行風格描述,例:Clean, modern, approachable]
24
+ - **Mood**: [填入情感品質,例:Friendly, energetic, reliable]
25
+ - **Inspiration**: [填入參考產品或設計風格,例:Notion, GitHub, Vercel]
26
+ - **Dark Mode**: [primary / secondary / unsupported]
27
+
28
+ ---
29
+
30
+ ## 2. Color Palette
31
+
32
+ <!-- FILL: 定義語義色彩 token 系統。5 個核心 token 均為必填。
33
+ 使用 token 名稱而非直接在程式碼中使用 hex 值。
34
+ 命名規則:kebab-case,與標準完全一致。 -->
35
+
36
+ ### Semantic Tokens(必填,5 個)
37
+
38
+ - **background**: `#______` — [填入:頁面底色說明]
39
+ - **surface**: `#______` — [填入:卡片、面板底色說明]
40
+ - **primary-text**: `#______` — [填入:主要文字顏色說明]
41
+ - **muted-text**: `#______` — [填入:次要文字、placeholder 說明]
42
+ - **accent**: `#______` — [填入:強調色、CTA 按鈕說明(全站只能 1 個 accent)]
43
+
44
+ ### Extended Tokens(選填)
45
+
46
+ <!-- 選填,如需要可加入以下 token -->
47
+ <!-- - **error**: `#______` -->
48
+ <!-- - **warning**: `#______` -->
49
+ <!-- - **success**: `#______` -->
50
+ <!-- - **border**: `#______` -->
51
+ <!-- - **overlay**: `rgba(______)` -->
52
+
53
+ ---
54
+
55
+ ## 3. Typography
56
+
57
+ <!-- FILL: 定義字體家族與排版角色。
58
+ 重要約束:最多 2 個字體家族(display 系列 + body 系列,可以是同一個)。
59
+ 4 個角色均為必填。 -->
60
+
61
+ ### Font Families(最多 2 個)
62
+
63
+ - **Display font**: [字體名稱] — 用於 display、headline 角色
64
+ - **Body font**: [字體名稱] — 用於 body、caption 角色(可與 display 相同)
65
+
66
+ ### Typographic Scale(4 個角色,均必填)
67
+
68
+ - **display**: [填入大小,需 ≥ 48px], weight [700], line-height [1.1] — 英雄標題、Splash 文字
69
+ - **headline**: [填入大小,範圍 24–32px], weight [600], line-height [1.3] — 區段標題、卡片標題
70
+ - **body**: 16px, weight 400, line-height 1.6 — 段落、主要內容
71
+ - **caption**: [填入大小,範圍 12–14px], weight 400, line-height 1.4 — 標籤、Metadata、輔助說明
72
+
73
+ ---
74
+
75
+ ## 4. Component Styling
76
+
77
+ <!-- FILL: 定義 UI 元件的視覺規則。
78
+ 邊框圓角、按鈕變體、輸入框、卡片均為必填。 -->
79
+
80
+ ### Border Radius
81
+
82
+ - **sm**: [填入,建議 4px] — 小型元素、徽章
83
+ - **md**: [填入,建議 8px] — 按鈕、輸入框
84
+ - **lg**: [填入,建議 12px] — 卡片、Modal
85
+ - **full**: 9999px — Pill 徽章、圓形頭像
86
+
87
+ ### Buttons
88
+
89
+ - **Primary**: `accent` 背景色,白色文字,`md` 圓角
90
+ - **Secondary**: `surface` 背景色,`primary-text` 文字,`md` 圓角,1px border
91
+ - **Ghost**: 透明背景,`accent` 文字,無邊框
92
+
93
+ <!-- FILL: 如有其他按鈕變體可在此新增 -->
94
+
95
+ ### Input Fields
96
+
97
+ - Background: `surface`
98
+ - Border: 1px solid `border`(若有定義)
99
+ - Focus ring: 2px solid `accent`
100
+ - Border radius: `md`
101
+ - Placeholder color: `muted-text`
102
+
103
+ ### Cards / Panels
104
+
105
+ - Background: `surface`
106
+ - Border: [填入:1px solid border / none / custom]
107
+ - Shadow: [填入:elevation-1 / none]
108
+ - Padding: `space-4` (24px)
109
+ - Border radius: `lg`
110
+
111
+ ---
112
+
113
+ ## 5. Layout & Spacing
114
+
115
+ <!-- FILL: 定義間距比例(必須使用 8px 基底的標準步進值)與網格系統。
116
+ 7 個間距 token 均為必填(注意:沒有 space-7)。 -->
117
+
118
+ ### Spacing Scale(8px 基底,7 個步進值,均必填)
119
+
120
+ - **space-1**: 4px — 圖示內距、緊湊元素
121
+ - **space-2**: 8px — 預設元素內距
122
+ - **space-3**: 16px — 元件內部間距
123
+ - **space-4**: 24px — 區塊間距、網格欄距
124
+ - **space-5**: 32px — 元件之間的間距
125
+ - **space-6**: 48px — 主要區段之間
126
+ - **space-8**: 64px — 頁面層級分隔
127
+
128
+ ### Grid System
129
+
130
+ - **Columns**: [填入,建議 12 欄]
131
+ - **Gutter**: space-4 (24px)
132
+ - **Max content width**: [填入,建議 1280px]
133
+ - **Page padding**: space-4 (24px) on mobile / space-6 (48px) on desktop
134
+
135
+ ---
136
+
137
+ ## 6. Depth & Shadow System
138
+
139
+ <!-- FILL: 定義陰影層次系統,至少需要 3 個 elevation 層級。
140
+ 陰影用於建立視覺層次,不依賴顏色變化。 -->
141
+
142
+ - **elevation-0**: no shadow — 扁平元素、緊貼背景的內容
143
+ - **elevation-1**: `[填入 CSS shadow]` — 卡片靜止態、懸浮元素
144
+ - **elevation-2**: `[填入 CSS shadow]` — 下拉選單、Tooltip
145
+ - **elevation-3**: `[填入 CSS shadow]` — Modal、Dialog、Drawer
146
+
147
+ <!-- 選填:
148
+ - **elevation-4**: `[填入 CSS shadow]` — 全畫面 overlay
149
+ -->
150
+
151
+ <!-- 範例(暗色主題):
152
+ - **elevation-1**: `0 1px 2px rgba(0,0,0,0.4)`
153
+ - **elevation-2**: `0 4px 8px rgba(0,0,0,0.3)`
154
+ - **elevation-3**: `0 8px 24px rgba(0,0,0,0.5)`
155
+ -->
156
+
157
+ ---
158
+
159
+ ## 7. Design Guidelines & Anti-patterns
160
+
161
+ <!-- FILL: UI 硬性約束與禁止模式清單。
162
+ 這是約束式 prompting 的核心——限制自由度以提升 UI 品質一致性。
163
+ 硬性約束至少 4 條,反模式至少 5 條(本模板已提供最低要求,請保留)。 -->
164
+
165
+ ### UI Hard Constraints
166
+
167
+ - 每頁最多 **1 個 H1**
168
+ - 頁面區段不超過 **6 個**
169
+ - 字體家族最多 **2 個**
170
+ - 強調色最多 **1 個**(禁止混用多個 accent 色)
171
+ - [填入:其他專案特定的硬性約束]
172
+
173
+ ### Anti-patterns(禁止模式)
174
+
175
+ - **禁止** floating badge(浮動徽章,脫離內容無歸屬)
176
+ - **禁止** generic card layout(完全相同的卡片堆疊作為主要內容)
177
+ - **禁止** dashboard grid as homepage(行銷首頁設計成數據儀表板)
178
+ - **禁止** competing CTAs(同畫面出現多個等重 CTA 按鈕)
179
+ - **禁止** color-only differentiation(僅用顏色區分狀態,無其他提示)
180
+ - [填入:其他專案特定的禁止模式]
181
+
182
+ ### Design Principles(選填)
183
+
184
+ <!-- 可以新增正向指導原則(非禁止事項)
185
+ 範例:
186
+ - 優先使用文字解決,而非堆砌元件(Restraint over complexity)
187
+ - 每個設計決定必須有功能理由,裝飾性元素需要明確理由
188
+ -->
189
+
190
+ ---
191
+
192
+ ## 8. Responsive Behavior
193
+
194
+ <!-- FILL: 定義斷點規則與響應式原則。
195
+ 必須採用 Mobile-first 方式(min-width media queries)。
196
+ 至少定義 3 個斷點(mobile / tablet / desktop)。 -->
197
+
198
+ ### Breakpoints(Mobile-first)
199
+
200
+ - **xs** (base): < 480px — 小型手機
201
+ - **sm**: ≥ 768px — 平板
202
+ - **md**: ≥ 1024px — 筆記型電腦
203
+ - **lg**: ≥ 1280px — 桌上型電腦
204
+ - **xl**: ≥ 1536px — 寬螢幕(選填)
205
+
206
+ ### Rules
207
+
208
+ - 採用 Mobile-first CSS(min-width 媒體查詢)
209
+ - xs / sm:單欄佈局
210
+ - md+:多欄佈局
211
+ - 行動裝置觸控目標最小 **44×44px**
212
+ - 導覽列在 sm 以下收合為漢堡選單或底部導覽列
213
+ - [填入:其他專案特定的響應式規則]
214
+
215
+ ---
216
+
217
+ ## 9. Agent Prompt References
218
+
219
+ <!-- FILL: AI Agent 快速讀取的設計意圖摘要。
220
+ AI Agent 應優先讀取此段落作為生成 UI 的整體定向。
221
+ Style Summary 限 1–2 句,Key Constraints 使用條列式。 -->
222
+
223
+ ### Style Summary
224
+
225
+ [填入 1–2 句描述整體設計意圖。例:
226
+ 「深色、簡約、以數據為核心的介面。專業美學,優先考慮資訊清晰度而非裝飾性。」]
227
+
228
+ ### Key Constraints for AI Generation
229
+
230
+ - 所有顏色必須使用語義 token 名稱(background, surface, accent),禁止在元件中硬編碼 hex 值
231
+ - 每頁只有 1 個 H1;區段數量 ≤ 6
232
+ - `accent` 是唯一允許的強調色
233
+ - [填入:其他最關鍵的設計約束]
234
+
235
+ ### Tone
236
+
237
+ [填入設計應帶給使用者的感受。例:「沉穩、自信、技術感。類似 Linear 或 Vercel 的 Dashboard 美學。」]
@@ -0,0 +1,57 @@
1
+ # Skill Brief: /{skill-name}
2
+
3
+ > **Purpose | 用途**: Minimal viable spec for Simple Skills — no XSPEC needed
4
+ > Simple Skill 的最小可行規格,不需建立 XSPEC
5
+ >
6
+ > **Time to fill | 填寫時間**: ~10 minutes
7
+ >
8
+ > **When to use | 適用條件**:
9
+ > All 4 judgment questions in `/process-to-skill` answered "No"
10
+ > `/process-to-skill` 的 4 個判斷問題全部回答「否」
11
+
12
+ ---
13
+
14
+ ## Trigger Context | 觸發情境
15
+
16
+ When would you reach for this Skill?
17
+ 什麼情況下會想用這個 Skill?
18
+
19
+ > Example: "When I need to create a DEC record and sync TECH-RADAR"
20
+
21
+ ---
22
+
23
+ ## Problem Statement | 問題陳述
24
+
25
+ Without this Skill, how do you do it now? Why is that a problem?
26
+ 沒有這個 Skill 時,現在怎麼做?為什麼不好?
27
+
28
+ > Example: "Manually recall steps each time; easy to forget updating TECH-RADAR"
29
+
30
+ ---
31
+
32
+ ## Core Steps | 核心步驟
33
+
34
+ (3–7 ordered steps | 3~7 個有序步驟)
35
+
36
+ 1.
37
+ 2.
38
+ 3.
39
+
40
+ ---
41
+
42
+ ## Acceptance Criteria | 驗收條件
43
+
44
+ (2–3 items | 2~3 條)
45
+
46
+ - **AC-1**: After execution, {artifact} exists and is correctly formatted
47
+ 執行後,{具體產物} 存在且格式正確
48
+ - **AC-2**: {Critical step} is not skipped
49
+ {關鍵步驟} 不被跳過
50
+
51
+ ---
52
+
53
+ ## Out of Scope | 不涵蓋的部分
54
+
55
+ (Explicit boundaries to prevent scope creep | 明確邊界,防止 Skill 膨脹)
56
+
57
+ -
@@ -0,0 +1,39 @@
1
+ # Skill Candidates | Skill 候選清單
2
+
3
+ > **The 3-Times Rule | 3 次法則**
4
+ >
5
+ > Same process done manually ≥ 3 times → record here → at 3 → run `/process-to-skill`
6
+ > 同一流程手動執行 ≥ 3 次 → 記錄於此 → 達 3 次 → 執行 `/process-to-skill`
7
+
8
+ ## How to Use | 使用方式
9
+
10
+ 1. When you notice a repeated process, add a row to Candidates below
11
+ 發現重複流程時,在「候選清單」表格新增一行
12
+ 2. Each time you repeat it manually, increment the Count
13
+ 每次重複手動執行時,更新「執行次數」
14
+ 3. When Count reaches 3, mark Trigger ✅ and run `/process-to-skill`
15
+ 次數達 3 時,觸發欄填 ✅,執行 `/process-to-skill`
16
+
17
+ ---
18
+
19
+ ## Candidates | 候選清單
20
+
21
+ | Name | Process Description | Count | Trigger | Skill |
22
+ |------|---------------------|:-----:|:-------:|-------|
23
+ | (example) /example | Step A → Step B → Step C → commit | 2 | - | - |
24
+
25
+ ---
26
+
27
+ ## Completed | 已完成
28
+
29
+ | Skill | Created | Type | Notes |
30
+ |-------|---------|:----:|-------|
31
+ | (example) /borrow | 2026-04-10 | Simple | External source borrowing flow |
32
+
33
+ ---
34
+
35
+ ## Deprecated | 已廢棄
36
+
37
+ | Skill | Deprecated | Reason | Superseded By |
38
+ |-------|-----------|--------|--------------|
39
+ | — | — | — | — |
@@ -0,0 +1,309 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: MIT
3
+ //
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+ // 錯誤訊息單一出口閘門  可攜版(複製到任何專案,只改下面的 CONFIG)
6
+ // ─────────────────────────────────────────────────────────────────────────────
7
+ //
8
+ // 它防的是什麼:
9
+ // 2026-09-03 使用者照著建議打上企業名稱,畫面回他一句 `Bad Request`。
10
+ // 真正的原因寫在回應的 `details` 裡,而呼叫端只讀了 `error`——把它丟掉了。
11
+ // 當天的修法改了**一個**呼叫端;隔天走訪整個前端,同型的有 24 處,
12
+ // 其中三處就在當時打開的那個檔案裡,一處只在往下十行。
13
+ // **「修好了」與「修好了其中一個」在畫面上無從分辨**,因為壞的在別的頁面。
14
+ //
15
+ // 它怎麼防:
16
+ // 規則收進一個檔案(單一出口),其餘每一處都必須經過它。
17
+ // 這支腳本走訪整個專案,找「有人自己把錯誤物件的欄位拼成字串」。
18
+ //
19
+ // 為什麼是獨立腳本而不是一支測試:
20
+ // 測試框架每個專案不一樣(vitest/jest/node:test),而這道規則跟框架無關。
21
+ // 寫成 .mjs 就不必在意目標專案用哪一套,也不必在意測試檔要放哪個目錄。
22
+ //
23
+ // 用法:
24
+ // node scripts/check-error-exit.mjs 走訪並檢查
25
+ // node scripts/check-error-exit.mjs --self-test 只驗判別式自己
26
+ // node scripts/check-error-exit.mjs --json 機器可讀輸出
27
+ //
28
+ // 退出碼:0 通過|1 有違規(或宣告與事實不符)|2 量不到(沒設定、走訪不到東西)
29
+ // 🔴 2 也是不通過。在一道會擋的閘門裡,如果「解析不了」放行,
30
+ // 那弄壞設定就成了繞過的方法。
31
+
32
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
33
+ import { join, relative, sep } from "node:path";
34
+ import { dirname } from "node:path";
35
+ import { fileURLToPath } from "node:url";
36
+
37
+ const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
38
+
39
+ // ═══════════════════════════════════════════════════════════════════════════
40
+ // CONFIG —— 複製到新專案後,要動的只有這一塊
41
+ // ═══════════════════════════════════════════════════════════════════════════
42
+ const CONFIG = {
43
+ /**
44
+ * 🔴 沒填就是沒設定,而沒設定會 exit 2,**不會安靜地通過**。
45
+ * 一支在新專案裡靜靜回綠的閘門,跟一支根本沒裝的閘門無從分辨。
46
+ */
47
+ configured: false,
48
+
49
+ /** 走訪哪些目錄(相對 repo 根)。 */
50
+ scanDirs: ["src"],
51
+
52
+ /** 規則住在哪個檔案。它是唯一被允許讀那些欄位的地方。 */
53
+ singleExit: null,
54
+
55
+ /** 走訪時跳過的目錄名。 */
56
+ skipDirs: ["node_modules", "dist", "build", ".vite", "__tests__", "coverage"],
57
+
58
+ /** 副檔名。 */
59
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
60
+
61
+ /** 走訪至少要看到幾個檔——低於這個數代表走訪器壞了,而那與「全部通過」輸出相同。 */
62
+ minFilesScanned: 10,
63
+
64
+ /**
65
+ * 這個專案根本不把錯誤回應轉成文字時填這裡(例如純資料處理的函式庫)。
66
+ * 🔴 **這個宣告本身會被驗證**:填了之後腳本會去找專案有沒有在讀 HTTP 回應,
67
+ * 找得到就代表宣告是假的,exit 1。不驗證的宣告只是一個有禮貌的關閉開關。
68
+ * 形狀:{ reason: "……", declaredOn: "YYYY-MM-DD" }
69
+ */
70
+ notApplicable: null,
71
+ };
72
+ // ═══════════════════════════════════════════════════════════════════════════
73
+
74
+ /**
75
+ * 判別式:抓「把錯誤物件的欄位當成給人看的字串」。
76
+ *
77
+ * ⚠️ 刻意**不**抓 `e instanceof Error ? e.message : "…"` 與 `e?.message ?? "…"`——
78
+ * 那些讀的是 JS 的 Error 物件,不是回應的 body。抓進來這道閘門就沒有人滿足得了,
79
+ * 而滿足不了的閘門的下場是被關掉。
80
+ *
81
+ * ⚠️ 也刻意**不**抓後備值是 null/undefined 的——那是成功路徑在讀選填欄位。
82
+ * 每加一個排除項就要說出它把問題改成了什麼:這裡把問題從「有沒有讀 message」
83
+ * 改成「**有沒有把 message 當成給人看的錯誤字串**」。
84
+ *
85
+ * ⚠️ 排除項必須寫成 `\?\?(?!\s*(?:null|undefined)\b)`,不能寫成 `\?\?\s*(?!null\b)`:
86
+ * 後者的 `\s*` 會回溯成零寬,讓否定環顧在空白處成立而整個排除失效。
87
+ * **這個 bug 是下面的反臂抓到的,不是看出來的。**
88
+ */
89
+ export function findsHandRolledErrorText(src) {
90
+ const re = /\b[A-Za-z_$][\w$]*\.(?:error|message)\s*\?\?(?!\s*(?:null|undefined)\b)/g;
91
+ return (src.match(re) ?? []).length;
92
+ }
93
+
94
+ /** 「這個專案有沒有在讀 HTTP 回應」——用來驗證 notApplicable 的宣告是不是真的。 */
95
+ export function readsHttpResponses(src) {
96
+ return /\bfetch\s*\(|\bres(?:ponse)?\.json\s*\(|\baxios\b|\bgot\s*\(/.test(src);
97
+ }
98
+
99
+ function walk(dirs) {
100
+ const out = [];
101
+ const skip = new Set(CONFIG.skipDirs);
102
+ const isTest = (n) => /\.(test|spec)\.[jt]sx?$/.test(n);
103
+ const visit = (dir) => {
104
+ let entries;
105
+ try {
106
+ entries = readdirSync(dir);
107
+ } catch {
108
+ return; // 目錄不存在——由 minFilesScanned 那道分母臂負責報告
109
+ }
110
+ for (const name of entries) {
111
+ const full = join(dir, name);
112
+ let st;
113
+ try {
114
+ st = statSync(full);
115
+ } catch {
116
+ continue;
117
+ }
118
+ if (st.isDirectory()) {
119
+ if (!skip.has(name)) visit(full);
120
+ continue;
121
+ }
122
+ if (!CONFIG.extensions.some((e) => name.endsWith(e))) continue;
123
+ if (isTest(name)) continue;
124
+ out.push(full);
125
+ }
126
+ };
127
+ for (const d of dirs) visit(join(REPO_ROOT, d));
128
+ return out;
129
+ }
130
+
131
+ // ── 自我測試:一個從未被觀察到會紅的閘門,與一個永遠回綠的閘門無從分辨 ──────
132
+ function selfTest() {
133
+ const arms = [
134
+ [
135
+ "正臂:抓得到真實的四種寫法",
136
+ () => {
137
+ const a = findsHandRolledErrorText("throw new Error(body.error ?? `HTTP ${res.status}`)") === 1;
138
+ const b = findsHandRolledErrorText('setError(data.error ?? "無法開始登入。")') === 1;
139
+ const c = findsHandRolledErrorText("throw new Error(err.message ?? err.error ?? `HTTP ${s}`)") === 2;
140
+ const d = findsHandRolledErrorText("throw new Error(retryErr.error ?? `HTTP ${s}`)") === 1;
141
+ return a && b && c && d;
142
+ },
143
+ ],
144
+ [
145
+ "🔴 負臂:JS Error 物件的讀法不得被抓(抓了這閘門就沒人滿足得了)",
146
+ () =>
147
+ findsHandRolledErrorText('setError(e instanceof Error ? e.message : "載入失敗")') === 0 &&
148
+ findsHandRolledErrorText('setError(e?.message ?? "Failed to load")') === 0 &&
149
+ findsHandRolledErrorText("throw new Error(await readApiError(res))") === 0,
150
+ ],
151
+ [
152
+ "🔴 負臂:成功路徑讀選填欄位不算(首跑抓到的假陽性)",
153
+ () =>
154
+ findsHandRolledErrorText("setModelListMessage(body.message ?? null)") === 0 &&
155
+ findsHandRolledErrorText("const m = body.message ?? undefined;") === 0 &&
156
+ findsHandRolledErrorText('const m = body.message ?? "失敗";') === 1,
157
+ ],
158
+ [
159
+ "宣告驗證臂:偵測得到專案有在讀 HTTP 回應",
160
+ () =>
161
+ readsHttpResponses('const r = await fetch("/api/x");') === true &&
162
+ readsHttpResponses("const b = await res.json();") === true,
163
+ ],
164
+ [
165
+ "🔴 宣告驗證的負臂:純計算的檔案不得被判為有讀回應",
166
+ () => readsHttpResponses("export const add = (a, b) => a + b;") === false,
167
+ ],
168
+ [
169
+ // ⚠️ 尚未設定、或宣告不適用時,這一臂沒有東西可量。它會**明說自己被跳過**,
170
+ // 不會靜靜回綠——「跳過」與「通過」在輸出上要分得出來。
171
+ CONFIG.configured && !CONFIG.notApplicable
172
+ ? "分母臂:走訪拿得到檔案(0 與『全部通過』的輸出相同)"
173
+ : "分母臂:跳過(尚未設定或已宣告不適用,沒有東西可走訪)",
174
+ () =>
175
+ !CONFIG.configured || CONFIG.notApplicable !== null || walk(CONFIG.scanDirs).length >= CONFIG.minFilesScanned,
176
+ ],
177
+ ];
178
+ let failed = 0;
179
+ console.log("[error-exit --self-test]");
180
+ for (const [name, fn] of arms) {
181
+ let ok = false;
182
+ // ⚠️ 用另一個變數,不要改 name——它是 for-of 解構出來的 const。
183
+ // 第一版直接 `name += …`,而那條路徑**只有在某個臂擲出例外時才會走到**,
184
+ // 也就是自我測試自己的錯誤處理是壞的,而平常永遠看不出來。lint 抓到的。
185
+ let note = "";
186
+ try {
187
+ ok = fn() === true;
188
+ } catch (e) {
189
+ ok = false;
190
+ note = ` (擲出例外:${e.message})`;
191
+ }
192
+ console.log(` ${ok ? "✓" : "✗"} ${name}${note}`);
193
+ if (!ok) failed++;
194
+ }
195
+ console.log(`[error-exit --self-test] 通過 ${arms.length - failed}/失敗 ${failed}`);
196
+ return failed === 0 ? 0 : 2;
197
+ }
198
+
199
+ // ── 主流程 ────────────────────────────────────────────────────────────────
200
+ function main() {
201
+ const argv = process.argv.slice(2);
202
+ if (argv.includes("--self-test")) return selfTest();
203
+ const asJson = argv.includes("--json");
204
+ const say = (s) => {
205
+ if (!asJson) console.log(s);
206
+ };
207
+ const emit = (verdict, extra = {}) => {
208
+ if (asJson) console.log(JSON.stringify({ verdict, ...extra }, null, 2));
209
+ return verdict === "pass" ? 0 : verdict === "violations" ? 1 : 2;
210
+ };
211
+
212
+ // 狀態一:沒設定。**不是通過。**
213
+ if (!CONFIG.configured) {
214
+ say("[error-exit] ✗ 這個專案還沒指定它的錯誤訊息單一出口。");
215
+ say(" 打開 scripts/check-error-exit.mjs 的 CONFIG 區塊,填 scanDirs 與 singleExit,");
216
+ say(" 然後把 configured 改成 true。真的用不到就填 notApplicable(要寫理由)。");
217
+ say(" 🔴 這裡刻意不放行:一支在新專案裡靜靜回綠的閘門,跟沒裝無從分辨。");
218
+ return emit("unmeasurable", { why: "not-configured" });
219
+ }
220
+
221
+ // 狀態二:宣告不適用——而宣告本身要被驗證。
222
+ if (CONFIG.notApplicable) {
223
+ const { reason, declaredOn } = CONFIG.notApplicable;
224
+ if (!reason || !declaredOn) {
225
+ say("[error-exit] ✗ notApplicable 要同時有 reason 與 declaredOn。沒有理由的豁免只是關閉開關。");
226
+ return emit("unmeasurable", { why: "declaration-incomplete" });
227
+ }
228
+ const files = walk(CONFIG.scanDirs);
229
+ const talkers = files.filter((f) => readsHttpResponses(readFileSync(f, "utf8")));
230
+ say(`[error-exit] 宣告不適用(${declaredOn}):${reason}`);
231
+ say(` 走訪 ${files.length} 個檔驗證這個宣告——不驗證的宣告只是有禮貌的關閉開關。`);
232
+ if (talkers.length > 0) {
233
+ say(`[error-exit] ✗ 宣告與程式碼不符:${talkers.length} 個檔在讀 HTTP 回應。`);
234
+ for (const t of talkers.slice(0, 5)) say(` · ${relative(REPO_ROOT, t)}`);
235
+ return emit("violations", { why: "false-declaration", files: talkers.map((t) => relative(REPO_ROOT, t)) });
236
+ }
237
+ say("[error-exit] ✓ 宣告成立:走訪範圍內沒有任何檔案在讀 HTTP 回應。");
238
+ return emit("pass", { state: "not-applicable" });
239
+ }
240
+
241
+ // 狀態三:正常走訪。
242
+ //
243
+ // 🔴 singleExit 允許是 null,而這**不是**一個放水的開關。
244
+ // 2026-09-04 把這道閘門裝進另外三個 repo 時才發現:它們今天都是 0 處。
245
+ // 要求它們先生一個「單一出口」檔案出來,等於逼一個**沒有任何呼叫端的模組**誕生,
246
+ // 而那正是我們在別的地方花整整一份規格在抓的東西(可達、但沒有人用)。
247
+ // 正確的語意是:**這道閘門要防的是第二處,不是第一處。**
248
+ // · 有指定出口 → 除了它,其餘一律 0。
249
+ // · 沒指定出口 → 最多容許 1 個檔(那個檔按定義就是出口);出現第 2 個就紅,
250
+ // 並且當場告訴你「現在有兩個了,挑一個當出口、其餘接過去」。
251
+ const hasDesignatedExit = typeof CONFIG.singleExit === "string" && CONFIG.singleExit.length > 0;
252
+ if (hasDesignatedExit && !existsSync(join(REPO_ROOT, CONFIG.singleExit))) {
253
+ say(`[error-exit] ✗ 指定的單一出口不存在:${CONFIG.singleExit}`);
254
+ say(" 檔案被搬走或改名時,這道閘門會變成在檢查一個不存在的規則。");
255
+ return emit("unmeasurable", { why: "single-exit-missing" });
256
+ }
257
+
258
+ const files = walk(CONFIG.scanDirs);
259
+ say(`[error-exit] 走訪 ${CONFIG.scanDirs.join("、")} 共 ${files.length} 個非測試檔`);
260
+ if (files.length < CONFIG.minFilesScanned) {
261
+ say(`[error-exit] ✗ 只走訪到 ${files.length} 個檔(下限 ${CONFIG.minFilesScanned})。`);
262
+ say(" 🔴 走訪不到東西與『全部通過』的輸出一模一樣,所以這裡當成量不到,不當成通過。");
263
+ return emit("unmeasurable", { why: "denominator-too-small", scanned: files.length });
264
+ }
265
+
266
+ const exitRel = hasDesignatedExit ? CONFIG.singleExit.split("/").join(sep) : null;
267
+ const carriers = []; // 含有那個形狀的檔(不含指定出口)
268
+ for (const f of files) {
269
+ const rel = relative(REPO_ROOT, f);
270
+ if (exitRel !== null && rel === exitRel) continue; // 規則本身住的地方
271
+ const hits = findsHandRolledErrorText(readFileSync(f, "utf8"));
272
+ if (hits > 0) carriers.push({ file: rel, hits });
273
+ }
274
+
275
+ // ── 有指定出口:其餘一律 0 ──────────────────────────────────────────────
276
+ if (hasDesignatedExit) {
277
+ if (carriers.length > 0) {
278
+ say(`[error-exit] ✗ ${carriers.length} 個檔自己把錯誤回應拼成字串:`);
279
+ for (const o of carriers) say(` · ${o.file}(${o.hits} 處)`);
280
+ say(` 改成經過 ${CONFIG.singleExit}——理由見那個檔的檔頭。`);
281
+ return emit("violations", { offenders: carriers });
282
+ }
283
+ say(`[error-exit] ✓ ${files.length} 個檔裡,只有 ${CONFIG.singleExit} 在讀那些欄位。`);
284
+ say(" 本閘門**沒有**證明的事:那個出口自己寫對了沒有。");
285
+ say(" 出口的優先順序若反了,所有呼叫端會一致地錯而這裡全綠——那是它自己單元測試的工作。");
286
+ return emit("pass", { scanned: files.length, exit: CONFIG.singleExit });
287
+ }
288
+
289
+ // ── 尚未指定出口:容許 1 個,第 2 個就是重複的開始 ──────────────────────
290
+ if (carriers.length > 1) {
291
+ say(`[error-exit] ✗ ${carriers.length} 個檔各自把錯誤回應拼成字串,而還沒有指定的單一出口:`);
292
+ for (const o of carriers) say(` · ${o.file}(${o.hits} 處)`);
293
+ say(" 挑其中一個當出口(或新開一個),其餘接過去,然後把 CONFIG.singleExit 填上。");
294
+ say(" 🔴 本閘門防的是**第二處**:第一處是實作,第二處開始是各寫各的。");
295
+ return emit("violations", { offenders: carriers, why: "duplication-without-exit" });
296
+ }
297
+ if (carriers.length === 1) {
298
+ say(`[error-exit] ✓ 只有一個檔在做這件事:${carriers[0].file}`);
299
+ say(" 它按定義就是這個 repo 的單一出口。出現第二個時本閘門會紅。");
300
+ say(" 把 CONFIG.singleExit 填成它,可以讓這件事變成明講的而不是碰巧的。");
301
+ return emit("pass", { scanned: files.length, deFactoExit: carriers[0].file });
302
+ }
303
+ say(`[error-exit] ✓ 走訪 ${files.length} 個檔,還沒有任何地方在把錯誤回應拼成字串。`);
304
+ say(" 這個類別目前是空的——第一個成員出現時不會紅(那是實作),");
305
+ say(" 第二個出現時會紅(那是重複)。**不是空轉:它在等第二處。**");
306
+ return emit("pass", { scanned: files.length, state: "class-empty" });
307
+ }
308
+
309
+ process.exit(main());
@@ -0,0 +1,10 @@
1
+ {
2
+ "_comment": "Add this to your Claude Code settings.json or Cursor mcp.json",
3
+ "mcpServers": {
4
+ "uds-design-standards": {
5
+ "command": "uds",
6
+ "args": ["mcp", "serve"],
7
+ "description": "UDS Frontend Design Standards Server"
8
+ }
9
+ }
10
+ }