@kitn.ai/ui 0.27.0 → 0.29.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 (612) hide show
  1. package/README.md +10 -2
  2. package/dist/{Icon-BnFKqqtY.js → Icon-DObhsRtm.js} +1 -1
  3. package/dist/{action-icons-CBskfBMz.js → action-icons-CcgNN2oT.js} +1 -1
  4. package/dist/agent-tooling/construct/public.d.ts +15 -0
  5. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  6. package/dist/arrow-down-CjRU3JgV.js +1 -0
  7. package/dist/arrow-left-Bnpb1UEW.js +1 -0
  8. package/dist/{artifact-CvXEm1lS.js → artifact-Bwt7OgcR.js} +1 -1
  9. package/dist/{attachments-C43ZegEq.js → attachments-Qr4kg-2b.js} +1 -1
  10. package/dist/{audio-visualizer-B-79y1Tj.js → audio-visualizer-DToYdfSc.js} +1 -1
  11. package/dist/{badge-BpUbq8c0.js → badge-CdEu_jn2.js} +1 -1
  12. package/dist/{bell-sn17Ip9v.js → bell-DQAAOpDz.js} +1 -1
  13. package/dist/{button-BH6rN0U-.js → button-DkuOnGLy.js} +1 -1
  14. package/dist/{card-renderer-Cb1gQmth.js → card-renderer-Jx70m6_l.js} +1 -1
  15. package/dist/{card-routing-DifQgS7n.js → card-routing-0YidER_3.js} +1 -1
  16. package/dist/check-njkVdZu2.js +1 -0
  17. package/dist/{checkbox-Dc9Yov_B.js → checkbox-D7iRB3nL.js} +1 -1
  18. package/dist/{checkbox-group-B1kDLLYk.js → checkbox-group-B2_rpoPM.js} +1 -1
  19. package/dist/chevron-down-B72s6PXR.js +1 -0
  20. package/dist/chevron-right-BatuHzUm.js +1 -0
  21. package/dist/{choice-card-BT3c1S8g.js → choice-card-m0BYqqOK.js} +1 -1
  22. package/dist/circle-check-B62pODB3.js +1 -0
  23. package/dist/{circle-x-wobWkoSx.js → circle-x-BPG0iPst.js} +1 -1
  24. package/dist/circle-zx0ByzY9.js +1 -0
  25. package/dist/code-block-ClMLKb7C.js +1 -0
  26. package/dist/{collapsible-CPJbf6FM.js → collapsible-B4DlWicL.js} +1 -1
  27. package/dist/components/chat-thread.d.ts +89 -1
  28. package/dist/components/conversation-item.d.ts +16 -0
  29. package/dist/components/conversation-panel.d.ts +29 -0
  30. package/dist/components/home-panel.d.ts +34 -0
  31. package/dist/components/widget-tab-bar.d.ts +16 -0
  32. package/dist/{composer-CjngLzal.js → composer-sQ0HcvyG.js} +3 -3
  33. package/dist/{confirm-card-DCx_A4bU.js → confirm-card-rQWDQsnC.js} +1 -1
  34. package/dist/construct-cli.es.js +185 -17
  35. package/dist/construct.d.ts +5 -0
  36. package/dist/construct.js +327 -0
  37. package/dist/{context-BY8V-Nlp.js → context-0kg4ZX1J.js} +1 -1
  38. package/dist/controllable-CnGpMF6r.js +1 -0
  39. package/dist/conversation-item-BxwQLaFJ.js +1 -0
  40. package/dist/conversation-list-BCfGN1JU.js +1 -0
  41. package/dist/{copy-B6DO4PqB.js → copy-n9u9rqpi.js} +1 -1
  42. package/dist/core-C8fzo39E.js +1 -12
  43. package/dist/{create-tween-CnMHviKB.js → create-tween-C-q-JCM-.js} +1 -1
  44. package/dist/{create-tween-D1aiGZZh.js → create-tween-CRrJXxBd.js} +1 -1
  45. package/dist/{create-tween-BPzaefTp.js → create-tween-DZ3RRDHD.js} +1 -1
  46. package/dist/{create-tween-DUSQUKpr.js → create-tween-uPkArjIG.js} +1 -1
  47. package/dist/custom-elements.json +51 -2
  48. package/dist/{default-input-CucQEOqH.js → default-input-CaMrJkgH.js} +1 -1
  49. package/dist/define-By-uL588.js +1 -0
  50. package/dist/define.js +2 -2
  51. package/dist/define.server.js +2 -2
  52. package/dist/{disclosure-CbLtajUQ.js → disclosure-WUImBbDv.js} +1 -1
  53. package/dist/{dropdown-BwhViJFd.js → dropdown-wZVeJOMd.js} +1 -1
  54. package/dist/elements/agent-card.js +1 -1
  55. package/dist/elements/artifact.js +1 -1
  56. package/dist/elements/attachments.js +1 -1
  57. package/dist/elements/audio-visualizer.js +1 -1
  58. package/dist/elements/avatar.js +1 -1
  59. package/dist/elements/badge.js +1 -1
  60. package/dist/elements/button.js +1 -1
  61. package/dist/elements/card.js +1 -1
  62. package/dist/elements/cards.js +1 -1
  63. package/dist/elements/chain-of-thought.js +1 -1
  64. package/dist/elements/chat-scope-picker.js +1 -1
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkbox-group.js +1 -1
  68. package/dist/elements/checkbox.js +1 -1
  69. package/dist/elements/checkpoint.js +1 -1
  70. package/dist/elements/choice.js +1 -1
  71. package/dist/elements/coachmark.js +1 -1
  72. package/dist/elements/code-block.js +1 -1
  73. package/dist/elements/command.js +1 -1
  74. package/dist/elements/compare.js +1 -1
  75. package/dist/elements/composer.js +1 -1
  76. package/dist/elements/confirm-card.js +1 -1
  77. package/dist/elements/context-meter.js +1 -1
  78. package/dist/elements/conversation-item.js +1 -1
  79. package/dist/elements/conversation-list.js +1 -1
  80. package/dist/elements/dialog.js +1 -1
  81. package/dist/elements/dock.js +3 -3
  82. package/dist/elements/dropdown.js +1 -1
  83. package/dist/elements/editable-label.js +1 -1
  84. package/dist/elements/embed.js +1 -1
  85. package/dist/elements/empty.js +1 -1
  86. package/dist/elements/feedback-bar.js +1 -1
  87. package/dist/elements/file-tree.js +1 -1
  88. package/dist/elements/file-upload.js +1 -1
  89. package/dist/elements/form.js +1 -1
  90. package/dist/elements/hover-card.js +1 -1
  91. package/dist/elements/icon.js +1 -1
  92. package/dist/elements/image.js +1 -1
  93. package/dist/elements/input.js +1 -1
  94. package/dist/elements/kbd.js +1 -1
  95. package/dist/elements/link-preview.js +1 -1
  96. package/dist/elements/loader.js +1 -1
  97. package/dist/elements/markdown.js +1 -1
  98. package/dist/elements/menu.js +1 -1
  99. package/dist/elements/message-skills.js +1 -1
  100. package/dist/elements/message.js +1 -1
  101. package/dist/elements/model-switcher.js +1 -1
  102. package/dist/elements/nav.js +1 -1
  103. package/dist/elements/notice.js +1 -1
  104. package/dist/elements/pane-grid.js +1 -1
  105. package/dist/elements/pane-group.js +1 -1
  106. package/dist/elements/pane.js +1 -1
  107. package/dist/elements/popover.js +1 -1
  108. package/dist/elements/progress-bar.js +1 -1
  109. package/dist/elements/prompt-dock.js +1 -1
  110. package/dist/elements/prompt-input.js +1 -1
  111. package/dist/elements/prompt-suggestions.js +1 -1
  112. package/dist/elements/radio-group.js +1 -1
  113. package/dist/elements/reasoning.js +1 -1
  114. package/dist/elements/remote.js +1 -1
  115. package/dist/elements/resizable.js +1 -1
  116. package/dist/elements/response-stream.js +1 -1
  117. package/dist/elements/screen.js +1 -1
  118. package/dist/elements/scroll-area.js +1 -1
  119. package/dist/elements/scroll-button.js +1 -1
  120. package/dist/elements/search.js +1 -1
  121. package/dist/elements/segmented.js +1 -1
  122. package/dist/elements/select.js +1 -1
  123. package/dist/elements/separator.js +1 -1
  124. package/dist/elements/setting-item.js +1 -1
  125. package/dist/elements/settings-group.js +1 -1
  126. package/dist/elements/skeleton.js +1 -1
  127. package/dist/elements/slider.js +1 -1
  128. package/dist/elements/source.js +1 -1
  129. package/dist/elements/status.js +1 -1
  130. package/dist/elements/switch.js +1 -1
  131. package/dist/elements/tabs.js +1 -1
  132. package/dist/elements/tasks.js +1 -1
  133. package/dist/elements/text-shimmer.js +1 -1
  134. package/dist/elements/thinking-bar.js +1 -1
  135. package/dist/elements/thread.js +1 -1
  136. package/dist/elements/toast.js +1 -1
  137. package/dist/elements/tool.js +1 -1
  138. package/dist/elements/tooltip.js +1 -1
  139. package/dist/elements/voice-input.js +1 -1
  140. package/dist/elements/voice-output.js +1 -1
  141. package/dist/elements.d.ts +20 -4
  142. package/dist/{ellipsis-DFr4Vqr3.js → ellipsis-CbOpJnU3.js} +1 -1
  143. package/dist/{embed-5s_vU4J0.js → embed-CrfjkbUG.js} +1 -1
  144. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  145. package/dist/{external-link-u9d85ORQ.js → external-link-ByXAwBBQ.js} +1 -1
  146. package/dist/{file-text-CX7_x42o.js → file-text-DMib2qwt.js} +1 -1
  147. package/dist/{file-tree-D3kBjXI5.js → file-tree-CJqM2aP7.js} +1 -1
  148. package/dist/{folder-V-YdIL8f.js → folder-_BAb929C.js} +1 -1
  149. package/dist/{form-BRNUMCN2.js → form-DSZgZQZk.js} +1 -1
  150. package/dist/{hover-card-DaeiYrTA.js → hover-card-BQbul9eq.js} +1 -1
  151. package/dist/{icon-BpixdZNq.js → icon-CdcfRhYI.js} +1 -1
  152. package/dist/index.d.ts +3 -1
  153. package/dist/index.js +2842 -2703
  154. package/dist/index.server.js +2820 -2681
  155. package/dist/{info-8mFsIjS3.js → info-DsFjGuI_.js} +1 -1
  156. package/dist/{input-d1Yuu-hz.js → input-DKbmkMos.js} +1 -1
  157. package/dist/kai.es.js +1 -1
  158. package/dist/{kbd-961zMPFB.js → kbd-PvdGhX4s.js} +1 -1
  159. package/dist/{link-preview-DIIbV2Sd.js → link-preview-DbM1866N.js} +1 -1
  160. package/dist/{link-DlZZBGaR.js → link-zF8PzWfF.js} +1 -1
  161. package/dist/{loader-YQszHFaW.js → loader-BM4CEz4G.js} +1 -1
  162. package/dist/{markdown-CVk1MPsj.js → markdown-LMvmAyBk.js} +7 -7
  163. package/dist/mcp.es.js +79 -5
  164. package/dist/{message-CwKVEdZg.js → message-BSsgvHvf.js} +1 -1
  165. package/dist/{message-DS8lzHc1.js → message-BYZECyek.js} +1 -1
  166. package/dist/message-circle-DruwObfX.js +1 -0
  167. package/dist/message-square-BG6q6mlm.js +1 -0
  168. package/dist/{minimize-2-UEZmP2QT.js → minimize-2-BQRoBV1V.js} +1 -1
  169. package/dist/{model-switcher-Kk1jEQ5t.js → model-switcher-CMpCOYcB.js} +1 -1
  170. package/dist/{overlay-C1od6LOz.js → overlay-Cb-MkyDa.js} +1 -1
  171. package/dist/{panel-right-ryET0yyn.js → panel-right-i8warFxT.js} +1 -1
  172. package/dist/{paperclip-BDNoZFJP.js → paperclip-ByY3UVO6.js} +1 -1
  173. package/dist/play-BvKKq3fX.js +1 -0
  174. package/dist/primitives/conversation-store.d.ts +54 -0
  175. package/dist/{progress-bar-BvYX0aoy.js → progress-bar-jVAHvMUf.js} +1 -1
  176. package/dist/{prompt-suggestion-BRFu2lcu.js → prompt-suggestion-CD-qtNgC.js} +1 -1
  177. package/dist/{radio-DcL23cNJ.js → radio-BsoBMhkF.js} +1 -1
  178. package/dist/react/index.d.ts +393 -0
  179. package/dist/react.js +20 -20
  180. package/dist/{reasoning-Cackq4Rh.js → reasoning-4kBPtlTx.js} +1 -1
  181. package/dist/register-impl-B1hLkrI8.js +424 -0
  182. package/dist/{resizable-Cp9HUYih.js → resizable-uPmY9VY-.js} +1 -1
  183. package/dist/{rotate-ccw-0DLRDHH5.js → rotate-ccw-B2xn93py.js} +1 -1
  184. package/dist/{rotate-cw-DOB9IGcU.js → rotate-cw-CMVLoCyH.js} +1 -1
  185. package/dist/{scroll-area-emVmWP4K.js → scroll-area-BqLUo8ZZ.js} +1 -1
  186. package/dist/{scroll-button-CeP_gv1x.js → scroll-button-DslXiJyL.js} +1 -1
  187. package/dist/{select-CWmu00tS.js → select-2cLRtPGT.js} +1 -1
  188. package/dist/{separator-CE6vly6z.js → separator-BWQtNJcM.js} +1 -1
  189. package/dist/{settings-CE-78SvZ.js → settings-BBR63jLg.js} +1 -1
  190. package/dist/{settings-group-ZFWNxFQR.js → settings-group-B2ciy-Iw.js} +1 -1
  191. package/dist/{skeleton-BebdP4mf.js → skeleton-CkHI-HgC.js} +1 -1
  192. package/dist/{slider-BAKRYUlz.js → slider-DDR9U-i0.js} +1 -1
  193. package/dist/{solid-BE5ui6sy.js → solid-BzCFdL25.js} +7720 -7058
  194. package/dist/{solid-DFhsce3O.js → solid-DruVOXnf.js} +5864 -5283
  195. package/dist/solid.d.ts +6 -2
  196. package/dist/solid.js +217 -210
  197. package/dist/solid.server.js +217 -210
  198. package/dist/{source-B0FlguSx.js → source-GEnFF528.js} +1 -1
  199. package/dist/{star-CBMZvLuN.js → star-CilHq8GP.js} +1 -1
  200. package/dist/store-Ciyk6eZG.js +1 -0
  201. package/dist/{switch-CViARZCy.js → switch-KkeQIbuH.js} +1 -1
  202. package/dist/{tasks-card-MjCcOhR_.js → tasks-card-BrN4bggJ.js} +1 -1
  203. package/dist/{text-shimmer-DKlwRF2G.js → text-shimmer-Dcj1MHuq.js} +1 -1
  204. package/dist/{textarea-3ay2Me2-.js → textarea-Dpvbngbg.js} +1 -1
  205. package/dist/theme.tokens.css +28 -0
  206. package/dist/{thumbs-up-DQcu2HMO.js → thumbs-up-CsT9Wzb9.js} +1 -1
  207. package/dist/{toast-store-C6yKOhbk.js → toast-store-tgK6MuMv.js} +1 -1
  208. package/dist/{tool-BCYNlfKy.js → tool-DzUjIBT8.js} +1 -1
  209. package/dist/{tooltip-05zI4hjs.js → tooltip-Bkkg_4t0.js} +1 -1
  210. package/dist/{trash-2-BR1RxGky.js → trash-2-jBKxjGGQ.js} +1 -1
  211. package/dist/{triangle-alert-DHohDOCy.js → triangle-alert-DlQ68ppf.js} +1 -1
  212. package/dist/types.d.ts +48 -3
  213. package/dist/ui/dock.d.ts +29 -0
  214. package/dist/{upload-BbGW6A_u.js → upload-TcAHXv9W.js} +1 -1
  215. package/dist/{url-scheme-policy-DHpoTJwB.js → url-scheme-policy-DR5DgvkM.js} +1 -1
  216. package/dist/{use-card-resolution-CJW4grFa.js → use-card-resolution-DaZqAdWf.js} +1 -1
  217. package/dist/{variant-aurora-xiMPty8f.js → variant-aurora-BhLuYxJR.js} +1 -1
  218. package/dist/{variant-aurora-BUOVgPOB.js → variant-aurora-CNmfHhcx.js} +2 -2
  219. package/dist/{variant-aurora-CUsUJvFI.js → variant-aurora-D6GsdTPA.js} +2 -2
  220. package/dist/{variant-aurora-CW2i4bfr.js → variant-aurora-DbW_OWL2.js} +1 -1
  221. package/dist/{variant-custom-D91HjAKz.js → variant-custom-BRvaNHSi.js} +1 -1
  222. package/dist/{variant-custom-BQtOnmeO.js → variant-custom-BvYHR62b.js} +1 -1
  223. package/dist/{variant-custom-CAnzzppW.js → variant-custom-DMTrEO5w.js} +2 -2
  224. package/dist/{variant-custom-CAm9L-E5.js → variant-custom-DV2x254s.js} +2 -2
  225. package/dist/{variant-wave-Ca1Ls4_y.js → variant-wave-BNMGrDfj.js} +2 -2
  226. package/dist/{variant-wave-uY5crU_K.js → variant-wave-BpDd8t3Z.js} +1 -1
  227. package/dist/{variant-wave-CxX39DKd.js → variant-wave-CyBueXj9.js} +2 -2
  228. package/dist/{variant-wave-DYyzIIZv.js → variant-wave-sp-qwsdI.js} +1 -1
  229. package/dist/x-Z5UntkIJ.js +1 -0
  230. package/frameworks/react/index.tsx +14 -4
  231. package/llms-full.txt +7 -2
  232. package/package.json +16 -16
  233. package/src/elements/element-meta.json +49 -6
  234. package/theme.css +28 -0
  235. package/bin/route.test.js +0 -58
  236. package/dist/arrow-down-Br0qtpsz.js +0 -1
  237. package/dist/arrow-left-Dj7xgE12.js +0 -1
  238. package/dist/check-DPeeMUYx.js +0 -1
  239. package/dist/chevron-down-CHSWk7ZT.js +0 -1
  240. package/dist/chevron-right-B7l_fMgx.js +0 -1
  241. package/dist/circle-Bb0yOpqM.js +0 -1
  242. package/dist/circle-check-BGZpCiz7.js +0 -1
  243. package/dist/code-block-CUQ5mtv0.js +0 -1
  244. package/dist/controllable-D43BKmtX.js +0 -1
  245. package/dist/conversation-list-D4lLU_yS.js +0 -1
  246. package/dist/define-CGGX-7Vg.js +0 -1
  247. package/dist/message-circle-Xf8Q-vZp.js +0 -1
  248. package/dist/message-square-Cxnwgkns.js +0 -1
  249. package/dist/play-OFIvYXUQ.js +0 -1
  250. package/dist/register-impl-C7rENvPK.js +0 -424
  251. package/dist/store-7eoadydQ.js +0 -1
  252. package/dist/x-C5m1JFgi.js +0 -1
  253. package/src/agent-tooling/archetypes.ts +0 -205
  254. package/src/agent-tooling/catalog/README.md +0 -676
  255. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  256. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  257. package/src/agent-tooling/catalog/invariants.ts +0 -284
  258. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  259. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  260. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  261. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  262. package/src/agent-tooling/construct/cli.ts +0 -131
  263. package/src/agent-tooling/construct/codegen.ts +0 -1353
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -250
  265. package/src/agent-tooling/construct/dev.ts +0 -148
  266. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  267. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  268. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -23
  269. package/src/agent-tooling/construct/schema.ts +0 -371
  270. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  271. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  272. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  273. package/src/agent-tooling/integrations/mastra.ts +0 -182
  274. package/src/agent-tooling/integrations/mock.ts +0 -148
  275. package/src/agent-tooling/integrations/ollama.ts +0 -97
  276. package/src/agent-tooling/integrations/openai.ts +0 -95
  277. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  278. package/src/agent-tooling/integrations/pi.ts +0 -176
  279. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  280. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  281. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  282. package/src/agent-tooling/mcp/manifest.ts +0 -422
  283. package/src/agent-tooling/mcp/server.ts +0 -116
  284. package/src/agent-tooling/mcp/stdio.ts +0 -18
  285. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  286. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  287. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  288. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  289. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  290. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  291. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  292. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  293. package/src/agent-tooling/recipes/index.ts +0 -22
  294. package/src/agent-tooling/recipes/types.ts +0 -32
  295. package/src/agent-tooling/registry.ts +0 -132
  296. package/src/agent-tooling/route-emit.ts +0 -305
  297. package/src/agent-tooling/types.ts +0 -390
  298. package/src/components/artifact-card.tsx +0 -120
  299. package/src/components/artifact.tsx +0 -914
  300. package/src/components/attachment-types.ts +0 -66
  301. package/src/components/attachments.tsx +0 -536
  302. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  303. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  304. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  305. package/src/components/audio-visualizer/index.tsx +0 -528
  306. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  307. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  308. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  309. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  310. package/src/components/audio-visualizer/sizes.ts +0 -54
  311. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  312. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  313. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  314. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  315. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  316. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  317. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  318. package/src/components/card-fallback.tsx +0 -60
  319. package/src/components/card-renderer.tsx +0 -220
  320. package/src/components/card.tsx +0 -212
  321. package/src/components/chain-of-thought.tsx +0 -348
  322. package/src/components/chat-container.tsx +0 -89
  323. package/src/components/chat-scope-picker.tsx +0 -57
  324. package/src/components/chat-thread.tsx +0 -518
  325. package/src/components/checkpoint.tsx +0 -88
  326. package/src/components/choice-card.tsx +0 -743
  327. package/src/components/coachmark.tsx +0 -249
  328. package/src/components/code-block.tsx +0 -181
  329. package/src/components/composer-dom.ts +0 -159
  330. package/src/components/composer-highlight.ts +0 -242
  331. package/src/components/composer-history.ts +0 -82
  332. package/src/components/composer.tsx +0 -1075
  333. package/src/components/confirm-card.tsx +0 -402
  334. package/src/components/context.tsx +0 -377
  335. package/src/components/conversation-item.tsx +0 -218
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/dismissed-stub.tsx +0 -80
  338. package/src/components/embed.tsx +0 -200
  339. package/src/components/empty.tsx +0 -177
  340. package/src/components/feedback-bar.tsx +0 -166
  341. package/src/components/file-tree.tsx +0 -530
  342. package/src/components/file-upload.tsx +0 -167
  343. package/src/components/form-widgets.tsx +0 -525
  344. package/src/components/form.tsx +0 -1296
  345. package/src/components/image.tsx +0 -65
  346. package/src/components/link-preview.tsx +0 -195
  347. package/src/components/loader.tsx +0 -367
  348. package/src/components/markdown.tsx +0 -162
  349. package/src/components/message-skills.tsx +0 -40
  350. package/src/components/message.tsx +0 -765
  351. package/src/components/model-switcher.tsx +0 -132
  352. package/src/components/prompt-input.tsx +0 -188
  353. package/src/components/prompt-suggestion.tsx +0 -150
  354. package/src/components/reasoning.tsx +0 -293
  355. package/src/components/response-compare-types.ts +0 -152
  356. package/src/components/response-compare.tsx +0 -455
  357. package/src/components/response-stream.tsx +0 -109
  358. package/src/components/screen.tsx +0 -181
  359. package/src/components/scroll-button.tsx +0 -93
  360. package/src/components/source.tsx +0 -192
  361. package/src/components/tasks-card.tsx +0 -801
  362. package/src/components/text-shimmer.tsx +0 -37
  363. package/src/components/thinking-bar.tsx +0 -50
  364. package/src/components/thread.tsx +0 -228
  365. package/src/components/toast.tsx +0 -503
  366. package/src/components/tool-classify.ts +0 -26
  367. package/src/components/tool-types.ts +0 -49
  368. package/src/components/tool.tsx +0 -190
  369. package/src/components/use-card-resolution.ts +0 -44
  370. package/src/components/voice-input.tsx +0 -222
  371. package/src/components/voice-output.tsx +0 -242
  372. package/src/components/workspace-shell.tsx +0 -285
  373. package/src/diagnostics/hook.ts +0 -352
  374. package/src/diagnostics/index.ts +0 -82
  375. package/src/diagnostics/report-request.ts +0 -296
  376. package/src/elements/agent-card.tsx +0 -67
  377. package/src/elements/artifact.tsx +0 -194
  378. package/src/elements/attachments.tsx +0 -140
  379. package/src/elements/audio-visualizer.tsx +0 -227
  380. package/src/elements/autoloader.ts +0 -89
  381. package/src/elements/avatar.tsx +0 -33
  382. package/src/elements/badge.tsx +0 -32
  383. package/src/elements/button.tsx +0 -149
  384. package/src/elements/card.tsx +0 -133
  385. package/src/elements/cards.tsx +0 -266
  386. package/src/elements/chain-of-thought.tsx +0 -141
  387. package/src/elements/chat-scope-picker.tsx +0 -65
  388. package/src/elements/chat-types.ts +0 -102
  389. package/src/elements/chat-workspace.tsx +0 -188
  390. package/src/elements/chat.tsx +0 -212
  391. package/src/elements/checkbox-group.tsx +0 -164
  392. package/src/elements/checkbox.tsx +0 -134
  393. package/src/elements/checkpoint.tsx +0 -47
  394. package/src/elements/choice.tsx +0 -100
  395. package/src/elements/coachmark.tsx +0 -90
  396. package/src/elements/code-block.tsx +0 -60
  397. package/src/elements/command.tsx +0 -197
  398. package/src/elements/compare.tsx +0 -111
  399. package/src/elements/compiled.css +0 -2
  400. package/src/elements/composer.tsx +0 -162
  401. package/src/elements/confirm-card.tsx +0 -76
  402. package/src/elements/context-meter.tsx +0 -107
  403. package/src/elements/conversation-item.tsx +0 -120
  404. package/src/elements/conversation-list.tsx +0 -203
  405. package/src/elements/css.ts +0 -5
  406. package/src/elements/default-input.tsx +0 -392
  407. package/src/elements/define-entry.ts +0 -12
  408. package/src/elements/define.tsx +0 -563
  409. package/src/elements/diagnostic-events.ts +0 -114
  410. package/src/elements/dialog.tsx +0 -145
  411. package/src/elements/disclosure.ts +0 -95
  412. package/src/elements/dock.tsx +0 -215
  413. package/src/elements/dropdown.tsx +0 -123
  414. package/src/elements/editable-label.tsx +0 -140
  415. package/src/elements/element-data-types.ts +0 -152
  416. package/src/elements/element-diagnostics.ts +0 -392
  417. package/src/elements/element-manifest.json +0 -354
  418. package/src/elements/element-nonscalar.json +0 -185
  419. package/src/elements/element-types.d.ts +0 -4337
  420. package/src/elements/embed.tsx +0 -35
  421. package/src/elements/empty.tsx +0 -29
  422. package/src/elements/feedback-bar.tsx +0 -66
  423. package/src/elements/file-tree.tsx +0 -62
  424. package/src/elements/file-upload.tsx +0 -44
  425. package/src/elements/form.tsx +0 -94
  426. package/src/elements/hover-card.tsx +0 -80
  427. package/src/elements/icon.tsx +0 -41
  428. package/src/elements/image.tsx +0 -32
  429. package/src/elements/input.tsx +0 -492
  430. package/src/elements/kbd.tsx +0 -45
  431. package/src/elements/link-preview.tsx +0 -34
  432. package/src/elements/loader.tsx +0 -25
  433. package/src/elements/markdown.tsx +0 -38
  434. package/src/elements/menu.tsx +0 -241
  435. package/src/elements/message-skills.tsx +0 -83
  436. package/src/elements/message.tsx +0 -361
  437. package/src/elements/model-switcher.tsx +0 -121
  438. package/src/elements/nav.tsx +0 -87
  439. package/src/elements/notice.tsx +0 -53
  440. package/src/elements/pane-grid.tsx +0 -111
  441. package/src/elements/pane-group.tsx +0 -119
  442. package/src/elements/pane.tsx +0 -129
  443. package/src/elements/popover.tsx +0 -81
  444. package/src/elements/progress-bar.tsx +0 -39
  445. package/src/elements/prompt-dock.tsx +0 -82
  446. package/src/elements/prompt-input.tsx +0 -240
  447. package/src/elements/prompt-suggestions.tsx +0 -113
  448. package/src/elements/radio-group.tsx +0 -129
  449. package/src/elements/reasoning.tsx +0 -71
  450. package/src/elements/register-impl.ts +0 -148
  451. package/src/elements/register.ts +0 -76
  452. package/src/elements/remote.tsx +0 -225
  453. package/src/elements/resizable.globals.d.ts +0 -36
  454. package/src/elements/resizable.tsx +0 -704
  455. package/src/elements/response-stream.tsx +0 -40
  456. package/src/elements/screen.tsx +0 -90
  457. package/src/elements/scroll-area.tsx +0 -33
  458. package/src/elements/scroll-button.tsx +0 -179
  459. package/src/elements/search.tsx +0 -185
  460. package/src/elements/segmented.tsx +0 -129
  461. package/src/elements/select.tsx +0 -165
  462. package/src/elements/separator.tsx +0 -36
  463. package/src/elements/setting-item.tsx +0 -50
  464. package/src/elements/settings-group.tsx +0 -37
  465. package/src/elements/skeleton.tsx +0 -45
  466. package/src/elements/slider.tsx +0 -171
  467. package/src/elements/slot-text.ts +0 -73
  468. package/src/elements/slots.ts +0 -787
  469. package/src/elements/source.tsx +0 -126
  470. package/src/elements/status.tsx +0 -42
  471. package/src/elements/styles.css +0 -328
  472. package/src/elements/switch.tsx +0 -118
  473. package/src/elements/tabs.tsx +0 -95
  474. package/src/elements/tasks.tsx +0 -103
  475. package/src/elements/text-shimmer.tsx +0 -28
  476. package/src/elements/thinking-bar.tsx +0 -43
  477. package/src/elements/thread.tsx +0 -139
  478. package/src/elements/toast.tsx +0 -106
  479. package/src/elements/tool.tsx +0 -78
  480. package/src/elements/tooltip.tsx +0 -85
  481. package/src/elements/validate-messages.ts +0 -76
  482. package/src/elements/voice-input.tsx +0 -100
  483. package/src/elements/voice-output.tsx +0 -82
  484. package/src/index.ts +0 -428
  485. package/src/primitives/audio-bands.ts +0 -174
  486. package/src/primitives/card-component-types.ts +0 -63
  487. package/src/primitives/card-contract.ts +0 -80
  488. package/src/primitives/card-data-types.ts +0 -361
  489. package/src/primitives/card-host.tsx +0 -37
  490. package/src/primitives/card-recovery.ts +0 -160
  491. package/src/primitives/card-registry.tsx +0 -78
  492. package/src/primitives/card-resolution.ts +0 -36
  493. package/src/primitives/card-routing.ts +0 -85
  494. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  495. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  496. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  497. package/src/primitives/card-schemas/choice.schema.json +0 -75
  498. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  499. package/src/primitives/card-schemas/embed.schema.json +0 -63
  500. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  501. package/src/primitives/card-schemas/form.schema.json +0 -53
  502. package/src/primitives/card-schemas/link.schema.json +0 -54
  503. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  504. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  505. package/src/primitives/card-tags.ts +0 -61
  506. package/src/primitives/card-validate-cards.ts +0 -255
  507. package/src/primitives/card-validate-schemas.ts +0 -58
  508. package/src/primitives/card-validate.ts +0 -131
  509. package/src/primitives/chat-config.tsx +0 -103
  510. package/src/primitives/composer-model.ts +0 -49
  511. package/src/primitives/composer-triggers.ts +0 -35
  512. package/src/primitives/controllable.ts +0 -21
  513. package/src/primitives/create-kai-chat.ts +0 -66
  514. package/src/primitives/create-tween.ts +0 -266
  515. package/src/primitives/embed-providers.ts +0 -254
  516. package/src/primitives/field-mask.ts +0 -256
  517. package/src/primitives/field-semantics.ts +0 -115
  518. package/src/primitives/highlighter.ts +0 -157
  519. package/src/primitives/input-mask.ts +0 -853
  520. package/src/primitives/link-preview.ts +0 -87
  521. package/src/primitives/message-feedback.ts +0 -124
  522. package/src/primitives/pdf-preview.ts +0 -121
  523. package/src/primitives/toast-store.ts +0 -338
  524. package/src/primitives/url-scheme-policy.ts +0 -70
  525. package/src/primitives/use-audio-analysis.ts +0 -340
  526. package/src/primitives/use-auto-resize.ts +0 -31
  527. package/src/primitives/use-resize-observer.ts +0 -45
  528. package/src/primitives/use-sequencer.ts +0 -72
  529. package/src/primitives/use-speech-recognition.ts +0 -146
  530. package/src/primitives/use-stick-to-bottom.ts +0 -75
  531. package/src/primitives/use-text-stream.ts +0 -143
  532. package/src/primitives/use-voice-recorder.ts +0 -62
  533. package/src/primitives/visualizer-sequences.ts +0 -350
  534. package/src/remote/host-embed.ts +0 -345
  535. package/src/remote/index.ts +0 -2
  536. package/src/remote/origin.ts +0 -30
  537. package/src/remote/provider-runtime.ts +0 -262
  538. package/src/remote/provider.ts +0 -2
  539. package/src/remote/validate.ts +0 -22
  540. package/src/remote/version.ts +0 -12
  541. package/src/remote/wire.ts +0 -48
  542. package/src/schemas/from-tool-call.ts +0 -151
  543. package/src/schemas/index.ts +0 -341
  544. package/src/schemas/provider-subsets.ts +0 -538
  545. package/src/schemas/registry.ts +0 -355
  546. package/src/schemas/tool-defs.ts +0 -793
  547. package/src/solid.ts +0 -165
  548. package/src/state/index.ts +0 -44
  549. package/src/state/messages.ts +0 -53
  550. package/src/state/mock.ts +0 -297
  551. package/src/state/parts.ts +0 -295
  552. package/src/state/persistence.ts +0 -180
  553. package/src/state/stream.ts +0 -246
  554. package/src/state/suggestions.ts +0 -9
  555. package/src/state/threads.ts +0 -142
  556. package/src/test-utils/fake-clock.ts +0 -88
  557. package/src/types.ts +0 -53
  558. package/src/ui/action-icons.ts +0 -53
  559. package/src/ui/agent-card.tsx +0 -218
  560. package/src/ui/avatar.tsx +0 -23
  561. package/src/ui/badge.tsx +0 -21
  562. package/src/ui/button.tsx +0 -49
  563. package/src/ui/card.tsx +0 -245
  564. package/src/ui/checkbox-group.tsx +0 -153
  565. package/src/ui/checkbox.tsx +0 -63
  566. package/src/ui/collapsible.tsx +0 -163
  567. package/src/ui/command.tsx +0 -103
  568. package/src/ui/dialog.tsx +0 -223
  569. package/src/ui/dock.tsx +0 -584
  570. package/src/ui/dropdown.tsx +0 -636
  571. package/src/ui/editable-label.tsx +0 -112
  572. package/src/ui/hover-card.tsx +0 -345
  573. package/src/ui/icon.tsx +0 -167
  574. package/src/ui/input.tsx +0 -391
  575. package/src/ui/kbd.tsx +0 -118
  576. package/src/ui/nav.tsx +0 -282
  577. package/src/ui/notice.tsx +0 -84
  578. package/src/ui/overlay.tsx +0 -277
  579. package/src/ui/pane-grid.tsx +0 -117
  580. package/src/ui/pane-group.tsx +0 -291
  581. package/src/ui/pane.tsx +0 -193
  582. package/src/ui/popover.tsx +0 -106
  583. package/src/ui/progress-bar.tsx +0 -83
  584. package/src/ui/prompt-dock.tsx +0 -145
  585. package/src/ui/radio.tsx +0 -150
  586. package/src/ui/resizable.tsx +0 -693
  587. package/src/ui/scroll-area.tsx +0 -26
  588. package/src/ui/segmented.tsx +0 -109
  589. package/src/ui/select.tsx +0 -168
  590. package/src/ui/separator.tsx +0 -10
  591. package/src/ui/settings-group.tsx +0 -67
  592. package/src/ui/skeleton.tsx +0 -73
  593. package/src/ui/slider.tsx +0 -178
  594. package/src/ui/status.tsx +0 -48
  595. package/src/ui/switch.tsx +0 -119
  596. package/src/ui/tabs.tsx +0 -168
  597. package/src/ui/textarea.tsx +0 -21
  598. package/src/ui/tooltip.tsx +0 -118
  599. package/src/utils/cn.ts +0 -30
  600. package/src/wire/chunk.ts +0 -248
  601. package/src/wire/consume.ts +0 -599
  602. package/src/wire/diagnostics.ts +0 -727
  603. package/src/wire/encode-probe.ts +0 -214
  604. package/src/wire/encode.ts +0 -947
  605. package/src/wire/files.ts +0 -342
  606. package/src/wire/formats/anthropic.ts +0 -274
  607. package/src/wire/formats/openai.ts +0 -228
  608. package/src/wire/index.ts +0 -95
  609. package/src/wire/media-types.ts +0 -344
  610. package/src/wire/read.ts +0 -396
  611. package/src/wire/sink-helpers.ts +0 -50
  612. package/src/wire/sse.ts +0 -153
