@utopia-studio-design/design-system-cli 0.8.0 → 0.8.1

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 (240) hide show
  1. package/bin/utopia-ds-mcp.mjs +5 -15
  2. package/bin/utopia-ds.mjs +3 -16
  3. package/data/docs/create-a-brandbook.md +11 -1
  4. package/data/manifests/blocks.json +21 -230
  5. package/data/manifests/patterns.json +0 -330
  6. package/lib/api.mjs +6 -193
  7. package/lib/brandbook-validation.mjs +112 -0
  8. package/package.json +2 -2
  9. package/data/blocks/semantic-pattern-parts/AuthParts.tsx +0 -48
  10. package/data/blocks/semantic-pattern-parts/ChoiceCards.tsx +0 -7
  11. package/data/blocks/semantic-pattern-parts/ListFilters.tsx +0 -9
  12. package/data/blocks/semantic-pattern-parts/OutcomeNotice.tsx +0 -7
  13. package/data/blocks/semantic-pattern-parts/PatternParts.tsx +0 -7
  14. package/data/blocks/semantic-pattern-parts/ProductParts.tsx +0 -38
  15. package/data/blocks/semantic-pattern-parts/ProgressSteps.tsx +0 -6
  16. package/data/blocks/semantic-pattern-parts/ReviewList.tsx +0 -7
  17. package/data/blocks/semantic-pattern-parts/ValidatedField.tsx +0 -8
  18. package/data/blocks/semantic-pattern-parts/WorkflowParts.tsx +0 -339
  19. package/data/blocks/semantic-pattern-parts/auth-parts.css +0 -27
  20. package/data/blocks/semantic-pattern-parts/pattern-parts.css +0 -25
  21. package/data/blocks/semantic-pattern-parts/product-parts.css +0 -25
  22. package/data/blocks/semantic-pattern-parts/types.ts +0 -3
  23. package/data/blocks/semantic-pattern-parts/workflow-parts.css +0 -118
  24. package/data/blocks/ux-pattern-examples/AccessExamples.tsx +0 -46
  25. package/data/blocks/ux-pattern-examples/AccountExamples.tsx +0 -133
  26. package/data/blocks/ux-pattern-examples/OnboardingExample.tsx +0 -15
  27. package/data/blocks/ux-pattern-examples/ProductExamples.tsx +0 -79
  28. package/data/blocks/ux-pattern-examples/ReviewExample.tsx +0 -14
  29. package/data/blocks/ux-pattern-examples/SignupExample.tsx +0 -22
  30. package/data/blocks/ux-pattern-examples/WorkflowExample.tsx +0 -1761
  31. package/data/blocks/ux-pattern-examples/WorkflowExamples.tsx +0 -190
  32. package/data/blocks/ux-pattern-examples/copy.ts +0 -6
  33. package/data/blocks/ux-pattern-examples/ux-examples.css +0 -18
  34. package/data/blocks/ux-pattern-examples/workflow-copy.ts +0 -76
  35. package/data/blocks/ux-pattern-examples/workflow-definitions.ts +0 -1291
  36. package/data/docs/ui-parts-qa.md +0 -172
  37. package/data/docs/ui-parts.md +0 -105
  38. package/data/docs/ux-pattern-adaptation-qa.md +0 -38
  39. package/data/docs/ux-pattern-adaptation.md +0 -41
  40. package/data/docs/ux-pattern-migration.md +0 -111
  41. package/data/docs/ux-pattern-release-2026-09-13.md +0 -26
  42. package/data/docs/ux-source-evidence/account-auth.json +0 -41
  43. package/data/docs/ux-source-evidence/account-forgot-password.json +0 -36
  44. package/data/docs/ux-source-evidence/account-invite.json +0 -63
  45. package/data/docs/ux-source-evidence/account-locked.json +0 -63
  46. package/data/docs/ux-source-evidence/account-login.json +0 -28
  47. package/data/docs/ux-source-evidence/account-mfa.json +0 -62
  48. package/data/docs/ux-source-evidence/account-onboarding-credentials.json +0 -52
  49. package/data/docs/ux-source-evidence/account-onboarding-legal.json +0 -56
  50. package/data/docs/ux-source-evidence/account-onboarding-orientation.json +0 -66
  51. package/data/docs/ux-source-evidence/account-onboarding-profile.json +0 -50
  52. package/data/docs/ux-source-evidence/account-onboarding.json +0 -69
  53. package/data/docs/ux-source-evidence/account-reset-password.json +0 -27
  54. package/data/docs/ux-source-evidence/account-session-expired.json +0 -62
  55. package/data/docs/ux-source-evidence/account-signup.json +0 -33
  56. package/data/docs/ux-source-evidence/account-verify-email.json +0 -34
  57. package/data/docs/ux-source-evidence/account-welcome.json +0 -41
  58. package/data/docs/ux-source-evidence/admin-analytics.json +0 -54
  59. package/data/docs/ux-source-evidence/admin-audit.json +0 -31
  60. package/data/docs/ux-source-evidence/admin-broadcasts-new.json +0 -36
  61. package/data/docs/ux-source-evidence/admin-broadcasts.json +0 -41
  62. package/data/docs/ux-source-evidence/admin-closures.json +0 -52
  63. package/data/docs/ux-source-evidence/admin-devices.json +0 -51
  64. package/data/docs/ux-source-evidence/admin-escalations.json +0 -35
  65. package/data/docs/ux-source-evidence/admin-incidents.json +0 -54
  66. package/data/docs/ux-source-evidence/admin-loading.json +0 -17
  67. package/data/docs/ux-source-evidence/admin-onboarding-detail.json +0 -80
  68. package/data/docs/ux-source-evidence/admin-onboarding.json +0 -62
  69. package/data/docs/ux-source-evidence/admin-payments.json +0 -45
  70. package/data/docs/ux-source-evidence/admin-providers.json +0 -38
  71. package/data/docs/ux-source-evidence/admin-settings.json +0 -18
  72. package/data/docs/ux-source-evidence/admin-subscriptions-detail-allocate.json +0 -42
  73. package/data/docs/ux-source-evidence/admin-subscriptions-detail.json +0 -48
  74. package/data/docs/ux-source-evidence/admin-subscriptions-new.json +0 -43
  75. package/data/docs/ux-source-evidence/admin-subscriptions.json +0 -41
  76. package/data/docs/ux-source-evidence/admin-transactions.json +0 -41
  77. package/data/docs/ux-source-evidence/error.json +0 -30
  78. package/data/docs/ux-source-evidence/loading.json +0 -19
  79. package/data/docs/ux-source-evidence/marketing-blog.json +0 -48
  80. package/data/docs/ux-source-evidence/marketing-contact.json +0 -36
  81. package/data/docs/ux-source-evidence/marketing.json +0 -64
  82. package/data/docs/ux-source-evidence/not-found.json +0 -28
  83. package/data/docs/ux-source-evidence/portal-loading.json +0 -17
  84. package/data/docs/ux-source-evidence/portal-mentor-messages.json +0 -31
  85. package/data/docs/ux-source-evidence/portal-mentor-profile.json +0 -23
  86. package/data/docs/ux-source-evidence/portal-mentor-requests-detail.json +0 -54
  87. package/data/docs/ux-source-evidence/portal-mentor-sessions-detail-assess.json +0 -42
  88. package/data/docs/ux-source-evidence/portal-mentor-settings.json +0 -18
  89. package/data/docs/ux-source-evidence/portal-mentor.json +0 -38
  90. package/data/docs/ux-source-evidence/portal-sessions-detail-live.json +0 -48
  91. package/data/docs/ux-source-evidence/portal-sponsor-billing.json +0 -28
  92. package/data/docs/ux-source-evidence/portal-sponsor-profile.json +0 -22
  93. package/data/docs/ux-source-evidence/portal-sponsor-sessions.json +0 -28
  94. package/data/docs/ux-source-evidence/portal-sponsor-settings.json +0 -18
  95. package/data/docs/ux-source-evidence/portal-sponsor-trainees.json +0 -36
  96. package/data/docs/ux-source-evidence/portal-sponsor.json +0 -52
  97. package/data/docs/ux-source-evidence/portal-trainee-competency.json +0 -42
  98. package/data/docs/ux-source-evidence/portal-trainee-credits.json +0 -40
  99. package/data/docs/ux-source-evidence/portal-trainee-mentors.json +0 -48
  100. package/data/docs/ux-source-evidence/portal-trainee-messages.json +0 -32
  101. package/data/docs/ux-source-evidence/portal-trainee-notifications.json +0 -35
  102. package/data/docs/ux-source-evidence/portal-trainee-profile.json +0 -26
  103. package/data/docs/ux-source-evidence/portal-trainee-request.json +0 -54
  104. package/data/docs/ux-source-evidence/portal-trainee-sessions-detail-feedback.json +0 -36
  105. package/data/docs/ux-source-evidence/portal-trainee-sessions-detail-precheck.json +0 -42
  106. package/data/docs/ux-source-evidence/portal-trainee-sessions-detail.json +0 -55
  107. package/data/docs/ux-source-evidence/portal-trainee-sessions.json +0 -36
  108. package/data/docs/ux-source-evidence/portal-trainee-settings-notifications.json +0 -38
  109. package/data/docs/ux-source-evidence/portal-trainee-settings.json +0 -18
  110. package/data/docs/ux-source-evidence/portal-trainee.json +0 -44
  111. package/data/docs/ux-source-evidence/portal-tv-detail.json +0 -39
  112. package/data/docs/ux-source-evidence/portal-tv.json +0 -44
  113. package/data/docs/ux-source-evidence/shared-admin-admin-shell.json +0 -35
  114. package/data/docs/ux-source-evidence/shared-auth-auth-primitives.json +0 -105
  115. package/data/docs/ux-source-evidence/shared-auth-auth-shell.json +0 -25
  116. package/data/docs/ux-source-evidence/shared-auth-onboarding-primitives.json +0 -52
  117. package/data/docs/ux-source-evidence/shared-auth-onboarding-shell.json +0 -28
  118. package/data/docs/ux-source-evidence/shared-auth-status-indicator.json +0 -41
  119. package/data/docs/ux-source-evidence/shared-portal-empty-state.json +0 -24
  120. package/data/docs/ux-source-evidence/shared-portal-loading-skeleton.json +0 -27
  121. package/data/docs/ux-source-evidence/shared-portal-notifications-dropdown.json +0 -39
  122. package/data/docs/ux-source-evidence/shared-portal-portal-shell.json +0 -36
  123. package/data/docs/ux-source-evidence/shared-portal-profile-form.json +0 -32
  124. package/data/docs/ux-source-evidence/shared-portal-settings-view.json +0 -81
  125. package/data/docs/ux-source-evidence/shared-portal-usage-sparkline.json +0 -18
  126. package/data/docs/ux-source-evidence/shared-portal-user-menu.json +0 -34
  127. package/data/manifests/ui-patterns.json +0 -1029
  128. package/data/manifests/ux-examples.json +0 -2177
  129. package/data/manifests/ux-patterns.json +0 -1135
  130. package/data/manifests/ux-source-inventory.json +0 -4669
  131. package/data/ui-parts/blocks/analytics-dashboard/AnalyticsMetricBlocks.tsx +0 -87
  132. package/data/ui-parts/blocks/analytics-dashboard/analytics-dashboard.css +0 -92
  133. package/data/ui-parts/blocks/semantic-pattern-parts/AuthParts.tsx +0 -48
  134. package/data/ui-parts/blocks/semantic-pattern-parts/ChoiceCards.tsx +0 -7
  135. package/data/ui-parts/blocks/semantic-pattern-parts/ListFilters.tsx +0 -9
  136. package/data/ui-parts/blocks/semantic-pattern-parts/OutcomeNotice.tsx +0 -7
  137. package/data/ui-parts/blocks/semantic-pattern-parts/ProductParts.tsx +0 -38
  138. package/data/ui-parts/blocks/semantic-pattern-parts/ProgressSteps.tsx +0 -6
  139. package/data/ui-parts/blocks/semantic-pattern-parts/ReviewList.tsx +0 -7
  140. package/data/ui-parts/blocks/semantic-pattern-parts/ValidatedField.tsx +0 -8
  141. package/data/ui-parts/blocks/semantic-pattern-parts/WorkflowParts.tsx +0 -339
  142. package/data/ui-parts/blocks/semantic-pattern-parts/auth-parts.css +0 -27
  143. package/data/ui-parts/blocks/semantic-pattern-parts/pattern-parts.css +0 -25
  144. package/data/ui-parts/blocks/semantic-pattern-parts/product-parts.css +0 -25
  145. package/data/ui-parts/blocks/semantic-pattern-parts/types.ts +0 -3
  146. package/data/ui-parts/blocks/semantic-pattern-parts/workflow-parts.css +0 -118
  147. package/data/ui-parts/blocks/ux-pattern-examples/AccessExamples.tsx +0 -46
  148. package/data/ui-parts/blocks/ux-pattern-examples/AccountExamples.tsx +0 -133
  149. package/data/ui-parts/blocks/ux-pattern-examples/ProductExamples.tsx +0 -79
  150. package/data/ui-parts/blocks/ux-pattern-examples/WorkflowExample.tsx +0 -1761
  151. package/data/ui-parts/blocks/ux-pattern-examples/WorkflowExamples.tsx +0 -190
  152. package/data/ui-parts/blocks/ux-pattern-examples/copy.ts +0 -6
  153. package/data/ui-parts/blocks/ux-pattern-examples/ux-examples.css +0 -18
  154. package/data/ui-parts/blocks/ux-pattern-examples/workflow-copy.ts +0 -76
  155. package/data/ui-parts/blocks/ux-pattern-examples/workflow-definitions.ts +0 -1291
  156. package/data/ux-source-evidence/account-auth.json +0 -41
  157. package/data/ux-source-evidence/account-forgot-password.json +0 -36
  158. package/data/ux-source-evidence/account-invite.json +0 -63
  159. package/data/ux-source-evidence/account-locked.json +0 -63
  160. package/data/ux-source-evidence/account-login.json +0 -28
  161. package/data/ux-source-evidence/account-mfa.json +0 -62
  162. package/data/ux-source-evidence/account-onboarding-credentials.json +0 -52
  163. package/data/ux-source-evidence/account-onboarding-legal.json +0 -56
  164. package/data/ux-source-evidence/account-onboarding-orientation.json +0 -66
  165. package/data/ux-source-evidence/account-onboarding-profile.json +0 -50
  166. package/data/ux-source-evidence/account-onboarding.json +0 -69
  167. package/data/ux-source-evidence/account-reset-password.json +0 -27
  168. package/data/ux-source-evidence/account-session-expired.json +0 -62
  169. package/data/ux-source-evidence/account-signup.json +0 -33
  170. package/data/ux-source-evidence/account-verify-email.json +0 -34
  171. package/data/ux-source-evidence/account-welcome.json +0 -41
  172. package/data/ux-source-evidence/admin-analytics.json +0 -54
  173. package/data/ux-source-evidence/admin-audit.json +0 -31
  174. package/data/ux-source-evidence/admin-broadcasts-new.json +0 -36
  175. package/data/ux-source-evidence/admin-broadcasts.json +0 -41
  176. package/data/ux-source-evidence/admin-closures.json +0 -52
  177. package/data/ux-source-evidence/admin-devices.json +0 -51
  178. package/data/ux-source-evidence/admin-escalations.json +0 -35
  179. package/data/ux-source-evidence/admin-incidents.json +0 -54
  180. package/data/ux-source-evidence/admin-loading.json +0 -17
  181. package/data/ux-source-evidence/admin-onboarding-detail.json +0 -80
  182. package/data/ux-source-evidence/admin-onboarding.json +0 -62
  183. package/data/ux-source-evidence/admin-payments.json +0 -45
  184. package/data/ux-source-evidence/admin-providers.json +0 -38
  185. package/data/ux-source-evidence/admin-settings.json +0 -18
  186. package/data/ux-source-evidence/admin-subscriptions-detail-allocate.json +0 -42
  187. package/data/ux-source-evidence/admin-subscriptions-detail.json +0 -48
  188. package/data/ux-source-evidence/admin-subscriptions-new.json +0 -43
  189. package/data/ux-source-evidence/admin-subscriptions.json +0 -41
  190. package/data/ux-source-evidence/admin-transactions.json +0 -41
  191. package/data/ux-source-evidence/error.json +0 -30
  192. package/data/ux-source-evidence/loading.json +0 -19
  193. package/data/ux-source-evidence/marketing-blog.json +0 -48
  194. package/data/ux-source-evidence/marketing-contact.json +0 -36
  195. package/data/ux-source-evidence/marketing.json +0 -64
  196. package/data/ux-source-evidence/not-found.json +0 -28
  197. package/data/ux-source-evidence/portal-loading.json +0 -17
  198. package/data/ux-source-evidence/portal-mentor-messages.json +0 -31
  199. package/data/ux-source-evidence/portal-mentor-profile.json +0 -23
  200. package/data/ux-source-evidence/portal-mentor-requests-detail.json +0 -54
  201. package/data/ux-source-evidence/portal-mentor-sessions-detail-assess.json +0 -42
  202. package/data/ux-source-evidence/portal-mentor-settings.json +0 -18
  203. package/data/ux-source-evidence/portal-mentor.json +0 -38
  204. package/data/ux-source-evidence/portal-sessions-detail-live.json +0 -48
  205. package/data/ux-source-evidence/portal-sponsor-billing.json +0 -28
  206. package/data/ux-source-evidence/portal-sponsor-profile.json +0 -22
  207. package/data/ux-source-evidence/portal-sponsor-sessions.json +0 -28
  208. package/data/ux-source-evidence/portal-sponsor-settings.json +0 -18
  209. package/data/ux-source-evidence/portal-sponsor-trainees.json +0 -36
  210. package/data/ux-source-evidence/portal-sponsor.json +0 -52
  211. package/data/ux-source-evidence/portal-trainee-competency.json +0 -42
  212. package/data/ux-source-evidence/portal-trainee-credits.json +0 -40
  213. package/data/ux-source-evidence/portal-trainee-mentors.json +0 -48
  214. package/data/ux-source-evidence/portal-trainee-messages.json +0 -32
  215. package/data/ux-source-evidence/portal-trainee-notifications.json +0 -35
  216. package/data/ux-source-evidence/portal-trainee-profile.json +0 -26
  217. package/data/ux-source-evidence/portal-trainee-request.json +0 -54
  218. package/data/ux-source-evidence/portal-trainee-sessions-detail-feedback.json +0 -36
  219. package/data/ux-source-evidence/portal-trainee-sessions-detail-precheck.json +0 -42
  220. package/data/ux-source-evidence/portal-trainee-sessions-detail.json +0 -55
  221. package/data/ux-source-evidence/portal-trainee-sessions.json +0 -36
  222. package/data/ux-source-evidence/portal-trainee-settings-notifications.json +0 -38
  223. package/data/ux-source-evidence/portal-trainee-settings.json +0 -18
  224. package/data/ux-source-evidence/portal-trainee.json +0 -44
  225. package/data/ux-source-evidence/portal-tv-detail.json +0 -39
  226. package/data/ux-source-evidence/portal-tv.json +0 -44
  227. package/data/ux-source-evidence/shared-admin-admin-shell.json +0 -35
  228. package/data/ux-source-evidence/shared-auth-auth-primitives.json +0 -105
  229. package/data/ux-source-evidence/shared-auth-auth-shell.json +0 -25
  230. package/data/ux-source-evidence/shared-auth-onboarding-primitives.json +0 -52
  231. package/data/ux-source-evidence/shared-auth-onboarding-shell.json +0 -28
  232. package/data/ux-source-evidence/shared-auth-status-indicator.json +0 -41
  233. package/data/ux-source-evidence/shared-portal-empty-state.json +0 -24
  234. package/data/ux-source-evidence/shared-portal-loading-skeleton.json +0 -27
  235. package/data/ux-source-evidence/shared-portal-notifications-dropdown.json +0 -39
  236. package/data/ux-source-evidence/shared-portal-portal-shell.json +0 -36
  237. package/data/ux-source-evidence/shared-portal-profile-form.json +0 -32
  238. package/data/ux-source-evidence/shared-portal-settings-view.json +0 -81
  239. package/data/ux-source-evidence/shared-portal-usage-sparkline.json +0 -18
  240. package/data/ux-source-evidence/shared-portal-user-menu.json +0 -34
