@kitn.ai/ui 0.28.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 (376) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-tooling/construct/public.d.ts +15 -0
  3. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  4. package/dist/construct-cli.es.js +3 -3
  5. package/dist/construct.d.ts +5 -0
  6. package/dist/construct.js +327 -0
  7. package/dist/core-C8fzo39E.js +1 -12
  8. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  9. package/dist/mcp.es.js +1 -1
  10. package/package.json +16 -16
  11. package/bin/route.test.js +0 -58
  12. package/src/agent-tooling/README.md +0 -192
  13. package/src/agent-tooling/archetypes.ts +0 -205
  14. package/src/agent-tooling/catalog/README.md +0 -676
  15. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  16. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  17. package/src/agent-tooling/catalog/invariants.ts +0 -284
  18. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  19. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  20. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  21. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  22. package/src/agent-tooling/construct/cli.ts +0 -147
  23. package/src/agent-tooling/construct/codegen.ts +0 -1635
  24. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  25. package/src/agent-tooling/construct/dev.ts +0 -148
  26. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  27. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  28. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  29. package/src/agent-tooling/construct/schema.ts +0 -452
  30. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  31. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  32. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  33. package/src/agent-tooling/integrations/mastra.ts +0 -182
  34. package/src/agent-tooling/integrations/mock.ts +0 -148
  35. package/src/agent-tooling/integrations/ollama.ts +0 -97
  36. package/src/agent-tooling/integrations/openai.ts +0 -95
  37. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  38. package/src/agent-tooling/integrations/pi.ts +0 -176
  39. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  40. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  41. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  42. package/src/agent-tooling/mcp/manifest.ts +0 -422
  43. package/src/agent-tooling/mcp/server.ts +0 -116
  44. package/src/agent-tooling/mcp/stdio.ts +0 -18
  45. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  46. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  47. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  48. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  49. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  50. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  51. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  52. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  53. package/src/agent-tooling/recipes/index.ts +0 -22
  54. package/src/agent-tooling/recipes/types.ts +0 -32
  55. package/src/agent-tooling/registry.ts +0 -132
  56. package/src/agent-tooling/route-emit.ts +0 -305
  57. package/src/agent-tooling/types.ts +0 -390
  58. package/src/components/artifact-card.tsx +0 -120
  59. package/src/components/artifact.tsx +0 -914
  60. package/src/components/attachment-types.ts +0 -66
  61. package/src/components/attachments.tsx +0 -536
  62. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  63. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  64. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  65. package/src/components/audio-visualizer/index.tsx +0 -528
  66. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  67. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  68. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  69. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  70. package/src/components/audio-visualizer/sizes.ts +0 -54
  71. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  72. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  73. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  74. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  75. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  76. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  77. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  78. package/src/components/card-fallback.tsx +0 -60
  79. package/src/components/card-renderer.tsx +0 -220
  80. package/src/components/card.tsx +0 -212
  81. package/src/components/chain-of-thought.tsx +0 -348
  82. package/src/components/chat-container.tsx +0 -89
  83. package/src/components/chat-scope-picker.tsx +0 -57
  84. package/src/components/chat-thread.tsx +0 -1014
  85. package/src/components/checkpoint.tsx +0 -88
  86. package/src/components/choice-card.tsx +0 -743
  87. package/src/components/coachmark.tsx +0 -249
  88. package/src/components/code-block.tsx +0 -181
  89. package/src/components/composer-dom.ts +0 -159
  90. package/src/components/composer-highlight.ts +0 -242
  91. package/src/components/composer-history.ts +0 -82
  92. package/src/components/composer.tsx +0 -1075
  93. package/src/components/confirm-card.tsx +0 -402
  94. package/src/components/context.tsx +0 -377
  95. package/src/components/conversation-item.tsx +0 -241
  96. package/src/components/conversation-list.tsx +0 -429
  97. package/src/components/conversation-panel.tsx +0 -118
  98. package/src/components/dismissed-stub.tsx +0 -80
  99. package/src/components/embed.tsx +0 -200
  100. package/src/components/empty.tsx +0 -177
  101. package/src/components/feedback-bar.tsx +0 -166
  102. package/src/components/file-tree.tsx +0 -530
  103. package/src/components/file-upload.tsx +0 -167
  104. package/src/components/form-widgets.tsx +0 -525
  105. package/src/components/form.tsx +0 -1296
  106. package/src/components/home-panel.tsx +0 -159
  107. package/src/components/image.tsx +0 -65
  108. package/src/components/link-preview.tsx +0 -195
  109. package/src/components/loader.tsx +0 -367
  110. package/src/components/markdown.tsx +0 -162
  111. package/src/components/message-skills.tsx +0 -40
  112. package/src/components/message.tsx +0 -765
  113. package/src/components/model-switcher.tsx +0 -132
  114. package/src/components/prompt-input.tsx +0 -188
  115. package/src/components/prompt-suggestion.tsx +0 -150
  116. package/src/components/reasoning.tsx +0 -293
  117. package/src/components/response-compare-types.ts +0 -152
  118. package/src/components/response-compare.tsx +0 -455
  119. package/src/components/response-stream.tsx +0 -109
  120. package/src/components/screen.tsx +0 -181
  121. package/src/components/scroll-button.tsx +0 -93
  122. package/src/components/source.tsx +0 -192
  123. package/src/components/tasks-card.tsx +0 -801
  124. package/src/components/text-shimmer.tsx +0 -37
  125. package/src/components/thinking-bar.tsx +0 -50
  126. package/src/components/thread.tsx +0 -228
  127. package/src/components/toast.tsx +0 -503
  128. package/src/components/tool-classify.ts +0 -26
  129. package/src/components/tool-types.ts +0 -49
  130. package/src/components/tool.tsx +0 -190
  131. package/src/components/use-card-resolution.ts +0 -44
  132. package/src/components/voice-input.tsx +0 -222
  133. package/src/components/voice-output.tsx +0 -242
  134. package/src/components/widget-tab-bar.tsx +0 -73
  135. package/src/components/workspace-shell.tsx +0 -285
  136. package/src/diagnostics/hook.ts +0 -352
  137. package/src/diagnostics/index.ts +0 -82
  138. package/src/diagnostics/report-request.ts +0 -296
  139. package/src/elements/agent-card.tsx +0 -67
  140. package/src/elements/artifact.tsx +0 -194
  141. package/src/elements/attachments.tsx +0 -140
  142. package/src/elements/audio-visualizer.tsx +0 -227
  143. package/src/elements/autoloader.ts +0 -89
  144. package/src/elements/avatar.tsx +0 -33
  145. package/src/elements/badge.tsx +0 -32
  146. package/src/elements/button.tsx +0 -149
  147. package/src/elements/card.tsx +0 -133
  148. package/src/elements/cards.tsx +0 -266
  149. package/src/elements/chain-of-thought.tsx +0 -141
  150. package/src/elements/chat-scope-picker.tsx +0 -65
  151. package/src/elements/chat-types.ts +0 -102
  152. package/src/elements/chat-workspace.tsx +0 -188
  153. package/src/elements/chat.tsx +0 -304
  154. package/src/elements/checkbox-group.tsx +0 -164
  155. package/src/elements/checkbox.tsx +0 -134
  156. package/src/elements/checkpoint.tsx +0 -47
  157. package/src/elements/choice.tsx +0 -100
  158. package/src/elements/coachmark.tsx +0 -90
  159. package/src/elements/code-block.tsx +0 -60
  160. package/src/elements/command.tsx +0 -197
  161. package/src/elements/compare.tsx +0 -111
  162. package/src/elements/compiled.css +0 -2
  163. package/src/elements/composer.tsx +0 -162
  164. package/src/elements/confirm-card.tsx +0 -76
  165. package/src/elements/context-meter.tsx +0 -107
  166. package/src/elements/conversation-item.tsx +0 -120
  167. package/src/elements/conversation-list.tsx +0 -203
  168. package/src/elements/css.ts +0 -5
  169. package/src/elements/default-input.tsx +0 -392
  170. package/src/elements/define-entry.ts +0 -12
  171. package/src/elements/define.tsx +0 -563
  172. package/src/elements/diagnostic-events.ts +0 -114
  173. package/src/elements/dialog.tsx +0 -145
  174. package/src/elements/disclosure.ts +0 -95
  175. package/src/elements/dock.tsx +0 -215
  176. package/src/elements/dropdown.tsx +0 -123
  177. package/src/elements/editable-label.tsx +0 -140
  178. package/src/elements/element-data-types.ts +0 -152
  179. package/src/elements/element-diagnostics.ts +0 -392
  180. package/src/elements/element-manifest.json +0 -354
  181. package/src/elements/element-nonscalar.json +0 -187
  182. package/src/elements/element-types.d.ts +0 -4353
  183. package/src/elements/embed.tsx +0 -35
  184. package/src/elements/empty.tsx +0 -29
  185. package/src/elements/feedback-bar.tsx +0 -66
  186. package/src/elements/file-tree.tsx +0 -62
  187. package/src/elements/file-upload.tsx +0 -44
  188. package/src/elements/form.tsx +0 -94
  189. package/src/elements/hover-card.tsx +0 -80
  190. package/src/elements/icon.tsx +0 -41
  191. package/src/elements/image.tsx +0 -32
  192. package/src/elements/input.tsx +0 -492
  193. package/src/elements/kbd.tsx +0 -45
  194. package/src/elements/link-preview.tsx +0 -34
  195. package/src/elements/loader.tsx +0 -25
  196. package/src/elements/markdown.tsx +0 -38
  197. package/src/elements/menu.tsx +0 -241
  198. package/src/elements/message-skills.tsx +0 -83
  199. package/src/elements/message.tsx +0 -361
  200. package/src/elements/model-switcher.tsx +0 -121
  201. package/src/elements/nav.tsx +0 -87
  202. package/src/elements/notice.tsx +0 -53
  203. package/src/elements/pane-grid.tsx +0 -111
  204. package/src/elements/pane-group.tsx +0 -119
  205. package/src/elements/pane.tsx +0 -129
  206. package/src/elements/popover.tsx +0 -81
  207. package/src/elements/progress-bar.tsx +0 -39
  208. package/src/elements/prompt-dock.tsx +0 -82
  209. package/src/elements/prompt-input.tsx +0 -240
  210. package/src/elements/prompt-suggestions.tsx +0 -113
  211. package/src/elements/radio-group.tsx +0 -129
  212. package/src/elements/reasoning.tsx +0 -71
  213. package/src/elements/register-impl.ts +0 -148
  214. package/src/elements/register.ts +0 -76
  215. package/src/elements/remote.tsx +0 -225
  216. package/src/elements/resizable.globals.d.ts +0 -36
  217. package/src/elements/resizable.tsx +0 -704
  218. package/src/elements/response-stream.tsx +0 -40
  219. package/src/elements/screen.tsx +0 -90
  220. package/src/elements/scroll-area.tsx +0 -33
  221. package/src/elements/scroll-button.tsx +0 -179
  222. package/src/elements/search.tsx +0 -185
  223. package/src/elements/segmented.tsx +0 -129
  224. package/src/elements/select.tsx +0 -165
  225. package/src/elements/separator.tsx +0 -36
  226. package/src/elements/setting-item.tsx +0 -50
  227. package/src/elements/settings-group.tsx +0 -37
  228. package/src/elements/skeleton.tsx +0 -45
  229. package/src/elements/slider.tsx +0 -171
  230. package/src/elements/slot-text.ts +0 -73
  231. package/src/elements/slots.ts +0 -787
  232. package/src/elements/source.tsx +0 -126
  233. package/src/elements/status.tsx +0 -42
  234. package/src/elements/styles.css +0 -328
  235. package/src/elements/switch.tsx +0 -118
  236. package/src/elements/tabs.tsx +0 -95
  237. package/src/elements/tasks.tsx +0 -103
  238. package/src/elements/text-shimmer.tsx +0 -28
  239. package/src/elements/thinking-bar.tsx +0 -43
  240. package/src/elements/thread.tsx +0 -139
  241. package/src/elements/toast.tsx +0 -106
  242. package/src/elements/tool.tsx +0 -78
  243. package/src/elements/tooltip.tsx +0 -85
  244. package/src/elements/validate-messages.ts +0 -76
  245. package/src/elements/voice-input.tsx +0 -100
  246. package/src/elements/voice-output.tsx +0 -82
  247. package/src/index.ts +0 -430
  248. package/src/primitives/audio-bands.ts +0 -174
  249. package/src/primitives/card-component-types.ts +0 -63
  250. package/src/primitives/card-contract.ts +0 -80
  251. package/src/primitives/card-data-types.ts +0 -361
  252. package/src/primitives/card-host.tsx +0 -37
  253. package/src/primitives/card-recovery.ts +0 -160
  254. package/src/primitives/card-registry.tsx +0 -78
  255. package/src/primitives/card-resolution.ts +0 -36
  256. package/src/primitives/card-routing.ts +0 -85
  257. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  258. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  259. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  260. package/src/primitives/card-schemas/choice.schema.json +0 -75
  261. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  262. package/src/primitives/card-schemas/embed.schema.json +0 -63
  263. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  264. package/src/primitives/card-schemas/form.schema.json +0 -53
  265. package/src/primitives/card-schemas/link.schema.json +0 -54
  266. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  267. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  268. package/src/primitives/card-tags.ts +0 -61
  269. package/src/primitives/card-validate-cards.ts +0 -255
  270. package/src/primitives/card-validate-schemas.ts +0 -58
  271. package/src/primitives/card-validate.ts +0 -131
  272. package/src/primitives/chat-config.tsx +0 -103
  273. package/src/primitives/composer-model.ts +0 -49
  274. package/src/primitives/composer-triggers.ts +0 -35
  275. package/src/primitives/controllable.ts +0 -21
  276. package/src/primitives/conversation-store.ts +0 -248
  277. package/src/primitives/create-kai-chat.ts +0 -66
  278. package/src/primitives/create-tween.ts +0 -266
  279. package/src/primitives/embed-providers.ts +0 -254
  280. package/src/primitives/field-mask.ts +0 -256
  281. package/src/primitives/field-semantics.ts +0 -115
  282. package/src/primitives/highlighter.ts +0 -157
  283. package/src/primitives/input-mask.ts +0 -853
  284. package/src/primitives/link-preview.ts +0 -87
  285. package/src/primitives/message-feedback.ts +0 -124
  286. package/src/primitives/pdf-preview.ts +0 -121
  287. package/src/primitives/toast-store.ts +0 -338
  288. package/src/primitives/url-scheme-policy.ts +0 -70
  289. package/src/primitives/use-audio-analysis.ts +0 -340
  290. package/src/primitives/use-auto-resize.ts +0 -31
  291. package/src/primitives/use-resize-observer.ts +0 -45
  292. package/src/primitives/use-sequencer.ts +0 -72
  293. package/src/primitives/use-speech-recognition.ts +0 -146
  294. package/src/primitives/use-stick-to-bottom.ts +0 -75
  295. package/src/primitives/use-text-stream.ts +0 -143
  296. package/src/primitives/use-voice-recorder.ts +0 -62
  297. package/src/primitives/visualizer-sequences.ts +0 -350
  298. package/src/remote/host-embed.ts +0 -345
  299. package/src/remote/index.ts +0 -2
  300. package/src/remote/origin.ts +0 -30
  301. package/src/remote/provider-runtime.ts +0 -262
  302. package/src/remote/provider.ts +0 -2
  303. package/src/remote/validate.ts +0 -22
  304. package/src/remote/version.ts +0 -12
  305. package/src/remote/wire.ts +0 -48
  306. package/src/schemas/from-tool-call.ts +0 -151
  307. package/src/schemas/index.ts +0 -341
  308. package/src/schemas/provider-subsets.ts +0 -538
  309. package/src/schemas/registry.ts +0 -355
  310. package/src/schemas/tool-defs.ts +0 -793
  311. package/src/solid.ts +0 -173
  312. package/src/state/index.ts +0 -44
  313. package/src/state/messages.ts +0 -53
  314. package/src/state/mock.ts +0 -297
  315. package/src/state/parts.ts +0 -295
  316. package/src/state/persistence.ts +0 -180
  317. package/src/state/stream.ts +0 -246
  318. package/src/state/suggestions.ts +0 -9
  319. package/src/state/threads.ts +0 -142
  320. package/src/test-utils/fake-clock.ts +0 -88
  321. package/src/types.ts +0 -95
  322. package/src/ui/action-icons.ts +0 -53
  323. package/src/ui/agent-card.tsx +0 -218
  324. package/src/ui/avatar.tsx +0 -23
  325. package/src/ui/badge.tsx +0 -21
  326. package/src/ui/button.tsx +0 -49
  327. package/src/ui/card.tsx +0 -245
  328. package/src/ui/checkbox-group.tsx +0 -153
  329. package/src/ui/checkbox.tsx +0 -63
  330. package/src/ui/collapsible.tsx +0 -163
  331. package/src/ui/command.tsx +0 -103
  332. package/src/ui/dialog.tsx +0 -223
  333. package/src/ui/dock.tsx +0 -630
  334. package/src/ui/dropdown.tsx +0 -636
  335. package/src/ui/editable-label.tsx +0 -112
  336. package/src/ui/hover-card.tsx +0 -345
  337. package/src/ui/icon.tsx +0 -167
  338. package/src/ui/input.tsx +0 -391
  339. package/src/ui/kbd.tsx +0 -118
  340. package/src/ui/nav.tsx +0 -282
  341. package/src/ui/notice.tsx +0 -84
  342. package/src/ui/overlay.tsx +0 -277
  343. package/src/ui/pane-grid.tsx +0 -117
  344. package/src/ui/pane-group.tsx +0 -291
  345. package/src/ui/pane.tsx +0 -193
  346. package/src/ui/popover.tsx +0 -106
  347. package/src/ui/progress-bar.tsx +0 -83
  348. package/src/ui/prompt-dock.tsx +0 -145
  349. package/src/ui/radio.tsx +0 -150
  350. package/src/ui/resizable.tsx +0 -693
  351. package/src/ui/scroll-area.tsx +0 -26
  352. package/src/ui/segmented.tsx +0 -109
  353. package/src/ui/select.tsx +0 -168
  354. package/src/ui/separator.tsx +0 -10
  355. package/src/ui/settings-group.tsx +0 -67
  356. package/src/ui/skeleton.tsx +0 -73
  357. package/src/ui/slider.tsx +0 -178
  358. package/src/ui/status.tsx +0 -48
  359. package/src/ui/switch.tsx +0 -119
  360. package/src/ui/tabs.tsx +0 -168
  361. package/src/ui/textarea.tsx +0 -21
  362. package/src/ui/tooltip.tsx +0 -118
  363. package/src/utils/cn.ts +0 -30
  364. package/src/wire/chunk.ts +0 -248
  365. package/src/wire/consume.ts +0 -599
  366. package/src/wire/diagnostics.ts +0 -727
  367. package/src/wire/encode-probe.ts +0 -214
  368. package/src/wire/encode.ts +0 -947
  369. package/src/wire/files.ts +0 -342
  370. package/src/wire/formats/anthropic.ts +0 -274
  371. package/src/wire/formats/openai.ts +0 -228
  372. package/src/wire/index.ts +0 -95
  373. package/src/wire/media-types.ts +0 -344
  374. package/src/wire/read.ts +0 -396
  375. package/src/wire/sink-helpers.ts +0 -50
  376. package/src/wire/sse.ts +0 -153
