@tmorrow/cre8-wc 2.3.0 → 2.3.2

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 (160) hide show
  1. package/a2ui/catalog-kg.json +6837 -116
  2. package/a2ui/catalog.compact.json +3 -3
  3. package/a2ui/catalog.json +73 -73
  4. package/a2ui/check-deploy-drift.mjs +147 -0
  5. package/a2ui/generate-catalog-kg.mjs +194 -18
  6. package/a2ui/kg-sources.mjs +291 -0
  7. package/a2ui/patterns/alert-banner.json +16 -0
  8. package/a2ui/patterns/data-table.json +67 -0
  9. package/a2ui/patterns/login-form.json +55 -0
  10. package/a2ui/patterns/modal-dialog.json +47 -0
  11. package/a2ui/patterns/page-layout.json +55 -0
  12. package/a2ui/patterns/tabbed-content.json +37 -0
  13. package/dist/assets/{Changelog-Documentation-BEz7qwHC.js → Changelog-Documentation-DyRD5g5c.js} +1 -1
  14. package/dist/assets/{Code-Guidelines-BRlChdnm.js → Code-Guidelines-DIxeIc7I.js} +1 -1
  15. package/dist/assets/{Color-6AOWCN3U-DeiMoXtk.js → Color-6AOWCN3U-Dznni4GY.js} +1 -1
  16. package/dist/assets/{Contributing-Guidelines-ZYkPHT5D.js → Contributing-Guidelines-C361mreO.js} +1 -1
  17. package/dist/assets/{DocsRenderer-JROSPFPF-DLyaYyWd.js → DocsRenderer-JROSPFPF-DVzuXMfE.js} +1 -1
  18. package/dist/assets/{Tokens-Documentation-DdehD3DX.js → Tokens-Documentation-DQ55nCPE.js} +1 -1
  19. package/dist/assets/{WithTooltip-7X4HQR7L-BWB3Yb4o.js → WithTooltip-7X4HQR7L-57g4vxQ5.js} +1 -1
  20. package/dist/assets/{accordion-item.stories-BAnUfHf7.js → accordion-item.stories-Cz0JPYkb.js} +1 -1
  21. package/dist/assets/{accordion.stories-B-5tkfuu.js → accordion.stories-CKPEtfSL.js} +1 -1
  22. package/dist/assets/{address-form.stories-DL1-wOd_.js → address-form.stories-clpPw22i.js} +1 -1
  23. package/dist/assets/{alert.stories-DkQjKtTE.js → alert.stories-UoZRIq2Z.js} +1 -1
  24. package/dist/assets/{badge-DyapNgMi.js → badge-Bf3zamLa.js} +1 -1
  25. package/dist/assets/{badge.stories-8NMDzMHB.js → badge.stories-BpZgJgka.js} +1 -1
  26. package/dist/assets/{band.stories-D5Z1gvOr.js → band.stories-CX5fEcU0.js} +1 -1
  27. package/dist/assets/{blocks-DTMWhAiD.js → blocks-F7P3fIJh.js} +5 -5
  28. package/dist/assets/{breadcrumbs.stories-CY40buuT.js → breadcrumbs.stories-CRuQAhFW.js} +1 -1
  29. package/dist/assets/{button-B559dEsw.js → button-BIrV07TC.js} +1 -1
  30. package/dist/assets/{button-group-Dg6GrxAH.js → button-group-Dnp9PfP1.js} +1 -1
  31. package/dist/assets/{button-group.stories-BxJK661K.js → button-group.stories-Br_EMXmB.js} +1 -1
  32. package/dist/assets/{button.stories-CzS_9O5r.js → button.stories-Dh9JhOw6.js} +1 -1
  33. package/dist/assets/{card-BoBkN7zZ.js → card-D7QkgRPU.js} +1 -1
  34. package/dist/assets/{card.stories-CJM3mMAl.js → card.stories-DZ6fUn4F.js} +1 -1
  35. package/dist/assets/{chart.stories-DTfsMOMw.js → chart.stories-5mvT-zpx.js} +1 -1
  36. package/dist/assets/{checkbox-field-item-D3itMvx5.js → checkbox-field-item-ysgkDLCX.js} +1 -1
  37. package/dist/assets/{checkbox-field-item.stories-dbJJd5j4.js → checkbox-field-item.stories-C-OuHysX.js} +1 -1
  38. package/dist/assets/{checkbox-field.stories-D0U38na0.js → checkbox-field.stories-DET4STIP.js} +1 -1
  39. package/dist/assets/{cre8-element-DmRct7AK.js → cre8-element-D3XuogmB.js} +1 -1
  40. package/dist/assets/{cre8-form-element-DOU8_QgO.js → cre8-form-element-CYVZKUkM.js} +1 -1
  41. package/dist/assets/{danger-button.stories-C9I-81sl.js → danger-button.stories-fAfsxvin.js} +1 -1
  42. package/dist/assets/{date-picker.stories-BLywvSGj.js → date-picker.stories-Ck6AgzHE.js} +1 -1
  43. package/dist/assets/{divider-D5Ptz_gO.js → divider-BY3ZlruA.js} +1 -1
  44. package/dist/assets/{divider.stories-DeZhkiUu.js → divider.stories-owgSQsO4.js} +1 -1
  45. package/dist/assets/{dropdown-CEMfVKWu.js → dropdown-C91qBvHH.js} +1 -1
  46. package/dist/assets/{dropdown-item.stories-Drl5X5AH.js → dropdown-item.stories-B_gF04eB.js} +1 -1
  47. package/dist/assets/{dropdown.stories-gErmDoak.js → dropdown.stories-CAVN9Hfk.js} +1 -1
  48. package/dist/assets/{f-po-ClP0V3UU.js → f-po-BibEwLg7.js} +1 -1
  49. package/dist/assets/{feature.stories-DMWFA4_w.js → feature.stories-BfyMh3-v.js} +1 -1
  50. package/dist/assets/{field-CyeqmMLD.js → field-BGNR3p0L.js} +1 -1
  51. package/dist/assets/{field-note-4gAB1YtN.js → field-note-BnKZocKm.js} +1 -1
  52. package/dist/assets/{field-note.stories-BIkt-4nw.js → field-note.stories-DY8NRFUg.js} +1 -1
  53. package/dist/assets/{field.stories-Bp-i75cD.js → field.stories-BPk8Sd15.js} +1 -1
  54. package/dist/assets/{field.styles-BuRZIGyO.js → field.styles-DluEkAA0.js} +1 -1
  55. package/dist/assets/{footer.stories-Dct4TXtx.js → footer.stories-DxcGN204.js} +1 -1
  56. package/dist/assets/{form-DdOes3CI.js → form-BEztLvfh.js} +1 -1
  57. package/dist/assets/{form.stories-Bxijt3vs.js → form.stories-Cm6F6p8Q.js} +1 -1
  58. package/dist/assets/{formatter-L2YTDE3Q-BC-dAH-7.js → formatter-L2YTDE3Q-EtWfIGsw.js} +1 -1
  59. package/dist/assets/{global-nav-item-B-CZOxU0.js → global-nav-item-BjYreeQ_.js} +1 -1
  60. package/dist/assets/{global-nav-item.stories-5fOY46FM.js → global-nav-item.stories-CtIfegX4.js} +1 -1
  61. package/dist/assets/{global-nav.stories-DKE_MdUD.js → global-nav.stories-CpxixIgP.js} +1 -1
  62. package/dist/assets/{grid-item-BoB-uijb.js → grid-item-DfRshyU7.js} +1 -1
  63. package/dist/assets/{grid.stories-CFmGCOQD.js → grid.stories-HoL4hFK5.js} +1 -1
  64. package/dist/assets/{header.stories-CTNVu9H3.js → header.stories-DtnMiHw5.js} +1 -1
  65. package/dist/assets/{heading-CLjq87aR.js → heading-Bd8rz14W.js} +1 -1
  66. package/dist/assets/{heading.stories-DtV0xOBN.js → heading.stories-D6LqhrSJ.js} +1 -1
  67. package/dist/assets/{hero.stories-Ca6F0_ZF.js → hero.stories-DbVmgYoe.js} +1 -1
  68. package/dist/assets/{icon-DPDhfDk5.js → icon-5TiNNxPR.js} +1 -1
  69. package/dist/assets/{icon.stories-C3Q7NyK3.js → icon.stories-CSF4vjWQ.js} +1 -1
  70. package/dist/assets/if-defined-BYzWFJjz.js +1 -0
  71. package/dist/assets/{iframe-Cd639NOt.js → iframe-DNXIQNo5.js} +4 -4
  72. package/dist/assets/{inline-alert.stories-DQzPNO1M.js → inline-alert.stories-DPeI6lZo.js} +1 -1
  73. package/dist/assets/{layout-container.stories-CEu1E5xz.js → layout-container.stories-DjnXlNhJ.js} +1 -1
  74. package/dist/assets/{layout.stories-C-r1Ysar.js → layout.stories-RpAgLydl.js} +1 -1
  75. package/dist/assets/{linelength-container.stories-Z1xot9Nf.js → linelength-container.stories-CBXpDJq9.js} +1 -1
  76. package/dist/assets/{link-D8WlhTPZ.js → link-Yrdg4UMD.js} +1 -1
  77. package/dist/assets/{link-list.stories-9cOc5cKF.js → link-list.stories-B5HBzRbn.js} +1 -1
  78. package/dist/assets/{link.stories-D54TIq-J.js → link.stories-CMfRfExj.js} +1 -1
  79. package/dist/assets/{list.stories-C1Jx4AhC.js → list.stories-DxiKX7Ag.js} +1 -1
  80. package/dist/assets/{loading-spinner-ByesL8fd.js → loading-spinner-Dtn9_2xi.js} +1 -1
  81. package/dist/assets/{loading-spinner.stories-B7qYKdri.js → loading-spinner.stories-BLxVyD_V.js} +1 -1
  82. package/dist/assets/{logo.stories-jiwYTlr2.js → logo.stories-Bp4xEAgc.js} +1 -1
  83. package/dist/assets/{main.stories-DIohnnzB.js → main.stories-Dl_ReGW2.js} +1 -1
  84. package/dist/assets/{modal-LqTEYNjw.js → modal-BkUVltsh.js} +1 -1
  85. package/dist/assets/{modal-DO_Vneby.js → modal-D805CQSw.js} +1 -1
  86. package/dist/assets/{modal.stories-Bf16sUUo.js → modal.stories-Cmt-pN5U.js} +1 -1
  87. package/dist/assets/{multi-select.stories-D2FX0drF.js → multi-select.stories-BUY8eZbU.js} +1 -1
  88. package/dist/assets/{nav-container.stories-Dz8D1KTt.js → nav-container.stories-8-Hdrqet.js} +1 -1
  89. package/dist/assets/{page-header.stories-QSawevlA.js → page-header.stories-DnIfsM6p.js} +1 -1
  90. package/dist/assets/{pagination.stories-zXMokh9Q.js → pagination.stories-BGHD1N4G.js} +1 -1
  91. package/dist/assets/{percent-bar.stories-CExBGXPP.js → percent-bar.stories-BHkYQ9QF.js} +1 -1
  92. package/dist/assets/{popover.stories-wZjzpaSh.js → popover.stories-_kYFHU0l.js} +1 -1
  93. package/dist/assets/{primary-nav.stories-B9chy1Uv.js → primary-nav.stories-CtvK3j2S.js} +1 -1
  94. package/dist/assets/{progress-meter-OmPLl0CJ.js → progress-meter-BlWAgZUd.js} +1 -1
  95. package/dist/assets/{progress-meter.stories-BY73_kXC.js → progress-meter.stories-GeVuGj_S.js} +1 -1
  96. package/dist/assets/{progress-steps-item-DX7cfkY6.js → progress-steps-item-DJNftsaD.js} +1 -1
  97. package/dist/assets/{progress-steps-item.stories-CUJlwofh.js → progress-steps-item.stories-1UHAaQUG.js} +1 -1
  98. package/dist/assets/{progress-steps.stories-B9o0nT3v.js → progress-steps.stories-BeZeRh7H.js} +1 -1
  99. package/dist/assets/{radio-field-item-ApN9fT3r.js → radio-field-item-CT1M0B3m.js} +1 -1
  100. package/dist/assets/{radio-field-item.stories-5eMm6X-l.js → radio-field-item.stories-BI1bjaVr.js} +1 -1
  101. package/dist/assets/{radio-field.stories-nUhPXwi3.js → radio-field.stories-BImvG2r2.js} +1 -1
  102. package/dist/assets/{remove-tag-1irQee-a.js → remove-tag-4TqbdK7Q.js} +1 -1
  103. package/dist/assets/{remove-tag.stories-CBKcGI5F.js → remove-tag.stories-BRl0J94X.js} +1 -1
  104. package/dist/assets/{sample-modal.stories-D2h88MGz.js → sample-modal.stories-DF5OldDU.js} +1 -1
  105. package/dist/assets/{section.stories-FSvR1k6O.js → section.stories-ElOjlSK7.js} +1 -1
  106. package/dist/assets/{select-tile-C0MvyMiv.js → select-tile-DNBzrxMY.js} +1 -1
  107. package/dist/assets/{select-tile-list.stories-B6tc2fV5.js → select-tile-list.stories-oKhYBTxt.js} +1 -1
  108. package/dist/assets/{select-tile.stories-BeJuC0QL.js → select-tile.stories-vu14aNAr.js} +1 -1
  109. package/dist/assets/{select.stories-iqUp3i6o.js → select.stories-CyxFtumd.js} +1 -1
  110. package/dist/assets/{sign-in.stories-LiBRbPNv.js → sign-in.stories-BLk1lY2i.js} +1 -1
  111. package/dist/assets/{skeleton-loader.stories-BKrmx5lC.js → skeleton-loader.stories-B9RgJ96w.js} +1 -1
  112. package/dist/assets/{split-button.stories-CzGaEK2m.js → split-button.stories-DAoFf1Px.js} +1 -1
  113. package/dist/assets/{spread-t5SXTlkZ.js → spread-DycKdtF1.js} +1 -1
  114. package/dist/assets/state-CETXgFRU.js +1 -0
  115. package/dist/assets/{submenu.stories-PZXeOJN7.js → submenu.stories-JGU9u6xB.js} +1 -1
  116. package/dist/assets/{syntaxhighlighter-T5IQBZDB-wKvCRvsc.js → syntaxhighlighter-T5IQBZDB-BWE8R-LG.js} +1 -1
  117. package/dist/assets/{table-header-CbbWqMDC.js → table-header-BFBYVGrO.js} +1 -1
  118. package/dist/assets/{table-object.stories-BhUz4NJk.js → table-object.stories-DZlKjO9A.js} +1 -1
  119. package/dist/assets/{table.stories-kpLio1OA.js → table.stories-BXgbpGTm.js} +1 -1
  120. package/dist/assets/{tabs.stories-DX6mOsXJ.js → tabs.stories-DavvGpOC.js} +1 -1
  121. package/dist/assets/{tag-BhnWTIDT.js → tag-CB0gsxGW.js} +1 -1
  122. package/dist/assets/{tag-list.stories-Bbkyxw29.js → tag-list.stories-CwO4ONea.js} +1 -1
  123. package/dist/assets/{tag.stories-eiczN1_F.js → tag.stories-CyhRz7Ae.js} +1 -1
  124. package/dist/assets/{tertiary-nav.stories-BmZ5z1S7.js → tertiary-nav.stories-D0avN5fj.js} +1 -1
  125. package/dist/assets/{text-link-B1JUg0aF.js → text-link-DeikfyWI.js} +1 -1
  126. package/dist/assets/{text-link.stories-P9lrKEa2.js → text-link.stories-DJ0ePcYU.js} +1 -1
  127. package/dist/assets/{text-passage-DfLhIsZs.js → text-passage-Cw8VlQkR.js} +1 -1
  128. package/dist/assets/{text-passage.stories-CSpA8rpO.js → text-passage.stories-B7S5M-Zh.js} +1 -1
  129. package/dist/assets/{tooltip.stories-CreTe2cH.js → tooltip.stories-CbsS1Mok.js} +1 -1
  130. package/dist/assets/{utility-nav.stories-D5lUQ87g.js → utility-nav.stories-BlsohD-7.js} +1 -1
  131. package/dist/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Bold.woff2 +0 -0
  132. package/dist/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-LatinExt.woff2 +0 -0
  133. package/dist/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Medium.woff2 +0 -0
  134. package/dist/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Regular.woff2 +0 -0
  135. package/dist/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-SemiBold.woff2 +0 -0
  136. package/dist/design-tokens/brands/cre8-vivid/css/fonts.css +31 -0
  137. package/dist/design-tokens/brands/cre8-vivid/css/tokens_brand.css +609 -0
  138. package/dist/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.css +248 -0
  139. package/dist/iframe.html +1 -1
  140. package/dist/project.json +1 -1
  141. package/dist/sb-addons/storybook-5/manager-bundle.js +1 -1
  142. package/lib/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Bold.woff2 +0 -0
  143. package/lib/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-LatinExt.woff2 +0 -0
  144. package/lib/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Medium.woff2 +0 -0
  145. package/lib/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-Regular.woff2 +0 -0
  146. package/lib/design-tokens/brands/cre8-vivid/css/assets/fonts/PlusJakartaSans-SemiBold.woff2 +0 -0
  147. package/lib/design-tokens/brands/cre8-vivid/css/fonts.css +31 -0
  148. package/lib/design-tokens/brands/cre8-vivid/css/tokens_brand.css +609 -0
  149. package/lib/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.css +248 -0
  150. package/lib/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.module.d.ts +3 -0
  151. package/lib/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.module.d.ts.map +1 -0
  152. package/lib/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.module.js +890 -0
  153. package/lib/design-tokens/brands/cre8-vivid/css/tokens_cre8-vivid.module.js.map +1 -0
  154. package/lib/scripts/generate-mcp-manifest.js +1 -0
  155. package/lib/scripts/generate-mcp-manifest.js.map +1 -1
  156. package/mcp-manifest.json +21 -21
  157. package/package.json +2 -1
  158. package/react-manifest.json +19 -19
  159. package/dist/assets/if-defined-CxQseQbA.js +0 -1
  160. package/dist/assets/state-XoJdIlqR.js +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "contractVersion": 1,