@@ -341,336 +341,6 @@
341
341
  "document",
342
342
  "logo-on-band"
343
343
  ]
344
- },
345
- {
346
- "id": "ux-pattern-examples",
347
- "title": "UX pattern page examples",
348
- "source": "blocks/ux-pattern-examples/ux-examples.css",
349
- "contract": "Human-facing UX pattern list with complete contextual page examples, preview/code inspection, base npm installation and optional AI handoff. Examples compose reusable parts; agents still select only needed parts. No required manual assembly. Use the user theme or Cloudblur, no source branding. Clearly distinguish shipped npm components from local example/MCP code. Input stays in demo memory; no signup, consent, review or provisioning is executed. Every example links internally to a pinned source pattern; source-indexed status is not a completed port. States can be inspected independently, without switching other examples. Retired invented review/workspace examples are not discoverable.",
350
- "ownership": [
351
- "UIPatternLibrary",
352
- "AccountExamples",
353
- "AuthFrame",
354
- "semantic-pattern-parts",
355
- "Button",
356
- "Checkbox",
357
- "TextInput"
358
- ],
359
- "slots": [
360
- "ux-example",
361
- "bar",
362
- "center",
363
- "form",
364
- "setup",
365
- "workspace",
366
- "actions",
367
- "check"
368
- ],
369
- "states": [
370
- "preview",
371
- "code",
372
- "invalid",
373
- "complete",
374
- "filtered",
375
- "empty",
376
- "copied",
377
- "copy-failed"
378
- ],
379
- "tokens": [
380
- "--ux-example-min-height",
381
- "--ux-example-form-width",
382
- "--ux-example-setup-width",
383
- "--surface",
384
- "--background",
385
- "--foreground",
386
- "--border",
387
- "--radius-surface"
388
- ],
389
- "responsive": {
390
- "behavior": "Bounded page stage, form center stacks at small widths; native tables/code scrolling without chrome, logical layout and localized examples."
391
- }
392
- },
393
- {
394
- "id": "semantic-pattern-parts",
395
- "title": "Composable product-neutral UI parts",
396
- "source": "blocks/semantic-pattern-parts/pattern-parts.css",
397
- "contract": "Parts expose product-owned labels, data and callbacks. No copied screen shells, brand names or portal roles. Choices, fields, filters, review rows, progress and results compose independently; reuse KPIGrid for metrics. User/room theme wins; otherwise Cloudblur. Surface radii are bounded independently from pill controls. MCP retrieves only selected parts with explicit shared-state bindings, never authorizes operations.",
398
- "ownership": [
399
- "PatternParts",
400
- "KPIGrid",
401
- "UIPatternLibrary",
402
- "UIPatternPreview",
403
- "Button",
404
- "TextInput",
405
- "NativeSelect",
406
- "Badge",
407
- "DataTable"
408
- ],
409
- "slots": [
410
- "pattern-choices",
411
- "pattern-field",
412
- "pattern-filters",
413
- "pattern-review",
414
- "pattern-steps",
415
- "pattern-result"
416
- ],
417
- "states": [
418
- "selected",
419
- "unselected",
420
- "empty",
421
- "invalid",
422
- "filtered",
423
- "ready",
424
- "loading",
425
- "error",
426
- "retry",
427
- "done",
428
- "current",
429
- "locked",
430
- "info",
431
- "success",
432
- "warning"
433
- ],
434
- "tokens": [
435
- "--pattern-part-radius",
436
- "--pattern-part-min",
437
- "--radius-surface",
438
- "--foreground",
439
- "--foreground-muted",
440
- "--primary",
441
- "--primary-foreground",
442
- "--surface",
443
- "--border",
444
- "--success",
445
- "--warning"
446
- ],
447
- "responsive": {
448
- "behavior": "Auto-fit parts, wrapped filters, native table scrolling without chrome, logical properties and translated labels for RTL. No motion required."
449
- }
450
- },
451
- {
452
- "id": "ux-pattern-catalog",
453
- "title": "UX pattern example library",
454
- "source": "src/patterns/ux-pattern-catalog.css",
455
- "contract": "Searchable catalogue links to one dedicated route per implemented UX pattern. Detail renders only that example, with back-to-list and adjacent links, Preview/Code, viewport, reset, state, npm and optional AI controls. Browser back/forward, refresh and legacy example query links work. No giant stacked one-pager; source-indexed items are not completed examples. User theme wins, otherwise Cloudblur. AI selects needed parts independently; demos are memory-only and publishing status is explicit. Catalogue and detail routes use the same templates application area and never mount the documentation sidebar, including mobile. The preview uses the full available main canvas.",
456
- "ownership": [
457
- "UIPatternLibrary",
458
- "UIPatternPreview",
459
- "TemplatesPage composition",
460
- "Button",
461
- "NativeSelect",
462
- "TextInput",
463
- "TextArea",
464
- "Badge",
465
- "semantic-pattern-parts",
466
- "KPIGrid"
467
- ],
468
- "slots": [
469
- "ux-pattern-catalog",
470
- "nav",
471
- "detail",
472
- "heading",
473
- "controls",
474
- "stage",
475
- "page",
476
- "code",
477
- "meta",
478
- "help",
479
- "feedback",
480
- "gallery-navigation",
481
- "gallery-identity",
482
- "gallery-sizes",
483
- "catalog-index",
484
- "catalog-entry",
485
- "catalog-link"
486
- ],
487
- "states": [
488
- "searching",
489
- "empty",
490
- "selected",
491
- "preview",
492
- "code",
493
- "copied",
494
- "copy-failed"
495
- ],
496
- "tokens": [
497
- "--ux-catalog-card-min",
498
- "--ux-catalog-content-max",
499
- "--ux-catalog-radius",
500
- "--ux-catalog-sample-height",
501
- "--ux-library-nav-width",
502
- "--ux-library-mobile-width",
503
- "--ux-library-code-height",
504
- "--ux-gallery-tablet-width",
505
- "--ux-gallery-search-width"
506
- ],
507
- "responsive": {
508
- "behavior": "Horizontal pattern navigation and toolbar wrap at 60rem. Full-width preview can be bounded to tablet/mobile widths; native table/code scrolling has no chrome. Logical layout supports Arabic."
509
- }
510
- },
511
- {
512
- "id": "auth-interactions",
513
- "title": "Composable account interactions",
514
- "source": "blocks/semantic-pattern-parts/auth-parts.css",
515
- "contract": "Password visibility/strength, six-digit entry, provider selection and centered account framing are independently reusable source-backed interactions. Product owns labels, rules, pending/error/success state and auth callbacks. OTP supports paste/backspace/arrows, labels and RTL numeric order. Preview remains in-memory and cannot authenticate, send mail, persist passwords or change security settings. Source screenshots and palettes are never rendered as themed ports.",
516
- "ownership": [
517
- "AuthParts",
518
- "AccountExamples",
519
- "UIPatternLibrary",
520
- "Button",
521
- "TextInput",
522
- "Checkbox"
523
- ],
524
- "slots": [
525
- "password-field",
526
- "verification-code",
527
- "provider-sign-in",
528
- "auth-part-frame",
529
- "auth-part-field",
530
- "auth-part-password",
531
- "auth-part-rules",
532
- "auth-part-code",
533
- "auth-part-providers",
534
- "auth-part-divider",
535
- "auth-part-actions",
536
- "auth-part-card",
537
- "auth-part-check",
538
- "auth-part-state"
539
- ],
540
- "states": [
541
- "hidden",
542
- "visible",
543
- "invalid",
544
- "partial",
545
- "complete",
546
- "pending",
547
- "waiting",
548
- "expired",
549
- "selected"
550
- ],
551
- "tokens": [
552
- "--auth-form-width",
553
- "--auth-code-cell-min",
554
- "--surface",
555
- "--background",
556
- "--foreground",
557
- "--foreground-muted",
558
- "--destructive-text",
559
- "--success-text",
560
- "--border",
561
- "--radius-input",
562
- "--radius-surface",
563
- "--auth-code-radius",
564
- "--auth-panel-radius"
565
- ],
566
- "responsive": {
567
- "behavior": "Container-bounded form, wrapping actions and logical spacing. Numeric codes remain LTR inside Arabic context; no custom motion."
568
- }
569
- },
570
- {
571
- "id": "product-interactions",
572
- "title": "Composable activity and preference interactions",
573
- "source": "blocks/semantic-pattern-parts/product-parts.css",
574
- "contract": "Host-owned activity rows, directory cards and per-event notification channels. Generic labels and callbacks, bounded semantic geometry, accessible empty and unread states. Channel restrictions are host data, not product-wide policy. Examples reuse only needed interactions, never a source portal shell. All demo activity remains in memory.",
575
- "ownership": [
576
- "ProductParts",
577
- "ProductExamples",
578
- "Button",
579
- "NativeSelect"
580
- ],
581
- "slots": [
582
- "activity-list",
583
- "activity-row",
584
- "directory-cards",
585
- "directory-card",
586
- "channel-preferences",
587
- "product-example",
588
- "product-content",
589
- "product-columns",
590
- "product-toolbar"
591
- ],
592
- "states": [
593
- "default",
594
- "empty",
595
- "unread",
596
- "archived",
597
- "selected",
598
- "filtered",
599
- "saved",
600
- "dirty"
601
- ],
602
- "tokens": [
603
- "--product-content-width",
604
- "--product-card-min",
605
- "--product-panel-radius",
606
- "--space-4",
607
- "--space-6",
608
- "--surface",
609
- "--surface-strong",
610
- "--foreground",
611
- "--foreground-muted",
612
- "--border"
613
- ],
614
- "responsive": {
615
- "behavior": "Container-query two-column layout collapses within mobile previews; rows and controls wrap. Logical spacing and native chrome-free scrolling."
616
- }
617
- },
618
- {
619
- "id": "workflow-interactions",
620
- "title": "Independent workflow fields, records, checks and media state",
621
- "source": "blocks/semantic-pattern-parts/workflow-parts.css",
622
- "contract": "Composable host-owned fields, record tables, prerequisite checks, ratings, measures, trends and media stages. Example definitions carry source-linked neutral scenarios, not source portal layouts. Required-field policy, authorization, prices, file transfer, device testing and mutations remain with the integrating product. Bounded surfaces, native scrolling without chrome, keyboard names and logical RTL layout.",
623
- "ownership": [
624
- "WorkflowParts",
625
- "WorkflowExample",
626
- "WorkflowExamples",
627
- "Button",
628
- "TextInput",
629
- "TextArea",
630
- "NativeSelect"
631
- ],
632
- "slots": [
633
- "workflow-example",
634
- "workflow-fields",
635
- "workflow-multi-select",
636
- "record-table",
637
- "step-checklist",
638
- "stat-strip",
639
- "rating-fields",
640
- "trend-summary",
641
- "media-stage"
642
- ],
643
- "states": [
644
- "default",
645
- "invalid",
646
- "empty",
647
- "pending",
648
- "pass",
649
- "fail",
650
- "locked",
651
- "selected",
652
- "complete",
653
- "scheduled",
654
- "live",
655
- "ended"
656
- ],
657
- "tokens": [
658
- "--workflow-table-min",
659
- "--workflow-media-min",
660
- "--product-panel-radius",
661
- "--space-4",
662
- "--space-5",
663
- "--border",
664
- "--surface",
665
- "--surface-strong",
666
- "--foreground-muted",
667
- "--destructive-text",
668
- "--primary",
669
- "--ring"
670
- ],
671
- "responsive": {
672
- "behavior": "Contained keyboard-scrollable tables; wrapping actions and single-column fields at narrow widths. Media does not start permissions or animations."
673
- }
674
344
  }