@@ -1,422 +0,0 @@
1
- /**
2
- * manifest.ts — reads dist/custom-elements.json (a Custom Elements Manifest)
3
- * and exposes helpers for the component_reference tool.
4
- *
5
- * Resolution strategy (dual-context) — each context is an EXACT location, never a
6
- * search. See `resolveManifestPath` for why that distinction is the whole point:
7
- * 1. Bundled bin: dist/mcp.es.js lives in dist/, so custom-elements.json is
8
- * a sibling → ./custom-elements.json relative to import.meta.url.
9
- * 2. Vitest (source): manifest.ts lives at <package>/src/agent-tooling/mcp/, so
10
- * the manifest is <package>/dist/custom-elements.json and nowhere else.
11
- *
12
- * It also answers "which of these 80 elements has anything to do with cards", for
13
- * the card contract component_reference serves. That question lives HERE rather than
14
- * in reference.ts because half of it is a question about the element manifest — the
15
- * kit's own `type -> tag` map, crossed against the tag list this module already owns
16
- * — and because both halves of the answer must come off one place. See
17
- * `cardTagForType` for the rule and for what happens when an eighth card type lands.
18
- */
19
-
20
- import { readFileSync, readdirSync, existsSync } from 'node:fs';
21
- import { fileURLToPath } from 'node:url';
22
- import { join, dirname, resolve } from 'node:path';
23
- // The package's own public entry, by the same specifier the scaffolder tells a
24
- // consumer's route to use. That is now a CHOICE, and this comment used to say the
25
- // opposite: the barrel re-exports src/schemas/registry.ts, which type-IMPORTED
26
- // `CardComponentMap` from src/primitives/card-registry.TSX, and pulling a .tsx into
27
- // this pass would mean giving tsconfig.mcp.json `jsx` + `jsxImportSource` + the DOM
28
- // lib, dragging the whole Solid component tree into a Node-only project — measured
29
- // as 0 errors -> 1364. Those two types moved to the DOM-free
30
- // src/primitives/card-component-types.ts, so a relative import of the barrel would
31
- // typecheck here today. It stays on the public specifier anyway, because emitting
32
- // and consuming the same string is the point of this module. The built entry
33
- // resolves to dist/schemas/index.d.ts, whose own reference to card-registry is a
34
- // .d.ts that skipLibCheck skips, so the Node/no-DOM guarantee survives intact.
35
- //
36
- // `BUILTIN_CARD_TAGS` is the authoritative `CardEnvelope.type -> kai-* tag` map and
37
- // arrives here as DATA, not a type. It is authored in src/primitives/card-tags.ts,
38
- // which holds that map ALONE — no Solid below it — so it is readable from source by a
39
- // Node/no-DOM project rather than only through this built entry. Before that split it
40
- // shared a module with `BUILTIN_CARD_COMPONENTS` and this module re-derived it by
41
- // convention instead; see `cardTagForType`.
42
- //
43
- // This costs a build before typecheck and before the unit suite. That is not a new
44
- // dependency: resolveManifestPath() below already requires dist/custom-elements.json,
45
- // and CI already runs `nx build ui` ahead of both.
46
- import { BUILTIN_CARD_TAGS, cardSchemaNames } from '@kitn.ai/ui/schemas';
47
-
48
- // ── CEM types ────────────────────────────────────────────────────────────────
49
-
50
- export interface CemType {
51
- text: string;
52
- }
53
-
54
- export interface CemMember {
55
- kind: 'field' | 'method';
56
- privacy?: 'public' | 'private' | 'protected';
57
- name: string;
58
- type?: CemType;
59
- description?: string;
60
- }
61
-
62
- export interface CemAttribute {
63
- name: string;
64
- fieldName?: string;
65
- type?: CemType;
66
- description?: string;
67
- }
68
-
69
- export interface CemEvent {
70
- name: string;
71
- type?: CemType;
72
- description?: string;
73
- }
74
-
75
- export interface CemCssProperty {
76
- name: string;
77
- description?: string;
78
- default?: string;
79
- }
80
-
81
- export interface CemSlot {
82
- name: string;
83
- description?: string;
84
- }
85
-
86
- export interface CemCssPart {
87
- name: string;
88
- description?: string;
89
- /** Our extension: a copy-paste styling example. */
90
- recipe?: string;
91
- }
92
-
93
- export interface Declaration {
94
- tagName?: string;
95
- name: string;
96
- kind: string;
97
- description?: string;
98
- members?: CemMember[];
99
- attributes?: CemAttribute[];
100
- events?: CemEvent[];
101
- cssProperties?: CemCssProperty[];
102
- slots?: CemSlot[];
103
- cssParts?: CemCssPart[];
104
- }
105
-
106
- interface CemModule {
107
- path?: string;
108
- declarations?: Declaration[];
109
- }
110
-
111
- interface CustomElementsManifest {
112
- modules: CemModule[];
113
- }
114
-
115
- // ── Manifest resolution ───────────────────────────────────────────────────────
116
- //
117
- // THE MANIFEST IS THIS PACKAGE'S OWN BUILD ARTIFACT, SO IT IS ADDRESSED, NOT SEARCHED
118
- // FOR. This used to walk up ten parent directories taking the first
119
- // `<dir>/dist/custom-elements.json` it found, and that is a categorically weaker
120
- // thing than it looks: "a custom-elements.json exists somewhere above me" and "THIS
121
- // package's custom-elements.json exists" are different facts, and a walk-up cannot
122
- // tell them apart. It reports success for both.
123
- //
124
- // It was not hypothetical. Measured from an agent git worktree at
125
- // `<repo>/.claude/worktrees/<agent>/packages/ui/src/agent-tooling/mcp`, the loop
126
- // climbed past the worktree's own (unbuilt) `packages/ui/dist`, out of the worktree
127
- // entirely, and bound on iteration 8 to `<repo>/dist/custom-elements.json` — a
128
- // leftover from the pre-monorepo layout, six weeks stale, 78 tags, and zero elements
129
- // declaring `cardSchemas`. The consequence is this repo's dominant failure mode in
130
- // its purest form: on an unbuilt tree the MCP manifest tests did not error, they
131
- // PASSED, 16 of 17, against an artifact from a tree nobody was working in. Two
132
- // checkouts could disagree about what they had tested and nothing said so.
133
- //
134
- // So the rule here is now: a missing manifest is a HARD FAILURE that names the path
135
- // it expected. Never a fallback, never a wider search. If this throws, the answer is
136
- // to build — not to let it find someone else's build.
137
-
138
- const PACKAGE_NAME = '@kitn.ai/ui';
139
- const MANIFEST_FILE = 'custom-elements.json';
140
-
141
- /**
142
- * `<package>/src/agent-tooling/mcp` -> `<package>`. A fixed, exact hop, and it is
143
- * CHECKED below rather than trusted: if this module is ever moved to a different
144
- * depth the derived root stops being this package and resolution throws, instead of
145
- * silently addressing whatever directory happens to sit three levels up.
146
- */
147
- const SOURCE_TO_PACKAGE_ROOT = ['..', '..', '..'] as const;
148
-
149
- /** Is `root` the root of THIS package — not merely *a* directory holding a dist/? */
150
- function isThisPackage(root: string): boolean {
151
- const manifest = join(root, 'package.json');
152
- if (!existsSync(manifest)) return false;
153
- try {
154
- return (JSON.parse(readFileSync(manifest, 'utf-8')) as { name?: string }).name === PACKAGE_NAME;
155
- } catch {
156
- return false;
157
- }
158
- }
159
-
160
- /**
161
- * Absolute path to this package's Custom Elements Manifest, or a throw naming what
162
- * it looked for.
163
- *
164
- * `fromDir` exists for the tests and defaults to this module's own directory. It is
165
- * the only way to write the check that matters: the guarantee is not "a manifest was
166
- * found", it is "THIS package's manifest was found", and the two only come apart
167
- * when there is a decoy above the origin. manifest.test.ts builds exactly that tree.
168
- */
169
- export function resolveManifestPath(
170
- fromDir: string = dirname(fileURLToPath(import.meta.url)),
171
- ): string {
172
- // 1. Bundled bin: dist/mcp.es.js and dist/custom-elements.json are siblings.
173
- // Unambiguous by construction — a sibling cannot be another checkout's artifact.
174
- const sibling = join(fromDir, MANIFEST_FILE);
175
- if (existsSync(sibling)) return sibling;
176
-
177
- // 2. Source (vitest, tsx): one exact location, derived and then verified.
178
- const packageRoot = resolve(fromDir, ...SOURCE_TO_PACKAGE_ROOT);
179
- const expected = join(packageRoot, 'dist', MANIFEST_FILE);
180
-
181
- if (!isThisPackage(packageRoot)) {
182
- throw new Error(
183
- `[${PACKAGE_NAME}] Cannot locate the Custom Elements Manifest: ${packageRoot} is not ` +
184
- `the ${PACKAGE_NAME} package root, so ${expected} would not be this package's ` +
185
- `manifest even if it existed.\n` +
186
- `Resolved from: ${fromDir}\n` +
187
- `This module must live at <package>/src/agent-tooling/mcp/ (or be bundled beside ` +
188
- `${MANIFEST_FILE} in dist/). Resolution deliberately does NOT search parent ` +
189
- `directories — finding some other checkout's manifest is worse than failing.`,
190
- );
191
- }
192
-
193
- if (!existsSync(expected)) {
194
- throw new Error(
195
- `[${PACKAGE_NAME}] Missing build artifact: ${expected}\n` +
196
- `Resolved from: ${fromDir}\n` +
197
- `The Custom Elements Manifest is generated by the build. Run \`nx build ui\` ` +
198
- `(or \`npm run build:api\` in packages/ui) and try again.\n` +
199
- `Resolution deliberately does NOT search parent directories: binding to a ` +
200
- `neighbouring checkout's manifest would make this succeed against stale data.`,
201
- );
202
- }
203
-
204
- return expected;
205
- }
206
-
207
- // ── Parsed manifest (module-level cache) ─────────────────────────────────────
208
-
209
- let _manifest: CustomElementsManifest | undefined;
210
-
211
- function getManifest(): CustomElementsManifest {
212
- if (!_manifest) {
213
- const path = resolveManifestPath();
214
- const raw = readFileSync(path, 'utf-8');
215
- _manifest = JSON.parse(raw) as CustomElementsManifest;
216
- }
217
- return _manifest;
218
- }
219
-
220
- function getDeclarations(): Declaration[] {
221
- return getManifest().modules.flatMap((m) => m.declarations ?? []);
222
- }
223
-
224
- // ── Public API ────────────────────────────────────────────────────────────────
225
-
226
- /** Returns the Declaration for a given custom-element tag, or undefined. */
227
- export function getElement(tag: string): Declaration | undefined {
228
- return getDeclarations().find((d) => d.tagName === tag);
229
- }
230
-
231
- /** Returns all custom-element tagNames, sorted alphabetically. */
232
- export function listElements(): string[] {
233
- return getDeclarations()
234
- .filter((d) => d.tagName)
235
- .map((d) => d.tagName!)
236
- .sort();
237
- }
238
-
239
- // ── Per-element entry map ─────────────────────────────────────────────────────
240
- //
241
- // A STATIC import, not an fs read off resolveManifestPath's dual-context pattern:
242
- // element-manifest.json (unlike custom-elements.json) is never copied into dist/,
243
- // so an fs read relative to this module's own URL would resolve in the vitest/source
244
- // context and 404 in the bundled dist/mcp.es.js. A static import sidesteps the gap
245
- // entirely — Rollup inlines the JSON at build time, so the bundled bin carries the
246
- // data with no runtime file dependency. NAMED import (not the whole module), matching
247
- // the same tradeoff element-diagnostics.ts already made for this file: a default
248
- // import would pull `files` in too for 0 benefit here.
249
- import { tags as ELEMENT_ENTRY_TAGS } from '../../elements/element-manifest.json';
250
-
251
- /**
252
- * The per-element entry basename for a tag, e.g. 'kai-chat' -> 'chat'.
253
- *
254
- * Read from element-manifest.json's `tags` map rather than derived by stripping
255
- * the `kai-` prefix: TEN of the eighty elements do not match that derivation
256
- * (`kai-conversations` -> `conversation-list`), so a derived path would emit a
257
- * broken import for them.
258
- */
259
- export function entryForTag(tag: string): string | undefined {
260
- return (ELEMENT_ENTRY_TAGS as Record<string, string>)[tag];
261
- }
262
-
263
- /**
264
- * The per-element entry basename for a tag the register-all bundle does NOT
265
- * carry, e.g. 'kai-remote' -> 'remote'. `undefined` for every tag `entryForTag`
266
- * already answers, and for a tag no built module registers.
267
- *
268
- * WHY THIS EXISTS. `entryForTag` reads element-manifest.json, which is generated
269
- * from the import list in register-impl.ts — so an opt-in element is absent from
270
- * it by construction, and the reference had nothing to name. It said "find the
271
- * entry point in the package's published exports", which is the one place in the
272
- * reference where "how to make this element exist" does not answer itself.
273
- *
274
- * WHY IT IS READ AND NOT DERIVED. Stripping `kai-` is wrong for ten of the eighty
275
- * elements, so guessing here risks exactly the broken import this tool exists to
276
- * catch. The fact is stated in vite.config.elements.ts, which adds an explicit
277
- * entry for each opt-in element precisely "so `@kitn.ai/ui/elements/remote`
278
- * resolves to a real dist file" — but a vite config is not shipped in the
279
- * package, so the runtime reads that intent where it LANDS: dist/elements/. A
280
- * candidate is a built module that element-manifest.json does not already claim
281
- * (plus the two non-element entries the same build emits), and it is matched to a
282
- * tag by the tag literal it registers. So the answer is the built artifact's,
283
- * confirmed against the tag rather than assumed from a filename.
284
- *
285
- * dist/elements/ is a sibling of the manifest in both contexts — the bundled bin
286
- * (dist/mcp.es.js) and vitest-over-source, which resolveManifestPath already
287
- * normalises — so this needs no second resolution strategy. A missing or
288
- * unreadable directory yields `undefined` rather than throwing: the caller's
289
- * fallback is the honest "this is opt-in" paragraph it already prints.
290
- */
291
- export function optInEntryForTag(tag: string): string | undefined {
292
- if (entryForTag(tag)) return undefined;
293
- return optInEntries().get(tag);
294
- }
295
-
296
- /** Not element entries: the register-all barrel and the DOM autoloader, both
297
- * emitted into dist/elements/ by the same per-element build. */
298
- const NON_ELEMENT_ENTRIES = new Set(['index', 'autoloader']);
299
-
300
- let _optInEntries: Map<string, string> | undefined;
301
-
302
- function optInEntries(): Map<string, string> {
303
- if (_optInEntries) return _optInEntries;
304
- _optInEntries = new Map();
305
-
306
- const dir = join(dirname(resolveManifestPath()), 'elements');
307
- let candidates: string[];
308
- try {
309
- const registered = new Set(Object.values(ELEMENT_ENTRY_TAGS as Record<string, string>));
310
- candidates = readdirSync(dir)
311
- .filter((f) => f.endsWith('.js'))
312
- .map((f) => f.slice(0, -'.js'.length))
313
- .filter((base) => !registered.has(base) && !NON_ELEMENT_ENTRIES.has(base));
314
- } catch {
315
- return _optInEntries;
316
- }
317
-
318
- // Only the tags element-manifest.json does not already answer for. Narrow on
319
- // purpose: an element module may mention a tag it merely renders, and matching
320
- // against the whole tag list would let that be read as a registration.
321
- const unclaimed = listElements().filter((t) => !entryForTag(t));
322
-
323
- for (const base of candidates) {
324
- let code: string;
325
- try {
326
- code = readFileSync(join(dir, `${base}.js`), 'utf-8');
327
- } catch {
328
- continue;
329
- }
330
- for (const tag of unclaimed) {
331
- if (!_optInEntries.has(tag) && code.includes(`"${tag}"`)) _optInEntries.set(tag, base);
332
- }
333
- }
334
-
335
- return _optInEntries;
336
- }
337
-
338
- // ── Which elements have anything to do with cards ────────────────────────────
339
- //
340
- // Two different populations, and conflating them would be the "attaches card
341
- // material to everything" failure:
342
- //
343
- // CARD-BACKED kai-confirm, kai-choice, … — one element per CardEnvelope.type.
344
- // These get a schema and a generated tool definition.
345
- // CARD HOST kai-chat, kai-message, … — the elements that RENDER a thread of
346
- // cards and therefore carry the `cardTypes` / `cardSchemas` props.
347
- // These get the wiring note, not a schema.
348
- //
349
- // Neither list is written down here. The host list is derived from the manifest; the
350
- // card-backed one is the kit's own map, read rather than guessed at. Either way an
351
- // eighth card type is covered the day it lands rather than the day someone remembers
352
- // this file.
353
-
354
- /** Cached derivations. Same lifetime as the parsed manifest above. */
355
- let _cardTags: Map<string, string> | undefined;
356
- let _cardHosts: string[] | undefined;
357
-
358
- /**
359
- * `CardEnvelope.type` -> the `kai-*` element that renders it.
360
- *
361
- * THE MAP IS IMPORTED, NOT INFERRED. `BUILTIN_CARD_TAGS` is the same object
362
- * `<kai-cards>` dispatches on in the browser, reached here through
363
- * `@kitn.ai/ui/schemas`. This function used to RE-DERIVE it by convention — the tag
364
- * is `kai-<t>` when that element exists, else the single element whose tag starts
365
- * `kai-<t>-` — which was correct against all 80 tags on this tree, `link` ->
366
- * `kai-link-preview` included, and was still a second copy of a fact the repo already
367
- * held. The eighth card type is the one that would have broken it: any type whose tag
368
- * is neither `kai-<t>` nor the sole `kai-<t>-*` had to be noticed by a human, and a
369
- * future `kai-form-field` would have made `form` ambiguous on its own. A lookup has
370
- * neither failure mode.
371
- *
372
- * WHY IT IS STILL CROSSED AGAINST THE MANIFEST. The map is authoritative for the
373
- * ASSOCIATION; only the manifest knows what actually got registered. A tag in the map
374
- * with no element behind it (a rename that missed this file) would otherwise have
375
- * `component_reference` send a harness to an element that does not exist. Entries with
376
- * no registered element are dropped, so the answer is a real tag or nothing.
377
- *
378
- * WHEN IT BREAKS, IT BREAKS LOUDLY. reference.test.ts asserts every member of
379
- * `cardSchemaNames` resolves AND that what it resolves to is in `listElements()`, so a
380
- * card type missing from the map, or pointed at a tag nobody registered, fails a test
381
- * instead of silently losing its schema in the reference.
382
- */
383
- export function cardTagForType(type: string): string | undefined {
384
- if (!_cardTags) {
385
- const present = new Set(listElements());
386
- _cardTags = new Map(Object.entries(BUILTIN_CARD_TAGS).filter(([, tag]) => present.has(tag)));
387
- }
388
- return _cardTags.get(type);
389
- }
390
-
391
- /** The inverse: which card type does this element render, if any. */
392
- export function cardTypeForTag(tag: string): string | undefined {
393
- for (const name of cardSchemaNames) {
394
- if (cardTagForType(name) === tag) return name;
395
- }
396
- return undefined;
397
- }
398
-
399
- /**
400
- * The elements that host a thread of cards, derived from the manifest: an element is
401
- * a card host exactly when it declares the `cardSchemas` prop.
402
- *
403
- * That prop is the one that carries a developer's own card schemas into the browser
404
- * validator, so "declares it" and "hosts cards" are the same fact rather than two
405
- * facts that can disagree. Today it selects kai-chat / kai-message / kai-thread /
406
- * kai-workspace; an element that grows the prop tomorrow joins without an edit here.
407
- */
408
- export function cardHostTags(): string[] {
409
- if (!_cardHosts) {
410
- _cardHosts = getDeclarations()
411
- .filter(
412
- (d) =>
413
- d.tagName !== undefined &&
414
- (d.members ?? []).some(
415
- (m) => m.kind === 'field' && m.privacy === 'public' && m.name === 'cardSchemas',
416
- ),
417
- )
418
- .map((d) => d.tagName!)
419
- .sort();
420
- }
421
- return _cardHosts;
422
- }
@@ -1,116 +0,0 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import {
3
- CallToolRequestSchema,
4
- ListToolsRequestSchema,
5
- } from '@modelcontextprotocol/sdk/types.js';
6
- import { createRequire } from 'node:module';
7
- import { z } from 'zod';
8
- import { reference } from './tools/reference';
9
- import { scaffold } from './tools/scaffold';
10
- import { theme } from './tools/theme';
11
- import { debug } from './tools/debug';
12
- import { constructTool } from './tools/construct';
13
- import type { Tool } from './tools/types';
14
- import { validateToolArgs } from './validate-args';
15
-
16
- const tools: Tool[] = [reference, scaffold, theme, debug, constructTool];
17
-
18
- const PACKAGE_NAME = '@kitn.ai/ui';
19
-
20
- /**
21
- * The `serverInfo` every MCP harness reads back on `initialize`. READ, NOT TYPED.
22
- *
23
- * This was a hand-typed `{ name: '@kitn.ai/ui', version: '0.15.0' }` and the kit kept
24
- * releasing past it, so every harness that connected was told a version ten minors
25
- * stale — the same "derive it, don't type it" failure as the CDN pins, minus their
26
- * lint. Nothing here is allowed to restate the version: `server.test.ts` reads
27
- * package.json off disk itself and compares.
28
- *
29
- * RESOLVED BY THE PACKAGE'S OWN NAME, not by path arithmetic. This module runs from
30
- * two places — `<package>/src/agent-tooling/mcp/server.ts` under vitest, and inlined
31
- * into `<package>/dist/mcp.es.js` for the bin — which sit at different depths, so a
32
- * relative hop would need one rule per context (what manifest.ts has to do, because
33
- * `dist/custom-elements.json` is a build artifact with no name to ask for). A
34
- * self-reference has no depth to get wrong: Node resolves `@kitn.ai/ui/package.json`
35
- * against the nearest package.json whose `name` matches, which is this package in
36
- * both contexts and in an install. It also never escapes into a neighbouring
37
- * checkout the way a parent-directory search can.
38
- *
39
- * WHY IT SURVIVES PUBLISHING. npm always ships package.json, `exports` carries
40
- * `"./package.json": "./package.json"` (self-reference is restricted to the exports
41
- * map, so that key is load-bearing — drop it and this throws, and the test goes red
42
- * with it), and `bin/mcp.js` imports `../dist/mcp.es.js` by its own URL, so the
43
- * resolver starts inside the installed package however it was launched (npx, global
44
- * install, symlink). Not a JSON import: that inlines the version at BUILD time, which
45
- * is a second copy that can disagree with the package.json shipped beside it, and it
46
- * would need `resolveJsonModule` on the repo's browser tsc pass as well as this one.
47
- *
48
- * A broken resolve throws instead of falling back to a placeholder — `bin/mcp.js`
49
- * turns that into a named fatal on stderr, which is the loud version. A wrong version
50
- * silently announced to every harness is the quiet one.
51
- */
52
- function packageIdentity(): { name: string; version: string } {
53
- const specifier = `${PACKAGE_NAME}/package.json`;
54
- const require = createRequire(import.meta.url);
55
- const pkg = require(specifier) as { name?: string; version?: string };
56
- if (pkg.name !== PACKAGE_NAME || typeof pkg.version !== 'string') {
57
- throw new Error(
58
- `[${PACKAGE_NAME}] Refusing to report a serverInfo that is not this package's: ` +
59
- `${specifier} resolved to ${require.resolve(specifier)}, whose name is ` +
60
- `${JSON.stringify(pkg.name)} and version ${JSON.stringify(pkg.version)}.`,
61
- );
62
- }
63
- return { name: pkg.name, version: pkg.version };
64
- }
65
-
66
- /**
67
- * The AI/UI MCP server. A stdio server (see ./stdio.ts) exposing the AI/UI tools
68
- * to any MCP harness. Registers four tools; Tasks 2–5 fill in each handler.
69
- *
70
- * The returned `Server` is augmented with `__listToolsForTest()`, a test-only
71
- * helper that returns the registered tool names without touching the transport.
72
- */
73
- export interface AiUiServer extends Server {
74
- __listToolsForTest(): string[];
75
- }
76
-
77
- export function createServer(): AiUiServer {
78
- const server = new Server(packageIdentity(), { capabilities: { tools: {} } }) as AiUiServer;
79
-
80
- const byName = new Map(tools.map((t) => [t.name, t]));
81
-
82
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
83
- tools: tools.map((t) => ({
84
- name: t.name,
85
- description: t.description,
86
- // The protocol requires a JSON Schema. We use zod 4's native converter
87
- // (the repo is on zod 4); the SDK-bundled zod-to-json-schema only
88
- // understands zod 3 and emits an empty schema for our zod 4 objects.
89
- inputSchema: z.toJSONSchema(t.inputSchema) as Record<string, unknown>,
90
- })),
91
- }));
92
-
93
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
94
- const tool = byName.get(request.params.name);
95
- if (!tool) {
96
- return {
97
- isError: true,
98
- content: [{ type: 'text', text: `Unknown tool: ${request.params.name}` }],
99
- };
100
- }
101
- const args = request.params.arguments ?? {};
102
- // Enforce the schema each tool ADVERTISES (additionalProperties: false +
103
- // required) — one path for all four tools. Without this, a wrong key was
104
- // silently ignored and the handler answered a different question (see
105
- // validate-args.ts for the observed failure).
106
- const problem = validateToolArgs(tool.name, tool.inputSchema, args);
107
- if (problem) {
108
- return { isError: true, content: [{ type: 'text', text: problem }] };
109
- }
110
- return tool.handler(args);
111
- });
112
-
113
- server.__listToolsForTest = () => tools.map((t) => t.name);
114
-
115
- return server;
116
- }
@@ -1,18 +0,0 @@
1
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
- import { createServer } from './server';
3
-
4
- /**
5
- * Build entry for the AI/UI MCP server. Connects the server (./server.ts) to a
6
- * stdio transport so any MCP harness (Claude Code, Codex, …) can drive it over
7
- * stdin/stdout. Compiled to dist/mcp.es.js by vite.config.mcp.ts and launched by
8
- * bin/mcp.js, which handles fatal errors / exit (this file stays free of Node
9
- * globals so it typechecks under the repo's vite/client-only tsconfig).
10
- */
11
- export async function startStdioServer(): Promise<void> {
12
- const server = createServer();
13
- const transport = new StdioServerTransport();
14
- await server.connect(transport);
15
- }
16
-
17
- // Auto-start when imported as the entry (the only consumer is bin/mcp.js).
18
- startStdioServer();
@@ -1,130 +0,0 @@
1
- import { z } from 'zod';
2
- import type { Tool } from './types';
3
- import { validateConstruct, CONSTRUCT_SCHEMA_URL } from '../../construct/schema';
4
-
5
- /**
6
- * construct — turn-by-turn authoring of a kitn construct (one JSON file → one
7
- * web component). Stateless by design: the HARNESS owns the construct file;
8
- * every call carries the full construct for THIS turn — that is what makes
9
- * turn 40 safe, there is no server-side draft to corrupt.
10
- *
11
- * Two entry shapes: `intent` alone returns a STARTER construct plus the
12
- * real-choice questions the intent leaves open (menu-honesty: never ask a
13
- * question the intent already answers). `construct` (optionally with
14
- * `intent`) validates — rejection is a NORMAL, non-error result, not a thrown
15
- * error, because an invalid turn does not change the file: the previous good
16
- * construct still stands.
17
- *
18
- * NOTE on the advertised schema: `Tool.inputSchema` is a plain `z.ZodObject`,
19
- * and both `server.ts` (`z.toJSONSchema`) and `validate-args.ts`
20
- * (`schema.shape`) need that exact shape — a `.superRefine` wrapper is a
21
- * `ZodEffects`-like type with no `.shape`, so it can't be `tool.inputSchema`.
22
- * The advertised schema therefore stays a plain `.strict()` object; the
23
- * "at least one of intent/construct" rule is enforced here in the handler
24
- * with the same message the skeleton's superRefine would have produced.
25
- */
26
-
27
- const inputSchema = z
28
- .object({
29
- intent: z
30
- .string()
31
- .min(1)
32
- .optional()
33
- .describe('What the author wants, in their words. Alone: returns a starter construct.'),
34
- construct: z
35
- .record(z.string(), z.unknown())
36
- .optional()
37
- .describe('The FULL construct JSON for this turn. The harness owns the file; send all of it every turn.'),
38
- })
39
- .strict();
40
-
41
- function starterFor(intent: string) {
42
- // Derive what the intent already implies; ask only what it leaves open.
43
- const impliesWidget = /widget|embed|bubble|corner|launcher/i.test(intent);
44
- const name = 'my-chat'; // real-choice: always ask for the tag name (it is theirs)
45
- return {
46
- construct: {
47
- $schema: CONSTRUCT_SCHEMA_URL,
48
- name,
49
- layout: 'widget',
50
- provider: { mode: 'mock' },
51
- },
52
- stated: impliesWidget ? ['layout: widget (implied by your request)'] : [],
53
- questions: [
54
- `What should the element tag be? (kebab-case, e.g. "acme-support"; using "${name}" until you say)`,
55
- ...(impliesWidget ? [] : ['Layout: widget, fullscreen, aside, split, or custom?']),
56
- ],
57
- };
58
- }
59
-
60
- export const constructTool: Tool = {
61
- name: 'construct',
62
- description:
63
- 'Author a kitn construct (one JSON file → one web component) turn by turn. ' +
64
- 'Send the full construct each turn; invalid turns come back REJECTED with per-path reasons and the previous good construct stands. ' +
65
- `Schema: ${CONSTRUCT_SCHEMA_URL}. Preview with "kai dev <file>".`,
66
- inputSchema,
67
- handler: async (args) => {
68
- const { intent, construct } = args as { intent?: string; construct?: Record<string, unknown> };
69
-
70
- if (!intent && !construct) {
71
- return {
72
- isError: true,
73
- content: [{ type: 'text', text: 'construct: pass intent, construct, or both' }],
74
- };
75
- }
76
-
77
- if (!construct) {
78
- const s = starterFor(intent ?? '');
79
- return {
80
- content: [
81
- {
82
- type: 'text',
83
- text: [
84
- 'STARTER construct (mock provider — keyless, previews immediately):',
85
- '```json',
86
- JSON.stringify(s.construct, null, 2),
87
- '```',
88
- ...s.stated,
89
- ...s.questions,
90
- ].join('\n'),
91
- },
92
- ],
93
- };
94
- }
95
-
96
- const out = validateConstruct(construct);
97
- if (!out.ok) {
98
- return {
99
- content: [
100
- {
101
- type: 'text',
102
- text: [
103
- 'REJECTED — this turn does not change the file; the previous good construct stands.',
104
- ...out.problems.map((p) => ` ${p.path || '(root)'}: ${p.message}`),
105
- ].join('\n'),
106
- },
107
- ],
108
- };
109
- }
110
-
111
- const c = out.construct;
112
- return {
113
- content: [
114
- {
115
- type: 'text',
116
- text: [
117
- `VALID: <${c.name}> (${c.layout}, ${c.provider.mode}).`,
118
- '```json',
119
- JSON.stringify(c, null, 2),
120
- '```',
121
- `Preview: kai dev <file>. Compile: kai compile <file>.`,
122
- ...(c.provider.mode === 'endpoint'
123
- ? ['Backend route: use the scaffold tool — it emits a compiling route for your framework and wire.']
124
- : []),
125
- ].join('\n'),
126
- },
127
- ],
128
- };
129
- },
130
- };