bitboss-ui 3.0.0-beta.4 → 3.0.0-beta.41

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 (937) hide show
  1. package/README.md +317 -98
  2. package/bin/bitboss-ui-mcp.mjs +1566 -75
  3. package/bin/bitboss-ui.mjs +716 -72
  4. package/dist/ai/BbAccordion.md +178 -56
  5. package/dist/ai/BbAlert.md +140 -28
  6. package/dist/ai/BbAsterisk.md +61 -4
  7. package/dist/ai/BbAvatar.md +194 -53
  8. package/dist/ai/BbBadge.md +250 -50
  9. package/dist/ai/BbBadgeButton.md +74 -21
  10. package/dist/ai/BbBaseButton.md +132 -51
  11. package/dist/ai/BbBaseCheckboxIcon.md +118 -26
  12. package/dist/ai/BbBaseRadioIcon.md +115 -26
  13. package/dist/ai/BbBaseSwitchIcon.md +123 -28
  14. package/dist/ai/BbBreadcrumbs.md +221 -51
  15. package/dist/ai/BbButton.md +389 -107
  16. package/dist/ai/BbCalendar.md +667 -0
  17. package/dist/ai/BbCheckbox.md +242 -80
  18. package/dist/ai/BbCheckboxGroup.md +575 -66
  19. package/dist/ai/BbCollapsible.md +158 -39
  20. package/dist/ai/BbColorInput.md +322 -82
  21. package/dist/ai/BbColorPalette.md +261 -61
  22. package/dist/ai/BbConfirm.md +220 -51
  23. package/dist/ai/BbConfirmPortal.md +1 -1
  24. package/dist/ai/BbDatePicker.md +272 -37
  25. package/dist/ai/BbDatePickerInput.md +321 -92
  26. package/dist/ai/BbDialog.md +492 -87
  27. package/dist/ai/BbDropdown.md +1182 -104
  28. package/dist/ai/BbDropdownButton.md +239 -61
  29. package/dist/ai/BbDropdownGroup.md +5 -5
  30. package/dist/ai/BbDropzone.md +140 -36
  31. package/dist/ai/BbForm.md +1165 -40
  32. package/dist/ai/BbIcon.md +100 -33
  33. package/dist/ai/BbIndicator.md +79 -12
  34. package/dist/ai/BbNumberInput.md +257 -87
  35. package/dist/ai/BbOffCanvas.md +396 -91
  36. package/dist/ai/BbPagination.md +199 -32
  37. package/dist/ai/BbPopover.md +219 -54
  38. package/dist/ai/BbProgress.md +137 -71
  39. package/dist/ai/BbPtScope.md +136 -0
  40. package/dist/ai/BbRadio.md +234 -43
  41. package/dist/ai/BbRadioGroup.md +529 -91
  42. package/dist/ai/BbRating.md +243 -61
  43. package/dist/ai/BbSelect.md +690 -120
  44. package/dist/ai/BbSelectPopover.md +434 -122
  45. package/dist/ai/BbSlider.md +275 -79
  46. package/dist/ai/BbSmoothHeight.md +142 -34
  47. package/dist/ai/BbSpinner.md +179 -81
  48. package/dist/ai/BbSwitch.md +249 -63
  49. package/dist/ai/BbSwitchGroup.md +394 -65
  50. package/dist/ai/BbTable.md +1666 -222
  51. package/dist/ai/BbTabs.md +898 -178
  52. package/dist/ai/BbTabsList.md +81 -7
  53. package/dist/ai/BbTabsPanels.md +77 -0
  54. package/dist/ai/BbTabsRoot.md +16 -15
  55. package/dist/ai/BbTag.md +256 -76
  56. package/dist/ai/BbTextInput.md +480 -102
  57. package/dist/ai/BbTextarea.md +310 -96
  58. package/dist/ai/BbTimePicker.md +159 -24
  59. package/dist/ai/BbTimePickerInput.md +277 -46
  60. package/dist/ai/BbToast.md +286 -40
  61. package/dist/ai/BbToastPortal.md +3 -3
  62. package/dist/ai/BbTooltip.md +187 -34
  63. package/dist/ai/BbTree.md +260 -85
  64. package/dist/ai/ChipsBox.md +43 -2
  65. package/dist/ai/ClearableButton.md +12 -0
  66. package/dist/ai/CommaBox.md +2 -1
  67. package/dist/ai/CommonField.md +63 -0
  68. package/dist/ai/CommonFieldInput.md +90 -0
  69. package/dist/ai/CommonPopover.md +17 -12
  70. package/dist/ai/CommonTimeSelector.md +63 -0
  71. package/dist/ai/ErrorIcon.md +20 -0
  72. package/dist/ai/FlatListBox.md +41 -11
  73. package/dist/ai/GroupedListBox.md +42 -12
  74. package/dist/ai/ListBox.md +46 -11
  75. package/dist/ai/OptionsContainer.md +13 -10
  76. package/dist/ai/WarningIcon.md +20 -0
  77. package/dist/ai/changelog.json +4025 -141
  78. package/dist/ai/components.json +51872 -10136
  79. package/dist/ai/composables/useBbConfig.md +72 -11
  80. package/dist/ai/composables/useBbDropdownContext.md +168 -0
  81. package/dist/ai/composables/useBbFormContext.md +51 -24
  82. package/dist/ai/composables/useBbFormField.md +134 -0
  83. package/dist/ai/composables/useBbTableContext.md +41 -19
  84. package/dist/ai/composables/useConfirm.md +16 -8
  85. package/dist/ai/composables/useCountdown.md +1 -1
  86. package/dist/ai/composables/useId.md +10 -10
  87. package/dist/ai/composables/useMobile.md +17 -10
  88. package/dist/ai/composables/useToast.md +25 -19
  89. package/dist/ai/design-tokens.json +940 -0
  90. package/dist/ai/design-tokens.manifest.yaml +175 -0
  91. package/dist/ai/guides/agent-contract.md +168 -22
  92. package/dist/ai/guides/ai-router.md +79 -40
  93. package/dist/ai/guides/app-layout.md +8 -4
  94. package/dist/ai/guides/coherence-playbook.md +8 -8
  95. package/dist/ai/guides/component-picker.md +42 -34
  96. package/dist/ai/guides/design-language.md +274 -97
  97. package/dist/ai/guides/design-tokens.md +493 -105
  98. package/dist/ai/guides/fetch-items-playbook.md +22 -16
  99. package/dist/ai/guides/icons-policy.md +67 -35
  100. package/dist/ai/guides/inertia-helpers.md +4 -1
  101. package/dist/ai/guides/inline-edit-playbook.md +13 -6
  102. package/dist/ai/guides/installation-and-plugin-setup.md +817 -73
  103. package/dist/ai/guides/migration/components/bb-accordion.md +37 -0
  104. package/dist/ai/guides/migration/components/bb-alert.md +2 -2
  105. package/dist/ai/guides/migration/components/bb-avatar.md +13 -14
  106. package/dist/ai/guides/migration/components/bb-badge.md +5 -5
  107. package/dist/ai/guides/migration/components/bb-breadcrumbs.md +9 -8
  108. package/dist/ai/guides/migration/components/bb-button.md +80 -20
  109. package/dist/ai/guides/migration/components/bb-checkbox-group.md +116 -29
  110. package/dist/ai/guides/migration/components/bb-checkbox.md +53 -10
  111. package/dist/ai/guides/migration/components/bb-chip.md +6 -6
  112. package/dist/ai/guides/migration/components/bb-collapsible.md +5 -5
  113. package/dist/ai/guides/migration/components/bb-color-input.md +5 -5
  114. package/dist/ai/guides/migration/components/bb-color-palette.md +16 -9
  115. package/dist/ai/guides/migration/components/bb-date-picker-input.md +45 -35
  116. package/dist/ai/guides/migration/components/bb-dialog.md +69 -36
  117. package/dist/ai/guides/migration/components/bb-dropdown-button.md +7 -1
  118. package/dist/ai/guides/migration/components/bb-dropdown.md +31 -8
  119. package/dist/ai/guides/migration/components/bb-dropzone.md +8 -0
  120. package/dist/ai/guides/migration/components/bb-icon.md +7 -7
  121. package/dist/ai/guides/migration/components/bb-intersection.md +1 -1
  122. package/dist/ai/guides/migration/components/bb-offcanvas.md +29 -31
  123. package/dist/ai/guides/migration/components/bb-pagination.md +10 -0
  124. package/dist/ai/guides/migration/components/bb-popover.md +19 -11
  125. package/dist/ai/guides/migration/components/bb-radio-group.md +14 -0
  126. package/dist/ai/guides/migration/components/bb-rating.md +61 -24
  127. package/dist/ai/guides/migration/components/bb-select-popover.md +9 -1
  128. package/dist/ai/guides/migration/components/bb-select.md +21 -4
  129. package/dist/ai/guides/migration/components/bb-slider.md +14 -6
  130. package/dist/ai/guides/migration/components/bb-switch-group.md +14 -0
  131. package/dist/ai/guides/migration/components/bb-table.md +574 -33
  132. package/dist/ai/guides/migration/components/bb-tabs.md +91 -41
  133. package/dist/ai/guides/migration/components/bb-tag.md +9 -7
  134. package/dist/ai/guides/migration/components/bb-text-input.md +12 -12
  135. package/dist/ai/guides/migration/components/bb-toast.md +2 -2
  136. package/dist/ai/guides/migration/components/bb-tooltip.md +18 -0
  137. package/dist/ai/guides/migration/components/bb-tree.md +11 -9
  138. package/dist/ai/guides/migration/components/use-confirm.md +9 -1
  139. package/dist/ai/guides/migration/v2-to-v3.md +828 -240
  140. package/dist/ai/guides/migration/v3-beta-css-classes.md +751 -0
  141. package/dist/ai/guides/migration/v3-beta-tooling.md +119 -0
  142. package/dist/ai/guides/options-items-playbook.md +161 -12
  143. package/dist/ai/guides/page-shell.md +1 -1
  144. package/dist/ai/guides/passthrough.md +958 -0
  145. package/dist/ai/guides/preset-components.md +361 -0
  146. package/dist/ai/guides/ssr-prefill.md +127 -0
  147. package/dist/ai/guides/validated-forms.md +466 -55
  148. package/dist/ai/guides/validation-libraries.md +171 -0
  149. package/dist/ai/guides/validation-providers.md +113 -0
  150. package/dist/ai/index.md +45 -44
  151. package/dist/ai/recipes/inertia/approvals-inbox.md +26 -10
  152. package/dist/ai/recipes/inertia/command-palette.md +2 -2
  153. package/dist/ai/recipes/inertia/inline-edit-workspace.md +46 -30
  154. package/dist/ai/recipes/inertia/layout-scaffold.md +6 -2
  155. package/dist/ai/recipes/inertia/onboarding.md +30 -8
  156. package/dist/ai/recipes/inertia/ownership-atlas.md +72 -49
  157. package/dist/ai/recipes/inertia/record-form.md +53 -19
  158. package/dist/ai/recipes/inertia/records-workspace.md +201 -49
  159. package/dist/ai/recipes/inertia/settings-workspace.md +3809 -0
  160. package/dist/ai/recipes/inertia/upload-center.md +54 -43
  161. package/dist/ai/recipes/inertia/wizard-form.md +98 -14
  162. package/dist/ai/recipes/nuxt/approvals-inbox.md +26 -10
  163. package/dist/ai/recipes/nuxt/command-palette.md +2 -2
  164. package/dist/ai/recipes/nuxt/inline-edit-workspace.md +68 -52
  165. package/dist/ai/recipes/nuxt/layout-scaffold.md +6 -2
  166. package/dist/ai/recipes/nuxt/onboarding.md +30 -8
  167. package/dist/ai/recipes/nuxt/record-form.md +66 -22
  168. package/dist/ai/recipes/nuxt/records-workspace.md +199 -48
  169. package/dist/ai/recipes/nuxt/settings-workspace.md +3898 -0
  170. package/dist/ai/recipes/nuxt/upload-center.md +52 -41
  171. package/dist/ai/recipes/nuxt/wizard-form.md +98 -14
  172. package/dist/ai/recipes/vue/approvals-inbox.md +28 -12
  173. package/dist/ai/recipes/vue/command-palette.md +2 -2
  174. package/dist/ai/recipes/vue/inline-edit-workspace.md +69 -53
  175. package/dist/ai/recipes/vue/layout-scaffold.md +6 -2
  176. package/dist/ai/recipes/vue/onboarding.md +32 -8
  177. package/dist/ai/recipes/vue/record-form.md +81 -54
  178. package/dist/ai/recipes/vue/records-workspace.md +198 -49
  179. package/dist/ai/recipes/vue/settings-workspace.md +3836 -0
  180. package/dist/ai/recipes/vue/upload-center.md +53 -42
  181. package/dist/ai/recipes/vue/wizard-form.md +97 -14
  182. package/dist/ai/source/BbAccordion.md +90 -24
  183. package/dist/ai/source/BbAlert.md +209 -62
  184. package/dist/ai/source/BbAsterisk.md +54 -4
  185. package/dist/ai/source/BbAvatar.md +73 -16
  186. package/dist/ai/source/BbBadge.md +265 -97
  187. package/dist/ai/source/BbBadgeButton.md +218 -79
  188. package/dist/ai/source/BbBaseButton.md +108 -12
  189. package/dist/ai/source/BbBaseCheckboxIcon.md +151 -36
  190. package/dist/ai/source/BbBaseRadioIcon.md +121 -17
  191. package/dist/ai/source/BbBaseSwitchIcon.md +138 -28
  192. package/dist/ai/source/BbBreadcrumbs.md +363 -69
  193. package/dist/ai/source/BbButton.md +563 -174
  194. package/dist/ai/source/BbCalendar.md +1744 -0
  195. package/dist/ai/source/BbCheckbox.md +470 -68
  196. package/dist/ai/source/BbCheckboxGroup.md +976 -95
  197. package/dist/ai/source/BbCollapsible.md +96 -8
  198. package/dist/ai/source/BbColorInput.md +597 -67
  199. package/dist/ai/source/BbColorPalette.md +1284 -65
  200. package/dist/ai/source/BbConfirm.md +149 -7
  201. package/dist/ai/source/BbConfirmPortal.md +89 -3
  202. package/dist/ai/source/BbDatePicker.md +527 -381
  203. package/dist/ai/source/BbDatePickerInput.md +2015 -118
  204. package/dist/ai/source/BbDialog.md +531 -64
  205. package/dist/ai/source/BbDropdown.md +885 -175
  206. package/dist/ai/source/BbDropdownButton.md +377 -79
  207. package/dist/ai/source/BbDropdownGroup.md +687 -96
  208. package/dist/ai/source/BbDropzone.md +140 -31
  209. package/dist/ai/source/BbForm.md +875 -17
  210. package/dist/ai/source/BbIcon.md +130 -52
  211. package/dist/ai/source/BbIndicator.md +117 -60
  212. package/dist/ai/source/BbNumberInput.md +667 -84
  213. package/dist/ai/source/BbOffCanvas.md +1007 -261
  214. package/dist/ai/source/BbPagination.md +203 -31
  215. package/dist/ai/source/BbPopover.md +267 -90
  216. package/dist/ai/source/BbProgress.md +88 -26
  217. package/dist/ai/source/BbPtScope.md +54 -0
  218. package/dist/ai/source/BbRadio.md +388 -58
  219. package/dist/ai/source/BbRadioGroup.md +940 -109
  220. package/dist/ai/source/BbRating.md +736 -84
  221. package/dist/ai/source/BbSelect.md +1096 -96
  222. package/dist/ai/source/BbSelectPopover.md +807 -114
  223. package/dist/ai/source/BbSlider.md +1390 -98
  224. package/dist/ai/source/BbSmoothHeight.md +48 -2
  225. package/dist/ai/source/BbSpinner.md +62 -6
  226. package/dist/ai/source/BbSwitch.md +297 -60
  227. package/dist/ai/source/BbSwitchGroup.md +761 -83
  228. package/dist/ai/source/BbTable.md +6950 -1864
  229. package/dist/ai/source/BbTabs.md +368 -111
  230. package/dist/ai/source/BbTabsList.md +503 -146
  231. package/dist/ai/source/BbTabsPanels.md +625 -0
  232. package/dist/ai/source/BbTabsRoot.md +319 -100
  233. package/dist/ai/source/BbTag.md +796 -87
  234. package/dist/ai/source/BbTextInput.md +497 -68
  235. package/dist/ai/source/BbTextarea.md +550 -65
  236. package/dist/ai/source/BbTimePicker.md +395 -69
  237. package/dist/ai/source/BbTimePickerInput.md +1233 -106
  238. package/dist/ai/source/BbToast.md +250 -74
  239. package/dist/ai/source/BbToastPortal.md +210 -66
  240. package/dist/ai/source/BbTooltip.md +181 -30
  241. package/dist/ai/source/BbTree.md +76 -11
  242. package/dist/ai/source/ChipsBox.md +25 -5
  243. package/dist/ai/source/CommaBox.md +21 -6
  244. package/dist/ai/source/{BbBaseInputContainer.md → CommonField.md} +467 -250
  245. package/dist/ai/source/CommonFieldInput.md +848 -0
  246. package/dist/ai/source/CommonPopover.md +116 -30
  247. package/dist/ai/source/CommonTimeSelector.md +726 -0
  248. package/dist/ai/source/ErrorIcon.md +2 -2
  249. package/dist/ai/source/FlatListBox.md +188 -17
  250. package/dist/ai/source/GroupedListBox.md +236 -44
  251. package/dist/ai/source/GuidesComponent.md +14 -7
  252. package/dist/ai/source/ListBox.md +46 -8
  253. package/dist/ai/source/OptionsContainer.md +288 -60
  254. package/dist/ai/source/WarningIcon.md +2 -2
  255. package/dist/assets/css/reset.css_inline.js +1 -1
  256. package/dist/assets/svgs/star.svg_raw.js +4 -0
  257. package/dist/components/BbAccordion/BbAccordion.vue_vue_type_script_setup_true_lang.js +49 -32
  258. package/dist/components/BbAccordion/types.d.ts +35 -3
  259. package/dist/components/BbAccordion/types.js +11 -0
  260. package/dist/components/BbAlert/BbAlert.vue_vue_type_script_setup_true_lang.js +46 -30
  261. package/dist/components/BbAlert/types.d.ts +37 -3
  262. package/dist/components/BbAlert/types.js +13 -0
  263. package/dist/components/BbAsterisk/BbAsterisk.vue.d.ts +3 -1
  264. package/dist/components/BbAsterisk/BbAsterisk.vue_vue_type_script_setup_true_lang.js +23 -8
  265. package/dist/components/BbAsterisk/types.d.ts +18 -0
  266. package/dist/components/BbAsterisk/types.js +7 -0
  267. package/dist/components/BbAvatar/BbAvatar.vue.d.ts +1 -1
  268. package/dist/components/BbAvatar/BbAvatar.vue_vue_type_script_setup_true_lang.js +57 -44
  269. package/dist/components/BbAvatar/types.d.ts +23 -0
  270. package/dist/components/BbAvatar/types.js +7 -0
  271. package/dist/components/BbBadge/BadgeBodyContent.vue_vue_type_script_setup_true_lang.js +24 -18
  272. package/dist/components/BbBadge/BbBadge.vue_vue_type_script_setup_true_lang.js +96 -53
  273. package/dist/components/BbBadge/BbBadgeButton.vue_vue_type_script_setup_true_lang.js +27 -8
  274. package/dist/components/BbBadge/badgeButtonContext.d.ts +25 -8
  275. package/dist/components/BbBadge/types.d.ts +46 -3
  276. package/dist/components/BbBadge/types.js +13 -0
  277. package/dist/components/BbBaseButton/BbBaseButton.vue_vue_type_script_setup_true_lang.js +109 -96
  278. package/dist/components/BbBaseButton/RouterComponent.vue_vue_type_script_setup_true_lang.js +11 -11
  279. package/dist/components/BbBaseButton/types.d.ts +33 -3
  280. package/dist/components/BbBaseButton/types.js +9 -2
  281. package/dist/components/BbBaseCheckboxIcon/BbBaseCheckboxIcon.vue_vue_type_script_setup_true_lang.js +50 -18
  282. package/dist/components/BbBaseCheckboxIcon/types.d.ts +31 -2
  283. package/dist/components/BbBaseCheckboxIcon/types.js +8 -0
  284. package/dist/components/BbBaseRadioIcon/BbBaseRadioIcon.vue_vue_type_script_setup_true_lang.js +45 -15
  285. package/dist/components/BbBaseRadioIcon/types.d.ts +31 -2
  286. package/dist/components/BbBaseRadioIcon/types.js +8 -0
  287. package/dist/components/BbBaseSwitchIcon/BbBaseSwitchIcon.vue_vue_type_script_setup_true_lang.js +48 -16
  288. package/dist/components/BbBaseSwitchIcon/types.d.ts +31 -2
  289. package/dist/components/BbBaseSwitchIcon/types.js +8 -0
  290. package/dist/components/BbBreadcrumbs/BbBreadcrumbs.vue_vue_type_script_setup_true_lang.js +187 -132
  291. package/dist/components/BbBreadcrumbs/types.d.ts +45 -3
  292. package/dist/components/BbBreadcrumbs/types.js +12 -0
  293. package/dist/components/BbButton/BbButton.vue.d.ts +5 -0
  294. package/dist/components/BbButton/BbButton.vue_vue_type_script_setup_true_lang.js +107 -81
  295. package/dist/components/BbButton/types.d.ts +113 -2
  296. package/dist/components/BbButton/types.js +12 -0
  297. package/dist/components/BbCalendar/BbCalendar.vue.d.ts +34 -0
  298. package/dist/components/BbCalendar/BbCalendar.vue.js +6 -0
  299. package/dist/components/BbCalendar/BbCalendar.vue_vue_type_script_setup_true_lang.js +608 -0
  300. package/dist/components/BbCalendar/CalendarMonthPanel.vue.js +5 -0
  301. package/dist/components/BbCalendar/CalendarMonthPanel.vue_vue_type_script_setup_true_lang.js +124 -0
  302. package/dist/components/BbCalendar/CalendarYearPanel.vue.js +5 -0
  303. package/dist/components/BbCalendar/CalendarYearPanel.vue_vue_type_script_setup_true_lang.js +126 -0
  304. package/dist/components/BbCalendar/calendarHost.d.ts +29 -0
  305. package/dist/components/BbCalendar/calendarHost.js +10 -0
  306. package/dist/components/BbCalendar/types.d.ts +225 -0
  307. package/dist/components/BbCalendar/types.js +29 -0
  308. package/dist/components/{BbBaseDatePicker/useDatePickerContext.d.ts → BbCalendar/useCalendarContext.d.ts} +10 -7
  309. package/dist/components/BbCalendar/useCalendarContext.js +11 -0
  310. package/dist/components/BbCalendar/useCalendarGrid.d.ts +208 -0
  311. package/dist/components/BbCalendar/useCalendarGrid.js +274 -0
  312. package/dist/components/BbCalendar/useDayGrid.d.ts +79 -0
  313. package/dist/components/BbCalendar/useDayGrid.js +204 -0
  314. package/dist/components/BbCalendar/useToday.d.ts +23 -0
  315. package/dist/components/BbCalendar/useToday.js +21 -0
  316. package/dist/components/BbCheckbox/BbCheckbox.vue.d.ts +7 -7
  317. package/dist/components/BbCheckbox/BbCheckbox.vue_vue_type_script_setup_true_lang.js +214 -72
  318. package/dist/components/BbCheckbox/types.d.ts +180 -13
  319. package/dist/components/BbCheckbox/types.js +8 -0
  320. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue.d.ts +15 -3
  321. package/dist/components/BbCheckboxGroup/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +338 -90
  322. package/dist/components/BbCheckboxGroup/types.d.ts +195 -20
  323. package/dist/components/BbCheckboxGroup/types.js +10 -0
  324. package/dist/components/BbCollapsible/BbCollapsible.vue.d.ts +2 -1
  325. package/dist/components/BbCollapsible/BbCollapsible.vue_vue_type_script_setup_true_lang.js +41 -19
  326. package/dist/components/BbCollapsible/types.d.ts +44 -1
  327. package/dist/components/BbCollapsible/types.js +7 -0
  328. package/dist/components/BbColorInput/BbColorInput.vue.d.ts +17 -7
  329. package/dist/components/BbColorInput/BbColorInput.vue_vue_type_script_setup_true_lang.js +330 -86
  330. package/dist/components/BbColorInput/types.d.ts +230 -12
  331. package/dist/components/BbColorInput/types.js +24 -0
  332. package/dist/components/BbColorPalette/BbColorPalette.vue.d.ts +10 -2
  333. package/dist/components/BbColorPalette/BbColorPalette.vue_vue_type_script_setup_true_lang.js +515 -108
  334. package/dist/components/BbColorPalette/types.d.ts +76 -7
  335. package/dist/components/BbColorPalette/types.js +12 -0
  336. package/dist/components/BbConfirm/BbConfirm.vue.d.ts +2 -1
  337. package/dist/components/BbConfirm/BbConfirm.vue_vue_type_script_setup_true_lang.js +125 -76
  338. package/dist/components/BbConfirm/BbConfirmPortal.vue.d.ts +1 -0
  339. package/dist/components/BbConfirm/types.d.ts +49 -0
  340. package/dist/components/BbConfirm/types.js +17 -0
  341. package/dist/components/BbDatePicker/BbDatePicker.vue.d.ts +16 -10
  342. package/dist/components/BbDatePicker/BbDatePicker.vue_vue_type_script_setup_true_lang.js +320 -223
  343. package/dist/components/BbDatePicker/types.d.ts +111 -17
  344. package/dist/components/BbDatePicker/types.js +33 -0
  345. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue.d.ts +16 -4
  346. package/dist/components/BbDatePickerInput/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +1172 -87
  347. package/dist/components/BbDatePickerInput/types.d.ts +224 -19
  348. package/dist/components/BbDatePickerInput/types.js +39 -0
  349. package/dist/components/BbDialog/BbDialog.vue.d.ts +3 -3
  350. package/dist/components/BbDialog/BbDialog.vue_vue_type_script_setup_true_lang.js +227 -136
  351. package/dist/components/BbDialog/types.d.ts +92 -3
  352. package/dist/components/BbDialog/types.js +16 -0
  353. package/dist/components/BbDialog/useDialogStack.d.ts +12 -0
  354. package/dist/components/BbDialog/useDialogStack.js +9 -2
  355. package/dist/components/BbDropdown/AdaptiveDropdown.vue.d.ts +2 -0
  356. package/dist/components/BbDropdown/AdaptiveDropdown.vue_vue_type_script_setup_true_lang.js +108 -96
  357. package/dist/components/BbDropdown/BbDropdown.vue.d.ts +10 -2
  358. package/dist/components/BbDropdown/BbDropdown.vue_vue_type_script_setup_true_lang.js +337 -268
  359. package/dist/components/BbDropdown/BbDropdownGroup.vue.d.ts +5 -1
  360. package/dist/components/BbDropdown/BbDropdownList.vue.d.ts +8 -2
  361. package/dist/components/BbDropdown/BbDropdownList.vue_vue_type_script_setup_true_lang.js +377 -293
  362. package/dist/components/BbDropdown/DropdownPipelineResolver.vue_vue_type_script_setup_true_lang.js +129 -118
  363. package/dist/components/BbDropdown/normalizeGroups.js +55 -31
  364. package/dist/components/BbDropdown/types.d.ts +288 -30
  365. package/dist/components/BbDropdown/types.js +21 -2
  366. package/dist/components/BbDropdown/useDropdownContext.d.ts +10 -4
  367. package/dist/components/BbDropdown/useDropdownGroupRegistry.d.ts +1 -0
  368. package/dist/components/BbDropdownButton/BbDropdownButton.vue.d.ts +18 -3
  369. package/dist/components/BbDropdownButton/BbDropdownButton.vue_vue_type_script_setup_true_lang.js +172 -40
  370. package/dist/components/BbDropdownButton/types.d.ts +137 -8
  371. package/dist/components/BbDropdownButton/types.js +35 -0
  372. package/dist/components/BbDropzone/BbDropzone.vue.d.ts +2 -2
  373. package/dist/components/BbDropzone/BbDropzone.vue_vue_type_script_setup_true_lang.js +186 -144
  374. package/dist/components/BbDropzone/types.d.ts +38 -4
  375. package/dist/components/BbDropzone/types.js +16 -0
  376. package/dist/components/BbForm/BbForm.vue.d.ts +94 -0
  377. package/dist/{validated → components/BbForm}/BbForm.vue.js +1 -1
  378. package/dist/components/BbForm/BbForm.vue_vue_type_script_setup_true_lang.js +317 -0
  379. package/dist/components/BbForm/BbFormCustomField.d.ts +14 -0
  380. package/dist/components/BbForm/BbFormCustomField.js +43 -0
  381. package/dist/components/BbForm/bindFormField.d.ts +16 -0
  382. package/dist/components/BbForm/bindFormField.js +85 -0
  383. package/dist/components/BbForm/formFields.d.ts +64 -0
  384. package/dist/components/BbForm/formFields.js +11 -0
  385. package/dist/components/BbForm/formSchema.d.ts +56 -0
  386. package/dist/components/BbForm/formSchema.js +196 -0
  387. package/dist/components/BbForm/standardSchema.d.ts +59 -0
  388. package/dist/components/BbIcon/BbIcon.vue_vue_type_script_setup_true_lang.js +58 -48
  389. package/dist/components/BbIcon/iconCache.d.ts +63 -0
  390. package/dist/components/BbIcon/iconCache.js +35 -0
  391. package/dist/components/BbIcon/types.d.ts +22 -2
  392. package/dist/components/BbIcon/types.js +7 -0
  393. package/dist/components/BbIndicator/BbIndicator.vue_vue_type_script_setup_true_lang.js +34 -21
  394. package/dist/components/BbIndicator/types.d.ts +24 -0
  395. package/dist/components/BbIndicator/types.js +7 -0
  396. package/dist/components/BbNumberInput/BbNumberInput.vue.d.ts +12 -8
  397. package/dist/components/BbNumberInput/BbNumberInput.vue_vue_type_script_setup_true_lang.js +308 -85
  398. package/dist/components/BbNumberInput/types.d.ts +201 -18
  399. package/dist/components/BbNumberInput/types.js +8 -0
  400. package/dist/components/BbOffCanvas/BbOffCanvas.vue.d.ts +3 -3
  401. package/dist/components/BbOffCanvas/BbOffCanvas.vue_vue_type_script_setup_true_lang.js +311 -210
  402. package/dist/components/BbOffCanvas/types.d.ts +79 -6
  403. package/dist/components/BbOffCanvas/types.js +15 -0
  404. package/dist/components/BbPagination/BbPagination.vue.d.ts +2 -2
  405. package/dist/components/BbPagination/BbPagination.vue_vue_type_script_setup_true_lang.js +125 -90
  406. package/dist/components/BbPagination/types.d.ts +38 -0
  407. package/dist/components/BbPagination/types.js +13 -0
  408. package/dist/components/BbPopover/BbPopover.vue.d.ts +4 -4
  409. package/dist/components/BbPopover/BbPopover.vue_vue_type_script_setup_true_lang.js +219 -179
  410. package/dist/components/BbPopover/types.d.ts +51 -5
  411. package/dist/components/BbPopover/types.js +14 -0
  412. package/dist/components/BbProgress/BbProgress.vue_vue_type_script_setup_true_lang.js +29 -16
  413. package/dist/components/BbProgress/types.d.ts +25 -0
  414. package/dist/components/BbProgress/types.js +7 -0
  415. package/dist/components/BbPtScope/BbPtScope.vue.d.ts +12 -0
  416. package/dist/components/BbPtScope/BbPtScope.vue.js +5 -0
  417. package/dist/components/BbPtScope/BbPtScope.vue_vue_type_script_setup_true_lang.js +13 -0
  418. package/dist/components/BbPtScope/types.d.ts +15 -0
  419. package/dist/components/BbRadio/BbRadio.vue.d.ts +7 -7
  420. package/dist/components/BbRadio/BbRadio.vue_vue_type_script_setup_true_lang.js +172 -59
  421. package/dist/components/BbRadio/types.d.ts +152 -13
  422. package/dist/components/BbRadio/types.js +8 -0
  423. package/dist/components/BbRadioGroup/BbRadioGroup.vue.d.ts +14 -2
  424. package/dist/components/BbRadioGroup/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +319 -92
  425. package/dist/components/BbRadioGroup/types.d.ts +198 -22
  426. package/dist/components/BbRadioGroup/types.js +10 -0
  427. package/dist/components/BbRating/BbRating.vue.d.ts +10 -8
  428. package/dist/components/BbRating/BbRating.vue_vue_type_script_setup_true_lang.js +259 -78
  429. package/dist/components/BbRating/types.d.ts +174 -13
  430. package/dist/components/BbRating/types.js +21 -0
  431. package/dist/components/BbSelect/BbSelect.vue.d.ts +17 -3
  432. package/dist/components/BbSelect/BbSelect.vue_vue_type_script_setup_true_lang.js +553 -83
  433. package/dist/components/BbSelect/types.d.ts +235 -20
  434. package/dist/components/BbSelect/types.js +41 -0
  435. package/dist/components/BbSelectPopover/BbSelectPopover.vue.d.ts +15 -1
  436. package/dist/components/BbSelectPopover/BbSelectPopover.vue_vue_type_script_setup_true_lang.js +541 -391
  437. package/dist/components/BbSelectPopover/types.d.ts +124 -8
  438. package/dist/components/BbSelectPopover/types.js +24 -0
  439. package/dist/components/BbSlider/BbSlider.vue.d.ts +13 -8
  440. package/dist/components/BbSlider/BbSlider.vue_vue_type_script_setup_true_lang.js +472 -96
  441. package/dist/components/BbSlider/types.d.ts +202 -13
  442. package/dist/components/BbSlider/types.js +26 -0
  443. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue.d.ts +1 -1
  444. package/dist/components/BbSmoothHeight/BbSmoothHeight.vue_vue_type_script_setup_true_lang.js +60 -48
  445. package/dist/components/BbSmoothHeight/types.d.ts +19 -0
  446. package/dist/components/BbSmoothHeight/types.js +7 -0
  447. package/dist/components/BbSpinner/BbSpinner.vue_vue_type_script_setup_true_lang.js +27 -14
  448. package/dist/components/BbSpinner/types.d.ts +22 -1
  449. package/dist/components/BbSpinner/types.js +7 -0
  450. package/dist/components/BbSwitch/BbSwitch.vue.d.ts +7 -7
  451. package/dist/components/BbSwitch/BbSwitch.vue_vue_type_script_setup_true_lang.js +220 -78
  452. package/dist/components/BbSwitch/types.d.ts +25 -10
  453. package/dist/components/BbSwitch/types.js +5 -0
  454. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue.d.ts +14 -2
  455. package/dist/components/BbSwitchGroup/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +338 -90
  456. package/dist/components/BbSwitchGroup/types.d.ts +30 -7
  457. package/dist/components/BbSwitchGroup/types.js +5 -0
  458. package/dist/components/BbTable/BbTable.vue.d.ts +27 -6
  459. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +2013 -685
  460. package/dist/components/BbTable/BbTableDataRow.d.ts +196 -0
  461. package/dist/components/BbTable/BbTableDataRow.js +151 -0
  462. package/dist/components/BbTable/BbTableExpandRow.d.ts +84 -0
  463. package/dist/components/BbTable/BbTableExpandRow.js +62 -0
  464. package/dist/components/BbTable/BbTableSelectToggle.d.ts +120 -0
  465. package/dist/components/BbTable/BbTableSelectToggle.js +122 -0
  466. package/dist/components/BbTable/gridWidgets.d.ts +30 -0
  467. package/dist/components/BbTable/gridWidgets.js +14 -0
  468. package/dist/components/BbTable/types.d.ts +473 -123
  469. package/dist/components/BbTable/types.js +31 -0
  470. package/dist/components/BbTable/utils.d.ts +145 -4
  471. package/dist/components/BbTable/utils.js +154 -37
  472. package/dist/components/BbTabs/BbTabs.vue.d.ts +3 -1
  473. package/dist/components/BbTabs/BbTabs.vue_vue_type_script_setup_true_lang.js +62 -26
  474. package/dist/components/BbTabs/BbTabsList.vue.d.ts +3 -10
  475. package/dist/components/BbTabs/BbTabsList.vue_vue_type_script_setup_true_lang.js +143 -81
  476. package/dist/components/BbTabs/BbTabsPanels.vue.d.ts +12 -0
  477. package/dist/components/{BbBaseSwitch/BbBaseSwitch.vue.js → BbTabs/BbTabsPanels.vue.js} +2 -2
  478. package/dist/components/BbTabs/BbTabsPanels.vue_vue_type_script_setup_true_lang.js +59 -0
  479. package/dist/components/BbTabs/BbTabsRoot.vue.d.ts +3 -1
  480. package/dist/components/BbTabs/BbTabsRoot.vue_vue_type_script_setup_true_lang.js +2 -1
  481. package/dist/components/BbTabs/types.d.ts +183 -23
  482. package/dist/components/BbTabs/types.js +34 -0
  483. package/dist/components/BbTag/BbTag.vue.d.ts +13 -10
  484. package/dist/components/BbTag/BbTag.vue_vue_type_script_setup_true_lang.js +383 -92
  485. package/dist/components/BbTag/types.d.ts +139 -14
  486. package/dist/components/BbTag/types.js +22 -0
  487. package/dist/components/BbTextInput/BbTextInput.vue.d.ts +10 -8
  488. package/dist/components/BbTextInput/BbTextInput.vue_vue_type_script_setup_true_lang.js +257 -84
  489. package/dist/components/BbTextInput/types.d.ts +168 -13
  490. package/dist/components/BbTextInput/types.js +8 -0
  491. package/dist/components/BbTextarea/BbTextarea.vue.d.ts +7 -7
  492. package/dist/components/BbTextarea/BbTextarea.vue_vue_type_script_setup_true_lang.js +291 -94
  493. package/dist/components/BbTextarea/types.d.ts +158 -14
  494. package/dist/components/BbTextarea/types.js +8 -0
  495. package/dist/components/BbTimePicker/BbTimePicker.vue.d.ts +12 -4
  496. package/dist/components/BbTimePicker/BbTimePicker.vue_vue_type_script_setup_true_lang.js +199 -122
  497. package/dist/components/BbTimePicker/types.d.ts +94 -7
  498. package/dist/components/BbTimePicker/types.js +18 -0
  499. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue.d.ts +14 -4
  500. package/dist/components/BbTimePickerInput/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +749 -86
  501. package/dist/components/BbTimePickerInput/types.d.ts +171 -22
  502. package/dist/components/BbTimePickerInput/types.js +25 -0
  503. package/dist/components/BbToast/BbToast.vue_vue_type_script_setup_true_lang.js +63 -25
  504. package/dist/components/BbToast/BbToastMessage.vue.d.ts +4 -1
  505. package/dist/components/BbToast/BbToastMessage.vue_vue_type_script_setup_true_lang.js +79 -76
  506. package/dist/components/BbToast/BbToastPortal.vue.d.ts +1 -0
  507. package/dist/components/BbToast/BbToastRegion.vue.d.ts +4 -1
  508. package/dist/components/BbToast/BbToastRegion.vue_vue_type_script_setup_true_lang.js +72 -64
  509. package/dist/components/BbToast/types.d.ts +54 -1
  510. package/dist/components/BbToast/types.js +28 -0
  511. package/dist/components/BbTooltip/BbTooltip.vue_vue_type_script_setup_true_lang.js +104 -87
  512. package/dist/components/BbTooltip/types.d.ts +40 -2
  513. package/dist/components/BbTooltip/types.js +7 -0
  514. package/dist/components/BbTree/BbTree.vue.d.ts +15 -3
  515. package/dist/components/BbTree/BbTree.vue_vue_type_script_setup_true_lang.js +51 -29
  516. package/dist/components/BbTree/BbTreeLevel.vue.d.ts +1 -1
  517. package/dist/components/BbTree/BbTreeLevel.vue_vue_type_script_setup_true_lang.js +17 -16
  518. package/dist/components/BbTree/context.d.ts +9 -1
  519. package/dist/components/BbTree/types.d.ts +40 -5
  520. package/dist/components/BbTree/types.js +7 -0
  521. package/dist/components/ChipsBox/ChipsBox.vue_vue_type_script_setup_true_lang.js +46 -44
  522. package/dist/components/ChipsBox/types.d.ts +7 -0
  523. package/dist/components/ClearableButton/ClearableButton.vue_vue_type_script_setup_true_lang.js +5 -5
  524. package/dist/components/CommaBox/CommaBox.vue_vue_type_script_setup_true_lang.js +11 -7
  525. package/dist/components/CommaBox/types.d.ts +7 -0
  526. package/dist/components/{BbBaseInputContainer/BbBaseInputContainer.vue.d.ts → CommonField/CommonField.vue.d.ts} +5 -5
  527. package/dist/components/{BbBaseRadio/BbBaseRadio.vue.js → CommonField/CommonField.vue.js} +2 -2
  528. package/dist/components/CommonField/CommonField.vue_vue_type_script_setup_true_lang.js +189 -0
  529. package/dist/components/CommonField/messageHeightMatrix.d.ts +2 -0
  530. package/dist/components/{BbBaseInputContainer → CommonField}/types.d.ts +52 -16
  531. package/dist/components/{CommonInputWrapper/CommonInputWrapper.vue.d.ts → CommonFieldInput/CommonFieldInput.vue.d.ts} +5 -4
  532. package/dist/components/{BbBaseRadioGroup/BbBaseRadioGroup.vue.js → CommonFieldInput/CommonFieldInput.vue.js} +2 -2
  533. package/dist/components/CommonFieldInput/CommonFieldInput.vue_vue_type_script_setup_true_lang.js +120 -0
  534. package/dist/components/CommonFieldInput/boxBorderMatrix.d.ts +10 -0
  535. package/dist/components/{CommonInputWrapper → CommonFieldInput}/types.d.ts +27 -8
  536. package/dist/components/CommonPopover/CommonPopover.vue.d.ts +11 -2
  537. package/dist/components/CommonPopover/CommonPopover.vue_vue_type_script_setup_true_lang.js +76 -63
  538. package/dist/components/CommonPopover/types.d.ts +27 -8
  539. package/dist/components/{BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.d.ts → CommonTimeSelector/CommonTimeSelector.vue.d.ts} +21 -2
  540. package/dist/components/{BbBaseColorPalette/BbBaseColorPalette.vue.js → CommonTimeSelector/CommonTimeSelector.vue.js} +2 -2
  541. package/dist/components/CommonTimeSelector/CommonTimeSelector.vue_vue_type_script_setup_true_lang.js +232 -0
  542. package/dist/components/CommonTimeSelector/types.d.ts +6 -0
  543. package/dist/components/FlatListBox/FlatListBox.vue.d.ts +5 -1
  544. package/dist/components/FlatListBox/FlatListBox.vue_vue_type_script_setup_true_lang.js +165 -95
  545. package/dist/components/FlatListBox/types.d.ts +24 -2
  546. package/dist/components/GroupedListBox/GroupedListBox.vue.d.ts +5 -1
  547. package/dist/components/GroupedListBox/GroupedListBox.vue_vue_type_script_setup_true_lang.js +217 -134
  548. package/dist/components/GroupedListBox/types.d.ts +24 -2
  549. package/dist/components/ListBox/ListBox.vue.d.ts +5 -1
  550. package/dist/components/ListBox/ListBox.vue_vue_type_script_setup_true_lang.js +95 -69
  551. package/dist/components/ListBox/types.d.ts +24 -2
  552. package/dist/components/OptionsContainer/OptionsContainer.vue.d.ts +1 -1
  553. package/dist/components/OptionsContainer/OptionsContainer.vue_vue_type_script_setup_true_lang.js +109 -37
  554. package/dist/components/OptionsContainer/types.d.ts +53 -9
  555. package/dist/components/Transitions/ScaleFade.vue_vue_type_script_setup_true_lang.js +8 -8
  556. package/dist/components/Transitions/Slide.vue.js +1 -1
  557. package/dist/composables/useBaseOptions.d.ts +12 -1
  558. package/dist/composables/useBaseOptions.js +77 -37
  559. package/dist/composables/useBbConfig.d.ts +27 -6
  560. package/dist/composables/useBbConfig.js +8 -2
  561. package/dist/composables/useBbDropdownContext.d.ts +5 -0
  562. package/dist/composables/useBbFormContext.d.ts +131 -8
  563. package/dist/composables/useBbFormContext.js +49 -30
  564. package/dist/composables/useBbFormField.d.ts +40 -0
  565. package/dist/composables/useBbFormField.js +39 -0
  566. package/dist/composables/useBbTableContext.d.ts +45 -1
  567. package/dist/composables/useBbTableContext.js +93 -87
  568. package/dist/composables/useBbTabsContext.d.ts +15 -9
  569. package/dist/composables/useBbTabsContext.js +121 -90
  570. package/dist/composables/useClosingInert.d.ts +4 -4
  571. package/dist/composables/useCoarsePointer.js +7 -10
  572. package/dist/composables/useCoherence.js +1 -1
  573. package/dist/composables/useConfig.d.ts +59 -0
  574. package/dist/composables/useConfig.js +15 -0
  575. package/dist/composables/useConfirm.d.ts +39 -7
  576. package/dist/composables/useConfirm.js +50 -41
  577. package/dist/composables/useEscapeStackEntry.d.ts +13 -0
  578. package/dist/composables/useEscapeStackEntry.js +16 -0
  579. package/dist/composables/useFormBinding.d.ts +116 -0
  580. package/dist/composables/useFormBinding.js +34 -0
  581. package/dist/composables/useHydrated.d.ts +18 -0
  582. package/dist/composables/useHydrated.js +13 -7
  583. package/dist/composables/useId.d.ts +4 -3
  584. package/dist/composables/useId.js +1 -7
  585. package/dist/composables/useItemsGetter.d.ts +11 -0
  586. package/dist/composables/useItemsGetter.js +44 -18
  587. package/dist/composables/useKeyboardInset.d.ts +28 -0
  588. package/dist/composables/useKeyboardInset.js +32 -0
  589. package/dist/composables/useLocale.js +10 -7
  590. package/dist/composables/useMobile.js +7 -10
  591. package/dist/composables/usePassthrough.d.ts +228 -0
  592. package/dist/composables/usePassthrough.js +247 -0
  593. package/dist/composables/usePrefill.d.ts +22 -2
  594. package/dist/composables/usePrefill.js +35 -19
  595. package/dist/composables/useSafeAreaInternal.js +1 -1
  596. package/dist/composables/useSegmentedFields.d.ts +2 -2
  597. package/dist/composables/useSsrState.d.ts +20 -0
  598. package/dist/composables/useSsrState.js +13 -0
  599. package/dist/composables/useTableWidthContext.d.ts +24 -4
  600. package/dist/composables/useTableWidthContext.js +31 -28
  601. package/dist/composables/useToast.d.ts +18 -1
  602. package/dist/composables/useToast.js +31 -18
  603. package/dist/composables/useToggleInput.d.ts +44 -0
  604. package/dist/composables/useToggleInput.js +39 -0
  605. package/dist/composables/useViewportWidth.d.ts +5 -25
  606. package/dist/composables/useViewportWidth.js +14 -7
  607. package/dist/deprecation/ai-deprecations.json.d.ts +1977 -289
  608. package/dist/deprecation/ai-deprecations.json.js +1 -1
  609. package/dist/deprecation/removedProps.js +9 -4
  610. package/dist/directives/bbDropdown.d.ts +15 -4
  611. package/dist/directives/bbDropdown.js +31 -9
  612. package/dist/directives/bbTooltip.d.ts +6 -0
  613. package/dist/directives/createPopoverDirective.d.ts +62 -0
  614. package/dist/directives/createPopoverDirective.js +92 -37
  615. package/dist/i18n/index.d.ts +10 -16
  616. package/dist/i18n/locales/cs.json +9 -5
  617. package/dist/i18n/locales/da.json +9 -5
  618. package/dist/i18n/locales/de.json +9 -5
  619. package/dist/i18n/locales/el.json +9 -5
  620. package/dist/i18n/locales/en.json +9 -5
  621. package/dist/i18n/locales/es.json +9 -5
  622. package/dist/i18n/locales/fi.json +9 -5
  623. package/dist/i18n/locales/fr.json +9 -5
  624. package/dist/i18n/locales/hu.json +9 -5
  625. package/dist/i18n/locales/it.json +9 -5
  626. package/dist/i18n/locales/ja.json +9 -5
  627. package/dist/i18n/locales/ko.json +9 -5
  628. package/dist/i18n/locales/nb.json +9 -5
  629. package/dist/i18n/locales/nl.json +9 -5
  630. package/dist/i18n/locales/pl.json +9 -5
  631. package/dist/i18n/locales/pt.json +9 -5
  632. package/dist/i18n/locales/ro.json +9 -5
  633. package/dist/i18n/locales/ru.json +9 -5
  634. package/dist/i18n/locales/sv.json +9 -5
  635. package/dist/i18n/locales/tr.json +9 -5
  636. package/dist/i18n/locales/uk.json +9 -5
  637. package/dist/i18n/locales/zh-cn.json +9 -5
  638. package/dist/icon-scan.d.ts +276 -0
  639. package/dist/icon-scan.js +485 -0
  640. package/dist/icons-whitelist.d.ts +5 -4
  641. package/dist/index.d.ts +40 -21
  642. package/dist/index.js +78 -71
  643. package/dist/llms-full.txt +61164 -27972
  644. package/dist/llms-medium.txt +1482 -366
  645. package/dist/llms.txt +32 -15
  646. package/dist/locale-blueprint.json +9 -5
  647. package/dist/nuxt-auto-imports.d.ts +76 -0
  648. package/dist/nuxt-auto-imports.js +32 -0
  649. package/dist/nuxt-module.d.ts +30 -15
  650. package/dist/nuxt.js +35 -9
  651. package/dist/passthrough-deduper.js +5 -0
  652. package/dist/plugin.d.ts +10 -1
  653. package/dist/plugin.js +29 -19
  654. package/dist/project-dts.d.ts +84 -0
  655. package/dist/project-dts.js +170 -0
  656. package/dist/reset.css +1 -1
  657. package/dist/runtime/nuxt-plugin.js +34 -21
  658. package/dist/styles.css +3 -2
  659. package/dist/types/AlertVariant.d.ts +10 -1
  660. package/dist/types/BadgeVariant.d.ts +16 -5
  661. package/dist/types/ButtonVariant.d.ts +12 -1
  662. package/dist/types/ColumnName.d.ts +30 -3
  663. package/dist/types/CommonProps.d.ts +2 -2
  664. package/dist/types/Config.d.ts +94 -1
  665. package/dist/types/ConfirmVariant.d.ts +8 -1
  666. package/dist/types/DropdownItemVariant.d.ts +8 -1
  667. package/dist/types/FieldLayout.d.ts +32 -0
  668. package/dist/types/IndicatorVariant.d.ts +11 -1
  669. package/dist/types/InputVariant.d.ts +30 -0
  670. package/dist/types/ItemProps.d.ts +50 -0
  671. package/dist/types/Option.d.ts +6 -0
  672. package/dist/types/PtScope.d.ts +15 -0
  673. package/dist/types/RegistryKey.d.ts +10 -0
  674. package/dist/types/TabsVariant.d.ts +25 -0
  675. package/dist/types/ToastVariant.d.ts +12 -2
  676. package/dist/types/TooltipVariant.d.ts +8 -1
  677. package/dist/types/passthrough.d.ts +362 -0
  678. package/dist/types/passthrough.js +78 -0
  679. package/dist/types/ptComponentMap.d.ts +62 -0
  680. package/dist/utilities/functions/hasVnodeListener.d.ts +16 -0
  681. package/dist/utilities/functions/hasVnodeListener.js +12 -0
  682. package/dist/utilities/functions/isImeComposing.d.ts +7 -0
  683. package/dist/utilities/functions/isImeComposing.js +4 -0
  684. package/dist/utilities/functions/itemProps.d.ts +46 -0
  685. package/dist/utilities/functions/itemProps.js +47 -0
  686. package/dist/utilities/functions/slotKey.d.ts +13 -8
  687. package/dist/utilities/functions/slotKey.js +78 -2
  688. package/dist/utilities/functions/snapToStep.js +2 -1
  689. package/dist/utilities/functions/toggleInput.d.ts +98 -0
  690. package/dist/utilities/functions/toggleInput.js +56 -0
  691. package/dist/utilities/functions/warnRemovedAttrs.d.ts +27 -1
  692. package/dist/utilities/functions/warnRemovedAttrs.js +75 -14
  693. package/dist/utilities/misc/listboxMetrics.d.ts +9 -3
  694. package/dist/utilities/misc/listboxMetrics.js +5 -2
  695. package/dist/utilities/misc/ssrStateInjectionKey.d.ts +42 -0
  696. package/dist/utilities/misc/ssrStateInjectionKey.js +4 -0
  697. package/dist/utils/cssLayers.d.ts +91 -0
  698. package/dist/utils/cssLayers.js +43 -0
  699. package/dist/utils/injectLibraryStyles.d.ts +3 -1
  700. package/dist/utils/injectLibraryStyles.js +24 -23
  701. package/dist/utils/overlayEscapeStack.d.ts +10 -0
  702. package/dist/utils/overlayEscapeStack.js +5 -3
  703. package/dist/utils/passthrough.d.ts +67 -0
  704. package/dist/utils/passthrough.js +100 -0
  705. package/dist/utils/passthroughDeduper.d.ts +2 -0
  706. package/dist/utils/ptScope.d.ts +8 -0
  707. package/dist/utils/ptScope.js +4 -0
  708. package/dist/utils/versionCheck.d.ts +19 -0
  709. package/dist/utils/versionCheck.js +18 -0
  710. package/dist/vite-plugin.d.ts +301 -53
  711. package/dist/vite.js +547 -375
  712. package/llms.txt +33 -16
  713. package/package.json +49 -27
  714. package/scripts/lib/check-fix.mjs +129 -0
  715. package/scripts/lib/component-attr-targets.ts +123 -0
  716. package/scripts/lib/component-tree.ts +648 -0
  717. package/scripts/lib/css-class-check.mjs +326 -0
  718. package/scripts/lib/css-class-surface.mjs +292 -0
  719. package/scripts/lib/css-color-resolve.mjs +172 -0
  720. package/scripts/lib/css-local-check.mjs +267 -0
  721. package/scripts/lib/design-token-manifest.mjs +499 -0
  722. package/scripts/lib/doc-sections.mjs +248 -0
  723. package/scripts/lib/ensure-manifest.mjs +28 -5
  724. package/scripts/lib/eslint-disable.mjs +141 -0
  725. package/scripts/lib/eslint-plugin.d.ts +64 -1
  726. package/scripts/lib/eslint-plugin.mjs +1285 -30
  727. package/scripts/lib/hand-imported-styles.mjs +326 -0
  728. package/scripts/lib/hand-roll-hints.mjs +50 -6
  729. package/scripts/lib/html-attributes.mjs +353 -0
  730. package/scripts/lib/local-components.mjs +177 -0
  731. package/scripts/lib/mcp-config.mjs +87 -58
  732. package/scripts/lib/migrate-fix.mjs +62 -3
  733. package/scripts/lib/project-variant-dts.mjs +122 -0
  734. package/scripts/lib/public-type-exports.mjs +273 -0
  735. package/scripts/lib/slot-key.mjs +147 -0
  736. package/scripts/lib/slot-renames.mjs +46 -0
  737. package/scripts/lib/squashed-slot-words.mjs +133 -0
  738. package/scripts/lib/validate-bb-markup.mjs +2213 -76
  739. package/scripts/lib/wrapper-props.mjs +188 -0
  740. package/dist/ai/BbBaseCheckbox.md +0 -49
  741. package/dist/ai/BbBaseCheckboxGroup.md +0 -64
  742. package/dist/ai/BbBaseColorInput.md +0 -65
  743. package/dist/ai/BbBaseColorPalette.md +0 -39
  744. package/dist/ai/BbBaseDatePicker.md +0 -43
  745. package/dist/ai/BbBaseDatePickerInput.md +0 -73
  746. package/dist/ai/BbBaseInputContainer.md +0 -48
  747. package/dist/ai/BbBaseNumberInput.md +0 -71
  748. package/dist/ai/BbBaseRadio.md +0 -46
  749. package/dist/ai/BbBaseRadioGroup.md +0 -64
  750. package/dist/ai/BbBaseRating.md +0 -52
  751. package/dist/ai/BbBaseSelect.md +0 -88
  752. package/dist/ai/BbBaseSlider.md +0 -56
  753. package/dist/ai/BbBaseSwitch.md +0 -49
  754. package/dist/ai/BbBaseSwitchGroup.md +0 -64
  755. package/dist/ai/BbBaseTag.md +0 -68
  756. package/dist/ai/BbBaseTextInput.md +0 -75
  757. package/dist/ai/BbBaseTextarea.md +0 -62
  758. package/dist/ai/BbBaseTimePickerInput.md +0 -62
  759. package/dist/ai/BbTabsPanes.md +0 -27
  760. package/dist/ai/CommonInputWrapper.md +0 -42
  761. package/dist/ai/source/BbBaseCheckbox.md +0 -461
  762. package/dist/ai/source/BbBaseCheckboxGroup.md +0 -554
  763. package/dist/ai/source/BbBaseColorInput.md +0 -431
  764. package/dist/ai/source/BbBaseColorPalette.md +0 -942
  765. package/dist/ai/source/BbBaseDatePicker.md +0 -1448
  766. package/dist/ai/source/BbBaseDatePickerInput.md +0 -1940
  767. package/dist/ai/source/BbBaseNumberInput.md +0 -617
  768. package/dist/ai/source/BbBaseRadio.md +0 -381
  769. package/dist/ai/source/BbBaseRadioGroup.md +0 -539
  770. package/dist/ai/source/BbBaseRating.md +0 -607
  771. package/dist/ai/source/BbBaseSelect.md +0 -945
  772. package/dist/ai/source/BbBaseSlider.md +0 -1144
  773. package/dist/ai/source/BbBaseSwitch.md +0 -246
  774. package/dist/ai/source/BbBaseSwitchGroup.md +0 -302
  775. package/dist/ai/source/BbBaseTag.md +0 -694
  776. package/dist/ai/source/BbBaseTextInput.md +0 -511
  777. package/dist/ai/source/BbBaseTextarea.md +0 -504
  778. package/dist/ai/source/BbBaseTimePickerInput.md +0 -1037
  779. package/dist/ai/source/BbTabsPanes.md +0 -377
  780. package/dist/ai/source/CommonInputWrapper.md +0 -584
  781. package/dist/alert-variants.d.ts +0 -19
  782. package/dist/assets/svgs/sort.svg_raw.js +0 -4
  783. package/dist/badge-variants.d.ts +0 -19
  784. package/dist/button-variants.d.ts +0 -21
  785. package/dist/components/BbBadge/BadgeAppendIcon.vue.d.ts +0 -3
  786. package/dist/components/BbBadge/BadgeAppendIcon.vue.js +0 -5
  787. package/dist/components/BbBadge/BadgeAppendIcon.vue_vue_type_script_setup_true_lang.js +0 -22
  788. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.d.ts +0 -40
  789. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue.js +0 -6
  790. package/dist/components/BbBaseCheckbox/BbBaseCheckbox.vue_vue_type_script_setup_true_lang.js +0 -145
  791. package/dist/components/BbBaseCheckbox/types.d.ts +0 -224
  792. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.d.ts +0 -19
  793. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue.js +0 -6
  794. package/dist/components/BbBaseCheckboxGroup/BbBaseCheckboxGroup.vue_vue_type_script_setup_true_lang.js +0 -190
  795. package/dist/components/BbBaseCheckboxGroup/types.d.ts +0 -257
  796. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.d.ts +0 -43
  797. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue.js +0 -6
  798. package/dist/components/BbBaseColorInput/BbBaseColorInput.vue_vue_type_script_setup_true_lang.js +0 -184
  799. package/dist/components/BbBaseColorInput/types.d.ts +0 -219
  800. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue.d.ts +0 -13
  801. package/dist/components/BbBaseColorPalette/BbBaseColorPalette.vue_vue_type_script_setup_true_lang.js +0 -395
  802. package/dist/components/BbBaseColorPalette/types.d.ts +0 -40
  803. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue.d.ts +0 -20
  804. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue.js +0 -6
  805. package/dist/components/BbBaseDatePicker/BbBaseDatePicker.vue_vue_type_script_setup_true_lang.js +0 -407
  806. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.d.ts +0 -47
  807. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue.js +0 -5
  808. package/dist/components/BbBaseDatePicker/BbBaseDatePickerInputDaySelector.vue_vue_type_script_setup_true_lang.js +0 -318
  809. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.js +0 -5
  810. package/dist/components/BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue_vue_type_script_setup_true_lang.js +0 -115
  811. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.js +0 -5
  812. package/dist/components/BbBaseDatePicker/BbBaseDatePickerYearSelector.vue_vue_type_script_setup_true_lang.js +0 -116
  813. package/dist/components/BbBaseDatePicker/types.d.ts +0 -108
  814. package/dist/components/BbBaseDatePicker/useDatePickerContext.js +0 -11
  815. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.d.ts +0 -31
  816. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue.js +0 -6
  817. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerInput.vue_vue_type_script_setup_true_lang.js +0 -737
  818. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue.js +0 -6
  819. package/dist/components/BbBaseDatePickerInput/BbBaseDatePickerTimeSelector.vue_vue_type_script_setup_true_lang.js +0 -204
  820. package/dist/components/BbBaseDatePickerInput/types.d.ts +0 -325
  821. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue.js +0 -6
  822. package/dist/components/BbBaseInputContainer/BbBaseInputContainer.vue_vue_type_script_setup_true_lang.js +0 -190
  823. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.d.ts +0 -52
  824. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue.js +0 -6
  825. package/dist/components/BbBaseNumberInput/BbBaseNumberInput.vue_vue_type_script_setup_true_lang.js +0 -215
  826. package/dist/components/BbBaseNumberInput/types.d.ts +0 -211
  827. package/dist/components/BbBaseRadio/BbBaseRadio.vue.d.ts +0 -33
  828. package/dist/components/BbBaseRadio/BbBaseRadio.vue_vue_type_script_setup_true_lang.js +0 -113
  829. package/dist/components/BbBaseRadio/types.d.ts +0 -179
  830. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue.d.ts +0 -19
  831. package/dist/components/BbBaseRadioGroup/BbBaseRadioGroup.vue_vue_type_script_setup_true_lang.js +0 -179
  832. package/dist/components/BbBaseRadioGroup/types.d.ts +0 -223
  833. package/dist/components/BbBaseRating/BbBaseRating.vue.d.ts +0 -38
  834. package/dist/components/BbBaseRating/BbBaseRating.vue.js +0 -6
  835. package/dist/components/BbBaseRating/BbBaseRating.vue_vue_type_script_setup_true_lang.js +0 -192
  836. package/dist/components/BbBaseRating/types.d.ts +0 -176
  837. package/dist/components/BbBaseSelect/BbBaseSelect.vue.d.ts +0 -19
  838. package/dist/components/BbBaseSelect/BbBaseSelect.vue.js +0 -6
  839. package/dist/components/BbBaseSelect/BbBaseSelect.vue_vue_type_script_setup_true_lang.js +0 -311
  840. package/dist/components/BbBaseSelect/types.d.ts +0 -297
  841. package/dist/components/BbBaseSlider/BbBaseSlider.vue.d.ts +0 -35
  842. package/dist/components/BbBaseSlider/BbBaseSlider.vue.js +0 -6
  843. package/dist/components/BbBaseSlider/BbBaseSlider.vue_vue_type_script_setup_true_lang.js +0 -340
  844. package/dist/components/BbBaseSlider/types.d.ts +0 -200
  845. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue.d.ts +0 -35
  846. package/dist/components/BbBaseSwitch/BbBaseSwitch.vue_vue_type_script_setup_true_lang.js +0 -146
  847. package/dist/components/BbBaseSwitch/types.d.ts +0 -10
  848. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.d.ts +0 -19
  849. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue.js +0 -6
  850. package/dist/components/BbBaseSwitchGroup/BbBaseSwitchGroup.vue_vue_type_script_setup_true_lang.js +0 -190
  851. package/dist/components/BbBaseSwitchGroup/types.d.ts +0 -8
  852. package/dist/components/BbBaseTag/BbBaseTag.vue.d.ts +0 -50
  853. package/dist/components/BbBaseTag/BbBaseTag.vue.js +0 -6
  854. package/dist/components/BbBaseTag/BbBaseTag.vue_vue_type_script_setup_true_lang.js +0 -266
  855. package/dist/components/BbBaseTag/types.d.ts +0 -160
  856. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.d.ts +0 -45
  857. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue.js +0 -6
  858. package/dist/components/BbBaseTextInput/BbBaseTextInput.vue_vue_type_script_setup_true_lang.js +0 -200
  859. package/dist/components/BbBaseTextInput/types.d.ts +0 -209
  860. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.d.ts +0 -39
  861. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue.js +0 -6
  862. package/dist/components/BbBaseTextarea/BbBaseTextarea.vue_vue_type_script_setup_true_lang.js +0 -187
  863. package/dist/components/BbBaseTextarea/types.d.ts +0 -170
  864. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.d.ts +0 -27
  865. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue.js +0 -6
  866. package/dist/components/BbBaseTimePickerInput/BbBaseTimePickerInput.vue_vue_type_script_setup_true_lang.js +0 -519
  867. package/dist/components/BbBaseTimePickerInput/types.d.ts +0 -151
  868. package/dist/components/BbTabs/BbTabsPanes.vue.d.ts +0 -16
  869. package/dist/components/BbTabs/BbTabsPanes.vue.js +0 -6
  870. package/dist/components/BbTabs/BbTabsPanes.vue_vue_type_script_setup_true_lang.js +0 -35
  871. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue.js +0 -6
  872. package/dist/components/CommonInputWrapper/CommonInputWrapper.vue_vue_type_script_setup_true_lang.js +0 -107
  873. package/dist/confirm-variants.d.ts +0 -17
  874. package/dist/dropdown-item-variants.d.ts +0 -17
  875. package/dist/indicator-variants.d.ts +0 -20
  876. package/dist/locale-registry.d.ts +0 -37
  877. package/dist/toast-variants.d.ts +0 -20
  878. package/dist/tooltip-variants.d.ts +0 -17
  879. package/dist/types/InputDirection.d.ts +0 -15
  880. package/dist/validated/BbCheckbox.vue.d.ts +0 -29
  881. package/dist/validated/BbCheckbox.vue.js +0 -5
  882. package/dist/validated/BbCheckbox.vue_vue_type_script_setup_true_lang.js +0 -75
  883. package/dist/validated/BbCheckboxGroup.vue.d.ts +0 -34
  884. package/dist/validated/BbCheckboxGroup.vue.js +0 -5
  885. package/dist/validated/BbCheckboxGroup.vue_vue_type_script_setup_true_lang.js +0 -82
  886. package/dist/validated/BbColorInput.vue.d.ts +0 -37
  887. package/dist/validated/BbColorInput.vue.js +0 -5
  888. package/dist/validated/BbColorInput.vue_vue_type_script_setup_true_lang.js +0 -75
  889. package/dist/validated/BbDatePickerInput.vue.d.ts +0 -41
  890. package/dist/validated/BbDatePickerInput.vue.js +0 -5
  891. package/dist/validated/BbDatePickerInput.vue_vue_type_script_setup_true_lang.js +0 -90
  892. package/dist/validated/BbDropzone.vue.d.ts +0 -24
  893. package/dist/validated/BbDropzone.vue.js +0 -5
  894. package/dist/validated/BbDropzone.vue_vue_type_script_setup_true_lang.js +0 -45
  895. package/dist/validated/BbForm.vue.d.ts +0 -28
  896. package/dist/validated/BbForm.vue_vue_type_script_setup_true_lang.js +0 -42
  897. package/dist/validated/BbNumberInput.vue.d.ts +0 -36
  898. package/dist/validated/BbNumberInput.vue.js +0 -5
  899. package/dist/validated/BbNumberInput.vue_vue_type_script_setup_true_lang.js +0 -72
  900. package/dist/validated/BbRadioGroup.vue.d.ts +0 -34
  901. package/dist/validated/BbRadioGroup.vue.js +0 -5
  902. package/dist/validated/BbRadioGroup.vue_vue_type_script_setup_true_lang.js +0 -78
  903. package/dist/validated/BbRating.vue.d.ts +0 -30
  904. package/dist/validated/BbRating.vue.js +0 -5
  905. package/dist/validated/BbRating.vue_vue_type_script_setup_true_lang.js +0 -63
  906. package/dist/validated/BbSelect.vue.d.ts +0 -46
  907. package/dist/validated/BbSelect.vue.js +0 -5
  908. package/dist/validated/BbSelect.vue_vue_type_script_setup_true_lang.js +0 -109
  909. package/dist/validated/BbSlider.vue.d.ts +0 -36
  910. package/dist/validated/BbSlider.vue.js +0 -5
  911. package/dist/validated/BbSlider.vue_vue_type_script_setup_true_lang.js +0 -69
  912. package/dist/validated/BbSwitch.vue.d.ts +0 -29
  913. package/dist/validated/BbSwitch.vue.js +0 -5
  914. package/dist/validated/BbSwitch.vue_vue_type_script_setup_true_lang.js +0 -75
  915. package/dist/validated/BbSwitchGroup.vue.d.ts +0 -34
  916. package/dist/validated/BbSwitchGroup.vue.js +0 -5
  917. package/dist/validated/BbSwitchGroup.vue_vue_type_script_setup_true_lang.js +0 -82
  918. package/dist/validated/BbTag.vue.d.ts +0 -36
  919. package/dist/validated/BbTag.vue.js +0 -5
  920. package/dist/validated/BbTag.vue_vue_type_script_setup_true_lang.js +0 -72
  921. package/dist/validated/BbTextInput.vue.d.ts +0 -36
  922. package/dist/validated/BbTextInput.vue.js +0 -5
  923. package/dist/validated/BbTextInput.vue_vue_type_script_setup_true_lang.js +0 -72
  924. package/dist/validated/BbTextarea.vue.d.ts +0 -36
  925. package/dist/validated/BbTextarea.vue.js +0 -5
  926. package/dist/validated/BbTextarea.vue_vue_type_script_setup_true_lang.js +0 -70
  927. package/dist/validated/BbTimePickerInput.vue.d.ts +0 -37
  928. package/dist/validated/BbTimePickerInput.vue.js +0 -5
  929. package/dist/validated/BbTimePickerInput.vue_vue_type_script_setup_true_lang.js +0 -81
  930. package/dist/validated/index.d.ts +0 -43
  931. package/dist/validated/useValidatedField.d.ts +0 -93
  932. package/dist/validated/useValidatedField.js +0 -51
  933. package/dist/validated.js +0 -21
  934. /package/dist/components/{BbBaseDatePicker/BbBaseDatePickerMonthSelector.vue.d.ts → BbCalendar/CalendarMonthPanel.vue.d.ts} +0 -0
  935. /package/dist/components/{BbBaseDatePicker/BbBaseDatePickerYearSelector.vue.d.ts → BbCalendar/CalendarYearPanel.vue.d.ts} +0 -0
  936. /package/dist/{components/BbBaseDatePicker/typeahead.d.ts → composables/useTypeahead.d.ts} +0 -0
  937. /package/dist/{components/BbBaseDatePicker/typeahead.js → composables/useTypeahead.js} +0 -0