675
345
  ]
676
346
  }
package/lib/api.mjs CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  validateAgentLayoutMutation,
7
7
  validateLayoutDocument,
8
8
  } from './composition-runtime.mjs'
9
+ export { validateBrandbook } from './brandbook-validation.mjs'
9
10
 
10
11
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
11
12
  const workspaceRoot = resolve(packageRoot, '../..')
@@ -17,7 +18,7 @@ export const apiVersion = 1
17
18
  export const cliVersion = packageMetadata.version
18
19
  export const mcpLaunch = {
19
20
  command: 'npx',
20
- args: ['-y', '--package', '@utopia-studio-design/design-system-cli', 'utopia-ds', 'mcp'],
21
+ args: ['-y', '--package', `${packageMetadata.name}@${cliVersion}`, 'utopia-ds', 'mcp'],
21
22
  }
22
23
 
23
24
  export function paths(root = hasWorkspaceSource ? workspaceRoot : packagedDataRoot) {
@@ -58,186 +59,6 @@ export function listTemplates() {
58
59
  return readJson(join(paths().manifests, 'templates.json')).templates
59
60
  }
60
61
 
61
- export function getUxPatternRegistry() {
62
- return readJson(join(paths().manifests, 'ux-patterns.json'))
63
- }
64
-
65
- export function listUxPatterns() {
66
- return getUxPatternRegistry().patterns
67
- }
68
-
69
- export function listUiParts() {
70
- return readJson(join(paths().manifests, 'ui-patterns.json')).parts
71
- }
72
-
73
- export function listUxExamples() {
74
- return readJson(join(paths().manifests, 'ux-examples.json')).examples
75
- }
76
-
77
- /** Complete source evidence, distinct from runnable Ceramic examples. */
78
- export function listUxSourcePatterns() {
79
- const inventory = readJson(join(paths().manifests, 'ux-source-inventory.json'))
80
- const examples = listUxExamples()
81
- return inventory.entries.map(({ evidence, ...entry }) => ({ ...entry,
82
- examples: examples.filter(example => (example.sourcePatterns ?? [example.sourcePattern]).includes(entry.id)).map(example => example.id),
83
- }))
84
- }
85
-
86
- export function findUxSourcePatterns(goal) {
87
- if (typeof goal !== 'string' || !goal.trim() || goal.length > 2000) return { ok: false, code: 'INVALID_GOAL' }
88
- const words = goal.toLowerCase().split(/\s+/).filter(word => word.length > 1)
89
- const candidates = listUxSourcePatterns().map(entry => {
90
- const text = [entry.id, entry.category, ...Object.values(entry.title), ...(entry.keywords ?? []), ...entry.fragments.map(f => f.id)].join(' ').toLowerCase()
91
- const aliases = (entry.keywords ?? []).filter(keyword => goal.toLowerCase().includes(keyword.toLowerCase()))
92
- return { ...entry, score: words.filter(word => text.includes(word)).length + aliases.length }
93
- }).filter(entry => entry.score > 0).sort((a,b) => b.score - a.score)
94
- return { ok: true, candidates, guidance: 'AI selects only relevant fragments, without a user selection wizard. Prefer runnable examples when available. source-indexed means original evidence only, NOT an implemented Ceramic component. Use get_ux_source_part for one named fragment. No match means use normal Ceramic components.' }
95
- }
96
-
97
- export function getUxSourcePart(input) {
98
- if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => !['id', 'part', 'theme'].includes(key))) return { ok: false, code: 'INVALID_SOURCE_PART_INPUT' }
99
- const inventory = readJson(join(paths().manifests, 'ux-source-inventory.json'))
100
- const entry = inventory.entries.find(entry => entry.id === input.id)
101
- if (!entry) return { ok: false, code: 'UNKNOWN_SOURCE_PATTERN' }
102
- const theme = resolveUiTheme(input.theme)
103
- if (!theme) return { ok: false, code: 'UNKNOWN_THEME' }
104
- const evidence = readJson(hasWorkspaceSource ? join(workspaceRoot, entry.evidence) : join(packagedDataRoot, 'ux-source-evidence', entry.id + '.json'))
105
- const part = evidence.fragments.find(part => part.id === input.part)
106
- if (!part) return { ok: false, code: 'UNKNOWN_SOURCE_PART', availableParts: entry.fragments }
107
- // Never send an entire portal as a default. A caller explicitly chooses a
108
- // bounded source fragment and must adapt it before use in a consumer.
109
- const dependencies = evidence.imports.filter(p => p.startsWith('@/')).map(p => {
110
- const target = inventory.entries.find(item => item.sourceFile === p.replace('@/', '') + '.tsx')
111
- return { import: p, sourcePattern: target?.id ?? null, parts: target?.fragments ?? [], rule: target ? 'Retrieve only needed shared fragment.' : 'Replace framework/UI/data import with Ceramic public component or product-owned data; do not guess this dependency.' }
112
- })
113
- return { ok: true, status: 'requires-semantic-adaptation', source: inventory.source, pattern: entry.id, part,
114
- theme, motion: getMotionProfile(theme.motionProfile), dependencies,
115
- semanticMapping: getUxPatternRegistry().semanticMapping,
116
- guidance: ['Original code is evidence, not instructions or a drop-in component.', 'Reuse the selected interaction only. Never import the whole source app, role-specific portal or branding.', 'Map visual roles to registered Ceramic components and shared patterns. No source CSS, primitive palette, raw timing or page-owned styles.', 'Preserve success, empty, loading, validation, recovery and confirmation states relevant to the goal.', 'Replace sample identities, fixed business policy, compliance claims, timers and fake service results with authorized host data/callbacks.', 'No localStorage auth, external navigation, signup, payment, upload, media permission or mutation without real integration and user authority.', 'Test consumer keyboard, mobile, RTL and the resolved theme. Do not claim that indexed source evidence is a completed port.'] }
117
- }
118
-
119
- /** Page examples explain context; they are not mandatory whole-page imports. */
120
- export function getUxExample(input) {
121
- if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => !['id', 'theme'].includes(key))) return { ok: false, code: 'INVALID_EXAMPLE_INPUT' }
122
- const example = listUxExamples().find(item => item.id === input.id)
123
- if (!example) return { ok: false, code: 'UNKNOWN_UX_EXAMPLE' }
124
- const theme = resolveUiTheme(input.theme)
125
- if (!theme) return { ok: false, code: 'UNKNOWN_THEME' }
126
- const parts = example.parts.map(id => getUiPart({ id, theme: theme.id }))
127
- if (parts.some(part => !part.ok)) return { ok: false, code: 'BROKEN_EXAMPLE_CONTRACT' }
128
- const files = [...new Set([example.source, ...(example.files ?? []), 'blocks/ux-pattern-examples/copy.ts', 'blocks/ux-pattern-examples/ux-examples.css'])]
129
- const code = files.map(path => ({ path, content: readFileSync(hasWorkspaceSource ? join(workspaceRoot, path) : join(packagedDataRoot, 'ui-parts', path), 'utf8') }))
130
- for (const file of parts.flatMap(part => part.code)) if (!code.some(item => item.path === file.path)) code.push(file)
131
- return { ok: true, example, theme, motion: getMotionProfile(theme.motionProfile), parts, code,
132
- install: 'npm install @utopia-studio-design/design-system',
133
- availability: 'Example bundles and MCP tools are available in Ceramic CLI 0.8.0 and later.',
134
- guidance: 'Inspect the contextual page example, then reuse only the parts that fit the user goal. Never require the user to browse or select examples first. Keep shared semantic CSS and the resolved user/room theme; Cloudblur is the fallback. Replace fixture data with authorized product data and callbacks. Demo signup, consent, completion and review do not create accounts, save, approve or deploy anything.' }
135
- }
136
-
137
- /** Candidate discovery, not a command to add every matching part. The coding
138
- * agent decides fit in context; the user never has to choose these parts. */
139
- export function findUiParts(goal) {
140
- if (typeof goal !== 'string' || !goal.trim() || goal.length > 2000) return { ok: false, code: 'INVALID_GOAL' }
141
- const text = goal.toLowerCase()
142
- const candidates = listUiParts().map(part => {
143
- const matches = part.keywords.filter(keyword => text.includes(keyword.toLowerCase()))
144
- return { ...part, score: matches.length, matchedIntents: matches }
145
- }).filter(part => part.score > 0).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id))
146
- const sourceCandidates = findUxSourcePatterns(goal).candidates.slice(0, 8)
147
- return { ok: true, candidates, sourceCandidates, guidance: 'The AI must check useWhen/avoidWhen against the goal and use only needed parts. Never ask the user to pick parts. Prefer ready Ceramic parts. sourceCandidates expose additional original interactions requiring semantic adaptation via get_ux_source_part, not whole-page import. If nothing fits, use ordinary components; never force a pattern.' }
148
- }
149
-
150
- function resolveUiTheme(theme) {
151
- const room = getRoomContext()
152
- const id = theme ?? room?.themeId ?? room?.theme?.id ?? 'utopia-cloudblur'
153
- // An invalid explicit/custom theme is not permission to silently rebrand.
154
- return typeof id === 'string' && id.trim() ? getTheme(id) : null
155
- }
156
-
157
- export function getUiPart(input) {
158
- if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => !['id', 'theme'].includes(key))) return { ok: false, code: 'INVALID_PART_INPUT' }
159
- const part = listUiParts().find(part => part.id === input.id)
160
- if (!part) return { ok: false, code: 'UNKNOWN_UI_PART' }
161
- const theme = resolveUiTheme(input.theme)
162
- if (!theme) return { ok: false, code: 'UNKNOWN_THEME' }
163
- const files = [...new Set([part.source, part.styles, ...(part.files ?? []), ...(part.id === 'choice-cards' || part.id === 'list-filters' || part.id === 'review-list' ? ['blocks/semantic-pattern-parts/types.ts'] : [])])]
164
- const code = files.map(path => ({ path, content: readFileSync(hasWorkspaceSource ? join(workspaceRoot, path) : join(packagedDataRoot, 'ui-parts', path), 'utf8') }))
165
- return { ok: true, part, theme, motion: getMotionProfile(theme.motionProfile), components: part.components.map(getComponent), code, guidance: 'Copy only this reusable export and its dependencies. All labels, data and callbacks are product-owned. Do not copy a screen shell or sample identities. CSS belongs to the shared composition, not the page. Apply the resolved theme to the common host. Never turn fixture results into real authorization.' }
166
- }
167
-
168
- export function prepareUiComposition(input) {
169
- if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => !['goal', 'theme'].includes(key))) return { ok: false, code: 'INVALID_COMPOSITION_INPUT' }
170
- const found = findUiParts(input.goal)
171
- if (!found.ok) return found
172
- const theme = resolveUiTheme(input.theme)
173
- if (!theme) return { ok: false, code: 'UNKNOWN_THEME' }
174
- const selected = found.candidates.slice(0, 4)
175
- const parts = selected.map(part => getUiPart({ id: part.id, theme: theme.id }))
176
- const ids = selected.map(part => part.id)
177
- const bindings = []
178
- if (ids.includes('list-filters') && ids.includes('review-list')) bindings.push({ from: 'ListFilters.query/status', via: 'Host-owned state and authorized filtered query', to: 'ReviewList.rows', rule: 'Reset both filter values; render empty/loading/error states from the query result.' })
179
- if (ids.includes('metric-summary') && ids.includes('review-list')) bindings.push({ from: 'Host-authorized rows and scope', to: 'KPIGrid.metrics', rule: 'Calculate counts for the same filter scope. Never invent totals from unloaded/paginated rows.' })
180
- if (ids.includes('outcome-notice')) bindings.push({ from: 'Confirmed service result', to: 'OutcomeNotice', rule: 'Show success only after confirmation; retry must call a real recovery callback.' })
181
- return { ok: true, status: selected.length ? 'composition-proposal' : found.sourceCandidates.length ? 'source-adaptation-candidates' : 'no-pattern-needed', goal: input.goal.trim(), theme: theme.id, parts, sourceCandidates: found.sourceCandidates, bindings, guidance: found.guidance, nextSteps: ['AI checks whether each candidate fits; discard unrelated parts without making the user choose.', 'When a relevant interaction exists only in sourceCandidates, use get_ux_source_part to inspect just that fragment and adapt its semantics; do not call it a ready Ceramic port.', 'Compose the selected exports around host-owned product data and callbacks. No complete portal or page import.', 'Use existing Ceramic components for anything not covered; patterns are optional.', 'Confirm external side effects separately; this read-only proposal does not build, save, approve or deploy.', 'Verify keyboard, responsive layout, loading/empty/error/retry, RTL and theme tokens in the consuming product.'] }
182
- }
183
-
184
- export function getUxPattern(id) {
185
- const registry = getUxPatternRegistry()
186
- // IDs are exact: do not normalize non-ASCII names into the same empty key.
187
- const pattern = registry.patterns.find(item => item.id === id)
188
- return pattern ? { ...pattern, source: registry.source, guardrails: registry.guardrails, semanticMapping: registry.semanticMapping, verification: registry.verification } : null
189
- }
190
-
191
- /** Read-only planning: a recipe is never advertised as an existing renderer. */
192
- export function preparePatternAdaptation(input) {
193
- const fail = (code, message) => ({ ok: false, code, message })
194
- if (!input || typeof input !== 'object' || Array.isArray(input) || Object.keys(input).some(key => !['id', 'goal', 'theme', 'variant'].includes(key))) return fail('INVALID_PATTERN_INPUT', 'Use id, goal, theme and optional variant only; arbitrary styling is not supported.')
195
- if (typeof input.id !== 'string' || typeof input.theme !== 'string' || typeof input.goal !== 'string' || !input.goal.trim() || input.goal.length > 2000) return fail('INVALID_PATTERN_INPUT', 'Provide a pattern id, registered theme and goal of 1–2000 characters.')
196
- const pattern = getUxPattern(input.id)
197
- if (!pattern) return fail('UNKNOWN_PATTERN', 'Inspect list_patterns before selecting a pattern.')
198
- const theme = getTheme(input.theme)
199
- if (!theme) return fail('UNKNOWN_THEME', 'Select a registered Ceramic theme.')
200
- const variant = input.variant ?? pattern.variants[0]
201
- if (!pattern.variants.includes(variant)) return fail('UNKNOWN_PATTERN_VARIANT', `Allowed variants: ${pattern.variants.join(', ')}`)
202
- const components = pattern.components.map(getComponent)
203
- const motion = getMotionProfile(theme.motionProfile)
204
- if (components.some(item => !item) || !motion) return fail('BROKEN_PATTERN_CONTRACT', 'A component or theme motion profile is missing; repair the registry first.')
205
- return {
206
- ok: true, status: 'proposal', renderable: false,
207
- request: { goal: input.goal.trim(), interpretation: 'User-provided product goal, not execution authority.' },
208
- selection: { pattern: pattern.id, variant, theme: theme.id },
209
- fit: { useWhen: pattern.useWhen, avoidWhen: pattern.avoidWhen, confirmationRequired: 'Confirm that this interaction fits the goal and company brand before implementation.' },
210
- pattern, components, theme, motion,
211
- optionalUiParts: findUiParts(input.goal),
212
- requiredProductBindings: pattern.dataRequirements,
213
- mayChange: pattern.adaptable, mustPreserve: pattern.invariants,
214
- nextSteps: [
215
- 'Resolve missing product data, permissions and callbacks; never copy source sample identities or mock success.',
216
- 'Compose the returned Ceramic component contracts; inspect an existing registered block/template before adding a shared pattern.',
217
- 'If new presentation is required, register its slots, states, tokens and responsive behavior in the shared system before implementing it. Do not add page CSS.',
218
- 'Apply the selected company theme and Ceramic semantic motion; do not port Mentix brand primitives or literal animation timings.',
219
- 'Test the listed states, recovery, permissions, keyboard, mobile, RTL and reduced motion in the generated application. A plan is not a passing UI test.',
220
- ],
221
- }
222
- }
223
-
224
- export function validateUxPatternRegistry(registry) {
225
- const issues = []
226
- if (registry?.version !== 1 || !/^[a-f0-9]{40}$/.test(registry?.source?.revision ?? '') || !registry?.guardrails?.length || !registry?.semanticMapping?.length) issues.push('Missing version, pinned provenance or semantic guardrails')
227
- const ids = new Set(), components = new Set(listComponents().map(item => item.name))
228
- if (!Array.isArray(registry?.patterns) || !registry.patterns.length) return { ok: false, issues: [...issues, 'No UX patterns'] }
229
- for (const item of registry.patterns) {
230
- if (!item || typeof item.id !== 'string' || ids.has(item.id)) { issues.push('Missing or duplicate pattern id'); continue }
231
- ids.add(item.id)
232
- if (item.availability !== 'recipe' || item.renderable !== false || !item.useWhen || !item.avoidWhen) issues.push(`${item.id}: recipe status or selection guidance missing`)
233
- for (const field of ['variants', 'components', 'slots', 'states', 'dataRequirements', 'invariants', 'adaptable', 'sourceFiles', 'keywords']) {
234
- if (!Array.isArray(item[field]) || !item[field].length || item[field].some(value => typeof value !== 'string' || !value)) issues.push(`${item.id}: ${field} incomplete`)
235
- }
236
- if (Array.isArray(item.components) && item.components.some(name => !components.has(name))) issues.push(`${item.id}: unknown Ceramic component`)
237
- }
238
- return { ok: issues.length === 0, issues }
239
- }
240
-
241
62
  export function listBlocks() {
242
63
  return readJson(join(paths().manifests, 'blocks.json')).blocks
243
64
  }
