@kitn.ai/ui 0.29.0 → 0.31.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-DJDuE_-x.js} +1 -1
- package/dist/action-icons-xkBBVKkF.js +1 -0
- package/dist/agent-tooling/construct/schema-url.d.ts +9 -0
- package/dist/agent-tooling/construct/schema.d.ts +76 -1
- package/dist/agent-tooling/construct/templates.d.ts +45 -0
- package/dist/arrow-down-DU6wOl-h.js +1 -0
- package/dist/arrow-left-DD46kN17.js +1 -0
- package/dist/artifact-DoUAr1Fd.js +1 -0
- package/dist/assets/dev-DwzHsqYD.js +553 -0
- package/dist/{attachments-Qr4kg-2b.js → attachments-BLWPDiLH.js} +1 -1
- package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-DhHicYvV.js} +1 -1
- package/dist/{badge-CdEu_jn2.js → badge-BGm7pcwi.js} +1 -1
- package/dist/{bell-DQAAOpDz.js → bell-CMEdSo7A.js} +1 -1
- package/dist/builder-app/App.d.ts +1 -0
- package/dist/builder-app/edit-guard.d.ts +8 -0
- package/dist/builder-app/main.d.ts +0 -0
- package/dist/builder-page/assets/index-C10OF-ur.js +72 -0
- package/dist/builder-page/assets/index-CFyKLBlu.css +1 -0
- package/dist/builder-page/index.html +20 -0
- package/dist/button-BM0YTTDQ.js +1 -0
- package/dist/{card-renderer-Jx70m6_l.js → card-renderer-Ds-wXc6_.js} +1 -1
- package/dist/check-BG1VfYjm.js +1 -0
- package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-CqXj8ehz.js} +1 -1
- package/dist/{checkbox-D7iRB3nL.js → checkbox-np_5mKxM.js} +1 -1
- package/dist/chevron-down-CZ4W0hy6.js +1 -0
- package/dist/chevron-right-5gdxkCTF.js +1 -0
- package/dist/{choice-card-m0BYqqOK.js → choice-card-BYBmPAT5.js} +1 -1
- package/dist/circle-C0lwjD2A.js +1 -0
- package/dist/circle-check-BfT1cxQU.js +1 -0
- package/dist/{circle-x-BPG0iPst.js → circle-x-DzUfvRqr.js} +1 -1
- package/dist/{code-block-ClMLKb7C.js → code-block-H6E5Eurc.js} +1 -1
- package/dist/{collapsible-B4DlWicL.js → collapsible-CBq1Tj6y.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 +63 -0
- package/dist/components/builder-panel-derived.d.ts +18 -0
- package/dist/components/builder-panel.d.ts +240 -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 +79 -0
- package/dist/components/builder-workspace-variants.d.ts +23 -0
- package/dist/components/captions.d.ts +66 -0
- package/dist/components/chat-thread.d.ts +27 -1
- package/dist/components/construct-form-paths.d.ts +54 -0
- package/dist/components/message.d.ts +5 -0
- package/dist/{composer-sQ0HcvyG.js → composer-B5IvgxAF.js} +1 -1
- package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B63pZIfG.js} +1 -1
- package/dist/construct-cli.es.js +469 -125
- package/dist/construct-templates.d.ts +5 -0
- package/dist/construct-templates.js +266 -0
- package/dist/construct.js +269 -86
- package/dist/{context-0kg4ZX1J.js → context-Byqor78j.js} +1 -1
- package/dist/controllable-C4BSt73s.js +1 -0
- package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-piXZFRWa.js} +1 -1
- package/dist/{conversation-list-BCfGN1JU.js → conversation-list-B5yu9cPg.js} +1 -1
- package/dist/{copy-n9u9rqpi.js → copy-DfI2NYEX.js} +1 -1
- package/dist/{create-tween-uPkArjIG.js → create-tween-C4j96_Aj.js} +1 -1
- package/dist/{create-tween-C-q-JCM-.js → create-tween-CHleHI8m.js} +1 -1
- package/dist/{create-tween-CRrJXxBd.js → create-tween-DQ6lOhdl.js} +1 -1
- package/dist/{create-tween-DZ3RRDHD.js → create-tween-DyjTgkJi.js} +1 -1
- package/dist/custom-elements.json +40 -5
- package/dist/{default-input-CaMrJkgH.js → default-input-Bwmt8Lai.js} +1 -1
- package/dist/define-B3OpsIDE.js +1 -0
- package/dist/define.js +41 -41
- package/dist/define.server.js +46 -46
- package/dist/{disclosure-WUImBbDv.js → disclosure-ZSAlD4wg.js} +1 -1
- package/dist/{dropdown-wZVeJOMd.js → dropdown-CSRhiMN2.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-actions.d.ts +12 -0
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-types.d.ts +7 -2
- 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/elements.d.ts +22 -10
- package/dist/{ellipsis-CbOpJnU3.js → ellipsis-CJ5QIjWo.js} +1 -1
- package/dist/{embed-CrfjkbUG.js → embed-6Vji0PfS.js} +1 -1
- package/dist/{external-link-ByXAwBBQ.js → external-link-BPTtTdet.js} +1 -1
- package/dist/{file-text-DMib2qwt.js → file-text-eVjcFDrK.js} +1 -1
- package/dist/{file-tree-CJqM2aP7.js → file-tree-a9tfWYmg.js} +1 -1
- package/dist/{folder-_BAb929C.js → folder-DN6Ilq6d.js} +1 -1
- package/dist/{form-DSZgZQZk.js → form-U1cwhcQx.js} +1 -1
- package/dist/{hover-card-BQbul9eq.js → hover-card-C5ptzZOZ.js} +1 -1
- package/dist/{icon-CdcfRhYI.js → icon-BOMrFp0D.js} +1 -1
- package/dist/index.js +2297 -2279
- package/dist/index.server.js +2102 -2084
- package/dist/{info-DsFjGuI_.js → info-DxzKsIHn.js} +1 -1
- package/dist/{input-DKbmkMos.js → input-aW72PACH.js} +1 -1
- package/dist/kai.es.js +1 -1
- package/dist/{kbd-PvdGhX4s.js → kbd-BP-6MwUs.js} +1 -1
- package/dist/{link-preview-DbM1866N.js → link-preview-CZaDilMG.js} +1 -1
- package/dist/{link-zF8PzWfF.js → link-rlN11N0B.js} +1 -1
- package/dist/loader-BdFK70fF.js +1 -0
- package/dist/{markdown-LMvmAyBk.js → markdown-DjEaoNz-.js} +1 -1
- package/dist/mcp.es.js +587 -111
- package/dist/message--Nlbemtp.js +1 -0
- package/dist/message-C88yTu2A.js +1 -0
- package/dist/message-circle-CZeVDN1f.js +1 -0
- package/dist/message-square-BXNBKC6i.js +1 -0
- package/dist/{minimize-2-BQRoBV1V.js → minimize-2-BxLOOSEf.js} +1 -1
- package/dist/{model-switcher-CMpCOYcB.js → model-switcher-BxRvub2A.js} +1 -1
- package/dist/{overlay-Cb-MkyDa.js → overlay-CDwKJtHN.js} +1 -1
- package/dist/{panel-right-i8warFxT.js → panel-right-BovedCwW.js} +1 -1
- package/dist/{paperclip-ByY3UVO6.js → paperclip-D0Xyjja2.js} +1 -1
- package/dist/play-DGJ4MgB2.js +1 -0
- package/dist/primitives/speech.d.ts +35 -0
- package/dist/primitives/use-auto-resize.d.ts +11 -0
- package/dist/{progress-bar-jVAHvMUf.js → progress-bar-D-aQfy5h.js} +1 -1
- package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-C6qLjMEQ.js} +1 -1
- package/dist/{radio-BsoBMhkF.js → radio-D1CkXISc.js} +1 -1
- package/dist/react/index.d.ts +22 -6
- package/dist/react.js +13 -13
- package/dist/{reasoning-4kBPtlTx.js → reasoning-DARmbgmE.js} +1 -1
- package/dist/register-impl-WcrdIihK.js +424 -0
- package/dist/{resizable-uPmY9VY-.js → resizable-Da6oSO2z.js} +1 -1
- package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-31ed1xK_.js} +1 -1
- package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-qkl39dw3.js} +1 -1
- package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-RrKnLYlA.js} +1 -1
- package/dist/{scroll-button-DslXiJyL.js → scroll-button--QeNjobK.js} +1 -1
- package/dist/{select-2cLRtPGT.js → select-CS_0mWW3.js} +1 -1
- package/dist/{separator-BWQtNJcM.js → separator-fT-zBypW.js} +1 -1
- package/dist/{settings-BBR63jLg.js → settings-dfkV_WDm.js} +1 -1
- package/dist/{settings-group-B2ciy-Iw.js → settings-group-CX694npG.js} +1 -1
- package/dist/{skeleton-CkHI-HgC.js → skeleton-BsqKD9TV.js} +1 -1
- package/dist/{slider-DDR9U-i0.js → slider-_EWfTH9H.js} +1 -1
- package/dist/{solid-DruVOXnf.js → solid-BITWG_VE.js} +4214 -3996
- package/dist/{solid-BzCFdL25.js → solid-CRFYWlBw.js} +5647 -5373
- 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-Da1TFiuj.js} +1 -1
- package/dist/speech-CjbWuqG2.js +1 -0
- package/dist/{star-CilHq8GP.js → star-ZvSbbXS6.js} +1 -1
- package/dist/{store-Ciyk6eZG.js → store-DE5lcr9q.js} +1 -1
- package/dist/{switch-KkeQIbuH.js → switch-P_fsHqv3.js} +1 -1
- package/dist/{tasks-card-BrN4bggJ.js → tasks-card-B86qqyZm.js} +1 -1
- package/dist/text-shimmer-BAkw_65G.js +1 -0
- package/dist/textarea-Bkinatpi.js +1 -0
- package/dist/theme.tokens.css +22 -21
- package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-CDGW7a4o.js} +1 -1
- package/dist/{toast-store-tgK6MuMv.js → toast-store-B94I50AO.js} +1 -1
- package/dist/{tool-DzUjIBT8.js → tool-CUiCeyi1.js} +1 -1
- package/dist/{tooltip-Bkkg_4t0.js → tooltip-B3wlQSPh.js} +1 -1
- package/dist/{trash-2-jBKxjGGQ.js → trash-2-Cu8yZmFQ.js} +1 -1
- package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CCtDUUmn.js} +1 -1
- package/dist/ui/button-variant-names.d.ts +12 -0
- package/dist/ui/button.d.ts +6 -0
- 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-CxotJlLv.js} +1 -1
- package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-DILUvNyj.js} +1 -1
- package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-BGaXBBGf.js} +1 -1
- package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-BLcQmvkd.js} +1 -1
- package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DZIfAtx1.js} +2 -2
- package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-DpoIW4ZX.js} +2 -2
- package/dist/{variant-custom-BRvaNHSi.js → variant-custom-BhtWdAxE.js} +1 -1
- package/dist/{variant-custom-DMTrEO5w.js → variant-custom-BtApuSyr.js} +2 -2
- package/dist/{variant-custom-DV2x254s.js → variant-custom-C-zS4ZtE.js} +2 -2
- package/dist/{variant-custom-BvYHR62b.js → variant-custom-swi9PXxU.js} +1 -1
- package/dist/{variant-wave-sp-qwsdI.js → variant-wave-7JCIwhpb.js} +1 -1
- package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-BG4nGr6x.js} +1 -1
- package/dist/{variant-wave-BNMGrDfj.js → variant-wave-C32lM9G2.js} +2 -2
- package/dist/{variant-wave-CyBueXj9.js → variant-wave-Dl6jOiK3.js} +2 -2
- package/dist/x-C4niw05N.js +1 -0
- package/frameworks/react/index.tsx +12 -6
- package/kit-base.css +311 -0
- package/llms-full.txt +9 -6
- package/llms.txt +1 -1
- package/package.json +23 -4
- package/solid.css +48 -0
- package/src/elements/element-meta.json +39 -14
- package/theme.css +39 -23
- package/dist/action-icons-CcgNN2oT.js +0 -1
- 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/assets/dev-5XzXYR21.js +0 -91
- package/dist/button-DkuOnGLy.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-BSsgvHvf.js +0 -1
- package/dist/message-BYZECyek.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
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { createServer } from "node:http";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, watch, renameSync } from "node:fs";
|
|
5
|
+
import { join, resolve, basename, dirname, extname } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { v as validateConstruct, g as generateProject, w as writeProject, a as accentContrastNotice } from "../construct-cli.es.js";
|
|
8
|
+
import "zod";
|
|
9
|
+
import "node:module";
|
|
10
|
+
const CONSTRUCT_SCHEMA_URL = "https://ui.kitn.ai/schemas/construct/v1.json";
|
|
11
|
+
const IDENTITY = { id: "identity", paths: ["name"] };
|
|
12
|
+
const THEME = { id: "theme", paths: ["theme.accent", "theme.mode", "theme.unreadColor"] };
|
|
13
|
+
const HEADER = { id: "header", paths: ["header.title"] };
|
|
14
|
+
const HEADER_CHROME = {
|
|
15
|
+
id: "header",
|
|
16
|
+
paths: ["header.title", "header.themeToggle", "header.actions"]
|
|
17
|
+
};
|
|
18
|
+
const EMPTY = { id: "empty", paths: ["empty.title", "empty.description", "empty.icon"] };
|
|
19
|
+
const HOME = { id: "home", paths: ["home"] };
|
|
20
|
+
const CAPABILITIES = {
|
|
21
|
+
id: "capabilities",
|
|
22
|
+
paths: [
|
|
23
|
+
"capabilities.starters",
|
|
24
|
+
"capabilities.attachments",
|
|
25
|
+
"capabilities.history",
|
|
26
|
+
"capabilities.conversations",
|
|
27
|
+
"capabilities.reasoning",
|
|
28
|
+
"capabilities.reasoningOpen"
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
const MESSAGE_ACTIONS = {
|
|
32
|
+
id: "messageActions",
|
|
33
|
+
paths: ["capabilities.messageActions.user", "capabilities.messageActions.assistant"]
|
|
34
|
+
};
|
|
35
|
+
const SOURCES = { id: "sources", paths: ["capabilities.sources.strip"] };
|
|
36
|
+
const WIDGET_CHROME = {
|
|
37
|
+
id: "widget",
|
|
38
|
+
paths: ["widget.position", "widget.launcherIcon", "widget.defaultOpen"]
|
|
39
|
+
};
|
|
40
|
+
const ASIDE = { id: "aside", paths: ["aside.position", "aside.width"] };
|
|
41
|
+
const COMPOSER_TRIGGERS = {
|
|
42
|
+
id: "composerTriggers",
|
|
43
|
+
paths: ["composer.triggers.slash", "composer.triggers.mention"]
|
|
44
|
+
};
|
|
45
|
+
const SHELL = { id: "shell", paths: ["shell.commandPalette", "shell.userMenu"] };
|
|
46
|
+
const CARDS = { id: "cards", paths: ["cards"] };
|
|
47
|
+
const PROVIDER = { id: "provider", paths: ["provider"] };
|
|
48
|
+
const widgetStarter = {
|
|
49
|
+
$schema: CONSTRUCT_SCHEMA_URL,
|
|
50
|
+
name: "support-widget",
|
|
51
|
+
layout: "widget",
|
|
52
|
+
provider: { mode: "mock" },
|
|
53
|
+
header: { title: "Support" },
|
|
54
|
+
theme: { unreadColor: "#38BDF8", mode: "system" },
|
|
55
|
+
empty: {
|
|
56
|
+
title: "Hi, we're here to help",
|
|
57
|
+
description: "Ask us about orders, refunds, and more."
|
|
58
|
+
},
|
|
59
|
+
home: {
|
|
60
|
+
greeting: { title: "How can we help? 👋", subtitle: "Orders, refunds, anything." },
|
|
61
|
+
recentConversation: true,
|
|
62
|
+
links: [
|
|
63
|
+
{ label: "Help center", href: "https://ui.kitn.ai", description: "Guides and FAQs", icon: "book-open" }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
// States the kit default loudly (the anchored-on-the-default convention,
|
|
67
|
+
// same as research's sources.strip) so the template's chrome fact is
|
|
68
|
+
// visible/editable in its own JSON.
|
|
69
|
+
widget: { position: "bottom-end" },
|
|
70
|
+
capabilities: {
|
|
71
|
+
starters: ["Where's my order?", "Request a refund"],
|
|
72
|
+
attachments: { accept: ["image/*", "application/pdf"] },
|
|
73
|
+
history: { persistence: "local" },
|
|
74
|
+
conversations: true
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const inAppAssistantStarter = {
|
|
78
|
+
$schema: CONSTRUCT_SCHEMA_URL,
|
|
79
|
+
name: "in-app-assistant",
|
|
80
|
+
layout: "aside",
|
|
81
|
+
provider: { mode: "mock" },
|
|
82
|
+
header: { title: "Assistant" },
|
|
83
|
+
// Dark-by-default (owner ruling, dark round): every buildable starter
|
|
84
|
+
// EXCEPT widget ships mode: 'dark' — widget is embedded in a host site and
|
|
85
|
+
// follows IT, not its own preference (T-3: this is registry data, not a
|
|
86
|
+
// schema default; 'system' stays the schema's own default for anyone
|
|
87
|
+
// hand-authoring a construct).
|
|
88
|
+
theme: { accent: "#0ea5e9", mode: "dark" },
|
|
89
|
+
// codegen's own defaults, stated so the geometry is visible/editable.
|
|
90
|
+
aside: { position: "end", width: "380px" },
|
|
91
|
+
capabilities: {
|
|
92
|
+
starters: ["Deploy payments to production", "Check the canary status"],
|
|
93
|
+
attachments: { accept: ["image/*", "application/pdf"] },
|
|
94
|
+
history: { persistence: "local" }
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const assistantStarter = {
|
|
98
|
+
$schema: CONSTRUCT_SCHEMA_URL,
|
|
99
|
+
name: "daily-assistant",
|
|
100
|
+
layout: "fullscreen",
|
|
101
|
+
provider: { mode: "mock" },
|
|
102
|
+
header: { title: "Assistant" },
|
|
103
|
+
// Dark-by-default (owner ruling, dark round) — see inAppAssistantStarter's
|
|
104
|
+
// note above.
|
|
105
|
+
theme: { accent: "#7c3aed", mode: "dark" },
|
|
106
|
+
empty: {
|
|
107
|
+
title: "What can I help with?",
|
|
108
|
+
description: "Ask anything, or start from a suggestion below."
|
|
109
|
+
},
|
|
110
|
+
capabilities: {
|
|
111
|
+
starters: ["Draft the Q3 board update", "Summarize a document", "Compare two options"],
|
|
112
|
+
attachments: { accept: ["image/*", "application/pdf"] },
|
|
113
|
+
history: { persistence: "local" },
|
|
114
|
+
conversations: true
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const researchStarter = {
|
|
118
|
+
$schema: CONSTRUCT_SCHEMA_URL,
|
|
119
|
+
name: "research-assistant",
|
|
120
|
+
layout: "fullscreen",
|
|
121
|
+
provider: { mode: "mock" },
|
|
122
|
+
header: { title: "Research" },
|
|
123
|
+
// Dark-by-default (owner ruling, dark round) — see inAppAssistantStarter's
|
|
124
|
+
// note above.
|
|
125
|
+
theme: { accent: "#0f766e", mode: "dark" },
|
|
126
|
+
capabilities: {
|
|
127
|
+
starters: ["How does the wire adapter work?", "What are message parts?"],
|
|
128
|
+
attachments: { accept: ["application/pdf"] },
|
|
129
|
+
history: { persistence: "local" },
|
|
130
|
+
// The template's defining fact, stated even though it matches the emit
|
|
131
|
+
// default (B-4): the row already renders; strip: true is the visible
|
|
132
|
+
// switch this template exists around.
|
|
133
|
+
sources: { strip: true },
|
|
134
|
+
// "assistant-style actions" (B-13) — the owner's A3 default matrix
|
|
135
|
+
// (builder-message-actions.tsx: user Edit on; assistant
|
|
136
|
+
// Copy/Like/Dislike on).
|
|
137
|
+
messageActions: { user: ["edit"], assistant: ["copy", "like", "dislike"] }
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const workspaceTriggers = {
|
|
141
|
+
triggers: {
|
|
142
|
+
slash: [
|
|
143
|
+
{ id: "summarize", label: "summarize", description: "Summarize the thread so far" },
|
|
144
|
+
{ id: "translate", label: "translate", description: "Translate the last message" }
|
|
145
|
+
],
|
|
146
|
+
mention: [
|
|
147
|
+
{ id: "researcher", label: "researcher", description: "Hands off to the research agent" },
|
|
148
|
+
{ id: "coder", label: "coder", description: "Hands off to the coding agent" }
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const workspaceBase = {
|
|
153
|
+
$schema: CONSTRUCT_SCHEMA_URL,
|
|
154
|
+
name: "build-workspace",
|
|
155
|
+
layout: "split",
|
|
156
|
+
provider: { mode: "mock" },
|
|
157
|
+
header: {
|
|
158
|
+
title: "Workspace",
|
|
159
|
+
themeToggle: true,
|
|
160
|
+
// The story's Share/Deploy rows, mapped onto the kit Button's real
|
|
161
|
+
// variant names (B-6a's enum): 'secondary' → outline, 'primary' → default.
|
|
162
|
+
actions: [
|
|
163
|
+
{ label: "Share", variant: "outline" },
|
|
164
|
+
{ label: "Deploy", variant: "default" }
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
// Dark-by-default (owner ruling, dark round) — see inAppAssistantStarter's
|
|
168
|
+
// note above. Both variants below spread ...workspaceBase without
|
|
169
|
+
// overriding theme, so this covers artifactPreview and appPreview too.
|
|
170
|
+
theme: { accent: "#ea580c", mode: "dark" },
|
|
171
|
+
shell: { commandPalette: true, userMenu: { name: "Ada", plan: "Pro" } },
|
|
172
|
+
composer: workspaceTriggers,
|
|
173
|
+
capabilities: {
|
|
174
|
+
starters: ["Build a pricing table", "Add a dark mode toggle"],
|
|
175
|
+
attachments: { accept: ["image/*"] },
|
|
176
|
+
history: { persistence: "local" }
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const workspaceArtifactPreview = {
|
|
180
|
+
...workspaceBase,
|
|
181
|
+
name: "artifact-workspace"
|
|
182
|
+
};
|
|
183
|
+
const workspaceAppPreview = {
|
|
184
|
+
...workspaceBase,
|
|
185
|
+
name: "app-workspace",
|
|
186
|
+
capabilities: {
|
|
187
|
+
...workspaceBase.capabilities,
|
|
188
|
+
starters: ["Build a landing page for a coffee shop", "Make the hero work on mobile"]
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
const TEMPLATES = [
|
|
192
|
+
{
|
|
193
|
+
id: "widget",
|
|
194
|
+
name: "Support widget",
|
|
195
|
+
description: "A floating chat that lives in the corner of your site.",
|
|
196
|
+
availability: "buildable",
|
|
197
|
+
starter: widgetStarter,
|
|
198
|
+
controls: [IDENTITY, THEME, HEADER, HOME, CAPABILITIES, WIDGET_CHROME, PROVIDER]
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: "inAppAssistant",
|
|
202
|
+
name: "In-app assistant",
|
|
203
|
+
description: "An assistant docked inside your existing app.",
|
|
204
|
+
availability: "buildable",
|
|
205
|
+
starter: inAppAssistantStarter,
|
|
206
|
+
// Design-parity fix wave (2026-08-29 audit): the story's In-app
|
|
207
|
+
// assistant panel shows Composer triggers, Message actions and a
|
|
208
|
+
// read-only Cards list, none of which were wired here even though the
|
|
209
|
+
// vocabulary and the panel machinery both already exist (proven working
|
|
210
|
+
// on Workspace/Assistant/Research). Voice/Reveal-mode/Rail-placement
|
|
211
|
+
// stay absent — those are the story's own labeled preview-only,
|
|
212
|
+
// T-5-deferred fields with no construct vocabulary at all.
|
|
213
|
+
controls: [IDENTITY, THEME, HEADER, ASIDE, COMPOSER_TRIGGERS, CAPABILITIES, MESSAGE_ACTIONS, CARDS, PROVIDER]
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: "assistant",
|
|
217
|
+
name: "Assistant",
|
|
218
|
+
description: "A full-page assistant with a history of past conversations.",
|
|
219
|
+
availability: "buildable",
|
|
220
|
+
starter: assistantStarter,
|
|
221
|
+
// Design-parity fix wave: the story's Assistant panel shows an App
|
|
222
|
+
// chrome / Shell section (Command palette toggle, User menu) that
|
|
223
|
+
// wasn't wired here — same already-working vocabulary as Workspace's
|
|
224
|
+
// SHELL section.
|
|
225
|
+
controls: [IDENTITY, THEME, HEADER, SHELL, EMPTY, CAPABILITIES, MESSAGE_ACTIONS, PROVIDER]
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: "research",
|
|
229
|
+
name: "Research",
|
|
230
|
+
description: "Search-first answers with cited sources.",
|
|
231
|
+
availability: "buildable",
|
|
232
|
+
starter: researchStarter,
|
|
233
|
+
controls: [IDENTITY, THEME, HEADER, CAPABILITIES, SOURCES, MESSAGE_ACTIONS, PROVIDER]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: "workspace",
|
|
237
|
+
name: "Workspace",
|
|
238
|
+
description: "Chat drives a live work surface: previews, code, and artifacts build beside the conversation.",
|
|
239
|
+
availability: "buildable",
|
|
240
|
+
starter: workspaceBase,
|
|
241
|
+
variants: [
|
|
242
|
+
{
|
|
243
|
+
id: "artifactPreview",
|
|
244
|
+
name: "Artifact preview beside chat",
|
|
245
|
+
description: "A code or rendered-output pane grows beside the conversation as you build.",
|
|
246
|
+
starter: workspaceArtifactPreview
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
id: "appPreview",
|
|
250
|
+
name: "App preview with device toggles",
|
|
251
|
+
description: "A full browser-chrome preview of the running app, with desktop, tablet, and mobile views.",
|
|
252
|
+
starter: workspaceAppPreview
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
controls: [
|
|
256
|
+
IDENTITY,
|
|
257
|
+
THEME,
|
|
258
|
+
HEADER_CHROME,
|
|
259
|
+
SHELL,
|
|
260
|
+
COMPOSER_TRIGGERS,
|
|
261
|
+
CAPABILITIES,
|
|
262
|
+
MESSAGE_ACTIONS,
|
|
263
|
+
PROVIDER
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
id: "voice",
|
|
268
|
+
name: "Voice",
|
|
269
|
+
description: "A voice-first assistant you talk to, push-to-talk and all.",
|
|
270
|
+
availability: "story-only"
|
|
271
|
+
}
|
|
272
|
+
];
|
|
273
|
+
function buildableTemplates() {
|
|
274
|
+
return TEMPLATES.filter((t) => t.availability === "buildable");
|
|
275
|
+
}
|
|
276
|
+
function workDirFor(name, root) {
|
|
277
|
+
return join(root, ".kai", name);
|
|
278
|
+
}
|
|
279
|
+
function installKey(files) {
|
|
280
|
+
const pkg = files.find((f) => f.path === "package.json");
|
|
281
|
+
return createHash("sha256").update(pkg?.code ?? "").digest("hex");
|
|
282
|
+
}
|
|
283
|
+
function regenerate(raw, sink, dir, opts = {}) {
|
|
284
|
+
const validated = validateConstruct(raw);
|
|
285
|
+
if (!validated.ok) return validated;
|
|
286
|
+
const files = generateProject(validated.construct, opts);
|
|
287
|
+
sink.write(files, dir);
|
|
288
|
+
return { ok: true, files, construct: validated.construct };
|
|
289
|
+
}
|
|
290
|
+
function regenTurn(readRaw, sink, dir, opts, io) {
|
|
291
|
+
try {
|
|
292
|
+
const raw = readRaw();
|
|
293
|
+
const out = regenerate(raw, sink, dir, opts);
|
|
294
|
+
if (!out.ok) {
|
|
295
|
+
io.error("construct rejected — last good preview stays up:");
|
|
296
|
+
for (const p of out.problems) io.error(` ${p.path || "(root)"}: ${p.message}`);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
io.log("construct changed — regenerated; Vite will hot-update the tab.");
|
|
300
|
+
const notice = accentContrastNotice(out.construct);
|
|
301
|
+
if (notice) io.log(notice);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
io.error(`regen failed (${err instanceof Error ? err.message : String(err)}) — last good preview stays up`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const KEY_FILE = ".kai-install-key";
|
|
307
|
+
async function ensureInstalled(dir, files, io) {
|
|
308
|
+
const key = installKey(files);
|
|
309
|
+
const keyPath = join(dir, KEY_FILE);
|
|
310
|
+
const installed = existsSync(keyPath) && readFileSync(keyPath, "utf8") === key;
|
|
311
|
+
if (installed) return;
|
|
312
|
+
io.log(`installing dependencies in ${dir} (first run or deps changed)…`);
|
|
313
|
+
await new Promise((done, fail) => {
|
|
314
|
+
const child = spawn("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
315
|
+
child.on("exit", (code) => code === 0 ? done() : fail(new Error(`npm install exited ${code}`)));
|
|
316
|
+
});
|
|
317
|
+
writeFileSync(keyPath, key);
|
|
318
|
+
}
|
|
319
|
+
async function dev(constructPath, opts = {}) {
|
|
320
|
+
const io = opts.io ?? { log: (s) => console.log(s), error: (s) => console.error(s) };
|
|
321
|
+
const abs = resolve(constructPath);
|
|
322
|
+
const readRaw = () => JSON.parse(readFileSync(abs, "utf8"));
|
|
323
|
+
const first = validateConstruct(readRaw());
|
|
324
|
+
if (!first.ok) {
|
|
325
|
+
for (const p of first.problems) io.error(` ${p.path || "(root)"}: ${p.message}`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
const dir = workDirFor(first.construct.name, process.cwd());
|
|
329
|
+
const files = generateProject(first.construct, { uiSpec: opts.uiSpec });
|
|
330
|
+
writeProject(files, dir);
|
|
331
|
+
const firstNotice = accentContrastNotice(first.construct);
|
|
332
|
+
if (firstNotice) io.log(firstNotice);
|
|
333
|
+
await ensureInstalled(dir, files, io);
|
|
334
|
+
const base = basename(abs);
|
|
335
|
+
watch(dirname(abs), (_event, filename) => {
|
|
336
|
+
if (filename !== base) return;
|
|
337
|
+
regenTurn(readRaw, { write: writeProject }, dir, { uiSpec: opts.uiSpec }, io);
|
|
338
|
+
});
|
|
339
|
+
io.log(`previewing <${first.construct.name}> — edit ${abs} and watch the tab.`);
|
|
340
|
+
const vite = spawn("npm", ["run", "dev"], { cwd: dir, stdio: "inherit" });
|
|
341
|
+
const killVite = () => vite.kill();
|
|
342
|
+
process.once("exit", killVite);
|
|
343
|
+
process.once("SIGINT", killVite);
|
|
344
|
+
process.once("SIGTERM", killVite);
|
|
345
|
+
return new Promise((_, rejectP) => {
|
|
346
|
+
vite.on("exit", (code) => {
|
|
347
|
+
rejectP(new Error(`vite dev exited ${code}`));
|
|
348
|
+
process.exit(code ?? 0);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function atomicWriteJson(abs, value) {
|
|
353
|
+
const tmp = `${abs}.tmp-${process.pid}`;
|
|
354
|
+
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}
|
|
355
|
+
`);
|
|
356
|
+
renameSync(tmp, abs);
|
|
357
|
+
}
|
|
358
|
+
function handleConstructPut(raw, abs) {
|
|
359
|
+
const out = validateConstruct(raw);
|
|
360
|
+
if (!out.ok) return out;
|
|
361
|
+
atomicWriteJson(abs, raw);
|
|
362
|
+
return { ok: true, construct: out.construct };
|
|
363
|
+
}
|
|
364
|
+
function shapeConstructGetResponse(onDisk) {
|
|
365
|
+
const checked = validateConstruct(onDisk);
|
|
366
|
+
return checked.ok ? onDisk : { ...onDisk, problems: checked.problems };
|
|
367
|
+
}
|
|
368
|
+
function createEventHub() {
|
|
369
|
+
const clients = /* @__PURE__ */ new Set();
|
|
370
|
+
return {
|
|
371
|
+
attach(res) {
|
|
372
|
+
res.writeHead(200, {
|
|
373
|
+
"content-type": "text/event-stream",
|
|
374
|
+
"cache-control": "no-cache",
|
|
375
|
+
connection: "keep-alive"
|
|
376
|
+
});
|
|
377
|
+
res.write(": connected\n\n");
|
|
378
|
+
clients.add(res);
|
|
379
|
+
res.on("close", () => clients.delete(res));
|
|
380
|
+
},
|
|
381
|
+
broadcast(event) {
|
|
382
|
+
for (const res of clients) res.write(`event: ${event}
|
|
383
|
+
data: {}
|
|
384
|
+
|
|
385
|
+
`);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
function listenLoopbackOnly(server, port, onListening) {
|
|
390
|
+
server.listen(port, "127.0.0.1", onListening);
|
|
391
|
+
}
|
|
392
|
+
const ASSET_TYPES = {
|
|
393
|
+
".html": "text/html; charset=utf-8",
|
|
394
|
+
".js": "text/javascript; charset=utf-8",
|
|
395
|
+
".css": "text/css; charset=utf-8",
|
|
396
|
+
".svg": "image/svg+xml",
|
|
397
|
+
".map": "application/json"
|
|
398
|
+
};
|
|
399
|
+
function serveBuilderAsset(urlPath, rootDir) {
|
|
400
|
+
const decoded = decodeURIComponent(urlPath.split("?")[0]);
|
|
401
|
+
const rel = decoded === "/" ? "index.html" : decoded.replace(/^\/+/, "");
|
|
402
|
+
const file = resolve(rootDir, rel);
|
|
403
|
+
if (!file.startsWith(resolve(rootDir) + "/") && file !== resolve(rootDir, "index.html")) return void 0;
|
|
404
|
+
if (!existsSync(file)) return void 0;
|
|
405
|
+
return { file, type: ASSET_TYPES[extname(file)] ?? "application/octet-stream" };
|
|
406
|
+
}
|
|
407
|
+
function resolveBuilderPageDir(startDir) {
|
|
408
|
+
const tried = [];
|
|
409
|
+
let dir = startDir;
|
|
410
|
+
for (let i = 0; i < 6; i++) {
|
|
411
|
+
const candidate = join(dir, "builder-page");
|
|
412
|
+
tried.push(candidate);
|
|
413
|
+
if (existsSync(join(candidate, "index.html"))) return { dir: candidate };
|
|
414
|
+
const atPackageRoot = existsSync(join(dir, "package.json"));
|
|
415
|
+
const parent = dirname(dir);
|
|
416
|
+
if (atPackageRoot || parent === dir) break;
|
|
417
|
+
dir = parent;
|
|
418
|
+
}
|
|
419
|
+
return { tried };
|
|
420
|
+
}
|
|
421
|
+
function builderPageDir() {
|
|
422
|
+
const out = resolveBuilderPageDir(dirname(fileURLToPath(import.meta.url)));
|
|
423
|
+
if ("dir" in out) return out.dir;
|
|
424
|
+
throw new Error(
|
|
425
|
+
`Missing build artifact: builder-page/index.html — the builder page ships prebuilt. Tried:
|
|
426
|
+
${out.tried.map((p) => ` ${p}`).join("\n")}
|
|
427
|
+
Run \`nx build ui\` (or npm run build in packages/ui) and try again.`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
async function readJsonBody(req) {
|
|
431
|
+
const chunks = [];
|
|
432
|
+
let size = 0;
|
|
433
|
+
for await (const chunk of req) {
|
|
434
|
+
size += chunk.length;
|
|
435
|
+
if (size > 1e6) throw new Error("body too large");
|
|
436
|
+
chunks.push(chunk);
|
|
437
|
+
}
|
|
438
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
439
|
+
}
|
|
440
|
+
async function devBuilder(constructPath, opts = {}) {
|
|
441
|
+
const io = opts.io ?? { log: (s) => console.log(s), error: (s) => console.error(s) };
|
|
442
|
+
const port = opts.port ?? 4400;
|
|
443
|
+
const previewPort = opts.previewPort ?? 4401;
|
|
444
|
+
let pageDir;
|
|
445
|
+
try {
|
|
446
|
+
pageDir = builderPageDir();
|
|
447
|
+
} catch (err) {
|
|
448
|
+
io.error(err instanceof Error ? err.message : String(err));
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
const hub = createEventHub();
|
|
452
|
+
let abs = constructPath ? resolve(constructPath) : void 0;
|
|
453
|
+
let previewUrl;
|
|
454
|
+
const boot = async (absPath) => {
|
|
455
|
+
const readRaw = () => JSON.parse(readFileSync(absPath, "utf8"));
|
|
456
|
+
const first = validateConstruct(readRaw());
|
|
457
|
+
if (!first.ok) {
|
|
458
|
+
for (const p of first.problems) io.error(` ${p.path || "(root)"}: ${p.message}`);
|
|
459
|
+
throw new Error("construct invalid");
|
|
460
|
+
}
|
|
461
|
+
const dir = workDirFor(first.construct.name, process.cwd());
|
|
462
|
+
const files = generateProject(first.construct, { uiSpec: opts.uiSpec });
|
|
463
|
+
writeProject(files, dir);
|
|
464
|
+
await ensureInstalled(dir, files, io);
|
|
465
|
+
const base = basename(absPath);
|
|
466
|
+
watch(dirname(absPath), (_event, filename) => {
|
|
467
|
+
if (filename !== base) return;
|
|
468
|
+
regenTurn(readRaw, { write: writeProject }, dir, { uiSpec: opts.uiSpec }, io);
|
|
469
|
+
hub.broadcast("construct");
|
|
470
|
+
});
|
|
471
|
+
const vite = spawn("npm", ["run", "dev", "--", "--port", String(previewPort), "--strictPort"], {
|
|
472
|
+
cwd: dir,
|
|
473
|
+
stdio: "inherit"
|
|
474
|
+
});
|
|
475
|
+
const killVite = () => vite.kill();
|
|
476
|
+
process.once("exit", killVite);
|
|
477
|
+
process.once("SIGINT", killVite);
|
|
478
|
+
process.once("SIGTERM", killVite);
|
|
479
|
+
previewUrl = `http://localhost:${previewPort}/`;
|
|
480
|
+
io.log(`previewing <${first.construct.name}> at ${previewUrl}`);
|
|
481
|
+
};
|
|
482
|
+
if (abs) await boot(abs);
|
|
483
|
+
const server = createServer(async (req, res) => {
|
|
484
|
+
const send = (code, body) => {
|
|
485
|
+
res.writeHead(code, { "content-type": "application/json" });
|
|
486
|
+
res.end(JSON.stringify(body));
|
|
487
|
+
};
|
|
488
|
+
try {
|
|
489
|
+
const url = req.url ?? "/";
|
|
490
|
+
if (req.method === "GET" && url === "/api/state") {
|
|
491
|
+
return send(200, abs ? { phase: "panel", constructPath: abs, construct: JSON.parse(readFileSync(abs, "utf8")), previewUrl } : { phase: "start" });
|
|
492
|
+
}
|
|
493
|
+
if (req.method === "GET" && url === "/api/construct") {
|
|
494
|
+
if (!abs) return send(404, { problems: [{ path: "", message: "no construct yet" }] });
|
|
495
|
+
return send(200, shapeConstructGetResponse(JSON.parse(readFileSync(abs, "utf8"))));
|
|
496
|
+
}
|
|
497
|
+
if (req.method === "GET" && url === "/api/events") return hub.attach(res);
|
|
498
|
+
if (req.method === "POST" && url === "/api/construct") {
|
|
499
|
+
if (!abs) return send(409, { problems: [{ path: "", message: "create a construct first" }] });
|
|
500
|
+
const out = handleConstructPut(await readJsonBody(req), abs);
|
|
501
|
+
return out.ok ? send(200, { ok: true }) : send(422, { problems: out.problems });
|
|
502
|
+
}
|
|
503
|
+
if (req.method === "POST" && url === "/api/create") {
|
|
504
|
+
if (abs) return send(409, { problems: [{ path: "", message: "a construct already exists in this session" }] });
|
|
505
|
+
const body = await readJsonBody(req);
|
|
506
|
+
const template = buildableTemplates().find((t) => t.id === body.templateId);
|
|
507
|
+
const starter = body.templateId === "scratch" || !template ? { name: body.name, layout: "fullscreen", provider: { mode: "mock" } } : {
|
|
508
|
+
...template.variants?.find((v) => v.id === body.variantId)?.starter ?? template.starter,
|
|
509
|
+
name: body.name
|
|
510
|
+
};
|
|
511
|
+
const validated = validateConstruct(starter);
|
|
512
|
+
if (!validated.ok) return send(422, { problems: validated.problems });
|
|
513
|
+
const target = resolve(process.cwd(), `${body.name}.construct.json`);
|
|
514
|
+
atomicWriteJson(target, starter);
|
|
515
|
+
abs = target;
|
|
516
|
+
await boot(target);
|
|
517
|
+
return send(200, { previewUrl, construct: starter });
|
|
518
|
+
}
|
|
519
|
+
const asset = serveBuilderAsset(url, pageDir);
|
|
520
|
+
if (asset) {
|
|
521
|
+
res.writeHead(200, { "content-type": asset.type });
|
|
522
|
+
return res.end(readFileSync(asset.file));
|
|
523
|
+
}
|
|
524
|
+
if (req.method === "GET") {
|
|
525
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
526
|
+
return res.end(readFileSync(join(pageDir, "index.html")));
|
|
527
|
+
}
|
|
528
|
+
return send(404, { problems: [{ path: "", message: "not found" }] });
|
|
529
|
+
} catch (err) {
|
|
530
|
+
return send(400, { problems: [{ path: "", message: err instanceof Error ? err.message : String(err) }] });
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
listenLoopbackOnly(server, port, () => io.log(`kai builder at http://localhost:${port}/ — the construct file stays yours.`));
|
|
534
|
+
return new Promise(() => {
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
export {
|
|
538
|
+
atomicWriteJson,
|
|
539
|
+
builderPageDir,
|
|
540
|
+
createEventHub,
|
|
541
|
+
dev,
|
|
542
|
+
devBuilder,
|
|
543
|
+
ensureInstalled,
|
|
544
|
+
handleConstructPut,
|
|
545
|
+
installKey,
|
|
546
|
+
listenLoopbackOnly,
|
|
547
|
+
regenTurn,
|
|
548
|
+
regenerate,
|
|
549
|
+
resolveBuilderPageDir,
|
|
550
|
+
serveBuilderAsset,
|
|
551
|
+
shapeConstructGetResponse,
|
|
552
|
+
workDirFor
|
|
553
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as d,q as m,s as b,p as h,i as l,S as f,m as x,t as p,G as j,H as I,a as R,d as w}from"./define-
|
|
1
|
+
import{c as d,q as m,s as b,p as h,i as l,S as f,m as x,t as p,G as j,H as I,a as R,d as w}from"./define-B3OpsIDE.js";import{c as g}from"./cn-DN5AWfiS.js";import{B as U}from"./button-BM0YTTDQ.js";import{H as V,a as B,b as G}from"./hover-card-C5ptzZOZ.js";import{x as O}from"./x-C4niw05N.js";import{I as q}from"./Icon-DJDuE_-x.js";import{f as W}from"./file-text-eVjcFDrK.js";import{p as X,g as Y,i as Z}from"./paperclip-D0Xyjja2.js";var J=[["path",{d:"M10 12.5 8 15l2 2.5",key:"1tg20x"}],["path",{d:"m14 12.5 2 2.5-2 2.5",key:"yinavb"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z",key:"1mlx9k"}]],K=e=>d(q,m(e,{name:"FileCode",iconNode:J})),Q=K,_=[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"m14.5 12.5-5 5",key:"b62r18"}],["path",{d:"m9.5 12.5 5 5",key:"1rk7el"}]],ee=e=>d(q,m(e,{name:"FileX",iconNode:_})),te=ee;const D=[{pattern:"image/jpeg",kind:"image"},{pattern:"image/png",kind:"image"},{pattern:"image/gif",kind:"image"},{pattern:"image/webp",kind:"image"},{pattern:"application/pdf",kind:"document"},{pattern:"text/*",kind:"text"},{pattern:"application/json",kind:"text"},{pattern:"application/xml",kind:"text"},{pattern:"application/x-yaml",kind:"text"},{pattern:"application/yaml",kind:"text"}],H="text/plain",ae=["","application/octet-stream"],C=e=>e.trim().toLowerCase(),A=e=>ae.includes(e===void 0?"":C(e)),re=e=>{if(!e.startsWith("."))return e;throw new Error(`\`accept\` entry "${e}" is a file extension, and this kit takes media types only. HTML's own accept attribute does take extensions, which is exactly why this throws rather than quietly matching nothing. Use a media type instead -- "text/*" covers source files, "image/*" images, "application/pdf" PDFs, and \`encodableMediaTypes()\` is the full set. You lose nothing by dropping the extension: a file the browser cannot name is decided by decoding its bytes, which is stronger than matching its name.`)},ne=e=>(typeof e=="string"?e.split(","):e).map(C).filter(a=>a!=="").map(re),P=e=>{const a=e.indexOf("/");return a===-1?[e,""]:[e.slice(0,a),e.slice(a+1)]},k=(e,a)=>{const[r,t]=P(e),[i,n]=P(a);return r!=="*"&&r!==i?!1:t==="*"||t===n},ie=(e,a)=>{if(k(e,a))return a;if(k(a,e))return e};function $(e={}){const a=e.accept===void 0?void 0:ne(e.accept),r=[];for(const t of D){if(a===void 0){r.push({...t});continue}for(const i of a){const n=ie(t.pattern,i);n!==void 0&&!r.some(s=>s.pattern===n)&&r.push({pattern:n,kind:t.kind})}}return{types:r.map(t=>t.pattern),accept:r.map(t=>t.pattern).join(","),decide(t){const i=t===void 0?"":C(t);if(A(i))return r.some(s=>k(s.pattern,H))?{status:"undetermined"}:{status:"unsupported"};const n=r.find(s=>k(s.pattern,i));return n?{status:"allowed",kind:n.kind}:D.some(s=>k(s.pattern,i))?{status:"filtered"}:{status:"unsupported"}}}}const E=$();var T=p("<div>"),se=p("<div part=attachment>"),F=p("<span class=sr-only>"),oe=p('<img class="size-full object-cover"height=96 width=96>'),de=p('<img class="size-full rounded object-cover"height=20 width=20>'),ce=p('<span class="text-warning text-caption block truncate">unsupported attachment format'),ue=p('<div part=attachment-name><span class="block truncate">'),le=p("<div part=attachment-name>"),pe=p('<span class="text-muted-foreground text-caption block truncate">');const ge={document:W,image:Z,source:Y,text:Q,unknown:X,unsendable:te},z=e=>{if(e.type==="source-document")return"source";const a=E.decide(e.mediaType);switch(a.status){case"allowed":return a.kind;case"unsupported":return"unsendable";case"undetermined":case"filtered":return"unknown"}},me=e=>{var a;return z(e)!=="unsendable"?void 0:`${((a=e.mediaType)==null?void 0:a.trim())||"This file type"} is not one of the attachment formats a model request can carry.`},N=e=>{if(e.type==="source-document")return e.title||e.filename||"Source";const a=z(e);return e.filename||(a==="image"?"Image":"Attachment")},L=j(),S=j(),he=()=>I(L)??{variant:"grid"},M=()=>{const e=I(S);if(!e)throw new Error("Attachment components must be used within <Attachment>");return e};function fe(e){const[a,r]=b(e,["variant","class","children"]),t=()=>a.variant??"grid";return d(L.Provider,{value:{get variant(){return t()}},get children(){var i=T();return h(i,m({get class(){return g("flex items-start",t()==="list"?"flex-col gap-2":"flex-wrap gap-2",t()==="grid"&&"w-fit",a.class)}},r),!1,!0),l(i,()=>a.children),i}})}function ve(e){const[a,r]=b(e,["data","onRemove","class","children"]),t=he(),i=()=>z(a.data),n=()=>me(a.data);return d(S.Provider,{value:{get data(){return a.data},get mediaCategory(){return i()},get onRemove(){return a.onRemove},get variant(){return t.variant}},get children(){var s=se();return h(s,m({get class(){return g("group relative",t.variant==="grid"&&"size-24 overflow-hidden rounded-lg",t.variant==="inline"&&["flex h-8 cursor-pointer select-none items-center gap-1.5","rounded-md bg-surface-strong px-1.5 text-foreground","font-medium text-sm transition-all","hover:bg-muted"],t.variant==="list"&&["flex w-full items-center gap-3 rounded-lg bg-surface p-3 text-foreground","hover:bg-muted/50"],a.class)},get"data-unsendable"(){return n()===void 0?void 0:""},get title(){return n()}},r),!1,!0),l(s,d(f,{get when(){return n()},children:o=>(()=>{var u=F();return l(u,o),u})()}),null),l(s,()=>a.children,null),s}})}function ye(e){const[a,r]=b(e,["fallbackIcon","class"]),t=M(),i=()=>t.variant==="inline"?"size-3":"size-4",n=o=>d(o,{get class(){return g(i(),t.mediaCategory==="unsendable"?"text-warning":"text-muted-foreground")}}),s=()=>{if(t.mediaCategory==="image"&&t.data.type==="file"&&t.data.url)return t.variant==="grid"?(()=>{var u=oe();return R(c=>{var v=t.data.filename||"Image",y=t.data.url;return v!==c.e&&w(u,"alt",c.e=v),y!==c.t&&w(u,"src",c.t=y),c},{e:void 0,t:void 0}),u})():(()=>{var u=de();return R(c=>{var v=t.data.filename||"Image",y=t.data.url;return v!==c.e&&w(u,"alt",c.e=v),y!==c.t&&w(u,"src",c.t=y),c},{e:void 0,t:void 0}),u})();const o=ge[t.mediaCategory];return a.fallbackIcon??n(o)};return(()=>{var o=T();return h(o,m({get class(){return g("flex shrink-0 items-center justify-center overflow-hidden",t.variant==="grid"&&"size-full bg-muted",t.variant==="inline"&&"size-5 rounded bg-background",t.variant==="list"&&"size-12 rounded bg-muted",a.class)}},r),!1,!0),l(o,s),o})()}function be(e){const[a,r]=b(e,["showMediaType","class"]),t=M(),i=()=>N(t.data);return d(f,{get when(){return t.variant!=="grid"},get fallback(){return d(f,{get when(){return t.mediaCategory!=="image"},get children(){var n=le();return h(n,m({get class(){return g("absolute inset-x-0 bottom-0 truncate px-1.5 py-1 text-caption","bg-background/85 backdrop-blur-sm",t.mediaCategory==="unsendable"?"text-warning":"text-foreground",a.class)}},r),!1,!0),l(n,i),n}})},get children(){var n=ue(),s=n.firstChild;return h(n,m({get class(){return g("min-w-0 flex-1",a.class)}},r),!1,!0),l(s,i),l(n,d(f,{get when(){return x(()=>t.mediaCategory==="unsendable")()&&t.variant==="list"},get fallback(){return d(f,{get when(){return x(()=>!!(a.showMediaType&&t.variant==="list"))()&&t.data.mediaType},get children(){var o=pe();return l(o,()=>t.data.mediaType),o}})},get children(){var o=ce(),u=o.firstChild;return l(o,(()=>{var c=x(()=>!!t.data.mediaType);return()=>c()?`${t.data.mediaType} \xB7 `:""})(),u),o}}),null),n}})}function ke(e){const a=M(),r=t=>{var i;t.stopPropagation(),(i=a.onRemove)==null||i.call(a)};return d(f,{get when(){return a.onRemove},get children(){return d(U,{get"aria-label"(){return e.label??"Remove"},get class(){return g(a.variant==="grid"&&["absolute top-2 right-2 size-6 rounded-full p-0","bg-background/80 backdrop-blur-sm","opacity-0 transition-opacity group-hover:opacity-100","hover:bg-background","[&>svg]:size-3"],a.variant==="inline"&&["size-5 rounded p-0","opacity-0 transition-opacity group-hover:opacity-100","[&>svg]:size-2.5"],a.variant==="list"&&["size-8 shrink-0 rounded p-0","[&>svg]:size-4"],e.class)},onClick:r,type:"button",variant:"ghost",get children(){return[x(()=>e.children??d(O,{})),(()=>{var t=F();return l(t,()=>e.label??"Remove"),t})()]}})}})}function xe(e){return d(V,{get openDelay(){return e.openDelay??0},get closeDelay(){return e.closeDelay??0},get children(){return e.children}})}function we(e){return d(B,{get class(){return e.class},get children(){return e.children}})}function ze(e){return d(G,{get class(){return g("w-auto p-2",e.class)},get children(){return e.children}})}function Ce(e){const[a,r]=b(e,["class","children"]);return(()=>{var t=T();return h(t,m({get class(){return g("flex items-center justify-center p-4 text-muted-foreground text-sm",a.class)}},r),!1,!0),l(t,()=>a.children??"No attachments"),t})()}export{fe as A,E as D,H as U,ve as a,xe as b,we as c,ye as d,be as e,ze as f,N as g,z as h,ke as i,Ce as j,A as n,$ as r};
|