@@ -25,7 +25,8 @@
25
25
  * is stable across zod 3 and 4, so the lower bound costs nothing.
26
26
  *
27
27
  * Run standalone: `npx bitboss-ui mcp` (delegated from bin/bitboss-ui.mjs).
28
- * Register with an MCP-capable harness via `npx bitboss-ui ai-init --mcp`.
28
+ * Registered with every MCP-capable harness by `npx bitboss-ui ai-init`
29
+ * (on by default; `--no-mcp` skips it).
29
30
  */
30
31
 
31
32
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
@@ -34,8 +35,17 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs';
34
35
  import { dirname, join, sep } from 'node:path';
35
36
  import { fileURLToPath } from 'node:url';
36
37
  import { z } from 'zod';
38
+ import {
39
+ frontmatter,
40
+ outline,
41
+ pickSections,
42
+ searchSections,
43
+ splitSections,
44
+ stripFrontmatter,
45
+ } from '../scripts/lib/doc-sections.mjs';
37
46
  import {
38
47
  loadManifest,
48
+ possessive,
39
49
  validateVueSnippet,
40
50
  } from '../scripts/lib/validate-bb-markup.mjs';
41
51
 
@@ -70,26 +80,217 @@ function getManifestMap() {
70
80
  return cachedManifestMap;
71
81
  }