@@ -408,10 +229,6 @@ export function search(query) {
408
229
  const terms = String(query).toLowerCase().split(/\s+/).filter(Boolean)
409
230
  const score = (text) => terms.reduce((total, term) => total + (text.toLowerCase().includes(term) ? 1 : 0), 0)
410
231
  const results = [
411
- ...listUiParts().map((item) => ({ kind: 'ui-part', id: item.id, title: item.title.en, summary: [Object.values(item.title).join(' '), item.useWhen, ...item.keywords].join(' '), item })),
412
- ...listUxExamples().map(item => ({ kind: 'ux-example', id: item.id, title: item.title.en, summary: [...Object.values(item.title), ...Object.values(item.description), ...item.parts].join(' '), item })),
413
- ...listUxSourcePatterns().map(item => ({ kind: 'ux-source-pattern', id: item.id, title: item.title.en, summary: [item.category, ...Object.values(item.title), ...item.fragments.map(f => f.id)].join(' '), item })),
414
- ...listUxPatterns().map((item) => ({ kind: 'ux-pattern', id: item.id, title: item.title, summary: [item.useWhen, ...item.keywords].join(' '), item })),
415
232
  ...listComponents().map((item) => ({ kind: 'component', id: item.name, title: item.name, summary: [...item.useWhen, item.category].join(' '), item })),
416
233
  ...listBlockDefinitions().map((item) => ({ kind: 'block-definition', id: item.id, title: item.title, summary: `${item.category} ${item.description} ${item.availability}`, item })),
417
234
  ...listBlocks().map((item) => ({ kind: 'block', id: item.id, title: item.title, summary: `${item.category} ${item.purpose}`, item })),
@@ -423,7 +240,7 @@ export function search(query) {
423
240
  ...listDocs().map((topic) => ({ kind: 'docs', id: topic, title: topic, summary: getDoc(topic)?.content.slice(0, 500) ?? '', item: { topic } })),
424
241
  ]
425
242
  return results
426
- .map((result) => ({ ...result, score: score(`${result.id} ${result.title} ${result.summary}`) }))
243
+ .map((result) => ({ ...result, score: score(`${result.title} ${result.summary}`) }))
427
244
  .filter((result) => result.score > 0)
428
245
  .sort((a, b) => b.score - a.score || a.title.localeCompare(b.title))
429
246
  .map(({ summary: _summary, ...result }) => result)
@@ -443,7 +260,6 @@ export function capabilityManifest() {
443
260
  { name: 'init', args: ['[directory]'], flags: ['--yes', '--theme <id>'], responseType: 'init-result' },
444
261
  { name: 'room', args: ['connect'], flags: ['--id <id>', '--slug <slug>', '--name <room>', '--brand <brand>', '--source <mode>', '--client <client>', '--directory <path>'], responseType: 'room-connect-result' },
445
262
  { name: 'search', args: ['<query>'], flags: [], responseType: 'search-results' },
446
- { name: 'pattern', args: ['<id>|--list'], flags: ['--goal <text>', '--theme <id>', '--variant <id>'], responseType: 'ux-pattern|ux-pattern-list|pattern-adaptation-plan' },
447
263
  { name: 'component', args: ['<name>|--list'], flags: [], responseType: 'component|component-list' },
448
264
  { name: 'registry', args: ['<block-id>|--list'], flags: ['--renderable'], responseType: 'block-definition|block-definition-list' },
449
265
  { name: 'layout', args: ['validate <file>', 'serialize <file>'], flags: [], responseType: 'layout-validation-result|layout-serialization-result' },
@@ -459,14 +275,14 @@ export function capabilityManifest() {
459
275
  ],
460
276
  mcp: {
461
277
  ...mcpLaunch,
462
- tools: ['get_room_context', 'search', 'list_ux_source_patterns', 'find_ux_source_patterns', 'get_ux_source_part', 'list_ux_examples', 'get_ux_example', 'find_ui_parts', 'get_ui_part', 'prepare_ui_composition', 'list_patterns', 'get_pattern', 'prepare_pattern_adaptation', 'list_components', 'get_component', 'list_block_definitions', 'get_block_definition', 'validate_layout', 'validate_agent_layout_mutation', 'list_blocks', 'get_block', 'list_templates', 'get_template', 'list_themes', 'get_theme', 'list_motion_profiles', 'get_motion_profile', 'list_logo_skills', 'get_logo_skill', 'prepare_logo_maker_run', 'get_brandbook_skill', 'prepare_brandbook_run', 'list_docs', 'get_docs', 'doctor'],
278
+ tools: ['get_room_context', 'search', 'list_components', 'get_component', 'list_block_definitions', 'get_block_definition', 'validate_layout', 'validate_agent_layout_mutation', 'list_blocks', 'get_block', 'list_templates', 'get_template', 'list_themes', 'get_theme', 'list_motion_profiles', 'get_motion_profile', 'list_logo_skills', 'get_logo_skill', 'prepare_logo_maker_run', 'get_brandbook_skill', 'prepare_brandbook_run', 'validate_brandbook', 'list_docs', 'get_docs', 'doctor'],
463
279
  },
464
280
  }
465
281
  }
466
282
 
467
283
  export function repositoryDoctor() {
468
284
  const required = [
469
- 'catalog.json', 'components.json', 'blocks.json', 'composition-registry.json', 'templates.json', 'themes.json', 'motion-profiles.json', 'logo-skills.json', 'ux-patterns.json', 'brandbook-skill.json',
285
+ 'catalog.json', 'components.json', 'blocks.json', 'composition-registry.json', 'templates.json', 'themes.json', 'motion-profiles.json', 'logo-skills.json', 'brandbook-skill.json',
470
286
  ].map((name) => join(paths().manifests, name))
471
287
  const docs = ['quick-start-ai', 'arabic-friendly', 'theme-authoring', 'composition-registry'].map((name) => join(paths().docs, `${name}.md`))
472
288
  const missing = [...required, ...docs].filter((path) => !existsSync(path))
@@ -491,10 +307,8 @@ export function repositoryDoctor() {
491
307
  && definition.agentPermissions
492
308
  ) === true
493
309
  if (!compositionContract) contractIssues.push('composition-registry.json: incomplete block or layout contract')
494
- const uxPatterns = missing.includes(join(paths().manifests, 'ux-patterns.json')) ? { ok: false, issues: ['Missing UX pattern registry'] } : validateUxPatternRegistry(getUxPatternRegistry())
495
- contractIssues.push(...uxPatterns.issues)
496
310
  return {
497
- ok: missing.length === 0 && motionContract && compositionContract && uxPatterns.ok,
311
+ ok: missing.length === 0 && motionContract && compositionContract,
498
312
  checks: {
499
313
  manifests: required.every(existsSync),
500
314
  docs: docs.every(existsSync),
@@ -502,7 +316,6 @@ export function repositoryDoctor() {
502
316
  blocks: listBlocks().length,
503
317
  blockDefinitions: compositionRegistry?.definitions?.length ?? 0,
504
318
  compositionContract,
505
- uxPatternContract: uxPatterns.ok,
506
319
  layoutSchemaVersion: compositionRegistry?.layoutSchemaVersion ?? null,
507
320
  templates: listTemplates().length,
508
321
  themes: listThemes().length,