@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.
- package/README.md +9 -0
- package/bin/mcp.js +22 -0
- package/dist/bash-InADTalH.js +6 -1
- package/dist/components/artifact.d.ts +58 -0
- package/dist/components/attachments.d.ts +67 -0
- package/dist/components/card-fallback.d.ts +10 -0
- package/dist/components/card-renderer.d.ts +13 -0
- package/dist/components/card.d.ts +28 -0
- package/dist/components/chain-of-thought.d.ts +29 -0
- package/dist/components/chat-container.d.ts +19 -0
- package/dist/components/chat-scope-picker.d.ts +9 -0
- package/dist/components/chat-thread.d.ts +93 -0
- package/dist/components/checkpoint.d.ts +20 -0
- package/dist/components/choice-card.d.ts +77 -0
- package/dist/components/code-block.d.ts +16 -0
- package/dist/components/confirm-card.d.ts +57 -0
- package/dist/components/context.d.ts +65 -0
- package/dist/components/conversation-item.d.ts +8 -0
- package/dist/components/conversation-list.d.ts +11 -0
- package/dist/components/embed.d.ts +21 -0
- package/dist/components/empty.d.ts +43 -0
- package/dist/components/feedback-bar.d.ts +45 -0
- package/dist/components/file-tree.d.ts +57 -0
- package/dist/components/file-upload.d.ts +16 -0
- package/dist/components/form-widgets.d.ts +31 -0
- package/dist/components/form.d.ts +103 -0
- package/dist/components/image.d.ts +12 -0
- package/dist/components/link-preview.d.ts +23 -0
- package/dist/components/loader.d.ts +60 -0
- package/dist/components/markdown.d.ts +8 -0
- package/dist/components/message-skills.d.ts +15 -0
- package/dist/components/message.d.ts +54 -0
- package/dist/components/model-switcher.d.ts +8 -0
- package/dist/components/prompt-input.d.ts +38 -0
- package/dist/components/prompt-suggestion.d.ts +13 -0
- package/dist/components/reasoning.d.ts +20 -0
- package/dist/components/response-stream.d.ts +14 -0
- package/dist/components/scroll-button.d.ts +7 -0
- package/dist/components/slash-command.d.ts +15 -0
- package/dist/components/source.d.ts +23 -0
- package/dist/components/tasks-card.d.ts +71 -0
- package/dist/components/text-shimmer.d.ts +9 -0
- package/dist/components/thinking-bar.d.ts +10 -0
- package/dist/components/tool.d.ts +16 -0
- package/dist/components/use-card-resolution.d.ts +12 -0
- package/dist/components/voice-input.d.ts +7 -0
- package/dist/core-AYMC6_lb.js +5874 -12
- package/dist/css-M7EaDHN_.js +6 -1
- package/dist/elements/artifact.d.ts +1 -0
- package/dist/elements/attachments.d.ts +1 -0
- package/dist/elements/card.d.ts +1 -0
- package/dist/elements/cards.d.ts +0 -0
- package/dist/elements/chain-of-thought.d.ts +13 -0
- package/dist/elements/chat-scope-picker.d.ts +1 -0
- package/dist/elements/chat-types.d.ts +41 -0
- package/dist/elements/chat-workspace.d.ts +1 -0
- package/dist/elements/chat.d.ts +1 -0
- package/dist/elements/checkpoint.d.ts +1 -0
- package/dist/elements/choice.d.ts +1 -0
- package/dist/elements/code-block.d.ts +1 -0
- package/dist/elements/confirm-card.d.ts +1 -0
- package/dist/elements/context-meter.d.ts +1 -0
- package/dist/elements/conversation-list.d.ts +11 -0
- package/dist/elements/css.d.ts +1 -0
- package/dist/elements/default-input.d.ts +40 -0
- package/dist/elements/define.d.ts +42 -0
- package/dist/elements/embed.d.ts +1 -0
- package/dist/elements/empty.d.ts +1 -0
- package/dist/elements/feedback-bar.d.ts +1 -0
- package/dist/elements/file-tree.d.ts +1 -0
- package/dist/elements/file-upload.d.ts +1 -0
- package/dist/elements/form.d.ts +1 -0
- package/dist/elements/image.d.ts +1 -0
- package/dist/elements/link-preview.d.ts +1 -0
- package/dist/elements/loader.d.ts +1 -0
- package/dist/elements/markdown.d.ts +1 -0
- package/dist/elements/message-skills.d.ts +17 -0
- package/dist/elements/message.d.ts +1 -0
- package/dist/elements/model-switcher.d.ts +11 -0
- package/dist/elements/popover.d.ts +1 -0
- package/dist/elements/prompt-input.d.ts +9 -0
- package/dist/elements/prompt-suggestions.d.ts +7 -0
- package/dist/elements/reasoning.d.ts +1 -0
- package/dist/elements/register-impl.d.ts +0 -0
- package/dist/elements/register.d.ts +3 -0
- package/dist/elements/remote.d.ts +1 -0
- package/dist/elements/resizable.d.ts +17 -0
- package/dist/elements/response-stream.d.ts +1 -0
- package/dist/elements/scroll-button.d.ts +1 -0
- package/dist/elements/source.d.ts +18 -0
- package/dist/elements/switch.d.ts +1 -0
- package/dist/elements/tasks.d.ts +1 -0
- package/dist/elements/text-shimmer.d.ts +1 -0
- package/dist/elements/thinking-bar.d.ts +1 -0
- package/dist/elements/tool.d.ts +1 -0
- package/dist/elements/voice-input.d.ts +1 -0
- package/dist/elements.d.ts +732 -0
- package/dist/engine-javascript-vq0WuIJl.js +2516 -14
- package/dist/github-dark-dimmed-DUshB20C.js +4 -1
- package/dist/github-light-JYsPkUQd.js +4 -1
- package/dist/html-CPZ3oZQ7.js +10 -1
- package/dist/index.d.ts +112 -2
- package/dist/index.js +13551 -0
- package/dist/javascript-C25yR2R2.js +6 -1
- package/dist/json-DxJze_jm.js +6 -1
- package/dist/kitn-chat.es.js +1 -77
- package/dist/llms/llms-full.txt +1 -1
- package/dist/llms/llms.txt +1 -1
- package/dist/mcp.es.js +2140 -0
- package/dist/primitives/card-contract.d.ts +103 -0
- package/dist/primitives/card-host.d.ts +12 -0
- package/dist/primitives/card-registry.d.ts +17 -0
- package/dist/primitives/card-resolution.d.ts +8 -0
- package/dist/primitives/card-routing.d.ts +12 -0
- package/dist/primitives/card-validate.d.ts +25 -0
- package/dist/primitives/chat-config.d.ts +31 -0
- package/dist/primitives/controllable.d.ts +13 -0
- package/dist/primitives/embed-providers.d.ts +65 -0
- package/dist/primitives/highlighter.d.ts +23 -0
- package/dist/primitives/link-preview.d.ts +47 -0
- package/dist/primitives/pdf-preview.d.ts +50 -0
- package/dist/primitives/use-auto-resize.d.ts +8 -0
- package/dist/primitives/use-resize-observer.d.ts +1 -0
- package/dist/primitives/use-stick-to-bottom.d.ts +5 -0
- package/dist/primitives/use-text-stream.d.ts +19 -0
- package/dist/primitives/use-voice-recorder.d.ts +9 -0
- package/dist/react/index.d.ts +1118 -0
- package/dist/react/runtime.d.ts +15 -0
- package/dist/react.js +265 -0
- package/dist/register-impl-wCsFPoh9.js +77 -0
- package/dist/register-ujhr1nBS.js +1 -0
- package/dist/remote/host-embed.d.ts +33 -0
- package/dist/remote/index.d.ts +2 -0
- package/dist/remote/origin.d.ts +5 -0
- package/dist/remote/provider-runtime.d.ts +27 -0
- package/dist/remote/provider.d.ts +2 -0
- package/dist/remote/validate.d.ts +4 -0
- package/dist/remote/version.d.ts +4 -0
- package/dist/remote/wire.d.ts +53 -0
- package/dist/svelte--5p79yCD.js +15 -1
- package/dist/tsx-B8rCNbgL.js +6 -1
- package/dist/types.d.ts +42 -0
- package/dist/typescript-RycA9KXf.js +6 -1
- package/dist/ui/action-icons.d.ts +11 -0
- package/dist/ui/avatar.d.ts +8 -0
- package/dist/ui/badge.d.ts +9 -0
- package/dist/ui/button.d.ts +10 -0
- package/dist/ui/collapsible.d.ts +27 -0
- package/dist/ui/dropdown.d.ts +20 -0
- package/dist/ui/hover-card.d.ts +28 -0
- package/dist/ui/overlay.d.ts +67 -0
- package/dist/ui/popover.d.ts +32 -0
- package/dist/ui/resizable.d.ts +76 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/separator.d.ts +5 -0
- package/dist/ui/skeleton.d.ts +5 -0
- package/dist/ui/switch.d.ts +19 -0
- package/dist/ui/textarea.d.ts +6 -0
- package/dist/ui/tooltip.d.ts +8 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/vue-BmIZj4XD.js +33 -1
- package/frameworks/react/index.tsx +4 -0
- package/frameworks/react/runtime.tsx +16 -2
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +29 -11
- package/src/agent-tooling/archetypes.ts +46 -0
- package/src/agent-tooling/integrations/cloudflare.ts +88 -0
- package/src/agent-tooling/integrations/langgraph.ts +60 -0
- package/src/agent-tooling/integrations/mastra.ts +27 -0
- package/src/agent-tooling/integrations/mock.ts +34 -0
- package/src/agent-tooling/integrations/ollama.ts +47 -0
- package/src/agent-tooling/integrations/openrouter.ts +26 -0
- package/src/agent-tooling/integrations/pi.ts +40 -0
- package/src/agent-tooling/integrations/pydantic-ai.ts +52 -0
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +44 -0
- package/src/agent-tooling/mcp/manifest.ts +128 -0
- package/src/agent-tooling/mcp/server.ts +59 -0
- package/src/agent-tooling/mcp/stdio.ts +18 -0
- package/src/agent-tooling/mcp/tools/debug.ts +305 -0
- package/src/agent-tooling/mcp/tools/reference.ts +132 -0
- package/src/agent-tooling/mcp/tools/scaffold.ts +1627 -0
- package/src/agent-tooling/mcp/tools/theme.ts +340 -0
- package/src/agent-tooling/mcp/tools/types.ts +14 -0
- package/src/agent-tooling/registry.ts +41 -0
- package/src/agent-tooling/types.ts +30 -0
- package/src/elements/compiled.css +1 -1
- package/src/elements/define.tsx +7 -1
- package/src/elements/element-types.d.ts +2 -1
- package/src/elements/register-impl.ts +55 -0
- package/src/elements/register.ts +17 -51
- package/theme.css +4 -2
- package/src/components/artifact.stories.tsx +0 -138
- package/src/components/attachments.stories.tsx +0 -303
- package/src/components/attachments.test.tsx +0 -64
- package/src/components/chain-of-thought.stories.tsx +0 -211
- package/src/components/chat-container.stories.tsx +0 -187
- package/src/components/chat-thread.test.tsx +0 -58
- package/src/components/checkpoint.stories.tsx +0 -102
- package/src/components/code-block.stories.tsx +0 -150
- package/src/components/confirm-card.stories.tsx +0 -74
- package/src/components/context.stories.tsx +0 -229
- package/src/components/context.test.tsx +0 -133
- package/src/components/conversation-item.stories.tsx +0 -125
- package/src/components/conversation-list.stories.tsx +0 -133
- package/src/components/default-input.test.tsx +0 -111
- package/src/components/empty.stories.tsx +0 -434
- package/src/components/feedback-bar.stories.tsx +0 -138
- package/src/components/feedback-bar.test.tsx +0 -103
- package/src/components/file-tree.stories.tsx +0 -73
- package/src/components/file-upload.stories.tsx +0 -156
- package/src/components/image.stories.tsx +0 -89
- package/src/components/loader.stories.tsx +0 -181
- package/src/components/markdown.stories.tsx +0 -180
- package/src/components/message-action-bar.test.tsx +0 -128
- package/src/components/message-narrow.stories.tsx +0 -329
- package/src/components/message-skills.stories.tsx +0 -211
- package/src/components/message.stories.tsx +0 -281
- package/src/components/model-switcher.stories.tsx +0 -123
- package/src/components/model-switcher.test.tsx +0 -65
- package/src/components/prompt-input.stories.tsx +0 -222
- package/src/components/prompt-suggestion.stories.tsx +0 -142
- package/src/components/reasoning.stories.tsx +0 -140
- package/src/components/resizable.test.tsx +0 -226
- package/src/components/scroll-button.stories.tsx +0 -100
- package/src/components/slash-command.stories.tsx +0 -163
- package/src/components/source-list.test.tsx +0 -152
- package/src/components/source.stories.tsx +0 -124
- package/src/components/tasks-card.stories.tsx +0 -78
- package/src/components/text-shimmer.stories.tsx +0 -87
- package/src/components/thinking-bar.stories.tsx +0 -87
- package/src/components/tool.stories.tsx +0 -153
- package/src/components/voice-input.stories.tsx +0 -83
- package/src/elements/artifact.stories.tsx +0 -506
- package/src/elements/attachments.stories.tsx +0 -190
- package/src/elements/card.stories.tsx +0 -113
- package/src/elements/cards.stories.tsx +0 -59
- package/src/elements/catalog.stories.tsx +0 -491
- package/src/elements/chain-of-thought.declarative.test.tsx +0 -153
- package/src/elements/chain-of-thought.stories.tsx +0 -113
- package/src/elements/chat-scope-picker.stories.tsx +0 -73
- package/src/elements/chat-workspace.stories.tsx +0 -288
- package/src/elements/chat.stories.tsx +0 -151
- package/src/elements/checkpoint.stories.tsx +0 -72
- package/src/elements/choice.stories.tsx +0 -240
- package/src/elements/code-block.stories.tsx +0 -83
- package/src/elements/composed-shell.stories.tsx +0 -316
- package/src/elements/confirm-card.stories.tsx +0 -227
- package/src/elements/context-meter.stories.tsx +0 -151
- package/src/elements/conversation-list.declarative.test.tsx +0 -137
- package/src/elements/conversation-list.stories.tsx +0 -243
- package/src/elements/embed.stories.tsx +0 -213
- package/src/elements/empty.stories.tsx +0 -111
- package/src/elements/feedback-bar.stories.tsx +0 -114
- package/src/elements/file-tree.stories.tsx +0 -134
- package/src/elements/file-upload.stories.tsx +0 -82
- package/src/elements/form.stories.tsx +0 -248
- package/src/elements/image.stories.tsx +0 -71
- package/src/elements/link-preview.stories.tsx +0 -209
- package/src/elements/loader.stories.tsx +0 -88
- package/src/elements/markdown.stories.tsx +0 -76
- package/src/elements/message-skills.declarative.test.tsx +0 -104
- package/src/elements/message-skills.stories.tsx +0 -114
- package/src/elements/message.stories.tsx +0 -218
- package/src/elements/model-switcher.declarative.test.tsx +0 -130
- package/src/elements/model-switcher.stories.tsx +0 -198
- package/src/elements/popover.stories.tsx +0 -80
- package/src/elements/prompt-input-slash-command.test.tsx +0 -128
- package/src/elements/prompt-input-stoppable.test.tsx +0 -88
- package/src/elements/prompt-input-toolbar-actions.test.tsx +0 -120
- package/src/elements/prompt-input.stories.tsx +0 -331
- package/src/elements/prompt-suggestions.declarative.test.tsx +0 -164
- package/src/elements/prompt-suggestions.stories.tsx +0 -213
- package/src/elements/reasoning.stories.tsx +0 -77
- package/src/elements/remote.stories.tsx +0 -314
- package/src/elements/resizable.stories.tsx +0 -426
- package/src/elements/response-stream.stories.tsx +0 -79
- package/src/elements/scroll-button.stories.tsx +0 -202
- package/src/elements/scroll-button.test.tsx +0 -148
- package/src/elements/source-list.stories.tsx +0 -143
- package/src/elements/source.stories.tsx +0 -88
- package/src/elements/switch.stories.tsx +0 -56
- package/src/elements/tasks.stories.tsx +0 -237
- package/src/elements/text-shimmer.stories.tsx +0 -64
- package/src/elements/thinking-bar.stories.tsx +0 -72
- package/src/elements/tool.stories.tsx +0 -89
- package/src/elements/voice-input.stories.tsx +0 -88
- package/src/primitives/controllable.test.ts +0 -47
- package/src/stories/chat-panel-layout.stories.tsx +0 -145
- package/src/stories/chat-scene.tsx +0 -571
- package/src/stories/checkpoint-restore.stories.tsx +0 -256
- package/src/stories/context-usage.stories.tsx +0 -212
- package/src/stories/conversation-with-reasoning.stories.tsx +0 -182
- package/src/stories/conversation-with-sources.stories.tsx +0 -471
- package/src/stories/docs/Accessibility.mdx +0 -119
- package/src/stories/docs/ChildElements.mdx +0 -269
- package/src/stories/docs/ForAIAgents.mdx +0 -162
- package/src/stories/docs/GettingStarted.mdx +0 -65
- package/src/stories/docs/Installation.mdx +0 -83
- package/src/stories/docs/Introduction.mdx +0 -50
- package/src/stories/docs/SolidJsAdvanced.mdx +0 -17
- package/src/stories/docs/Theming.mdx +0 -85
- package/src/stories/docs/element-controls.ts +0 -121
- package/src/stories/docs/frameworks/Angular.mdx +0 -245
- package/src/stories/docs/frameworks/Html.mdx +0 -227
- package/src/stories/docs/frameworks/Overview.mdx +0 -47
- package/src/stories/docs/frameworks/React.mdx +0 -227
- package/src/stories/docs/frameworks/Solid.mdx +0 -173
- package/src/stories/docs/frameworks/Svelte.mdx +0 -194
- package/src/stories/docs/frameworks/Vue.mdx +0 -238
- package/src/stories/docs/generative-ui-overview.mdx +0 -186
- package/src/stories/docs/recipes/SpeechToText.mdx +0 -7
- package/src/stories/docs/recipes/Streaming.mdx +0 -68
- package/src/stories/docs/recipes/TextToSpeech.mdx +0 -35
- package/src/stories/docs/theme-editor/canvas.tsx +0 -32
- package/src/stories/docs/theme-editor/inspector.tsx +0 -66
- package/src/stories/docs/theme-editor/presets.test.ts +0 -32
- package/src/stories/docs/theme-editor/presets.ts +0 -64
- package/src/stories/docs/theme-editor/theme-css.test.ts +0 -19
- package/src/stories/docs/theme-editor/theme-css.ts +0 -15
- package/src/stories/docs/theme-editor/theme-editor.tsx +0 -146
- package/src/stories/docs/theme-tokens.tsx +0 -174
- package/src/stories/examples/ChoosingComponents.mdx +0 -106
- package/src/stories/examples/sample-data.ts +0 -79
- package/src/stories/examples/usage/checkpoint-restore.ts +0 -156
- package/src/stories/examples/usage/context-usage.ts +0 -591
- package/src/stories/examples/usage/conversation-with-reasoning.ts +0 -224
- package/src/stories/examples/usage/conversation-with-sources.ts +0 -589
- package/src/stories/examples/usage/empty-state.ts +0 -144
- package/src/stories/examples/usage/full-chat-app.ts +0 -277
- package/src/stories/examples/usage/index.ts +0 -63
- package/src/stories/examples/usage/message-actions.ts +0 -704
- package/src/stories/examples/usage/pattern-centered-conversation.ts +0 -446
- package/src/stories/examples/usage/pattern-chat-panel-layout.ts +0 -442
- package/src/stories/examples/usage/pattern-docked-widget.ts +0 -479
- package/src/stories/examples/usage/prompt-input-variants.ts +0 -1356
- package/src/stories/examples/usage/streaming-response.ts +0 -687
- package/src/stories/examples/usage/types.ts +0 -33
- package/src/stories/full-chat.stories.tsx +0 -18
- package/src/stories/message-actions.stories.tsx +0 -230
- package/src/stories/pattern-centered-conversation.stories.tsx +0 -93
- package/src/stories/pattern-docked-widget.stories.tsx +0 -93
- package/src/stories/pattern-empty-state.stories.tsx +0 -76
- package/src/stories/prompt-input-variants.stories.tsx +0 -456
- package/src/stories/streaming-response.stories.tsx +0 -438
- package/src/stories/theme-editor.stories.tsx +0 -16
- package/src/stories/token-reference.stories.tsx +0 -18
- package/src/stories/typography.stories.tsx +0 -78
- package/src/ui/avatar.stories.tsx +0 -103
- package/src/ui/badge.stories.tsx +0 -86
- package/src/ui/button.stories.tsx +0 -145
- package/src/ui/collapsible.stories.tsx +0 -69
- package/src/ui/dropdown.stories.tsx +0 -59
- package/src/ui/hover-card.stories.tsx +0 -77
- package/src/ui/hover-card.test.tsx +0 -30
- package/src/ui/overlay.stories.tsx +0 -115
- package/src/ui/popover.stories.tsx +0 -81
- package/src/ui/popover.test.tsx +0 -99
- package/src/ui/resizable.stories.tsx +0 -236
- package/src/ui/scroll-area.stories.tsx +0 -50
- package/src/ui/separator.stories.tsx +0 -81
- package/src/ui/skeleton.stories.tsx +0 -337
- package/src/ui/switch.stories.tsx +0 -51
- package/src/ui/switch.test.tsx +0 -59
- package/src/ui/textarea.stories.tsx +0 -76
- 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>;
|