@kitn.ai/ui 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
- package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
- package/dist/agent-tooling/construct/public.d.ts +15 -0
- package/dist/agent-tooling/construct/schema.d.ts +111 -0
- package/dist/arrow-down-D783iMJj.js +1 -0
- package/dist/arrow-left-0VLM5kyg.js +1 -0
- package/dist/artifact-DGjzHYUT.js +1 -0
- package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
- package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
- package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
- package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
- package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
- package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
- package/dist/check-CiEOVnEN.js +1 -0
- package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
- package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
- package/dist/chevron-down-CSobuZRG.js +1 -0
- package/dist/chevron-right-DR9ZAP-2.js +1 -0
- package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
- package/dist/circle-BC66EYF7.js +1 -0
- package/dist/circle-check-BqmahW0O.js +1 -0
- package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
- package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
- package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
- package/dist/components/builder-composer-triggers.d.ts +62 -0
- package/dist/components/builder-layout.d.ts +54 -0
- package/dist/components/builder-message-actions.d.ts +72 -0
- package/dist/components/builder-panel.d.ts +189 -0
- package/dist/components/builder-preview.d.ts +11 -0
- package/dist/components/builder-shell-controls.d.ts +69 -0
- package/dist/components/builder-skeleton.d.ts +58 -0
- package/dist/components/builder-start.d.ts +75 -0
- package/dist/components/builder-workspace-variants.d.ts +23 -0
- package/dist/components/captions.d.ts +66 -0
- package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
- package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
- package/dist/construct-cli.es.js +3 -3
- package/dist/construct.d.ts +5 -0
- package/dist/construct.js +327 -0
- package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
- package/dist/controllable-BagRpyHv.js +1 -0
- package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
- package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
- package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
- package/dist/core-C8fzo39E.js +1 -12
- package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
- package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
- package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
- package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
- package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
- package/dist/define-CI0y3eE4.js +1 -0
- package/dist/define.js +40 -40
- package/dist/define.server.js +45 -45
- package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
- package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- package/dist/elements/card.js +1 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkbox-group.js +1 -1
- package/dist/elements/checkbox.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- package/dist/elements/coachmark.js +1 -1
- package/dist/elements/code-block.js +1 -1
- package/dist/elements/command.js +1 -1
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.js +1 -1
- package/dist/elements/confirm-card.js +1 -1
- package/dist/elements/context-meter.js +1 -1
- package/dist/elements/conversation-item.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.js +1 -1
- package/dist/elements/dropdown.js +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/embed.js +1 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- package/dist/elements/hover-card.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- package/dist/elements/link-preview.js +1 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.js +1 -1
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- package/dist/elements/nav.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-grid.js +1 -1
- package/dist/elements/pane-group.js +1 -1
- package/dist/elements/pane.js +1 -1
- package/dist/elements/popover.js +1 -1
- package/dist/elements/progress-bar.js +1 -1
- package/dist/elements/prompt-dock.js +1 -1
- package/dist/elements/prompt-input.js +1 -1
- package/dist/elements/prompt-suggestions.js +1 -1
- package/dist/elements/radio-group.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +1 -1
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/select.js +1 -1
- package/dist/elements/separator.js +1 -1
- package/dist/elements/setting-item.js +1 -1
- package/dist/elements/settings-group.js +1 -1
- package/dist/elements/skeleton.js +1 -1
- package/dist/elements/slider.js +1 -1
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
- package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
- package/dist/engine-javascript-C1x7zo1_.js +1 -141
- package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
- package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
- package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
- package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
- package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
- package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
- package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
- package/dist/index.js +1741 -1725
- package/dist/index.server.js +1582 -1566
- package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
- package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
- package/dist/kai.es.js +1 -1
- package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
- package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
- package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
- package/dist/loader-KvJB6NrT.js +1 -0
- package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
- package/dist/mcp.es.js +9 -5
- package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
- package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
- package/dist/message-circle-BPpp5QKv.js +1 -0
- package/dist/message-square-BLbsd9BJ.js +1 -0
- package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
- package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
- package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
- package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
- package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
- package/dist/play-BXy1u7rW.js +1 -0
- package/dist/primitives/use-auto-resize.d.ts +11 -0
- package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
- package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
- package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
- package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
- package/dist/register-impl-DvEnhIxx.js +424 -0
- package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
- package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
- package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
- package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
- package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
- package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
- package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
- package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
- package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
- package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
- package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
- package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
- package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
- package/dist/solid.d.ts +6 -0
- package/dist/solid.js +259 -254
- package/dist/solid.server.js +259 -254
- package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
- package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
- package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
- package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
- package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
- package/dist/text-shimmer-BSzgEnDH.js +1 -0
- package/dist/textarea-DrYNt_0z.js +1 -0
- package/dist/theme.tokens.css +22 -21
- package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
- package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
- package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
- package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
- package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
- package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
- package/dist/ui/color-field.d.ts +48 -0
- package/dist/ui/textarea.d.ts +4 -0
- package/dist/ui/toggle-chip.d.ts +40 -0
- package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
- package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
- package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
- package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
- package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
- package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
- package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
- package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
- package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
- package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
- package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
- package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
- package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
- package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
- package/dist/x-eiO9V6J6.js +1 -0
- package/{src/elements/styles.css → kit-base.css} +27 -44
- package/package.json +32 -17
- package/solid.css +33 -0
- package/theme.css +39 -23
- package/bin/route.test.js +0 -58
- package/dist/arrow-down-CjRU3JgV.js +0 -1
- package/dist/arrow-left-Bnpb1UEW.js +0 -1
- package/dist/artifact-Bwt7OgcR.js +0 -1
- package/dist/check-njkVdZu2.js +0 -1
- package/dist/chevron-down-B72s6PXR.js +0 -1
- package/dist/chevron-right-BatuHzUm.js +0 -1
- package/dist/circle-check-B62pODB3.js +0 -1
- package/dist/circle-zx0ByzY9.js +0 -1
- package/dist/controllable-CnGpMF6r.js +0 -1
- package/dist/define-By-uL588.js +0 -1
- package/dist/loader-BM4CEz4G.js +0 -1
- package/dist/message-circle-DruwObfX.js +0 -1
- package/dist/message-square-BG6q6mlm.js +0 -1
- package/dist/play-BvKKq3fX.js +0 -1
- package/dist/register-impl-B1hLkrI8.js +0 -424
- package/dist/text-shimmer-Dcj1MHuq.js +0 -1
- package/dist/textarea-Dpvbngbg.js +0 -1
- package/dist/x-Z5UntkIJ.js +0 -1
- package/src/agent-tooling/README.md +0 -192
- package/src/agent-tooling/archetypes.ts +0 -205
- package/src/agent-tooling/catalog/README.md +0 -676
- package/src/agent-tooling/catalog/catalog-types.ts +0 -231
- package/src/agent-tooling/catalog/fabrications.ts +0 -96
- package/src/agent-tooling/catalog/invariants.ts +0 -284
- package/src/agent-tooling/catalog/labs-titles.ts +0 -114
- package/src/agent-tooling/catalog/scenarios.ts +0 -87
- package/src/agent-tooling/catalog/surfaces.ts +0 -347
- package/src/agent-tooling/construct/cli-entry.ts +0 -8
- package/src/agent-tooling/construct/cli.ts +0 -147
- package/src/agent-tooling/construct/codegen.ts +0 -1635
- package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
- package/src/agent-tooling/construct/dev.ts +0 -148
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
- package/src/agent-tooling/construct/schema.ts +0 -452
- package/src/agent-tooling/integrations/anthropic.ts +0 -442
- package/src/agent-tooling/integrations/cloudflare.ts +0 -218
- package/src/agent-tooling/integrations/langgraph.ts +0 -133
- package/src/agent-tooling/integrations/mastra.ts +0 -182
- package/src/agent-tooling/integrations/mock.ts +0 -148
- package/src/agent-tooling/integrations/ollama.ts +0 -97
- package/src/agent-tooling/integrations/openai.ts +0 -95
- package/src/agent-tooling/integrations/openrouter.ts +0 -82
- package/src/agent-tooling/integrations/pi.ts +0 -176
- package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
- package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
- package/src/agent-tooling/mcp/manifest.ts +0 -422
- package/src/agent-tooling/mcp/server.ts +0 -116
- package/src/agent-tooling/mcp/stdio.ts +0 -18
- package/src/agent-tooling/mcp/tools/construct.ts +0 -130
- package/src/agent-tooling/mcp/tools/debug.ts +0 -621
- package/src/agent-tooling/mcp/tools/reference.ts +0 -980
- package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
- package/src/agent-tooling/mcp/tools/theme.ts +0 -456
- package/src/agent-tooling/mcp/tools/types.ts +0 -14
- package/src/agent-tooling/mcp/validate-args.ts +0 -141
- package/src/agent-tooling/recipes/composed-thread.ts +0 -714
- package/src/agent-tooling/recipes/index.ts +0 -22
- package/src/agent-tooling/recipes/types.ts +0 -32
- package/src/agent-tooling/registry.ts +0 -132
- package/src/agent-tooling/route-emit.ts +0 -305
- package/src/agent-tooling/types.ts +0 -390
- package/src/components/artifact-card.tsx +0 -120
- package/src/components/artifact.tsx +0 -914
- package/src/components/attachment-types.ts +0 -66
- package/src/components/attachments.tsx +0 -536
- package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
- package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
- package/src/components/audio-visualizer/fit-scale.ts +0 -112
- package/src/components/audio-visualizer/index.tsx +0 -528
- package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
- package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
- package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
- package/src/components/audio-visualizer/sizes.ts +0 -54
- package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
- package/src/components/audio-visualizer/variant-bar.tsx +0 -175
- package/src/components/audio-visualizer/variant-custom.tsx +0 -344
- package/src/components/audio-visualizer/variant-grid.tsx +0 -175
- package/src/components/audio-visualizer/variant-radial.tsx +0 -163
- package/src/components/audio-visualizer/variant-wave.tsx +0 -130
- package/src/components/audio-visualizer/wave.glsl.ts +0 -130
- package/src/components/card-fallback.tsx +0 -60
- package/src/components/card-renderer.tsx +0 -220
- package/src/components/card.tsx +0 -212
- package/src/components/chain-of-thought.tsx +0 -348
- package/src/components/chat-container.tsx +0 -89
- package/src/components/chat-scope-picker.tsx +0 -57
- package/src/components/chat-thread.tsx +0 -1014
- package/src/components/checkpoint.tsx +0 -88
- package/src/components/choice-card.tsx +0 -743
- package/src/components/coachmark.tsx +0 -249
- package/src/components/code-block.tsx +0 -181
- package/src/components/composer-dom.ts +0 -159
- package/src/components/composer-highlight.ts +0 -242
- package/src/components/composer-history.ts +0 -82
- package/src/components/composer.tsx +0 -1075
- package/src/components/confirm-card.tsx +0 -402
- package/src/components/context.tsx +0 -377
- package/src/components/conversation-item.tsx +0 -241
- package/src/components/conversation-list.tsx +0 -429
- package/src/components/conversation-panel.tsx +0 -118
- package/src/components/dismissed-stub.tsx +0 -80
- package/src/components/embed.tsx +0 -200
- package/src/components/empty.tsx +0 -177
- package/src/components/feedback-bar.tsx +0 -166
- package/src/components/file-tree.tsx +0 -530
- package/src/components/file-upload.tsx +0 -167
- package/src/components/form-widgets.tsx +0 -525
- package/src/components/form.tsx +0 -1296
- package/src/components/home-panel.tsx +0 -159
- package/src/components/image.tsx +0 -65
- package/src/components/link-preview.tsx +0 -195
- package/src/components/loader.tsx +0 -367
- package/src/components/markdown.tsx +0 -162
- package/src/components/message-skills.tsx +0 -40
- package/src/components/message.tsx +0 -765
- package/src/components/model-switcher.tsx +0 -132
- package/src/components/prompt-input.tsx +0 -188
- package/src/components/prompt-suggestion.tsx +0 -150
- package/src/components/reasoning.tsx +0 -293
- package/src/components/response-compare-types.ts +0 -152
- package/src/components/response-compare.tsx +0 -455
- package/src/components/response-stream.tsx +0 -109
- package/src/components/screen.tsx +0 -181
- package/src/components/scroll-button.tsx +0 -93
- package/src/components/source.tsx +0 -192
- package/src/components/tasks-card.tsx +0 -801
- package/src/components/text-shimmer.tsx +0 -37
- package/src/components/thinking-bar.tsx +0 -50
- package/src/components/thread.tsx +0 -228
- package/src/components/toast.tsx +0 -503
- package/src/components/tool-classify.ts +0 -26
- package/src/components/tool-types.ts +0 -49
- package/src/components/tool.tsx +0 -190
- package/src/components/use-card-resolution.ts +0 -44
- package/src/components/voice-input.tsx +0 -222
- package/src/components/voice-output.tsx +0 -242
- package/src/components/widget-tab-bar.tsx +0 -73
- package/src/components/workspace-shell.tsx +0 -285
- package/src/diagnostics/hook.ts +0 -352
- package/src/diagnostics/index.ts +0 -82
- package/src/diagnostics/report-request.ts +0 -296
- package/src/elements/agent-card.tsx +0 -67
- package/src/elements/artifact.tsx +0 -194
- package/src/elements/attachments.tsx +0 -140
- package/src/elements/audio-visualizer.tsx +0 -227
- package/src/elements/autoloader.ts +0 -89
- package/src/elements/avatar.tsx +0 -33
- package/src/elements/badge.tsx +0 -32
- package/src/elements/button.tsx +0 -149
- package/src/elements/card.tsx +0 -133
- package/src/elements/cards.tsx +0 -266
- package/src/elements/chain-of-thought.tsx +0 -141
- package/src/elements/chat-scope-picker.tsx +0 -65
- package/src/elements/chat-types.ts +0 -102
- package/src/elements/chat-workspace.tsx +0 -188
- package/src/elements/chat.tsx +0 -304
- package/src/elements/checkbox-group.tsx +0 -164
- package/src/elements/checkbox.tsx +0 -134
- package/src/elements/checkpoint.tsx +0 -47
- package/src/elements/choice.tsx +0 -100
- package/src/elements/coachmark.tsx +0 -90
- package/src/elements/code-block.tsx +0 -60
- package/src/elements/command.tsx +0 -197
- package/src/elements/compare.tsx +0 -111
- package/src/elements/compiled.css +0 -2
- package/src/elements/composer.tsx +0 -162
- package/src/elements/confirm-card.tsx +0 -76
- package/src/elements/context-meter.tsx +0 -107
- package/src/elements/conversation-item.tsx +0 -120
- package/src/elements/conversation-list.tsx +0 -203
- package/src/elements/css.ts +0 -5
- package/src/elements/default-input.tsx +0 -392
- package/src/elements/define-entry.ts +0 -12
- package/src/elements/define.tsx +0 -563
- package/src/elements/diagnostic-events.ts +0 -114
- package/src/elements/dialog.tsx +0 -145
- package/src/elements/disclosure.ts +0 -95
- package/src/elements/dock.tsx +0 -215
- package/src/elements/dropdown.tsx +0 -123
- package/src/elements/editable-label.tsx +0 -140
- package/src/elements/element-data-types.ts +0 -152
- package/src/elements/element-diagnostics.ts +0 -392
- package/src/elements/element-manifest.json +0 -354
- package/src/elements/element-nonscalar.json +0 -187
- package/src/elements/element-types.d.ts +0 -4353
- package/src/elements/embed.tsx +0 -35
- package/src/elements/empty.tsx +0 -29
- package/src/elements/feedback-bar.tsx +0 -66
- package/src/elements/file-tree.tsx +0 -62
- package/src/elements/file-upload.tsx +0 -44
- package/src/elements/form.tsx +0 -94
- package/src/elements/hover-card.tsx +0 -80
- package/src/elements/icon.tsx +0 -41
- package/src/elements/image.tsx +0 -32
- package/src/elements/input.tsx +0 -492
- package/src/elements/kbd.tsx +0 -45
- package/src/elements/link-preview.tsx +0 -34
- package/src/elements/loader.tsx +0 -25
- package/src/elements/markdown.tsx +0 -38
- package/src/elements/menu.tsx +0 -241
- package/src/elements/message-skills.tsx +0 -83
- package/src/elements/message.tsx +0 -361
- package/src/elements/model-switcher.tsx +0 -121
- package/src/elements/nav.tsx +0 -87
- package/src/elements/notice.tsx +0 -53
- package/src/elements/pane-grid.tsx +0 -111
- package/src/elements/pane-group.tsx +0 -119
- package/src/elements/pane.tsx +0 -129
- package/src/elements/popover.tsx +0 -81
- package/src/elements/progress-bar.tsx +0 -39
- package/src/elements/prompt-dock.tsx +0 -82
- package/src/elements/prompt-input.tsx +0 -240
- package/src/elements/prompt-suggestions.tsx +0 -113
- package/src/elements/radio-group.tsx +0 -129
- package/src/elements/reasoning.tsx +0 -71
- package/src/elements/register-impl.ts +0 -148
- package/src/elements/register.ts +0 -76
- package/src/elements/remote.tsx +0 -225
- package/src/elements/resizable.globals.d.ts +0 -36
- package/src/elements/resizable.tsx +0 -704
- package/src/elements/response-stream.tsx +0 -40
- package/src/elements/screen.tsx +0 -90
- package/src/elements/scroll-area.tsx +0 -33
- package/src/elements/scroll-button.tsx +0 -179
- package/src/elements/search.tsx +0 -185
- package/src/elements/segmented.tsx +0 -129
- package/src/elements/select.tsx +0 -165
- package/src/elements/separator.tsx +0 -36
- package/src/elements/setting-item.tsx +0 -50
- package/src/elements/settings-group.tsx +0 -37
- package/src/elements/skeleton.tsx +0 -45
- package/src/elements/slider.tsx +0 -171
- package/src/elements/slot-text.ts +0 -73
- package/src/elements/slots.ts +0 -787
- package/src/elements/source.tsx +0 -126
- package/src/elements/status.tsx +0 -42
- package/src/elements/switch.tsx +0 -118
- package/src/elements/tabs.tsx +0 -95
- package/src/elements/tasks.tsx +0 -103
- package/src/elements/text-shimmer.tsx +0 -28
- package/src/elements/thinking-bar.tsx +0 -43
- package/src/elements/thread.tsx +0 -139
- package/src/elements/toast.tsx +0 -106
- package/src/elements/tool.tsx +0 -78
- package/src/elements/tooltip.tsx +0 -85
- package/src/elements/validate-messages.ts +0 -76
- package/src/elements/voice-input.tsx +0 -100
- package/src/elements/voice-output.tsx +0 -82
- package/src/index.ts +0 -430
- package/src/primitives/audio-bands.ts +0 -174
- package/src/primitives/card-component-types.ts +0 -63
- package/src/primitives/card-contract.ts +0 -80
- package/src/primitives/card-data-types.ts +0 -361
- package/src/primitives/card-host.tsx +0 -37
- package/src/primitives/card-recovery.ts +0 -160
- package/src/primitives/card-registry.tsx +0 -78
- package/src/primitives/card-resolution.ts +0 -36
- package/src/primitives/card-routing.ts +0 -85
- package/src/primitives/card-schemas/artifact.schema.json +0 -92
- package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
- package/src/primitives/card-schemas/card-event.schema.json +0 -12
- package/src/primitives/card-schemas/choice.schema.json +0 -75
- package/src/primitives/card-schemas/confirm.schema.json +0 -65
- package/src/primitives/card-schemas/embed.schema.json +0 -63
- package/src/primitives/card-schemas/form.result.schema.json +0 -7
- package/src/primitives/card-schemas/form.schema.json +0 -53
- package/src/primitives/card-schemas/link.schema.json +0 -54
- package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
- package/src/primitives/card-schemas/tasks.schema.json +0 -83
- package/src/primitives/card-tags.ts +0 -61
- package/src/primitives/card-validate-cards.ts +0 -255
- package/src/primitives/card-validate-schemas.ts +0 -58
- package/src/primitives/card-validate.ts +0 -131
- package/src/primitives/chat-config.tsx +0 -103
- package/src/primitives/composer-model.ts +0 -49
- package/src/primitives/composer-triggers.ts +0 -35
- package/src/primitives/controllable.ts +0 -21
- package/src/primitives/conversation-store.ts +0 -248
- package/src/primitives/create-kai-chat.ts +0 -66
- package/src/primitives/create-tween.ts +0 -266
- package/src/primitives/embed-providers.ts +0 -254
- package/src/primitives/field-mask.ts +0 -256
- package/src/primitives/field-semantics.ts +0 -115
- package/src/primitives/highlighter.ts +0 -157
- package/src/primitives/input-mask.ts +0 -853
- package/src/primitives/link-preview.ts +0 -87
- package/src/primitives/message-feedback.ts +0 -124
- package/src/primitives/pdf-preview.ts +0 -121
- package/src/primitives/toast-store.ts +0 -338
- package/src/primitives/url-scheme-policy.ts +0 -70
- package/src/primitives/use-audio-analysis.ts +0 -340
- package/src/primitives/use-auto-resize.ts +0 -31
- package/src/primitives/use-resize-observer.ts +0 -45
- package/src/primitives/use-sequencer.ts +0 -72
- package/src/primitives/use-speech-recognition.ts +0 -146
- package/src/primitives/use-stick-to-bottom.ts +0 -75
- package/src/primitives/use-text-stream.ts +0 -143
- package/src/primitives/use-voice-recorder.ts +0 -62
- package/src/primitives/visualizer-sequences.ts +0 -350
- package/src/remote/host-embed.ts +0 -345
- package/src/remote/index.ts +0 -2
- package/src/remote/origin.ts +0 -30
- package/src/remote/provider-runtime.ts +0 -262
- package/src/remote/provider.ts +0 -2
- package/src/remote/validate.ts +0 -22
- package/src/remote/version.ts +0 -12
- package/src/remote/wire.ts +0 -48
- package/src/schemas/from-tool-call.ts +0 -151
- package/src/schemas/index.ts +0 -341
- package/src/schemas/provider-subsets.ts +0 -538
- package/src/schemas/registry.ts +0 -355
- package/src/schemas/tool-defs.ts +0 -793
- package/src/solid.ts +0 -173
- package/src/state/index.ts +0 -44
- package/src/state/messages.ts +0 -53
- package/src/state/mock.ts +0 -297
- package/src/state/parts.ts +0 -295
- package/src/state/persistence.ts +0 -180
- package/src/state/stream.ts +0 -246
- package/src/state/suggestions.ts +0 -9
- package/src/state/threads.ts +0 -142
- package/src/test-utils/fake-clock.ts +0 -88
- package/src/types.ts +0 -95
- package/src/ui/action-icons.ts +0 -53
- package/src/ui/agent-card.tsx +0 -218
- package/src/ui/avatar.tsx +0 -23
- package/src/ui/badge.tsx +0 -21
- package/src/ui/button.tsx +0 -49
- package/src/ui/card.tsx +0 -245
- package/src/ui/checkbox-group.tsx +0 -153
- package/src/ui/checkbox.tsx +0 -63
- package/src/ui/collapsible.tsx +0 -163
- package/src/ui/command.tsx +0 -103
- package/src/ui/dialog.tsx +0 -223
- package/src/ui/dock.tsx +0 -630
- package/src/ui/dropdown.tsx +0 -636
- package/src/ui/editable-label.tsx +0 -112
- package/src/ui/hover-card.tsx +0 -345
- package/src/ui/icon.tsx +0 -167
- package/src/ui/input.tsx +0 -391
- package/src/ui/kbd.tsx +0 -118
- package/src/ui/nav.tsx +0 -282
- package/src/ui/notice.tsx +0 -84
- package/src/ui/overlay.tsx +0 -277
- package/src/ui/pane-grid.tsx +0 -117
- package/src/ui/pane-group.tsx +0 -291
- package/src/ui/pane.tsx +0 -193
- package/src/ui/popover.tsx +0 -106
- package/src/ui/progress-bar.tsx +0 -83
- package/src/ui/prompt-dock.tsx +0 -145
- package/src/ui/radio.tsx +0 -150
- package/src/ui/resizable.tsx +0 -693
- package/src/ui/scroll-area.tsx +0 -26
- package/src/ui/segmented.tsx +0 -109
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -10
- package/src/ui/settings-group.tsx +0 -67
- package/src/ui/skeleton.tsx +0 -73
- package/src/ui/slider.tsx +0 -178
- package/src/ui/status.tsx +0 -48
- package/src/ui/switch.tsx +0 -119
- package/src/ui/tabs.tsx +0 -168
- package/src/ui/textarea.tsx +0 -21
- package/src/ui/tooltip.tsx +0 -118
- package/src/utils/cn.ts +0 -30
- package/src/wire/chunk.ts +0 -248
- package/src/wire/consume.ts +0 -599
- package/src/wire/diagnostics.ts +0 -727
- package/src/wire/encode-probe.ts +0 -214
- package/src/wire/encode.ts +0 -947
- package/src/wire/files.ts +0 -342
- package/src/wire/formats/anthropic.ts +0 -274
- package/src/wire/formats/openai.ts +0 -228
- package/src/wire/index.ts +0 -95
- package/src/wire/media-types.ts +0 -344
- package/src/wire/read.ts +0 -396
- package/src/wire/sink-helpers.ts +0 -50
- package/src/wire/sse.ts +0 -153
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure `state -> highlight set` mappers for the audio visualizer variants.
|
|
3
|
-
*
|
|
4
|
-
* Ported from livekit/components-js `packages/shadcn/hooks/agents-ui/`
|
|
5
|
-
* (Apache License 2.0). Upstream runs four separate animator hooks, each with
|
|
6
|
-
* its own requestAnimationFrame loop. We keep the sequences (verbatim) but move
|
|
7
|
-
* the timing into one shared driver, `use-sequencer.ts`.
|
|
8
|
-
*
|
|
9
|
-
* Every generator returns a NON-EMPTY array so callers can index with
|
|
10
|
-
* `sequence[tick % sequence.length]` without a guard.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export type VisualizerState =
|
|
14
|
-
| 'idle'
|
|
15
|
-
| 'connecting'
|
|
16
|
-
| 'listening'
|
|
17
|
-
| 'thinking'
|
|
18
|
-
| 'speaking'
|
|
19
|
-
| 'disconnected';
|
|
20
|
-
|
|
21
|
-
export interface Coordinate {
|
|
22
|
-
x: number;
|
|
23
|
-
y: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const KNOWN: readonly VisualizerState[] = [
|
|
27
|
-
'idle',
|
|
28
|
-
'connecting',
|
|
29
|
-
'listening',
|
|
30
|
-
'thinking',
|
|
31
|
-
'speaking',
|
|
32
|
-
// First-class since 2026-08-10 (Rob): the dead-connection look (flat wave,
|
|
33
|
-
// nothing lit) upstream renders for its 'disconnected' state. It was an
|
|
34
|
-
// alias for 'idle' until idle adopted upstream's gentle wave, which left
|
|
35
|
-
// the flat line unreachable.
|
|
36
|
-
'disconnected',
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* LiveKit's AgentState carries room-lifecycle values that mean nothing here.
|
|
41
|
-
* Accept them so markup ported from LiveKit works unchanged.
|
|
42
|
-
*/
|
|
43
|
-
const ALIASES: Record<string, VisualizerState> = {
|
|
44
|
-
// Both are dead-connection looks upstream, so 'failed' rides with
|
|
45
|
-
// 'disconnected' rather than 'idle'.
|
|
46
|
-
failed: 'disconnected',
|
|
47
|
-
initializing: 'connecting',
|
|
48
|
-
'pre-connect-buffering': 'connecting',
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export function normalizeState(input: string | undefined): VisualizerState {
|
|
52
|
-
if (!input) return 'idle';
|
|
53
|
-
if ((KNOWN as readonly string[]).includes(input)) return input as VisualizerState;
|
|
54
|
-
return ALIASES[input] ?? 'idle';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ---------------------------------------------------------------- bar
|
|
58
|
-
|
|
59
|
-
export function barSequence(state: VisualizerState, barCount: number): number[][] {
|
|
60
|
-
switch (state) {
|
|
61
|
-
case 'connecting': {
|
|
62
|
-
// A mirrored pair sweeping outward: [0, n-1], [1, n-2], ...
|
|
63
|
-
const seq: number[][] = [];
|
|
64
|
-
for (let x = 0; x < barCount; x++) seq.push([x, barCount - 1 - x]);
|
|
65
|
-
return seq.length ? seq : [[]];
|
|
66
|
-
}
|
|
67
|
-
case 'listening':
|
|
68
|
-
case 'thinking': {
|
|
69
|
-
// Blink the center bar. -1 is a deliberate no-index frame (the "off" beat).
|
|
70
|
-
return [[Math.floor(barCount / 2)], [-1]];
|
|
71
|
-
}
|
|
72
|
-
case 'speaking':
|
|
73
|
-
return [Array.from({ length: barCount }, (_, i) => i)];
|
|
74
|
-
// Dead-connection look: mirrors idle (nothing lit) for now. A dedicated
|
|
75
|
-
// arm so the pending LiveKit disconnected-state measurement can adjust
|
|
76
|
-
// it in one line.
|
|
77
|
-
case 'disconnected':
|
|
78
|
-
return [[]];
|
|
79
|
-
case 'idle':
|
|
80
|
-
default:
|
|
81
|
-
return [[]];
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function barInterval(state: VisualizerState, barCount: number): number {
|
|
86
|
-
switch (state) {
|
|
87
|
-
// The whole sweep should take 2s regardless of how many bars it crosses.
|
|
88
|
-
case 'connecting':
|
|
89
|
-
return 2000 / Math.max(1, barCount);
|
|
90
|
-
case 'listening':
|
|
91
|
-
return 500;
|
|
92
|
-
case 'thinking':
|
|
93
|
-
return 150;
|
|
94
|
-
default:
|
|
95
|
-
return 1000;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// ---------------------------------------------------------------- grid
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Walk the perimeter of a ring `spread` cells out from center, clockwise.
|
|
103
|
-
*
|
|
104
|
-
* NOTE: This diverges from upstream use-agent-audio-visualizer-grid.ts in two ways:
|
|
105
|
-
* (1) We use separate centerX and centerY (upstream uses row-center for both axes).
|
|
106
|
-
* Upstream never ships non-square grids, so the bug never manifested. Our public
|
|
107
|
-
* API is square-only too now (the grid's single `count` prop, 2026-08-09), but
|
|
108
|
-
* this function keeps taking rows/columns as plain params, so the correct
|
|
109
|
-
* arbitrary-shape handling stays -- it costs nothing and guards any future caller.
|
|
110
|
-
* (2) We distinguish spread === 0 from spread === undefined (upstream treats 0 as falsy).
|
|
111
|
-
* Again, upstream never ships spread=0 explicitly; we do for API completeness.
|
|
112
|
-
*/
|
|
113
|
-
function gridRing(rows: number, columns: number, spread: number): Coordinate[] {
|
|
114
|
-
const seq: Coordinate[] = [];
|
|
115
|
-
const centerX = Math.floor(columns / 2);
|
|
116
|
-
const centerY = Math.floor(rows / 2);
|
|
117
|
-
const topLeft = { x: Math.max(0, centerX - spread), y: Math.max(0, centerY - spread) };
|
|
118
|
-
const bottomRight = {
|
|
119
|
-
x: Math.min(columns - 1, centerX + spread),
|
|
120
|
-
y: Math.min(rows - 1, centerY + spread),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
for (let x = topLeft.x; x <= bottomRight.x; x++) seq.push({ x, y: topLeft.y });
|
|
124
|
-
for (let y = topLeft.y + 1; y <= bottomRight.y; y++) seq.push({ x: bottomRight.x, y });
|
|
125
|
-
for (let x = bottomRight.x - 1; x >= topLeft.x; x--) seq.push({ x, y: bottomRight.y });
|
|
126
|
-
for (let y = bottomRight.y - 1; y > topLeft.y; y--) seq.push({ x: topLeft.x, y });
|
|
127
|
-
|
|
128
|
-
return seq;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function gridSequence(
|
|
132
|
-
state: VisualizerState,
|
|
133
|
-
rows: number,
|
|
134
|
-
columns: number,
|
|
135
|
-
spread?: number,
|
|
136
|
-
): Coordinate[] {
|
|
137
|
-
const center = { x: Math.floor(columns / 2), y: Math.floor(rows / 2) };
|
|
138
|
-
|
|
139
|
-
switch (state) {
|
|
140
|
-
case 'connecting': {
|
|
141
|
-
const maxSpread = Math.floor(Math.max(rows, columns) / 2);
|
|
142
|
-
const clamped = spread !== undefined ? Math.min(spread, maxSpread) : maxSpread;
|
|
143
|
-
const ring = gridRing(rows, columns, clamped);
|
|
144
|
-
return ring.length ? ring : [center];
|
|
145
|
-
}
|
|
146
|
-
case 'listening': {
|
|
147
|
-
// One lit frame followed by eight dark ones: a slow heartbeat.
|
|
148
|
-
const off = { x: -1, y: -1 };
|
|
149
|
-
return [center, off, off, off, off, off, off, off, off];
|
|
150
|
-
}
|
|
151
|
-
case 'thinking': {
|
|
152
|
-
// Sweep the middle row left to right, then back.
|
|
153
|
-
const y = Math.floor(rows / 2);
|
|
154
|
-
const seq: Coordinate[] = [];
|
|
155
|
-
for (let x = 0; x < columns; x++) seq.push({ x, y });
|
|
156
|
-
for (let x = columns - 1; x >= 0; x--) seq.push({ x, y });
|
|
157
|
-
return seq.length ? seq : [center];
|
|
158
|
-
}
|
|
159
|
-
// Dead-connection look: the same centre resting frame as idle
|
|
160
|
-
// (variant-grid suppresses the highlight for both, so nothing lights).
|
|
161
|
-
// A dedicated arm so the pending LiveKit measurement can adjust it in
|
|
162
|
-
// one line.
|
|
163
|
-
case 'disconnected':
|
|
164
|
-
return [center];
|
|
165
|
-
default:
|
|
166
|
-
return [center];
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// ---------------------------------------------------------------- radial
|
|
171
|
-
|
|
172
|
-
/** Largest divisor of `n` that is at most `max`. Always at least 1. */
|
|
173
|
-
function largestDivisorAtMost(n: number, max: number): number {
|
|
174
|
-
const gcd = (a: number, b: number): number => {
|
|
175
|
-
while (b !== 0) {
|
|
176
|
-
const t = b;
|
|
177
|
-
b = a % b;
|
|
178
|
-
a = t;
|
|
179
|
-
}
|
|
180
|
-
return a;
|
|
181
|
-
};
|
|
182
|
-
for (let i = max; i >= 1; i--) if (gcd(n, i) === i) return i;
|
|
183
|
-
return 1;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Partition the ring into interleaved groups. Lighting one group per tick reads
|
|
188
|
-
* as a rotating pattern rather than a single travelling dot. Every index appears
|
|
189
|
-
* in exactly one group.
|
|
190
|
-
*/
|
|
191
|
-
function radialGroups(barCount: number): number[][] {
|
|
192
|
-
const divisor =
|
|
193
|
-
barCount > 8
|
|
194
|
-
? barCount / largestDivisorAtMost(barCount, 4)
|
|
195
|
-
: largestDivisorAtMost(barCount, 2);
|
|
196
|
-
const safe = Math.max(1, Math.floor(divisor));
|
|
197
|
-
const perGroup = Math.floor(barCount / safe);
|
|
198
|
-
return Array.from({ length: safe }, (_, i) =>
|
|
199
|
-
Array.from({ length: perGroup }, (_, j) => j * safe + i),
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function radialSequence(state: VisualizerState, barCount: number): number[][] {
|
|
204
|
-
switch (state) {
|
|
205
|
-
case 'connecting': {
|
|
206
|
-
// Pair each bar with the one opposite it, sweeping around the circle.
|
|
207
|
-
const center = Math.floor(barCount / 2);
|
|
208
|
-
const seq: number[][] = [];
|
|
209
|
-
for (let x = 0; x < barCount; x++) seq.push([x, (x + center) % barCount]);
|
|
210
|
-
return seq.length ? seq : [[]];
|
|
211
|
-
}
|
|
212
|
-
case 'listening':
|
|
213
|
-
case 'thinking': {
|
|
214
|
-
const groups = radialGroups(barCount);
|
|
215
|
-
return groups.length ? groups : [[]];
|
|
216
|
-
}
|
|
217
|
-
case 'speaking':
|
|
218
|
-
return [Array.from({ length: barCount }, (_, i) => i)];
|
|
219
|
-
// Dead-connection look: mirrors idle (nothing lit) for now, one-line
|
|
220
|
-
// adjustable once the LiveKit measurement lands.
|
|
221
|
-
case 'disconnected':
|
|
222
|
-
return [[]];
|
|
223
|
-
case 'idle':
|
|
224
|
-
default:
|
|
225
|
-
return [[]];
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export function radialInterval(state: VisualizerState): number {
|
|
230
|
-
switch (state) {
|
|
231
|
-
case 'connecting':
|
|
232
|
-
case 'listening':
|
|
233
|
-
return 500;
|
|
234
|
-
// Infinity parks the sequencer: `thinking` spins the whole container in CSS
|
|
235
|
-
// with every bar lit, so ticking would fight the animation.
|
|
236
|
-
case 'thinking':
|
|
237
|
-
return Infinity;
|
|
238
|
-
default:
|
|
239
|
-
return 1000;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ---------------------------------------------------------------- shader
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Uniform targets for the aura and custom shaders. An array intensity means
|
|
247
|
-
* "ping-pong between these two" (see create-tween). `speaking` intensity is
|
|
248
|
-
* omitted from the pulse because live volume drives it instantly instead.
|
|
249
|
-
*/
|
|
250
|
-
export function shaderTargets(
|
|
251
|
-
state: VisualizerState,
|
|
252
|
-
): { intensity: number | [number, number]; speed: number } {
|
|
253
|
-
switch (state) {
|
|
254
|
-
case 'listening':
|
|
255
|
-
return { intensity: [0.5, 0.8], speed: 2.5 };
|
|
256
|
-
case 'thinking':
|
|
257
|
-
return { intensity: [0.25, 0.5], speed: 4.0 };
|
|
258
|
-
// Same pulse as thinking, its own speed: uSpeed is the only
|
|
259
|
-
// state-correlated scalar besides intensity that reaches a custom
|
|
260
|
-
// shader's GLSL (see customUniforms in variant-custom.tsx), so the two
|
|
261
|
-
// transitional states sharing 4.0 made them indistinguishable to any
|
|
262
|
-
// consumer shader keying off the kit's uniforms -- the Custom story's
|
|
263
|
-
// per-state looks are the concrete consumer. Every state now maps to a
|
|
264
|
-
// distinct speed: idle 1, listening/speaking 2.5 (told apart by band
|
|
265
|
-
// energy), thinking 4, connecting 6.
|
|
266
|
-
case 'connecting':
|
|
267
|
-
return { intensity: [0.25, 0.5], speed: 6.0 };
|
|
268
|
-
case 'speaking':
|
|
269
|
-
return { intensity: 0.3, speed: 2.5 };
|
|
270
|
-
// Dead-connection look: idle's dim intensity but its OWN speed, so a
|
|
271
|
-
// shader keying off uSpeed can draw a dead line distinct from idle's
|
|
272
|
-
// calm ridge (see the connecting arm's comment: uSpeed is the only
|
|
273
|
-
// other state-correlated scalar reaching consumer GLSL). Still
|
|
274
|
-
// one-line adjustable once the LiveKit measurement lands.
|
|
275
|
-
case 'disconnected':
|
|
276
|
-
return { intensity: 0.3, speed: 0.5 };
|
|
277
|
-
case 'idle':
|
|
278
|
-
default:
|
|
279
|
-
return { intensity: 0.3, speed: 1 };
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const WAVE_SPEED = 5;
|
|
284
|
-
const WAVE_AMPLITUDE = 0.025;
|
|
285
|
-
const WAVE_FREQUENCY = 10;
|
|
286
|
-
|
|
287
|
-
/** Uniform targets for the wave shader. Same shape, different curve. */
|
|
288
|
-
export function waveTargets(state: VisualizerState): {
|
|
289
|
-
speed: number;
|
|
290
|
-
amplitude: number;
|
|
291
|
-
frequency: number;
|
|
292
|
-
opacity: number | [number, number];
|
|
293
|
-
pulseDuration: number;
|
|
294
|
-
} {
|
|
295
|
-
switch (state) {
|
|
296
|
-
case 'listening':
|
|
297
|
-
return {
|
|
298
|
-
speed: WAVE_SPEED,
|
|
299
|
-
amplitude: WAVE_AMPLITUDE,
|
|
300
|
-
frequency: WAVE_FREQUENCY,
|
|
301
|
-
opacity: [1.0, 0.3],
|
|
302
|
-
pulseDuration: 0.75,
|
|
303
|
-
};
|
|
304
|
-
case 'thinking':
|
|
305
|
-
case 'connecting':
|
|
306
|
-
return {
|
|
307
|
-
speed: WAVE_SPEED * 4,
|
|
308
|
-
amplitude: WAVE_AMPLITUDE / 4,
|
|
309
|
-
frequency: WAVE_FREQUENCY * 4,
|
|
310
|
-
opacity: [1.0, 0.3],
|
|
311
|
-
pulseDuration: 0.4,
|
|
312
|
-
};
|
|
313
|
-
case 'speaking':
|
|
314
|
-
// Upstream's wave switch has NO 'idle' arm: idle falls through to this
|
|
315
|
-
// same speaking/default arm (speed 10, amplitude 0.025, frequency 10,
|
|
316
|
-
// opacity 1), a gentle undulation (~1.05px centreline waviness, ~1.5px/s
|
|
317
|
-
// phase drift, measured on the md tile). Upstream's explicitly FLAT
|
|
318
|
-
// state is 'disconnected' -- the dedicated arm below. We had flattened
|
|
319
|
-
// idle instead; Rob wants upstream's look (2026-08-09).
|
|
320
|
-
case 'idle':
|
|
321
|
-
return {
|
|
322
|
-
speed: WAVE_SPEED * 2,
|
|
323
|
-
amplitude: WAVE_AMPLITUDE,
|
|
324
|
-
frequency: WAVE_FREQUENCY,
|
|
325
|
-
opacity: 1.0,
|
|
326
|
-
pulseDuration: 0,
|
|
327
|
-
};
|
|
328
|
-
// Upstream's EXPLICIT flat state, measured: 'disconnected' is the one
|
|
329
|
-
// arm of their wave switch that zeroes the line. First-class here since
|
|
330
|
-
// 2026-08-10 (Rob: 'the disconnected wave needs to be that kind of flat
|
|
331
|
-
// line'). `default` keeps the same flat targets for out-of-union
|
|
332
|
-
// strings, which normalizeState prevents real callers from reaching.
|
|
333
|
-
case 'disconnected':
|
|
334
|
-
return {
|
|
335
|
-
speed: WAVE_SPEED,
|
|
336
|
-
amplitude: 0,
|
|
337
|
-
frequency: 0,
|
|
338
|
-
opacity: 1.0,
|
|
339
|
-
pulseDuration: 0,
|
|
340
|
-
};
|
|
341
|
-
default:
|
|
342
|
-
return {
|
|
343
|
-
speed: WAVE_SPEED,
|
|
344
|
-
amplitude: 0,
|
|
345
|
-
frequency: 0,
|
|
346
|
-
opacity: 1.0,
|
|
347
|
-
pulseDuration: 0,
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
}
|
package/src/remote/host-embed.ts
DELETED
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
// src/remote/host-embed.ts
|
|
2
|
-
// The host embed SDK: mountRemoteCard() + the RemoteCardHandle. Drops one sandboxed
|
|
3
|
-
// cross-origin iframe, runs the handshake (origin+source+nonce+version), pushes
|
|
4
|
-
// CardContext + CardEnvelope down, validates inbound up-frames, and routes every
|
|
5
|
-
// CardEvent through the SAME routeCardEvent the native transport uses. Auto-sizes the
|
|
6
|
-
// iframe from `resize`, intercepts `focus-edge`.
|
|
7
|
-
//
|
|
8
|
-
// Security-critical, stateful, vanilla DOM ONLY — NO SolidJS imports. See the
|
|
9
|
-
// iframe-transport design spec ("Host embed SDK surface" + addendum H-A/H-C/H-D/H-E/
|
|
10
|
-
// H-F/H-G/H-O).
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
type CardEnvelope,
|
|
14
|
-
type CardContext,
|
|
15
|
-
type CardEvent,
|
|
16
|
-
type CardPolicy,
|
|
17
|
-
} from '../primitives/card-contract';
|
|
18
|
-
import { createPacker, isCardWireFrame, type WireMessage } from './wire';
|
|
19
|
-
import { assertCrossOrigin, redactFrame } from './origin';
|
|
20
|
-
import { isValidVersion } from './version';
|
|
21
|
-
import { hasPollutionKey, isKnownEventKind } from './validate';
|
|
22
|
-
import { routeCardEvent } from '../primitives/card-routing';
|
|
23
|
-
|
|
24
|
-
export interface MountRemoteCardOptions {
|
|
25
|
-
/** Where to mount the iframe. */
|
|
26
|
-
container: HTMLElement;
|
|
27
|
-
/** The card to render (carried down as a `render` frame). */
|
|
28
|
-
envelope: CardEnvelope;
|
|
29
|
-
/** EXACT provider origin (https). Pinned for all origin checks. */
|
|
30
|
-
providerOrigin: string;
|
|
31
|
-
/** The provider URL the iframe frames (must be same-origin as providerOrigin). */
|
|
32
|
-
src: string;
|
|
33
|
-
/** Ambient context; theme/locale/conversationId/short-lived authToken. */
|
|
34
|
-
context: CardContext;
|
|
35
|
-
/** The SAME routing policy native cards use. resize/focus-edge are handled by the SDK. */
|
|
36
|
-
policy?: CardPolicy;
|
|
37
|
-
/** Override sandbox. Default: allow-scripts allow-forms allow-same-origin (NO allow-popups — H-G). */
|
|
38
|
-
sandbox?: string;
|
|
39
|
-
/** Cap auto-height (px); frame scrolls internally beyond it. */
|
|
40
|
-
maxHeight?: number;
|
|
41
|
-
/** Handshake timeout (ms). Default 5000. */
|
|
42
|
-
handshakeTimeoutMs?: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface RemoteCardHandle {
|
|
46
|
-
/** Push new ambient context (theme toggle, token refresh). Shallow top-level merge;
|
|
47
|
-
* `theme`/`a11y` replaced wholesale. Always sends a FULL resolved CardContext. */
|
|
48
|
-
updateContext(context: Partial<CardContext>): void;
|
|
49
|
-
/** Re-render with a new/updated envelope (same id = update). */
|
|
50
|
-
update(envelope: CardEnvelope): void;
|
|
51
|
-
/** Send `teardown`, stop listeners, remove the iframe. Idempotent. */
|
|
52
|
-
destroy(): void;
|
|
53
|
-
/** Current bridge state for the host to reflect in UI. */
|
|
54
|
-
state(): 'connecting' | 'open' | 'error' | 'closed';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type BridgeState = 'connecting' | 'open' | 'error' | 'closed';
|
|
58
|
-
|
|
59
|
-
const HOST_SUPPORTED_VERSIONS = ['1'];
|
|
60
|
-
const DEFAULT_SANDBOX = 'allow-scripts allow-forms allow-same-origin';
|
|
61
|
-
const DEFAULT_HANDSHAKE_TIMEOUT_MS = 5000;
|
|
62
|
-
|
|
63
|
-
/** Provider host for the iframe title (best-effort; never throws). */
|
|
64
|
-
function providerHost(providerOrigin: string): string {
|
|
65
|
-
try { return new URL(providerOrigin).host; } catch { return providerOrigin; }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function mountRemoteCard(options: MountRemoteCardOptions): RemoteCardHandle {
|
|
69
|
-
const {
|
|
70
|
-
container,
|
|
71
|
-
providerOrigin,
|
|
72
|
-
src,
|
|
73
|
-
policy,
|
|
74
|
-
maxHeight,
|
|
75
|
-
} = options;
|
|
76
|
-
|
|
77
|
-
// ── Cross-origin precondition (H-F): fail closed BEFORE mounting. ──
|
|
78
|
-
const hostOrigin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
79
|
-
assertCrossOrigin(src, providerOrigin, hostOrigin);
|
|
80
|
-
|
|
81
|
-
const handshakeTimeoutMs = options.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS;
|
|
82
|
-
|
|
83
|
-
// ── Bridge identity + generation (H-A). A new nonce per generation; stale frames are
|
|
84
|
-
// rejected by construction (generation capture + nonce equality). ──
|
|
85
|
-
let generation = 0;
|
|
86
|
-
let nonce = mintNonce();
|
|
87
|
-
let packer = createPacker('1', nonce); // provisional until `ready` negotiates the version.
|
|
88
|
-
|
|
89
|
-
// ── State machine (H-E). ──
|
|
90
|
-
let state: BridgeState = 'connecting';
|
|
91
|
-
|
|
92
|
-
// ── Latest-wins pre-OPEN buffer (H-E). Always the newest pending context/render. ──
|
|
93
|
-
let currentContext: CardContext = resolveContext(options.context);
|
|
94
|
-
let currentEnvelope: CardEnvelope = options.envelope;
|
|
95
|
-
let pendingContext: CardContext | null = null;
|
|
96
|
-
let pendingRender: CardEnvelope | null = null;
|
|
97
|
-
|
|
98
|
-
let iframe: HTMLIFrameElement | null = null;
|
|
99
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
100
|
-
let listener: ((e: MessageEvent) => void) | null = null;
|
|
101
|
-
|
|
102
|
-
function warn(data: unknown): void {
|
|
103
|
-
try { console.warn('[kai-remote]', redactFrame(data)); } catch { /* best-effort */ }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function postDown(message: WireMessage): void {
|
|
107
|
-
const cw = iframe?.contentWindow;
|
|
108
|
-
if (!cw) return;
|
|
109
|
-
try { cw.postMessage(packer(message), providerOrigin); } catch { /* best-effort */ }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function clearTimer(): void {
|
|
113
|
-
if (timer !== undefined) { clearTimeout(timer); timer = undefined; }
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function sendContext(ctx: CardContext): void {
|
|
117
|
-
if (state === 'open') postDown({ dir: 'down', kind: 'context', context: ctx });
|
|
118
|
-
else if (state === 'connecting') pendingContext = ctx; // latest-wins; no buffer in error/closed
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function sendRender(envelope: CardEnvelope): void {
|
|
122
|
-
if (state === 'open') postDown({ dir: 'down', kind: 'render', envelope });
|
|
123
|
-
else if (state === 'connecting') pendingRender = envelope; // latest-wins; no buffer in error/closed
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function flushBuffer(): void {
|
|
127
|
-
// Order: context → render (H-E), so the runtime themes before first paint.
|
|
128
|
-
if (pendingContext) { postDown({ dir: 'down', kind: 'context', context: pendingContext }); pendingContext = null; }
|
|
129
|
-
if (pendingRender) { postDown({ dir: 'down', kind: 'render', envelope: pendingRender }); pendingRender = null; }
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function renderFallback(message: string): void {
|
|
133
|
-
// Replace the iframe with an inline accessible fallback + a Retry button.
|
|
134
|
-
const fallback = document.createElement('div');
|
|
135
|
-
fallback.setAttribute('role', 'alert');
|
|
136
|
-
fallback.dataset.kaiRemoteFallback = '';
|
|
137
|
-
const msg = document.createElement('p');
|
|
138
|
-
msg.textContent = message;
|
|
139
|
-
fallback.appendChild(msg);
|
|
140
|
-
const retry = document.createElement('button');
|
|
141
|
-
retry.type = 'button';
|
|
142
|
-
retry.textContent = 'Retry';
|
|
143
|
-
retry.addEventListener('click', () => retryMount());
|
|
144
|
-
fallback.appendChild(retry);
|
|
145
|
-
if (iframe && iframe.parentNode === container) container.replaceChild(fallback, iframe);
|
|
146
|
-
else container.appendChild(fallback);
|
|
147
|
-
iframe = null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function toError(message: string): void {
|
|
151
|
-
if (state === 'closed') return;
|
|
152
|
-
clearTimer();
|
|
153
|
-
state = 'error';
|
|
154
|
-
pendingContext = null;
|
|
155
|
-
pendingRender = null; // discard the coalesced buffer (H-O)
|
|
156
|
-
renderFallback(message);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** Build the iframe, wire the listener BEFORE setting src (race closure), append, set src. */
|
|
160
|
-
function createIframe(): void {
|
|
161
|
-
const myGen = generation;
|
|
162
|
-
const el = document.createElement('iframe');
|
|
163
|
-
el.setAttribute('sandbox', options.sandbox ?? DEFAULT_SANDBOX);
|
|
164
|
-
el.setAttribute('referrerpolicy', 'no-referrer');
|
|
165
|
-
el.setAttribute('allow', '');
|
|
166
|
-
const titleBase = currentEnvelope.title ?? currentEnvelope.type;
|
|
167
|
-
el.setAttribute('title', `${titleBase} — provided by ${providerHost(providerOrigin)}`);
|
|
168
|
-
el.style.border = '0';
|
|
169
|
-
el.style.width = '100%';
|
|
170
|
-
|
|
171
|
-
el.addEventListener('load', () => {
|
|
172
|
-
if (generation !== myGen || state !== 'connecting') return;
|
|
173
|
-
// Provisional packer (negotiated version is set on `ready`).
|
|
174
|
-
packer = createPacker('1', nonce);
|
|
175
|
-
postDown({ dir: 'down', kind: 'hello', supportedVersions: HOST_SUPPORTED_VERSIONS });
|
|
176
|
-
clearTimer();
|
|
177
|
-
timer = setTimeout(() => {
|
|
178
|
-
if (generation !== myGen || state !== 'connecting') return;
|
|
179
|
-
toError('[timeout] The card took too long to load.');
|
|
180
|
-
policy?.onError?.(currentEnvelope.id, '[timeout] handshake timed out');
|
|
181
|
-
}, handshakeTimeoutMs);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Listener BEFORE src (H — load-before-listener race closure).
|
|
185
|
-
listener = (event: MessageEvent) => onMessage(event, myGen);
|
|
186
|
-
window.addEventListener('message', listener);
|
|
187
|
-
|
|
188
|
-
iframe = el;
|
|
189
|
-
container.appendChild(el);
|
|
190
|
-
el.setAttribute('src', src); // set LAST.
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function retryMount(): void {
|
|
194
|
-
// Guard: only retry from error state; a double-click (or stray call) is a no-op.
|
|
195
|
-
if (state !== 'error') return;
|
|
196
|
-
// New generation + new nonce; stale frames from the dead iframe are rejected.
|
|
197
|
-
generation += 1;
|
|
198
|
-
nonce = mintNonce();
|
|
199
|
-
packer = createPacker('1', nonce);
|
|
200
|
-
state = 'connecting';
|
|
201
|
-
pendingContext = null;
|
|
202
|
-
pendingRender = null;
|
|
203
|
-
clearTimer();
|
|
204
|
-
if (listener) { window.removeEventListener('message', listener); listener = null; }
|
|
205
|
-
// Defensively remove any lingering iframe before creating a fresh one.
|
|
206
|
-
if (iframe) { iframe.remove(); iframe = null; }
|
|
207
|
-
// Always re-push the latest resolved context + envelope after the new handshake.
|
|
208
|
-
pendingContext = currentContext;
|
|
209
|
-
pendingRender = currentEnvelope;
|
|
210
|
-
// Remove any existing fallback before re-mounting.
|
|
211
|
-
container.querySelectorAll('[data-kai-remote-fallback]').forEach((n) => n.remove());
|
|
212
|
-
createIframe();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function sizeIframe(height: number): void {
|
|
216
|
-
if (!iframe) return;
|
|
217
|
-
const clamped = Math.min(height, maxHeight ?? Infinity);
|
|
218
|
-
iframe.style.height = `${clamped}px`;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function moveFocusPastIframe(): void {
|
|
222
|
-
// v1 focus-edge handling: blur the iframe so default browser tab order moves past it.
|
|
223
|
-
// (A richer "next host focusable" mover is a later refinement; blur is deterministic
|
|
224
|
-
// and never routes through CardPolicy.)
|
|
225
|
-
if (iframe) { try { iframe.blur(); } catch { /* best-effort */ } }
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function onMessage(event: MessageEvent, myGen: number): void {
|
|
229
|
-
// ── Stale-generation defense (H-A): ignore frames from a superseded/closed bridge. ──
|
|
230
|
-
if (myGen !== generation || state === 'closed' || state === 'error') return;
|
|
231
|
-
const data = event.data;
|
|
232
|
-
|
|
233
|
-
// ── Inbound security gates, in order (H-A/H-C/H-D): ──
|
|
234
|
-
// 1. origin pin 2. source-window pin 3. structural + direction guard
|
|
235
|
-
// 4. nonce equality (bridge-instance binding)
|
|
236
|
-
if (event.origin !== providerOrigin) return;
|
|
237
|
-
if (event.source !== iframe?.contentWindow) return;
|
|
238
|
-
if (!isCardWireFrame(data, 'up')) return;
|
|
239
|
-
if (data.nonce !== nonce) return;
|
|
240
|
-
|
|
241
|
-
// A throw past the gate must NOT kill the listener.
|
|
242
|
-
try {
|
|
243
|
-
const message = data.message;
|
|
244
|
-
switch (message.kind) {
|
|
245
|
-
case 'ready': {
|
|
246
|
-
if (state !== 'connecting') return;
|
|
247
|
-
const accepted = message.acceptedVersion;
|
|
248
|
-
// 5. version: accepted MUST be a host-supported version (H-C).
|
|
249
|
-
if (!isValidVersion(accepted) || !HOST_SUPPORTED_VERSIONS.includes(accepted)) {
|
|
250
|
-
toError('[version-unsupported] This card needs a different host version.');
|
|
251
|
-
policy?.onError?.(currentEnvelope.id, '[version-unsupported] no compatible protocol version');
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
// Rebuild the packer with the negotiated version (H-C).
|
|
255
|
-
packer = createPacker(accepted, nonce);
|
|
256
|
-
clearTimer();
|
|
257
|
-
state = 'open';
|
|
258
|
-
// Seed the buffer with the current resolved context + envelope, then flush.
|
|
259
|
-
if (!pendingContext) pendingContext = currentContext;
|
|
260
|
-
if (!pendingRender) pendingRender = currentEnvelope;
|
|
261
|
-
flushBuffer();
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
case 'event': {
|
|
265
|
-
if (state !== 'open') return;
|
|
266
|
-
const ev: CardEvent = message.event;
|
|
267
|
-
// cardId fence (H-E): drop in-flight events for a replaced/stale card.
|
|
268
|
-
if (ev.cardId !== currentEnvelope.id) return;
|
|
269
|
-
// resize is transport plumbing — intercept, never route (H-J / spec UP table).
|
|
270
|
-
if (ev.kind === 'resize') { sizeIframe(ev.height); return; }
|
|
271
|
-
// Schema/pollution gate before routing (H-D).
|
|
272
|
-
if (!isKnownEventKind(ev.kind) || hasPollutionKey(ev)) { warn(data); return; }
|
|
273
|
-
routeCardEvent(policy ?? {}, ev);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
case 'focus-edge': {
|
|
277
|
-
// a11y plumbing — intercept, never route (H-O).
|
|
278
|
-
moveFocusPastIframe();
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
case 'fault': {
|
|
282
|
-
const code = message.code;
|
|
283
|
-
const reason = message.message;
|
|
284
|
-
toError(`[${code}] The card reported a problem.`);
|
|
285
|
-
policy?.onError?.(currentEnvelope.id, `[${code}] ${reason}`);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
default:
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
} catch {
|
|
292
|
-
warn(data);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// ── Public handle ──────────────────────────────────────────────────────────
|
|
297
|
-
const handle: RemoteCardHandle = {
|
|
298
|
-
updateContext(partial: Partial<CardContext>): void {
|
|
299
|
-
if (state === 'closed') return;
|
|
300
|
-
currentContext = mergeContext(currentContext, partial);
|
|
301
|
-
sendContext(currentContext);
|
|
302
|
-
},
|
|
303
|
-
update(envelope: CardEnvelope): void {
|
|
304
|
-
if (state === 'closed') return;
|
|
305
|
-
currentEnvelope = envelope;
|
|
306
|
-
sendRender(envelope);
|
|
307
|
-
},
|
|
308
|
-
destroy(): void {
|
|
309
|
-
if (state === 'closed') return;
|
|
310
|
-
generation += 1; // tombstone the current generation (rejects stale inbound).
|
|
311
|
-
if (state === 'open') postDown({ dir: 'down', kind: 'teardown' });
|
|
312
|
-
state = 'closed';
|
|
313
|
-
clearTimer();
|
|
314
|
-
if (listener) { window.removeEventListener('message', listener); listener = null; }
|
|
315
|
-
if (iframe) { iframe.remove(); iframe = null; }
|
|
316
|
-
container.querySelectorAll('[data-kai-remote-fallback]').forEach((n) => n.remove());
|
|
317
|
-
},
|
|
318
|
-
state(): BridgeState {
|
|
319
|
-
return state;
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
createIframe();
|
|
324
|
-
return handle;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/** Crypto-random hex nonce (H-A): 16 bytes → 32 hex chars. */
|
|
328
|
-
function mintNonce(): string {
|
|
329
|
-
const bytes = new Uint8Array(16);
|
|
330
|
-
crypto.getRandomValues(bytes);
|
|
331
|
-
let out = '';
|
|
332
|
-
for (const b of bytes) out += b.toString(16).padStart(2, '0');
|
|
333
|
-
return out;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/** A shallow copy so the caller's context object isn't mutated by later merges. */
|
|
337
|
-
function resolveContext(ctx: CardContext): CardContext {
|
|
338
|
-
return { ...ctx };
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/** Shallow top-level merge (H-E): `theme` and `a11y` are replaced wholesale, not
|
|
342
|
-
* deep-merged. Returns a new full resolved CardContext. */
|
|
343
|
-
function mergeContext(base: CardContext, partial: Partial<CardContext>): CardContext {
|
|
344
|
-
return { ...base, ...partial };
|
|
345
|
-
}
|
package/src/remote/index.ts
DELETED