@kitn.ai/ui 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/README.md +9 -0
  2. package/bin/mcp.js +22 -0
  3. package/dist/bash-InADTalH.js +6 -1
  4. package/dist/components/artifact.d.ts +58 -0
  5. package/dist/components/attachments.d.ts +67 -0
  6. package/dist/components/card-fallback.d.ts +10 -0
  7. package/dist/components/card-renderer.d.ts +13 -0
  8. package/dist/components/card.d.ts +28 -0
  9. package/dist/components/chain-of-thought.d.ts +29 -0
  10. package/dist/components/chat-container.d.ts +19 -0
  11. package/dist/components/chat-scope-picker.d.ts +9 -0
  12. package/dist/components/chat-thread.d.ts +93 -0
  13. package/dist/components/checkpoint.d.ts +20 -0
  14. package/dist/components/choice-card.d.ts +77 -0
  15. package/dist/components/code-block.d.ts +16 -0
  16. package/dist/components/confirm-card.d.ts +57 -0
  17. package/dist/components/context.d.ts +65 -0
  18. package/dist/components/conversation-item.d.ts +8 -0
  19. package/dist/components/conversation-list.d.ts +11 -0
  20. package/dist/components/embed.d.ts +21 -0
  21. package/dist/components/empty.d.ts +43 -0
  22. package/dist/components/feedback-bar.d.ts +45 -0
  23. package/dist/components/file-tree.d.ts +57 -0
  24. package/dist/components/file-upload.d.ts +16 -0
  25. package/dist/components/form-widgets.d.ts +31 -0
  26. package/dist/components/form.d.ts +103 -0
  27. package/dist/components/image.d.ts +12 -0
  28. package/dist/components/link-preview.d.ts +23 -0
  29. package/dist/components/loader.d.ts +60 -0
  30. package/dist/components/markdown.d.ts +8 -0
  31. package/dist/components/message-skills.d.ts +15 -0
  32. package/dist/components/message.d.ts +54 -0
  33. package/dist/components/model-switcher.d.ts +8 -0
  34. package/dist/components/prompt-input.d.ts +38 -0
  35. package/dist/components/prompt-suggestion.d.ts +13 -0
  36. package/dist/components/reasoning.d.ts +20 -0
  37. package/dist/components/response-stream.d.ts +14 -0
  38. package/dist/components/scroll-button.d.ts +7 -0
  39. package/dist/components/slash-command.d.ts +15 -0
  40. package/dist/components/source.d.ts +23 -0
  41. package/dist/components/tasks-card.d.ts +71 -0
  42. package/dist/components/text-shimmer.d.ts +9 -0
  43. package/dist/components/thinking-bar.d.ts +10 -0
  44. package/dist/components/tool.d.ts +16 -0
  45. package/dist/components/use-card-resolution.d.ts +12 -0
  46. package/dist/components/voice-input.d.ts +7 -0
  47. package/dist/core-AYMC6_lb.js +5874 -12
  48. package/dist/css-M7EaDHN_.js +6 -1
  49. package/dist/elements/artifact.d.ts +1 -0
  50. package/dist/elements/attachments.d.ts +1 -0
  51. package/dist/elements/card.d.ts +1 -0
  52. package/dist/elements/cards.d.ts +0 -0
  53. package/dist/elements/chain-of-thought.d.ts +13 -0
  54. package/dist/elements/chat-scope-picker.d.ts +1 -0
  55. package/dist/elements/chat-types.d.ts +41 -0
  56. package/dist/elements/chat-workspace.d.ts +1 -0
  57. package/dist/elements/chat.d.ts +1 -0
  58. package/dist/elements/checkpoint.d.ts +1 -0
  59. package/dist/elements/choice.d.ts +1 -0
  60. package/dist/elements/code-block.d.ts +1 -0
  61. package/dist/elements/confirm-card.d.ts +1 -0
  62. package/dist/elements/context-meter.d.ts +1 -0
  63. package/dist/elements/conversation-list.d.ts +11 -0
  64. package/dist/elements/css.d.ts +1 -0
  65. package/dist/elements/default-input.d.ts +40 -0
  66. package/dist/elements/define.d.ts +42 -0
  67. package/dist/elements/embed.d.ts +1 -0
  68. package/dist/elements/empty.d.ts +1 -0
  69. package/dist/elements/feedback-bar.d.ts +1 -0
  70. package/dist/elements/file-tree.d.ts +1 -0
  71. package/dist/elements/file-upload.d.ts +1 -0
  72. package/dist/elements/form.d.ts +1 -0
  73. package/dist/elements/image.d.ts +1 -0
  74. package/dist/elements/link-preview.d.ts +1 -0
  75. package/dist/elements/loader.d.ts +1 -0
  76. package/dist/elements/markdown.d.ts +1 -0
  77. package/dist/elements/message-skills.d.ts +17 -0
  78. package/dist/elements/message.d.ts +1 -0
  79. package/dist/elements/model-switcher.d.ts +11 -0
  80. package/dist/elements/popover.d.ts +1 -0
  81. package/dist/elements/prompt-input.d.ts +9 -0
  82. package/dist/elements/prompt-suggestions.d.ts +7 -0
  83. package/dist/elements/reasoning.d.ts +1 -0
  84. package/dist/elements/register-impl.d.ts +0 -0
  85. package/dist/elements/register.d.ts +3 -0
  86. package/dist/elements/remote.d.ts +1 -0
  87. package/dist/elements/resizable.d.ts +17 -0
  88. package/dist/elements/response-stream.d.ts +1 -0
  89. package/dist/elements/scroll-button.d.ts +1 -0
  90. package/dist/elements/source.d.ts +18 -0
  91. package/dist/elements/switch.d.ts +1 -0
  92. package/dist/elements/tasks.d.ts +1 -0
  93. package/dist/elements/text-shimmer.d.ts +1 -0
  94. package/dist/elements/thinking-bar.d.ts +1 -0
  95. package/dist/elements/tool.d.ts +1 -0
  96. package/dist/elements/voice-input.d.ts +1 -0
  97. package/dist/elements.d.ts +732 -0
  98. package/dist/engine-javascript-vq0WuIJl.js +2516 -14
  99. package/dist/github-dark-dimmed-DUshB20C.js +4 -1
  100. package/dist/github-light-JYsPkUQd.js +4 -1
  101. package/dist/html-CPZ3oZQ7.js +10 -1
  102. package/dist/index.d.ts +112 -2
  103. package/dist/index.js +13551 -0
  104. package/dist/javascript-C25yR2R2.js +6 -1
  105. package/dist/json-DxJze_jm.js +6 -1
  106. package/dist/kitn-chat.es.js +1 -77
  107. package/dist/llms/llms-full.txt +1 -1
  108. package/dist/llms/llms.txt +1 -1
  109. package/dist/mcp.es.js +2140 -0
  110. package/dist/primitives/card-contract.d.ts +103 -0
  111. package/dist/primitives/card-host.d.ts +12 -0
  112. package/dist/primitives/card-registry.d.ts +17 -0
  113. package/dist/primitives/card-resolution.d.ts +8 -0
  114. package/dist/primitives/card-routing.d.ts +12 -0
  115. package/dist/primitives/card-validate.d.ts +25 -0
  116. package/dist/primitives/chat-config.d.ts +31 -0
  117. package/dist/primitives/controllable.d.ts +13 -0
  118. package/dist/primitives/embed-providers.d.ts +65 -0
  119. package/dist/primitives/highlighter.d.ts +23 -0
  120. package/dist/primitives/link-preview.d.ts +47 -0
  121. package/dist/primitives/pdf-preview.d.ts +50 -0
  122. package/dist/primitives/use-auto-resize.d.ts +8 -0
  123. package/dist/primitives/use-resize-observer.d.ts +1 -0
  124. package/dist/primitives/use-stick-to-bottom.d.ts +5 -0
  125. package/dist/primitives/use-text-stream.d.ts +19 -0
  126. package/dist/primitives/use-voice-recorder.d.ts +9 -0
  127. package/dist/react/index.d.ts +1118 -0
  128. package/dist/react/runtime.d.ts +15 -0
  129. package/dist/react.js +265 -0
  130. package/dist/register-impl-wCsFPoh9.js +77 -0
  131. package/dist/register-ujhr1nBS.js +1 -0
  132. package/dist/remote/host-embed.d.ts +33 -0
  133. package/dist/remote/index.d.ts +2 -0
  134. package/dist/remote/origin.d.ts +5 -0
  135. package/dist/remote/provider-runtime.d.ts +27 -0
  136. package/dist/remote/provider.d.ts +2 -0
  137. package/dist/remote/validate.d.ts +4 -0
  138. package/dist/remote/version.d.ts +4 -0
  139. package/dist/remote/wire.d.ts +53 -0
  140. package/dist/svelte--5p79yCD.js +15 -1
  141. package/dist/tsx-B8rCNbgL.js +6 -1
  142. package/dist/types.d.ts +42 -0
  143. package/dist/typescript-RycA9KXf.js +6 -1
  144. package/dist/ui/action-icons.d.ts +11 -0
  145. package/dist/ui/avatar.d.ts +8 -0
  146. package/dist/ui/badge.d.ts +9 -0
  147. package/dist/ui/button.d.ts +10 -0
  148. package/dist/ui/collapsible.d.ts +27 -0
  149. package/dist/ui/dropdown.d.ts +20 -0
  150. package/dist/ui/hover-card.d.ts +28 -0
  151. package/dist/ui/overlay.d.ts +67 -0
  152. package/dist/ui/popover.d.ts +32 -0
  153. package/dist/ui/resizable.d.ts +76 -0
  154. package/dist/ui/scroll-area.d.ts +5 -0
  155. package/dist/ui/separator.d.ts +5 -0
  156. package/dist/ui/skeleton.d.ts +5 -0
  157. package/dist/ui/switch.d.ts +19 -0
  158. package/dist/ui/textarea.d.ts +6 -0
  159. package/dist/ui/tooltip.d.ts +8 -0
  160. package/dist/utils/cn.d.ts +2 -0
  161. package/dist/vue-BmIZj4XD.js +33 -1
  162. package/frameworks/react/index.tsx +4 -0
  163. package/frameworks/react/runtime.tsx +16 -2
  164. package/llms-full.txt +1 -1
  165. package/llms.txt +1 -1
  166. package/package.json +29 -11
  167. package/src/agent-tooling/archetypes.ts +46 -0
  168. package/src/agent-tooling/integrations/cloudflare.ts +88 -0
  169. package/src/agent-tooling/integrations/langgraph.ts +60 -0
  170. package/src/agent-tooling/integrations/mastra.ts +27 -0
  171. package/src/agent-tooling/integrations/mock.ts +34 -0
  172. package/src/agent-tooling/integrations/ollama.ts +47 -0
  173. package/src/agent-tooling/integrations/openrouter.ts +26 -0
  174. package/src/agent-tooling/integrations/pi.ts +40 -0
  175. package/src/agent-tooling/integrations/pydantic-ai.ts +52 -0
  176. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +44 -0
  177. package/src/agent-tooling/mcp/manifest.ts +128 -0
  178. package/src/agent-tooling/mcp/server.ts +59 -0
  179. package/src/agent-tooling/mcp/stdio.ts +18 -0
  180. package/src/agent-tooling/mcp/tools/debug.ts +305 -0
  181. package/src/agent-tooling/mcp/tools/reference.ts +132 -0
  182. package/src/agent-tooling/mcp/tools/scaffold.ts +1627 -0
  183. package/src/agent-tooling/mcp/tools/theme.ts +340 -0
  184. package/src/agent-tooling/mcp/tools/types.ts +14 -0
  185. package/src/agent-tooling/registry.ts +41 -0
  186. package/src/agent-tooling/types.ts +30 -0
  187. package/src/elements/compiled.css +1 -1
  188. package/src/elements/define.tsx +7 -1
  189. package/src/elements/element-types.d.ts +2 -1
  190. package/src/elements/register-impl.ts +55 -0
  191. package/src/elements/register.ts +17 -51
  192. package/theme.css +4 -2
  193. package/src/components/artifact.stories.tsx +0 -138
  194. package/src/components/attachments.stories.tsx +0 -303
  195. package/src/components/attachments.test.tsx +0 -64
  196. package/src/components/chain-of-thought.stories.tsx +0 -211
  197. package/src/components/chat-container.stories.tsx +0 -187
  198. package/src/components/chat-thread.test.tsx +0 -58
  199. package/src/components/checkpoint.stories.tsx +0 -102
  200. package/src/components/code-block.stories.tsx +0 -150
  201. package/src/components/confirm-card.stories.tsx +0 -74
  202. package/src/components/context.stories.tsx +0 -229
  203. package/src/components/context.test.tsx +0 -133
  204. package/src/components/conversation-item.stories.tsx +0 -125
  205. package/src/components/conversation-list.stories.tsx +0 -133
  206. package/src/components/default-input.test.tsx +0 -111
  207. package/src/components/empty.stories.tsx +0 -434
  208. package/src/components/feedback-bar.stories.tsx +0 -138
  209. package/src/components/feedback-bar.test.tsx +0 -103
  210. package/src/components/file-tree.stories.tsx +0 -73
  211. package/src/components/file-upload.stories.tsx +0 -156
  212. package/src/components/image.stories.tsx +0 -89
  213. package/src/components/loader.stories.tsx +0 -181
  214. package/src/components/markdown.stories.tsx +0 -180
  215. package/src/components/message-action-bar.test.tsx +0 -128
  216. package/src/components/message-narrow.stories.tsx +0 -329
  217. package/src/components/message-skills.stories.tsx +0 -211
  218. package/src/components/message.stories.tsx +0 -281
  219. package/src/components/model-switcher.stories.tsx +0 -123
  220. package/src/components/model-switcher.test.tsx +0 -65
  221. package/src/components/prompt-input.stories.tsx +0 -222
  222. package/src/components/prompt-suggestion.stories.tsx +0 -142
  223. package/src/components/reasoning.stories.tsx +0 -140
  224. package/src/components/resizable.test.tsx +0 -226
  225. package/src/components/scroll-button.stories.tsx +0 -100
  226. package/src/components/slash-command.stories.tsx +0 -163
  227. package/src/components/source-list.test.tsx +0 -152
  228. package/src/components/source.stories.tsx +0 -124
  229. package/src/components/tasks-card.stories.tsx +0 -78
  230. package/src/components/text-shimmer.stories.tsx +0 -87
  231. package/src/components/thinking-bar.stories.tsx +0 -87
  232. package/src/components/tool.stories.tsx +0 -153
  233. package/src/components/voice-input.stories.tsx +0 -83
  234. package/src/elements/artifact.stories.tsx +0 -506
  235. package/src/elements/attachments.stories.tsx +0 -190
  236. package/src/elements/card.stories.tsx +0 -113
  237. package/src/elements/cards.stories.tsx +0 -59
  238. package/src/elements/catalog.stories.tsx +0 -491
  239. package/src/elements/chain-of-thought.declarative.test.tsx +0 -153
  240. package/src/elements/chain-of-thought.stories.tsx +0 -113
  241. package/src/elements/chat-scope-picker.stories.tsx +0 -73
  242. package/src/elements/chat-workspace.stories.tsx +0 -288
  243. package/src/elements/chat.stories.tsx +0 -151
  244. package/src/elements/checkpoint.stories.tsx +0 -72
  245. package/src/elements/choice.stories.tsx +0 -240
  246. package/src/elements/code-block.stories.tsx +0 -83
  247. package/src/elements/composed-shell.stories.tsx +0 -316
  248. package/src/elements/confirm-card.stories.tsx +0 -227
  249. package/src/elements/context-meter.stories.tsx +0 -151
  250. package/src/elements/conversation-list.declarative.test.tsx +0 -137
  251. package/src/elements/conversation-list.stories.tsx +0 -243
  252. package/src/elements/embed.stories.tsx +0 -213
  253. package/src/elements/empty.stories.tsx +0 -111
  254. package/src/elements/feedback-bar.stories.tsx +0 -114
  255. package/src/elements/file-tree.stories.tsx +0 -134
  256. package/src/elements/file-upload.stories.tsx +0 -82
  257. package/src/elements/form.stories.tsx +0 -248
  258. package/src/elements/image.stories.tsx +0 -71
  259. package/src/elements/link-preview.stories.tsx +0 -209
  260. package/src/elements/loader.stories.tsx +0 -88
  261. package/src/elements/markdown.stories.tsx +0 -76
  262. package/src/elements/message-skills.declarative.test.tsx +0 -104
  263. package/src/elements/message-skills.stories.tsx +0 -114
  264. package/src/elements/message.stories.tsx +0 -218
  265. package/src/elements/model-switcher.declarative.test.tsx +0 -130
  266. package/src/elements/model-switcher.stories.tsx +0 -198
  267. package/src/elements/popover.stories.tsx +0 -80
  268. package/src/elements/prompt-input-slash-command.test.tsx +0 -128
  269. package/src/elements/prompt-input-stoppable.test.tsx +0 -88
  270. package/src/elements/prompt-input-toolbar-actions.test.tsx +0 -120
  271. package/src/elements/prompt-input.stories.tsx +0 -331
  272. package/src/elements/prompt-suggestions.declarative.test.tsx +0 -164
  273. package/src/elements/prompt-suggestions.stories.tsx +0 -213
  274. package/src/elements/reasoning.stories.tsx +0 -77
  275. package/src/elements/remote.stories.tsx +0 -314
  276. package/src/elements/resizable.stories.tsx +0 -426
  277. package/src/elements/response-stream.stories.tsx +0 -79
  278. package/src/elements/scroll-button.stories.tsx +0 -202
  279. package/src/elements/scroll-button.test.tsx +0 -148
  280. package/src/elements/source-list.stories.tsx +0 -143
  281. package/src/elements/source.stories.tsx +0 -88
  282. package/src/elements/switch.stories.tsx +0 -56
  283. package/src/elements/tasks.stories.tsx +0 -237
  284. package/src/elements/text-shimmer.stories.tsx +0 -64
  285. package/src/elements/thinking-bar.stories.tsx +0 -72
  286. package/src/elements/tool.stories.tsx +0 -89
  287. package/src/elements/voice-input.stories.tsx +0 -88
  288. package/src/primitives/controllable.test.ts +0 -47
  289. package/src/stories/chat-panel-layout.stories.tsx +0 -145
  290. package/src/stories/chat-scene.tsx +0 -571
  291. package/src/stories/checkpoint-restore.stories.tsx +0 -256
  292. package/src/stories/context-usage.stories.tsx +0 -212
  293. package/src/stories/conversation-with-reasoning.stories.tsx +0 -182
  294. package/src/stories/conversation-with-sources.stories.tsx +0 -471
  295. package/src/stories/docs/Accessibility.mdx +0 -119
  296. package/src/stories/docs/ChildElements.mdx +0 -269
  297. package/src/stories/docs/ForAIAgents.mdx +0 -162
  298. package/src/stories/docs/GettingStarted.mdx +0 -65
  299. package/src/stories/docs/Installation.mdx +0 -83
  300. package/src/stories/docs/Introduction.mdx +0 -50
  301. package/src/stories/docs/SolidJsAdvanced.mdx +0 -17
  302. package/src/stories/docs/Theming.mdx +0 -85
  303. package/src/stories/docs/element-controls.ts +0 -121
  304. package/src/stories/docs/frameworks/Angular.mdx +0 -245
  305. package/src/stories/docs/frameworks/Html.mdx +0 -227
  306. package/src/stories/docs/frameworks/Overview.mdx +0 -47
  307. package/src/stories/docs/frameworks/React.mdx +0 -227
  308. package/src/stories/docs/frameworks/Solid.mdx +0 -173
  309. package/src/stories/docs/frameworks/Svelte.mdx +0 -194
  310. package/src/stories/docs/frameworks/Vue.mdx +0 -238
  311. package/src/stories/docs/generative-ui-overview.mdx +0 -186
  312. package/src/stories/docs/recipes/SpeechToText.mdx +0 -7
  313. package/src/stories/docs/recipes/Streaming.mdx +0 -68
  314. package/src/stories/docs/recipes/TextToSpeech.mdx +0 -35
  315. package/src/stories/docs/theme-editor/canvas.tsx +0 -32
  316. package/src/stories/docs/theme-editor/inspector.tsx +0 -66
  317. package/src/stories/docs/theme-editor/presets.test.ts +0 -32
  318. package/src/stories/docs/theme-editor/presets.ts +0 -64
  319. package/src/stories/docs/theme-editor/theme-css.test.ts +0 -19
  320. package/src/stories/docs/theme-editor/theme-css.ts +0 -15
  321. package/src/stories/docs/theme-editor/theme-editor.tsx +0 -146
  322. package/src/stories/docs/theme-tokens.tsx +0 -174
  323. package/src/stories/examples/ChoosingComponents.mdx +0 -106
  324. package/src/stories/examples/sample-data.ts +0 -79
  325. package/src/stories/examples/usage/checkpoint-restore.ts +0 -156
  326. package/src/stories/examples/usage/context-usage.ts +0 -591
  327. package/src/stories/examples/usage/conversation-with-reasoning.ts +0 -224
  328. package/src/stories/examples/usage/conversation-with-sources.ts +0 -589
  329. package/src/stories/examples/usage/empty-state.ts +0 -144
  330. package/src/stories/examples/usage/full-chat-app.ts +0 -277
  331. package/src/stories/examples/usage/index.ts +0 -63
  332. package/src/stories/examples/usage/message-actions.ts +0 -704
  333. package/src/stories/examples/usage/pattern-centered-conversation.ts +0 -446
  334. package/src/stories/examples/usage/pattern-chat-panel-layout.ts +0 -442
  335. package/src/stories/examples/usage/pattern-docked-widget.ts +0 -479
  336. package/src/stories/examples/usage/prompt-input-variants.ts +0 -1356
  337. package/src/stories/examples/usage/streaming-response.ts +0 -687
  338. package/src/stories/examples/usage/types.ts +0 -33
  339. package/src/stories/full-chat.stories.tsx +0 -18
  340. package/src/stories/message-actions.stories.tsx +0 -230
  341. package/src/stories/pattern-centered-conversation.stories.tsx +0 -93
  342. package/src/stories/pattern-docked-widget.stories.tsx +0 -93
  343. package/src/stories/pattern-empty-state.stories.tsx +0 -76
  344. package/src/stories/prompt-input-variants.stories.tsx +0 -456
  345. package/src/stories/streaming-response.stories.tsx +0 -438
  346. package/src/stories/theme-editor.stories.tsx +0 -16
  347. package/src/stories/token-reference.stories.tsx +0 -18
  348. package/src/stories/typography.stories.tsx +0 -78
  349. package/src/ui/avatar.stories.tsx +0 -103
  350. package/src/ui/badge.stories.tsx +0 -86
  351. package/src/ui/button.stories.tsx +0 -145
  352. package/src/ui/collapsible.stories.tsx +0 -69
  353. package/src/ui/dropdown.stories.tsx +0 -59
  354. package/src/ui/hover-card.stories.tsx +0 -77
  355. package/src/ui/hover-card.test.tsx +0 -30
  356. package/src/ui/overlay.stories.tsx +0 -115
  357. package/src/ui/popover.stories.tsx +0 -81
  358. package/src/ui/popover.test.tsx +0 -99
  359. package/src/ui/resizable.stories.tsx +0 -236
  360. package/src/ui/scroll-area.stories.tsx +0 -50
  361. package/src/ui/separator.stories.tsx +0 -81
  362. package/src/ui/skeleton.stories.tsx +0 -337
  363. package/src/ui/switch.stories.tsx +0 -51
  364. package/src/ui/switch.test.tsx +0 -59
  365. package/src/ui/textarea.stories.tsx +0 -76
  366. package/src/ui/tooltip.stories.tsx +0 -74
