@kitn.ai/ui 0.25.2 → 0.27.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 (603) hide show
  1. package/README.md +17 -6
  2. package/bin/mcp.js +16 -3
  3. package/bin/route.js +23 -0
  4. package/bin/route.test.js +58 -0
  5. package/dist/{elements/chunks/Icon-b5A8hlHs.js → Icon-BnFKqqtY.js} +1 -1
  6. package/dist/action-icons-CBskfBMz.js +1 -0
  7. package/dist/arrow-down-Br0qtpsz.js +1 -0
  8. package/dist/arrow-left-Dj7xgE12.js +1 -0
  9. package/dist/artifact-CvXEm1lS.js +1 -0
  10. package/dist/assets/dev-5XzXYR21.js +91 -0
  11. package/dist/attachments-C43ZegEq.js +1 -0
  12. package/dist/audio-visualizer-B-79y1Tj.js +1 -0
  13. package/dist/badge-BpUbq8c0.js +1 -0
  14. package/dist/bash-InADTalH.js +1 -6
  15. package/dist/bell-sn17Ip9v.js +1 -0
  16. package/dist/{elements/chunks/button-B9okqG73.js → button-BH6rN0U-.js} +1 -1
  17. package/dist/card-renderer-Cb1gQmth.js +1 -0
  18. package/dist/card-routing-DifQgS7n.js +1 -0
  19. package/dist/check-DPeeMUYx.js +1 -0
  20. package/dist/checkbox-Dc9Yov_B.js +1 -0
  21. package/dist/checkbox-group-B1kDLLYk.js +1 -0
  22. package/dist/chevron-down-CHSWk7ZT.js +1 -0
  23. package/dist/chevron-right-B7l_fMgx.js +1 -0
  24. package/dist/choice-card-BT3c1S8g.js +1 -0
  25. package/dist/circle-Bb0yOpqM.js +1 -0
  26. package/dist/circle-check-BGZpCiz7.js +1 -0
  27. package/dist/circle-x-wobWkoSx.js +1 -0
  28. package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
  29. package/dist/code-block-CUQ5mtv0.js +1 -0
  30. package/dist/collapsible-CPJbf6FM.js +1 -0
  31. package/dist/components/attachment-types.d.ts +53 -1
  32. package/dist/components/attachments.d.ts +31 -0
  33. package/dist/components/audio-visualizer/fit-scale.d.ts +50 -0
  34. package/dist/components/audio-visualizer/index.d.ts +15 -1
  35. package/dist/components/audio-visualizer/variant-bar.d.ts +24 -1
  36. package/dist/components/card-renderer.d.ts +13 -0
  37. package/dist/components/card.d.ts +4 -0
  38. package/dist/components/chat-thread.d.ts +49 -42
  39. package/dist/components/code-block.d.ts +22 -0
  40. package/dist/components/conversation-item.d.ts +66 -1
  41. package/dist/components/conversation-list.d.ts +77 -0
  42. package/dist/components/form-widgets.d.ts +67 -2
  43. package/dist/components/form.d.ts +89 -0
  44. package/dist/components/message.d.ts +29 -0
  45. package/dist/components/reasoning.d.ts +6 -0
  46. package/dist/components/scroll-button.d.ts +11 -0
  47. package/dist/components/thread.d.ts +5 -0
  48. package/dist/components/toast.d.ts +2 -1
  49. package/dist/components/tool-types.d.ts +9 -0
  50. package/dist/components/voice-input.d.ts +8 -0
  51. package/dist/components/voice-output.d.ts +12 -1
  52. package/dist/components/workspace-shell.d.ts +87 -0
  53. package/dist/composer-CjngLzal.js +106 -0
  54. package/dist/confirm-card-DCx_A4bU.js +1 -0
  55. package/dist/construct-cli.es.js +1169 -0
  56. package/dist/context-BY8V-Nlp.js +1 -0
  57. package/dist/controllable-D43BKmtX.js +1 -0
  58. package/dist/conversation-list-D4lLU_yS.js +1 -0
  59. package/dist/copy-B6DO4PqB.js +1 -0
  60. package/dist/core-AYMC6_lb.js +12 -5874
  61. package/dist/{create-tween-CUzOlaMS.js → create-tween-BPzaefTp.js} +1 -1
  62. package/dist/{create-tween-B5Y4Im8G.js → create-tween-CnMHviKB.js} +1 -1
  63. package/dist/{create-tween-4z1XYLkR.js → create-tween-D1aiGZZh.js} +1 -1
  64. package/dist/{elements/chunks/create-tween-CUrM6D_o.js → create-tween-DUSQUKpr.js} +2 -2
  65. package/dist/css-M7EaDHN_.js +1 -6
  66. package/dist/custom-elements.json +3468 -1927
  67. package/dist/default-input-CucQEOqH.js +1 -0
  68. package/dist/define-CGGX-7Vg.js +1 -0
  69. package/dist/define.d.ts +4 -0
  70. package/dist/define.js +510 -0
  71. package/dist/define.server.d.ts +5 -0
  72. package/dist/define.server.js +506 -0
  73. package/dist/diagnostics/hook.d.ts +81 -0
  74. package/dist/diagnostics/index.d.ts +7 -0
  75. package/dist/diagnostics/report-request.d.ts +61 -0
  76. package/dist/diagnostics.d.ts +5 -0
  77. package/dist/diagnostics.js +209 -0
  78. package/dist/disclosure-CbLtajUQ.js +1 -0
  79. package/dist/dropdown-BwhViJFd.js +1 -0
  80. package/dist/elements/agent-card.js +1 -1
  81. package/dist/elements/artifact.js +1 -1
  82. package/dist/elements/attachments.js +1 -1
  83. package/dist/elements/audio-visualizer.js +1 -1
  84. package/dist/elements/autoloader.js +1 -1
  85. package/dist/elements/avatar.js +1 -1
  86. package/dist/elements/badge.js +1 -1
  87. package/dist/elements/button.js +1 -1
  88. package/dist/elements/card.js +1 -1
  89. package/dist/elements/cards.js +1 -1
  90. package/dist/elements/chain-of-thought.js +1 -1
  91. package/dist/elements/chat-scope-picker.js +1 -1
  92. package/dist/elements/chat-workspace.js +1 -1
  93. package/dist/elements/chat.js +1 -1
  94. package/dist/elements/checkbox-group.d.ts +1 -0
  95. package/dist/elements/checkbox-group.js +1 -0
  96. package/dist/elements/checkbox.d.ts +1 -0
  97. package/dist/elements/checkbox.js +1 -0
  98. package/dist/elements/checkpoint.js +1 -1
  99. package/dist/elements/choice.js +1 -1
  100. package/dist/elements/coachmark.js +1 -1
  101. package/dist/elements/code-block.js +1 -1
  102. package/dist/elements/command.js +1 -1
  103. package/dist/elements/compare.js +1 -1
  104. package/dist/elements/composer.js +1 -1
  105. package/dist/elements/confirm-card.js +1 -1
  106. package/dist/elements/context-meter.js +1 -1
  107. package/dist/elements/conversation-item.d.ts +1 -0
  108. package/dist/elements/conversation-item.js +1 -0
  109. package/dist/elements/conversation-list.js +1 -1
  110. package/dist/elements/default-input.d.ts +3 -3
  111. package/dist/elements/define-entry.d.ts +12 -0
  112. package/dist/elements/define.d.ts +27 -0
  113. package/dist/elements/diagnostic-events.d.ts +74 -0
  114. package/dist/elements/dialog.js +1 -1
  115. package/dist/elements/dock.d.ts +1 -0
  116. package/dist/elements/dock.js +243 -0
  117. package/dist/elements/dropdown.d.ts +1 -0
  118. package/dist/elements/dropdown.js +1 -0
  119. package/dist/elements/editable-label.js +1 -1
  120. package/dist/elements/element-data-types.d.ts +37 -0
  121. package/dist/elements/element-diagnostics.d.ts +81 -0
  122. package/dist/elements/embed.js +1 -1
  123. package/dist/elements/empty.js +1 -1
  124. package/dist/elements/feedback-bar.js +1 -1
  125. package/dist/elements/file-tree.js +1 -1
  126. package/dist/elements/file-upload.js +1 -1
  127. package/dist/elements/form.js +1 -1
  128. package/dist/elements/hover-card.js +1 -1
  129. package/dist/elements/icon.js +1 -1
  130. package/dist/elements/image.js +1 -1
  131. package/dist/elements/input.js +1 -1
  132. package/dist/elements/kbd.js +1 -1
  133. package/dist/elements/link-preview.js +1 -1
  134. package/dist/elements/loader.js +1 -1
  135. package/dist/elements/markdown.js +1 -1
  136. package/dist/elements/menu.js +1 -1
  137. package/dist/elements/message-skills.js +1 -1
  138. package/dist/elements/message.js +1 -1
  139. package/dist/elements/model-switcher.js +1 -1
  140. package/dist/elements/nav.js +1 -1
  141. package/dist/elements/notice.js +1 -1
  142. package/dist/elements/pane-grid.d.ts +1 -0
  143. package/dist/elements/pane-grid.js +1 -0
  144. package/dist/elements/pane-group.js +1 -1
  145. package/dist/elements/pane.js +1 -1
  146. package/dist/elements/popover.js +1 -1
  147. package/dist/elements/progress-bar.js +1 -1
  148. package/dist/elements/prompt-dock.js +1 -1
  149. package/dist/elements/prompt-input.js +1 -1
  150. package/dist/elements/prompt-suggestions.js +1 -1
  151. package/dist/elements/radio-group.d.ts +1 -0
  152. package/dist/elements/radio-group.js +1 -0
  153. package/dist/elements/reasoning.js +1 -1
  154. package/dist/elements/register.d.ts +2 -0
  155. package/dist/elements/remote.js +1 -1
  156. package/dist/elements/resizable.js +1 -1
  157. package/dist/elements/response-stream.js +3 -3
  158. package/dist/elements/screen.js +1 -1
  159. package/dist/elements/scroll-area.js +1 -1
  160. package/dist/elements/scroll-button.js +1 -1
  161. package/dist/elements/search.js +1 -1
  162. package/dist/elements/segmented.js +1 -1
  163. package/dist/elements/select.d.ts +1 -0
  164. package/dist/elements/select.js +1 -0
  165. package/dist/elements/separator.js +1 -1
  166. package/dist/elements/setting-item.js +1 -1
  167. package/dist/elements/settings-group.js +1 -1
  168. package/dist/elements/skeleton.js +1 -1
  169. package/dist/elements/slider.d.ts +1 -0
  170. package/dist/elements/slider.js +1 -0
  171. package/dist/elements/slots.d.ts +36 -4
  172. package/dist/elements/source.js +1 -1
  173. package/dist/elements/status.js +1 -1
  174. package/dist/elements/switch.js +1 -1
  175. package/dist/elements/tabs.js +1 -1
  176. package/dist/elements/tasks.js +1 -1
  177. package/dist/elements/text-shimmer.js +1 -1
  178. package/dist/elements/thinking-bar.js +1 -1
  179. package/dist/elements/thread.js +1 -1
  180. package/dist/elements/toast.js +1 -1
  181. package/dist/elements/tool.js +1 -1
  182. package/dist/elements/tooltip.js +1 -1
  183. package/dist/elements/voice-input.js +1 -1
  184. package/dist/elements/voice-output.js +1 -1
  185. package/dist/elements.d.ts +589 -167
  186. package/dist/{elements/chunks/ellipsis-CVxqfsDZ.js → ellipsis-DFr4Vqr3.js} +1 -1
  187. package/dist/embed-5s_vU4J0.js +1 -0
  188. package/dist/engine-javascript-vq0WuIJl.js +14 -2516
  189. package/dist/{elements/chunks/external-link-DG2sRdQL.js → external-link-u9d85ORQ.js} +1 -1
  190. package/dist/file-text-CX7_x42o.js +1 -0
  191. package/dist/{elements/chunks/file-tree-yGWNK0Js.js → file-tree-D3kBjXI5.js} +1 -1
  192. package/dist/folder-V-YdIL8f.js +1 -0
  193. package/dist/form-BRNUMCN2.js +1 -0
  194. package/dist/github-dark-dimmed-DUshB20C.js +1 -4
  195. package/dist/github-light-JYsPkUQd.js +1 -4
  196. package/dist/hover-card-DaeiYrTA.js +1 -0
  197. package/dist/html-CPZ3oZQ7.js +1 -10
  198. package/dist/icon-BpixdZNq.js +1 -0
  199. package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
  200. package/dist/index.d.ts +3 -1
  201. package/dist/index.js +8473 -6470
  202. package/dist/index.server.js +6495 -4958
  203. package/dist/info-8mFsIjS3.js +1 -0
  204. package/dist/input-d1Yuu-hz.js +1 -0
  205. package/dist/javascript-C25yR2R2.js +1 -6
  206. package/dist/json-DxJze_jm.js +1 -6
  207. package/dist/kai-provider.es.js +40 -40
  208. package/dist/kai.es.js +1 -1
  209. package/dist/kbd-961zMPFB.js +1 -0
  210. package/dist/link-DlZZBGaR.js +1 -0
  211. package/dist/{elements/chunks/link-preview-Cf5KOP-i.js → link-preview-DIIbV2Sd.js} +1 -1
  212. package/dist/loader-YQszHFaW.js +1 -0
  213. package/dist/{elements/chunks/markdown-DbozyYqa.js → markdown-CVk1MPsj.js} +1 -1
  214. package/dist/mcp.es.js +3873 -544
  215. package/dist/message-CwKVEdZg.js +1 -0
  216. package/dist/message-DS8lzHc1.js +1 -0
  217. package/dist/message-circle-Xf8Q-vZp.js +1 -0
  218. package/dist/message-square-Cxnwgkns.js +1 -0
  219. package/dist/{elements/chunks/minimize-2-SegJ_oku.js → minimize-2-UEZmP2QT.js} +1 -1
  220. package/dist/{elements/chunks/model-switcher-D7JrFFHp.js → model-switcher-Kk1jEQ5t.js} +1 -1
  221. package/dist/{elements/chunks/overlay-CV7z2YuX.js → overlay-C1od6LOz.js} +1 -1
  222. package/dist/panel-right-ryET0yyn.js +1 -0
  223. package/dist/paperclip-BDNoZFJP.js +1 -0
  224. package/dist/play-OFIvYXUQ.js +1 -0
  225. package/dist/primitives/card-data-types.d.ts +49 -0
  226. package/dist/primitives/card-routing.d.ts +1 -33
  227. package/dist/primitives/card-validate.d.ts +2 -2
  228. package/dist/primitives/chat-config.d.ts +29 -2
  229. package/dist/primitives/field-mask.d.ts +96 -0
  230. package/dist/primitives/field-semantics.d.ts +36 -0
  231. package/dist/primitives/input-mask.d.ts +46 -0
  232. package/dist/primitives/url-scheme-policy.d.ts +34 -0
  233. package/dist/primitives/use-resize-observer.d.ts +23 -0
  234. package/dist/primitives/use-speech-recognition.d.ts +8 -0
  235. package/dist/primitives/use-text-stream.d.ts +5 -0
  236. package/dist/progress-bar-BvYX0aoy.js +1 -0
  237. package/dist/prompt-suggestion-BRFu2lcu.js +1 -0
  238. package/dist/radio-DcL23cNJ.js +1 -0
  239. package/dist/react/index.d.ts +306 -283
  240. package/dist/react.js +309 -247
  241. package/dist/reasoning-Cackq4Rh.js +1 -0
  242. package/dist/register-impl-C7rENvPK.js +424 -0
  243. package/dist/{elements/chunks/resizable-Dpzjlvp4.js → resizable-Cp9HUYih.js} +1 -1
  244. package/dist/rotate-ccw-0DLRDHH5.js +1 -0
  245. package/dist/rotate-cw-DOB9IGcU.js +1 -0
  246. package/dist/schemas/form.schema.json +21 -1
  247. package/dist/schemas/index.d.ts +1 -1
  248. package/dist/schemas/tool-defs.d.ts +45 -0
  249. package/dist/schemas.js +398 -305
  250. package/dist/scroll-area-emVmWP4K.js +1 -0
  251. package/dist/scroll-button-CeP_gv1x.js +1 -0
  252. package/dist/select-CWmu00tS.js +1 -0
  253. package/dist/{elements/chunks/separator-DH2r_ZSZ.js → separator-CE6vly6z.js} +1 -1
  254. package/dist/{elements/chunks/settings-BFMOd6yB.js → settings-CE-78SvZ.js} +1 -1
  255. package/dist/{elements/chunks/settings-group-B3VZKIcz.js → settings-group-ZFWNxFQR.js} +1 -1
  256. package/dist/{elements/chunks/skeleton-N8BuWYmf.js → skeleton-BebdP4mf.js} +1 -1
  257. package/dist/slider-BAKRYUlz.js +1 -0
  258. package/dist/slots-DaNjX0rc.js +1 -0
  259. package/dist/{solid-BMuDmFo_.js → solid-BE5ui6sy.js} +10672 -8116
  260. package/dist/{solid-CGYNdLRR.js → solid-DFhsce3O.js} +8137 -6056
  261. package/dist/solid.d.ts +15 -0
  262. package/dist/solid.js +248 -235
  263. package/dist/solid.server.js +248 -235
  264. package/dist/source-B0FlguSx.js +1 -0
  265. package/dist/star-CBMZvLuN.js +1 -0
  266. package/dist/state/index.d.ts +5 -1
  267. package/dist/state/mock.d.ts +32 -2
  268. package/dist/state/persistence.d.ts +51 -0
  269. package/dist/state/stream.d.ts +50 -0
  270. package/dist/state/threads.d.ts +71 -0
  271. package/dist/state.js +297 -172
  272. package/dist/store-7eoadydQ.js +1 -0
  273. package/dist/svelte--5p79yCD.js +1 -15
  274. package/dist/switch-CViARZCy.js +1 -0
  275. package/dist/tasks-card-MjCcOhR_.js +1 -0
  276. package/dist/text-shimmer-DKlwRF2G.js +1 -0
  277. package/dist/textarea-3ay2Me2-.js +1 -0
  278. package/dist/theme.tokens.css +82 -13
  279. package/dist/{elements/chunks/thumbs-up-DQe0hvkZ.js → thumbs-up-DQcu2HMO.js} +1 -1
  280. package/dist/toast-store-C6yKOhbk.js +1 -0
  281. package/dist/{elements/chunks/tool-C1YtxwPu.js → tool-BCYNlfKy.js} +1 -1
  282. package/dist/{elements/chunks/tooltip-BqwnFWhn.js → tooltip-05zI4hjs.js} +1 -1
  283. package/dist/trash-2-BR1RxGky.js +1 -0
  284. package/dist/{elements/chunks/triangle-alert-B6or7F5u.js → triangle-alert-DHohDOCy.js} +1 -1
  285. package/dist/tsx-B8rCNbgL.js +1 -6
  286. package/dist/types.d.ts +4 -2
  287. package/dist/typescript-RycA9KXf.js +1 -6
  288. package/dist/ui/checkbox-group.d.ts +83 -0
  289. package/dist/ui/checkbox.d.ts +40 -0
  290. package/dist/ui/dock.d.ts +131 -0
  291. package/dist/ui/hover-card.d.ts +44 -0
  292. package/dist/ui/icon.d.ts +3 -0
  293. package/dist/ui/input.d.ts +48 -2
  294. package/dist/ui/radio.d.ts +85 -0
  295. package/dist/ui/select.d.ts +71 -0
  296. package/dist/ui/slider.d.ts +65 -0
  297. package/dist/ui/switch.d.ts +9 -2
  298. package/dist/upload-BbGW6A_u.js +1 -0
  299. package/dist/url-scheme-policy-DHpoTJwB.js +1 -0
  300. package/dist/use-card-resolution-CJW4grFa.js +1 -0
  301. package/dist/{variant-aurora-DwSOfraQ.js → variant-aurora-BUOVgPOB.js} +27 -27
  302. package/dist/{variant-aurora-wKvAQ5wp.js → variant-aurora-CUsUJvFI.js} +28 -28
  303. package/dist/{variant-aurora-XEkPT0_z.js → variant-aurora-CW2i4bfr.js} +2 -2
  304. package/dist/{elements/chunks/variant-aurora-QXTZPyST.js → variant-aurora-xiMPty8f.js} +2 -2
  305. package/dist/variant-custom-BQtOnmeO.js +1 -0
  306. package/dist/{variant-custom-BhS9wIpU.js → variant-custom-CAm9L-E5.js} +65 -65
  307. package/dist/{variant-custom-eFIg2XWQ.js → variant-custom-CAnzzppW.js} +40 -40
  308. package/dist/variant-custom-D91HjAKz.js +1 -0
  309. package/dist/{variant-wave-CUWGx9Bn.js → variant-wave-Ca1Ls4_y.js} +21 -21
  310. package/dist/{variant-wave-CbVsmgwT.js → variant-wave-CxX39DKd.js} +25 -25
  311. package/dist/{variant-wave-BwzrHD1s.js → variant-wave-DYyzIIZv.js} +2 -2
  312. package/dist/{elements/chunks/variant-wave-DDCwhLas.js → variant-wave-uY5crU_K.js} +2 -2
  313. package/dist/vue-BmIZj4XD.js +1 -33
  314. package/dist/wire/chunk.d.ts +47 -0
  315. package/dist/wire/diagnostics.d.ts +575 -0
  316. package/dist/wire/encode-probe.d.ts +70 -0
  317. package/dist/wire/encode.d.ts +24 -0
  318. package/dist/wire/index.d.ts +2 -0
  319. package/dist/wire/sse.d.ts +10 -2
  320. package/dist/wire.js +917 -480
  321. package/dist/x-C5m1JFgi.js +1 -0
  322. package/frameworks/react/index.tsx +325 -108
  323. package/llms-full.txt +1354 -82
  324. package/llms.txt +6 -3
  325. package/package.json +39 -6
  326. package/src/agent-tooling/archetypes.ts +41 -9
  327. package/src/agent-tooling/catalog/README.md +676 -0
  328. package/src/agent-tooling/catalog/catalog-types.ts +231 -0
  329. package/src/agent-tooling/catalog/fabrications.ts +96 -0
  330. package/src/agent-tooling/catalog/invariants.ts +284 -0
  331. package/src/agent-tooling/catalog/labs-titles.ts +114 -0
  332. package/src/agent-tooling/catalog/scenarios.ts +87 -0
  333. package/src/agent-tooling/catalog/surfaces.ts +347 -0
  334. package/src/agent-tooling/construct/cli-entry.ts +8 -0
  335. package/src/agent-tooling/construct/cli.ts +131 -0
  336. package/src/agent-tooling/construct/codegen.ts +1353 -0
  337. package/src/agent-tooling/construct/construct.v1.schema.json +250 -0
  338. package/src/agent-tooling/construct/dev.ts +148 -0
  339. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
  340. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
  341. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +23 -0
  342. package/src/agent-tooling/construct/schema.ts +371 -0
  343. package/src/agent-tooling/integrations/anthropic.ts +7 -1
  344. package/src/agent-tooling/integrations/cloudflare.ts +43 -2
  345. package/src/agent-tooling/integrations/langgraph.ts +7 -1
  346. package/src/agent-tooling/integrations/mastra.ts +7 -1
  347. package/src/agent-tooling/integrations/mock.ts +92 -17
  348. package/src/agent-tooling/integrations/ollama.ts +7 -1
  349. package/src/agent-tooling/integrations/openai.ts +7 -1
  350. package/src/agent-tooling/integrations/openrouter.ts +7 -1
  351. package/src/agent-tooling/integrations/pi.ts +56 -1
  352. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +7 -1
  353. package/src/agent-tooling/mcp/css-raw.d.ts +12 -0
  354. package/src/agent-tooling/mcp/manifest.ts +100 -1
  355. package/src/agent-tooling/mcp/server.ts +63 -6
  356. package/src/agent-tooling/mcp/tools/construct.ts +130 -0
  357. package/src/agent-tooling/mcp/tools/debug.ts +126 -4
  358. package/src/agent-tooling/mcp/tools/reference.ts +542 -5
  359. package/src/agent-tooling/mcp/tools/scaffold.ts +1834 -307
  360. package/src/agent-tooling/mcp/tools/theme.ts +146 -30
  361. package/src/agent-tooling/mcp/validate-args.ts +141 -0
  362. package/src/agent-tooling/recipes/composed-thread.ts +714 -0
  363. package/src/agent-tooling/recipes/index.ts +22 -0
  364. package/src/agent-tooling/recipes/types.ts +32 -0
  365. package/src/agent-tooling/registry.ts +24 -7
  366. package/src/agent-tooling/route-emit.ts +26 -2
  367. package/src/components/attachment-types.ts +54 -1
  368. package/src/components/attachments.tsx +169 -22
  369. package/src/components/audio-visualizer/fit-scale.ts +112 -0
  370. package/src/components/audio-visualizer/index.tsx +80 -3
  371. package/src/components/audio-visualizer/variant-aurora.tsx +10 -4
  372. package/src/components/audio-visualizer/variant-bar.tsx +38 -6
  373. package/src/components/audio-visualizer/variant-custom.tsx +8 -2
  374. package/src/components/audio-visualizer/variant-grid.tsx +16 -11
  375. package/src/components/audio-visualizer/variant-radial.tsx +15 -10
  376. package/src/components/audio-visualizer/variant-wave.tsx +7 -2
  377. package/src/components/card-renderer.tsx +39 -8
  378. package/src/components/card.tsx +10 -2
  379. package/src/components/chat-container.tsx +4 -1
  380. package/src/components/chat-scope-picker.tsx +2 -2
  381. package/src/components/chat-thread.tsx +105 -13
  382. package/src/components/choice-card.tsx +102 -37
  383. package/src/components/coachmark.tsx +1 -1
  384. package/src/components/code-block.tsx +81 -5
  385. package/src/components/composer.tsx +89 -8
  386. package/src/components/confirm-card.tsx +20 -4
  387. package/src/components/conversation-item.tsx +138 -4
  388. package/src/components/conversation-list.tsx +230 -15
  389. package/src/components/embed.tsx +4 -0
  390. package/src/components/empty.tsx +14 -3
  391. package/src/components/file-tree.tsx +5 -1
  392. package/src/components/form-widgets.tsx +257 -195
  393. package/src/components/form.tsx +336 -21
  394. package/src/components/loader.tsx +12 -5
  395. package/src/components/message-skills.tsx +1 -1
  396. package/src/components/message.tsx +142 -12
  397. package/src/components/prompt-input.tsx +7 -1
  398. package/src/components/prompt-suggestion.tsx +4 -1
  399. package/src/components/reasoning.tsx +30 -3
  400. package/src/components/response-compare.tsx +2 -2
  401. package/src/components/response-stream.tsx +13 -7
  402. package/src/components/screen.tsx +5 -0
  403. package/src/components/scroll-button.tsx +63 -4
  404. package/src/components/source.tsx +6 -1
  405. package/src/components/tasks-card.tsx +58 -16
  406. package/src/components/thread.tsx +10 -1
  407. package/src/components/toast.tsx +11 -5
  408. package/src/components/tool-types.ts +9 -0
  409. package/src/components/voice-input.tsx +35 -3
  410. package/src/components/voice-output.tsx +46 -6
  411. package/src/components/workspace-shell.tsx +285 -0
  412. package/src/diagnostics/hook.ts +352 -0
  413. package/src/diagnostics/index.ts +82 -0
  414. package/src/diagnostics/report-request.ts +296 -0
  415. package/src/elements/attachments.tsx +9 -8
  416. package/src/elements/audio-visualizer.tsx +48 -4
  417. package/src/elements/chat-workspace.tsx +159 -287
  418. package/src/elements/chat.tsx +31 -10
  419. package/src/elements/checkbox-group.tsx +164 -0
  420. package/src/elements/checkbox.tsx +134 -0
  421. package/src/elements/code-block.tsx +19 -1
  422. package/src/elements/command.tsx +4 -1
  423. package/src/elements/compiled.css +1 -1
  424. package/src/elements/composer.tsx +12 -1
  425. package/src/elements/conversation-item.tsx +120 -0
  426. package/src/elements/conversation-list.tsx +60 -11
  427. package/src/elements/default-input.tsx +5 -5
  428. package/src/elements/define-entry.ts +12 -0
  429. package/src/elements/define.tsx +168 -8
  430. package/src/elements/diagnostic-events.ts +114 -0
  431. package/src/elements/dialog.tsx +47 -0
  432. package/src/elements/disclosure.ts +34 -12
  433. package/src/elements/dock.tsx +215 -0
  434. package/src/elements/dropdown.tsx +123 -0
  435. package/src/elements/element-data-types.ts +40 -0
  436. package/src/elements/element-diagnostics.ts +392 -0
  437. package/src/elements/element-manifest.json +36 -0
  438. package/src/elements/element-meta.json +1483 -560
  439. package/src/elements/element-nonscalar.json +185 -0
  440. package/src/elements/element-types.d.ts +589 -167
  441. package/src/elements/feedback-bar.tsx +5 -0
  442. package/src/elements/icon-names.json +29 -0
  443. package/src/elements/input.tsx +312 -23
  444. package/src/elements/menu.tsx +13 -0
  445. package/src/elements/message.tsx +2 -0
  446. package/src/elements/pane-grid.tsx +111 -0
  447. package/src/elements/prompt-dock.tsx +2 -1
  448. package/src/elements/prompt-input.tsx +16 -10
  449. package/src/elements/radio-group.tsx +129 -0
  450. package/src/elements/register-impl.ts +52 -0
  451. package/src/elements/register.ts +28 -0
  452. package/src/elements/resizable.tsx +52 -25
  453. package/src/elements/scroll-button.tsx +59 -6
  454. package/src/elements/select.tsx +165 -0
  455. package/src/elements/slider.tsx +171 -0
  456. package/src/elements/slots.ts +108 -13
  457. package/src/elements/styles.css +119 -9
  458. package/src/elements/thinking-bar.tsx +16 -7
  459. package/src/elements/thread.tsx +2 -0
  460. package/src/elements/toast.tsx +17 -1
  461. package/src/elements/tool.tsx +26 -5
  462. package/src/elements/voice-input.tsx +11 -2
  463. package/src/elements/voice-output.tsx +16 -3
  464. package/src/index.ts +4 -1
  465. package/src/primitives/card-data-types.ts +49 -0
  466. package/src/primitives/card-host.tsx +4 -2
  467. package/src/primitives/card-routing.ts +7 -56
  468. package/src/primitives/card-schemas/form.schema.json +21 -1
  469. package/src/primitives/card-validate.ts +10 -2
  470. package/src/primitives/chat-config.tsx +33 -6
  471. package/src/primitives/field-mask.ts +256 -0
  472. package/src/primitives/field-semantics.ts +115 -0
  473. package/src/primitives/input-mask.ts +853 -0
  474. package/src/primitives/toast-store.ts +66 -4
  475. package/src/primitives/url-scheme-policy.ts +70 -0
  476. package/src/primitives/use-resize-observer.ts +33 -0
  477. package/src/primitives/use-speech-recognition.ts +12 -1
  478. package/src/primitives/use-stick-to-bottom.ts +34 -2
  479. package/src/primitives/use-text-stream.ts +33 -2
  480. package/src/remote/provider-runtime.ts +6 -3
  481. package/src/schemas/index.ts +1 -0
  482. package/src/schemas/tool-defs.ts +307 -6
  483. package/src/solid.ts +15 -0
  484. package/src/state/index.ts +13 -1
  485. package/src/state/mock.ts +92 -6
  486. package/src/state/persistence.ts +180 -0
  487. package/src/state/stream.ts +71 -4
  488. package/src/state/threads.ts +142 -0
  489. package/src/types.ts +4 -2
  490. package/src/ui/agent-card.tsx +2 -2
  491. package/src/ui/avatar.tsx +1 -1
  492. package/src/ui/checkbox-group.tsx +153 -0
  493. package/src/ui/checkbox.tsx +63 -0
  494. package/src/ui/dialog.tsx +6 -0
  495. package/src/ui/dock.tsx +584 -0
  496. package/src/ui/dropdown.tsx +67 -23
  497. package/src/ui/hover-card.tsx +156 -6
  498. package/src/ui/icon.tsx +53 -0
  499. package/src/ui/input.tsx +275 -16
  500. package/src/ui/kbd.tsx +1 -1
  501. package/src/ui/nav.tsx +1 -1
  502. package/src/ui/pane-group.tsx +2 -2
  503. package/src/ui/radio.tsx +150 -0
  504. package/src/ui/resizable.tsx +11 -0
  505. package/src/ui/select.tsx +168 -0
  506. package/src/ui/slider.tsx +178 -0
  507. package/src/ui/switch.tsx +49 -18
  508. package/src/utils/cn.ts +11 -5
  509. package/src/wire/chunk.ts +47 -0
  510. package/src/wire/consume.ts +185 -26
  511. package/src/wire/diagnostics.ts +727 -0
  512. package/src/wire/encode-probe.ts +214 -0
  513. package/src/wire/encode.ts +267 -14
  514. package/src/wire/formats/anthropic.ts +8 -1
  515. package/src/wire/formats/openai.ts +5 -0
  516. package/src/wire/index.ts +22 -0
  517. package/src/wire/read.ts +250 -6
  518. package/src/wire/sse.ts +16 -3
  519. package/theme.css +84 -13
  520. package/dist/elements/chunks/action-icons-DW9muWrY.js +0 -1
  521. package/dist/elements/chunks/arrow-left-iJVnQmxA.js +0 -1
  522. package/dist/elements/chunks/artifact-BSuPYFHY.js +0 -1
  523. package/dist/elements/chunks/attachments-CL6TaqIb.js +0 -1
  524. package/dist/elements/chunks/audio-visualizer-BuUqQmaO.js +0 -1
  525. package/dist/elements/chunks/badge-TIMiJFKc.js +0 -1
  526. package/dist/elements/chunks/bash-InADTalH.js +0 -1
  527. package/dist/elements/chunks/card-renderer-CSoTL_e1.js +0 -1
  528. package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
  529. package/dist/elements/chunks/chat-thread-DxoKaStk.js +0 -1
  530. package/dist/elements/chunks/check-MdLzbxrm.js +0 -1
  531. package/dist/elements/chunks/chevron-down-MK7IzDqe.js +0 -1
  532. package/dist/elements/chunks/chevron-right-C5jXhmtV.js +0 -1
  533. package/dist/elements/chunks/choice-card-CGMc3kek.js +0 -1
  534. package/dist/elements/chunks/circle-BG7VkPep.js +0 -1
  535. package/dist/elements/chunks/circle-check-GqvO2UBs.js +0 -1
  536. package/dist/elements/chunks/circle-x-mhH7pOK2.js +0 -1
  537. package/dist/elements/chunks/code-block-ClhQO9RW.js +0 -1
  538. package/dist/elements/chunks/collapsible-DBcBkFPh.js +0 -1
  539. package/dist/elements/chunks/composer-CZZmtYOT.js +0 -69
  540. package/dist/elements/chunks/confirm-card-BWjf2-xo.js +0 -1
  541. package/dist/elements/chunks/context-hKjNqiyQ.js +0 -1
  542. package/dist/elements/chunks/conversation-list-CsGJjSKG.js +0 -1
  543. package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
  544. package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
  545. package/dist/elements/chunks/default-input-B1Mem5wu.js +0 -1
  546. package/dist/elements/chunks/define-B_tXMYRm.js +0 -1
  547. package/dist/elements/chunks/disclosure-DAoYOKew.js +0 -1
  548. package/dist/elements/chunks/download-DnCyWFJE.js +0 -1
  549. package/dist/elements/chunks/dropdown-CmNna5lT.js +0 -1
  550. package/dist/elements/chunks/embed-CjAD2jSi.js +0 -1
  551. package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
  552. package/dist/elements/chunks/file-text-D0J9F6M7.js +0 -1
  553. package/dist/elements/chunks/folder-NV1pi_ud.js +0 -1
  554. package/dist/elements/chunks/form-Cp8Y00Wn.js +0 -1
  555. package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
  556. package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
  557. package/dist/elements/chunks/hover-card-6KtXpLwT.js +0 -1
  558. package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
  559. package/dist/elements/chunks/icon-97R8SR2p.js +0 -1
  560. package/dist/elements/chunks/info-C8r5Q6cc.js +0 -1
  561. package/dist/elements/chunks/input-DrseEjhp.js +0 -1
  562. package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
  563. package/dist/elements/chunks/json-DxJze_jm.js +0 -1
  564. package/dist/elements/chunks/kbd-OGJDUT-O.js +0 -1
  565. package/dist/elements/chunks/link-BdsfLB7b.js +0 -1
  566. package/dist/elements/chunks/loader-B5QzK_8_.js +0 -1
  567. package/dist/elements/chunks/message-CE4k-qaj.js +0 -1
  568. package/dist/elements/chunks/message-DtXKPqiR.js +0 -1
  569. package/dist/elements/chunks/message-square-C9ovmtOo.js +0 -1
  570. package/dist/elements/chunks/paperclip-Bg0ITU3b.js +0 -1
  571. package/dist/elements/chunks/progress-bar-D1_rzt6N.js +0 -1
  572. package/dist/elements/chunks/prompt-suggestion-D5Sm8xF1.js +0 -1
  573. package/dist/elements/chunks/reasoning-BrxQfpfI.js +0 -1
  574. package/dist/elements/chunks/rotate-cw-DzVDJOA1.js +0 -1
  575. package/dist/elements/chunks/scroll-area-93A1bbeG.js +0 -1
  576. package/dist/elements/chunks/scroll-button-CrTo7wm4.js +0 -1
  577. package/dist/elements/chunks/share-DgNbkJKY.js +0 -1
  578. package/dist/elements/chunks/slots-CIw9RlAe.js +0 -1
  579. package/dist/elements/chunks/source-w9V0NnBn.js +0 -1
  580. package/dist/elements/chunks/star-DHvACxtm.js +0 -1
  581. package/dist/elements/chunks/store-HIPGhNz9.js +0 -1
  582. package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
  583. package/dist/elements/chunks/tasks-card-lPxoodlA.js +0 -1
  584. package/dist/elements/chunks/text-shimmer-BY_rI3s5.js +0 -1
  585. package/dist/elements/chunks/textarea-DPfuhswM.js +0 -1
  586. package/dist/elements/chunks/toast-store-VUZZBhzH.js +0 -1
  587. package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
  588. package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
  589. package/dist/elements/chunks/use-card-resolution-DJg32jGH.js +0 -1
  590. package/dist/elements/chunks/variant-custom-D5ZlmziF.js +0 -1
  591. package/dist/elements/chunks/video-Bb86fVYI.js +0 -1
  592. package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
  593. package/dist/elements/chunks/x-BOhjBeOd.js +0 -1
  594. package/dist/llms/llms-full.txt +0 -2834
  595. package/dist/llms/llms.txt +0 -156
  596. package/dist/primitives/card-validate-generator.testlib.d.ts +0 -20
  597. package/dist/register-impl-DGmGzrEM.js +0 -145
  598. package/dist/ui/stat.d.ts +0 -16
  599. package/dist/variant-custom-MkTNTycd.js +0 -1
  600. package/src/primitives/card-validate-generator.testlib.ts +0 -38
  601. package/src/ui/stat.tsx +0 -41
  602. /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
  603. /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