@@ -1,980 +0,0 @@
1
- import { z } from 'zod';
2
- import {
3
- KAI_TOOL_PREFIX,
4
- cardSchemaNames,
5
- cardSchemas,
6
- cardTools,
7
- isCardSchemaName,
8
- toolNameForCardType,
9
- } from '@kitn.ai/ui/schemas';
10
- import type { CardSchemaName, ToolProvider } from '@kitn.ai/ui/schemas';
11
- import type { Tool } from './types';
12
- import {
13
- cardHostTags,
14
- cardTagForType,
15
- cardTypeForTag,
16
- entryForTag,
17
- getElement,
18
- listElements,
19
- optInEntryForTag,
20
- } from '../manifest';
21
- import type { CemMember } from '../manifest';
22
- // The RAW literals, not listInvariants() / listSurfaceRecipes(). Those re-run a
23
- // zod parse over the whole catalog, and this is a per-lookup serving path called
24
- // once for every element a harness asks about. The parse is not skipped, only
25
- // moved: invariants.test.ts and surfaces.test.ts run it over these same literals
26
- // in CI, so a malformed record fails a test rather than a request.
27
- import { invariants } from '../../catalog/invariants';
28
- import { surfaceRecipes } from '../../catalog/surfaces';
29
- import type { TInvariant, TInvariantExample, TSurfaceRecipe } from '../../catalog/catalog-types';
30
- import { listCodeRecipes, getCodeRecipe } from '../../recipes';
31
- import type { CodeRecipe } from '../../recipes';
32
- import { readFileSync, existsSync } from 'node:fs';
33
- import { dirname, join } from 'node:path';
34
- import { resolveManifestPath } from '../manifest';
35
-
36
- /**
37
- * component_reference — look up AI/UI (kai-*) web components, their props,
38
- * events, attributes, and CSS custom properties from the live Custom Elements
39
- * Manifest (dist/custom-elements.json).
40
- *
41
- * Backed by manifest.ts which resolves the CEM in both the bundled bin
42
- * (dist/mcp.es.js sibling) and the Vitest source context (walks up to find
43
- * dist/custom-elements.json in the repo root).
44
- *
45
- * For a card-backed element it also serves the card's JSON Schema and a tool
46
- * definition GENERATED by `cardTools()`. See `renderCardContract` for why not one
47
- * byte of that is written here as a literal.
48
- */
49
-
50
- /** Types that warrant the JS-property contract note. */
51
- const JS_ONLY_TYPE_PATTERNS = /\[\]|\{|Record</;
52
-
53
- function isJsOnlyType(typeText: string | undefined): boolean {
54
- return typeText ? JS_ONLY_TYPE_PATTERNS.test(typeText) : false;
55
- }
56
-
57
- // ─────────────────────────────────────────────────────────────────────────────
58
- // The imperative half of the interaction surface
59
- // ─────────────────────────────────────────────────────────────────────────────
60
-
61
- /**
62
- * A CEM member of `kind: 'method'`.
63
- *
64
- * `CemMember` in manifest.ts types what EVERY member carries. `parameters` and
65
- * `return` exist only on methods, and gen-element-api.mjs writes the AUTHORED
66
- * parameter list into a single `parameters[0].name` rather than splitting it, so
67
- * the signature is rebuilt from those two fields rather than read off one.
68
- */
69
- interface CemMethodMember extends CemMember {
70
- kind: 'method';
71
- parameters?: { name: string }[];
72
- return?: { type?: { text?: string } };
73
- }
74
-
75
- function isPublicMethod(member: CemMember): member is CemMethodMember {
76
- return member.kind === 'method' && member.privacy === 'public';
77
- }
78
-
79
- /** `maximize(index: number): void` — the call as a consumer types it. */
80
- function methodSignature(method: CemMethodMember): string {
81
- return `${method.name}(${method.parameters?.[0]?.name ?? ''}): ${method.return?.type?.text ?? 'void'}`;
82
- }
83
-
84
- // ─────────────────────────────────────────────────────────────────────────────
85
- // The card contract
86
- // ─────────────────────────────────────────────────────────────────────────────
87
-
88
- const PROVIDERS = ['openai', 'anthropic', 'jsonschema'] as const;
89
-
90
- /**
91
- * What a caller gets when they do not name a provider.
92
- *
93
- * NOT a coin-flip between the two wire formats, and deliberately not "serve all
94
- * three". The three envelopes are not interchangeable in a way a reader can patch
95
- * up: OpenAI nests the schema at `function.parameters`, Anthropic puts it flat at
96
- * `input_schema`. Handing over one of those unasked means a harness on the other
97
- * provider pastes it in and gets a 400 it will blame on the kit.
98
- *
99
- * `jsonschema` is the only one of the three that is not a wire envelope at all —
100
- * `{ name, description, schema }` cannot be mistaken for either provider's shape, so
101
- * a caller who reads it as one is corrected by the field names before they ship it.
102
- * It is also directly usable, not a booby prize: `tool({ inputSchema: jsonSchema(
103
- * def.schema) })` is exactly what the Vercel AI SDK wants, and of the nine
104
- * integrations this MCP scaffolds, exactly one (openrouter) posts a raw OpenAI-wire
105
- * tools array; the rest go through an SDK or an agent framework that takes the bare
106
- * schema.
107
- *
108
- * Serving all three was the other candidate and it loses on cost for no gain in
109
- * safety: measured on this tree, one card's pretty-printed definition runs
110
- * 1.7-5.3 KB, so three of them plus the schema turns a single `kai-artifact` lookup
111
- * into roughly 20 KB of context. The response names all three modes and the exact
112
- * call that produces each, so a caller who does know their provider is one re-ask
113
- * away and still never invents an envelope.
114
- */
115
- const DEFAULT_PROVIDER: ToolProvider = 'jsonschema';
116
-
117
- function isProvider(value: string): value is ToolProvider {
118
- return (PROVIDERS as readonly string[]).includes(value);
119
- }
120
-
121
- /** Stable fence info strings, so a reader (and reference.test.ts) can lift the blocks back out exactly. */
122
- const TOOL_FENCE = 'kai-tool-definition';
123
- const SCHEMA_FENCE = 'kai-card-schema';
124
-
125
- function fence(info: string, value: unknown): string[] {
126
- return ['```json ' + info, JSON.stringify(value, null, 2), '```'];
127
- }
128
-
129
- /**
130
- * Render a card type as it would be written in JS source.
131
- *
132
- * The seven built-ins are all bare identifiers, but a card type is whatever string a
133
- * developer put in `CardEnvelope.type` — `pricing-table` is legal and reaches this
134
- * code the day an eighth built-in is hyphenated. Emitting `{ pricing-table: … }` as a
135
- * copy-paste sample would be a syntax error, so the quoting is decided, not assumed.
136
- */
137
- const BARE_IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
138
-
139
- function asKey(cardType: string): string {
140
- return BARE_IDENTIFIER.test(cardType) ? cardType : JSON.stringify(cardType);
141
- }
142
-
143
- function asMember(cardType: string): string {
144
- return BARE_IDENTIFIER.test(cardType) ? `.${cardType}` : `[${JSON.stringify(cardType)}]`;
145
- }
146
-
147
- /**
148
- * The loop, in the four facts a harness cannot infer from a prop table.
149
- *
150
- * Shared by the card-backed and the card-host sections because they are the same
151
- * contract seen from the two ends, and a second copy would be the drift this whole
152
- * task exists to remove, one level up from the tool definition.
153
- *
154
- * `example` is the card the caller actually asked about, so the illustration is about
155
- * their card rather than a fixed one they then have to translate.
156
- */
157
- function loopWiring(example: string): string[] {
158
- return [
159
- '',
160
- '#### Wiring the loop',
161
- `- **Tool names are \`${KAI_TOOL_PREFIX}<card type>\`.** \`${toolNameForCardType(example)}\` produces \`{ type: "${example}" }\`. ` +
162
- 'Use `isCardTool(name)` to split card calls from your own tools; never match the prefix by hand.',
163
- '- **`tool_call_id` becomes `CardEnvelope.id`, unchanged.** That is what makes a revision UPSERT: ' +
164
- 'a model that re-sends the same tool call id replaces the card in place instead of rendering a second copy of it. ' +
165
- 'Generating your own id breaks that silently.',
166
- '- **`cardFromToolCall(name, input, { id: call.id })`** turns the call into a renderable envelope, ' +
167
- 'or returns `null` when it is one of your own tools so the loop falls through to it. It never throws.',
168
- '- **Everything above is one import:** `import { cardTools, cardFromToolCall, isCardTool } from \'@kitn.ai/ui/schemas\'`. ' +
169
- `The raw documents also ship as JSON (\`@kitn.ai/ui/schemas/${example}.schema.json\`) for a Python or Go backend.`,
170
- ];
171
- }
172
-
173
- /** The card-backed section: schema + a GENERATED tool definition. */
174
- function renderCardContract(tag: string, cardType: CardSchemaName, provider: ToolProvider): string[] {
175
- const schema = cardSchemas[cardType];
176
-
177
- // GENERATED, NEVER RESTATED.
178
- //
179
- // This calls the same `cardTools` a consumer's route calls, on the same schema, so
180
- // the definition served here cannot diverge from the one they ship — not when a
181
- // schema gains a field, not when the projection changes what it strips. A literal
182
- // typed into this file would read identically today and rot on the first schema
183
- // change, which is exactly the hand-copy drift this tool exists to remove.
184
- // reference.test.ts asserts byte-equality against BOTH `cardTools({ [type]: schema },
185
- // …)` and the matching entry of the whole-registry `cardTools({ provider })`, so a
186
- // hand-edit here fails a test rather than shipping.
187
- const [def] = cardTools({ [cardType]: schema }, { provider });
188
-
189
- const lines: string[] = [
190
- '',
191
- '### Card contract',
192
- `\`<${tag}>\` renders \`CardEnvelope.type: "${cardType}"\`. A model does not emit an envelope; ` +
193
- `it calls the tool \`${toolNameForCardType(cardType)}\`, and the kit turns that call back into one.`,
194
- ];
195
-
196
- lines.push(
197
- '',
198
- `#### Tool definition — provider \`${provider}\``,
199
- `Generated by \`cardTools({ ${asKey(cardType)}: cardSchemas${asMember(cardType)} }, { provider: '${provider}' })\`. ` +
200
- 'Copy it; do not retype it, and do not hand-maintain a second copy — regenerate instead.',
201
- `Ask again with \`provider\` set to \`openai\`, \`anthropic\` or \`jsonschema\` for the other envelopes. ` +
202
- 'They are NOT interchangeable: OpenAI nests the schema at `function.parameters`, Anthropic puts it flat at `input_schema`.',
203
- ...fence(TOOL_FENCE, def),
204
- );
205
-
206
- lines.push(
207
- '',
208
- '#### Card data JSON Schema',
209
- `\`import { cardSchemas } from '@kitn.ai/ui/schemas'\` → \`cardSchemas${asMember(cardType)}\`. ` +
210
- `Raw document: \`@kitn.ai/ui/schemas/${cardType}.schema.json\`.`,
211
- 'This is the authored contract, and it is what `registry.validate()` checks arriving data against. ' +
212
- 'The tool definition above carries the same document with `$schema`, `$id` and `x-kai-*` stripped — ' +
213
- 'that projection is `cardTools`\' job, so do not put a raw schema on the wire yourself.',
214
- ...fence(SCHEMA_FENCE, schema),
215
- );
216
-
217
- lines.push(...loopWiring(cardType));
218
- return lines;
219
- }
220
-
221
- /** The card-host section: no schema of its own, but this is where the props live. */
222
- function renderCardHost(tag: string): string[] {
223
- const rows = cardSchemaNames.map((type) => {
224
- const cardTag = cardTagForType(type);
225
- return `- \`${type}\` → \`<${cardTag ?? '(no element)'}>\`, tool \`${toolNameForCardType(type)}\``;
226
- });
227
-
228
- return [
229
- '',
230
- '### Card contract',
231
- `\`<${tag}>\` renders generative-UI cards inside the thread. It is a HOST: it draws whatever ` +
232
- 'envelopes arrive, and carries the two props that say what a card may be.',
233
- '',
234
- '- **`cardTypes`** — `Record<envelope type, custom element tag>`. What DRAWS a card. ' +
235
- `Merged over the built-ins, so your entry overrides ours and the other ${cardSchemaNames.length - 1} still render.`,
236
- '- **`cardSchemas`** — `Record<envelope type, JSON Schema>`. What a VALID card looks like. ' +
237
- `This is the prop that carries YOUR OWN card schemas into the browser validator; the ${cardSchemaNames.length} built-ins are already known. ` +
238
- 'Both are objects, so both are JS properties (`el.cardSchemas = …`), never HTML attributes.',
239
- '',
240
- 'Write both once with `createCardRegistry({ use, custom })` from `@kitn.ai/ui/schemas` and thread it to both ends: ' +
241
- '`el.cardTypes = cards.tags` / `el.cardSchemas = cards.validationSchemas` on the client, `cardTools(cards, { provider })` on the route.',
242
- '',
243
- 'Built-in card types (ask `component_reference` for one of these tags to get its schema and tool definition):',
244
- ...rows,
245
- ...loopWiring(cardSchemaNames[0]),
246
- ];
247
- }
248
-
249
- // ─────────────────────────────────────────────────────────────────────────────
250
- // The composition catalog: invariants, and recipe membership
251
- // ─────────────────────────────────────────────────────────────────────────────
252
-
253
- /**
254
- * An invariant applies to a tag if it is unscoped by tag, or names it.
255
- *
256
- * `appliesTo.targets` deliberately does NOT filter here: `upgrade-race` is
257
- * scoped to script-tag DELIVERY, which is a fact about how the page loads and
258
- * not about which element is on it — every element can be dropped onto a CDN
259
- * page. So it is served everywhere and the scope is RENDERED (see `scopeOf`),
260
- * which is the difference between a conditional rule a reader can apply and an
261
- * unqualified one they will either over-apply or stop trusting.
262
- */
263
- function invariantsFor(tag: string): TInvariant[] {
264
- return invariants.filter((i) => !i.appliesTo.tags || i.appliesTo.tags.includes(tag));
265
- }
266
-
267
- /**
268
- * The recipe's nesting, as markup a reader can paste.
269
- *
270
- * `noteSep` is how much of the record to print: the appendix passes ' — ' and
271
- * gets the WHY, an element lookup passes '' and gets only the shape, on the same
272
- * split the wiring rows already use. A recipe with no `composition` prints
273
- * nothing at all rather than "flat" — the field being absent means nobody
274
- * decided, and a rendered "(none)" would turn a gap into a claim.
275
- */
276
- function compositionLines(r: TSurfaceRecipe, noteSep: string): string[] {
277
- if (!r.composition) return [];
278
- return [
279
- '- **Composition** — where the parts go (a slotted child, not a sibling):',
280
- ...r.composition.map(
281
- (c) =>
282
- ` - \`<${c.child} slot="${c.slot}">\` goes INSIDE \`<${c.parent}>\`` +
283
- (noteSep && c.note ? `${noteSep}${c.note}` : ''),
284
- ),
285
- ];
286
- }
287
-
288
- function recipesFor(tag: string): TSurfaceRecipe[] {
289
- return surfaceRecipes.filter((r) => r.ingredients.includes(tag));
290
- }
291
-
292
- /**
293
- * How the coverage of one invariant reads — never a bare status word, and never
294
- * silence.
295
- *
296
- * Three of the catalog's records are enforced by NOTHING and two more by half of
297
- * what they say. A section that printed every rule as an equal-looking bullet
298
- * would put back exactly the overstatement those records were rewritten to
299
- * remove, one layer further out where it is harder to see. The wording also says
300
- * whose code the guard reads: every path here is inside the KIT's own repo, and
301
- * none of them checks the consumer's.
302
- */
303
- function coverageOf(inv: TInvariant): string {
304
- const by = inv.enforcedBy;
305
- // `guard` is '' only for kind:'none', and that combination reaches neither the
306
- // 'enforced' nor the 'partial' branch below: invariants.test.ts ("open ⟺
307
- // enforcedBy.kind none") asserts the equivalence in BOTH directions, so a
308
- // kind:'none' record is always status:'open'. Named here because a reader of
309
- // this file alone cannot see what makes `enforced by ` with nothing after it
310
- // unreachable.
311
- const guard =
312
- by.kind === 'test'
313
- ? `the kit's own tests (${by.paths.join(', ')})`
314
- : by.kind === 'lint'
315
- ? `the kit's \`${by.script}\` script, in required CI`
316
- : by.kind === 'structural'
317
- ? `a structural guarantee in ${by.path}`
318
- : '';
319
-
320
- switch (inv.status) {
321
- case 'enforced':
322
- return `enforced by ${guard}`;
323
- case 'partial':
324
- return `PARTIALLY ENFORCED: one half is covered, by ${guard}; the statement says which half is not`;
325
- case 'open':
326
- return (
327
- 'NOT ENFORCED: nothing in the kit checks this' +
328
- (by.kind === 'none' && by.until ? `, until ${by.until}` : '') +
329
- '. A rule you apply, not a guarantee you will be warned about'
330
- );
331
- }
332
- }
333
-
334
- /** What narrows an invariant, when something does. `targets` is not `tags`. */
335
- function scopeOf(inv: TInvariant): string {
336
- const { tags, targets, parts } = inv.appliesTo;
337
- const bits: string[] = [];
338
- if (tags) bits.push(`only ${tags.join(', ')}`);
339
- if (targets) bits.push(`${targets.join(' / ')} delivery only`);
340
- if (parts) bits.push(`parts ${parts.join(', ')}`);
341
- return bits.join('; ');
342
- }
343
-
344
- /**
345
- * The wrong/right pairs, as one fenced block per invariant.
346
- *
347
- * A fence rather than inline code because a `right` form is allowed to span
348
- * lines (the URL guards do), and because the pairs are meant to be
349
- * pattern-matched and grepped verbatim — the self-audit checklist greps emitted
350
- * code for the `wrong` form and expects zero hits, which only works if what is
351
- * served here is the literal and not a paraphrase of it.
352
- */
353
- function exampleLines(examples: TInvariantExample[]): string[] {
354
- if (examples.length === 0) return [];
355
- const out: string[] = ['', '```js'];
356
- examples.forEach((ex, i) => {
357
- if (i > 0) out.push('');
358
- out.push('// WRONG', ex.wrong, '// RIGHT', ex.right);
359
- if (ex.note) out.push(...ex.note.split('\n').map((l) => `// ${l}`));
360
- });
361
- out.push('```');
362
- return out;
363
- }
364
-
365
- /**
366
- * The one sentence saying how much of this section is actually guarded.
367
- *
368
- * BOTH numerators are derived and both are needed. `open` alone was the first
369
- * form of this line, and it is the more quotable half: "3 of the 7 below are
370
- * enforced by NOTHING" compresses, in any reader summarising it, into "3
371
- * unenforced, 4 enforced" — and two of that four are `partial`, covered on one
372
- * half only. That is this repo's own compression-drops-the-qualifier failure,
373
- * sitting in the sentence written to prevent it. Naming both counts leaves the
374
- * compression nothing to invent.
375
- *
376
- * Returns '' when every applicable record is fully enforced, so the line can
377
- * never outlive the gap it describes and become a comfortable falsehood.
378
- *
379
- * Exported for reference.test.ts, which drives all four count combinations over
380
- * synthetic records — the real catalog can only instance one of them at a time.
381
- */
382
- export function coverageSummary(applicable: TInvariant[]): string {
383
- const open = applicable.filter((i) => i.status === 'open').length;
384
- const partial = applicable.filter((i) => i.status === 'partial').length;
385
- if (open === 0 && partial === 0) return '';
386
-
387
- const total = applicable.length;
388
- const half = (n: number) => `only half of what ${n === 1 ? 'it says' : 'they say'}`;
389
- const clauses: string[] = [];
390
-
391
- if (open > 0) {
392
- clauses.push(`${open} of the ${total} below ${open === 1 ? 'is' : 'are'} enforced by NOTHING at all`);
393
- }
394
- if (partial > 0) {
395
- clauses.push(
396
- open > 0
397
- ? `${partial} more by ${half(partial)}`
398
- : `${partial} of the ${total} below ${partial === 1 ? 'is' : 'are'} enforced by ${half(partial)}`,
399
- );
400
- }
401
- return ` ${clauses.join(', and ')}.`;
402
- }
403
-
404
- /**
405
- * `###` to match every other section heading in this file (see '### Props'),
406
- * `####` for the per-record blocks, matching the card contract's sub-headings.
407
- *
408
- * Each invariant gets its heading (id, scope, coverage) and its one-line
409
- * `statement` — enough to apply the rule and to know how much to trust it —
410
- * but NOT the diagnosis and wrong/right examples. Those are the bulk: measured
411
- * on this tree, the full body of the 7 catalog records runs ~13 KB, and every
412
- * unscoped record (5 of 7) applies to all 80 elements, so printing the full
413
- * body here paid that in full on every lookup. `renderInvariantAppendix`
414
- * carries the long form exactly once; this function points to it instead of
415
- * repeating it.
416
- */
417
- function catalogSectionLines(tag: string): string[] {
418
- const applicable = invariantsFor(tag);
419
- const lines: string[] = [];
420
-
421
- if (applicable.length > 0) {
422
- lines.push(
423
- '',
424
- '### Invariants',
425
- 'Rules that have already broken real consumers of this kit. Each block says what enforces ' +
426
- 'it — read that line rather than assuming CI catches a violation, because nothing here ' +
427
- 'reads YOUR code.' + coverageSummary(applicable) + ' Diagnosis and wrong/right examples for ' +
428
- 'every invariant are served once, not repeated per element — call component_reference with ' +
429
- '{ name: "invariants" }.',
430
- );
431
-
432
- for (const inv of applicable) {
433
- const scope = scopeOf(inv);
434
- lines.push('', `#### ${inv.id}${scope ? ` (${scope})` : ''} — ${coverageOf(inv)}`, inv.statement);
435
- }
436
- }
437
-
438
- // No recipe, no section. An element that is in none gets its universal
439
- // invariants and nothing else — a "part of: (none)" row would be a fabricated
440
- // membership claim dressed as an empty one.
441
- const recipes = recipesFor(tag);
442
- if (recipes.length > 0) {
443
- lines.push(
444
- '',
445
- '### Appears in surface recipes',
446
- 'Compositions this element is part of, each with the whole ingredient list and the host ' +
447
- 'wiring — nothing coordinates one element with another except your own code ' +
448
- '(host-coordinates). The WHY behind each wiring edge, and the caveats on the nesting ' +
449
- 'below, are served once rather than repeated per ingredient — call component_reference ' +
450
- 'with { name: "recipes" }.',
451
- );
452
- for (const r of recipes) {
453
- lines.push(
454
- '',
455
- `#### ${r.id} — ${r.intent}`,
456
- `- **Ingredients:** ${r.ingredients.map((t) => `\`<${t}>\``).join(', ')}`,
457
- `- **Delivery:** ${r.targets.join(', ')} · archetype: ${r.archetypes.join(', ')}`,
458
- `- **Backend:** your own endpoint, read with \`${r.backend.reader}\` from \`@kitn.ai/ui/wire\``,
459
- // WHERE the parts go. Printed per element and not only in the appendix,
460
- // because this is the one fact a builder cannot infer from anything else
461
- // on the page: the wiring rows say which event drives which property and
462
- // are silent about nesting, so an element lookup that omitted this left
463
- // the reader to guess between a child and a sibling. Short enough to
464
- // repeat; the `note` (the WHY) stays in the appendix with the wiring notes.
465
- ...compositionLines(r, ''),
466
- // Bare ids, deliberately. This row is a DEPENDENCY list, not a coverage
467
- // claim, and it can only ever be read a few lines below the full
468
- // `### Invariants` section in the same response, where each of these ids
469
- // already carries its own coverage line. Repeating the status here would
470
- // print it a second (and, with two recipes, a third) time per element for
471
- // no fact a reader does not already have on the page.
472
- `- **Invariants it leans on:** ${r.invariants.join(', ')}`,
473
- // Compact: the edge (event out of A, property into B) with no `note`.
474
- // The note is the WHY — often a full sentence, sometimes several — and
475
- // repeating it is the same shape of duplication task 4 removed from
476
- // invariants: this recipe's ingredients (kai-chat, kai-conversations,
477
- // kai-resizable, kai-artifact) all print this identical wiring list.
478
- // `renderRecipeAppendix` carries the notes exactly once.
479
- '- **Wiring** — event out of A, property into B, wired by the host:',
480
- );
481
- for (const w of r.wiring) {
482
- lines.push(` - \`<${w.from}>\` fires \`${w.event}\` → host sets \`${w.to}.${w.property}\``);
483
- }
484
- }
485
- }
486
-
487
- return lines;
488
- }
489
-
490
- /**
491
- * The long-form recipe reference, served exactly once rather than repeated on
492
- * every ingredient. `catalogSectionLines` prints the ingredients, delivery,
493
- * backend and a compact wiring list (edge only, no `note`) per element and
494
- * points here for the rest — the WHY behind each wiring edge, which is the
495
- * bulk: `workspace-chat` alone has 4 ingredients, and every one of them
496
- * printed every wiring note in full before this moved. Reached via
497
- * `component_reference({ name: "recipes" })`.
498
- */
499
- function renderRecipeAppendix(): string[] {
500
- const lines: string[] = [
501
- `## Surface recipe catalog (${surfaceRecipes.length} total) — wiring notes`,
502
- '',
503
- 'Every element lookup that appears in a recipe lists its ingredients, delivery, backend and ' +
504
- 'a compact wiring list (event out of A, property into B). This is the long form: the WHY ' +
505
- 'behind each wiring edge, written once here rather than repeated on every ingredient.',
506
- ];
507
-
508
- for (const r of surfaceRecipes) {
509
- lines.push(
510
- '',
511
- `#### ${r.id} — ${r.intent}`,
512
- `- **Ingredients:** ${r.ingredients.map((t) => `\`<${t}>\``).join(', ')}`,
513
- `- **Delivery:** ${r.targets.join(', ')} · archetype: ${r.archetypes.join(', ')}`,
514
- `- **Backend:** your own endpoint, read with \`${r.backend.reader}\` from \`@kitn.ai/ui/wire\``,
515
- `- **Invariants it leans on:** ${r.invariants.join(', ')}`,
516
- ...compositionLines(r, ' — '),
517
- '- **Wiring** — event out of A, property into B, wired by the host:',
518
- );
519
- for (const w of r.wiring) {
520
- lines.push(
521
- ` - \`<${w.from}>\` fires \`${w.event}\` → host sets \`${w.to}.${w.property}\`` +
522
- (w.note ? ` — ${w.note}` : ''),
523
- );
524
- }
525
- }
526
-
527
- return lines;
528
- }
529
-
530
- /**
531
- * The long-form invariant reference, served exactly once rather than repeated
532
- * on every element it applies to. `catalogSectionLines` prints only the id,
533
- * scope and one-line statement per element and points here for the rest —
534
- * this is that "rest": every record's full statement again for context, its
535
- * diagnosis rows, and its wrong/right examples, each written once for the
536
- * whole catalog regardless of how many of the 80 elements the record applies
537
- * to. Reached via `component_reference({ name: "invariants" })`.
538
- */
539
- function renderInvariantAppendix(): string[] {
540
- const lines: string[] = [
541
- `## Invariant catalog (${invariants.length} total) — diagnosis and examples`,
542
- '',
543
- 'Every element lookup lists the invariants that apply to it by id and one-line statement. ' +
544
- 'This is the long form: full statement, diagnosis and wrong/right examples for each record, ' +
545
- 'written once here rather than repeated on every element it applies to.',
546
- ];
547
-
548
- for (const inv of invariants) {
549
- const scope = scopeOf(inv);
550
- lines.push('', `#### ${inv.id}${scope ? ` (${scope})` : ''} — ${coverageOf(inv)}`, inv.statement);
551
- if (inv.diagnosis.length > 0) {
552
- lines.push('', 'If you are debugging:');
553
- for (const d of inv.diagnosis) lines.push(`- ${d.symptom} → ${d.cause}`);
554
- }
555
- lines.push(...exampleLines(inv.examples));
556
- }
557
-
558
- return lines;
559
- }
560
-
561
- // ─────────────────────────────────────────────────────────────────────────────
562
- // The programmatic layer and the code recipes
563
- // ─────────────────────────────────────────────────────────────────────────────
564
-
565
- /** The topic names that all resolve to the programmatic-layer appendix. */
566
- const PROGRAMMATIC_ALIASES = ['programmatic', 'state', 'wire', 'state-wire'] as const;
567
-
568
- /**
569
- * The `/state` + `/wire` appendix (rung-6 F-46): a marker-fenced section of the
570
- * package-root `llms-full.txt`, which `build:api` DERIVES from the shipped
571
- * `dist/state/*.d.ts` + `dist/wire/*.d.ts` (scripts/gen-llms-programmatic.mjs).
572
- * Read, never restated: this tool restating one signature by hand is exactly
573
- * the drift the generator exists to remove. The root copy is the CANONICAL and
574
- * ONLY shipped copy (owner-ruled 2026-08-25): a second copy under `dist/llms/`
575
- * used to ship too, ~293 KB of duplicate tarball weight — and it once went
576
- * stale against the root while both claimed to be the artifact. It resolves
577
- * relative to the manifest (`dist/custom-elements.json`), whose parent's
578
- * parent is the package root in both contexts — bundled bin and source/vitest.
579
- */
580
- /**
581
- * The fence gen-llms-programmatic.mjs writes around the section inside
582
- * llms-full.txt. REGISTERED COPY of `PROGRAMMATIC_MARKERS` in that script —
583
- * this TS module cannot import the generator .mjs. If either side moves, the
584
- * slice below misses and the reference tests fail on the "Missing build
585
- * artifact" branch, so the drift is loud.
586
- */
587
- const PROGRAMMATIC_START = '<!-- kai:programmatic:start -->';
588
- const PROGRAMMATIC_END = '<!-- kai:programmatic:end -->';
589
-
590
- function renderProgrammaticAppendix(): string {
591
- // Sliced out of the SHIPPED llms-full.txt rather than served from a file of
592
- // its own: a standalone copy was ~50 KB of duplicate tarball weight
593
- // (verify:pack priced it), and slicing keeps one derivation with zero extra
594
- // shipped bytes.
595
- const path = join(dirname(resolveManifestPath()), '..', 'llms-full.txt');
596
- const missing = (what: string) =>
597
- `Missing build artifact: ${what}\n\n` +
598
- 'The programmatic-layer reference is generated from the shipped dist/*.d.ts by the ' +
599
- 'build (a marker-fenced section of the package-root llms-full.txt). Run `nx build ui` ' +
600
- '(or `npm run build:api` in packages/ui) and ask again. It is deliberately not restated ' +
601
- 'here: a hand-typed copy would drift from the declarations your editor shows.';
602
- if (!existsSync(path)) return missing(path);
603
- const full = readFileSync(path, 'utf-8');
604
- const start = full.indexOf(PROGRAMMATIC_START);
605
- const end = full.indexOf(PROGRAMMATIC_END);
606
- if (start === -1 || end === -1 || end <= start) {
607
- return missing(`the ${PROGRAMMATIC_START} section inside ${path}`);
608
- }
609
- return full.slice(start + PROGRAMMATIC_START.length, end).trim();
610
- }
611
-
612
- /**
613
- * One code recipe as files a builder pastes. The catalog half (ingredients,
614
- * wiring edges, invariants — each executed by surfaces.test.ts) is the surface
615
- * recipe of the same id; this is the body a data record cannot carry, and
616
- * `verify:scaffold` compiles every `lang: 'ts'` file of it.
617
- */
618
- function renderCodeRecipe(r: CodeRecipe): string {
619
- const lines: string[] = [
620
- `## Recipe: ${r.title} (\`${r.id}\`)`,
621
- '',
622
- r.intent,
623
- '',
624
- `**Elements composed:** ${r.ingredients.map((t) => `\`<${t}>\``).join(', ')}`,
625
- '',
626
- '**Read these before pasting:**',
627
- ...r.notes.map((n) => `- ${n}`),
628
- ];
629
- for (const f of r.files) {
630
- lines.push('', `### \`${f.path}\``, '', '```' + f.lang, f.code.trimEnd(), '```');
631
- }
632
- lines.push(
633
- '',
634
- 'The wiring topology, invariants and composition claims behind this recipe are the ' +
635
- `surface recipe of the same id — call component_reference with { name: "recipes" }.`,
636
- );
637
- return lines.join('\n');
638
- }
639
-
640
- /**
641
- * The payload out of `CustomEvent<T>`, or `undefined` when there is no payload.
642
- *
643
- * The manifest types every event, but as the wrapper — printing that raw teaches
644
- * a reader to write `CustomEvent<...>` where a payload belongs. Anything that is
645
- * not of the form `CustomEvent<…>` has NO payload to print, and this returns
646
- * `undefined` so the caller omits the `detail` clause entirely.
647
- *
648
- * That is read off the generator rather than guessed at. gen-element-api.mjs
649
- * writes the CEM type as ``CustomEvent<${e.detail}>`` when the element declares a
650
- * detail and the bare string `CustomEvent` when it does not — exactly two shapes,
651
- * and the bare one means the detail is `void` (e.g. `'kai-click': void` in
652
- * button.tsx). Passing an unrecognised type through unchanged looked like a safe
653
- * fallback for an already-unwrapped payload; what it actually caught was the void
654
- * events, which then rendered ``Carries no detail. `detail`: `CustomEvent` `` — a
655
- * line contradicting itself, on 13 events across 10 elements. The whole-manifest
656
- * probe in reference.test.ts holds both directions of the rule.
657
- */
658
- function eventDetail(typeText: string | undefined): string | undefined {
659
- const m = /^CustomEvent<([\s\S]*)>$/.exec(typeText?.trim() ?? '');
660
- return m ? m[1].trim() || undefined : undefined;
661
- }
662
-
663
- function formatReference(tag: string, provider: ToolProvider): string {
664
- const el = getElement(tag);
665
-
666
- if (!el) {
667
- const all = listElements();
668
- const sample = all.slice(0, 5).join(', ');
669
- return (
670
- `Unknown element: ${tag}\n\n` +
671
- `Valid tags include: ${sample} (and ${Math.max(0, all.length - 5)} more).\n` +
672
- `Call component_reference with no name (or name: "list") to list all ${all.length} elements.`
673
- );
674
- }
675
-
676
- const lines: string[] = [];
677
-
678
- // ── Header ─────────────────────────────────────────────────────────────────
679
- lines.push(`## <${tag}>`);
680
- if (el.description) {
681
- lines.push('', el.description.trim());
682
- }
683
-
684
- // ── Getting the element ────────────────────────────────────────────────────
685
- // FIRST, above every other section. An element that never upgrades renders
686
- // nothing and logs NOTHING: the property assigns and reads back fine, and
687
- // whenDefined() never settles, so the listener is never attached. That symptom
688
- // is also what props-not-attributes blames on a different cause, so a reader
689
- // who has the invariants and not this line is steered to the wrong diagnosis.
690
- const entry = entryForTag(tag);
691
- const iface = el.name;
692
- const neverUpgrades =
693
- 'If you skip registering it the element never upgrades: nothing renders, ' +
694
- '**no error and no warning is logged**, a property you set assigns and reads ' +
695
- `back correctly, and \`customElements.whenDefined('${tag}')\` never resolves.`;
696
- lines.push('', '### Getting the element');
697
- if (entry) {
698
- lines.push(
699
- `Register it before you use it. ${neverUpgrades}`,
700
- '',
701
- '```ts',
702
- "import '@kitn.ai/ui/elements';",
703
- `import '@kitn.ai/ui/elements/${entry}'; // or just this one`,
704
- '```',
705
- );
706
- } else {
707
- // entryForTag is undefined exactly when register-impl.ts does not import this
708
- // element's source file — i.e. it is NOT in the register-all bundle. The only
709
- // current instance is kai-remote, a deliberate exception (opt-in cross-origin
710
- // iframe card) documented at src/elements/element-diagnostics.ts:347-363 and
711
- // vite.config.elements.ts:44-50. `import '@kitn.ai/ui/elements'` would NOT
712
- // register a tag in this state, so asserting it here is exactly the false
713
- // claim this section exists to prevent.
714
- //
715
- // The specifier is still NOT guessed — stripping `kai-` is wrong for ten of
716
- // the eighty elements. `optInEntryForTag` reads it off the module the
717
- // per-element build actually emitted, matched to this tag by the tag literal
718
- // it registers; see the note there. Telling the reader to go look it up was
719
- // the last place in this reference where "how to make the element exist" did
720
- // not answer itself, and the answer was in the build config all along.
721
- const optIn = optInEntryForTag(tag);
722
- lines.push(
723
- `**\`${tag}\` is opt-in — it is not part of \`import '@kitn.ai/ui/elements'\` ` +
724
- '(register-all), and that import alone will NOT register it.** ' +
725
- (optIn
726
- ? `Import its own entry point instead. ${neverUpgrades}`
727
- : // No built module claims this tag, so there is no specifier to name.
728
- // Stay honest rather than inventing one.
729
- 'Find its specific `@kitn.ai/ui/elements/<name>` entry point in the ' +
730
- `package's published exports before using it. ${neverUpgrades}`),
731
- );
732
- if (optIn) {
733
- lines.push('', '```ts', `import '@kitn.ai/ui/elements/${optIn}';`, '```');
734
- }
735
- }
736
- if (iface) {
737
- lines.push(
738
- '',
739
- `TypeScript: \`import type { ${iface} } from '@kitn.ai/ui/elements';\` — ` +
740
- 'the element interface ships with the package; do not hand-roll a structural type.',
741
- );
742
- }
743
-
744
- // ── Contract note ──────────────────────────────────────────────────────────
745
- lines.push(
746
- '',
747
- '### AI/UI contract',
748
- '`kai-*` elements accept **array and object data as JavaScript properties** ' +
749
- '(set in JavaScript via `el.property = value`, not as HTML attributes). ' +
750
- 'Events are native CustomEvents — listen with `el.addEventListener("event-name", handler)` ' +
751
- 'and read `event.detail` for the payload.',
752
- );
753
-
754
- // ── Card contract ─────────────────────────────────────────────────────────
755
- // Attached to the two populations manifest.ts derives, and to nothing else. A
756
- // reference that hangs card material off all 80 elements is worse than one that
757
- // hangs it off none: it teaches a harness that every element takes a tool call.
758
- const cardType = cardTypeForTag(tag);
759
- if (cardType !== undefined && isCardSchemaName(cardType)) {
760
- lines.push(...renderCardContract(tag, cardType, provider));
761
- } else if (cardHostTags().includes(tag)) {
762
- lines.push(...renderCardHost(tag));
763
- }
764
-
765
- // ── Public JS properties ───────────────────────────────────────────────────
766
- const publicFields = (el.members ?? []).filter(
767
- (m) => m.kind === 'field' && m.privacy === 'public',
768
- );
769
-
770
- if (publicFields.length > 0) {
771
- lines.push('', '### Props (JavaScript properties)');
772
- for (const field of publicFields) {
773
- const type = field.type?.text ?? 'unknown';
774
- const jsOnly = isJsOnlyType(type);
775
- const desc = field.description?.trim() ?? '';
776
- const note = jsOnly ? ' ⚑ set as a JS property, not an HTML attribute' : '';
777
- lines.push(`- **${field.name}** \`${type}\`${note}`);
778
- if (desc) {
779
- lines.push(` ${desc}`);
780
- }
781
- }
782
- }
783
-
784
- // ── HTML attributes ────────────────────────────────────────────────────────
785
- const attrs = el.attributes ?? [];
786
- if (attrs.length > 0) {
787
- lines.push('', '### Attributes (HTML-safe)');
788
- for (const attr of attrs) {
789
- const type = attr.type?.text ?? 'unknown';
790
- const desc = attr.description?.trim() ?? '';
791
- lines.push(`- **${attr.name}** \`${type}\``);
792
- if (desc) {
793
- lines.push(` ${desc}`);
794
- }
795
- }
796
- }
797
-
798
- // ── Events ────────────────────────────────────────────────────────────────
799
- const events = el.events ?? [];
800
- if (events.length > 0) {
801
- lines.push('', '### Events (CustomEvent, listen via addEventListener)');
802
- for (const ev of events) {
803
- const desc = ev.description?.trim() ?? '';
804
- const detail = eventDetail(ev.type?.text);
805
- lines.push(
806
- detail
807
- ? `- **${ev.name}** — ${desc} \`detail\`: \`${detail}\``
808
- : `- **${ev.name}** — ${desc}`,
809
- );
810
- }
811
- }
812
-
813
- // ── Methods ───────────────────────────────────────────────────────────────
814
- // The input half of the interaction surface. These were in the manifest and in
815
- // the shipped types and rendered in NO reference, so the only way to find one
816
- // was to read the kit's source.
817
- const methods = (el.members ?? []).filter(isPublicMethod);
818
- if (methods.length > 0) {
819
- lines.push(
820
- '',
821
- '### Methods (call these on the element instance)',
822
- `Get the element (\`const el = document.querySelector('${tag}')\`), then call it. ` +
823
- 'Methods drive the element from your code; the events above report back what the ' +
824
- 'user did. Both are public API.',
825
- );
826
- for (const method of methods) {
827
- const desc = method.description?.trim() ?? '';
828
- lines.push(`- **${methodSignature(method)}**${desc ? ` — ${desc}` : ''}`);
829
- }
830
- }
831
-
832
- // ── CSS custom properties ─────────────────────────────────────────────────
833
- const cssProps = el.cssProperties ?? [];
834
- if (cssProps.length > 0) {
835
- lines.push('', '### CSS custom properties');
836
- for (const prop of cssProps) {
837
- const desc = prop.description?.trim() ?? '';
838
- const def = prop.default ? ` (default: ${prop.default})` : '';
839
- lines.push(`- **${prop.name}**${def}${desc ? ` — ${desc}` : ''}`);
840
- }
841
- }
842
-
843
- // ── Composition slots ──────────────────────────────────────────────────────
844
- const slots = el.slots ?? [];
845
- if (slots.length > 0) {
846
- lines.push(
847
- '',
848
- '### Composition slots',
849
- 'Project your own markup into these named regions — add a light-DOM child ' +
850
- 'with a `slot="…"` attribute (e.g. `<div slot="sidebar">…</div>`).',
851
- );
852
- for (const slot of slots) {
853
- const desc = slot.description?.trim() ?? '';
854
- lines.push(`- **${slot.name}**${desc ? ` — ${desc}` : ''}`);
855
- }
856
- }
857
-
858
- // ── Styleable parts (::part) ───────────────────────────────────────────────
859
- const parts = el.cssParts ?? [];
860
- if (parts.length > 0) {
861
- lines.push(
862
- '',
863
- '### Styleable parts (`::part`)',
864
- 'Restyle these from outside the Shadow DOM via `' + tag + '::part(name) { … }`.',
865
- );
866
- for (const part of parts) {
867
- const desc = part.description?.trim() ?? '';
868
- lines.push(`- **${part.name}**${desc ? ` — ${desc}` : ''}`);
869
- if (part.recipe) {
870
- lines.push(' ```css', ` ${part.recipe}`, ' ```');
871
- }
872
- }
873
- }
874
-
875
- // ── The composition catalog ────────────────────────────────────────────────
876
- lines.push(...catalogSectionLines(tag));
877
-
878
- return lines.join('\n');
879
- }
880
-
881
- export const reference: Tool = {
882
- name: 'component_reference',
883
- description:
884
- 'Look up AI/UI (kai-*) web components: their tags, props, events, imperative methods, and usage examples. ' +
885
- 'For a card-backed element it also returns the card\'s JSON Schema and a ready-to-send ' +
886
- 'tool definition generated from it — pass `provider` to get that provider\'s envelope. ' +
887
- 'Also serves the programmatic layer (name: "programmatic" — the @kitn.ai/ui/state + ' +
888
- '@kitn.ai/ui/wire streaming/mock/encode API) and complete code recipes ' +
889
- '(e.g. name: "composed-thread" — a hand-composed thread with no <kai-chat>).',
890
- inputSchema: z.object({
891
- name: z
892
- .string()
893
- .optional()
894
- .describe(
895
- 'The element tag, e.g. "kai-chat". Omit it (or pass "list") to get the ' +
896
- 'index of every element with a one-line summary, then ask again for the one you want. ' +
897
- 'Pass "invariants" for the full diagnosis and wrong/right examples behind every ' +
898
- 'invariant id an element lookup shows. Pass "recipes" for the full wiring notes ' +
899
- 'behind every surface recipe an element lookup names. Pass "programmatic" (or ' +
900
- '"state" / "wire") for the @kitn.ai/ui/state + @kitn.ai/ui/wire API — streaming ' +
901
- 'folds, the mock responder, the SSE readers/encoders. Pass a code-recipe id ' +
902
- '(e.g. "composed-thread") for a complete pasteable composition.',
903
- ),
904
- provider: z
905
- .enum(PROVIDERS)
906
- .optional()
907
- .describe(
908
- 'Which tool-definition envelope to project for a card-backed element. ' +
909
- `Defaults to "${DEFAULT_PROVIDER}", the provider-neutral { name, description, schema } form.`,
910
- ),
911
- }),
912
- handler: async (args: Record<string, unknown>) => {
913
- const name = typeof args.name === 'string' ? args.name.trim() : undefined;
914
-
915
- // Validated HERE, not left to the zod schema above. server.ts advertises
916
- // `inputSchema` over the protocol but hands `request.params.arguments` straight
917
- // to this handler without parsing it, so an unrecognised provider would reach
918
- // `cardTools`, which treats anything that is not "openai"/"anthropic" as the
919
- // jsonschema branch. A caller asking for "gemini" would then get a definition in
920
- // a shape they did not ask for, with nothing saying so. Refusing is the only
921
- // answer that cannot be mistaken for an answer.
922
- const rawProvider = args.provider;
923
- if (rawProvider !== undefined && (typeof rawProvider !== 'string' || !isProvider(rawProvider))) {
924
- return {
925
- content: [
926
- {
927
- type: 'text' as const,
928
- text:
929
- `Unknown provider: ${JSON.stringify(rawProvider)}\n\n` +
930
- `Valid providers are ${PROVIDERS.map((p) => `"${p}"`).join(', ')}. ` +
931
- `Omit it to get "${DEFAULT_PROVIDER}", the provider-neutral { name, description, schema } form ` +
932
- 'that the Vercel AI SDK and most agent frameworks take directly.\n' +
933
- 'No tool definition was returned, because guessing which envelope you meant would hand you ' +
934
- 'a shape your provider rejects with nothing saying why.',
935
- },
936
- ],
937
- };
938
- }
939
- const provider: ToolProvider = rawProvider ?? DEFAULT_PROVIDER;
940
-
941
- let text: string;
942
-
943
- if (!name || name === 'list') {
944
- const tags = listElements();
945
- const cardRows = cardSchemaNames
946
- .map((t) => cardTagForType(t))
947
- .filter((t): t is string => t !== undefined);
948
- text =
949
- `AI/UI elements (${tags.length} total):\n\n` +
950
- tags.map((t) => ` ${t}`).join('\n') +
951
- '\n\nCall component_reference with a specific name (e.g. { name: "kai-chat" }) for full API details.' +
952
- `\n\nCard-backed elements — ask for one of these to get its JSON Schema and a generated ` +
953
- `\`${KAI_TOOL_PREFIX}*\` tool definition:\n ${cardRows.join(', ')}` +
954
- `\nThe elements that HOST them (and carry the \`cardTypes\` / \`cardSchemas\` props): ${cardHostTags().join(', ')}` +
955
- `\n\nCall component_reference with { name: "invariants" } for the full diagnosis and ` +
956
- 'wrong/right examples behind every invariant id shown on an element lookup.' +
957
- `\n\nCall component_reference with { name: "recipes" } for the full wiring notes behind ` +
958
- 'every surface recipe an element lookup names.' +
959
- `\n\nCall component_reference with { name: "programmatic" } for the @kitn.ai/ui/state + ` +
960
- '@kitn.ai/ui/wire API — createAssistantStream, the part folds, createMockResponder ' +
961
- '(and its scripted tool calls), the SSE readers and the provider encoders. That layer ' +
962
- 'is what a host wires when it composes elements by hand instead of using <kai-chat>.' +
963
- `\n\nComplete pasteable compositions (code recipes): ${listCodeRecipes()
964
- .map((r) => `{ name: "${r.id}" } — ${r.title}`)
965
- .join('; ')}.`;
966
- } else if (name === 'invariants') {
967
- text = renderInvariantAppendix().join('\n');
968
- } else if (name === 'recipes') {
969
- text = renderRecipeAppendix().join('\n');
970
- } else if ((PROGRAMMATIC_ALIASES as readonly string[]).includes(name)) {
971
- text = renderProgrammaticAppendix();
972
- } else if (getCodeRecipe(name)) {
973
- text = renderCodeRecipe(getCodeRecipe(name)!);
974
- } else {
975
- text = formatReference(name, provider);
976
- }
977
-
978
- return { content: [{ type: 'text' as const, text }] };
979
- },
980
- };