@godxjp/ui 19.6.0 → 20.1.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 (326) hide show
  1. package/README.md +8 -2
  2. package/dist/app/theme-axes.d.ts +2 -0
  3. package/dist/app/theme-axes.js +45 -0
  4. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  5. package/dist/components/charts/chart-cartesian.js +52 -3
  6. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  7. package/dist/components/charts/chart-category-axis.js +93 -0
  8. package/dist/components/charts/chart-frame.d.ts +10 -1
  9. package/dist/components/charts/chart-frame.js +19 -3
  10. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  11. package/dist/components/charts/compact-bar-trend.js +2 -0
  12. package/dist/components/charts/pie-chart.d.ts +1 -1
  13. package/dist/components/charts/pie-chart.js +12 -1
  14. package/dist/components/charts/recharts-peer.d.ts +49 -0
  15. package/dist/components/charts/recharts-peer.js +45 -0
  16. package/dist/components/data-display/card.d.ts +14 -3
  17. package/dist/components/data-display/card.js +22 -4
  18. package/dist/components/data-display/code-block.js +6 -2
  19. package/dist/components/data-display/collapsible.d.ts +23 -4
  20. package/dist/components/data-display/collapsible.js +119 -4
  21. package/dist/components/data-display/data-table.d.ts +39 -4
  22. package/dist/components/data-display/data-table.js +802 -270
  23. package/dist/components/data-display/descriptions.d.ts +27 -6
  24. package/dist/components/data-display/descriptions.js +58 -17
  25. package/dist/components/data-display/index.d.ts +5 -1
  26. package/dist/components/data-display/index.js +4 -0
  27. package/dist/components/data-display/legend.d.ts +15 -0
  28. package/dist/components/data-display/legend.js +11 -0
  29. package/dist/components/data-display/list-row.d.ts +10 -1
  30. package/dist/components/data-display/list-row.js +8 -2
  31. package/dist/components/data-display/popover.d.ts +60 -7
  32. package/dist/components/data-display/popover.js +268 -39
  33. package/dist/components/data-display/progress.d.ts +50 -2
  34. package/dist/components/data-display/progress.js +57 -9
  35. package/dist/components/data-display/range-timeline.d.ts +38 -0
  36. package/dist/components/data-display/range-timeline.js +161 -0
  37. package/dist/components/data-display/scroll-area.js +13 -2
  38. package/dist/components/data-display/service-launcher-card.js +10 -10
  39. package/dist/components/data-display/table.d.ts +11 -3
  40. package/dist/components/data-display/table.js +48 -18
  41. package/dist/components/data-display/tree-list.js +4 -9
  42. package/dist/components/data-entry/calendar.d.ts +2 -2
  43. package/dist/components/data-entry/calendar.js +79 -33
  44. package/dist/components/data-entry/cascader.d.ts +1 -1
  45. package/dist/components/data-entry/cascader.js +188 -24
  46. package/dist/components/data-entry/checkbox.d.ts +19 -6
  47. package/dist/components/data-entry/checkbox.js +55 -16
  48. package/dist/components/data-entry/choice-option.d.ts +1 -1
  49. package/dist/components/data-entry/color-picker.d.ts +1 -1
  50. package/dist/components/data-entry/color-picker.js +17 -5
  51. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  52. package/dist/components/data-entry/control-appearance.js +39 -0
  53. package/dist/components/data-entry/control-surface.d.ts +61 -0
  54. package/dist/components/data-entry/control-surface.js +39 -0
  55. package/dist/components/data-entry/date-picker.d.ts +1 -1
  56. package/dist/components/data-entry/date-picker.js +344 -113
  57. package/dist/components/data-entry/date-range-picker.d.ts +2 -2
  58. package/dist/components/data-entry/date-range-picker.js +278 -140
  59. package/dist/components/data-entry/field.js +0 -1
  60. package/dist/components/data-entry/form-field.d.ts +1 -1
  61. package/dist/components/data-entry/form-field.js +39 -4
  62. package/dist/components/data-entry/form.d.ts +4 -0
  63. package/dist/components/data-entry/form.js +5 -3
  64. package/dist/components/data-entry/index.d.ts +7 -3
  65. package/dist/components/data-entry/index.js +10 -1
  66. package/dist/components/data-entry/input-otp.d.ts +1 -1
  67. package/dist/components/data-entry/input.d.ts +12 -34
  68. package/dist/components/data-entry/input.js +92 -24
  69. package/dist/components/data-entry/label.d.ts +3 -2
  70. package/dist/components/data-entry/label.js +23 -10
  71. package/dist/components/data-entry/month-picker.d.ts +2 -2
  72. package/dist/components/data-entry/month-picker.js +47 -10
  73. package/dist/components/data-entry/month-range-picker.d.ts +2 -2
  74. package/dist/components/data-entry/month-range-picker.js +51 -11
  75. package/dist/components/data-entry/number-input.d.ts +7 -0
  76. package/dist/components/data-entry/number-input.js +147 -98
  77. package/dist/components/data-entry/password-input.d.ts +1 -1
  78. package/dist/components/data-entry/radio.d.ts +1 -1
  79. package/dist/components/data-entry/radio.js +61 -13
  80. package/dist/components/data-entry/search-input.d.ts +1 -1
  81. package/dist/components/data-entry/search-input.js +16 -2
  82. package/dist/components/data-entry/search-select.d.ts +2 -2
  83. package/dist/components/data-entry/search-select.js +209 -78
  84. package/dist/components/data-entry/select.d.ts +22 -4
  85. package/dist/components/data-entry/select.js +215 -163
  86. package/dist/components/data-entry/slider.d.ts +9 -1
  87. package/dist/components/data-entry/slider.js +87 -9
  88. package/dist/components/data-entry/switch.d.ts +3 -0
  89. package/dist/components/data-entry/switch.js +29 -3
  90. package/dist/components/data-entry/textarea.d.ts +14 -56
  91. package/dist/components/data-entry/textarea.js +80 -33
  92. package/dist/components/data-entry/time-picker.d.ts +2 -2
  93. package/dist/components/data-entry/time-picker.js +333 -109
  94. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  95. package/dist/components/data-entry/time-range-picker.js +89 -0
  96. package/dist/components/data-entry/transfer.d.ts +1 -1
  97. package/dist/components/data-entry/transfer.js +99 -31
  98. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  99. package/dist/components/data-entry/tree-select.d.ts +1 -1
  100. package/dist/components/data-entry/tree-select.js +197 -92
  101. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  102. package/dist/components/data-entry/tree-utils.js +7 -14
  103. package/dist/components/data-entry/upload-files.d.ts +2 -0
  104. package/dist/components/data-entry/upload-files.js +31 -0
  105. package/dist/components/data-entry/upload-request.d.ts +4 -0
  106. package/dist/components/data-entry/upload-request.js +53 -0
  107. package/dist/components/data-entry/upload-types.d.ts +28 -0
  108. package/dist/components/data-entry/upload-types.js +2 -0
  109. package/dist/components/data-entry/upload.d.ts +2 -2
  110. package/dist/components/data-entry/upload.js +482 -117
  111. package/dist/components/feedback/dialog.d.ts +105 -38
  112. package/dist/components/feedback/dialog.js +268 -193
  113. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  114. package/dist/components/feedback/overlay-close-focus.js +31 -0
  115. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  116. package/dist/components/feedback/sheet.d.ts +53 -11
  117. package/dist/components/feedback/sheet.js +150 -81
  118. package/dist/components/feedback/tooltip.d.ts +51 -7
  119. package/dist/components/feedback/tooltip.js +107 -25
  120. package/dist/components/general/button.d.ts +1 -1
  121. package/dist/components/general/button.js +7 -3
  122. package/dist/components/general/index.d.ts +1 -0
  123. package/dist/components/general/index.js +2 -0
  124. package/dist/components/general/logo.d.ts +17 -0
  125. package/dist/components/general/logo.js +22 -16
  126. package/dist/components/general/typography.d.ts +3 -0
  127. package/dist/components/general/typography.js +15 -1
  128. package/dist/components/general/visually-hidden.d.ts +3 -0
  129. package/dist/components/general/visually-hidden.js +9 -0
  130. package/dist/components/layout/app-launcher.d.ts +34 -0
  131. package/dist/components/layout/app-launcher.js +228 -0
  132. package/dist/components/layout/app-shell.d.ts +3 -1
  133. package/dist/components/layout/app-shell.js +69 -12
  134. package/dist/components/layout/aspect-ratio.js +0 -1
  135. package/dist/components/layout/auth-divider.js +0 -1
  136. package/dist/components/layout/breadcrumb.d.ts +14 -2
  137. package/dist/components/layout/breadcrumb.js +46 -4
  138. package/dist/components/layout/flex.d.ts +1 -1
  139. package/dist/components/layout/flex.js +41 -3
  140. package/dist/components/layout/index.d.ts +3 -0
  141. package/dist/components/layout/index.js +5 -1
  142. package/dist/components/layout/nav-surface.d.ts +26 -0
  143. package/dist/components/layout/nav-surface.js +17 -0
  144. package/dist/components/layout/org-switcher.d.ts +5 -1
  145. package/dist/components/layout/org-switcher.js +25 -4
  146. package/dist/components/layout/page-container.d.ts +1 -1
  147. package/dist/components/layout/page-container.js +5 -3
  148. package/dist/components/layout/responsive-grid.d.ts +16 -2
  149. package/dist/components/layout/responsive-grid.js +29 -2
  150. package/dist/components/layout/separator.js +0 -1
  151. package/dist/components/layout/sidebar.js +4 -1
  152. package/dist/components/layout/split-pane.d.ts +14 -1
  153. package/dist/components/layout/split-pane.js +26 -13
  154. package/dist/components/layout/topbar-item.d.ts +3 -0
  155. package/dist/components/layout/topbar-item.js +19 -5
  156. package/dist/components/layout/topbar.d.ts +1 -1
  157. package/dist/components/layout/topbar.js +27 -6
  158. package/dist/components/navigation/app-setting-picker.js +21 -2
  159. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  160. package/dist/components/navigation/app-setting-toggle.js +96 -0
  161. package/dist/components/navigation/dropdown-menu.d.ts +227 -18
  162. package/dist/components/navigation/dropdown-menu.js +402 -118
  163. package/dist/components/navigation/index.d.ts +2 -0
  164. package/dist/components/navigation/index.js +2 -0
  165. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  166. package/dist/components/navigation/pagination.d.ts +2 -2
  167. package/dist/components/navigation/pagination.js +155 -83
  168. package/dist/components/navigation/steps.d.ts +2 -2
  169. package/dist/components/navigation/steps.js +29 -4
  170. package/dist/components/navigation/tabs.d.ts +29 -16
  171. package/dist/components/navigation/tabs.js +374 -144
  172. package/dist/components/ui/accordion.d.ts +50 -5
  173. package/dist/components/ui/accordion.js +239 -33
  174. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  175. package/dist/components/ui/aspect-ratio.js +15 -13
  176. package/dist/components/ui/avatar.d.ts +29 -4
  177. package/dist/components/ui/avatar.js +111 -25
  178. package/dist/components/ui/hover-card.d.ts +42 -4
  179. package/dist/components/ui/hover-card.js +183 -27
  180. package/dist/components/ui/input-otp.d.ts +26 -28
  181. package/dist/components/ui/input-otp.js +50 -7
  182. package/dist/components/ui/label.js +0 -1
  183. package/dist/components/ui/password-input.d.ts +36 -2
  184. package/dist/components/ui/password-input.js +27 -7
  185. package/dist/components/ui/rating.d.ts +25 -0
  186. package/dist/components/ui/rating.js +67 -27
  187. package/dist/components/ui/segmented.d.ts +12 -3
  188. package/dist/components/ui/segmented.js +17 -2
  189. package/dist/components/ui/separator.d.ts +12 -2
  190. package/dist/components/ui/separator.js +30 -9
  191. package/dist/components/ui/tag-input.d.ts +45 -0
  192. package/dist/components/ui/tag-input.js +109 -27
  193. package/dist/components/ui/toggle-group.d.ts +50 -5
  194. package/dist/components/ui/toggle-group.js +79 -20
  195. package/dist/components/ui/toggle.d.ts +31 -5
  196. package/dist/components/ui/toggle.js +42 -3
  197. package/dist/form/form-context.d.ts +29 -0
  198. package/dist/form/form-context.js +44 -4
  199. package/dist/form/form-field-array.d.ts +22 -0
  200. package/dist/form/form-field-array.js +50 -0
  201. package/dist/form/form-field-control.d.ts +2 -1
  202. package/dist/form/form-field-control.js +116 -40
  203. package/dist/form/form-root.d.ts +2 -1
  204. package/dist/form/form-root.js +142 -23
  205. package/dist/form/index.d.ts +3 -1
  206. package/dist/form/index.js +12 -1
  207. package/dist/i18n/messages/en.json +64 -5
  208. package/dist/i18n/messages/ja.json +64 -5
  209. package/dist/i18n/messages/vi.json +64 -5
  210. package/dist/inertia/index.d.ts +20 -0
  211. package/dist/inertia/index.js +60 -1
  212. package/dist/lib/control-styles.d.ts +25 -3
  213. package/dist/lib/control-styles.js +9 -3
  214. package/dist/lib/datetime/picker-format.d.ts +8 -0
  215. package/dist/lib/datetime/picker-format.js +54 -0
  216. package/dist/lib/slot.d.ts +32 -0
  217. package/dist/lib/slot.js +22 -0
  218. package/dist/lib/variants.d.ts +22 -3
  219. package/dist/lib/variants.js +56 -1
  220. package/dist/props/components/app.prop.d.ts +25 -1
  221. package/dist/props/components/charts.prop.d.ts +21 -0
  222. package/dist/props/components/data-display.prop.d.ts +72 -4
  223. package/dist/props/components/data-entry.prop.d.ts +718 -46
  224. package/dist/props/components/form.prop.d.ts +142 -4
  225. package/dist/props/components/general.prop.d.ts +17 -1
  226. package/dist/props/components/index.d.ts +3 -3
  227. package/dist/props/components/layout.prop.d.ts +281 -11
  228. package/dist/props/components/navigation.prop.d.ts +114 -4
  229. package/dist/props/registry.d.ts +397 -11
  230. package/dist/props/registry.js +526 -11
  231. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  232. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  233. package/dist/props/vocabulary/index.d.ts +5 -5
  234. package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
  235. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  236. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  237. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  238. package/dist/styles/badge-layout.css +2 -1
  239. package/dist/styles/card-layout.css +26 -4
  240. package/dist/styles/chart-layout.css +15 -0
  241. package/dist/styles/control.css +657 -15
  242. package/dist/styles/core.css +5 -2
  243. package/dist/styles/data-display-layout.css +313 -6
  244. package/dist/styles/data-entry-layout.css +13 -0
  245. package/dist/styles/focus-ring.css +4 -0
  246. package/dist/styles/index.css +5 -2
  247. package/dist/styles/layout.css +327 -4
  248. package/dist/styles/navigation-layout.css +227 -0
  249. package/dist/styles/shell-layout.css +369 -13
  250. package/dist/styles/table-layout.css +95 -6
  251. package/dist/styles/text-layout.css +10 -4
  252. package/dist/tokens/base.css +2 -1
  253. package/dist/tokens/components/badge.css +1 -0
  254. package/dist/tokens/components/chart.css +6 -0
  255. package/dist/tokens/components/control.css +79 -2
  256. package/dist/tokens/components/data-display.css +20 -0
  257. package/dist/tokens/components/descriptions.css +11 -0
  258. package/dist/tokens/components/flex.css +8 -0
  259. package/dist/tokens/components/navigation.css +55 -0
  260. package/dist/tokens/components/shell.css +53 -3
  261. package/dist/tokens/components/table.css +14 -0
  262. package/dist/tokens/foundation.css +2 -0
  263. package/dist/tokens/semantic/layout.css +9 -0
  264. package/docs/COMPONENTS.md +9 -3
  265. package/docs/CONSUMER-RULES.md +13 -0
  266. package/docs/DESIGN-AUTHORITY.md +145 -83
  267. package/docs/DEVELOPMENT.md +4 -3
  268. package/docs/FORMS.md +151 -6
  269. package/docs/FRAME-COVERAGE-REPORT.md +32 -17
  270. package/docs/README.md +15 -15
  271. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  272. package/docs/TESTING.md +15 -6
  273. package/docs/WHAT-BELONGS-HERE.md +179 -0
  274. package/docs/charts/cjk-category-axis.tsx +81 -0
  275. package/docs/data-display/card/index.tsx +22 -0
  276. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  277. package/docs/data-display/data-table/index.tsx +23 -0
  278. package/docs/data-display/descriptions.tsx +41 -0
  279. package/docs/data-display/legend.tsx +145 -0
  280. package/docs/data-display/progress.tsx +32 -0
  281. package/docs/data-display/scroll-area.tsx +31 -25
  282. package/docs/data-display/table.tsx +104 -45
  283. package/docs/data-display/timeline.tsx +41 -0
  284. package/docs/data-entry/date-picker.tsx +85 -0
  285. package/docs/data-entry/date-range-picker.tsx +26 -0
  286. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  287. package/docs/data-entry/form.tsx +74 -4
  288. package/docs/data-entry/input-otp.tsx +24 -0
  289. package/docs/data-entry/input.tsx +46 -1
  290. package/docs/data-entry/month-range-picker.tsx +1 -1
  291. package/docs/data-entry/segmented.tsx +1 -1
  292. package/docs/data-entry/select.tsx +29 -2
  293. package/docs/data-entry/switch.tsx +41 -0
  294. package/docs/data-entry/textarea.tsx +38 -0
  295. package/docs/data-entry/time-picker.tsx +85 -1
  296. package/docs/data-entry/time-range-picker.tsx +55 -0
  297. package/docs/data-entry/transfer.tsx +17 -0
  298. package/docs/data-entry/upload.tsx +56 -12
  299. package/docs/feedback/sheet.tsx +1 -1
  300. package/docs/feedback/tooltip.tsx +1 -1
  301. package/docs/general/activity.tsx +2 -2
  302. package/docs/general/button/index.tsx +14 -1
  303. package/docs/general/typography.tsx +14 -1
  304. package/docs/layout/app-launcher.tsx +151 -0
  305. package/docs/layout/app-shell-arrangements.tsx +225 -0
  306. package/docs/layout/app-shell.tsx +11 -0
  307. package/docs/layout/aspect-ratio.tsx +1 -1
  308. package/docs/layout/flex.tsx +50 -0
  309. package/docs/layout/responsive-grid.tsx +21 -1
  310. package/docs/layout/topbar.tsx +5 -9
  311. package/docs/navigation/app-setting-picker.tsx +37 -1
  312. package/docs/navigation/app-setting-toggle.tsx +111 -0
  313. package/docs/navigation/breadcrumb.tsx +48 -0
  314. package/docs/navigation/dropdown-menu.tsx +21 -0
  315. package/docs/navigation/pagination.tsx +52 -0
  316. package/docs/navigation/steps.tsx +37 -0
  317. package/docs/navigation/tabs.tsx +97 -1
  318. package/docs/query/button-refetch.tsx +1 -0
  319. package/package.json +28 -8
  320. package/scripts/_agent-setup.mjs +182 -3
  321. package/scripts/consumer-rule.md +98 -0
  322. package/scripts/guinea-pig-skill.md +322 -0
  323. package/scripts/init-guinea-pig.mjs +84 -0
  324. package/scripts/postinstall.mjs +13 -2
  325. package/scripts/ui-audit.mjs +351 -37
  326. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -235,6 +235,58 @@ export default function Demo() {
235
235
  />
236
236
  </CardContent>
237
237
  </Card>
238
+
239
+ {/* Ant Design parity surface — showQuickJumper / size / align / responsive */}
240
+ <Card>
241
+ <CardHeader>
242
+ <CardTitle level={2}>showQuickJumper · size · align (Ant Design パリティ)</CardTitle>
243
+ <CardDescription>
244
+ showQuickJumper はページ番号を直接入力するフィールド(Enter または goButton
245
+ で確定、範囲外はクランプ)。size=&quot;sm&quot; はバーに --control-height
246
+ を一度だけ再束縛するので、ページボタン・サイズ変更・ジャンプ欄が同時に縮む。align
247
+ は論理軸(start / center / end)。responsive は既定で有効で、モバイル幅では simple
248
+ 形態に畳む。
249
+ </CardDescription>
250
+ </CardHeader>
251
+ <CardContent>
252
+ <Flex direction="col" gap="lg">
253
+ <div id="antd-pagination-jumper">
254
+ <Pagination
255
+ ariaLabel="クイックジャンパー付きページネーション"
256
+ value={3}
257
+ total={95}
258
+ pageSize={10}
259
+ showTotal
260
+ showSizeChanger
261
+ showQuickJumper
262
+ onValueChange={() => {}}
263
+ />
264
+ </div>
265
+ <div id="antd-pagination-sm">
266
+ <Pagination
267
+ ariaLabel="小サイズ・中央寄せのページネーション"
268
+ value={3}
269
+ total={95}
270
+ pageSize={10}
271
+ size="sm"
272
+ align="center"
273
+ showQuickJumper={{ goButton: "移動" }}
274
+ onValueChange={() => {}}
275
+ />
276
+ </div>
277
+ <div id="antd-pagination-start">
278
+ <Pagination
279
+ ariaLabel="先頭寄せのページネーション"
280
+ value={3}
281
+ total={95}
282
+ pageSize={10}
283
+ align="start"
284
+ onValueChange={() => {}}
285
+ />
286
+ </div>
287
+ </Flex>
288
+ </CardContent>
289
+ </Card>
238
290
  </Flex>
239
291
  </PageContainer>
240
292
  );