3
- "sourceCatalog": "https://cre8.dev/a2ui/catalogs/cre8-wc/2.2.2",
4
- "libraryVersion": "2.2.2",
3
+ "sourceCatalog": "https://cre8.dev/a2ui/catalogs/cre8-wc/2.3.1",
4
+ "libraryVersion": "2.3.1",
5
5
  "componentCount": 86,
6
6
  "components": [
7
7
  {
@@ -1662,7 +1662,7 @@
1662
1662
  },
1663
1663
  {
1664
1664
  "name": "cre8-progress-steps",
1665
- "category": "Other",
1665
+ "category": "Feedback",
1666
1666
  "props": {
1667
1667
  "steps": {
1668
1668
  "type": "array"
package/a2ui/catalog.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://cre8.dev/a2ui/catalogs/cre8-wc/2.2.2",
3
+ "$id": "https://cre8.dev/a2ui/catalogs/cre8-wc/2.3.1",
4
4
  "title": "cre8-wc A2UI Catalog",
5
5
  "description": "cre8 Web Components is a library of presentational UI web components to be consumed by # web applications.",
6
6
  "x-native-events": [
@@ -54,7 +54,7 @@
54
54
  "x-a2ui": {
55
55
  "catalogId": "cre8-wc",
56
56
  "library": "@tmorrow/cre8-wc",
57
- "libraryVersion": "2.2.2",
57
+ "libraryVersion": "2.3.1",
58
58
  "tagPrefix": "cre8",
59
59
  "framework": "Lit 3.3.1"
60
60
  },
@@ -167,6 +167,9 @@
167
167
  {
168
168
  "$ref": "#/$defs/components/cre8-progress-meter"
169
169
  },
170
+ {
171
+ "$ref": "#/$defs/components/cre8-progress-steps"
172
+ },
170
173
  {
171
174
  "$ref": "#/$defs/components/cre8-progress-steps-item"
172
175
  },
@@ -317,9 +320,6 @@
317
320
  {
318
321
  "$ref": "#/$defs/components/cre8-utility-nav-item"
319
322
  },
320
- {
321
- "$ref": "#/$defs/components/cre8-progress-steps"
322
- },
323
323
  {
324
324
  "$ref": "#/$defs/components/cre8-heading"
325
325
  },
@@ -3291,6 +3291,74 @@
3291
3291
  },
3292
3292
  "additionalProperties": false
3293
3293
  },
3294
+ "cre8-progress-steps": {
3295
+ "type": "object",
3296
+ "title": "cre8-progress-steps",
3297
+ "x-category": "Feedback",
3298
+ "description": "The Progress Steps component is used to display where a user is in a multistep process.\nIt clearly indicates the total number of steps, which steps are complete and incomplete,\nand which step you’re currently on. They help users estimate how long a task will take and can be\nused to track status on orders.\n\nThe Progress Steps component should be used as a parent component for `cre8-progress-steps-item` components.\nThese Components serve a contextual purpose and don't provide any functionality.\n\n# How to Use\n\nProgress Steps is used when there is ample horizontal space and two to six steps. It displays each step by name\nand number to help users understand exactly where they are in a process. It is the preferred option for desktop.\nProgress Steps should change to Compact Steps on mobile web to conserve space.\n\nProgress Steps can also be used to track order status. It provides a quick visual of how an order is progressing\nwith options to alert users of any problems along the way. When used for order status, Progress Steps should\nchange to Vertical Steps on mobile web to conserve space while allowing alerts and messages to remain visible.",
3299
+ "required": [
3300
+ "component"
3301
+ ],
3302
+ "properties": {
3303
+ "component": {
3304
+ "const": "cre8-progress-steps",
3305
+ "description": "Component tag name"
3306
+ },
3307
+ "props": {
3308
+ "type": "object",
3309
+ "additionalProperties": false,
3310
+ "properties": {
3311
+ "steps": {
3312
+ "type": "array",
3313
+ "items": {
3314
+ "type": "object",
3315
+ "properties": {
3316
+ "name": {
3317
+ "type": "string"
3318
+ },
3319
+ "message": {
3320
+ "type": "string"
3321
+ },
3322
+ "state": {
3323
+ "type": "string",
3324
+ "enum": [
3325
+ "error",
3326
+ "warning",
3327
+ "complete",
3328
+ "current"
3329
+ ]
3330
+ }
3331
+ },
3332
+ "required": [
3333
+ "name"
3334
+ ],
3335
+ "additionalProperties": false
3336
+ },
3337
+ "description": "Steps for a data-driven progress indicator. Note that the visible label is\neach item's `name` prop rather than its content — `cre8-progress-steps-item`\ndoes not render children, which is easy to get wrong by hand.",
3338
+ "x-kind": "attribute"
3339
+ }
3340
+ }
3341
+ },
3342
+ "children": {
3343
+ "type": "array",
3344
+ "description": "The Progress Steps Item components that represent the steps in the multistep process.",
3345
+ "items": {
3346
+ "$ref": "#/$defs/Child"
3347
+ }
3348
+ },
3349
+ "events": {
3350
+ "type": "object",
3351
+ "description": "Event bindings. Each key is an event name; the value names the handler to emit.",
3352
+ "propertyNames": {
3353
+ "$ref": "#/$defs/NativeEventName"
3354
+ },
3355
+ "additionalProperties": {
3356
+ "$ref": "#/$defs/EventBinding"
3357
+ }
3358
+ }
3359
+ },
3360
+ "additionalProperties": false
3361
+ },
3294
3362
  "cre8-progress-steps-item": {
3295
3363
  "type": "object",
3296
3364
  "title": "cre8-progress-steps-item",
@@ -7402,74 +7470,6 @@
7402
7470
  },
7403
7471
  "additionalProperties": false
7404
7472
  },
7405
- "cre8-progress-steps": {
7406
- "type": "object",
7407
- "title": "cre8-progress-steps",
7408
- "x-category": "Other",
7409
- "description": "The Progress Steps component is used to display where a user is in a multistep process.\nIt clearly indicates the total number of steps, which steps are complete and incomplete,\nand which step you’re currently on. They help users estimate how long a task will take and can be\nused to track status on orders.\n\nThe Progress Steps component should be used as a parent component for `cre8-progress-steps-item` components.\nThese Components serve a contextual purpose and don't provide any functionality.\n\n# How to Use\n\nProgress Steps is used when there is ample horizontal space and two to six steps. It displays each step by name\nand number to help users understand exactly where they are in a process. It is the preferred option for desktop.\nProgress Steps should change to Compact Steps on mobile web to conserve space.\n\nProgress Steps can also be used to track order status. It provides a quick visual of how an order is progressing\nwith options to alert users of any problems along the way. When used for order status, Progress Steps should\nchange to Vertical Steps on mobile web to conserve space while allowing alerts and messages to remain visible.",
7410
- "required": [
7411
- "component"
7412
- ],
7413
- "properties": {
7414
- "component": {
7415
- "const": "cre8-progress-steps",
7416
- "description": "Component tag name"
7417
- },
7418
- "props": {
7419
- "type": "object",
7420
- "additionalProperties": false,
7421
- "properties": {
7422
- "steps": {
7423
- "type": "array",
7424
- "items": {
7425
- "type": "object",
7426
- "properties": {
7427
- "name": {
7428
- "type": "string"
7429
- },
7430
- "message": {
7431
- "type": "string"
7432
- },
7433
- "state": {
7434
- "type": "string",
7435
- "enum": [
7436
- "error",
7437
- "warning",
7438
- "complete",
7439
- "current"
7440
- ]
7441
- }
7442
- },
7443
- "required": [
7444
- "name"
7445
- ],
7446
- "additionalProperties": false
7447
- },
7448
- "description": "Steps for a data-driven progress indicator. Note that the visible label is\neach item's `name` prop rather than its content — `cre8-progress-steps-item`\ndoes not render children, which is easy to get wrong by hand.",
7449
- "x-kind": "attribute"
7450
- }
7451
- }
7452
- },
7453
- "children": {
7454
- "type": "array",
7455
- "description": "The Progress Steps Item components that represent the steps in the multistep process.",
7456
- "items": {
7457
- "$ref": "#/$defs/Child"
7458
- }
7459
- },
7460
- "events": {
7461
- "type": "object",
7462
- "description": "Event bindings. Each key is an event name; the value names the handler to emit.",
7463
- "propertyNames": {
7464
- "$ref": "#/$defs/NativeEventName"
7465
- },
7466
- "additionalProperties": {
7467
- "$ref": "#/$defs/EventBinding"
7468
- }
7469
- }
7470
- },
7471
- "additionalProperties": false
7472
- },
7473
7473
  "cre8-heading": {
7474
7474
  "type": "object",
7475
7475
  "title": "cre8-heading",
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deployment-drift check for the knowledge graph.
4
+ *
5
+ * Generation keeps catalog-kg.json honest with the library it was built from.
6
+ * It does nothing about a copy of that file that was deployed and then left
7
+ * behind — which is how the Claude plugin served 1.0.27 (via the unscoped
8
+ * `cre8-mcp` package) while the checkout was on 2.3.x. This script compares the local graph against every other place
9
+ * one is served from and exits non-zero if any of them differ.
10
+ *
11
+ * Targets, each optional:
12
+ * --url <base> a running cre8-mcp API (a Vercel deployment, a local
13
+ * dev server).
14
+ * Fetches <base>/a2ui/runtime/catalog-kg.json.
15
+ * Repeatable. Also read from CRE8_MCP_URLS (comma-separated).
16
+ * --file <path> another checkout or bundle's catalog-kg.json
17
+ * (a plugin's vendored copy, an npm tarball). Repeatable.
18
+ * --npm [<version>] the published @tmorrow/cre8-wc package (latest by
19
+ * default) — what anyone installing the connector gets.
20
+ * --plugin <.mcp.json> a Claude plugin's server config. Resolves the npm
21
+ * package its `npx` line runs, then checks the
22
+ * @tmorrow/cre8-wc that package depends on. This is
23
+ * the surface that drifted furthest: the plugin ran
24
+ * the unscoped `cre8-mcp` (0.5.0, Feb 2026), which
25
+ * bundles its own 1.0.27 manifest and depends on no
26
+ * design-system package at all.
27
+ *
28
+ * pnpm --filter @tmorrow/cre8-wc check:deploy-drift -- --npm --plugin .claude/marketplaces/tmorrow_ai/cre8/.mcp.json
29
+ */
30
+ import { createHash } from 'node:crypto';
31
+ import { readFileSync, mkdtempSync, rmSync } from 'node:fs';
32
+ import { tmpdir } from 'node:os';
33
+ import { dirname, join, resolve } from 'node:path';
34
+ import { execSync } from 'node:child_process';
35
+ import { fileURLToPath } from 'node:url';
36
+
37
+ const __dirname = dirname(fileURLToPath(import.meta.url));
38
+ const localPath = resolve(__dirname, 'catalog-kg.json');
39
+
40
+ const args = process.argv.slice(2);
41
+ const urls = (process.env.CRE8_MCP_URLS ?? '').split(',').map((s) => s.trim()).filter(Boolean);
42
+ const files = [];
43
+ const plugins = [];
44
+ let npm = null;
45
+ for (let i = 0; i < args.length; i++) {
46
+ if (args[i] === '--url') urls.push(args[++i]);
47
+ else if (args[i] === '--file') files.push(args[++i]);
48
+ else if (args[i] === '--plugin') plugins.push(args[++i]);
49
+ else if (args[i] === '--npm') npm = args[i + 1] && !args[i + 1].startsWith('--') ? args[++i] : 'latest';
50
+ else { console.error(`unknown argument ${args[i]}`); process.exit(2); }
51
+ }
52
+ if (!urls.length && !files.length && !npm && !plugins.length) {
53
+ console.error('nothing to compare against: pass --url, --file or --npm (or set CRE8_MCP_URLS)');
54
+ process.exit(2);
55
+ }
56
+
57
+ const fingerprint = (kg) => ({
58
+ library_version: kg.meta?.library_version ?? null,
59
+ components: kg.nodes?.filter((n) => n.type === 'component').length ?? 0,
60
+ categories: kg.nodes?.filter((n) => n.type === 'category').length ?? 0,
61
+ contains_edges: kg.meta?.contains_edges ?? kg.edges?.filter((e) => e.rel === 'CONTAINS').length ?? 0,
62
+ patterns: kg.nodes?.filter((n) => n.type === 'pattern').length ?? 0,
63
+ sha256: createHash('sha256').update(JSON.stringify({ nodes: kg.nodes, edges: kg.edges })).digest('hex').slice(0, 12),
64
+ });
65
+
66
+ const local = fingerprint(JSON.parse(readFileSync(localPath, 'utf8')));
67
+ const targets = [];
68
+
69
+ for (const url of urls) {
70
+ const endpoint = `${url.replace(/\/$/, '')}/a2ui/runtime/catalog-kg.json`;
71
+ try {
72
+ const res = await fetch(endpoint);
73
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
74
+ targets.push({ name: endpoint, fp: fingerprint(await res.json()) });
75
+ } catch (err) {
76
+ targets.push({ name: endpoint, error: err?.message ?? String(err) });
77
+ }
78
+ }
79
+ for (const file of files) {
80
+ try {
81
+ targets.push({ name: file, fp: fingerprint(JSON.parse(readFileSync(resolve(file), 'utf8'))) });
82
+ } catch (err) {
83
+ targets.push({ name: file, error: err?.message ?? String(err) });
84
+ }
85
+ }
86
+ /** The catalog-kg.json inside a published @tmorrow/cre8-wc, or an error. */
87
+ function fromNpm(spec) {
88
+ const dir = mkdtempSync(join(tmpdir(), 'cre8-kg-'));
89
+ try {
90
+ const tgz = execSync(`npm pack ${spec} --pack-destination ${dir} --silent`, { encoding: 'utf8' }).trim().split('\n').pop();
91
+ execSync(`tar -xzf ${join(dir, tgz)} -C ${dir} package/a2ui/catalog-kg.json`);
92
+ return { fp: fingerprint(JSON.parse(readFileSync(join(dir, 'package', 'a2ui', 'catalog-kg.json'), 'utf8'))) };
93
+ } catch (err) {
94
+ return { error: `no catalog-kg.json in the published package (${err?.message?.split('\n')[0] ?? err})` };
95
+ } finally {
96
+ rmSync(dir, { recursive: true, force: true });
97
+ }
98
+ }
99
+
100
+ if (npm) {
101
+ const name = `@tmorrow/cre8-wc@${npm}`;
102
+ targets.push({ name, ...fromNpm(name) });
103
+ }
104
+
105
+ for (const file of plugins) {
106
+ let label = file;
107
+ try {
108
+ const cfg = JSON.parse(readFileSync(resolve(file), 'utf8'));
109
+ const servers = Object.values(cfg.mcpServers ?? {});
110
+ const server = servers.find((s) => s.command === 'npx') ?? servers[0];
111
+ const pkg = (server?.args ?? []).find((a) => !a.startsWith('-'));
112
+ if (!pkg) throw new Error('no npx package in mcpServers');
113
+ label = `plugin → ${pkg}`;
114
+ const view = JSON.parse(execSync(`npm view ${pkg} version dependencies --json`, { encoding: 'utf8' }));
115
+ const wcRange = view.dependencies?.['@tmorrow/cre8-wc'];
116
+ if (!wcRange) {
117
+ targets.push({ name: `${label}@${view.version}`, error: 'does not depend on @tmorrow/cre8-wc — it bundles its own catalog and can never be graph-backed' });
118
+ continue;
119
+ }
120
+ const wcVersion = JSON.parse(execSync(`npm view "@tmorrow/cre8-wc@${wcRange}" version --json`, { encoding: 'utf8' }));
121
+ const resolved = Array.isArray(wcVersion) ? wcVersion.at(-1) : wcVersion;
122
+ targets.push({ name: `${label}@${view.version} (wc ${resolved})`, ...fromNpm(`@tmorrow/cre8-wc@${resolved}`) });
123
+ } catch (err) {
124
+ targets.push({ name: label, error: err?.message?.split('\n')[0] ?? String(err) });
125
+ }
126
+ }
127
+
128
+ const keys = Object.keys(local);
129
+ const pad = (s, n) => String(s).padEnd(n);
130
+ console.log(pad('', 34) + keys.map((k) => pad(k, 17)).join(''));
131
+ console.log(pad('local checkout', 34) + keys.map((k) => pad(local[k], 17)).join(''));
132
+ let drifted = 0;
133
+ for (const t of targets) {
134
+ if (t.error) {
135
+ drifted++;
136
+ console.log(`${pad(t.name.slice(0, 33), 34)}DRIFTED: ${t.error}`);
137
+ continue;
138
+ }
139
+ const same = t.fp.sha256 === local.sha256;
140
+ if (!same) drifted++;
141
+ console.log(pad(t.name.slice(0, 33), 34) + keys.map((k) => pad(t.fp[k] === local[k] ? t.fp[k] : `${t.fp[k]} !!`, 17)).join(''));
142
+ }
143
+ if (drifted) {
144
+ console.error(`\n${drifted} deployment(s) do not serve the graph this checkout builds. Redeploy them with the library.`);
145
+ process.exit(1);
146
+ }
147
+ console.log('\nall deployments serve the same knowledge graph as this checkout');
@@ -1,31 +1,61 @@
1
1
  /**
2
- * Generates catalog-kg.json - the knowledge-graph projection of the a2ui
3
- * catalog that cre8-mcp's KG-backed handlers serve.
2
+ * Generates catalog-kg.json the knowledge graph cre8-mcp serves.
4
3
  *
5
- * Deterministic: same catalog.json in, same graph out. Runs after
6
- * generate-catalog.mjs (which derives catalog.json from mcp-manifest.json),
7
- * so `build:a2ui` keeps manifest -> catalog -> catalog-kg aligned.
4
+ * This is the single source of truth for everything cre8-mcp says about
5
+ * *relationships* between components. The catalog (catalog.json) says what
6
+ * each component accepts; this graph says what goes where, and why it is
7
+ * believed. Every tool that answers a structural question — get_composition,
8
+ * get_content_model, get_patterns, list_components — reads this file, and so
9
+ * does the eval oracle (evals/cre8-a2ui-vs-mcp/oracle/build_oracle.py). One
10
+ * regeneration refreshes all of them; nothing downstream re-derives.
8
11
  *
9
- * Graph shape (consumed by packages/cre8-mcp/src/handlers.ts and
10
- * surface-routes.ts):
11
- * nodes: category (cat:<Name>), component (<tag>), slot (slot:<tag>:<name>),
12
- * enum_prop (prop:<tag>:<prop>)
13
- * edges: BELONGS_TO, HAS_SLOT, HAS_ENUM_PROP
12
+ * Deterministic: same inputs in, same graph out. Runs after
13
+ * generate-catalog.mjs, so `build:a2ui` keeps manifest -> catalog -> kg aligned.
14
+ *
15
+ * Nodes
16
+ * category cat:<Name>
17
+ * component <tag> props, slots, accepts_children, category,
18
+ * exemplar (smallest authored A2UI subtree)
19
+ * slot slot:<tag>:<name>
20
+ * enum_prop prop:<tag>:<prop>
21
+ * pattern pattern:<slug> name, description, spec (authored A2UI, validated)
22
+ *
23
+ * Edges
24
+ * BELONGS_TO component -> category
25
+ * HAS_SLOT component -> slot
26
+ * HAS_ENUM_PROP component -> enum_prop
27
+ * CONTAINS parent -> child { slot, count, evidence:[{kind,file}] }
28
+ * Only ever from observed artifacts (stories, component
29
+ * render templates, a2ui examples, a2ui patterns) — never
30
+ * from the naming rule. See kg-sources.mjs for the readers.
31
+ * USED_IN_PATTERN component -> pattern
32
+ * IN_FAMILY component <-> component sharing a name prefix. Undirected
33
+ * on purpose: cre8-tag-list contains cre8-tag, and the names
34
+ * do not say so.
35
+ * EXTENDS component -> base class (from graphify: Cre8FormElement …)
36
+ * IMPORTS component -> component, module-level (from graphify)
14
37
  */
15
38
  import { readFileSync, writeFileSync } from 'node:fs';
16
39
  import { fileURLToPath } from 'node:url';
17
40
  import { dirname, resolve } from 'node:path';
41
+ import { newContainment, scanComponentsDir, scanExamples, scanGraphify, scanPatterns } from './kg-sources.mjs';
42
+ import { registerCatalog, validateSpec } from './index.js';
18
43
 
19
44
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
45
 
21
46
  const catalogPath = resolve(__dirname, 'catalog.json');
22
47
  const pkgPath = resolve(__dirname, '..', 'package.json');
23
48
  const outPath = resolve(__dirname, 'catalog-kg.json');
49
+ const componentsDir = resolve(__dirname, '..', 'components');
50
+ const examplesDir = resolve(__dirname, 'examples');
51
+ const patternsDir = resolve(__dirname, 'patterns');
52
+ const graphifyPath = process.env.CRE8_GRAPHIFY ?? resolve(__dirname, '..', '..', '..', 'graphify-out', 'graph.json');
24
53
 
25
54
  const catalog = JSON.parse(readFileSync(catalogPath, 'utf8'));
26
55
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
27
56
 
28
57
  const components = catalog.$defs?.components ?? {};
58
+ const knownTags = new Set(Object.keys(components));
29
59
 
30
60
  /** Collapses whitespace/newlines and truncates with an ellipsis. */
31
61
  const summarize = (text, max) => {
@@ -34,21 +64,38 @@ const summarize = (text, max) => {
34
64
  return flat.length > max ? `${flat.slice(0, max)}…` : flat;
35
65
  };
36
66
 
67
+ // ─── evidence ───────────────────────────────────────────────────────────────
68
+
69
+ const stories = newContainment();
70
+ const sources = newContainment();
71
+ const scanned = scanComponentsDir(componentsDir, { stories, sources });
72
+ const examples = scanExamples(examplesDir);
73
+ const patternSet = scanPatterns(patternsDir);
74
+ const graphify = scanGraphify(graphifyPath, knownTags);
75
+
37
76
  const nodes = [];
38
77
  const edges = [];
39
78
 
40
- // Category nodes, alphabetical. Components without x-category land in Other.
79
+ // ─── categories ─────────────────────────────────────────────────────────────
80
+
81
+ // A component's category comes from the manifest's x-category. A component
82
+ // with none is not silently filed under "Other" any more: it is reported at
83
+ // the end and the build fails, because "Other" is exactly the kind of
84
+ // hand-maintained metadata this graph exists to stop drifting.
85
+ const uncategorized = [];
41
86
  const categories = new Set();
42
- for (const def of Object.values(components)) {
43
- categories.add(def['x-category'] || 'Other');
87
+ for (const [tag, def] of Object.entries(components)) {
88
+ if (!def['x-category'] || def['x-category'] === 'Other') uncategorized.push(tag);
89
+ else categories.add(def['x-category']);
44
90
  }
45
91
  for (const label of [...categories].sort()) {
46
92
  nodes.push({ id: `cat:${label}`, type: 'category', label });
47
93
  }
48
94
 
49
- // Component, slot, and enum-prop nodes in catalog order.
95
+ // ─── components, slots, enum props ──────────────────────────────────────────
96
+
50
97
  for (const [tag, def] of Object.entries(components)) {
51
- const category = def['x-category'] || 'Other';
98
+ const category = def['x-category'] ?? null;
52
99
  const propDefs = def.properties?.props?.properties ?? {};
53
100
  const slotNames = Object.keys(def.properties?.slots?.properties ?? {});
54
101
  const slotDescriptions = def['x-slot-descriptions'] ?? {};
@@ -64,6 +111,7 @@ for (const [tag, def] of Object.entries(components)) {
64
111
  };
65
112
  }
66
113
 
114
+ const ex = examples.exemplar.get(tag);
67
115
  nodes.push({
68
116
  id: tag,
69
117
  type: 'component',
@@ -72,8 +120,10 @@ for (const [tag, def] of Object.entries(components)) {
72
120
  props,
73
121
  slots: slotNames,
74
122
  accepts_children: Boolean(def.properties?.children),
123
+ extends: graphify.extends.get(tag) ?? null,
124
+ exemplar: ex ? { source: ex.source, path: ex.path, spec: ex.spec } : null,
75
125
  });
76
- edges.push({ from: tag, to: `cat:${category}`, rel: 'BELONGS_TO' });
126
+ if (category) edges.push({ from: tag, to: `cat:${category}`, rel: 'BELONGS_TO' });
77
127
 
78
128
  for (const slotName of slotNames) {
79
129
  const id = `slot:${tag}:${slotName}`;
@@ -102,14 +152,125 @@ for (const [tag, def] of Object.entries(components)) {
102
152
  }
103
153
  }
104
154
 
155
+ // ─── CONTAINS: merged evidence ──────────────────────────────────────────────
156
+
157
+ /**
158
+ * HTML and A2UI name the same position differently: unslotted markup is
159
+ * `children` in HTML, but for a component whose content model is slots the
160
+ * spec calls it `slots.default`. The graph speaks A2UI, because that is what
161
+ * the tools emit and validate — so the catalog's content model for the parent
162
+ * decides, and a story's unslotted child lands in `default` on a slotted
163
+ * component and in `children` (null) on a children component.
164
+ */
165
+ const a2uiSlot = (parent, slot) => {
166
+ const def = components[parent];
167
+ const takesChildren = Boolean(def?.properties?.children);
168
+ const slotNames = Object.keys(def?.properties?.slots?.properties ?? {});
169
+ if (slot == null) return takesChildren || !slotNames.includes('default') ? null : 'default';
170
+ if (slot === 'default' && takesChildren) return null;
171
+ return slot;
172
+ };
173
+
174
+ /** key "parent|slot|child" -> { count, evidence: Map<kind, Set<file>> } */
175
+ const contains = new Map();
176
+ const merge = (kind, containment) => {
177
+ for (const [parent, bySlot] of containment) {
178
+ if (!knownTags.has(parent)) continue;
179
+ for (const [rawSlot, byChild] of bySlot) {
180
+ const slot = a2uiSlot(parent, rawSlot);
181
+ for (const [child, rec] of byChild) {
182
+ if (!knownTags.has(child)) continue; // cre8-icon-legacy and friends are not in the catalog
183
+ const key = `${parent}|${slot ?? ''}|${child}`;
184
+ const e = contains.get(key) ?? { parent, slot, child, count: 0, evidence: new Map() };
185
+ e.count += rec.count;
186
+ const files = e.evidence.get(kind) ?? new Set();
187
+ for (const f of rec.files) files.add(f);
188
+ e.evidence.set(kind, files);
189
+ contains.set(key, e);
190
+ }
191
+ }
192
+ }
193
+ };
194
+ merge('source', sources);
195
+ merge('story', stories);
196
+ merge('example', examples.containment);
197
+ merge('pattern', patternSet.containment);
198
+
199
+ const containsEdges = [...contains.values()]
200
+ .sort((a, b) => a.parent.localeCompare(b.parent) || (a.slot ?? '').localeCompare(b.slot ?? '') || a.child.localeCompare(b.child))
201
+ .map((e) => ({
202
+ from: e.parent,
203
+ to: e.child,
204
+ rel: 'CONTAINS',
205
+ slot: e.slot,
206
+ count: e.count,
207
+ evidence: [...e.evidence].flatMap(([kind, files]) => [...files].sort().map((file) => ({ kind, file }))),
208
+ }));
209
+ edges.push(...containsEdges);
210
+
211
+ // ─── patterns ───────────────────────────────────────────────────────────────
212
+
213
+ // A pattern is an authored spec, so it is held to the same bar as anything an
214
+ // agent would emit: it must validate against the catalog it ships with.
215
+ const registered = registerCatalog(catalog);
216
+ const invalidPatterns = [];
217
+ for (const p of patternSet.patterns) {
218
+ try {
219
+ validateSpec(p.spec, registered);
220
+ } catch (err) {
221
+ invalidPatterns.push(`${p.source}: ${err?.message ?? err}`);
222
+ continue;
223
+ }
224
+ nodes.push({
225
+ id: `pattern:${p.slug}`,
226
+ type: 'pattern',
227
+ name: p.name,
228
+ description: p.description,
229
+ source: p.source,
230
+ spec: p.spec,
231
+ components: p.components,
232
+ });
233
+ for (const tag of p.components) edges.push({ from: tag, to: `pattern:${p.slug}`, rel: 'USED_IN_PATTERN' });
234
+ }
235
+
236
+ // ─── IN_FAMILY ──────────────────────────────────────────────────────────────
237
+
238
+ const tags = [...knownTags].sort();
239
+ for (const a of tags) {
240
+ for (const b of tags) {
241
+ if (a < b && (b.startsWith(`${a}-`) || a.startsWith(`${b}-`))) {
242
+ edges.push({ from: a, to: b, rel: 'IN_FAMILY' });
243
+ }
244
+ }
245
+ }
246
+
247
+ // ─── EXTENDS / IMPORTS ──────────────────────────────────────────────────────
248
+
249
+ for (const [tag, base] of [...graphify.extends].sort()) {
250
+ edges.push({ from: tag, to: `class:${base}`, rel: 'EXTENDS' });
251
+ }
252
+ for (const [from, set] of [...graphify.imports].sort()) {
253
+ for (const to of [...set].sort()) edges.push({ from, to, rel: 'IMPORTS' });
254
+ }
255
+
256
+ // ─── write ──────────────────────────────────────────────────────────────────
257
+
105
258
  const kg = {
106
259
  meta: {
107
- generated_from: 'catalog.json',
260
+ generated_from: ['catalog.json', 'components/*/*.stories.ts', 'components/*/*.ts', 'a2ui/examples/*.json', 'a2ui/patterns/*.json', graphify.found ? 'graphify-out/graph.json' : null].filter(Boolean),
108
261
  catalog_id: 'cre8-wc',
109
262
  library: pkg.name,
110
263
  library_version: pkg.version,
264
+ graphify_commit: graphify.commit,
265
+ evidence: {
266
+ story_files: scanned.storyFiles,
267
+ source_files: scanned.sourceFiles,
268
+ example_files: examples.files,
269
+ pattern_files: patternSet.patterns.map((p) => p.source.replace('a2ui/patterns/', '')),
270
+ },
111
271
  total_nodes: nodes.length,
112
272
  total_edges: edges.length,
273
+ contains_edges: containsEdges.length,
113
274
  },
114
275
  nodes,
115
276
  edges,
@@ -118,5 +279,20 @@ const kg = {
118
279
  writeFileSync(outPath, `${JSON.stringify(kg, null, 2)}\n`, 'utf8');
119
280
  console.log(
120
281
  `catalog-kg.json: ${nodes.length} nodes, ${edges.length} edges `
121
- + `(${Object.keys(components).length} components, ${categories.size} categories)`,
282
+ + `(${knownTags.size} components, ${categories.size} categories, `
283
+ + `${containsEdges.length} CONTAINS from ${scanned.storyFiles} stories + ${scanned.sourceFiles} sources + ${examples.files.length} examples + ${patternSet.patterns.length} patterns`
284
+ + `${graphify.found ? `, graphify@${(graphify.commit ?? '').slice(0, 7)}` : ', no graphify graph'})`,
122
285
  );
286
+
287
+ if (invalidPatterns.length) {
288
+ console.error(`\ncatalog-kg: ${invalidPatterns.length} pattern(s) do not validate against the catalog:\n ${invalidPatterns.join('\n ')}`);
289
+ process.exit(1);
290
+ }
291
+
292
+ if (uncategorized.length) {
293
+ console.error(
294
+ `\ncatalog-kg: ${uncategorized.length} component(s) have no category: ${uncategorized.join(', ')}\n`
295
+ + 'Add them to CATEGORY_MAP in scripts/generate-mcp-manifest.ts — "Other" is not a category.',
296
+ );
297
+ process.exit(1);
298
+ }