72
82
 
73
- /** `search_components({ query })` — substring match over name/description. */
83
+ /** `search_components({ query })` — token match over name/description. */
74
84
  const SEARCH_DEFAULT_LIMIT = 20;
75
85
 
76
86
  /**
77
- * Relevance score for one component against a lowercased needle. Higher wins;
87
+ * Ranking for the manifest's type tiers. `api` types are the ones an app is
88
+ * expected to reach for — they appear in a component's own props or events —
89
+ * so they lead. `wrapper` (`<Component>Props`) matters only when wrapping one
90
+ * of our components, and `advanced` is registries, contexts and adapters.
91
+ * Publishing 166 exports as a flat list made every one look equally important.
92
+ */
93
+ const TYPE_USAGE_RANK = { api: 0, wrapper: 1, advanced: 2 };
94
+
95
+ /**
96
+ * WHY THIS IS NOT A PLAIN SUBSTRING MATCH ANY MORE.
97
+ *
98
+ * It was, and a consumer pilot (2026-09-09) hand-rolled three components the
99
+ * library ships because the whole query string had to appear verbatim in one
100
+ * field. `table` found BbTable; `data table` — the term most of the industry
101
+ * uses — found NOTHING, because no name or description contains that exact
102
+ * pair. Same for `command palette`, `stepper wizard`, `skeleton loading`.
103
+ *
104
+ * An empty result is the worst possible answer for a tool whose stated job is
105
+ * "find the right Bb* component before writing usage code": it is
106
+ * indistinguishable from "nothing here, build it yourself". So two things
107
+ * changed. Multi-word queries are TOKENISED, and every search — hit or miss —
108
+ * consults the component picker's "Not in this library" table, which is where
109
+ * the authoritative answers for the invented names already lived.
110
+ */
111
+
112
+ /** English filler that would otherwise match half the corpus on its own. */
113
+ const SEARCH_STOPWORDS = new Set([
114
+ 'a',
115
+ 'an',
116
+ 'the',
117
+ 'and',
118
+ 'or',
119
+ 'not',
120
+ 'no',
121
+ 'is',
122
+ 'it',
123
+ 'in',
124
+ 'on',
125
+ 'for',
126
+ 'of',
127
+ 'to',
128
+ 'with',
129
+ 'component',
130
+ 'components',
131
+ 'ui',
132
+ 'view',
133
+ 'widget',
134
+ 'element',
135
+ ]);
136
+
137
+ /**
138
+ * `'data table view'` → `['data', 'table']`. Order is not significant.
139
+ *
140
+ * Names arrive as tags and identifiers too (review D6-6): `bb-select` used to
141
+ * return all 60 components on the token `bb`, and `BbCheckboxIcon` nothing.
142
+ * So a CamelCase word is also split into its words, the joined word loses a
143
+ * leading `bb`, and a bare `bb` is dropped.
144
+ */
145
+ function tokenize(query) {
146
+ const raw = String(query ?? '')
147
+ .split(/[^A-Za-z0-9]+/)
148
+ .filter(Boolean)
149
+ .flatMap((word) => {
150
+ const lower = word.toLowerCase();
151
+ const parts = word
152
+ .replace(/^Bb(?=[A-Z])/, '')
153
+ .split(/(?<=[a-z0-9])(?=[A-Z])/)
154
+ .map((part) => part.toLowerCase());
155
+ return [
156
+ lower.replace(/^bb(?=.)/, ''),
157
+ ...(parts.length > 1 ? parts : []),
158
+ ];
159
+ })
160
+ .filter((token) => token && token !== 'bb');
161
+ const meaningful = [...new Set(raw)].filter((t) => !SEARCH_STOPWORDS.has(t));
162
+ // An all-stopword query ('the view') still deserves its literal reading
163
+ // rather than an empty token list that matches everything.
164
+ return meaningful.length > 0 ? meaningful : raw;
165
+ }
166
+
167
+ /**
168
+ * Relevance score for one component against ONE lowercased token. Higher wins;
78
169
  * 0 means "no match". Name hits always outrank description hits so
79
170
  * `search_components({ query: 'table' })` leads with BbTable, not with every
80
171
  * component whose prose mentions a table.
81
172
  */