@@ -259,6 +259,43 @@ export default function Demo() {
259
259
  </Flex>
260
260
  </CardContent>
261
261
  </Card>
262
+
263
+ {/* Ant Design parity surface — percent + navigation */}
264
+ <Card>
265
+ <CardHeader>
266
+ <CardTitle level={2}>percent · navigation (Ant Design パリティ)</CardTitle>
267
+ <CardDescription>
268
+ percent は antd と同じく「現在ステップ」の進捗のみ(0–100
269
+ にクランプ)。マーカーの周りに確定アークを描き、role=&quot;progressbar&quot;
270
+ として読み上げられる。type=&quot;navigation&quot; は antd
271
+ のスラブ型ナビゲーションバーで、既定のヘアライン
272
+ コネクタは切られ、代わりにシェブロンで繋がる。
273
+ </CardDescription>
274
+ </CardHeader>
275
+ <CardContent>
276
+ <Flex direction="col" gap="lg">
277
+ <div id="antd-steps-percent">
278
+ <Steps
279
+ value={1}
280
+ percent={40}
281
+ items={[{ title: "申込" }, { title: "審査" }, { title: "完了" }]}
282
+ />
283
+ </div>
284
+ <div id="antd-steps-navigation">
285
+ <Steps
286
+ type="navigation"
287
+ value={1}
288
+ onValueChange={() => {}}
289
+ items={[
290
+ { title: "申込", description: "受付済" },
291
+ { title: "審査", description: "書類確認中" },
292
+ { title: "完了", description: "未着手" },
293
+ ]}
294
+ />
295
+ </div>
296
+ </Flex>
297
+ </CardContent>
298
+ </Card>
262
299
  </Flex>
263
300
  </PageContainer>
264
301
  );