@@ -0,0 +1,340 @@
1
+ import { z } from 'zod';
2
+ import type { Tool } from './types';
3
+
4
+ /**
5
+ * theme — produce a `--kai-*` CSS token override block from a brand color or
6
+ * description. Tokens are sourced exclusively from the real names in theme.css.
7
+ *
8
+ * Real --kai-color-* names (verified against repo-root theme.css):
9
+ * --kai-color-primary → brand color
10
+ * --kai-color-primary-foreground → AA-contrast fg (white or black)
11
+ * --kai-color-ring → focus ring (brand color)
12
+ * --kai-color-accent → tinted accent surface
13
+ * --kai-color-accent-foreground → text on accent surface
14
+ */
15
+
16
+ // ─── hex color utilities (no deps) ──────────────────────────────────────────
17
+
18
+ /** Parse #rgb or #rrggbb → { r, g, b } 0-255. Returns null on failure. */
19
+ function parseHex(hex: string): { r: number; g: number; b: number } | null {
20
+ const s = hex.trim().replace(/^#/, '');
21
+ if (s.length === 3) {
22
+ const r = parseInt(s[0] + s[0], 16);
23
+ const g = parseInt(s[1] + s[1], 16);
24
+ const b = parseInt(s[2] + s[2], 16);
25
+ if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
26
+ return { r, g, b };
27
+ }
28
+ if (s.length === 6) {
29
+ const r = parseInt(s.slice(0, 2), 16);
30
+ const g = parseInt(s.slice(2, 4), 16);
31
+ const b = parseInt(s.slice(4, 6), 16);
32
+ if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
33
+ return { r, g, b };
34
+ }
35
+ return null;
36
+ }
37
+
38
+ function toHex(r: number, g: number, b: number): string {
39
+ return (
40
+ '#' +
41
+ [r, g, b]
42
+ .map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0'))
43
+ .join('')
44
+ );
45
+ }
46
+
47
+ /**
48
+ * Relative luminance (WCAG 2.1) — used for AA contrast check.
49
+ * Returns 0 (black) to 1 (white).
50
+ */
51
+ function relativeLuminance(r: number, g: number, b: number): number {
52
+ const lin = (c: number) => {
53
+ const s = c / 255;
54
+ return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
55
+ };
56
+ return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
57
+ }
58
+
59
+ /** White or black for maximum contrast against the brand color. */
60
+ function foreground(r: number, g: number, b: number): '#ffffff' | '#000000' {
61
+ const lum = relativeLuminance(r, g, b);
62
+ // Contrast against white = (1 + 0.05) / (lum + 0.05)
63
+ // Contrast against black = (lum + 0.05) / (0 + 0.05)
64
+ const contrastWhite = 1.05 / (lum + 0.05);
65
+ const contrastBlack = (lum + 0.05) / 0.05;
66
+ return contrastWhite >= contrastBlack ? '#ffffff' : '#000000';
67
+ }
68
+
69
+ /** Lighten a color by a ratio 0-1 (moves toward white). */
70
+ function lighten(r: number, g: number, b: number, ratio: number): string {
71
+ return toHex(
72
+ r + (255 - r) * ratio,
73
+ g + (255 - g) * ratio,
74
+ b + (255 - b) * ratio,
75
+ );
76
+ }
77
+
78
+ /** Darken a color by a ratio 0-1 (moves toward black). */
79
+ function darken(r: number, g: number, b: number, ratio: number): string {
80
+ return toHex(r * (1 - ratio), g * (1 - ratio), b * (1 - ratio));
81
+ }
82
+
83
+ /** Produce a tinted accent surface (very light tint of the brand color). */
84
+ function accentSurface(r: number, g: number, b: number): string {
85
+ return lighten(r, g, b, 0.88);
86
+ }
87
+
88
+ /** Dark-mode variant: lighten the brand so it reads well on dark backgrounds. */
89
+ function darkModeBrand(r: number, g: number, b: number): string {
90
+ const lum = relativeLuminance(r, g, b);
91
+ // If brand is already light enough for dark bg, keep it; otherwise lighten.
92
+ if (lum > 0.25) return toHex(r, g, b);
93
+ return lighten(r, g, b, 0.35);
94
+ }
95
+
96
+ /** Dark-mode accent surface: subtle dark tint of brand. */
97
+ function darkAccentSurface(r: number, g: number, b: number): string {
98
+ return darken(r, g, b, 0.75);
99
+ }
100
+
101
+ // ─── keyword → hex fallback map ──────────────────────────────────────────────
102
+
103
+ const KEYWORD_COLORS: Record<string, string> = {
104
+ blue: '#3b82f6',
105
+ navy: '#1e3a8a',
106
+ sky: '#0ea5e9',
107
+ cyan: '#06b6d4',
108
+ teal: '#14b8a6',
109
+ green: '#22c55e',
110
+ emerald: '#10b981',
111
+ lime: '#84cc16',
112
+ yellow: '#eab308',
113
+ amber: '#f59e0b',
114
+ orange: '#f97316',
115
+ red: '#ef4444',
116
+ rose: '#f43f5e',
117
+ pink: '#ec4899',
118
+ purple: '#a855f7',
119
+ violet: '#7c3aed',
120
+ indigo: '#6366f1',
121
+ slate: '#64748b',
122
+ gray: '#6b7280',
123
+ zinc: '#71717a',
124
+ neutral: '#737373',
125
+ stone: '#78716c',
126
+ white: '#f8fafc',
127
+ black: '#0f172a',
128
+ };
129
+
130
+ const DEFAULT_BRAND = '#6366f1'; // indigo — kit's own brand feel
131
+
132
+ /**
133
+ * Resolve a brand hex from input.
134
+ * Returns { hex, note } where note explains the assumption if we guessed.
135
+ */
136
+ function resolveBrand(
137
+ brand?: string,
138
+ description?: string,
139
+ ): { hex: string; r: number; g: number; b: number; note: string } {
140
+ // 1. Explicit hex
141
+ if (brand) {
142
+ const parsed = parseHex(brand);
143
+ if (parsed) {
144
+ return { hex: brand.startsWith('#') ? brand : `#${brand}`, ...parsed, note: '' };
145
+ }
146
+ // brand provided but unparseable — fall through with a note
147
+ const fallback = parseHex(DEFAULT_BRAND)!;
148
+ return {
149
+ hex: DEFAULT_BRAND,
150
+ ...fallback,
151
+ note: `Could not parse \`${brand}\` as a hex color — defaulted to **${DEFAULT_BRAND}** (indigo). Pass a valid \`#rgb\` or \`#rrggbb\` value to use your color.`,
152
+ };
153
+ }
154
+
155
+ // 2. Description → keyword match
156
+ if (description) {
157
+ const lower = description.toLowerCase();
158
+ for (const [keyword, hex] of Object.entries(KEYWORD_COLORS)) {
159
+ if (lower.includes(keyword)) {
160
+ const parsed = parseHex(hex)!;
161
+ return {
162
+ hex,
163
+ ...parsed,
164
+ note: `No brand color provided — inferred **${hex}** (${keyword}) from description. Override with \`brand: '#rrggbb'\` to use an exact color.`,
165
+ };
166
+ }
167
+ }
168
+ // Description present but no keyword matched → tasteful default
169
+ const parsed = parseHex(DEFAULT_BRAND)!;
170
+ return {
171
+ hex: DEFAULT_BRAND,
172
+ ...parsed,
173
+ note: `No recognizable color keyword in description — defaulted to **${DEFAULT_BRAND}** (indigo). Override with \`brand: '#rrggbb'\` for an exact color.`,
174
+ };
175
+ }
176
+
177
+ // 3. Nothing provided → kit brand default
178
+ const parsed = parseHex(DEFAULT_BRAND)!;
179
+ return {
180
+ hex: DEFAULT_BRAND,
181
+ ...parsed,
182
+ note: `No brand color or description provided — defaulted to **${DEFAULT_BRAND}** (indigo, the kit's own brand). Pass \`brand: '#rrggbb'\` to use your color.`,
183
+ };
184
+ }
185
+
186
+ // ─── CSS block builders ───────────────────────────────────────────────────────
187
+
188
+ interface TokenSet {
189
+ primary: string;
190
+ primaryFg: string;
191
+ ring: string;
192
+ accent: string;
193
+ accentFg: string;
194
+ }
195
+
196
+ function buildTokenSet(r: number, g: number, b: number): TokenSet {
197
+ const primary = toHex(r, g, b);
198
+ const primaryFg = foreground(r, g, b);
199
+ const accent = accentSurface(r, g, b);
200
+ // foreground on the very-light accent surface
201
+ const accentFgColor = foreground(
202
+ ...([accent]
203
+ .map((h) => parseHex(h)!)
204
+ .flatMap((c) => [c.r, c.g, c.b]) as [number, number, number]),
205
+ );
206
+ return {
207
+ primary,
208
+ primaryFg,
209
+ ring: primary,
210
+ accent,
211
+ accentFg: accentFgColor,
212
+ };
213
+ }
214
+
215
+ function buildDarkTokenSet(r: number, g: number, b: number): TokenSet {
216
+ const darkBrand = darkModeBrand(r, g, b);
217
+ const parsed = parseHex(darkBrand)!;
218
+ const primary = darkBrand;
219
+ const primaryFg = foreground(parsed.r, parsed.g, parsed.b);
220
+ const accent = darkAccentSurface(r, g, b);
221
+ const accentFgParsed = parseHex(accent)!;
222
+ return {
223
+ primary,
224
+ primaryFg,
225
+ ring: darkBrand,
226
+ accent,
227
+ accentFg: foreground(accentFgParsed.r, accentFgParsed.g, accentFgParsed.b),
228
+ };
229
+ }
230
+
231
+ function cssBlock(selector: string, tokens: TokenSet): string {
232
+ return [
233
+ `${selector} {`,
234
+ ` --kai-color-primary: ${tokens.primary};`,
235
+ ` --kai-color-primary-foreground: ${tokens.primaryFg};`,
236
+ ` --kai-color-ring: ${tokens.ring};`,
237
+ ` --kai-color-accent: ${tokens.accent};`,
238
+ ` --kai-color-accent-foreground: ${tokens.accentFg};`,
239
+ `}`,
240
+ ].join('\n');
241
+ }
242
+
243
+ // ─── Tool definition ─────────────────────────────────────────────────────────
244
+
245
+ export const theme: Tool = {
246
+ name: 'theme',
247
+ description:
248
+ 'Generate a --kai-* CSS token override block from a brand color or description. ' +
249
+ 'Paste the block into your global stylesheet to brand every kai-* element in one shot.',
250
+
251
+ inputSchema: z.object({
252
+ brand: z
253
+ .string()
254
+ .optional()
255
+ .describe('Brand color as #rgb or #rrggbb hex (e.g. "#7c3aed")'),
256
+ description: z
257
+ .string()
258
+ .optional()
259
+ .describe(
260
+ 'Natural-language description of your product (used to infer a color when `brand` is omitted)',
261
+ ),
262
+ mode: z
263
+ .enum(['light', 'dark', 'both'])
264
+ .optional()
265
+ .describe(
266
+ '"light" → :root only (default); "dark" → .dark only; "both" → :root + .dark',
267
+ ),
268
+ }),
269
+
270
+ handler: async (args) => {
271
+ const {
272
+ brand,
273
+ description,
274
+ mode = 'light',
275
+ } = args as { brand?: string; description?: string; mode?: 'light' | 'dark' | 'both' };
276
+
277
+ const { hex, r, g, b, note } = resolveBrand(brand, description);
278
+
279
+ const lightTokens = buildTokenSet(r, g, b);
280
+ const darkTokens = buildDarkTokenSet(r, g, b);
281
+
282
+ // Which blocks to emit
283
+ const blocks: string[] = [];
284
+ if (mode === 'light' || mode === 'both') {
285
+ blocks.push(cssBlock(':root', lightTokens));
286
+ }
287
+ if (mode === 'dark' || mode === 'both') {
288
+ blocks.push(cssBlock('.dark', darkTokens));
289
+ }
290
+
291
+ const cssOutput = blocks.join('\n\n');
292
+
293
+ const noteLabel = note.startsWith('Could not parse') ? 'Note' : 'Assumption';
294
+ const noteSection = note ? `\n> **${noteLabel}:** ${note}\n` : '';
295
+
296
+ const text = `\
297
+ ## AI/UI theme override — \`${hex}\`
298
+ ${noteSection}
299
+ Paste this block into your **global stylesheet** (before the \`@import\` of \`@kitn.ai/ui\` or after — order doesn't matter since \`--kai-*\` tokens are resolved at runtime via \`var()\` fallbacks). For \`mode:'dark'\` overrides, the \`.dark\` class must be on a parent element (e.g. \`<html class="dark">\`) for them to take effect.
300
+
301
+ \`\`\`css
302
+ ${cssOutput}
303
+ \`\`\`
304
+
305
+ ### How it works
306
+
307
+ The \`--kai-color-*\` tokens pierce the Shadow DOM via CSS custom-property inheritance. Every \`kai-*\` element reads them through a \`var(--kai-color-primary, <default>)\` fallback chain defined in \`theme.css\`. Setting them on \`:root\` (or a wrapper element) is enough to rebrand everything globally.
308
+
309
+ **Tokens emitted** (verified names from \`theme.css\`):
310
+ - \`--kai-color-primary\` — primary brand color
311
+ - \`--kai-color-primary-foreground\` — AA-contrast foreground on primary (auto-selected black/white)
312
+ - \`--kai-color-ring\` — keyboard focus ring
313
+ - \`--kai-color-accent\` — tinted accent surface
314
+ - \`--kai-color-accent-foreground\` — text on accent surface
315
+
316
+ ### Apply to a subtree only
317
+
318
+ \`\`\`css
319
+ /* scope to a specific container instead of :root */
320
+ .my-chat-widget {
321
+ ${blocks[0]
322
+ ?.split('\n')
323
+ .slice(1, -1)
324
+ .map((l) => ' ' + l)
325
+ .join('\n')}
326
+ }
327
+ \`\`\`
328
+
329
+ ### Fine-tune the full palette
330
+
331
+ The theme editor lets you tweak every token interactively and copy the result:
332
+
333
+ **→ [Open Theme Editor](https://ui.kitn.ai/theme/editor/)**
334
+
335
+ For the complete token list see the [theming guide](https://ui.kitn.ai/guides/theming/) and the source \`theme.css\` in the package root.
336
+ `;
337
+
338
+ return { content: [{ type: 'text', text }] };
339
+ },
340
+ };
@@ -0,0 +1,14 @@
1
+ import type { z } from 'zod';
2
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
+
4
+ /**
5
+ * The shape every AI/UI MCP tool module exports. The server reads `inputSchema`
6
+ * (a zod object) to advertise the tool over the protocol — converting it to JSON
7
+ * Schema — and calls `handler` when the tool is invoked.
8
+ */
9
+ export interface Tool {
10
+ name: string;
11
+ description: string;
12
+ inputSchema: z.ZodObject<z.ZodRawShape>;
13
+ handler: (args: Record<string, unknown>) => Promise<CallToolResult>;
14
+ }
@@ -0,0 +1,41 @@
1
+ import type { Integration, Archetype } from './types';
2
+ import openrouter from './integrations/openrouter';
3
+ import vercelAiSdk from './integrations/vercel-ai-sdk';
4
+ import langgraph from './integrations/langgraph';
5
+ import cloudflare from './integrations/cloudflare';
6
+ import ollama from './integrations/ollama';
7
+ import mastra from './integrations/mastra';
8
+ import pi from './integrations/pi';
9
+ import pydanticAi from './integrations/pydantic-ai';
10
+ import mock from './integrations/mock';
11
+ import { archetypes as _archetypes } from './archetypes';
12
+
13
+ export const integrations: Integration[] = [
14
+ openrouter,
15
+ vercelAiSdk,
16
+ langgraph,
17
+ cloudflare,
18
+ ollama,
19
+ mastra,
20
+ pi,
21
+ pydanticAi,
22
+ mock,
23
+ ];
24
+
25
+ export const archetypes: Archetype[] = _archetypes;
26
+
27
+ export function getIntegration(id: string): Integration | undefined {
28
+ return integrations.find((i) => i.id === id);
29
+ }
30
+
31
+ export function getArchetype(id: string): Archetype | undefined {
32
+ return archetypes.find((a) => a.id === id);
33
+ }
34
+
35
+ export function listIntegrations(): Integration[] {
36
+ return integrations;
37
+ }
38
+
39
+ export function listArchetypes(): Archetype[] {
40
+ return archetypes;
41
+ }
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+
3
+ export const Category = z.enum(['provider', 'gateway', 'framework', 'harness', 'mock']);
4
+ export const Language = z.enum(['ts', 'python']);
5
+ export const StreamFormat = z.enum(['openai-sse', 'ai-sdk', 'native']);
6
+ export const Framework = z.enum(['html', 'react', 'next', 'vue', 'svelte', 'fastapi', 'express', 'worker', 'tanstack-start']);
7
+ export const Placement = z.enum(['side', 'full-page', 'docked-widget', 'inline']);
8
+
9
+ export const IntegrationSchema = z.object({
10
+ id: z.string(),
11
+ title: z.string(),
12
+ category: Category,
13
+ language: Language,
14
+ streamFormat: StreamFormat,
15
+ envVars: z.array(z.string()).default([]),
16
+ routeTemplates: z.record(z.string(), z.string()), // keyed by Framework value → code string
17
+ streamMapping: z.string(), // prose: how the stream maps to messages
18
+ runNote: z.string(),
19
+ docsSlug: z.string(),
20
+ });
21
+ export type Integration = z.infer<typeof IntegrationSchema>;
22
+
23
+ export const ArchetypeSchema = z.object({
24
+ id: z.string(),
25
+ title: z.string(),
26
+ components: z.array(z.string()), // kai-* tags, e.g. ['kai-chat', 'kai-sources']
27
+ defaultPlacement: Placement,
28
+ docsSlug: z.string(),
29
+ });
30
+ export type Archetype = z.infer<typeof ArchetypeSchema>;