@kitn.ai/ui 0.15.1 → 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 (192) 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 +24 -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
@@ -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>;