@@ -46,6 +46,17 @@ const journalItems = [
46
46
 
47
47
  export default function Demo() {
48
48
  const [activeTab, setActiveTab] = useState("pending");
49
+ const [editableTabs, setEditableTabs] = useState([
50
+ { value: "je-0042", label: "JE-0042", content: <Text as="p">売上計上 ¥480,000</Text> },
51
+ { value: "je-0043", label: "JE-0043", content: <Text as="p">仕入計上 ¥120,000</Text> },
52
+ {
53
+ value: "je-0040",
54
+ label: "JE-0040 (固定)",
55
+ content: <Text as="p">給与支払 ¥2,800,000</Text>,
56
+ closable: false,
57
+ },
58
+ ]);
59
+ const [editableTab, setEditableTab] = useState("je-0042");
49
60
 
50
61
  return (
51
62
  <PageContainer
@@ -106,7 +117,7 @@ export default function Demo() {
106
117
  <CardTitle level={2}>320px stress · 長いローカライズラベル</CardTitle>
107
118
  <CardDescription>
108
119
  狭いコンテナでも長いラベルはクリップされず、水平タブリストが自身でスクロールする
109
- 。compact navigation への変換は Tabs API に存在しないため擬似実装しない
120
+ 。compact navigation への変換は Tabs API に存在しないため擬似実装しない ·
110
121
  スクロールが意図した縮退動作。
111
122
  </CardDescription>
112
123
  </CardHeader>
@@ -308,6 +319,91 @@ export default function Demo() {
308
319
  </Flex>
309
320
  </CardContent>
310
321
  </Card>
322
+
323
+ {/* Ant Design parity surface — editable-card + extra + centered + placement + size */}
324
+ <Card>
325
+ <CardHeader>
326
+ <CardTitle level={2}>Editable card · onEdit / extra / hideAdd</CardTitle>
327
+ <CardDescription>
328
+ variant=&quot;editable-card&quot; は Ant Design の editable-card。タブ内の ×
329
+ はポインタ用ショートカット(aria-hidden)で、キーボードでは Delete /
330
+ Backspace(aria-keyshortcuts)。追加ボタンは tablist の外にある本物の button。extra は
331
+ antd の tabBarExtraContent を論理軸(start / end)にしたもの。
332
+ </CardDescription>
333
+ </CardHeader>
334
+ <CardContent>
335
+ <Tabs
336
+ id="antd-editable-card"
337
+ variant="editable-card"
338
+ value={editableTab}
339
+ onValueChange={setEditableTab}
340
+ onEdit={(target, action) => {
341
+ if (action === "add") {
342
+ const next = `tab-${editableTabs.length + 1}`;
343
+ setEditableTabs([
344
+ ...editableTabs,
345
+ {
346
+ value: next,
347
+ label: `新規 ${editableTabs.length + 1}`,
348
+ content: <Text as="p">新規タブ {next}</Text>,
349
+ },
350
+ ]);
351
+ setEditableTab(next);
352
+ return;
353
+ }
354
+ const rest = editableTabs.filter((item) => item.value !== target);
355
+ setEditableTabs(rest);
356
+ if (target === editableTab && rest[0]) setEditableTab(rest[0].value);
357
+ }}
358
+ extra={{
359
+ end: (
360
+ <Button size="sm" variant="outline">
361
+ 一括操作
362
+ </Button>
363
+ ),
364
+ }}
365
+ items={editableTabs}
366
+ />
367
+ </CardContent>
368
+ </Card>
369
+
370
+ <Card>
371
+ <CardHeader>
372
+ <CardTitle level={2}>tabPlacement · size · centered</CardTitle>
373
+ <CardDescription>
374
+ tabPlacement は antd 6.6.2 の名前で、値は論理軸(top / bottom / start / end)。start /
375
+ end は tablist を縦方向のロービングフォーカスに切り替える。size はライブラリの control
376
+ band(sm / md / lg)に対応。
377
+ </CardDescription>
378
+ </CardHeader>
379
+ <CardContent>
380
+ <Flex direction="col" gap="lg">
381
+ <Tabs
382
+ id="antd-centered"
383
+ defaultValue="pending"
384
+ variant="line"
385
+ centered
386
+ items={journalItems}
387
+ />
388
+ <Tabs
389
+ id="antd-bottom"
390
+ defaultValue="pending"
391
+ variant="card"
392
+ tabPlacement="bottom"
393
+ size="sm"
394
+ items={journalItems}
395
+ />
396
+ <Tabs
397
+ id="antd-start"
398
+ defaultValue="pending"
399
+ variant="line"
400
+ tabPlacement="start"
401
+ size="lg"
402
+ items={journalItems}
403
+ />
404
+ </Flex>
405
+ </CardContent>
406
+ </Card>
311
407
  </Flex>
312
408
  </PageContainer>
313
409
  );
@@ -81,6 +81,7 @@ function VariantBlock() {
81
81
  <ButtonRefetch query={query} variant="ghost" label="ghost" />
82
82
  <ButtonRefetch query={query} variant="destructive" label="destructive" />
83
83
  <ButtonRefetch query={query} variant="link" label="link" />
84
+ <ButtonRefetch query={query} variant="bare" label="bare" />
84
85
  </Flex>
85
86
  </CardContent>
86
87
  </Card>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "19.6.0",
4
- "godxUiMcp": "19.6.0",
3
+ "version": "20.1.0",
4
+ "godxUiMcp": "20.1.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -30,6 +30,9 @@
30
30
  "scripts/visual-audit-rules.mjs",
31
31
  "scripts/audit-hook.mjs",
32
32
  "scripts/init-agent-kit.mjs",
33
+ "scripts/init-guinea-pig.mjs",
34
+ "scripts/guinea-pig-skill.md",
35
+ "scripts/consumer-rule.md",
33
36
  "scripts/postinstall.mjs",
34
37
  "scripts/_agent-setup.mjs",
35
38
  "scripts/cli.mjs",
@@ -82,6 +85,22 @@
82
85
  "types": "./dist/components/charts/compact-bar-trend.d.ts",
83
86
  "import": "./dist/components/charts/compact-bar-trend.js"
84
87
  },
88
+ "./charts/line-chart": {
89
+ "types": "./dist/components/charts/line-chart.d.ts",
90
+ "import": "./dist/components/charts/line-chart.js"
91
+ },
92
+ "./charts/bar-chart": {
93
+ "types": "./dist/components/charts/bar-chart.d.ts",
94
+ "import": "./dist/components/charts/bar-chart.js"
95
+ },
96
+ "./charts/area-chart": {
97
+ "types": "./dist/components/charts/area-chart.d.ts",
98
+ "import": "./dist/components/charts/area-chart.js"
99
+ },
100
+ "./charts/pie-chart": {
101
+ "types": "./dist/components/charts/pie-chart.d.ts",
102
+ "import": "./dist/components/charts/pie-chart.js"
103
+ },
85
104
  "./ui": {
86
105
  "types": "./dist/components/ui/index.d.ts",
87
106
  "import": "./dist/components/ui/index.js"
@@ -308,10 +327,12 @@
308
327
  "format": "prettier --check .",
309
328
  "format:fix": "prettier --write .",
310
329
  "test": "vitest run",
330
+ "test:manual": "vitest run --config vitest.manual.config.ts",
311
331
  "test:visual:auth-login": "node scripts/auth-shell-login-visual.mjs",
312
332
  "test:visual:auth-registration": "node scripts/auth-shell-registration-visual.mjs",
313
333
  "test:visual:topbar-collision": "node scripts/topbar-collision-visual.mjs",
314
334
  "test:visual:table-collection-cjk": "node scripts/table-collection-cjk-visual.mjs",
335
+ "test:visual:chart-cjk-axis": "node scripts/chart-cjk-axis-visual.mjs",
315
336
  "test:watch": "vitest",
316
337
  "test:coverage": "vitest run --coverage",
317
338
  "check:example-imports": "node scripts/check-example-imports.mjs",
@@ -335,8 +356,8 @@
335
356
  "check:frame-runtime": "pnpm check:data-entry-frame-runtime && pnpm check:data-entry-touch-aria && pnpm check:layout-nav-frames && pnpm check:provider-feedback-query-runtime && pnpm check:layout-nav-closure && pnpm check:final-touch-rtl && pnpm check:data-table-pagination-wrap && pnpm check:button-icon-xs",
336
357
  "verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:frame-coverage && pnpm test",
337
358
  "verify:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
338
- "verify:ci": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm test",
339
- "verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync",
359
+ "verify:ci": "pnpm verify:ci:static && pnpm check:frame-contracts && pnpm test",
360
+ "verify:ci:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:registry && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:no-antd-runtime && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:gate-coverage && pnpm check:mcp-prop-sync",
340
361
  "verify:browser": "pnpm check:contrast && pnpm check:visual-audit",
341
362
  "verify:release": "pnpm verify:static && pnpm check:frame-contracts && pnpm check:frame-coverage && pnpm check:frame-axe",
342
363
  "verify:publish-tree": "pnpm build && pnpm check:packed-public-contract && pnpm check:use-client && pnpm check:dist-tokens-resolve",
@@ -365,9 +386,6 @@
365
386
  "check:rtl": "node scripts/check-rtl.mjs",
366
387
  "check:typography": "node scripts/check-typography.mjs",
367
388
  "gen:component-tokens": "node scripts/gen-component-tokens.mjs",
368
- "gen:antd-tokens": "node scripts/gen-antd-tokens.mjs",
369
- "check:antd-tokens": "node scripts/gen-antd-tokens.mjs --check",
370
- "report:antd-tokens": "node scripts/gen-antd-tokens.mjs --report",
371
389
  "check:no-antd-runtime": "node scripts/check-no-antd-runtime.mjs",
372
390
  "gen:email-tokens": "node scripts/gen-email-tokens.mjs",
373
391
  "check:core-isolation": "node scripts/check-core-isolation.mjs",
@@ -384,6 +402,7 @@
384
402
  "dev": "node scripts/dev.mjs",
385
403
  "prepublishOnly": "pnpm run build",
386
404
  "check:audit-sync": "node scripts/check-audit-sync.mjs",
405
+ "check:gate-coverage": "node scripts/check-gate-coverage.mjs",
387
406
  "check:contrast": "node scripts/check-contrast.mjs",
388
407
  "visual-audit": "node scripts/visual-audit.mjs",
389
408
  "check:visual-audit": "node scripts/visual-audit-smoke.mjs",
@@ -451,6 +470,7 @@
451
470
  "@radix-ui/react-toggle": "^1.1.18",
452
471
  "@radix-ui/react-toggle-group": "^1.1.19",
453
472
  "@radix-ui/react-tooltip": "^1.2.16",
473
+ "@react-aria/utils": "^3.34.1",
454
474
  "@tanstack/react-table": "^9.2.4",
455
475
  "class-variance-authority": "^0.7.1",
456
476
  "clsx": "^2.1.1",
@@ -460,6 +480,7 @@
460
480
  "input-otp": "^1.5.0",
461
481
  "lucide-react": "^1.37.0",
462
482
  "qrcode.react": "4.2.0",
483
+ "react-aria-components": "^1.21.1",
463
484
  "react-day-picker": "^10.0.1",
464
485
  "react-resizable-panels": "^4.12.3",
465
486
  "sonner": "^2.0.8",
@@ -483,7 +504,6 @@
483
504
  "@types/react-dom": "^19.2.5",
484
505
  "@vitejs/plugin-react": "^6.1.1",
485
506
  "@vitest/coverage-v8": "^4.1.11",
486
- "antd": "6.6.2",
487
507
  "axe-core": "^4.13.0",
488
508
  "eslint": "^10.9.1",
489
509
  "eslint-plugin-react": "^7.37.5",
@@ -4,10 +4,15 @@
4
4
  * NON-DESTRUCTIVE: it only creates a missing file or ADDS a missing key, never
5
5
  * overwrites existing config.
6
6
  */
7
+ import { createHash } from "node:crypto";
7
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
9
  import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
9
11
 
10
12
  /** The godxjp-ui MCP server — pulled on demand via npx (no extra dependency to ship). */
13
+ /** This package's own root — the source of the version we stamp with. */
14
+ const SELF_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
15
+
11
16
  export const MCP_SERVER = { command: "npx", args: ["@godxjp/ui-mcp"] };
12
17
  export const MCP_KEY = "godx-ui";
13
18
 
@@ -16,7 +21,47 @@ export const AUDIT_HOOK_CMD = "node node_modules/@godxjp/ui/scripts/audit-hook.m
16
21
  export const PRIMER_CMD = "cat .claude/godxjp-ui-workflow.md";
17
22
 
18
23
  /** The per-session workflow mandate the SessionStart hook injects into the agent. */
19
- export const WORKFLOW_MD = `# @godxjp/ui mandatory workflow (read every session)
24
+ export const KIT_VERSION = readJson(join(SELF_ROOT, "package.json"))?.version ?? "0.0.0";
25
+
26
+ const STAMP = (v) => `<!-- godxjp-ui:version ${v} -->`;
27
+ const STAMP_RE = /<!-- godxjp-ui:version ([^\s]+) -->/;
28
+
29
+ /** The version stamped in `text`, or null when it predates stamping. */
30
+ export function stampedVersion(text) {
31
+ return text?.match(STAMP_RE)?.[1] ?? null;
32
+ }
33
+
34
+ /**
35
+ * A stamp that tracks the CONTENT, for the files this package owns outright.
36
+ *
37
+ * A version stamp answers "which release wrote this", which is the wrong question for a file whose
38
+ * whole job is to carry current guidance. Measured: editing `consumer-rule.md` without bumping the
39
+ * package left two of three consumers holding the previous text, with a stamp that read as current
40
+ * and nothing anywhere reporting a difference. The rules are edited far more often than the
41
+ * version moves — most of all while they are being written, which is exactly when a stale copy
42
+ * does the most damage.
43
+ *
44
+ * So the digest goes in alongside the version: the version stays for humans reading the file, and
45
+ * the digest is what the refresh actually compares. Identical body → still a no-op.
46
+ */
47
+ const DIGEST_RE = /<!-- godxjp-ui:digest ([0-9a-f]{12}) -->/;
48
+ const digestOf = (body) => createHash("sha256").update(body).digest("hex").slice(0, 12);
49
+ const OWNED_STAMP = (body) => `${STAMP(KIT_VERSION)}\n<!-- godxjp-ui:digest ${digestOf(body)} -->`;
50
+
51
+ /** The content digest stamped in `text`, or null when it predates digest stamping. */
52
+ export function stampedDigest(text) {
53
+ return text?.match(DIGEST_RE)?.[1] ?? null;
54
+ }
55
+
56
+ /**
57
+ * Replace the MANAGED region of a file and leave everything else alone.
58
+ *
59
+ * Refreshing is only safe if it cannot eat hand-written content, so the contract is narrow: the
60
+ * region is delimited, and anything outside the delimiters survives byte-for-byte. A consumer that
61
+ * appended repo-specific sections keeps them.
62
+ */
63
+ export const WORKFLOW_MD = `${STAMP(KIT_VERSION)}
64
+ # @godxjp/ui — mandatory workflow (read every session)
20
65
 
21
66
  You are building UI in an app that uses @godxjp/ui. Follow this EVERY time you create
22
67
  or change a component, page, or form — no exceptions.
@@ -50,6 +95,7 @@ or change a component, page, or form — no exceptions.
50
95
  /** Delimited block appended to the consumer's CLAUDE.md — loaded into the agent's context
51
96
  * every turn (the most reliable "ensure it reads the rules"). Markers keep it idempotent. */
52
97
  export const CLAUDE_MD_BLOCK = `<!-- godxjp-ui:start (managed by @godxjp/ui — edit .claude/godxjp-ui-workflow.md instead) -->
98
+ ${STAMP(KIT_VERSION)}
53
99
  ## @godxjp/ui — mandatory UI workflow (do NOT skip)
54
100
 
55
101
  This app uses @godxjp/ui. EVERY time you build or change UI:
@@ -82,6 +128,24 @@ function readJson(path) {
82
128
  }
83
129
 
84
130
  /** Ensure `.mcp.json` registers the godx-ui MCP server. Returns 'created' | 'added' | 'present'. */
131
+ /**
132
+ * The version that wrote each managed artefact, stamped so `postinstall` can tell "already there"
133
+ * apart from "already there and STALE".
134
+ *
135
+ * Everything below used to be install-once: `ensureMcpJson` returned early on a present key,
136
+ * `writeWorkflowMd` on a present file, `ensureClaudeMd` on a present marker. So `npm update
137
+ * @godxjp/ui` brought new components, new audit rules and new catalog entries — and left the
138
+ * agent reading whatever guidance shipped the day the package was FIRST installed. The library
139
+ * moved; the instructions for using it did not.
140
+ */
141
+ export function refreshBlock(current, next, startMarker, endMarker) {
142
+ const i = current.indexOf(startMarker);
143
+ if (i < 0) return current.replace(/\s*$/, "") + "\n\n" + next;
144
+ const j = endMarker ? current.indexOf(endMarker, i) : -1;
145
+ const tail = j < 0 ? "" : current.slice(j + endMarker.length);
146
+ return current.slice(0, i) + next + tail;
147
+ }
148
+
85
149
  export function ensureMcpJson(root) {
86
150
  const path = join(root, ".mcp.json");
87
151
  const json = readJson(path) ?? {};
@@ -127,7 +191,14 @@ export function ensureClaudeHooks(root) {
127
191
  export function writeWorkflowMd(root) {
128
192
  const path = join(root, ".claude", "godxjp-ui-workflow.md");
129
193
  mkdirSync(dirname(path), { recursive: true });
130
- if (existsSync(path)) return false;
194
+ // This file is owned entirely by the package — the CLAUDE.md block tells the consumer to edit
195
+ // it, but nothing else reads from it, so a stale copy is pure loss. Rewrite when the stamp moves.
196
+ if (existsSync(path)) {
197
+ const cur = readFileSync(path, "utf8");
198
+ if (stampedVersion(cur) === KIT_VERSION) return false;
199
+ writeFileSync(path, WORKFLOW_MD);
200
+ return "refreshed";
201
+ }
131
202
  writeFileSync(path, WORKFLOW_MD);
132
203
  return true;
133
204
  }
@@ -139,7 +210,16 @@ export function writeWorkflowMd(root) {
139
210
  export function ensureClaudeMd(root) {
140
211
  const path = join(root, "CLAUDE.md");
141
212
  const existing = existsSync(path) ? readFileSync(path, "utf8") : null;
142
- if (existing?.includes("godxjp-ui:start")) return "present";
213
+ if (existing?.includes("godxjp-ui:start")) {
214
+ // Present — but at WHICH version? Refresh only the delimited block; anything the consumer
215
+ // wrote around it is untouched.
216
+ if (stampedVersion(existing) === KIT_VERSION) return "present";
217
+ writeFileSync(
218
+ path,
219
+ refreshBlock(existing, CLAUDE_MD_BLOCK, "<!-- godxjp-ui:start", "<!-- godxjp-ui:end -->"),
220
+ );
221
+ return "refreshed";
222
+ }
143
223
  if (existing == null) {
144
224
  writeFileSync(path, CLAUDE_MD_BLOCK);
145
225
  return "created";
@@ -157,3 +237,102 @@ export function shouldSkip(root) {
157
237
  if (pkg.name === "@godxjp/ui" || pkg.name === "@godxjp/ui-mcp") return "self";
158
238
  return null;
159
239
  }
240
+
241
+ /**
242
+ * Keep an opted-in guinea-pig skill current.
243
+ *
244
+ * The file is co-authored: sections 0–7 come from this package, and section 8 onward is whatever
245
+ * the repo wrote about ITSELF — its package manager, its audit baseline, its deliberate
246
+ * exceptions. So the refresh replaces the head and keeps the tail, which is the only split that
247
+ * lets the guidance move without eating the consumer's own notes.
248
+ *
249
+ * Only runs where `.guinea-pig-optin` exists: the skill carries an obligation to fix things
250
+ * UPSTREAM, and pushing that into a repo that never asked for it would tell its agent to go edit
251
+ * a library it has no mandate over.
252
+ */
253
+ export function refreshGuineaPigSkill(root) {
254
+ const dir = join(root, ".claude", "skills", "godx-ui-guinea-pig");
255
+ const target = join(dir, "SKILL.md");
256
+ const optin = join(dir, ".guinea-pig-optin");
257
+ if (!existsSync(optin) || !existsSync(target)) return false;
258
+
259
+ const base = readFileSync(join(SELF_ROOT, "scripts", "guinea-pig-skill.md"), "utf8");
260
+ /*
261
+ * The marker tracks the BASE TEXT, not the release — the same correction the consumer rule file
262
+ * needed, for the same reason. A version marker means editing this skill without cutting a
263
+ * release reaches nobody, and the skill is edited far more often than the version moves. The
264
+ * digest covers only the base: everything from the `# 8.` marker down belongs to the repo and
265
+ * must not make the package's own content look changed.
266
+ *
267
+ * `<version>:<digest>` rather than a bare digest, so the file still says which release wrote it
268
+ * to anyone reading it. Only the digest half is compared.
269
+ */
270
+ const stamp = `${KIT_VERSION}:${digestOf(base)}`;
271
+ if (readFileSync(optin, "utf8").trim().split(":").pop() === digestOf(base)) return false;
272
+
273
+ const current = readFileSync(target, "utf8");
274
+ const marker = "\n---\n\n# 8. ";
275
+ const i = current.indexOf(marker);
276
+ writeFileSync(target, base.replace(/\s*$/, "") + "\n" + (i < 0 ? "" : current.slice(i)));
277
+ writeFileSync(optin, `${stamp}\n`);
278
+ return true;
279
+ }
280
+
281
+ /** The stamp `init-guinea-pig` writes on a fresh install, so the first refresh is a no-op. */
282
+ export function guineaPigStamp() {
283
+ return `${KIT_VERSION}:${digestOf(readFileSync(join(SELF_ROOT, "scripts", "guinea-pig-skill.md"), "utf8"))}`;
284
+ }
285
+
286
+ /**
287
+ * Install the common consumer rules as a PATH-TRIGGERED file, and wire them into `.ai/rules`.
288
+ *
289
+ * The skill and this file say overlapping things on purpose, because they fire at different
290
+ * moments: a skill loads when the TASK matches its description — once, at the start — while an
291
+ * `.ai/rules` entry loads every time an agent touches a file under its glob. Measured over one
292
+ * session: a dashboard file was edited dozens of times and the skill was never re-read, so the
293
+ * laws that mattered were out of context for every edit after the first.
294
+ *
295
+ * The glob is DETECTED, not assumed. A rule wired to a directory the repo does not have is a rule
296
+ * that never fires, which is worse than no rule at all — it looks installed.
297
+ *
298
+ * Unlike the skill, this file is owned OUTRIGHT by the package and is rewritten whole. That is the
299
+ * honest shape for `.ai/rules`, where the convention is one file per concern and the index loads
300
+ * them all: a repo with something of its own to say writes its own rule file instead of editing
301
+ * this one. The file says so at the top, because the first draft preserved nothing and silently
302
+ * ate a note left inside it — measured, and the reason for that banner.
303
+ */
304
+ export function ensureConsumerRules(root) {
305
+ const uiDir = ["resources/js", "app/javascript", "src/components", "src", "app"].find((d) =>
306
+ existsSync(join(root, d)),
307
+ );
308
+ if (!uiDir) return false;
309
+
310
+ const dir = join(root, ".ai", "rules");
311
+ const target = join(dir, "godxjp-ui.md");
312
+ const body = readFileSync(join(SELF_ROOT, "scripts", "consumer-rule.md"), "utf8");
313
+ const front = `---\npaths:\n - '${uiDir}/**'\n---\n\n`;
314
+ // The digest covers the FRONT MATTER too: the detected glob is part of what makes this file
315
+ // correct, and a repo that grows a `resources/js` after shipping with `src` needs the rewrite.
316
+ const managed = `${front}${body}`;
317
+ const next = `${OWNED_STAMP(managed)}\n${managed}`;
318
+
319
+ if (existsSync(target) && stampedDigest(readFileSync(target, "utf8")) === digestOf(managed)) {
320
+ return false;
321
+ }
322
+ mkdirSync(dir, { recursive: true });
323
+ writeFileSync(target, next);
324
+
325
+ // Only touch the index when the repo keeps one; a missing index means the repo reads rule files
326
+ // directly, and inventing one would change how it loads everything else.
327
+ const index = join(dir, "index.md");
328
+ if (existsSync(index)) {
329
+ const cur = readFileSync(index, "utf8");
330
+ if (!cur.includes(".ai/rules/godxjp-ui.md")) {
331
+ writeFileSync(
332
+ index,
333
+ cur.replace(/\s*$/, "") + `\n| ${uiDir}/** | .ai/rules/godxjp-ui.md |\n`,
334
+ );
335
+ }
336
+ }
337
+ return uiDir;
338
+ }