82
- function scoreComponent(component, needle) {
173
+ function scoreToken(component, needle) {
83
174
  const name = component.name.toLowerCase();
84
175
  const description = (component.description ?? '').toLowerCase();
85
176
  if (name === needle) return 100;
86
177
  if (name === `bb${needle}`) return 95; // 'button' → BbButton
87
178
  if (name.startsWith(needle) || name.startsWith(`bb${needle}`)) return 80;
88
179
  if (name.includes(needle)) return 60;
89
- if (description.includes(needle)) return 30;
180
+ // Descriptions match at a WORD START, never mid-word: a plain substring made
181
+ // 'not' hit "notification" and returned four components for a nonsense
182
+ // query. Trailing suffixes still count, so 'card' finds "cards".
183
+ if (new RegExp(`\\b${needle}`).test(description)) return 30;
90
184
  return 0;
91
185
  }
92
186
 
187
+ /**
188
+ * Score against every token. A component that matches MORE of the query ranks
189
+ * above one that matches a single token harder, so `data table` puts BbTable
190
+ * (both tokens) above a component whose description merely says "data".
191
+ */
192
+ function scoreComponent(component, tokens) {
193
+ let total = 0;
194
+ let matched = 0;
195
+ for (const token of tokens) {
196
+ const score = scoreToken(component, token);
197
+ if (score > 0) {
198
+ matched += 1;
199
+ total += score;
200
+ }
201
+ }
202
+ return matched === 0 ? { matched: 0, score: 0 } : { matched, score: total };
203
+ }
204
+
205
+ /**
206
+ * The picker's "Not in this library" table, parsed from the shipped guide so
207
+ * there is exactly one source of truth. Rows carry both kinds of answer:
208
+ * redirects (`BbDrawer` → "It is BbOffCanvas") and verdicts (`BbCard` → "Does
209
+ * not exist — a card is a <div> with tokens"). Both are better answers to a
210
+ * miss than an empty array.
211
+ */
212
+ const PICKER_PATH = join(AI_ROOT, 'guides', 'component-picker.md');
213
+ let cachedNotInLibrary = null;
214
+
215
+ /** `'BbDataTable'` → `['bbdatatable', 'data', 'table']`. */
216
+ function aliasTokens(cell) {
217
+ const words = cell
218
+ .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1') // links → their text
219
+ .replace(/[`*_]/g, '')
220
+ .split(/[^A-Za-z0-9]+/)
221
+ .filter(Boolean);
222
+ const tokens = new Set();
223
+ for (const word of words) {
224
+ tokens.add(word.toLowerCase());
225
+ // Split CamelCase so `BbDataTable` is reachable by 'data' and 'table'.
226
+ for (const part of word.replace(/^Bb/, '').split(/(?=[A-Z])/))
227
+ if (part.length > 1) tokens.add(part.toLowerCase());
228
+ }
229
+ return [...tokens].filter((t) => !SEARCH_STOPWORDS.has(t) && t !== 'bb');
230
+ }
231
+
232
+ function loadNotInLibrary() {
233
+ if (cachedNotInLibrary) return cachedNotInLibrary;
234
+ cachedNotInLibrary = [];
235
+ if (!existsSync(PICKER_PATH)) return cachedNotInLibrary;
236
+ const md = readFileSync(PICKER_PATH, 'utf-8');
237
+ const section = md.split(/^## Not in this library\s*$/m)[1];
238
+ if (!section) return cachedNotInLibrary;
239
+ for (const line of section.split('\n')) {
240
+ if (!line.startsWith('|')) continue;
241
+ // Tolerate a missing trailing `|`: markdown renders such a row fine, so
242
+ // dropping it here would silently lose an answer (it already did once).
243
+ const cells = line
244
+ .replace(/^\|/, '')
245
+ .replace(/\|\s*$/, '')
246
+ .split('|');
247
+ if (cells.length < 2) continue;
248
+ const assumed = cells[0].trim();
249
+ const reality = cells[1].trim();
250
+ // Skip the header and its `---` separator.
251
+ if (!assumed || /^-+$/.test(assumed) || /^Assumed\b/i.test(assumed))
252
+ continue;
253
+ cachedNotInLibrary.push({
254
+ assumed,
255
+ reality,
256
+ tokens: aliasTokens(assumed),
257
+ // The names the row is ABOUT: `BbSkeleton` → 'skeleton'.
258
+ names: [...assumed.matchAll(/`(\w+)`/g)].map(([, name]) =>
259
+ name.toLowerCase().replace(/^(bb|use)(?=.)/, '')
260
+ ),
261
+ });
262
+ }
263
+ return cachedNotInLibrary;
264
+ }
265
+
266
+ /**
267
+ * Picker rows the query is about. A row matches when the query names the
268
+ * row's own component (`skeleton loading` → BbSkeleton, `drawer` → BbDrawer),
269
+ * or when every word of a multi-word query is in the row (`data table`),
270
+ * counting a shared 6-letter stem (`scheduler` / `scheduling`). One shared
271
+ * generic word is not enough any more: 'text input' answered with the
272
+ * rich-text-editor verdict as "the authoritative answer", 'tab' with the
273
+ * cross-tab live-feed row (review D6-7).
274
+ */
275
+ function matchNotInLibrary(tokens) {
276
+ if (!tokens.length) return [];
277
+ const covers = (row, token) =>
278
+ row.tokens.some(
279
+ (t) =>
280
+ t === token ||
281
+ (t.length >= 6 &&
282
+ token.length >= 6 &&
283
+ t.slice(0, 6) === token.slice(0, 6))
284
+ );
285
+ return loadNotInLibrary()
286
+ .filter(
287
+ (row) =>
288
+ tokens.some((t) => row.names.includes(t)) ||
289
+ (tokens.length > 1 && tokens.every((t) => covers(row, t)))
290
+ )
291
+ .map((row) => ({ assumed: row.assumed, reality: row.reality }));
292
+ }
293
+
93
294
  function searchComponents({ query, limit, includeReferenceOnly } = {}) {
94
295
  const manifest = loadComponentsManifest();
95
296
  const needle = String(query ?? '')
@@ -104,13 +305,88 @@ function searchComponents({ query, limit, includeReferenceOnly } = {}) {
104
305
  ? manifest.components
105
306
  : manifest.components.filter((c) => !c.referenceOnly);
106
307
 
308
+ // No query: the catalog, one line per component (review D6-19) — the
309
+ // answer to "which components exist?", which no tool gave before.
310
+ if (!needle || needle === '*') {
311
+ return {
312
+ query: query ?? '',
313
+ count: pool.length,
314
+ catalog: pool.map((c) => `${c.name} (${c.group}): ${c.description}`),
315
+ hint: 'The whole consumer catalog. get_component({ name }) for one; search_components({ query }) to rank by a need.',
316
+ };
317
+ }
318
+
319
+ const tokens = tokenize(needle);
320
+ const notInLibrary = matchNotInLibrary(tokens);
321
+
322
+ // A matched picker row NAMES the real component ("`BbDrawer` / `BbSheet` →
323
+ // It is BbOffCanvas"). Rank those first: the picker knows the answer, and
324
+ // returning nothing for `drawer` while BbOffCanvas ships is the whole bug.
325
+ const redirected = new Set();
326
+ for (const { reality } of notInLibrary)
327
+ for (const name of reality.match(/\bBb[A-Z][A-Za-z]+/g) ?? [])
328
+ redirected.add(name);
329
+
107
330
  const scored = pool
108
- .map((c) => ({ c, score: scoreComponent(c, needle) }))
331
+ .map((c) => {
332
+ const base = scoreComponent(c, tokens);
333
+ const bonus = redirected.has(c.name) ? 90 : 0;
334
+ return bonus > 0
335
+ ? { c, matched: base.matched + 1, score: base.score + bonus }
336
+ : { c, ...base };
337
+ })
109
338
  .filter(({ score }) => score > 0)
110
- // Ties break alphabetically so results are stable between calls.
111
- .sort((a, b) => b.score - a.score || a.c.name.localeCompare(b.c.name));
339
+ // More of the query matched wins first; then strength; then alphabetical
340
+ // so results are stable between calls.
341
+ .sort(
342
+ (a, b) =>
343
+ b.matched - a.matched ||
344
+ b.score - a.score ||
345
+ a.c.name.localeCompare(b.c.name)
346
+ );
112
347
 
113
348
  const shown = scored.slice(0, max);
349
+
350
+ // Internal components an exact search would have found (review D6-15):
351
+ // 'CommonPopover' answered "No manifest match" although it is in the
352
+ // manifest, only filtered out as reference-only.
353
+ const hiddenReferenceOnly = includeReferenceOnly
354
+ ? []
355
+ : manifest.components
356
+ .filter((c) => c.referenceOnly)
357
+ .filter((c) => scoreComponent(c, tokens).score >= 80)
358
+ .map((c) => c.name);
359
+
360
+ /**
361
+ * Public type exports whose name matches the query. Scored the same way as
362
+ * a component name (exact, prefix, substring) but never mixed into the
363
+ * component list — a type is not something you render, and ranking it
364
+ * beside components is how it gets written as a tag.
365
+ */
366
+ const matchedTypes = (manifest.types ?? [])
367
+ .filter((type) => {
368
+ const lower = type.name.toLowerCase();
369
+ return tokens.some(
370
+ (token) => lower === token || lower.includes(token.toLowerCase())
371
+ );
372
+ })
373
+ // `api` first: those are the types you meet writing markup. The rest are
374
+ // wrapper props and internals, which rank below anything you would use.
375
+ .sort((a, b) => TYPE_USAGE_RANK[a.usage] - TYPE_USAGE_RANK[b.usage])
376
+ .slice(0, max)
377
+ .map((type) => ({
378
+ name: type.name,
379
+ kind: 'type',
380
+ usage: type.usage,
381
+ component: type.component,
382
+ ...(type.deprecated ? { deprecated: true } : {}),
383
+ ...(type.replacedBy ? { replacedBy: type.replacedBy } : {}),
384
+ usedBy: type.usedBy ?? [],
385
+ // The short answer only; get_component(name) has the definition.
386
+ ...(type.values ? { values: type.values } : {}),
387
+ import: `import type { ${type.replacedBy ?? type.name} } from 'bitboss-ui';`,
388
+ }));
389
+
114
390
  return {
115
391
  query: query ?? '',
116
392
  count: shown.length,
@@ -128,6 +404,30 @@ function searchComponents({ query, limit, includeReferenceOnly } = {}) {
128
404
  referenceOnly: Boolean(c.referenceOnly),
129
405
  contract: c.contract,
130
406
  })),
407
+ // Authoritative answers for names agents invent. Present on hits too: a
408
+ // `card` query that ranks BbBaseButton (its description mentions cards)
409
+ // still needs the picker's verdict that there is no BbCard.
410
+ ...(notInLibrary.length > 0 ? { notInLibrary } : {}),
411
+ // A query that names a public TYPE gets it back as a type, so the answer
412
+ // to "is BbTableColumn a thing" is never an empty component list. The
413
+ // consumer who hit this concluded the export was undocumented and
414
+ // allowlisted the tag.
415
+ ...(matchedTypes.length > 0 ? { types: matchedTypes } : {}),
416
+ ...(hiddenReferenceOnly.length
417
+ ? {
418
+ hiddenReferenceOnly,
419
+ referenceOnlyHint:
420
+ 'Internal building blocks, not consumer API: never write them in a template. Use the ranked components; pass includeReferenceOnly: true only to read how one works.',
421
+ }
422
+ : {}),
423
+ guidance:
424
+ notInLibrary.length > 0
425
+ ? 'The `notInLibrary` entries are the authoritative answer for this query — prefer them over the ranked components, and do not hand-roll what they redirect you to.'
426
+ : shown.length > 0
427
+ ? 'Ranked by relevance. Confirm props with `get_component` before writing usage code.'
428
+ : matchedTypes.length > 0
429
+ ? 'No component matches, but `types` does: these are TYPE exports. Import one for the value you pass to the prop named in its `usedBy` — never write it as a tag, and never allowlist it.'
430
+ : 'No manifest match and no picker entry. Zero results does NOT mean "not covered" — search a single plain noun (`table`, not `data table`), then read the guide `component-picker` (its "Not in this library" table is the full list of names that do not exist and what to use instead) before building anything by hand.',
131
431
  };
132
432
  }
133
433
 
@@ -176,16 +476,297 @@ function truncateMarkdown(text, maxChars, readHint) {
176
476
  };
177
477
  }
178
478
 
179
- function getComponent({ name, maxChars } = {}) {
479
+ /**
480
+ * Names an agent brings from v2, from an older beta or from habit, mapped to
481
+ * what replaced them. Parsed from the shipped docs so there is one source of
482
+ * truth: the v2 → v3 guide's § 5.1 component table, and changelog rows that
483
+ * say "BbX is renamed BbY". Without it `get_component('BbChip')` answered
484
+ * "unknown component" although the guide had the exact answer (review D6-5).
485
+ */
486
+ let cachedRetired = null;
487
+ function loadRetired() {
488
+ if (cachedRetired) return cachedRetired;
489
+ cachedRetired = new Map();
490
+ const guidePath = join(AI_ROOT, 'guides', 'migration', 'v2-to-v3.md');
491
+ if (existsSync(guidePath)) {
492
+ const md = readFileSync(guidePath, 'utf-8');
493
+ const table = md.split(/^### 5\.1 .*$/m)[1]?.split(/^### /m)[0] ?? '';
494
+ for (const line of table.split('\n')) {
495
+ if (!line.startsWith('|')) continue;
496
+ const [was, now, todo] = line
497
+ .replace(/^\|/, '')
498
+ .replace(/\|\s*$/, '')
499
+ .split('|')
500
+ .map((cell) => cell.trim());
501
+ if (!was || !now || /^-+$/.test(was) || was === 'v2') continue;
502
+ for (const [, retired] of was.matchAll(/`(\w+)`/g)) {
503
+ cachedRetired.set(retired, {
504
+ now: now.replace(/\*\*/g, ''),
505
+ todo: (todo ?? '').replace(/\*\*/g, '').split(/(?<=\.)\s/)[0],
506
+ guide: 'migration/v2-to-v3.md',
507
+ section: '5.1 Components renamed, split, or removed',
508
+ });
509
+ }
510
+ }
511
+ }
512
+ if (existsSync(CHANGELOG_PATH)) {
513
+ const doc = JSON.parse(readFileSync(CHANGELOG_PATH, 'utf-8'));
514
+ for (const row of doc.breaking ?? []) {
515
+ const match = String(row.description ?? '').match(
516
+ /\b(Bb[A-Z]\w+) is renamed (Bb[A-Z]\w+)/
517
+ );
518
+ if (match && !cachedRetired.has(match[1])) {
519
+ cachedRetired.set(match[1], {
520
+ now: `\`${match[2]}\``,
521
+ todo: row.description.split(/(?<=\.)\s|—/)[0].trim(),
522
+ guide: row.guide ?? null,
523
+ firstReleasedIn: row.firstReleasedIn ?? null,
524
+ });
525
+ }
526
+ }
527
+ }
528
+ return cachedRetired;
529
+ }
530
+
531
+ /** `bb-date-picker-input` → `BbDatePickerInput`; `button` → `Button`. */
532
+ const pascal = (value) =>
533
+ String(value ?? '')
534
+ .split(/[^A-Za-z0-9]+/)
535
+ .filter(Boolean)
536
+ .map((part) => part[0].toUpperCase() + part.slice(1))
537
+ .join('');
538
+
539
+ /** Levenshtein distance, small inputs only. */
540
+ function editDistance(a, b) {
541
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
542
+ for (let i = 1; i <= a.length; i += 1) {
543
+ let previous = row[0];
544
+ row[0] = i;
545
+ for (let j = 1; j <= b.length; j += 1) {
546
+ const current = row[j];
547
+ row[j] = Math.min(
548
+ row[j] + 1,
549
+ row[j - 1] + 1,
550
+ previous + (a[i - 1] === b[j - 1] ? 0 : 1)
551
+ );
552
+ previous = current;
553
+ }
554
+ }
555
+ return row[b.length];
556
+ }
557
+
558
+ /**
559
+ * Find the component an agent meant. Exact first; then the spellings agents
560
+ * really send — `bb-button`, `bbbutton`, `Button` (review D6-2) — before
561
+ * giving up with the nearest names.
562
+ */
563
+ function resolveComponent(manifest, name) {
564
+ const raw = String(name ?? '').trim();
565
+ const exact = manifest.components.find((c) => c.name === raw);
566
+ if (exact) return { entry: exact };
567
+ const byLower = new Map(
568
+ manifest.components.map((c) => [c.name.toLowerCase(), c])
569
+ );
570
+ const candidates = [raw, pascal(raw)].flatMap((value) => [
571
+ value.toLowerCase(),
572
+ `bb${value.toLowerCase().replace(/^bb/, '')}`,
573
+ ]);
574
+ for (const candidate of candidates) {
575
+ const hit = byLower.get(candidate);
576
+ if (hit) return { entry: hit, resolvedFrom: raw };
577
+ }
578
+ return null;
579
+ }
580
+
581
+ function nearestComponents(manifest, name, count = 3) {
582
+ const needle = pascal(name).toLowerCase().replace(/^bb/, '');
583
+ return manifest.components
584
+ .filter((c) => !c.referenceOnly)
585
+ .map((c) => ({
586
+ name: c.name,
587
+ distance: editDistance(needle, c.name.toLowerCase().replace(/^bb/, '')),
588
+ }))
589
+ .sort((a, b) => a.distance - b.distance)
590
+ .slice(0, count)
591
+ .filter(({ distance }) => distance <= Math.max(3, needle.length / 2))
592
+ .map(({ name: found }) => found);
593
+ }
594
+
595
+ /**
596
+ * A component whose props are generic over its ROW (`BbTableProps<Row>`,
597
+ * `BbSelectProps<Item>`): a prop type names the parameter `T`.
598
+ */
599
+ const isGeneric = (entry) =>
600
+ entry.props.some((p) =>
601
+ /(^|[^A-Za-z0-9_])T([^A-Za-z0-9_]|$)/.test(p.type ?? '')
602
+ );
603
+
604
+ const propsType = (entry) =>
605
+ `${entry.name}Props${isGeneric(entry) ? '<Row>' : ''}['pt']`;
606
+
607
+ /** `row: '…', 'row:selected': '…'` — the object form, from the real parts. */
608
+ function ptExample(entry) {
609
+ const names = entry.pt.parts.map((p) => p.name);
610
+ const part =
611
+ ['row', 'option', 'item', 'icon', 'label'].find((n) => names.includes(n)) ??
612
+ names[0];
613
+ // A state that is on for this part: per-node states name their parts.
614
+ const state = (
615
+ entry.pt.states?.find((s) =>
616
+ new RegExp(`\`${part}\``).test(s.description ?? '')
617
+ ) ??
618
+ entry.pt.states?.find((s) => /^Component-wide/.test(s.description ?? ''))
619
+ )?.name;
620
+ return `${part}: '…'${state ? `, '${part}:${state}': '…'` : ''}`;
621
+ }
622
+
623
+ const PT_TYPING_READ =
624
+ "get_guide({ name: 'passthrough.md', sections: ['Typing `pt` in `<script>`'] })";
625
+
626
+ function ptTyping(entry) {
627
+ // Both after-bench misses (2026-09-24) typed a table-agnostic preset
628
+ // `BbTableProps<any>['pt']`: say what to write when there is no row type.
629
+ const anyRow = isGeneric(entry)
630
+ ? ` (\`${entry.name}Props['pt']\` for a preset that fits any row type, never \`<any>\`)`
631
+ : '';
632
+ return `In <script> (a const, a preset, a wrapper's \`pt\` prop) type it as \`${propsType(entry)}\`${anyRow} with \`satisfies\` for a const; a split global map uses \`definePt\` from 'bitboss-ui/vite'. PtValue / PtMap are not exported. ${PT_TYPING_READ}`;
633
+ }
634
+
635
+ /**
636
+ * The next reads a component answer points at, each one call. Built from what
637
+ * the contract itself links, so it cannot name a guide the package lacks.
638
+ */
639
+ function seeAlso(entry, contract) {
640
+ const out = [];
641
+ // The option-list family links the items playbook; its wrapper section is
642
+ // where "write a MemberSelect around BbSelect" is answered (Q52.6.1).
643
+ if (/options-items-playbook\.md/.test(contract) && isGeneric(entry))
644
+ out.push(
645
+ `Your own ${entry.name} with fixed items (a CustomerSelect): a preset, one call to definePreset (a helper you copy from the guide, not a bitboss-ui export): get_guide({ name: 'preset-components.md' }). Wrapping BbSelect in your own component with its own logic: get_guide({ name: 'options-items-playbook.md', sections: ['Wrapping BbSelect in your own component'] })`
646
+ );
647
+ if (entry.validated)
648
+ out.push(
649
+ `Validation (rules or a Zod / Valibot / Yup schema): get_guide({ name: 'validated-forms.md' })`
650
+ );
651
+ return out;
652
+ }
653
+
654
+ /** Guide sections of a contract: everything under `## Usage & Guidelines`. */
655
+ function contractGuideSections(markdown) {
656
+ const all = splitSections(markdown);
657
+ const start = all.findIndex(
658
+ (s) => s.level === 2 && /^Usage & Guidelines/i.test(s.title)
659
+ );
660
+ if (start === -1) return [];
661
+ const end = all.findIndex((s, i) => i > start && s.level === 2);
662
+ return all.slice(start + 1, end === -1 ? undefined : end);
663
+ }
664
+
665
+ /** Sections every agent needs, served whole in the default answer. */
666
+ const ALWAYS_SECTIONS = [/^gotchas/i, /^accessibility/i];
667
+
668
+ /**
669
+ * `get_component({ name, sections?, include?, maxChars? })`.
670
+ *
671
+ * COMPACT BY DEFAULT (release review 2026-09-23, D6-4). The old answer was
672
+ * the manifest entry plus the whole contract cut at 40 000 chars: 76–101 KB,
673
+ * and the cut dropped `Gotchas` on six components while the tail it kept
674
+ * repeated the structured entry. Blind Haiku answerers could not read it and
675
+ * guessed. Now the default is the structured entry (props never cut — a
676
+ * partial prop list is what makes agents invent API) minus the parts that
677
+ * repeat it (`pt:*` prop rows: the `pt` section lists every part and state),
678
+ * the guide's outline, and its Gotchas + Accessibility sections. Guide
679
+ * sections, the component tree, the CSS variables with their descriptions
680
+ * and the whole contract come on request.
681
+ */
682
+ function getComponent({ name, sections, include, maxChars } = {}) {
180
683
  const manifest = loadComponentsManifest();
181
- const entry = manifest.components.find((c) => c.name === name);
684
+ const resolved = resolveComponent(manifest, name);
685
+ const entry = resolved?.entry;
182
686
  if (!entry) {
687
+ /*
688
+ * A public TYPE asked for as a component. `BbTableColumn`,
689
+ * `BbDropdownItem`, `BbTabsItem` and `BbBreadcrumbsItem` are exports an
690
+ * agent meets in a props table and reasonably looks up here; answering
691
+ * "unknown component — try search_components" sent one consumer to the
692
+ * `allowComponents` allowlist instead, which silences every check on the
693
+ * tag. Answer the real question: what it is, and where it is used.
694
+ */
695
+ const type = (manifest.types ?? []).find((t) => t.name === name);
696
+ if (type) {
697
+ const use = type.usedBy?.[0];
698
+ return {
699
+ found: true,
700
+ kind: 'type',
701
+ name,
702
+ usage: type.usage,
703
+ ...(type.deprecated ? { deprecated: true } : {}),
704
+ ...(type.replacedBy ? { replacedBy: type.replacedBy } : {}),
705
+ component: type.component,
706
+ usedBy: type.usedBy ?? [],
707
+ // What it is (Q50.2): the declaration, the accepted values when
708
+ // finite (open when `extensibleVia` names a registry), and the
709
+ // resolved fields when the declaration leans on a private type.
710
+ ...(type.definition ? { definition: type.definition } : {}),
711
+ ...(type.values ? { values: type.values } : {}),
712
+ ...(type.extensibleVia ? { extensibleVia: type.extensibleVia } : {}),
713
+ ...(type.fields ? { fields: type.fields } : {}),
714
+ // A union of private members: each member's fields (Q51.21).
715
+ ...(type.members ? { members: type.members } : {}),
716
+ import: `import type { ${type.replacedBy ?? name} } from 'bitboss-ui';`,
717
+ hint: use
718
+ ? `A type, not a component: it types ${possessive(use.component)} \`${use.name}\` ${use.surface}. \`definition\` above is the type itself; call get_component('${use.component}') to see it in use.`
719
+ : 'A type, not a component — import it for the value you pass, never write it as a tag.',
720
+ };
721
+ }
722
+ // A directive (`v-bb-tooltip`, `vBbTooltip`) — review D3-13.
723
+ const directiveName = String(name ?? '')
724
+ .trim()
725
+ .replace(/^vBb([A-Z]\w*)$/, (_, word) => `v-bb-${word.toLowerCase()}`)
726
+ .toLowerCase();
727
+ const directive = (manifest.directives ?? []).find(
728
+ (d) => d.name === directiveName
729
+ );
730
+ if (directive) {
731
+ const value = (manifest.types ?? []).find(
732
+ (t) => t.name === directive.value
733
+ );
734
+ return {
735
+ found: true,
736
+ kind: 'directive',
737
+ ...directive,
738
+ ...(value?.definition ? { valueDefinition: value.definition } : {}),
739
+ ...(value?.fields ? { valueFields: value.fields } : {}),
740
+ hint: `A directive, the floating twin of ${directive.mirrors}: read get_component({ name: '${directive.mirrors}', sections: ['directive'] }) for its guide section.`,
741
+ };
742
+ }
743
+ const retired = loadRetired().get(String(name ?? '').trim());
744
+ if (retired) {
745
+ return {
746
+ found: false,
747
+ name,
748
+ retired: true,
749
+ now: retired.now,
750
+ todo: retired.todo,
751
+ guide: retired.guide,
752
+ ...(retired.section ? { section: retired.section } : {}),
753
+ hint: `\`${name}\` is not in this version. \`now\` says what replaced it; read get_guide({ name: '${retired.guide}'${retired.section ? `, sections: ['${retired.section}']` : ''} }) for the full row.`,
754
+ };
755
+ }
756
+ const picker = matchNotInLibrary(tokenize(name));
757
+ const didYouMean = nearestComponents(manifest, name);
183
758
  return {
184
759
  found: false,
185
760
  name,
186
- hint: 'Unknown component name — try search_components first.',
761
+ ...(didYouMean.length ? { didYouMean } : {}),
762
+ ...(picker.length ? { notInLibrary: picker.slice(0, 3) } : {}),
763
+ hint: picker.length
764
+ ? "Not a component here — `notInLibrary` is the picker's verdict for this name."
765
+ : 'Unknown component name. Try one of `didYouMean`, or search_components with a plain noun.',
187
766
  };
188
767
  }
768
+
769
+ const wanted = new Set(include ?? []);
189
770
  const contractPath = entry.contract ?? null;
190
771
  const contractAbsPath = contractPath
191
772
  ? join(PACKAGE_ROOT, 'dist', contractPath)
@@ -193,19 +774,143 @@ function getComponent({ name, maxChars } = {}) {
193
774
  const raw =
194
775
  contractAbsPath && existsSync(contractAbsPath)
195
776
  ? readFileSync(contractAbsPath, 'utf-8')
196
- : null;
197
- const { content, ...meta } = truncateMarkdown(
198
- raw,
199
- maxChars,
200
- `The structured \`component\` field above is COMPLETE (all props/events/slots) — the cut text is guidance prose only.`
777
+ : '';
778
+ const guide = contractGuideSections(raw);
779
+
780
+ /*
781
+ * The types this component's own API names, so "what do I import to build
782
+ * the value for `columns`?" is answered where the question is asked. Without
783
+ * it an agent reads `BbTableColumn<T>[]` in the props table and has nowhere
784
+ * to go — one consumer concluded the export was undocumented and allowlisted
785
+ * the tag. Only types the component actually uses, never the whole export
786
+ * list: a menu is not an answer.
787
+ */
788
+ const types = (manifest.types ?? [])
789
+ .filter((type) =>
790
+ (type.usedBy ?? []).some((use) => use.component === entry.name)
791
+ )
792
+ .filter((type) => !type.deprecated)
793
+ .map((type) => ({
794
+ name: type.name,
795
+ usedBy: (type.usedBy ?? []).filter((use) => use.component === entry.name),
796
+ import: `import type { ${type.name} } from 'bitboss-ui';`,
797
+ ...(type.values ? { values: type.values } : {}),
798
+ ...(type.extensibleVia ? { extensibleVia: type.extensibleVia } : {}),
799
+ ...(type.fields ? { fields: type.fields } : {}),
800
+ // The union's shape, then what each private member takes (Q51.21).
801
+ ...(!type.values && !type.fields && type.definition
802
+ ? { definition: type.definition }
803
+ : {}),
804
+ ...(type.members ? { members: type.members } : {}),
805
+ }));
806
+
807
+ const ptRows = entry.props.filter(
808
+ (p) => p.name === 'pt' || p.name.startsWith('pt:')
809
+ );
810
+ const component = {
811
+ ...entry,
812
+ props: (wanted.has('ptProps')
813
+ ? entry.props
814
+ : entry.props.filter((p) => !ptRows.includes(p))
815
+ ).map(({ required, ...prop }) => (required ? { ...prop, required } : prop)),
816
+ ...(entry.cssProps && !wanted.has('cssProps')
817
+ ? { cssProps: entry.cssProps.map((c) => c.name ?? c) }
818
+ : {}),
819
+ };
820
+ if (!wanted.has('tree')) delete component.tree;
821
+ // The rendered `.bb-*` classes (Q46.5) are for tools (`check`, `validate`);
822
+ // an agent restyles through pt and the locals. include: ['css'] lists them.
823
+ if (!wanted.has('css')) delete component.css;
824
+ // `removed` and `renamed` repeat each other with migration metadata; one
825
+ // line per old name answers "what happened to X" (include 'history' for
826
+ // the records the fixers use).
827
+ if (
828
+ !wanted.has('history') &&
829
+ (entry.removed?.length || entry.renamed?.length)
830
+ ) {
831
+ const renamedFrom = new Set((entry.renamed ?? []).map((r) => r.from));
832
+ // A slot row reads as a slot (`#no-data → #empty`), a removal with no
833
+ // single successor carries its hint (Q51.16).
834
+ const spell = (r, name) => (r.surface === 'slot' ? `#${name}` : name);
835
+ // A rename that also maps VALUES says which: `inputDirection →
836
+ // listLayout` alone sent 2 of 3 answerers to `list-layout="vertical"`
837
+ // when the map is vertical → vertical-stretch (2026-09-24).
838
+ const values = (r) =>
839
+ Object.entries(r.fix?.valueMap ?? {})
840
+ .filter(([from, to]) => from !== to)
841
+ .map(([from, to]) => `"${from}" → "${to}"`)
842
+ .join(', ');
843
+ component.history = [
844
+ ...(entry.renamed ?? []).map(
845
+ (r) =>
846
+ `${spell(r, r.from)} → ${spell(r, r.to)}${r.fix?.kind && r.fix.kind !== 'rename' ? ` (${r.fix.kind})` : ''}${values(r) ? ` (values: ${values(r)})` : ''}`
847
+ ),
848
+ ...(entry.removed ?? [])
849
+ .filter((r) => !renamedFrom.has(r.name))
850
+ .map(
851
+ (r) =>
852
+ `${spell(r, r.name)} removed${r.new ? ` → ${spell(r, r.new)}` : ''}${r.hint ? ` — ${r.hint}` : ''}`
853
+ ),
854
+ ];
855
+ delete component.removed;
856
+ delete component.renamed;
857
+ }
858
+
859
+ const { picked, missing } = pickSections(guide, sections);
860
+ const always = guide.filter(
861
+ (s) => ALWAYS_SECTIONS.some((re) => re.test(s.title)) && !picked.includes(s)
201
862
  );
863
+ const contract = wanted.has('contract')
864
+ ? truncateMarkdown(
865
+ raw,
866
+ maxChars,
867
+ 'The structured `component` field above is complete; the cut text is guide prose.'
868
+ )
869
+ : null;
870
+
202
871
  return {
203
872
  found: true,
204
- // Never truncated: the precision-critical surface.
205
- component: entry,
873
+ ...(resolved.resolvedFrom ? { resolvedFrom: resolved.resolvedFrom } : {}),
874
+ component,
875
+ ...(types.length > 0 ? { types } : {}),
876
+ ...(ptRows.length && !wanted.has('ptProps')
877
+ ? {
878
+ ptProps: `${ptRows.length} pt:* props not listed: every \`pt:<part>\` and \`pt:<part>:<state>\` in \`component.pt\` is a prop taking a class string (or object / array), and \`pt\` takes the same entries as one object keyed WITHOUT the \`pt:\` prefix: { ${ptExample(entry)} }.`,
879
+ }
880
+ : {}),
881
+ /*
882
+ * Where agents land when they type `pt` in <script> (Q52.7.1 receipts):
883
+ * 5 of 6 blind Haiku runs opened get_component first, never saw the
884
+ * passthrough guide's typing section, and hand-copied the part unions
885
+ * or invented a `PtValue`. The one that found the section scored 4/4.
886
+ */
887
+ ...(entry.pt?.parts?.length ? { ptTyping: ptTyping(entry) } : {}),
888
+ ...(seeAlso(entry, raw).length ? { seeAlso: seeAlso(entry, raw) } : {}),
889
+ guide: {
890
+ sections: guide
891
+ .filter((s) => s.level === 3)
892
+ .map((s) => ({ title: s.title, chars: s.text.length })),
893
+ ...(picked.length
894
+ ? { requested: picked.map((s) => ({ title: s.title, text: s.text })) }
895
+ : {}),
896
+ ...(missing.length ? { notFound: missing } : {}),
897
+ ...(always.length
898
+ ? { always: always.map((s) => ({ title: s.title, text: s.text })) }
899
+ : {}),
900
+ },
206
901
  contractPath,
207
- contractContent: content,
208
- ...meta,
902
+ ...(contract
903
+ ? {
904
+ contract: contract.content,
905
+ ...(contract.truncated
906
+ ? {
907
+ contractTruncated: true,
908
+ contractHint: contract.hint,
909
+ }
910
+ : {}),
911
+ }
912
+ : {}),
913
+ hint: `Structured API above is complete. Read guide sections with get_component({ name: '${entry.name}', sections: ['<title from guide.sections>'] }); add include: ['tree' | 'cssProps' | 'css' | 'ptProps' | 'history' | 'contract'] for the component tree, CSS variables with descriptions, the .bb-* classes it renders, every pt:* row, the full v2/beta rename records, or the whole contract. search_docs finds a topic across all docs.`,
209
914
  };
210
915
  }
211
916
 
@@ -219,16 +924,53 @@ const STYLES_CSS = join(PACKAGE_ROOT, 'dist', 'styles.css');
219
924
  * every comma-part is built solely from these — `:root`, `.light`, `:root.dark`
220
925
  * and `html.dark` are theme roots; `.bb-tooltip .bb-common-popover__bubble` is
221
926
  * not, however many `--bb-*` it redeclares.
927
+ *
928
+ * `.bb-theme` is a theme root too: it is the island boundary the derived block
929
+ * re-specifies its formulas on (design-tokens.md § the CSS mechanic).
930
+ */
931
+ const THEME_ROOT_PART = /^(?::root|html|body|\.light|\.dark|\.bb-theme)+$/;
932
+
933
+ /**
934
+ * Unwrap the `:where(…)` / `:is(…)` a selector list may be wrapped in. The
935
+ * derived-token block ships as `:where(:root,.light,.dark,.bb-theme)`, and
936
+ * splitting THAT on commas yields `:where(:root` and `.bb-theme)` — neither of
937
+ * which is a theme root, so without this every derived token is misreported as
938
+ * a component rebind with no value. That is not a cosmetic slip: `localRebinds`
939
+ * is documented to agents as "not something to copy".
222
940
  */
223
- const THEME_ROOT_PART = /^(?::root|html|body|\.light|\.dark)+$/;
941
+ function unwrapSelectorList(selector) {
942
+ const trimmed = selector.trim();
943
+ const match = /^:(?:where|is)\((.*)\)$/s.exec(trimmed);
944
+ return match ? match[1] : trimmed;
945
+ }
946
+
224
947
  function isThemeSelector(selector) {
225
- return selector
948
+ return unwrapSelectorList(selector)
226
949
  .split(',')
227
950
  .every((part) =>
228
951
  THEME_ROOT_PART.test(part.replace(/[\s>+~]+/g, '').trim())
229
952
  );
230
953
  }
231
954
 
955
+ /**
956
+ * A theme token is a KNOB (the consumer sets it) or DERIVED (a formula the
957
+ * library recomputes at every theme boundary). Setting a derived value is the
958
+ * documented trap — it stops tracking the knob it was computed from.
959
+ *
960
+ * The split is structural in the shipped sheet, so it needs no curated list to
961
+ * drift: knobs are declared on the plain scheme roots, formulas inside the
962
+ * `:where(…)` boundary block. A name in BOTH is a knob that TRACKS another one
963
+ * until pinned — and because the boundary block re-specifies it, a pin has to
964
+ * be repeated at every boundary it is used on, `.dark` included.
965
+ */
966
+ const isDerivedBlock = (selector) => /^:(?:where|is)\(/.test(selector.trim());
967
+ const tokenKind = (inKnobBlock, inDerivedBlock) =>
968
+ inKnobBlock && inDerivedBlock
969
+ ? 'knob-tracking'
970
+ : inDerivedBlock
971
+ ? 'derived'
972
+ : 'knob';
973
+
232
974
  /**
233
975
  * Walk a stylesheet and yield every `--bb-*` declaration WITH the selector that
234
976
  * owns it. A flat regex cannot do this: it sees a declaration but not its
@@ -237,6 +979,11 @@ function isThemeSelector(selector) {
237
979
  * tolerant of the missing final semicolon that minified CSS emits) is the
238
980
  * cheapest way to keep the scope — and this file ships in the package, so it
239
981
  * may not reach for postcss the way the dev-only `check:tokens` script does.
982
+ *
983
+ * `when` carries the enclosing `@supports` condition(s), if any: a value there
984
+ * is not the theme value but one browser path — `--bb-primary-fg` ships an
985
+ * auto-contrast formula with literal fallbacks, and folding the fallbacks into
986
+ * the theme values tells an agent to pin a literal that defeats the formula.
240
987
  */
241
988
  function* eachTokenDeclaration(css) {
242
989
  const stack = [];
@@ -257,11 +1004,23 @@ function* eachTokenDeclaration(css) {
257
1004
  quote = char;
258
1005
  buffer += char;
259
1006
  } else if (char === '{') {
260
- stack.push(buffer.trim());
1007
+ // A comment before a rule would otherwise prefix its selector or
1008
+ // hide the `@supports` it opens.
1009
+ stack.push(buffer.replace(/\/\*[\s\S]*?\*\//g, '').trim());
261
1010
  buffer = '';
262
1011
  } else if (char === '}' || char === ';') {
263
1012
  const decl = declaration();
264
- if (decl) yield { ...decl, selector: stack[stack.length - 1] ?? '' };
1013
+ if (decl) {
1014
+ const supports = stack
1015
+ .slice(0, -1)
1016
+ .filter((scope) => scope.startsWith('@supports'))
1017
+ .map((scope) => scope.replace(/^@supports\s*/, ''));
1018
+ yield {
1019
+ ...decl,
1020
+ selector: stack[stack.length - 1] ?? '',
1021
+ ...(supports.length ? { when: supports.join(' and ') } : {}),
1022
+ };
1023
+ }
265
1024
  if (char === '}') stack.pop();
266
1025
  } else {
267
1026
  buffer += char;
@@ -281,7 +1040,8 @@ function* eachTokenDeclaration(css) {
281
1040
  * different components and is only meaningful inside that component's scope.
282
1041
  * Serving them as one flat list would invite exactly the wrong move — an agent
283
1042
  * writing `:root { --gap: … }` and wondering why nothing changed. They are
284
- * documented per component, which `get_component` already serves.
1043
+ * documented per component: `get_component` carries them as `cssProps`, each
1044
+ * with the root class to set it on, its default, and what it is.
285
1045
  *
286
1046
  * WHY `dist/styles.css` AND NOT `src/assets/css/variables.css`: `src/` is not
287
1047
  * in the published package, so the source file does not exist for the consumer
@@ -301,9 +1061,27 @@ function listTokens({ filter } = {}) {
301
1061
  }
302
1062
  const css = readFileSync(STYLES_CSS, 'utf-8');
303
1063
  const byName = new Map();
304
- for (const { name, value, selector } of eachTokenDeclaration(css)) {
305
- const entry = byName.get(name) ?? { theme: [], local: [] };
1064
+ for (const { name, value, selector, when } of eachTokenDeclaration(css)) {
1065
+ const entry = byName.get(name) ?? {
1066
+ theme: [],
1067
+ local: [],
1068
+ conditional: [],
1069
+ knobBlock: false,
1070
+ derivedBlock: false,
1071
+ };
306
1072
  if (isThemeSelector(selector)) {
1073
+ if (isDerivedBlock(selector)) entry.derivedBlock = true;
1074
+ else entry.knobBlock = true;
1075
+ }
1076
+ if (when) {
1077
+ // One browser path, not the theme value nor a dark override.
1078
+ if (
1079
+ !entry.conditional.some(
1080
+ (c) => c.when === when && c.selector === selector
1081
+ )
1082
+ )
1083
+ entry.conditional.push({ when, selector, value });
1084
+ } else if (isThemeSelector(selector)) {
307
1085
  // Light first, dark after: report both rather than let one win.
308
1086
  if (!entry.theme.includes(value)) entry.theme.push(value);
309
1087
  } else if (!entry.local.some((r) => r.selector === selector)) {
@@ -320,11 +1098,13 @@ function listTokens({ filter } = {}) {
320
1098
  const tokens = [...byName.entries()]
321
1099
  .filter(([name]) => !needle || name.toLowerCase().includes(needle))
322
1100
  .sort(([a], [b]) => a.localeCompare(b))
323
- .map(([name, { theme, local }]) => ({
1101
+ .map(([name, { theme, local, conditional, knobBlock, derivedBlock }]) => ({
324
1102
  name,
1103
+ kind: tokenKind(knobBlock, derivedBlock),
325
1104
  value: theme[0],
326
1105
  ...(theme.length > 1 ? { themeOverrides: theme.slice(1) } : {}),
327
1106
  ...(local.length > 0 ? { localRebinds: local } : {}),
1107
+ ...(conditional.length > 0 ? { conditional } : {}),
328
1108
  }));
329
1109
  return {
330
1110
  count: tokens.length,
@@ -332,11 +1112,19 @@ function listTokens({ filter } = {}) {
332
1112
  tokens,
333
1113
  hint:
334
1114
  needle && tokens.length === 0
335
- ? `No token name contains '${needle}'. Call list_tokens with no filter for all ${byName.size} — the names are semantic (primary/danger/panel/text/border/radius/…), not literal colours.`
336
- : 'Theme tokens are set by the consumer app (e.g. on :root / .dark); `themeOverrides` is the dark-theme value. `localRebinds` is a component rebinding the token inside its own subtree — not something to copy. Component-level unprefixed tokens are documented per component; see the design-tokens guide via get_guide.',
1115
+ ? `No token name contains '${needle}'. Call list_tokens with no filter for all ${byName.size} — the names are semantic (primary/danger/panel/text/border/radius/…), not literal colours. ${FONT_NOTE}`
1116
+ : FONT_NOTE +
1117
+ ' Theme tokens are set by the consumer app (e.g. on :root / .dark); `themeOverrides` is the dark-theme value. `localRebinds` is a component rebinding the token inside its own subtree — not something to copy. `conditional` is a value that applies only under an @supports condition (`when`) — e.g. an auto-contrast formula with literal fallbacks for older browsers; pinning a fallback literal defeats the formula. `kind` says what you may set: "knob" is yours; "derived" is a formula recomputed at every theme boundary, so setting it stops it tracking the knob it came from — set that knob instead; "knob-tracking" is a knob that follows another until you pin it, and the pin must be repeated at every boundary you use, .dark included. Component-level unprefixed tokens are documented per component; see the design-tokens guide via get_guide.',
337
1118
  };
338
1119
  }
339
1120
 
1121
+ /**
1122
+ * Q53.11: there is no font-family token, by ruling; agents kept looking for
1123
+ * one. Said in every list_tokens answer.
1124
+ */
1125
+ const FONT_NOTE =
1126
+ "Components have no font token; they inherit the page's `font-family`. Set it on `body` (or a `.bb-theme` island) to theme it.";
1127
+
340
1128
  /** Every guide markdown path under dist/ai/guides, relative to that dir. */
341
1129
  function collectGuidePaths(dir, prefix = '') {
342
1130
  const out = [];
@@ -352,41 +1140,412 @@ function collectGuidePaths(dir, prefix = '') {
352
1140
 
353
1141
  /** `list_guides()` — the shipped prose guides an agent can read. */
354
1142
  function listGuides() {
355
- const guides = collectGuidePaths(join(AI_ROOT, 'guides')).sort();
1143
+ const guidesDir = join(AI_ROOT, 'guides');
1144
+ const all = collectGuidePaths(guidesDir).sort();
1145
+ /*
1146
+ * Title + summary per guide (review D6-13): 57 bare paths could not tell an
1147
+ * agent which one answers its question. The 40 per-component migration
1148
+ * pages collapse to one row — get_guide('migration/components/<kebab>').
1149
+ */
1150
+ const perComponent = all.filter((p) => p.startsWith('migration/components/'));
1151
+ const guides = all
1152
+ .filter((p) => !perComponent.includes(p))
1153
+ .map((path) => {
1154
+ const markdown = readFileSync(join(guidesDir, path), 'utf-8');
1155
+ const meta = frontmatter(markdown);
1156
+ const title =
1157
+ meta.title ??
1158
+ stripFrontmatter(markdown)
1159
+ .match(/^# (.+)$/m)?.[1]
1160
+ ?.trim();
1161
+ return {
1162
+ name: path,
1163
+ ...(title ? { title } : {}),
1164
+ ...(meta.summary ? { summary: meta.summary } : {}),
1165
+ };
1166
+ });
356
1167
  return {
357
- count: guides.length,
1168
+ count: all.length,
358
1169
  guides,
359
- hint: 'Read one with get_guide({ name }). Start at `ai-router.md`, then `agent-contract.md` — do not read them all.',
1170
+ ...(perComponent.length
1171
+ ? {
1172
+ perComponentMigration: `${perComponent.length} pages: get_guide({ name: 'migration/components/<kebab-name>' }), e.g. 'migration/components/bb-select'.`,
1173
+ }
1174
+ : {}),
1175
+ hint: 'Read one with get_guide({ name }); a long guide answers with its outline — then pass sections. search_docs finds the section for a question across every guide. Start at `ai-router.md` — do not read them all.',
360
1176
  };
361
1177
  }
362
1178
 
363
- /** `get_guide({ name, maxChars })` — read one guide by relative path. */
364
- function getGuide({ name, maxChars } = {}) {
365
- const rel = String(name ?? '').replace(/^\/+/, '');
366
- // Contain reads to the guides dir — no traversal out of the knowledge base.
367
- if (!rel || rel.includes('..')) {
1179
+ /** Guides this size or larger answer with an outline unless asked for more. */
1180
+ // The router (13 KB, the documented entry point) still comes whole.
1181
+ const GUIDE_OUTLINE_OVER = 16000;
1182
+
1183
+ /**
1184
+ * The shipped guide a pointer means. Pointers come from everywhere — the
1185
+ * changelog (`components/bb-table.md (CSS table)`), contracts
1186
+ * (`guides/passthrough.md`), the repo layout (`ai/guides/…`) — and every form
1187
+ * used to answer "Guide not found" (review D6-11).
1188
+ */
1189
+ function resolveGuidePath(name) {
1190
+ const guidesDir = join(AI_ROOT, 'guides');
1191
+ const all = collectGuidePaths(guidesDir);
1192
+ let rel = String(name ?? '')
1193
+ .trim()
1194
+ .replace(/\s*\(.*\)\s*$/, '')
1195
+ .replace(/^\/+/, '')
1196
+ .replace(/^(dist\/)?(ai\/)?(guides\/)?/, '');
1197
+ if (!rel || rel.includes('..')) return null;
1198
+ if (!rel.endsWith('.md')) rel = `${rel}.md`;
1199
+ const tries = [rel, `migration/${rel}`, `migration/components/${rel}`];
1200
+ for (const attempt of tries) if (all.includes(attempt)) return attempt;
1201
+ const base = rel.split('/').pop();
1202
+ const byBase = all.filter((p) => p.split('/').pop() === base);
1203
+ return byBase.length === 1 ? byBase[0] : null;
1204
+ }
1205
+
1206
+ /** `get_guide({ name, sections?, maxChars? })`. */
1207
+ function getGuide({ name, sections, maxChars } = {}) {
1208
+ const resolved = resolveGuidePath(name);
1209
+ if (!resolved) {
1210
+ const all = collectGuidePaths(join(AI_ROOT, 'guides'));
1211
+ const needle = String(name ?? '').toLowerCase();
1212
+ const near = all
1213
+ .filter((p) =>
1214
+ needle
1215
+ .split(/[^a-z0-9]+/)
1216
+ .some((w) => w.length > 3 && p.toLowerCase().includes(w))
1217
+ )
1218
+ .slice(0, 5);
368
1219
  return {
369
1220
  found: false,
370
- error: `Invalid guide name '${name}'.`,
371
- hint: 'Call list_guides for the available names.',
1221
+ error: `Guide not found: ${name}`,
1222
+ ...(near.length ? { didYouMean: near } : {}),
1223
+ hint: 'Call list_guides for the names, or search_docs to find the section by topic.',
372
1224
  };
373
1225
  }
374
- const fileName = rel.endsWith('.md') ? rel : `${rel}.md`;
375
- const guidesDir = join(AI_ROOT, 'guides');
376
- const filePath = join(guidesDir, fileName);
377
- if (!filePath.startsWith(guidesDir) || !existsSync(filePath)) {
1226
+ const markdown = readFileSync(join(AI_ROOT, 'guides', resolved), 'utf-8');
1227
+ const meta = frontmatter(markdown);
1228
+ const all = splitSections(markdown);
1229
+ const base = {
1230
+ found: true,
1231
+ name: resolved,
1232
+ ...(resolved !== name ? { resolvedFrom: name } : {}),
1233
+ ...(meta.title ? { title: meta.title } : {}),
1234
+ };
1235
+ if (sections?.length) {
1236
+ const { picked, missing } = pickSections(all, sections);
378
1237
  return {
379
- found: false,
380
- error: `Guide not found: ${fileName}`,
381
- hint: 'Call list_guides for the available names.',
1238
+ ...base,
1239
+ sections: picked.map((s) => ({ title: s.title, text: s.text })),
1240
+ ...(missing.length ? { notFound: missing, outline: outline(all) } : {}),
382
1241
  };
383
1242
  }
384
- const { content, ...meta } = truncateMarkdown(
385
- readFileSync(filePath, 'utf-8'),
1243
+ const body = stripFrontmatter(markdown);
1244
+ if (maxChars === undefined && body.length >= GUIDE_OUTLINE_OVER) {
1245
+ const intro = body.split(/^## /m)[0].trim();
1246
+ return {
1247
+ ...base,
1248
+ ...(meta.summary ? { summary: meta.summary } : {}),
1249
+ chars: body.length,
1250
+ intro: intro.slice(0, 2000),
1251
+ outline: outline(all),
1252
+ hint: `This guide is ${body.length} chars. Read what you need: get_guide({ name: '${resolved}', sections: ['<title from outline>'] }) — a ## section includes its ### children. maxChars: 0 returns the whole guide.`,
1253
+ };
1254
+ }
1255
+ const { content, ...cut } = truncateMarkdown(
1256
+ markdown,
386
1257
  maxChars,
387
- `Guides are ordered narrative — the cut tail is later sections.`
1258
+ 'Guides are ordered narrative — the cut tail is later sections.'
388
1259
  );
389
- return { found: true, name: fileName, content, ...meta };
1260
+ return { ...base, content, ...cut };
1261
+ }
1262
+
1263
+ /**
1264
+ * `search_docs({ query, limit? })` — the section that answers a question,
1265
+ * across guides, composables, component guides, component props and recipes.
1266
+ *
1267
+ * WHY (review 2026-09-23). The facts Haiku missed were all shipped — the
1268
+ * `.dark` class, `cssLayers`, `passthroughDeduper`, `ssrViewportWidth`, the
1269
+ * `ai-init` and `changelog` commands, `prefill: false` — but each sat in one
1270
+ * section of a long document, and no tool could say which. Each result is a
1271
+ * snippet plus the exact call that reads the whole section.
1272
+ */
1273
+ let cachedDocIndex = null;
1274
+ function docIndex() {
1275
+ if (cachedDocIndex) return cachedDocIndex;
1276
+ const entries = [];
1277
+ const addSections = (source, markdown, read) => {
1278
+ for (const section of splitSections(markdown)) {
1279
+ if (section.own.length < 40) continue;
1280
+ entries.push({
1281
+ source,
1282
+ section: section.title,
1283
+ text: section.own,
1284
+ read: read(section.title),
1285
+ });
1286
+ }
1287
+ };
1288
+ const guidesDir = join(AI_ROOT, 'guides');
1289
+ for (const path of collectGuidePaths(guidesDir)) {
1290
+ addSections(
1291
+ `guide ${path}`,
1292
+ readFileSync(join(guidesDir, path), 'utf-8'),
1293
+ (title) => ({
1294
+ tool: 'get_guide',
1295
+ args: { name: path, sections: [title] },
1296
+ })
1297
+ );
1298
+ }
1299
+ const composablesDir = join(AI_ROOT, 'composables');
1300
+ if (existsSync(composablesDir)) {
1301
+ for (const file of readdirSync(composablesDir).filter((f) =>
1302
+ f.endsWith('.md')
1303
+ )) {
1304
+ const markdown = readFileSync(join(composablesDir, file), 'utf-8');
1305
+ const name = file.slice(0, -3);
1306
+ entries.push({
1307
+ source: `composable ${name}`,
1308
+ section: frontmatter(markdown).summary ?? name,
1309
+ text: stripFrontmatter(markdown).slice(0, 4000),
1310
+ read: { tool: 'get_composable', args: { name } },
1311
+ });
1312
+ }
1313
+ }
1314
+ const manifest = loadComponentsManifest();
1315
+ for (const component of manifest.components.filter((c) => !c.referenceOnly)) {
1316
+ const path = join(PACKAGE_ROOT, 'dist', component.contract ?? '');
1317
+ if (component.contract && existsSync(path)) {
1318
+ for (const section of contractGuideSections(
1319
+ readFileSync(path, 'utf-8')
1320
+ )) {
1321
+ if (section.own.length < 40) continue;
1322
+ entries.push({
1323
+ source: `component ${component.name}`,
1324
+ section: section.title,
1325
+ text: section.own,
1326
+ read: {
1327
+ tool: 'get_component',
1328
+ args: { name: component.name, sections: [section.title] },
1329
+ },
1330
+ });
1331
+ }
1332
+ }
1333
+ for (const prop of component.props) {
1334
+ if (prop.name.startsWith('pt')) continue;
1335
+ entries.push({
1336
+ source: `component ${component.name}`,
1337
+ section: `prop ${prop.name}`,
1338
+ text: `${prop.name}: ${prop.type}${prop.default ? ` = ${prop.default}` : ''}. ${prop.description ?? ''}`,
1339
+ read: { tool: 'get_component', args: { name: component.name } },
1340
+ });
1341
+ }
1342
+ for (const event of component.events ?? []) {
1343
+ entries.push({
1344
+ source: `component ${component.name}`,
1345
+ section: `event ${event.name}`,
1346
+ text: `@${event.name} ${event.signature}. ${event.description ?? ''}`,
1347
+ read: { tool: 'get_component', args: { name: component.name } },
1348
+ });
1349
+ }
1350
+ /*
1351
+ * The rename registry: an agent upgrading an app searches the OLD name
1352
+ * (`enabled-while-loading`, `pt:input`, `#no-data`), which no current
1353
+ * section spells. One entry per row, with the name written every way a
1354
+ * query may (camel, kebab, split words), read = its migration guide.
1355
+ */
1356
+ for (const row of component.removed ?? []) {
1357
+ const spell = (name) => (row.surface === 'slot' ? `#${name}` : name);
1358
+ const ways = (name) =>
1359
+ [
1360
+ ...new Set([
1361
+ name,
1362
+ name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`),
1363
+ name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').toLowerCase(),
1364
+ ]),
1365
+ ].join(' / ');
1366
+ const kind = row.surface ?? 'prop';
1367
+ const guide = row.migration?.replace(/^ai\/guides\//, '');
1368
+ entries.push({
1369
+ source: `component ${component.name}`,
1370
+ section: `${row.new ? 'renamed' : 'removed'} ${kind} ${spell(row.name)}`,
1371
+ text:
1372
+ `${kind} ${ways(spell(row.name))} ` +
1373
+ (row.new
1374
+ ? `was renamed to ${ways(spell(row.new))} on ${component.name}`
1375
+ : `was removed from ${component.name}`) +
1376
+ `${row.since && !/unreleased/.test(row.since) ? ` in ${row.since}` : ''}.` +
1377
+ Object.entries(row.fix?.valueMap ?? {})
1378
+ .filter(([from, to]) => from !== to)
1379
+ .map(([from, to]) => ` The value "${from}" becomes "${to}".`)
1380
+ .join('') +
1381
+ `${row.hint ? ` ${row.hint}.` : ''} \`bitboss-ui check --fix\` rewrites a rename.`,
1382
+ read: guide
1383
+ ? { tool: 'get_guide', args: { name: guide } }
1384
+ : { tool: 'get_component', args: { name: component.name } },
1385
+ });
1386
+ }
1387
+ }
1388
+ for (const platform of RECIPE_PLATFORMS) {
1389
+ const dir = join(AI_ROOT, 'recipes', platform);
1390
+ if (!existsSync(dir)) continue;
1391
+ for (const file of readdirSync(dir).filter((f) => f.endsWith('.md'))) {
1392
+ const name = file.slice(0, -3);
1393
+ const markdown = readFileSync(join(dir, file), 'utf-8');
1394
+ entries.push({
1395
+ source: `recipe ${platform}/${name}`,
1396
+ section: frontmatter(markdown).title ?? name,
1397
+ text: frontmatter(markdown).summary ?? name,
1398
+ read: { tool: 'get_recipe', args: { platform, name } },
1399
+ });
1400
+ }
1401
+ }
1402
+ // Class renames (the sweep map rows of changelog.json): an app's
1403
+ // stylesheet names the OLD class, so the old class must find the new one.
1404
+ if (existsSync(CHANGELOG_PATH)) {
1405
+ const changelog = JSON.parse(readFileSync(CHANGELOG_PATH, 'utf-8'));
1406
+ for (const row of changelog.breaking ?? []) {
1407
+ if (row.surface !== 'class' || !String(row.id).startsWith('css:'))
1408
+ continue;
1409
+ entries.push({
1410
+ source: `class ${row.components?.[0] ?? ''}`.trim(),
1411
+ section: `renamed class ${row.from}`,
1412
+ text:
1413
+ `class ${row.from} was renamed to ${row.to}` +
1414
+ `${row.firstReleasedIn ? ` in ${row.firstReleasedIn}` : ''}` +
1415
+ (row.from.includes('--')
1416
+ ? '.'
1417
+ : `; its modifiers follow (${row.from}--x → ${row.to}--x).`) +
1418
+ `${row.note ? ` ${row.note}.` : ''}`,
1419
+ read: {
1420
+ tool: 'get_guide',
1421
+ args: { name: 'migration/v3-beta-css-classes.md' },
1422
+ },
1423
+ });
1424
+ }
1425
+ /*
1426
+ * Every other break, with the release that first shipped it. "In which
1427
+ * version did the activator scope lose `isOpen`?" had no search path: the
1428
+ * answer (f202, firstReleasedIn 3.0.0-beta.35) lived only in
1429
+ * list_changes, which 1 answerer in 12 called (ai-docs access push,
1430
+ * 2026-09-24). Prop / pt / slot renames are already indexed from the
1431
+ * components' registry rows above, so only the rest comes in here.
1432
+ */
1433
+ const releases = changelog.releases ?? [];
1434
+ for (const row of changelog.breaking ?? []) {
1435
+ if (row.surface === 'class') continue;
1436
+ if (row.kind === 'rename' && ['prop', 'pt', 'slot'].includes(row.surface))
1437
+ continue;
1438
+ const what =
1439
+ row.kind === 'rename'
1440
+ ? `${row.surface ?? ''} ${row.from} → ${row.to ?? '(removed)'}`.trim()
1441
+ : String(row.description ?? '');
1442
+ if (!what) continue;
1443
+ const at = row.firstReleasedIn;
1444
+ const before = at
1445
+ ? releases.filter((r) => compareVersions(r, at) < 0).at(-1)
1446
+ : releases.at(-1);
1447
+ entries.push({
1448
+ source: `change ${row.id}`,
1449
+ section: `breaking change: ${what.length > 90 ? `${what.slice(0, 90)}…` : what}`,
1450
+ text:
1451
+ `${what}${row.note ? ` (${row.note})` : ''}. ` +
1452
+ (at
1453
+ ? `First released in ${at}.`
1454
+ : 'Not released yet: it ships in the next release.') +
1455
+ `${row.guide ? ` Migration: ${row.guide}.` : ''}`,
1456
+ read: {
1457
+ tool: 'list_changes',
1458
+ args: before ? { since: before, ...(at ? { until: at } : {}) } : {},
1459
+ },
1460
+ });
1461
+ }
1462
+ }
1463
+ /*
1464
+ * The public types an app builds values with (`api` tier: BbTreeItem,
1465
+ * BbTableColumn, ButtonVariantType). "What shape must each BbTree item
1466
+ * have?" matched only the prop row `items: BbTreeItem<Meta>[]`, never the
1467
+ * type's fields, so 2 of 3 answerers guessed `{ label, children }`.
1468
+ */
1469
+ for (const type of manifest.types ?? []) {
1470
+ if (type.usage !== 'api' || type.deprecated) continue;
1471
+ const use = (type.usedBy ?? [])
1472
+ .map((u) => `${u.component} ${u.name} ${u.surface}`)
1473
+ .join(', ');
1474
+ entries.push({
1475
+ source: `type ${type.name}`,
1476
+ section: `type ${type.name}${use ? ` (${use})` : ''}`,
1477
+ // The words questions use ("shape", "fields", "values") are spelled
1478
+ // out: the declaration alone never says them.
1479
+ text:
1480
+ `${type.name}${use ? `, the type of ${use}` : ''}: ` +
1481
+ (type.values
1482
+ ? `accepted values ${type.values.join(' | ')}`
1483
+ : type.fields
1484
+ ? `object shape, fields ${type.fields.join('; ')}`
1485
+ : String(type.definition ?? '')) +
1486
+ `. import type { ${type.name} } from 'bitboss-ui'.`,
1487
+ read: { tool: 'get_component', args: { name: type.name } },
1488
+ });
1489
+ }
1490
+ const readme = join(PACKAGE_ROOT, 'README.md');
1491
+ if (existsSync(readme)) {
1492
+ addSections('README', readFileSync(readme, 'utf-8'), () => ({
1493
+ tool: 'read file',
1494
+ args: { path: 'node_modules/bitboss-ui/README.md' },
1495
+ }));
1496
+ }
1497
+ cachedDocIndex = entries;
1498
+ return entries;
1499
+ }
1500
+
1501
+ function searchDocs({ query, limit } = {}) {
1502
+ const max = Number.isFinite(limit) && limit > 0 ? Math.min(limit, 20) : 8;
1503
+ const { tokens, total, results } = searchSections(docIndex(), query, max);
1504
+ return {
1505
+ query: query ?? '',
1506
+ tokens,
1507
+ count: results.length,
1508
+ ...(total > results.length ? { totalMatches: total } : {}),
1509
+ results,
1510
+ hint: results.length
1511
+ ? 'Each result is one section; `read` is the call that returns it whole. Prefer the top results: they match the most query words.'
1512
+ : 'Nothing matched. Use fewer, more specific words (a prop, option or component name), or search_components for components.',
1513
+ };
1514
+ }
1515
+
1516
+ /** `get_composable({ name })` — one composable's doc (useToast, useConfirm…). */
1517
+ function getComposable({ name } = {}) {
1518
+ const dir = join(AI_ROOT, 'composables');
1519
+ const files = existsSync(dir)
1520
+ ? readdirSync(dir).filter((f) => f.endsWith('.md'))
1521
+ : [];
1522
+ const wanted = String(name ?? '').replace(/\.md$/, '');
1523
+ const file = files.find(
1524
+ (f) => f.slice(0, -3).toLowerCase() === wanted.toLowerCase()
1525
+ );
1526
+ if (!file) {
1527
+ return {
1528
+ found: false,
1529
+ error: `Composable not found: ${name}`,
1530
+ available: files.map((f) => f.slice(0, -3)),
1531
+ };
1532
+ }
1533
+ const markdown = readFileSync(join(dir, file), 'utf-8');
1534
+ /*
1535
+ * A composable that needs a host component says so FIRST, as a field: with
1536
+ * no `<BbConfirm />`, `await confirm()` never settles. Every blind answerer
1537
+ * of "await an Are-you-sure dialog" (4 of 4, 2026-09-24) left the host out,
1538
+ * although the doc's second paragraph states it.
1539
+ */
1540
+ const host = frontmatter(markdown).summary?.match(
1541
+ /Requires (exactly one <Bb\w+ \/> host[^.]*)\./
1542
+ )?.[1];
1543
+ return {
1544
+ found: true,
1545
+ name: file.slice(0, -3),
1546
+ ...(host ? { requires: host } : {}),
1547
+ content: stripFrontmatter(markdown),
1548
+ };
390
1549
  }
391
1550
 
392
1551
  function listRecipes({ platform } = {}) {
@@ -398,21 +1557,40 @@ function listRecipes({ platform } = {}) {
398
1557
  error: `Unknown platform(s): ${invalid.join(', ')} — expected one of ${RECIPE_PLATFORMS.join(', ')}`,
399
1558
  };
400
1559
  }
401
- const recipes = [];
1560
+ /*
1561
+ * One row per recipe with its platforms, title, summary and size (review
1562
+ * D6-13): records-workspace / inline-edit-workspace / approvals-inbox could
1563
+ * not be told apart by name, and each costs 11–61 KB to open.
1564
+ */
1565
+ const byName = new Map();
402
1566
  for (const p of platforms) {
403
1567
  const dir = join(AI_ROOT, 'recipes', p);
404
1568
  if (!existsSync(dir)) continue;
405
1569
  for (const file of readdirSync(dir)) {
406
- if (file.endsWith('.md')) {
407
- recipes.push({ platform: p, name: file.slice(0, -3) });
408
- }
1570
+ if (!file.endsWith('.md')) continue;
1571
+ const name = file.slice(0, -3);
1572
+ const markdown = readFileSync(join(dir, file), 'utf-8');
1573
+ const meta = frontmatter(markdown);
1574
+ const row = byName.get(name) ?? {
1575
+ name,
1576
+ ...(meta.title ? { title: meta.title } : {}),
1577
+ ...(meta.summary ? { summary: meta.summary } : {}),
1578
+ platforms: [],
1579
+ chars: {},
1580
+ };
1581
+ row.platforms.push(p);
1582
+ row.chars[p] = markdown.length;
1583
+ byName.set(name, row);
409
1584
  }
410
1585
  }
411
- return { recipes };
1586
+ return {
1587
+ recipes: [...byName.values()],
1588
+ hint: 'get_recipe({ platform, name }) returns the whole recipe (they are copied whole); pass sections to read only part of a long one.',
1589
+ };
412
1590
  }
413
1591
 
414
1592
  /** `get_recipe({ platform, name })` — read one recipe's markdown content. */
415
- function getRecipe({ platform, name, maxChars } = {}) {
1593
+ function getRecipe({ platform, name, sections, maxChars } = {}) {
416
1594
  if (!RECIPE_PLATFORMS.includes(platform)) {
417
1595
  return {
418
1596
  found: false,
@@ -442,9 +1620,26 @@ function getRecipe({ platform, name, maxChars } = {}) {
442
1620
  hint: 'Call list_recipes for the available names.',
443
1621
  };
444
1622
  }
1623
+ const markdown = readFileSync(filePath, 'utf-8');
1624
+ if (sections?.length) {
1625
+ const all = splitSections(markdown);
1626
+ const { picked, missing } = pickSections(all, sections);
1627
+ return {
1628
+ found: true,
1629
+ platform,
1630
+ name: fileName.slice(0, -3),
1631
+ sections: picked.map((section) => ({
1632
+ title: section.title,
1633
+ text: section.text,
1634
+ })),
1635
+ ...(missing.length ? { notFound: missing, outline: outline(all) } : {}),
1636
+ };
1637
+ }
1638
+ // Whole by default (review D6-14): a recipe is copied whole, and the old
1639
+ // 40 000-char default cut 7 of 9 vue recipes inside their page code.
445
1640
  const { content, ...meta } = truncateMarkdown(
446
- readFileSync(filePath, 'utf-8'),
447
- maxChars,
1641
+ markdown,
1642
+ maxChars ?? 0,
448
1643
  `Recipes are ordered narrative — the cut tail is later sections.`
449
1644
  );
450
1645
  return {
@@ -459,8 +1654,17 @@ function getRecipe({ platform, name, maxChars } = {}) {
459
1654
  /** `validate({ code })` — Phase 2 validator core over a Vue snippet. */
460
1655
  function validateCode({ code } = {}) {
461
1656
  const manifest = getManifestMap();
462
- const { findings } = validateVueSnippet(String(code ?? ''), manifest);
463
- return { ok: findings.length === 0, findings };
1657
+ const { findings: all } = validateVueSnippet(String(code ?? ''), manifest);
1658
+ // `severity: 'warning'` findings (a slot spelled the pre-reset way, Q53.15
1659
+ // C9b) are reported apart and never make the snippet invalid — the same
1660
+ // split `bitboss-ui check` prints.
1661
+ const findings = all.filter((f) => f.severity !== 'warning');
1662
+ const warnings = all.filter((f) => f.severity === 'warning');
1663
+ return {
1664
+ ok: findings.length === 0,
1665
+ findings,
1666
+ ...(warnings.length ? { warnings } : {}),
1667
+ };
464
1668
  }
465
1669
 
466
1670
  /**
@@ -469,12 +1673,178 @@ function validateCode({ code } = {}) {
469
1673
  * becomes an `isError` result carrying `Error: <message>` — preserving the
470
1674
  * exact result shape of the previous hand-rolled dispatch.
471
1675
  */
1676
+ const CHANGELOG_PATH = join(AI_ROOT, 'changelog.json');
1677
+
1678
+ /**
1679
+ * Order two versions on this library's line: `3.0.0-beta.21` after
1680
+ * `3.0.0-beta.9` (numeric, not lexical — the bug every hand-rolled compare
1681
+ * has), and any prerelease before its own stable release.
1682
+ */
1683
+ function compareVersions(a, b) {
1684
+ const parse = (v) => {
1685
+ const [core, pre = ''] = String(v).split('-');
1686
+ const nums = core.split('.').map((n) => Number.parseInt(n, 10) || 0);
1687
+ const [tag = '', n = ''] = pre.split('.');
1688
+ return { nums, tag, n: Number.parseInt(n, 10) || 0 };
1689
+ };
1690
+ const x = parse(a);
1691
+ const y = parse(b);
1692
+ for (let i = 0; i < 3; i += 1) {
1693
+ if ((x.nums[i] ?? 0) !== (y.nums[i] ?? 0))
1694
+ return (x.nums[i] ?? 0) - (y.nums[i] ?? 0);
1695
+ }
1696
+ // No prerelease tag outranks any prerelease of the same core version.
1697
+ if (!x.tag && y.tag) return 1;
1698
+ if (x.tag && !y.tag) return -1;
1699
+ if (x.tag !== y.tag) return x.tag < y.tag ? -1 : 1; // alpha < beta < rc
1700
+ return x.n - y.n;
1701
+ }
1702
+
1703
+ /**
1704
+ * `list_changes({ since, until })` — the breaking changes between two releases.
1705
+ *
1706
+ * WHY THIS TOOL EXISTS. A consumer agent on 2026-09-09 asked "what changed
1707
+ * between beta.20 and beta.21?", found nothing in the knowledge base that could
1708
+ * answer it, and diffed the two published tarballs by hand. The data existed
1709
+ * (`dist/ai/changelog.json`) but no tool served it, and its rows carried no
1710
+ * release, so even reading the file could not have answered the question. Both
1711
+ * halves are fixed: rows are stamped with `firstReleasedIn` at build time, and
1712
+ * this serves the slice.
1713
+ */
1714
+ /*
1715
+ * The answer's rows, compact (owner rule: compact by default): empty fields,
1716
+ * `ruling` and `since` dropped, and the class renames (85 one-to-one pairs from the sweep map,
1717
+ * Q51.19) folded into ONE `{ ".old": ".new" }` map — complete, and a tenth of
1718
+ * the size of 85 row objects. Everything else stays a full row.
1719
+ */
1720
+ function compactChanges(rows) {
1721
+ const classRenames = {};
1722
+ const breaking = [];
1723
+ for (const row of rows) {
1724
+ if (row.surface === 'class' && String(row.id).startsWith('css:')) {
1725
+ classRenames[row.from] = row.to;
1726
+ continue;
1727
+ }
1728
+ // `ruling` is the library's internal decision id and `since` the
1729
+ // register's authoring-date note (firstReleasedIn is the release): both
1730
+ // stay in changelog.json, neither helps an upgrade.
1731
+ breaking.push(
1732
+ Object.fromEntries(
1733
+ Object.entries(row).filter(
1734
+ ([key, value]) =>
1735
+ key !== 'ruling' &&
1736
+ key !== 'since' &&
1737
+ value !== '' &&
1738
+ value !== undefined &&
1739
+ !(Array.isArray(value) && value.length === 0)
1740
+ )
1741
+ )
1742
+ );
1743
+ }
1744
+ return Object.keys(classRenames).length
1745
+ ? {
1746
+ breaking,
1747
+ classRenames,
1748
+ classRenamesNote:
1749
+ 'class renames from the beta.36 sweep map: modifiers follow (.old--x → .new--x); ai/guides/migration/v3-beta-css-classes.md',
1750
+ }
1751
+ : { breaking };
1752
+ }
1753
+
1754
+ /*
1755
+ * Rows carry `kind` AND `surface`; 2 of 3 answerers told a script to switch on
1756
+ * `kind` to tell a class rename from a prop rename (2026-09-24).
1757
+ */
1758
+ const ROW_FIELDS =
1759
+ '`surface` says what a rename names (prop | slot | pt | cssVar | class | option); `kind` is only rename vs behaviour; `firstReleasedIn` is the first npm release with the change.';
1760
+
1761
+ function listChanges({ since: rawSince, until: rawUntil } = {}) {
1762
+ // The repo's own tags are spelled `v3.0.0-beta.33` (review D6-12).
1763
+ const since =
1764
+ rawSince == null ? rawSince : String(rawSince).replace(/^v/, '');
1765
+ const until =
1766
+ rawUntil == null ? rawUntil : String(rawUntil).replace(/^v/, '');
1767
+ if (!existsSync(CHANGELOG_PATH)) {
1768
+ return {
1769
+ error: `changelog.json not found at ${CHANGELOG_PATH} — reinstall bitboss-ui (or run \`npm run build\` when working in the library repo).`,
1770
+ };
1771
+ }
1772
+ const doc = JSON.parse(readFileSync(CHANGELOG_PATH, 'utf-8'));
1773
+ const releases = doc.releases ?? [];
1774
+ const known = new Set(releases);
1775
+
1776
+ // A typo'd version must not silently return "nothing changed" — that reads
1777
+ // as a clean upgrade and is the worst possible wrong answer here.
1778
+ for (const [label, value] of [
1779
+ ['since', since],
1780
+ ['until', until],
1781
+ ]) {
1782
+ if (value != null && !known.has(String(value))) {
1783
+ if ((doc.unpublished ?? []).includes(String(value))) {
1784
+ const next = releases.find(
1785
+ (r) => compareVersions(r, String(value)) > 0
1786
+ );
1787
+ return {
1788
+ error: `${value} was never published to npm; its changes shipped in ${next ?? 'the next release'}.`,
1789
+ knownReleases: releases,
1790
+ hint: `Pass the version you installed from npm (for example the one before it, since=${releases.filter((r) => compareVersions(r, String(value)) < 0).at(-1) ?? '…'}).`,
1791
+ };
1792
+ }
1793
+ return {
1794
+ error: `Unknown ${label} version '${value}'.`,
1795
+ knownReleases: releases,
1796
+ hint: 'Pass a version exactly as listed in knownReleases, or omit both to get every break in the v2 → v3 upgrade.',
1797
+ };
1798
+ }
1799
+ }
1800
+
1801
+ const all = doc.breaking ?? [];
1802
+ // No range asked for: the whole v2 → v3 set, which is what the file has
1803
+ // always meant.
1804
+ if (since == null && until == null) {
1805
+ return {
1806
+ version: doc.version,
1807
+ upgrade: doc.upgrade,
1808
+ guide: doc.guide,
1809
+ releases,
1810
+ summary: doc.summary,
1811
+ count: all.length,
1812
+ ...compactChanges(all),
1813
+ hint: `Narrow to one upgrade hop with list_changes({ since: "<your current version>" }) — that answers "what breaks if I bump". ${ROW_FIELDS}`,
1814
+ };
1815
+ }
1816
+
1817
+ const inRange = all.filter((entry) => {
1818
+ const at = entry.firstReleasedIn;
1819
+ // Unreleased rows belong to the future: they ship in whatever comes
1820
+ // next, so they count only when the caller left `until` open.
1821
+ if (at == null) return until == null;
1822
+ if (since != null && compareVersions(at, String(since)) <= 0) return false;
1823
+ if (until != null && compareVersions(at, String(until)) > 0) return false;
1824
+ return true;
1825
+ });
1826
+
1827
+ return {
1828
+ version: doc.version,
1829
+ since: since ?? null,
1830
+ until: until ?? doc.version,
1831
+ count: inRange.length,
1832
+ ...compactChanges(inRange),
1833
+ guide: doc.guide,
1834
+ hint:
1835
+ inRange.length === 0
1836
+ ? 'No breaking changes recorded in that range — features and fixes are deliberately not tracked here, so an empty result means nothing BREAKS, not that nothing changed.'
1837
+ : `Each entry names the component and the new spelling; \`guide\` is the migration page with the full explanation. ${ROW_FIELDS}`,
1838
+ };
1839
+ }
1840
+
472
1841
  function toolCallback(fn) {
473
1842
  return (args) => {
474
1843
  try {
475
1844
  const result = fn(args ?? {});
476
1845
  return {
477
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
1846
+ // Compact JSON: indentation was a quarter of every answer (review D6).
1847
+ content: [{ type: 'text', text: JSON.stringify(result) }],
478
1848
  isError: false,
479
1849
  };
480
1850
  } catch (error) {
@@ -489,18 +1859,34 @@ function toolCallback(fn) {
489
1859
 
490
1860
  const platformSchema = z.enum(RECIPE_PLATFORMS);
491
1861
 
1862
+ /**
1863
+ * Sent once at initialize (review D6-1): an MCP-only agent otherwise had no
1864
+ * way to know which tool answers which question, and read whole guides.
1865
+ */
1866
+ const SERVER_INSTRUCTIONS = [
1867
+ 'bitboss-ui: a Vue 3 component library. Answer from these tools, never from memory — agents that guess invent props.',
1868
+ "- Tailwind v4 app: set cssLayers: TAILWIND_V4_LAYERS ('bitboss-ui/vite') at setup, or utilities lose.",
1869
+ '- A topic or "how do I…" question (dark mode, cascade layers, SSR, a plugin option, a CLI command): search_docs, then open the section it points to.',
1870
+ '- Which component: search_components (empty query = the whole catalog). One component: get_component({ name }) — compact; pass sections for guide prose, include for more.',
1871
+ '- A type in a props table (BbTableColumn, ButtonVariantType): get_component({ name }) returns its definition and values.',
1872
+ '- After writing markup: validate. Before custom CSS: list_tokens.',
1873
+ '- An old name (v2 or earlier-beta prop, slot, pt key, class) that stopped working: search_docs(the old name). Which release changed something, or what a bump breaks: list_changes({ since }), each row has firstReleasedIn.',
1874
+ "- pt in <script> (a const, a wrapper's prop): type it <Name>Props['pt']; Pt* types are not exported.",
1875
+ '- Composables (useToast, useConfirm…): get_composable. Whole pages: list_recipes, get_recipe. Long guides answer with an outline: pass sections.',
1876
+ ].join('\n');
1877
+
492
1878
  /** Register the knowledge-base tools on a fresh McpServer instance. */
493
1879
  function buildServer() {
494
1880
  const server = new McpServer(
495
1881
  { name: 'bitboss-ui', version: packageVersion() },
496
- { capabilities: { tools: {} } }
1882
+ { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS }
497
1883
  );
498
1884
 
499
1885
  server.registerTool(
500
1886
  'search_components',
501
1887
  {
502
1888
  description:
503
- 'Search the bitboss-ui component manifest by name and description, ranked by relevance (exact/prefix name matches first, description matches last). Returns consumer-API components only by default. Use this to find the right Bb* component before writing usage code.',
1889
+ 'Search the bitboss-ui component manifest by name and description, ranked by relevance (exact/prefix name matches first, description matches last). Multi-word queries are matched per word, so "data table" finds BbTable. Also returns `notInLibrary`: the component picker\'s authoritative verdicts for names agents commonly invent — either a redirect ("BbDrawer" is BbOffCanvas) or a confirmation that it does not exist and what to do instead. Returns consumer-API components only by default. Use this to find the right Bb* component before writing usage code. An empty result does NOT mean the need is uncovered — read the `component-picker` guide before hand-rolling anything.',
504
1890
  inputSchema: {
505
1891
  query: z
506
1892
  .string()
@@ -517,7 +1903,7 @@ function buildServer() {
517
1903
  .boolean()
518
1904
  .optional()
519
1905
  .describe(
520
- 'Include reference-only internal components (BbBase*, Common*). Default false — these are not consumer API and should not be recommended.'
1906
+ 'Include reference-only internal components (Common*, listbox internals). Default false — these are not consumer API and should not be recommended. BbBaseButton and the BbBase*Icon glyphs are consumer API and are always included.'
521
1907
  ),
522
1908
  },
523
1909
  },
@@ -528,16 +1914,39 @@ function buildServer() {
528
1914
  'get_component',
529
1915
  {
530
1916
  description:
531
- 'Get the full manifest entry (props/events/slots/models, removed/renamed history) for one bitboss-ui component by exact name, plus the rendered contract markdown content.',
1917
+ "One bitboss-ui component: every prop, event, slot, v-model and pt part (never cut), the types its API uses with their values, the guide's outline and its Gotchas + Accessibility sections. Compact by default; pass `sections` for guide prose and `include` for more. Also answers for a public TYPE name (its definition and values), a v2/beta name that was removed or renamed (what replaced it), and near-miss spellings ('bb-button', 'Button').",
532
1918
  inputSchema: {
533
- name: z.string().describe("Exact component name, e.g. 'BbButton'."),
1919
+ name: z
1920
+ .string()
1921
+ .describe("Component name, e.g. 'BbButton' ('bb-button' works too)."),
1922
+ sections: z
1923
+ .array(z.string())
1924
+ .optional()
1925
+ .describe(
1926
+ "Guide sections to return whole, by title from `guide.sections`, e.g. ['Toggle buttons']. Case-insensitive; a partial title matches."
1927
+ ),
1928
+ include: z
1929
+ .array(
1930
+ z.enum([
1931
+ 'tree',
1932
+ 'cssProps',
1933
+ 'css',
1934
+ 'ptProps',
1935
+ 'history',
1936
+ 'contract',
1937
+ ])
1938
+ )
1939
+ .optional()
1940
+ .describe(
1941
+ 'Extra parts: tree = the component tree, cssProps = CSS variables with descriptions, css = the .bb-* classes it renders (by block; for a selector you must write), ptProps = every pt:* prop row, history = full v2/beta rename records, contract = the whole contract markdown.'
1942
+ ),
534
1943
  maxChars: z
535
1944
  .number()
536
1945
  .int()
537
1946
  .min(0)
538
1947
  .optional()
539
1948
  .describe(
540
- `Cap on the returned contract markdown (default ${MARKDOWN_DEFAULT_MAX_CHARS}; 0 = no cap). The structured props/events/slots are never truncated.`
1949
+ `With include: ['contract'] only — cap on the contract markdown (default ${MARKDOWN_DEFAULT_MAX_CHARS}; 0 = no cap).`
541
1950
  ),
542
1951
  },
543
1952
  },
@@ -571,17 +1980,46 @@ function buildServer() {
571
1980
  toolCallback(listGuides)
572
1981
  );
573
1982
 
1983
+ server.registerTool(
1984
+ 'list_changes',
1985
+ {
1986
+ description:
1987
+ 'Breaking changes between two bitboss-ui releases — what breaks if you bump. Call with since=<the version you are on> before upgrading. Omit both arguments for every break in the v2 → v3 upgrade. Only BREAKING changes are tracked; features and fixes are not.',
1988
+ inputSchema: {
1989
+ since: z
1990
+ .string()
1991
+ .optional()
1992
+ .describe(
1993
+ "Exclusive lower bound — the version you are currently on, e.g. '3.0.0-beta.20'. Its own breaks are excluded; you already have them."
1994
+ ),
1995
+ until: z
1996
+ .string()
1997
+ .optional()
1998
+ .describe(
1999
+ 'Inclusive upper bound (default: the installed version). Unreleased breaks are included only when this is omitted.'
2000
+ ),
2001
+ },
2002
+ },
2003
+ toolCallback(listChanges)
2004
+ );
2005
+
574
2006
  server.registerTool(
575
2007
  'get_guide',
576
2008
  {
577
2009
  description:
578
- "Read one bitboss-ui guide by name (as listed by list_guides, e.g. 'ai-router.md' or 'migration/v2-to-v3.md').",
2010
+ "Read one bitboss-ui guide (names from list_guides, e.g. 'design-tokens' or 'migration/v2-to-v3'). A long guide answers with its outline: then pass `sections`. Pointers such as 'ai/guides/passthrough.md' or 'components/bb-table.md' resolve too.",
579
2011
  inputSchema: {
580
2012
  name: z
581
2013
  .string()
582
2014
  .describe(
583
2015
  "Guide path relative to the guides dir, e.g. 'design-tokens.md'. The '.md' suffix is optional."
584
2016
  ),
2017
+ sections: z
2018
+ .array(z.string())
2019
+ .optional()
2020
+ .describe(
2021
+ "Section titles from the outline, e.g. ['Dark mode']. A ## section includes its ### children."
2022
+ ),
585
2023
  maxChars: z
586
2024
  .number()
587
2025
  .int()
@@ -599,7 +2037,7 @@ function buildServer() {
599
2037
  'list_recipes',
600
2038
  {
601
2039
  description:
602
- 'List available page-level recipes (whole-page compositions), optionally filtered by platform.',
2040
+ 'List the page-level recipes (whole-page compositions) with title, summary, platforms and size, optionally filtered by platform.',
603
2041
  inputSchema: {
604
2042
  platform: platformSchema
605
2043
  .optional()
@@ -613,8 +2051,12 @@ function buildServer() {
613
2051
  'get_recipe',
614
2052
  {
615
2053
  description:
616
- 'Read the full markdown content of one recipe by platform and name.',
2054
+ 'Read one recipe by platform and name — whole by default (recipes are copied whole); pass `sections` to read part of a long one.',
617
2055
  inputSchema: {
2056
+ sections: z
2057
+ .array(z.string())
2058
+ .optional()
2059
+ .describe('Section titles to return instead of the whole recipe.'),
618
2060
  platform: platformSchema.describe(
619
2061
  'Which platform variant of the recipe to read.'
620
2062
  ),
@@ -626,19 +2068,51 @@ function buildServer() {
626
2068
  .int()
627
2069
  .min(0)
628
2070
  .optional()
2071
+ .describe('Optional cap on the returned markdown (default: no cap).'),
2072
+ },
2073
+ },
2074
+ toolCallback(getRecipe)
2075
+ );
2076
+
2077
+ server.registerTool(
2078
+ 'search_docs',
2079
+ {
2080
+ description:
2081
+ 'Find the section that answers a question, across every guide, component guide, component prop and event, composable, recipe and the README. Use it for "how do I…" and "is there…" questions (dark mode, cascade layers, SSR, a plugin option, a CLI command, a migration). Each result is a snippet plus the exact call that reads the whole section.',
2082
+ inputSchema: {
2083
+ query: z
2084
+ .string()
629
2085
  .describe(
630
- `Cap on the returned markdown (default ${MARKDOWN_DEFAULT_MAX_CHARS}; 0 = no cap).`
2086
+ "A few specific words, e.g. 'dark mode class' or 'tailwind cascade layers'."
631
2087
  ),
2088
+ limit: z
2089
+ .number()
2090
+ .int()
2091
+ .positive()
2092
+ .optional()
2093
+ .describe('Max results (default 8, max 20).'),
632
2094
  },
633
2095
  },
634
- toolCallback(getRecipe)
2096
+ toolCallback(searchDocs)
2097
+ );
2098
+
2099
+ server.registerTool(
2100
+ 'get_composable',
2101
+ {
2102
+ description:
2103
+ "Read one composable's doc (useToast, useConfirm, useBbTableContext, useMobile…): what it returns, what host it needs, examples.",
2104
+ inputSchema: {
2105
+ name: z.string().describe("Composable name, e.g. 'useToast'."),
2106
+ },
2107
+ },
2108
+ toolCallback(getComposable)
635
2109
  );
636
2110
 
637
2111
  server.registerTool(
638
2112
  'validate',
639
2113
  {
640
2114
  description:
641
- 'Validate a Vue template/SFC snippet against the installed components.json manifest: reports unknown Bb* props, unknown v-models, and removed/renamed props. Run this after writing bitboss-ui markup.',
2115
+ 'Validate a Vue template/SFC snippet against the installed components.json manifest: reports unknown Bb* props, unknown v-models, removed/renamed props, and imports that are not public (a file inside bitboss-ui/dist, a Pt* type). Run this after writing bitboss-ui markup.',
642
2116
  inputSchema: {
643
2117
  code: z
644
2118
  .string()
@@ -659,8 +2133,21 @@ export async function main() {
659
2133
  const server = buildServer();
660
2134
  const transport = new StdioServerTransport();
661
2135
  await server.connect(transport);
2136
+ // Settle on stdin's end as well as the transport's close. `onclose` does
2137
+ // not fire when the host simply closes the pipe, so awaiting it alone left
2138
+ // the caller's top-level `await main()` pending at exit and Node printed
2139
+ // "Detected unsettled top-level await" on every clean shutdown (2026-09-09).
2140
+ // `once` on both, and idempotent resolve, so whichever arrives first wins.
662
2141
  return new Promise((resolve) => {
663
- transport.onclose = () => resolve();
2142
+ let done = false;
2143
+ const settle = () => {
2144
+ if (done) return;
2145
+ done = true;
2146
+ resolve();
2147
+ };
2148
+ transport.onclose = settle;
2149
+ process.stdin.once('end', settle);
2150
+ process.stdin.once('close', settle);
664
2151
  });
665
2152
  }
666
2153
 
@@ -675,7 +2162,11 @@ export const start = main;
675
2162
  * concurrently. Importing this module does not start a server.
676
2163
  */
677
2164
  export {
2165
+ buildServer,
2166
+ SERVER_INSTRUCTIONS,
678
2167
  searchComponents,
2168
+ searchDocs,
2169
+ getComposable,
679
2170
  getComponent,
680
2171
  listTokens,
681
2172
  listGuides,