@@ -54,7 +54,10 @@ interface Props extends Record<string, unknown> {
54
54
 
55
55
  /** Events fired by `<kai-composer>`. */
56
56
  interface Events {
57
- /** The user submitted the composer (Enter or programmatic submit). */
57
+ /** The user submitted the composer (Enter or programmatic submit). Note the
58
+ * detail carries no `attachments`; `<kai-composer>` is the bare editing
59
+ * surface: no send button, toolbar, or attachments. For a drop-in composer
60
+ * row with all three, reach for `<kai-prompt-input>`, which is built on this. */
58
61
  'kai-submit': { doc: ComposerDoc; text: string; entities: EntityRef[] };
59
62
  /** The content changed (fires on every input event). */
60
63
  'kai-value-change': { doc: ComposerDoc; text: string; entities: EntityRef[] };
@@ -75,6 +78,14 @@ interface Events {
75
78
  'kai-blur': { originalEvent: FocusEvent };
76
79
  }
77
80
 
81
+ /**
82
+ * `<kai-composer>` — the bare editing surface: rich text, entity pills,
83
+ * trigger menus, Enter-to-submit, and nothing else. No send button, no
84
+ * toolbar, no attachments — that division is deliberate. For a drop-in chat
85
+ * composer with a send button, toolbar, and attachment staging, reach for
86
+ * `<kai-prompt-input>`, which is built on this element. Keep `<kai-composer>`
87
+ * when you are composing the input row yourself and want to own those pieces.
88
+ */
78
89
  defineWebComponent<Props, Events>('kai-composer', {
79
90
  value: undefined,
80
91
  placeholder: undefined,
@@ -0,0 +1,120 @@
1
+ import { createSignal, onCleanup, onMount } from 'solid-js';
2
+ import { defineWebComponent } from './define';
3
+ import { readSlots, CONVERSATION_ITEM_SLOTS } from './slots';
4
+ import { SlottedConversationItem } from '../components/conversation-item';
5
+ import { isStandaloneConversationItem, readConversationItemId } from '../components/conversation-list';
6
+
7
+ interface Props extends Record<string, unknown> {
8
+ /** The row's identity: the `conversation-id` attribute (host `id` is the
9
+ * fallback). Inside `<kai-conversations>` it is handed to the container's
10
+ * selection contract (`kai-conversation-select`); standalone it is the `id`
11
+ * in this element's own `kai-select` detail. */
12
+ conversationId?: string;
13
+ /** Selected state. Reflected as `aria-current` on the row body and a
14
+ * `data-active` styling hook on the row; inside a container the container
15
+ * drives it from its `activeId`, standalone you set it yourself. */
16
+ active?: boolean;
17
+ /** Dense single-line row padding. */
18
+ compact?: boolean;
19
+ }
20
+
21
+ interface Events {
22
+ /** STANDALONE activation only: the row was activated (click, Enter or Space on its body) while the item is NOT a
23
+ * direct child of `<kai-conversations>`. `id` is the row's identity: the
24
+ * `conversation-id` attribute, else the host `id`. Inside a container this
25
+ * never fires: activation surfaces once, as `kai-conversation-select` on the
26
+ * container. */
27
+ 'kai-select': { id: string };
28
+ }
29
+
30
+ /**
31
+ * `<kai-conversation-item>` — one composed row of a consumer-owned conversation
32
+ * loop. Two placements, one activation event each:
33
+ *
34
+ * SLOTTED into `<kai-conversations>`' light DOM (a direct child): the consumer
35
+ * owns the loop (framework-native `map`, `<For>`, `v-for`); the container
36
+ * detects these children, skips its data rendering, and runs the parent-item
37
+ * contract over them — selection state flowing container to item, roving
38
+ * tabindex, arrow-key traversal, and the accessible list/row relationship
39
+ * (list rows with button bodies and `aria-current` marking the active one;
40
+ * axe's nested-interactive and aria-required-children
41
+ * rules are why this is not listbox/option). Activation (click, Enter, Space)
42
+ * surfaces as `kai-conversation-select` on the container, and the item itself
43
+ * fires nothing — no double event.
44
+ *
45
+ * STANDALONE (anywhere else — a hand-composed rail, or wrapped in another
46
+ * element even inside a container, since the container manages only direct
47
+ * children): the row activates ITSELF.
48
+ * Its shadow body is a tabbable `role="button"`, and click / Enter / Space
49
+ * fire `kai-select` on this element with `{ id }` — non-bubbling, like every
50
+ * `kai-*` event, so listen on the item itself. What a standalone row does NOT
51
+ * have is the container's LIST story: roving tabindex across rows, arrow-key
52
+ * traversal, and the shared `role="list"` relationship — each standalone row
53
+ * is an ordinary tab stop, and a hand-composed rail brings its own list
54
+ * semantics (or slots the rows into `<kai-conversations>` and gets them for
55
+ * free).
56
+ *
57
+ * Slots: the default slot is the title; `leading`, `meta` and `menu` are the
58
+ * named regions. The `menu` slot takes your OWN popover (rename, fork, archive
59
+ * live there); the element provides only the region plus focus and ARIA
60
+ * plumbing, never a declarative actions prop, and a click inside it never
61
+ * selects the row — in either placement.
62
+ */
63
+ defineWebComponent<Props, Events>('kai-conversation-item', {
64
+ conversationId: undefined,
65
+ active: undefined,
66
+ compact: undefined,
67
+ }, (props, { element, flag, reflectFlag, dispatch }) => {
68
+ // Which named regions the consumer has filled; drives the conditional
69
+ // wrappers so an empty region leaves no stray box behind.
70
+ const [slots, setSlots] = createSignal<Record<string, boolean>>({});
71
+ // Standalone vs container-managed, decided at mount (an item is not
72
+ // reparented in practice; the activation handler re-checks at event time so
73
+ // a row moved INTO a container can never double-fire).
74
+ const [standalone, setStandalone] = createSignal(false);
75
+ onMount(() => {
76
+ const read = () => setSlots(readSlots(element, CONVERSATION_ITEM_SLOTS));
77
+ read();
78
+ const observer = new MutationObserver(read);
79
+ observer.observe(element, { childList: true, attributes: true, subtree: true });
80
+ onCleanup(() => observer.disconnect());
81
+
82
+ // The HOST is the row LISTITEM:
83
+ // it wraps the activation body AND the consumer's tabbable menu, so it must
84
+ // never be the activation control itself — axe nested-interactive bans
85
+ // focusable descendants of a control. The button role, aria-current and the
86
+ // tabindex live on the shadow BODY (`data-kai-item-body`): inside a
87
+ // container its controller stamps them; standalone the component renders
88
+ // them itself. An authored role wins.
89
+ if (!element.hasAttribute('role')) element.setAttribute('role', 'listitem');
90
+
91
+ setStandalone(isStandaloneConversationItem(element));
92
+ });
93
+
94
+ // Standalone activation → the per-item `kai-select` event. The re-check at
95
+ // event time keeps this dead the moment the item becomes a container's direct
96
+ // child, so the container's `kai-conversation-select` stays the only event.
97
+ const activate = () => {
98
+ if (!isStandaloneConversationItem(element)) return;
99
+ dispatch('kai-select', { id: readConversationItemId(element) });
100
+ };
101
+
102
+ // Property and attribute stay in agreement for `active`; the body's
103
+ // aria-current follows it reactively (nothing is written to the host).
104
+ reflectFlag('active');
105
+
106
+ return (
107
+ <SlottedConversationItem
108
+ conversationId={props.conversationId as string | undefined}
109
+ active={flag('active')}
110
+ compact={flag('compact')}
111
+ hostSemantics
112
+ onActivate={standalone() ? activate : undefined}
113
+ leading={slots().leading ? <slot name="leading" /> : undefined}
114
+ meta={slots().meta ? <slot name="meta" /> : undefined}
115
+ menu={slots().menu ? <slot name="menu" /> : undefined}
116
+ >
117
+ <slot />
118
+ </SlottedConversationItem>
119
+ );
120
+ });
@@ -1,9 +1,12 @@
1
- import { createSignal, onMount, onCleanup, Show } from 'solid-js';
1
+ import { createSignal, createEffect, onMount, onCleanup, Show } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { createControllableSignal } from '../primitives/controllable';
4
4
  import { readSlots, CONVERSATIONS_SLOTS } from './slots';
5
- import { ConversationList, CollapsedRail, type ConversationListController } from '../components/conversation-list';
6
- import type { ConversationGroup, ConversationSummary, ConversationScope } from '../types';
5
+ import {
6
+ ConversationList, CollapsedRail, createConversationItemsController,
7
+ type ConversationListController,
8
+ } from '../components/conversation-list';
9
+ import type { ConversationGroup, ConversationSummary } from '../types';
7
10
 
8
11
  interface Props extends Record<string, unknown> {
9
12
  /** The list's section headers (`{ id, name, sortOrder, createdAt }`), rendered
@@ -16,7 +19,11 @@ interface Props extends Record<string, unknown> {
16
19
  * matching no entry in `groups`, falls into a trailing "Ungrouped" section, so
17
20
  * nothing you pass in is ever dropped. There is no recency bucketing. Set as a
18
21
  * JS property. Omit to supply them as `<kai-conversation>` light-DOM children
19
- * instead, or for the empty state. */
22
+ * instead, or for the empty state. A search query that matches nothing shows a
23
+ * visible "No conversations match your search" state, distinct from the
24
+ * zero-conversations empty state. Slotted `<kai-conversation-item>` children
25
+ * switch the list into item mode instead: your own rows win and this array is
26
+ * not rendered. */
20
27
  conversations?: ConversationSummary[];
21
28
  /** The id of the currently-open conversation, highlighted in the list. */
22
29
  activeId?: string;
@@ -28,10 +35,14 @@ interface Props extends Record<string, unknown> {
28
35
  /** Initial collapsed state when uncontrolled (default false). Use the
29
36
  * `default-collapsed` attribute to start collapsed in plain HTML. */
30
37
  defaultCollapsed?: boolean;
38
+ /** Dense single-line rows (a leading dot + title, no message count). */
39
+ compact?: boolean;
31
40
  }
32
41
 
33
42
  interface Events {
34
- /** A conversation was selected. */
43
+ /** A conversation was selected. The selection event in BOTH modes: a
44
+ * batteries data row, or an activated `<kai-conversation-item>` child
45
+ * (click, Enter or Space). */
35
46
  'kai-conversation-select': { id: string };
36
47
  /** The "New chat" button was clicked. */
37
48
  'kai-new-chat': Record<string, never>;
@@ -50,19 +61,19 @@ interface Events {
50
61
  * - `id` → ConversationSummary.id
51
62
  * - `group-id` → ConversationSummary.groupId (optional)
52
63
  * - textContent → ConversationSummary.title
53
- * Required fields not expressible as HTML attributes (`scope`, `messageCount`,
54
- * `lastMessageAt`, `updatedAt`) receive safe defaults so the rendered list item
55
- * is fully functional with just `id` + title text.
64
+ * Fields not expressible as HTML attributes are NOT fabricated: the
65
+ * optional `scope` and `lastMessageAt` stay absent, and the required
66
+ * `messageCount`/`updatedAt` get honest defaults zero messages, and an empty
67
+ * `updatedAt` from which no trailing relative time is derived (the epoch it
68
+ * used to fabricate rendered a bogus "many days ago" on every declarative row).
56
69
  */
57
70
  export function parseKaiConversationElement(n: Element): ConversationSummary {
58
71
  return {
59
72
  id: n.getAttribute('id') ?? '',
60
73
  title: n.textContent?.trim() ?? '',
61
74
  groupId: n.getAttribute('group-id') ?? undefined,
62
- scope: { type: 'collection' } as ConversationScope,
63
75
  messageCount: 0,
64
- lastMessageAt: new Date(0).toISOString(),
65
- updatedAt: new Date(0).toISOString(),
76
+ updatedAt: '',
66
77
  };
67
78
  }
68
79
 
@@ -72,17 +83,34 @@ defineWebComponent<Props, Events>('kai-conversations', {
72
83
  activeId: undefined,
73
84
  collapsed: undefined,
74
85
  defaultCollapsed: undefined,
86
+ compact: undefined,
75
87
  }, (props, { dispatch, element, expose, flag }) => {
76
88
  // Read declarative <kai-conversation> children from light DOM.
77
89
  // Shadow DOM with no <slot> suppresses them visually — they're invisible data carriers.
78
90
  const [slottedConversations, setSlottedConversations] = createSignal<ConversationSummary[]>([]);
91
+ // Item mode: light-DOM <kai-conversation-item> children
92
+ // mean the CONSUMER owns the loop — the container skips its data rendering and
93
+ // runs the parent-item contract over the hosts instead.
94
+ const [itemHosts, setItemHosts] = createSignal<HTMLElement[]>([]);
79
95
  // Which composition slots (header/empty/footer) the consumer has filled.
80
96
  const [slots, setSlots] = createSignal<Record<string, boolean>>({});
81
97
  onMount(() => {
82
98
  const read = () => {
83
99
  const nodes = [...element.querySelectorAll('kai-conversation')];
84
100
  setSlottedConversations(nodes.map(parseKaiConversationElement));
101
+ // Reference-stable: a fresh array every observer tick would re-run the
102
+ // sync effect (whose writes the observer sees) in a feedback loop.
103
+ const hosts = [...element.querySelectorAll<HTMLElement>(':scope > kai-conversation-item')];
104
+ setItemHosts((prev) =>
105
+ prev.length === hosts.length && hosts.every((h, i) => h === prev[i]) ? prev : hosts,
106
+ );
85
107
  setSlots(readSlots(element, CONVERSATIONS_SLOTS));
108
+ // Re-sync on EVERY mutation, not only membership changes: an item host
109
+ // that upgrades after the first sync mutates its own attributes (the
110
+ // facade's mount), which lands here — and its shadow body needs stamping
111
+ // even though the hosts array is reference-stable. sync() writes
112
+ // on-change only, so this cannot feed the observer a loop.
113
+ if (hosts.length) itemsController.sync();
86
114
  };
87
115
  read();
88
116
  const observer = new MutationObserver(read);
@@ -90,9 +118,26 @@ defineWebComponent<Props, Events>('kai-conversations', {
90
118
  onCleanup(() => observer.disconnect());
91
119
  });
92
120
 
121
+ const itemMode = () => itemHosts().length > 0;
122
+
93
123
  // Prop conversations take precedence; slotted children are appended after.
94
124
  const allConversations = () => [...(props.conversations ?? []), ...slottedConversations()];
95
125
 
126
+ // The parent-item contract: selection flowing container→item, roving tabindex,
127
+ // ARIA list-row bookkeeping — pure DOM, host-agnostic (see the controller's JSDoc in
128
+ // components/conversation-list.tsx). Solid context cannot cross the element
129
+ // boundary, so the channel is DOM traversal by construction.
130
+ const itemsController = createConversationItemsController({
131
+ getItems: itemHosts,
132
+ getActiveId: () => props.activeId as string | undefined,
133
+ onSelect: (id) => dispatch('kai-conversation-select', { id }),
134
+ });
135
+ // Re-derive the bookkeeping whenever the children change (the MutationObserver
136
+ // and the shadow slot's slotchange both funnel into itemHosts) or activeId moves.
137
+ createEffect(() => {
138
+ if (itemMode()) itemsController.sync();
139
+ });
140
+
96
141
  // ── Rail collapse (controlled/uncontrolled, same pattern as kai-workspace) ──
97
142
  // `collapsed` (when set) wins; otherwise the element manages its own state,
98
143
  // seeded from `defaultCollapsed`. `setCollapsedTo` always writes the internal
@@ -143,8 +188,12 @@ defineWebComponent<Props, Events>('kai-conversations', {
143
188
  onSelect={(id) => dispatch('kai-conversation-select', { id })}
144
189
  onNewChat={() => dispatch('kai-new-chat')}
145
190
  onToggleSidebar={() => { dispatch('kai-toggle-sidebar'); setCollapsedTo(true); }}
191
+ compact={flag('compact')}
146
192
  onSearchChange={(query) => dispatch('kai-search', { query })}
147
193
  controllerRef={(c) => (controller = c)}
194
+ items={itemMode() ? <slot /> : undefined}
195
+ itemsKeyDown={itemsController.handleKeyDown}
196
+ itemsClick={itemsController.handleClick}
148
197
  header={slots().header ? <slot name="header" /> : undefined}
149
198
  footer={slots().footer ? <slot name="footer" /> : undefined}
150
199
  empty={slots().empty ? <slot name="empty" /> : undefined}
@@ -70,8 +70,8 @@ export interface DefaultPromptInputProps {
70
70
  * (name, media type, reason) and renders nothing itself: what the user should
71
71
  * see is the application's call, not the kit's. */
72
72
  onAttachmentsRejected?: (rejected: RejectedAttachment[]) => void;
73
- /** Show a Search (Globe) button in the left toolbar; calls `onSearch`. */
74
- search?: boolean;
73
+ /** Show a web-search (Globe) button in the left toolbar; calls `onWebSearch`. */
74
+ webSearch?: boolean;
75
75
  /** Show a Voice (Mic) button in the left toolbar; calls `onVoice`. */
76
76
  voice?: boolean;
77
77
  /** Send-button visibility. `'always'` (default) always shows it; `'auto'` shows
@@ -84,7 +84,7 @@ export interface DefaultPromptInputProps {
84
84
  onSubmit: () => void;
85
85
  onSuggestionClick: (v: string) => void;
86
86
  onAttachmentsChange?: (attachments: AttachmentData[]) => void;
87
- onSearch?: () => void;
87
+ onWebSearch?: () => void;
88
88
  onVoice?: () => void;
89
89
  /** When `true` and `loading` is also `true`, the send button is replaced by
90
90
  * a Stop button that calls `onStop`. */
@@ -296,7 +296,7 @@ export function DefaultPromptInput(props: DefaultPromptInputProps) {
296
296
  <Paperclip class="size-4" />
297
297
  </Button>
298
298
  </Show>
299
- <Show when={props.search}>
299
+ <Show when={props.webSearch}>
300
300
  <Button
301
301
  type="button"
302
302
  variant="outline"
@@ -304,7 +304,7 @@ export function DefaultPromptInput(props: DefaultPromptInputProps) {
304
304
  class="rounded-full gap-1"
305
305
  aria-label="Search the web"
306
306
  disabled={props.disabled}
307
- onClick={() => props.onSearch?.()}
307
+ onClick={() => props.onWebSearch?.()}
308
308
  >
309
309
  <Globe class="size-4" />
310
310
  Search
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @kitn.ai/ui/define — the facade seam, public.
3
+ *
4
+ * The construct engine's GENERATED projects (and any consumer who wants to wrap
5
+ * a pure-Solid interior as one self-registering element) import from here. Its
6
+ * own subpath rather than ./solid because define.tsx carries ELEMENT_CSS (the
7
+ * full compiled kit CSS) and solid-element — weight ./solid consumers must not
8
+ * pay. SSR-safe by construction: defineWebComponent no-ops without
9
+ * customElements (see define.tsx).
10
+ */
11
+ export { defineWebComponent } from './define';
12
+ export type { WebComponentContext } from './define';
@@ -1,7 +1,8 @@
1
1
  import { customElement } from 'solid-element';
2
2
  import { ChatConfig } from '../primitives/chat-config';
3
3
  import { ELEMENT_CSS } from './css';
4
- import { createSignal, onCleanup, Show, type JSX } from 'solid-js';
4
+ import { elementDiagnosticsWanted, installElementDiagnostics } from './element-diagnostics';
5
+ import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js';
5
6
 
6
7
  /**
7
8
  * Shared constructable stylesheet, built once and adopted by every element's
@@ -78,6 +79,33 @@ export interface WebComponentContext<E = Record<string, unknown>> {
78
79
  * convention). Methods are attached when the facade renders (on element upgrade).
79
80
  */
80
81
  expose: (methods: Record<string, (...args: never[]) => unknown>) => void;
82
+ /**
83
+ * Reflect a boolean prop to its host attribute AND make that prop read back what
84
+ * was set. Use this instead of hand-rolling
85
+ * `createEffect(() => element.toggleAttribute('x', flag('x')))`.
86
+ *
87
+ * WHY IT IS ONE CALL AND NOT TWO. The reflection is what BREAKS the read-back, so
88
+ * the fix has to be attached to it or it gets forgotten — and it was, three times.
89
+ * `toggleAttribute(name, true)` sets the attribute to the EMPTY STRING;
90
+ * component-register's `attributeChangedCallback` then writes the prop back as
91
+ * `this[name] = parseAttributeValue("")`, and `parseAttributeValue` returns
92
+ * `undefined` for the empty string. So a reflected flag became write-only:
93
+ * `el.loading = true` left `el.loading === undefined` while `[loading]` was on the
94
+ * host. The element kept BEHAVING correctly, because `flag()` reads the attribute —
95
+ * which is precisely why nobody noticed until a consumer tried to read the property
96
+ * back (findings G-05).
97
+ *
98
+ * What this installs is an instance-level wrapper around the accessor
99
+ * component-register already created, coercing every incoming value through the
100
+ * same `flag()` policy (`resolveFlag`) — so the `undefined` write-back resolves to
101
+ * the attribute that caused it, and the property and the attribute can no longer
102
+ * disagree. It delegates to the underlying setter, so reactivity is untouched.
103
+ *
104
+ * `source` overrides where the ON/OFF value comes from, for an element whose truth
105
+ * is an internal controller rather than the prop (see `wireDisclosure`). Returning
106
+ * `undefined` from it means "not ready, leave the attribute alone".
107
+ */
108
+ reflectFlag: (name: string, source?: () => boolean | undefined) => void;
81
109
  /**
82
110
  * Whether the element should currently render its dark-mode look --
83
111
  * exactly the SAME resolved value that already drives the `.dark` class
@@ -197,10 +225,22 @@ function defineWithNonReflectingProps<T>(
197
225
  tag: string,
198
226
  keys: readonly string[],
199
227
  define: () => T,
228
+ /**
229
+ * Anything else that must be on the prototype BEFORE the registry sees the
230
+ * class. Today that is the element-layer diagnostics, and it needs this seam
231
+ * for a reason that is adjacent to the one above but not the same: `define()`
232
+ * SNAPSHOTS the lifecycle callbacks (`connectedCallback`,
233
+ * `attributeChangedCallback`, …) off the prototype into the custom-element
234
+ * definition, and the browser invokes the snapshot. A wrapper installed
235
+ * afterwards is present on the prototype, passes `hasOwnProperty`, and is
236
+ * never called. See `installElementDiagnostics`.
237
+ */
238
+ alsoPatch?: (proto: object) => void,
200
239
  ): { result: T; handled: boolean } {
201
- // `handled` = nothing more for the caller to do. With no colliding props there is
202
- // nothing to install at all, so that case is trivially handled.
203
- if (keys.length === 0) return { result: define(), handled: true };
240
+ // `handled` = nothing more for the caller to do. With no colliding props and
241
+ // nothing else to patch there is nothing to install at all, so that case is
242
+ // trivially handled.
243
+ if (keys.length === 0 && !alsoPatch) return { result: define(), handled: true };
204
244
  const registry = customElements;
205
245
  const hadOwnDefine = Object.prototype.hasOwnProperty.call(registry, 'define');
206
246
  const inner = registry.define;
@@ -214,7 +254,8 @@ function defineWithNonReflectingProps<T>(
214
254
  options?: ElementDefinitionOptions,
215
255
  ) {
216
256
  if (name === tag) {
217
- installNonReflectingProps(constructor.prototype, keys);
257
+ if (keys.length) installNonReflectingProps(constructor.prototype, keys);
258
+ alsoPatch?.(constructor.prototype);
218
259
  handled = true;
219
260
  }
220
261
  return inner.call(this, name, constructor, options);
@@ -237,6 +278,76 @@ function defineWithNonReflectingProps<T>(
237
278
  }
238
279
  }
239
280
 
281
+ /**
282
+ * Marks a setter as one of ours, so the wrap is idempotent WITHOUT being permanent.
283
+ *
284
+ * The mark goes on the setter function rather than on the element, and that is the
285
+ * whole subtlety: component-register installs a FRESH instance accessor from
286
+ * `initializeProps` on every (re)connect after a release, which throws our wrapper
287
+ * away. An element-level "already done" flag would then skip re-wrapping and the
288
+ * property would quietly go write-only again on the second mount. An unmarked setter
289
+ * is by definition a new one, so it gets wrapped again.
290
+ */
291
+ const FLAG_READ_BACK = Symbol('kai-flag-read-back');
292
+
293
+ /**
294
+ * Wrap the instance accessor component-register created for `name` so every value
295
+ * written to it — a consumer's assignment, or the `undefined` write-back that
296
+ * `attributeChangedCallback` performs after a `toggleAttribute` — is resolved through
297
+ * the same policy `flag()` uses.
298
+ *
299
+ * TIMING. This must run from the facade body, i.e. during `connectedCallback` AFTER
300
+ * `initializeProps`, and that is not a detail: `initializeProps` harvests any value
301
+ * set on the element BEFORE upgrade (`value = element[key]`) and only then installs
302
+ * the accessor. Wrapping earlier (on the prototype, the way `installNonReflectingProps`
303
+ * does) would be shadowed by that accessor and would also sit in front of the harvest —
304
+ * the same class of defect `define-upgrade-ordering.test.tsx` pins for attributes.
305
+ */
306
+ function installFlagReadBack(element: HTMLElement, name: string, attribute: string): void {
307
+ const inner = Object.getOwnPropertyDescriptor(element, name);
308
+ if (!inner?.get || !inner.set) {
309
+ // Reached only if `name` is not a declared prop of this element — a typo, or a
310
+ // facade reflecting something it never declared. Warn rather than no-op silently;
311
+ // a silent skip here would look exactly like a working read-back.
312
+ console.warn(
313
+ `reflectFlag("${name}"): no such declared prop on <${element.localName}> — ` +
314
+ `the attribute will still reflect, but the property will not read back.`,
315
+ );
316
+ return;
317
+ }
318
+ const { get, set } = inner;
319
+ if ((set as { [FLAG_READ_BACK]?: true })[FLAG_READ_BACK]) return;
320
+
321
+ const wrapped = function (this: HTMLElement, value: unknown) {
322
+ set.call(this, resolveFlag(this, value, attribute));
323
+ } as ((value: unknown) => void) & { [FLAG_READ_BACK]?: true };
324
+ wrapped[FLAG_READ_BACK] = true;
325
+
326
+ Object.defineProperty(element, name, {
327
+ get,
328
+ set: wrapped,
329
+ enumerable: inner.enumerable ?? true,
330
+ configurable: true,
331
+ });
332
+
333
+ // Seed, but ONLY upwards. The value sitting in the prop store right now may already
334
+ // be the broken one: `<el loading>` parses to `undefined` in `initializeProps`
335
+ // exactly as it does in the write-back, so without this the bare-attribute case
336
+ // would still read back `undefined` until something else wrote to the prop.
337
+ //
338
+ // WHY NOT SEED `false` TOO. Writing `false` over an `undefined` would look tidier
339
+ // and is wrong: for props declared with an `undefined` default, `undefined` MEANS
340
+ // "the consumer has not set this", and at least one caller depends on telling that
341
+ // apart from an explicit `false` — `wireDisclosure` seeds from `defaultOpen` only
342
+ // while `open` is unset, so a blanket `false` seed would clobber
343
+ // `<el default-open>` on every mount. Promoting only a present attribute to `true`
344
+ // fixes the read-back without inventing an opinion the author never expressed.
345
+ const current = get.call(element);
346
+ if (typeof current !== 'boolean' && resolveFlag(element, current, attribute)) {
347
+ wrapped.call(element, true);
348
+ }
349
+ }
350
+
240
351
  /** Underlying flag resolution; see `WebComponentContext.flag`. */
241
352
  function resolveFlag(element: HTMLElement, value: unknown, attribute: string): boolean {
242
353
  if (value === true) return true;
@@ -329,6 +440,21 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
329
440
  const flag = (name: string) =>
330
441
  resolveFlag(element, (props as Record<string, unknown>)[name], toAttr(name));
331
442
 
443
+ // Reflect a boolean prop to its attribute and keep the property readable. See
444
+ // WebComponentContext.reflectFlag for the defect this exists to close.
445
+ const reflectFlag: WebComponentContext<E>['reflectFlag'] = (name, source) => {
446
+ const attribute = toAttr(name);
447
+ installFlagReadBack(element, name, attribute);
448
+ createEffect(() => {
449
+ const on = source ? source() : flag(name);
450
+ // `undefined` means the caller's source is not ready yet (a controller a
451
+ // primitive has not handed up). Leave the author's attribute alone rather
452
+ // than writing a guessed OFF over it.
453
+ if (on === undefined) return;
454
+ element.toggleAttribute(attribute, on);
455
+ });
456
+ };
457
+
332
458
  // Attach imperative methods onto the host instance. See WebComponentContext.expose.
333
459
  // Uses defineProperty so a method can shadow an inherited getter-only accessor
334
460
  // (e.g. `focus`/`blur`) which a plain assignment would throw on. A method name
@@ -381,15 +507,39 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
381
507
  <div classList={{ dark: isDark() }} style={{ display: 'contents', color: 'var(--color-foreground)' }}>
382
508
  <div ref={portalNode} />
383
509
  <ChatConfig portalMount={portalNode}>
384
- {Facade(props as unknown as P, { element, dispatch, flag, expose, dark: isDark })}
510
+ {Facade(props as unknown as P, {
511
+ element,
512
+ dispatch,
513
+ flag,
514
+ reflectFlag,
515
+ expose,
516
+ dark: isDark,
517
+ })}
385
518
  </ChatConfig>
386
519
  </div>
387
520
  </>
388
521
  );
389
522
  };
390
523
 
391
- const { result: Ctor, handled } = defineWithNonReflectingProps(tag, shadowedProps, () =>
392
- customElement(tag, defaults, renderFacade),
524
+ // Element-layer diagnostics: report the three `kai-` contract violations that
525
+ // are otherwise silent (an array or object prop set as an HTML attribute, the
526
+ // same array reference handed back, a new array of the same item objects).
527
+ //
528
+ // HERE because this function is the single choke point — every kai-* element
529
+ // registers through it, which `elements/slots.test.ts` already enforces — so
530
+ // one call covers every element with no per-element work and no second list.
531
+ //
532
+ // Through the pre-define seam, not after the fact, because the registry
533
+ // snapshots lifecycle callbacks at definition time; see `alsoPatch` above.
534
+ // `elementDiagnosticsWanted` is asked first so a tag with no non-scalar prop
535
+ // (37 of the 80) does not even pay for the registry interception.
536
+ const wantsDiagnostics = elementDiagnosticsWanted(tag);
537
+
538
+ const { result: Ctor, handled } = defineWithNonReflectingProps(
539
+ tag,
540
+ shadowedProps,
541
+ () => customElement(tag, defaults, renderFacade),
542
+ wantsDiagnostics ? (proto) => installElementDiagnostics(tag, proto) : undefined,
393
543
  );
394
544
 
395
545
  // Belt and braces for the one path the wrap cannot see: if `customElements.define`
@@ -400,4 +550,14 @@ export function defineWebComponent<P extends Record<string, unknown>, E = Record
400
550
  // in the normal case, where the accessors are already on this same prototype.
401
551
  const proto = (Ctor as unknown as { prototype?: object } | undefined)?.prototype;
402
552
  if (!handled && proto) installNonReflectingProps(proto, shadowedProps);
553
+
554
+ // NOTE the diagnostics have no equivalent late fallback, and must not get one.
555
+ // The non-reflecting props still work when installed late (they only have to
556
+ // beat the NEXT constructor); the diagnostics do not, because the registry has
557
+ // already snapshotted the lifecycle callbacks it will invoke. Installing them
558
+ // here would produce a wrapper that is visibly present and never called —
559
+ // which is worse than not installing it, since it would read as coverage. So
560
+ // in the one environment the pre-define seam cannot reach (a frozen registry:
561
+ // SES lockdown, a sealed polyfill), element diagnostics are simply absent, and
562
+ // every other element behaviour is unaffected.
403
563
  }