@vendoai/ui 0.4.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/LICENSE +202 -0
- package/README.md +7 -0
- package/dist/chrome/activity-ledger.d.ts +14 -0
- package/dist/chrome/activity-ledger.d.ts.map +1 -0
- package/dist/chrome/activity-ledger.js +40 -0
- package/dist/chrome/activity-ledger.js.map +1 -0
- package/dist/chrome/activity-panel.d.ts +7 -0
- package/dist/chrome/activity-panel.d.ts.map +1 -0
- package/dist/chrome/activity-panel.js +27 -0
- package/dist/chrome/activity-panel.js.map +1 -0
- package/dist/chrome/activity-semantics.d.ts +42 -0
- package/dist/chrome/activity-semantics.d.ts.map +1 -0
- package/dist/chrome/activity-semantics.js +119 -0
- package/dist/chrome/activity-semantics.js.map +1 -0
- package/dist/chrome/approval-card.d.ts +22 -0
- package/dist/chrome/approval-card.d.ts.map +1 -0
- package/dist/chrome/approval-card.js +95 -0
- package/dist/chrome/approval-card.js.map +1 -0
- package/dist/chrome/approval-sheet.d.ts +23 -0
- package/dist/chrome/approval-sheet.d.ts.map +1 -0
- package/dist/chrome/approval-sheet.js +72 -0
- package/dist/chrome/approval-sheet.js.map +1 -0
- package/dist/chrome/automations-panel.d.ts +3 -0
- package/dist/chrome/automations-panel.d.ts.map +1 -0
- package/dist/chrome/automations-panel.js +305 -0
- package/dist/chrome/automations-panel.js.map +1 -0
- package/dist/chrome/build-beat.d.ts +70 -0
- package/dist/chrome/build-beat.d.ts.map +1 -0
- package/dist/chrome/build-beat.js +101 -0
- package/dist/chrome/build-beat.js.map +1 -0
- package/dist/chrome/chrome-css.d.ts +7 -0
- package/dist/chrome/chrome-css.d.ts.map +1 -0
- package/dist/chrome/chrome-css.js +2042 -0
- package/dist/chrome/chrome-css.js.map +1 -0
- package/dist/chrome/chrome-root.d.ts +13 -0
- package/dist/chrome/chrome-root.d.ts.map +1 -0
- package/dist/chrome/chrome-root.js +39 -0
- package/dist/chrome/chrome-root.js.map +1 -0
- package/dist/chrome/clipboard.d.ts +4 -0
- package/dist/chrome/clipboard.d.ts.map +1 -0
- package/dist/chrome/clipboard.js +49 -0
- package/dist/chrome/clipboard.js.map +1 -0
- package/dist/chrome/connect-card.d.ts +19 -0
- package/dist/chrome/connect-card.d.ts.map +1 -0
- package/dist/chrome/connect-card.js +57 -0
- package/dist/chrome/connect-card.js.map +1 -0
- package/dist/chrome/connect-dock.d.ts +25 -0
- package/dist/chrome/connect-dock.d.ts.map +1 -0
- package/dist/chrome/connect-dock.js +192 -0
- package/dist/chrome/connect-dock.js.map +1 -0
- package/dist/chrome/connected-accounts-panel.d.ts +14 -0
- package/dist/chrome/connected-accounts-panel.d.ts.map +1 -0
- package/dist/chrome/connected-accounts-panel.js +157 -0
- package/dist/chrome/connected-accounts-panel.js.map +1 -0
- package/dist/chrome/dev-mode.d.ts +5 -0
- package/dist/chrome/dev-mode.d.ts.map +1 -0
- package/dist/chrome/dev-mode.js +7 -0
- package/dist/chrome/dev-mode.js.map +1 -0
- package/dist/chrome/discoverability.d.ts +33 -0
- package/dist/chrome/discoverability.d.ts.map +1 -0
- package/dist/chrome/discoverability.js +63 -0
- package/dist/chrome/discoverability.js.map +1 -0
- package/dist/chrome/embeds.d.ts +21 -0
- package/dist/chrome/embeds.d.ts.map +1 -0
- package/dist/chrome/embeds.js +181 -0
- package/dist/chrome/embeds.js.map +1 -0
- package/dist/chrome/fluid-thinking.d.ts +15 -0
- package/dist/chrome/fluid-thinking.d.ts.map +1 -0
- package/dist/chrome/fluid-thinking.js +37 -0
- package/dist/chrome/fluid-thinking.js.map +1 -0
- package/dist/chrome/humanize.d.ts +46 -0
- package/dist/chrome/humanize.d.ts.map +1 -0
- package/dist/chrome/humanize.js +104 -0
- package/dist/chrome/humanize.js.map +1 -0
- package/dist/chrome/index.d.ts +39 -0
- package/dist/chrome/index.d.ts.map +1 -0
- package/dist/chrome/index.js +38 -0
- package/dist/chrome/index.js.map +1 -0
- package/dist/chrome/markdown.d.ts +23 -0
- package/dist/chrome/markdown.d.ts.map +1 -0
- package/dist/chrome/markdown.js +149 -0
- package/dist/chrome/markdown.js.map +1 -0
- package/dist/chrome/morph-toast.d.ts +43 -0
- package/dist/chrome/morph-toast.d.ts.map +1 -0
- package/dist/chrome/morph-toast.js +89 -0
- package/dist/chrome/morph-toast.js.map +1 -0
- package/dist/chrome/no-policy-notice.d.ts +8 -0
- package/dist/chrome/no-policy-notice.d.ts.map +1 -0
- package/dist/chrome/no-policy-notice.js +18 -0
- package/dist/chrome/no-policy-notice.js.map +1 -0
- package/dist/chrome/onest-font.gen.d.ts +10 -0
- package/dist/chrome/onest-font.gen.d.ts.map +1 -0
- package/dist/chrome/onest-font.gen.js +10 -0
- package/dist/chrome/onest-font.gen.js.map +1 -0
- package/dist/chrome/overlay-registry.d.ts +66 -0
- package/dist/chrome/overlay-registry.d.ts.map +1 -0
- package/dist/chrome/overlay-registry.js +103 -0
- package/dist/chrome/overlay-registry.js.map +1 -0
- package/dist/chrome/palette-hotkey.d.ts +42 -0
- package/dist/chrome/palette-hotkey.d.ts.map +1 -0
- package/dist/chrome/palette-hotkey.js +91 -0
- package/dist/chrome/palette-hotkey.js.map +1 -0
- package/dist/chrome/policy-notice-body.d.ts +3 -0
- package/dist/chrome/policy-notice-body.d.ts.map +1 -0
- package/dist/chrome/policy-notice-body.js +6 -0
- package/dist/chrome/policy-notice-body.js.map +1 -0
- package/dist/chrome/takeover-portal.d.ts +16 -0
- package/dist/chrome/takeover-portal.d.ts.map +1 -0
- package/dist/chrome/takeover-portal.js +21 -0
- package/dist/chrome/takeover-portal.js.map +1 -0
- package/dist/chrome/thread/attachments.d.ts +24 -0
- package/dist/chrome/thread/attachments.d.ts.map +1 -0
- package/dist/chrome/thread/attachments.js +50 -0
- package/dist/chrome/thread/attachments.js.map +1 -0
- package/dist/chrome/thread/composer.d.ts +63 -0
- package/dist/chrome/thread/composer.d.ts.map +1 -0
- package/dist/chrome/thread/composer.js +259 -0
- package/dist/chrome/thread/composer.js.map +1 -0
- package/dist/chrome/thread/index.d.ts +41 -0
- package/dist/chrome/thread/index.d.ts.map +1 -0
- package/dist/chrome/thread/index.js +258 -0
- package/dist/chrome/thread/index.js.map +1 -0
- package/dist/chrome/thread/message-data.d.ts +35 -0
- package/dist/chrome/thread/message-data.d.ts.map +1 -0
- package/dist/chrome/thread/message-data.js +127 -0
- package/dist/chrome/thread/message-data.js.map +1 -0
- package/dist/chrome/thread/message-list.d.ts +30 -0
- package/dist/chrome/thread/message-list.d.ts.map +1 -0
- package/dist/chrome/thread/message-list.js +11 -0
- package/dist/chrome/thread/message-list.js.map +1 -0
- package/dist/chrome/thread/message.d.ts +18 -0
- package/dist/chrome/thread/message.d.ts.map +1 -0
- package/dist/chrome/thread/message.js +57 -0
- package/dist/chrome/thread/message.js.map +1 -0
- package/dist/chrome/thread/parts.d.ts +53 -0
- package/dist/chrome/thread/parts.d.ts.map +1 -0
- package/dist/chrome/thread/parts.js +184 -0
- package/dist/chrome/thread/parts.js.map +1 -0
- package/dist/chrome/thread/scrolling.d.ts +26 -0
- package/dist/chrome/thread/scrolling.d.ts.map +1 -0
- package/dist/chrome/thread/scrolling.js +214 -0
- package/dist/chrome/thread/scrolling.js.map +1 -0
- package/dist/chrome/truncate.d.ts +12 -0
- package/dist/chrome/truncate.d.ts.map +1 -0
- package/dist/chrome/truncate.js +18 -0
- package/dist/chrome/truncate.js.map +1 -0
- package/dist/chrome/vendo-activities.d.ts +24 -0
- package/dist/chrome/vendo-activities.d.ts.map +1 -0
- package/dist/chrome/vendo-activities.js +38 -0
- package/dist/chrome/vendo-activities.js.map +1 -0
- package/dist/chrome/vendo-overlay.d.ts +63 -0
- package/dist/chrome/vendo-overlay.d.ts.map +1 -0
- package/dist/chrome/vendo-overlay.js +256 -0
- package/dist/chrome/vendo-overlay.js.map +1 -0
- package/dist/chrome/vendo-page.d.ts +3 -0
- package/dist/chrome/vendo-page.d.ts.map +1 -0
- package/dist/chrome/vendo-page.js +162 -0
- package/dist/chrome/vendo-page.js.map +1 -0
- package/dist/chrome/vendo-palette.d.ts +29 -0
- package/dist/chrome/vendo-palette.d.ts.map +1 -0
- package/dist/chrome/vendo-palette.js +95 -0
- package/dist/chrome/vendo-palette.js.map +1 -0
- package/dist/chrome/vendo-slot.d.ts +79 -0
- package/dist/chrome/vendo-slot.d.ts.map +1 -0
- package/dist/chrome/vendo-slot.js +153 -0
- package/dist/chrome/vendo-slot.js.map +1 -0
- package/dist/chrome/vendo-toasts.d.ts +40 -0
- package/dist/chrome/vendo-toasts.d.ts.map +1 -0
- package/dist/chrome/vendo-toasts.js +135 -0
- package/dist/chrome/vendo-toasts.js.map +1 -0
- package/dist/chrome/vendo-trigger.d.ts +24 -0
- package/dist/chrome/vendo-trigger.d.ts.map +1 -0
- package/dist/chrome/vendo-trigger.js +30 -0
- package/dist/chrome/vendo-trigger.js.map +1 -0
- package/dist/chrome/waiting-queue.d.ts +8 -0
- package/dist/chrome/waiting-queue.d.ts.map +1 -0
- package/dist/chrome/waiting-queue.js +21 -0
- package/dist/chrome/waiting-queue.js.map +1 -0
- package/dist/client-impl.d.ts +4 -0
- package/dist/client-impl.d.ts.map +1 -0
- package/dist/client-impl.js +160 -0
- package/dist/client-impl.js.map +1 -0
- package/dist/client.d.ts +136 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +2 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +97 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +71 -0
- package/dist/context.js.map +1 -0
- package/dist/eject-templates/activities/index.tsx +113 -0
- package/dist/eject-templates/templates.json +29 -0
- package/dist/eject-templates/thread/attachments.tsx +69 -0
- package/dist/eject-templates/thread/composer.tsx +409 -0
- package/dist/eject-templates/thread/index.tsx +422 -0
- package/dist/eject-templates/thread/message-data.ts +151 -0
- package/dist/eject-templates/thread/message-list.tsx +123 -0
- package/dist/eject-templates/thread/message.tsx +149 -0
- package/dist/eject-templates/thread/parts.tsx +293 -0
- package/dist/eject-templates/thread/scrolling.ts +223 -0
- package/dist/embeds.d.ts +28 -0
- package/dist/embeds.d.ts.map +1 -0
- package/dist/embeds.js +2 -0
- package/dist/embeds.js.map +1 -0
- package/dist/hooks/index.d.ts +18 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +19 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/scripted-transport.d.ts +44 -0
- package/dist/hooks/scripted-transport.d.ts.map +1 -0
- package/dist/hooks/scripted-transport.js +58 -0
- package/dist/hooks/scripted-transport.js.map +1 -0
- package/dist/hooks/use-activity.d.ts +17 -0
- package/dist/hooks/use-activity.d.ts.map +1 -0
- package/dist/hooks/use-activity.js +50 -0
- package/dist/hooks/use-activity.js.map +1 -0
- package/dist/hooks/use-app.d.ts +19 -0
- package/dist/hooks/use-app.d.ts.map +1 -0
- package/dist/hooks/use-app.js +66 -0
- package/dist/hooks/use-app.js.map +1 -0
- package/dist/hooks/use-approvals.d.ts +13 -0
- package/dist/hooks/use-approvals.d.ts.map +1 -0
- package/dist/hooks/use-approvals.js +14 -0
- package/dist/hooks/use-approvals.js.map +1 -0
- package/dist/hooks/use-apps.d.ts +17 -0
- package/dist/hooks/use-apps.d.ts.map +1 -0
- package/dist/hooks/use-apps.js +30 -0
- package/dist/hooks/use-apps.js.map +1 -0
- package/dist/hooks/use-automations.d.ts +25 -0
- package/dist/hooks/use-automations.d.ts.map +1 -0
- package/dist/hooks/use-automations.js +30 -0
- package/dist/hooks/use-automations.js.map +1 -0
- package/dist/hooks/use-connections.d.ts +12 -0
- package/dist/hooks/use-connections.d.ts.map +1 -0
- package/dist/hooks/use-connections.js +15 -0
- package/dist/hooks/use-connections.js.map +1 -0
- package/dist/hooks/use-connector-catalog.d.ts +8 -0
- package/dist/hooks/use-connector-catalog.d.ts.map +1 -0
- package/dist/hooks/use-connector-catalog.js +52 -0
- package/dist/hooks/use-connector-catalog.js.map +1 -0
- package/dist/hooks/use-grants.d.ts +13 -0
- package/dist/hooks/use-grants.d.ts.map +1 -0
- package/dist/hooks/use-grants.js +14 -0
- package/dist/hooks/use-grants.js.map +1 -0
- package/dist/hooks/use-mobile-takeover.d.ts +22 -0
- package/dist/hooks/use-mobile-takeover.d.ts.map +1 -0
- package/dist/hooks/use-mobile-takeover.js +66 -0
- package/dist/hooks/use-mobile-takeover.js.map +1 -0
- package/dist/hooks/use-resource.d.ts +21 -0
- package/dist/hooks/use-resource.d.ts.map +1 -0
- package/dist/hooks/use-resource.js +79 -0
- package/dist/hooks/use-resource.js.map +1 -0
- package/dist/hooks/use-slot-app.d.ts +19 -0
- package/dist/hooks/use-slot-app.d.ts.map +1 -0
- package/dist/hooks/use-slot-app.js +18 -0
- package/dist/hooks/use-slot-app.js.map +1 -0
- package/dist/hooks/use-threads.d.ts +16 -0
- package/dist/hooks/use-threads.d.ts.map +1 -0
- package/dist/hooks/use-threads.js +15 -0
- package/dist/hooks/use-threads.js.map +1 -0
- package/dist/hooks/use-vendo-overlay.d.ts +31 -0
- package/dist/hooks/use-vendo-overlay.d.ts.map +1 -0
- package/dist/hooks/use-vendo-overlay.js +23 -0
- package/dist/hooks/use-vendo-overlay.js.map +1 -0
- package/dist/hooks/use-vendo-status.d.ts +6 -0
- package/dist/hooks/use-vendo-status.d.ts.map +1 -0
- package/dist/hooks/use-vendo-status.js +28 -0
- package/dist/hooks/use-vendo-status.js.map +1 -0
- package/dist/hooks/use-vendo-thread.d.ts +39 -0
- package/dist/hooks/use-vendo-thread.d.ts.map +1 -0
- package/dist/hooks/use-vendo-thread.js +185 -0
- package/dist/hooks/use-vendo-thread.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/kit/charts/bar.d.ts +16 -0
- package/dist/kit/charts/bar.d.ts.map +1 -0
- package/dist/kit/charts/bar.js +21 -0
- package/dist/kit/charts/bar.js.map +1 -0
- package/dist/kit/charts/donut.d.ts +16 -0
- package/dist/kit/charts/donut.d.ts.map +1 -0
- package/dist/kit/charts/donut.js +17 -0
- package/dist/kit/charts/donut.js.map +1 -0
- package/dist/kit/charts/line.d.ts +19 -0
- package/dist/kit/charts/line.d.ts.map +1 -0
- package/dist/kit/charts/line.js +21 -0
- package/dist/kit/charts/line.js.map +1 -0
- package/dist/kit/charts/progress.d.ts +12 -0
- package/dist/kit/charts/progress.d.ts.map +1 -0
- package/dist/kit/charts/progress.js +25 -0
- package/dist/kit/charts/progress.js.map +1 -0
- package/dist/kit/charts/sanitize.d.ts +24 -0
- package/dist/kit/charts/sanitize.d.ts.map +1 -0
- package/dist/kit/charts/sanitize.js +50 -0
- package/dist/kit/charts/sanitize.js.map +1 -0
- package/dist/kit/charts/sparkline.d.ts +11 -0
- package/dist/kit/charts/sparkline.d.ts.map +1 -0
- package/dist/kit/charts/sparkline.js +17 -0
- package/dist/kit/charts/sparkline.js.map +1 -0
- package/dist/kit/data/badge.d.ts +13 -0
- package/dist/kit/data/badge.d.ts.map +1 -0
- package/dist/kit/data/badge.js +12 -0
- package/dist/kit/data/badge.js.map +1 -0
- package/dist/kit/data/card-list.d.ts +23 -0
- package/dist/kit/data/card-list.d.ts.map +1 -0
- package/dist/kit/data/card-list.js +43 -0
- package/dist/kit/data/card-list.js.map +1 -0
- package/dist/kit/data/data-table.d.ts +32 -0
- package/dist/kit/data/data-table.d.ts.map +1 -0
- package/dist/kit/data/data-table.js +153 -0
- package/dist/kit/data/data-table.js.map +1 -0
- package/dist/kit/data/stat.d.ts +15 -0
- package/dist/kit/data/stat.d.ts.map +1 -0
- package/dist/kit/data/stat.js +28 -0
- package/dist/kit/data/stat.js.map +1 -0
- package/dist/kit/feedback/accordion.d.ts +15 -0
- package/dist/kit/feedback/accordion.d.ts.map +1 -0
- package/dist/kit/feedback/accordion.js +33 -0
- package/dist/kit/feedback/accordion.js.map +1 -0
- package/dist/kit/feedback/callout.d.ts +13 -0
- package/dist/kit/feedback/callout.d.ts.map +1 -0
- package/dist/kit/feedback/callout.js +24 -0
- package/dist/kit/feedback/callout.js.map +1 -0
- package/dist/kit/feedback/tabs.d.ts +14 -0
- package/dist/kit/feedback/tabs.d.ts.map +1 -0
- package/dist/kit/feedback/tabs.js +37 -0
- package/dist/kit/feedback/tabs.js.map +1 -0
- package/dist/kit/format.d.ts +60 -0
- package/dist/kit/format.d.ts.map +1 -0
- package/dist/kit/format.js +123 -0
- package/dist/kit/format.js.map +1 -0
- package/dist/kit/forms/button.d.ts +17 -0
- package/dist/kit/forms/button.d.ts.map +1 -0
- package/dist/kit/forms/button.js +33 -0
- package/dist/kit/forms/button.js.map +1 -0
- package/dist/kit/forms/checkbox.d.ts +9 -0
- package/dist/kit/forms/checkbox.d.ts.map +1 -0
- package/dist/kit/forms/checkbox.js +9 -0
- package/dist/kit/forms/checkbox.js.map +1 -0
- package/dist/kit/forms/date-picker.d.ts +13 -0
- package/dist/kit/forms/date-picker.d.ts.map +1 -0
- package/dist/kit/forms/date-picker.js +9 -0
- package/dist/kit/forms/date-picker.js.map +1 -0
- package/dist/kit/forms/disclaimer.d.ts +8 -0
- package/dist/kit/forms/disclaimer.d.ts.map +1 -0
- package/dist/kit/forms/disclaimer.js +20 -0
- package/dist/kit/forms/disclaimer.js.map +1 -0
- package/dist/kit/forms/field.d.ts +18 -0
- package/dist/kit/forms/field.d.ts.map +1 -0
- package/dist/kit/forms/field.js +19 -0
- package/dist/kit/forms/field.js.map +1 -0
- package/dist/kit/forms/form.d.ts +10 -0
- package/dist/kit/forms/form.d.ts.map +1 -0
- package/dist/kit/forms/form.js +9 -0
- package/dist/kit/forms/form.js.map +1 -0
- package/dist/kit/forms/input.d.ts +14 -0
- package/dist/kit/forms/input.d.ts.map +1 -0
- package/dist/kit/forms/input.js +9 -0
- package/dist/kit/forms/input.js.map +1 -0
- package/dist/kit/forms/select.d.ts +21 -0
- package/dist/kit/forms/select.d.ts.map +1 -0
- package/dist/kit/forms/select.js +35 -0
- package/dist/kit/forms/select.js.map +1 -0
- package/dist/kit/forms/textarea.d.ts +12 -0
- package/dist/kit/forms/textarea.d.ts.map +1 -0
- package/dist/kit/forms/textarea.js +9 -0
- package/dist/kit/forms/textarea.js.map +1 -0
- package/dist/kit/index.d.ts +42 -0
- package/dist/kit/index.d.ts.map +1 -0
- package/dist/kit/index.js +45 -0
- package/dist/kit/index.js.map +1 -0
- package/dist/kit/kit-prompt.d.ts +7 -0
- package/dist/kit/kit-prompt.d.ts.map +1 -0
- package/dist/kit/kit-prompt.js +7 -0
- package/dist/kit/kit-prompt.js.map +1 -0
- package/dist/kit/layout.d.ts +29 -0
- package/dist/kit/layout.d.ts.map +1 -0
- package/dist/kit/layout.js +64 -0
- package/dist/kit/layout.js.map +1 -0
- package/dist/kit/registry.d.ts +11 -0
- package/dist/kit/registry.d.ts.map +1 -0
- package/dist/kit/registry.js +34 -0
- package/dist/kit/registry.js.map +1 -0
- package/dist/kit/schema.d.ts +9 -0
- package/dist/kit/schema.d.ts.map +1 -0
- package/dist/kit/schema.js +9 -0
- package/dist/kit/schema.js.map +1 -0
- package/dist/kit/tokens.d.ts +33 -0
- package/dist/kit/tokens.d.ts.map +1 -0
- package/dist/kit/tokens.js +48 -0
- package/dist/kit/tokens.js.map +1 -0
- package/dist/kit/values.d.ts +55 -0
- package/dist/kit/values.d.ts.map +1 -0
- package/dist/kit/values.js +108 -0
- package/dist/kit/values.js.map +1 -0
- package/dist/theme.d.ts +25 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +100 -0
- package/dist/theme.js.map +1 -0
- package/dist/tree/bindings.d.ts +4 -0
- package/dist/tree/bindings.d.ts.map +1 -0
- package/dist/tree/bindings.js +20 -0
- package/dist/tree/bindings.js.map +1 -0
- package/dist/tree/branded.d.ts +124 -0
- package/dist/tree/branded.d.ts.map +1 -0
- package/dist/tree/branded.js +319 -0
- package/dist/tree/branded.js.map +1 -0
- package/dist/tree/error-boundary.d.ts +22 -0
- package/dist/tree/error-boundary.d.ts.map +1 -0
- package/dist/tree/error-boundary.js +25 -0
- package/dist/tree/error-boundary.js.map +1 -0
- package/dist/tree/fluid-reveal.d.ts +22 -0
- package/dist/tree/fluid-reveal.d.ts.map +1 -0
- package/dist/tree/fluid-reveal.js +28 -0
- package/dist/tree/fluid-reveal.js.map +1 -0
- package/dist/tree/forming-skeleton.d.ts +14 -0
- package/dist/tree/forming-skeleton.d.ts.map +1 -0
- package/dist/tree/forming-skeleton.js +36 -0
- package/dist/tree/forming-skeleton.js.map +1 -0
- package/dist/tree/frames.d.ts +52 -0
- package/dist/tree/frames.d.ts.map +1 -0
- package/dist/tree/frames.js +143 -0
- package/dist/tree/frames.js.map +1 -0
- package/dist/tree/host-mount.d.ts +24 -0
- package/dist/tree/host-mount.d.ts.map +1 -0
- package/dist/tree/host-mount.js +0 -0
- package/dist/tree/host-mount.js.map +1 -0
- package/dist/tree/index.d.ts +9 -0
- package/dist/tree/index.d.ts.map +1 -0
- package/dist/tree/index.js +9 -0
- package/dist/tree/index.js.map +1 -0
- package/dist/tree/jail/JailedComponent.d.ts +41 -0
- package/dist/tree/jail/JailedComponent.d.ts.map +1 -0
- package/dist/tree/jail/JailedComponent.js +269 -0
- package/dist/tree/jail/JailedComponent.js.map +1 -0
- package/dist/tree/jail/runtime-bundle.gen.d.ts +3 -0
- package/dist/tree/jail/runtime-bundle.gen.d.ts.map +1 -0
- package/dist/tree/jail/runtime-bundle.gen.js +3 -0
- package/dist/tree/jail/runtime-bundle.gen.js.map +1 -0
- package/dist/tree/jail/runtime-entry.d.ts +18 -0
- package/dist/tree/jail/runtime-entry.d.ts.map +1 -0
- package/dist/tree/jail/runtime-entry.js +440 -0
- package/dist/tree/jail/runtime-entry.js.map +1 -0
- package/dist/tree/jail/viewport-css.d.ts +17 -0
- package/dist/tree/jail/viewport-css.d.ts.map +1 -0
- package/dist/tree/jail/viewport-css.js +32 -0
- package/dist/tree/jail/viewport-css.js.map +1 -0
- package/dist/tree/mcp-shim/entry.d.ts +2 -0
- package/dist/tree/mcp-shim/entry.d.ts.map +1 -0
- package/dist/tree/mcp-shim/entry.js +45 -0
- package/dist/tree/mcp-shim/entry.js.map +1 -0
- package/dist/tree/mcp-shim/http-open-card.d.ts +5 -0
- package/dist/tree/mcp-shim/http-open-card.d.ts.map +1 -0
- package/dist/tree/mcp-shim/http-open-card.js +61 -0
- package/dist/tree/mcp-shim/http-open-card.js.map +1 -0
- package/dist/tree/mcp-shim/shim-core.d.ts +58 -0
- package/dist/tree/mcp-shim/shim-core.d.ts.map +1 -0
- package/dist/tree/mcp-shim/shim-core.js +176 -0
- package/dist/tree/mcp-shim/shim-core.js.map +1 -0
- package/dist/tree/mcp-shim/theme.d.ts +8 -0
- package/dist/tree/mcp-shim/theme.d.ts.map +1 -0
- package/dist/tree/mcp-shim/theme.js +36 -0
- package/dist/tree/mcp-shim/theme.js.map +1 -0
- package/dist/tree/notice.d.ts +8 -0
- package/dist/tree/notice.d.ts.map +1 -0
- package/dist/tree/notice.js +30 -0
- package/dist/tree/notice.js.map +1 -0
- package/dist/tree/primitives.d.ts +30 -0
- package/dist/tree/primitives.d.ts.map +1 -0
- package/dist/tree/primitives.js +105 -0
- package/dist/tree/primitives.js.map +1 -0
- package/dist/tree/renderer-v2.d.ts +15 -0
- package/dist/tree/renderer-v2.d.ts.map +1 -0
- package/dist/tree/renderer-v2.js +71 -0
- package/dist/tree/renderer-v2.js.map +1 -0
- package/dist/tree/renderer.d.ts +77 -0
- package/dist/tree/renderer.d.ts.map +1 -0
- package/dist/tree/renderer.js +376 -0
- package/dist/tree/renderer.js.map +1 -0
- package/dist/voice/driver.d.ts +94 -0
- package/dist/voice/driver.d.ts.map +1 -0
- package/dist/voice/driver.js +2 -0
- package/dist/voice/driver.js.map +1 -0
- package/dist/voice/index.d.ts +7 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +5 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/realtime-driver.d.ts +57 -0
- package/dist/voice/realtime-driver.d.ts.map +1 -0
- package/dist/voice/realtime-driver.js +592 -0
- package/dist/voice/realtime-driver.js.map +1 -0
- package/dist/voice/stage.d.ts +12 -0
- package/dist/voice/stage.d.ts.map +1 -0
- package/dist/voice/stage.js +259 -0
- package/dist/voice/stage.js.map +1 -0
- package/dist/voice/use-voice-approvals.d.ts +16 -0
- package/dist/voice/use-voice-approvals.d.ts.map +1 -0
- package/dist/voice/use-voice-approvals.js +77 -0
- package/dist/voice/use-voice-approvals.js.map +1 -0
- package/dist/voice/use-voice.d.ts +26 -0
- package/dist/voice/use-voice.d.ts.map +1 -0
- package/dist/voice/use-voice.js +201 -0
- package/dist/voice/use-voice.js.map +1 -0
- package/dist/voice/voice-act.d.ts +13 -0
- package/dist/voice/voice-act.d.ts.map +1 -0
- package/dist/voice/voice-act.js +301 -0
- package/dist/voice/voice-act.js.map +1 -0
- package/dist/voice/voice-blob.d.ts +17 -0
- package/dist/voice/voice-blob.d.ts.map +1 -0
- package/dist/voice/voice-blob.js +67 -0
- package/dist/voice/voice-blob.js.map +1 -0
- package/dist/voice/voice-consent.d.ts +17 -0
- package/dist/voice/voice-consent.d.ts.map +1 -0
- package/dist/voice/voice-consent.js +45 -0
- package/dist/voice/voice-consent.js.map +1 -0
- package/dist/voice/voice-drawer.d.ts +10 -0
- package/dist/voice/voice-drawer.d.ts.map +1 -0
- package/dist/voice/voice-drawer.js +22 -0
- package/dist/voice/voice-drawer.js.map +1 -0
- package/dist/wire-types.d.ts +238 -0
- package/dist/wire-types.d.ts.map +1 -0
- package/dist/wire-types.js +2 -0
- package/dist/wire-types.js.map +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejected from @vendoai/ui v0.4.0 — yours to edit.
|
|
3
|
+
* Presentation only: data and wire logic still flow through @vendoai/ui
|
|
4
|
+
* imports, so protocol updates keep working while these pixels are yours.
|
|
5
|
+
*/
|
|
6
|
+
import { isToolUIPart } from "ai";
|
|
7
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { useVendoDiscoverability, useVendoGreeting } from "../../context.js";
|
|
9
|
+
import { useVendoThread } from "../../hooks/use-vendo-thread.js";
|
|
10
|
+
import { StatusRibbon } from "../build-beat.js";
|
|
11
|
+
import { ChromeRoot } from "../chrome-root.js";
|
|
12
|
+
import { defaultVendoGreeting, hasSeen, markSeen, type VendoDiscoverability, type VendoGreeting } from "../discoverability.js";
|
|
13
|
+
import { MorphToast, type MorphToastProps } from "../morph-toast.js";
|
|
14
|
+
import { Composer, dragHasFiles, useComposer } from "./composer.js";
|
|
15
|
+
import { MessageList } from "./message-list.js";
|
|
16
|
+
import { useMessageWindow, useStickToBottom } from "./scrolling.js";
|
|
17
|
+
import { approvalByCall, riskByCall, userText } from "./message-data.js";
|
|
18
|
+
|
|
19
|
+
/** Lane pick 4B — a rich landing suggestion: two-line starter card. */
|
|
20
|
+
export interface VendoSuggestionCard {
|
|
21
|
+
/** Card headline (verb-first reads best: "Build a view"). */
|
|
22
|
+
title: string;
|
|
23
|
+
/** One concrete outcome line under the title. */
|
|
24
|
+
description: string;
|
|
25
|
+
/** Sent as the message on tap; defaults to the title. */
|
|
26
|
+
prompt?: string;
|
|
27
|
+
/** Optional host-supplied leading icon node. */
|
|
28
|
+
icon?: import("react").ReactNode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface VendoThreadProps {
|
|
32
|
+
threadId?: string;
|
|
33
|
+
/** Landing headline shown above the composer while the thread is empty. */
|
|
34
|
+
greeting?: string;
|
|
35
|
+
/** Starter prompts on the empty landing; clicking sends one. Lane pick 4B —
|
|
36
|
+
* a plain string keeps today's pill chip; the object form renders a two-line
|
|
37
|
+
* starter card (title + concrete outcome, optional icon) with more scent. */
|
|
38
|
+
suggestions?: (string | VendoSuggestionCard)[];
|
|
39
|
+
/** Show a mic affordance in the composer that launches the host's voice surface. */
|
|
40
|
+
onVoice?: () => void;
|
|
41
|
+
/** ENG-222 — fires with the effective thread id once it is known, including
|
|
42
|
+
* the fresh `thr_` the server mints for a new conversation. Lets a host
|
|
43
|
+
* surface (e.g. VendoPage's sidebar) pull the new conversation into its list. */
|
|
44
|
+
onThreadId?: (threadId: string) => void;
|
|
45
|
+
/** The discoverability dial (ui-usage-dx §6), overriding the provider's:
|
|
46
|
+
* `"quiet"` disables the fire-once greeting-as-tutorial below. */
|
|
47
|
+
discoverability?: VendoDiscoverability;
|
|
48
|
+
/** Greeting-as-tutorial content (intro + prompt chips) overriding the
|
|
49
|
+
* provider's `greeting`. Distinct from `greeting` above (the returning-user
|
|
50
|
+
* landing headline) — this one renders once per user, ever. */
|
|
51
|
+
firstRunGreeting?: VendoGreeting;
|
|
52
|
+
/** Rendered directly above the composer in both landing and conversation
|
|
53
|
+
* layouts — the seam VendoOverlay uses for its command chip strip (the
|
|
54
|
+
* one-surface ⌘K design). Presentation-only; the thread never reads it. */
|
|
55
|
+
composerAccessory?: import("react").ReactNode;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 08-ui §4 — conversation chrome over the headless thread transport. */
|
|
59
|
+
export function VendoThread({
|
|
60
|
+
threadId,
|
|
61
|
+
greeting = "What can I help you build?",
|
|
62
|
+
suggestions = [],
|
|
63
|
+
onVoice,
|
|
64
|
+
onThreadId,
|
|
65
|
+
discoverability,
|
|
66
|
+
firstRunGreeting,
|
|
67
|
+
composerAccessory,
|
|
68
|
+
}: VendoThreadProps) {
|
|
69
|
+
const thread = useVendoThread(threadId);
|
|
70
|
+
// ui-usage-dx §6 — greeting-as-tutorial: the user's FIRST-ever conversation
|
|
71
|
+
// open (fresh thread only — an adopted thread with history is not a first
|
|
72
|
+
// open and does not burn the flag) renders the agent-voiced intro + starter
|
|
73
|
+
// chips locally. Presentation-only: nothing here touches the transport or
|
|
74
|
+
// the transcript; chips prefill the composer and never send.
|
|
75
|
+
const providerDial = useVendoDiscoverability();
|
|
76
|
+
const dial = discoverability ?? providerDial;
|
|
77
|
+
const contextGreeting = useVendoGreeting();
|
|
78
|
+
const tutorial = firstRunGreeting ?? contextGreeting ?? defaultVendoGreeting;
|
|
79
|
+
const [tutorialActive, setTutorialActive] = useState(false);
|
|
80
|
+
// Arming is REACTIVE, not mount-only: surfaces that don't remount their
|
|
81
|
+
// thread (VendoPage flips threadId props on one instance) become eligible
|
|
82
|
+
// later — e.g. when the page's dial gate opens on an explicit "New
|
|
83
|
+
// conversation". Burned on first showing (not on interaction) — a reload
|
|
84
|
+
// mid-look never replays it, per the once-per-user-ever rule.
|
|
85
|
+
const messageCount = thread.messages.length;
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (tutorialActive || dial === "quiet" || threadId !== undefined) return;
|
|
88
|
+
if (messageCount > 0 || hasSeen("greeting")) return;
|
|
89
|
+
markSeen("greeting");
|
|
90
|
+
setTutorialActive(true);
|
|
91
|
+
}, [tutorialActive, dial, threadId, messageCount]);
|
|
92
|
+
// Once the landing is left (a turn exists, or the surface switches to a
|
|
93
|
+
// stored thread), the tutorial is done for good on this instance too — the
|
|
94
|
+
// burned flag keeps every later landing plain.
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (tutorialActive && (messageCount > 0 || threadId !== undefined)) setTutorialActive(false);
|
|
97
|
+
}, [tutorialActive, messageCount, threadId]);
|
|
98
|
+
// ENG-222 — surface the effective (possibly server-minted) thread id upward.
|
|
99
|
+
const reportedThreadId = thread.threadId;
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (reportedThreadId !== undefined) onThreadId?.(reportedThreadId);
|
|
102
|
+
}, [reportedThreadId, onThreadId]);
|
|
103
|
+
const busy = thread.status === "submitted" || thread.status === "streaming";
|
|
104
|
+
// busy is a content-revision signal for the scroll hook: turn-actions mount
|
|
105
|
+
// below the last turn when a stream settles, which changes the list height.
|
|
106
|
+
const scroll = useStickToBottom(thread.messages, threadId, busy);
|
|
107
|
+
const approvalCardRefs = useRef(new Map<string, HTMLDivElement | null>());
|
|
108
|
+
const [morph, setMorph] = useState<Omit<MorphToastProps, "onDone"> | null>(null);
|
|
109
|
+
|
|
110
|
+
// A build's approval lands below a tall generated view — off-screen — so it
|
|
111
|
+
// would sit unnoticed until the reader scrolls. When a NEW approval appears,
|
|
112
|
+
// bring it into view (and re-stick), so consent is never something you have
|
|
113
|
+
// to go hunting for.
|
|
114
|
+
const seenApprovalsRef = useRef<Set<string>>(new Set());
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
const pending = thread.messages
|
|
117
|
+
.flatMap(message => message.parts)
|
|
118
|
+
.filter(part => isToolUIPart(part) && part.state === "approval-requested")
|
|
119
|
+
.map(part => (part as { approval?: { id?: string } }).approval?.id)
|
|
120
|
+
.filter((id): id is string => typeof id === "string");
|
|
121
|
+
const fresh = pending.find(id => !seenApprovalsRef.current.has(id));
|
|
122
|
+
seenApprovalsRef.current = new Set(pending);
|
|
123
|
+
if (fresh === undefined) return;
|
|
124
|
+
const timer = setTimeout(() => {
|
|
125
|
+
const card = approvalCardRefs.current.get(fresh)?.querySelector<HTMLElement>(".fl-approval");
|
|
126
|
+
// block: "end", not "center": a sibling surface sharing this pane's
|
|
127
|
+
// flex column (VendoStage docked below the thread, Maple's /vendo tab)
|
|
128
|
+
// can leave the list shorter than the card itself at a short viewport
|
|
129
|
+
// height — centering then crops evenly off BOTH edges, hiding the
|
|
130
|
+
// card's own Approve/Decline row behind whatever renders next in flow
|
|
131
|
+
// with no way to reach it. Bottom-aligning always leaves the action
|
|
132
|
+
// row — the part the reader actually needs — as the last thing in
|
|
133
|
+
// view, consistent with the list's own stick-to-bottom behavior.
|
|
134
|
+
if (card) card.scrollIntoView({ behavior: "smooth", block: "end" });
|
|
135
|
+
else scroll.jumpToLatest();
|
|
136
|
+
}, 80);
|
|
137
|
+
return () => clearTimeout(timer);
|
|
138
|
+
}, [thread.messages, scroll]);
|
|
139
|
+
|
|
140
|
+
const messageWindow = useMessageWindow(thread.messages, scroll.listRef, threadId);
|
|
141
|
+
// ENG-218 — entrance-animation gating on restore. The .fl-item-in rise runs
|
|
142
|
+
// when an article first mounts; a reopened long thread mounts them all at once
|
|
143
|
+
// → a stampede on first paint. We record every message id present when the
|
|
144
|
+
// thread is first shown (and after each switch) as "restored" and suppress
|
|
145
|
+
// the entrance on those; only turns that arrive AFTER restore (streamed
|
|
146
|
+
// replies, sends) animate. A ref, not state — read during render, no re-render.
|
|
147
|
+
const restoredIdsRef = useRef<{ key: string | undefined; ids: Set<string> }>({ key: undefined, ids: new Set() });
|
|
148
|
+
if (restoredIdsRef.current.key !== threadId) {
|
|
149
|
+
restoredIdsRef.current = { key: threadId, ids: new Set(thread.messages.map(message => message.id)) };
|
|
150
|
+
} else if (restoredIdsRef.current.ids.size === 0 && thread.messages.length > 0) {
|
|
151
|
+
// First non-empty render after an async history load (mount → list/get):
|
|
152
|
+
// that whole batch is a restore, not new arrivals.
|
|
153
|
+
restoredIdsRef.current.ids = new Set(thread.messages.map(message => message.id));
|
|
154
|
+
}
|
|
155
|
+
const isRestored = (id: string) => restoredIdsRef.current.ids.has(id);
|
|
156
|
+
const composerApi = useComposer({ busy, sendMessage: message => thread.sendMessage(message) });
|
|
157
|
+
const { setDraft, setQueued, textareaRef, send } = composerApi;
|
|
158
|
+
const risks = useMemo(() => riskByCall(thread.messages), [thread.messages]);
|
|
159
|
+
const guardApprovals = useMemo(() => approvalByCall(thread.messages), [thread.messages]);
|
|
160
|
+
const landing = thread.messages.length === 0;
|
|
161
|
+
const activeAssistant = thread.messages.at(-1)?.role === "assistant" ? thread.messages.at(-1) : undefined;
|
|
162
|
+
const assistantHasVisibleText = activeAssistant?.parts.some(
|
|
163
|
+
part => part.type === "text" && part.text.trim().length > 0,
|
|
164
|
+
) ?? false;
|
|
165
|
+
// ENG-217 — the three streaming moments each get exactly ONE affordance:
|
|
166
|
+
// before the first chunk the generating skeleton holds the floor; a streamed
|
|
167
|
+
// turn whose text is still empty shows the lone caret (renderPart); once
|
|
168
|
+
// text flows the trailing caret rides .fl-md--streaming. FluidThinking
|
|
169
|
+
// covers the remaining gap (tool phases with no text yet).
|
|
170
|
+
const awaitingFirstChunk = busy && (activeAssistant === undefined || activeAssistant.parts.length === 0);
|
|
171
|
+
const lastPart = activeAssistant?.parts.at(-1);
|
|
172
|
+
const caretShowing = busy && lastPart?.type === "text" && lastPart.state === "streaming"
|
|
173
|
+
&& lastPart.text.trim().length === 0;
|
|
174
|
+
// Once ANY build beat exists in the active turn, the checklist is the
|
|
175
|
+
// progress voice — the thinking indicator between beats reads as two
|
|
176
|
+
// indicators fighting.
|
|
177
|
+
const hasBeats = activeAssistant?.parts.some(part => isToolUIPart(part)) ?? false;
|
|
178
|
+
const working = busy && !assistantHasVisibleText && !awaitingFirstChunk && !caretShowing && !hasBeats;
|
|
179
|
+
|
|
180
|
+
// ENG-215 — edit the last user turn: drop it (and anything after) from the
|
|
181
|
+
// transcript and refill the composer, so re-sending amends rather than
|
|
182
|
+
// duplicates. Only meaningful when idle.
|
|
183
|
+
const lastUserIndex = (() => {
|
|
184
|
+
for (let index = thread.messages.length - 1; index >= 0; index -= 1) {
|
|
185
|
+
if (thread.messages[index]?.role === "user") return index;
|
|
186
|
+
}
|
|
187
|
+
return -1;
|
|
188
|
+
})();
|
|
189
|
+
// Turn actions attach by id, not list index: the map below renders a windowed
|
|
190
|
+
// slice (ENG-218), so positional indices no longer line up with thread.messages.
|
|
191
|
+
const lastUserId = lastUserIndex >= 0 ? thread.messages[lastUserIndex]?.id : undefined;
|
|
192
|
+
const editLast = () => {
|
|
193
|
+
if (busy || lastUserIndex < 0) return;
|
|
194
|
+
const message = thread.messages[lastUserIndex];
|
|
195
|
+
if (!message) return;
|
|
196
|
+
thread.setMessages(thread.messages.slice(0, lastUserIndex));
|
|
197
|
+
setQueued(null);
|
|
198
|
+
setDraft(userText(message));
|
|
199
|
+
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// ENG-215 — regenerate the last assistant turn (re-issues from the preserved
|
|
203
|
+
// user message; no duplication). Only when idle and an assistant turn exists.
|
|
204
|
+
const lastAssistantIndex = (() => {
|
|
205
|
+
for (let index = thread.messages.length - 1; index >= 0; index -= 1) {
|
|
206
|
+
if (thread.messages[index]?.role === "assistant") return index;
|
|
207
|
+
}
|
|
208
|
+
return -1;
|
|
209
|
+
})();
|
|
210
|
+
const lastAssistantId = lastAssistantIndex >= 0 ? thread.messages[lastAssistantIndex]?.id : undefined;
|
|
211
|
+
const regenerateLast = () => {
|
|
212
|
+
if (busy || lastAssistantIndex < 0) return;
|
|
213
|
+
void thread.regenerate();
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// ENG-214 — a broken turn (failed send, mid-stream drop, any thread.error)
|
|
217
|
+
// surfaces VISIBLY in the thread, not only through the hidden status span.
|
|
218
|
+
// The copy stays friendly — raw transport errors are announced to assistive
|
|
219
|
+
// tech below but never printed to end users. Retry regenerates the failed
|
|
220
|
+
// turn from the preserved user message (no duplication).
|
|
221
|
+
const errorBanner = thread.error ? (
|
|
222
|
+
<div className="fl-error">
|
|
223
|
+
<span>Something went wrong and the response didn’t finish.</span>
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
className="fl-error-retry"
|
|
227
|
+
onClick={() => {
|
|
228
|
+
// Nothing to re-issue (sends append the user turn before any request
|
|
229
|
+
// fires, so this is a defensive rail): degrade to dismissing the
|
|
230
|
+
// error instead of letting regenerate() throw on an empty thread.
|
|
231
|
+
if (thread.messages.length === 0) {
|
|
232
|
+
thread.clearError();
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
void thread.regenerate();
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
Retry
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
241
|
+
) : null;
|
|
242
|
+
|
|
243
|
+
const composer = (
|
|
244
|
+
<Composer
|
|
245
|
+
composer={composerApi}
|
|
246
|
+
busy={busy}
|
|
247
|
+
status={thread.status}
|
|
248
|
+
errorMessage={thread.status === "error" && thread.error ? thread.error.message : undefined}
|
|
249
|
+
onStop={() => void thread.stop()}
|
|
250
|
+
onVoice={onVoice}
|
|
251
|
+
/>
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const approvals = thread.messages.flatMap(message => message.parts).filter(isToolUIPart).filter(part => part.state === "approval-requested");
|
|
255
|
+
|
|
256
|
+
// Lane pick C1 — the live status ribbon: while the turn works through tool
|
|
257
|
+
// calls (and no text has started flowing), the ACTIVE call narrates above
|
|
258
|
+
// the composer — label · elapsed · step N of M. The transcript stays
|
|
259
|
+
// beat-free (parts.tsx renders only errored calls). Once text streams the
|
|
260
|
+
// ribbon yields the floor to the caret choreography.
|
|
261
|
+
const activeToolParts = (activeAssistant?.parts ?? []).filter(isToolUIPart);
|
|
262
|
+
const liveToolPart = [...activeToolParts].reverse()
|
|
263
|
+
.find(part => part.state !== "output-available" && part.state !== "output-error");
|
|
264
|
+
// A turn parked on an approval is not "busy" (the stream yielded), but the
|
|
265
|
+
// pause still narrates: the ribbon holds "— waiting for your approval" while
|
|
266
|
+
// the card sits in the transcript.
|
|
267
|
+
const awaitingApprovalPart = activeToolParts.find(part => part.state === "approval-requested");
|
|
268
|
+
const activeToolPart = busy && !assistantHasVisibleText
|
|
269
|
+
? liveToolPart ?? (activeToolParts.length > 0 && !caretShowing ? activeToolParts.at(-1) : undefined)
|
|
270
|
+
: awaitingApprovalPart;
|
|
271
|
+
const ribbon = activeToolPart ? (
|
|
272
|
+
<StatusRibbon
|
|
273
|
+
part={activeToolPart}
|
|
274
|
+
stepIndex={activeToolParts.indexOf(activeToolPart) + 1}
|
|
275
|
+
stepTotal={activeToolParts.length}
|
|
276
|
+
risk={risks.get(activeToolPart.toolCallId) ?? "read"}
|
|
277
|
+
/>
|
|
278
|
+
) : null;
|
|
279
|
+
|
|
280
|
+
// Lane pick 2E — the WHOLE thread surface is the drop target (the composer
|
|
281
|
+
// bar no longer owns drag): a huge, overshoot-proof zone with a centered
|
|
282
|
+
// card naming what will happen. Depth counter as before (child crossings).
|
|
283
|
+
const { dragDepth, setDragDepth, setFiles } = composerApi;
|
|
284
|
+
const dropProps = {
|
|
285
|
+
onDragEnter: (event: React.DragEvent) => {
|
|
286
|
+
if (!dragHasFiles(event)) return;
|
|
287
|
+
event.preventDefault();
|
|
288
|
+
setDragDepth(depth => depth + 1);
|
|
289
|
+
},
|
|
290
|
+
onDragOver: (event: React.DragEvent) => {
|
|
291
|
+
if (dragHasFiles(event)) event.preventDefault();
|
|
292
|
+
},
|
|
293
|
+
onDragLeave: (event: React.DragEvent) => {
|
|
294
|
+
if (dragHasFiles(event)) setDragDepth(depth => Math.max(0, depth - 1));
|
|
295
|
+
},
|
|
296
|
+
onDrop: (event: React.DragEvent) => {
|
|
297
|
+
if (!dragHasFiles(event)) return;
|
|
298
|
+
event.preventDefault();
|
|
299
|
+
setDragDepth(0);
|
|
300
|
+
const dropped = Array.from(event.dataTransfer.files);
|
|
301
|
+
if (dropped.length > 0) setFiles(current => [...current, ...dropped]);
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
const dropOverlay = dragDepth > 0 ? (
|
|
305
|
+
<div className="fl-drop fl-drop--thread">
|
|
306
|
+
<div className="fl-drop-card">
|
|
307
|
+
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
308
|
+
<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48" />
|
|
309
|
+
</svg>
|
|
310
|
+
Drop files to attach to your message
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
) : null;
|
|
314
|
+
|
|
315
|
+
if (landing) {
|
|
316
|
+
return (
|
|
317
|
+
<ChromeRoot>
|
|
318
|
+
<div className="fl-thread" role="region" aria-label="Vendo conversation" {...dropProps}>
|
|
319
|
+
{dropOverlay}
|
|
320
|
+
<div className="fl-landing">
|
|
321
|
+
{tutorialActive ? (
|
|
322
|
+
// The one-time tutorial replaces the headline (and the host's
|
|
323
|
+
// send-on-tap suggestion chips — two chip rows with different
|
|
324
|
+
// behaviors would read as one). Chips PREFILL, never send.
|
|
325
|
+
<div className="fl-greeting" role="group" aria-label="Getting started">
|
|
326
|
+
<p className="fl-greeting-intro">{tutorial.intro}</p>
|
|
327
|
+
<div className="fl-chips fl-greeting-chips">
|
|
328
|
+
{tutorial.prompts.slice(0, 3).map((text, i) => (
|
|
329
|
+
<button
|
|
330
|
+
type="button"
|
|
331
|
+
className="fl-chip"
|
|
332
|
+
key={`${i}-${text}`}
|
|
333
|
+
onClick={() => {
|
|
334
|
+
setDraft(text);
|
|
335
|
+
requestAnimationFrame(() => textareaRef.current?.focus());
|
|
336
|
+
}}
|
|
337
|
+
>
|
|
338
|
+
{text}
|
|
339
|
+
</button>
|
|
340
|
+
))}
|
|
341
|
+
</div>
|
|
342
|
+
</div>
|
|
343
|
+
) : (
|
|
344
|
+
<h1 className="fl-greet">{greeting}</h1>
|
|
345
|
+
)}
|
|
346
|
+
{errorBanner}
|
|
347
|
+
{composerAccessory}
|
|
348
|
+
<div className="fl-landing-composer">{composer}</div>
|
|
349
|
+
{!tutorialActive && suggestions.length > 0 ? (
|
|
350
|
+
// Lane pick 4B — object suggestions render as two-line starter
|
|
351
|
+
// cards (title + concrete outcome, optional host icon); plain
|
|
352
|
+
// strings keep the pill chip. A MIXED array renders both
|
|
353
|
+
// containers (cards grid, then a chips row) so string entries
|
|
354
|
+
// never stretch as grid cells (AI-review catch). Both send on
|
|
355
|
+
// tap, unchanged.
|
|
356
|
+
<>
|
|
357
|
+
{suggestions.some(s => typeof s !== "string") ? (
|
|
358
|
+
<div className="fl-cards">
|
|
359
|
+
{suggestions.flatMap((suggestion, i) => {
|
|
360
|
+
if (typeof suggestion === "string") return [];
|
|
361
|
+
const prompt = suggestion.prompt ?? suggestion.title;
|
|
362
|
+
return [(
|
|
363
|
+
<button type="button" className="fl-card" key={`${i}-${suggestion.title}`} onClick={() => send(prompt)}>
|
|
364
|
+
{suggestion.icon}
|
|
365
|
+
<b>{suggestion.title}</b>
|
|
366
|
+
<span>{suggestion.description}</span>
|
|
367
|
+
</button>
|
|
368
|
+
)];
|
|
369
|
+
})}
|
|
370
|
+
</div>
|
|
371
|
+
) : null}
|
|
372
|
+
{suggestions.some(s => typeof s === "string") ? (
|
|
373
|
+
<div className="fl-chips">
|
|
374
|
+
{suggestions.flatMap((text, i) => (
|
|
375
|
+
typeof text === "string"
|
|
376
|
+
? [<button type="button" className="fl-chip" key={`${i}-${text}`} onClick={() => send(text)}>{text}</button>]
|
|
377
|
+
: []
|
|
378
|
+
))}
|
|
379
|
+
</div>
|
|
380
|
+
) : null}
|
|
381
|
+
</>
|
|
382
|
+
) : null}
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
</ChromeRoot>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return (
|
|
390
|
+
<ChromeRoot>
|
|
391
|
+
<div className="fl-thread" role="region" aria-label="Vendo conversation" {...dropProps}>
|
|
392
|
+
{dropOverlay}
|
|
393
|
+
<MessageList
|
|
394
|
+
scroll={scroll}
|
|
395
|
+
messageWindow={messageWindow}
|
|
396
|
+
busy={busy}
|
|
397
|
+
risks={risks}
|
|
398
|
+
isRestored={isRestored}
|
|
399
|
+
activeAssistantId={activeAssistant?.id}
|
|
400
|
+
lastUserId={lastUserId}
|
|
401
|
+
lastAssistantId={lastAssistantId}
|
|
402
|
+
onEditLast={editLast}
|
|
403
|
+
onRegenerateLast={regenerateLast}
|
|
404
|
+
approvals={approvals}
|
|
405
|
+
guardApprovals={guardApprovals}
|
|
406
|
+
cardRefs={approvalCardRefs}
|
|
407
|
+
respond={response => thread.addToolApprovalResponse(response)}
|
|
408
|
+
onMorph={setMorph}
|
|
409
|
+
messages={thread.messages}
|
|
410
|
+
sendMessage={message => thread.sendMessage(message)}
|
|
411
|
+
awaitingFirstChunk={awaitingFirstChunk}
|
|
412
|
+
working={working}
|
|
413
|
+
/>
|
|
414
|
+
{errorBanner}
|
|
415
|
+
{composerAccessory}
|
|
416
|
+
{ribbon}
|
|
417
|
+
{composer}
|
|
418
|
+
</div>
|
|
419
|
+
{morph ? <MorphToast {...morph} onDone={() => setMorph(null)} /> : null}
|
|
420
|
+
</ChromeRoot>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejected from @vendoai/ui v0.4.0 — yours to edit.
|
|
3
|
+
* Presentation only: data and wire logic still flow through @vendoai/ui
|
|
4
|
+
* imports, so protocol updates keep working while these pixels are yours.
|
|
5
|
+
*/
|
|
6
|
+
import type { ApprovalRequest, RiskLabel } from "@vendoai/core";
|
|
7
|
+
import { isToolUIPart, type UIMessage } from "ai";
|
|
8
|
+
import { previewArgs } from "../humanize.js";
|
|
9
|
+
import { LONG_TEXT_CAP, truncateHead } from "../truncate.js";
|
|
10
|
+
|
|
11
|
+
export function partData(part: UIMessage["parts"][number]): unknown {
|
|
12
|
+
return "data" in part ? part.data : part;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ENG-216 — a stable placeholder for the in-thread synthesized ApprovalRequest's
|
|
16
|
+
// required `createdAt`. The wire approval part carries no timestamp; this value
|
|
17
|
+
// is never displayed (the card hides the context byline in-thread) and a fixed
|
|
18
|
+
// constant replaces the former per-render `new Date()` that churned on every
|
|
19
|
+
// re-render and broke deterministic tests.
|
|
20
|
+
export const SYNTHESIZED_CREATED_AT = "1970-01-01T00:00:00.000Z";
|
|
21
|
+
|
|
22
|
+
export function riskByCall(messages: UIMessage[]): Map<string, RiskLabel> {
|
|
23
|
+
const risks = new Map<string, RiskLabel>();
|
|
24
|
+
for (const message of messages) {
|
|
25
|
+
for (const part of message.parts) {
|
|
26
|
+
if (part.type !== "data-vendo-approval") continue;
|
|
27
|
+
const data = partData(part) as { toolCallId?: unknown; risk?: unknown };
|
|
28
|
+
if (typeof data.toolCallId === "string" && ["read", "write", "destructive"].includes(String(data.risk))) {
|
|
29
|
+
risks.set(data.toolCallId, data.risk as RiskLabel);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return risks;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Guard approval metadata by tool call — carried in the data-vendo-approval
|
|
37
|
+
part beside the native ai-SDK approval (whose own id is transport-local). */
|
|
38
|
+
export function approvalByCall(messages: UIMessage[]): Map<string, {
|
|
39
|
+
approvalId?: string;
|
|
40
|
+
invalidatedGrant?: ApprovalRequest["invalidatedGrant"];
|
|
41
|
+
}> {
|
|
42
|
+
const approvals = new Map<string, {
|
|
43
|
+
approvalId?: string;
|
|
44
|
+
invalidatedGrant?: ApprovalRequest["invalidatedGrant"];
|
|
45
|
+
}>();
|
|
46
|
+
for (const message of messages) {
|
|
47
|
+
for (const part of message.parts) {
|
|
48
|
+
if (part.type !== "data-vendo-approval") continue;
|
|
49
|
+
const data = partData(part) as {
|
|
50
|
+
toolCallId?: unknown;
|
|
51
|
+
approvalId?: unknown;
|
|
52
|
+
invalidatedGrant?: { id?: unknown; grantedAt?: unknown };
|
|
53
|
+
};
|
|
54
|
+
if (typeof data.toolCallId !== "string") continue;
|
|
55
|
+
approvals.set(data.toolCallId, {
|
|
56
|
+
...(typeof data.approvalId === "string" ? { approvalId: data.approvalId } : {}),
|
|
57
|
+
...(typeof data.invalidatedGrant?.id === "string"
|
|
58
|
+
&& typeof data.invalidatedGrant.grantedAt === "string"
|
|
59
|
+
? { invalidatedGrant: data.invalidatedGrant as NonNullable<ApprovalRequest["invalidatedGrant"]> }
|
|
60
|
+
: {}),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return approvals;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function toolName(part: Extract<UIMessage["parts"][number], { toolCallId: string }>): string {
|
|
68
|
+
return part.type === "dynamic-tool" && "toolName" in part ? part.toolName : part.type.replace(/^tool-/, "");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The app-boundary title: the payload's `name`, else its first heading Text node. */
|
|
72
|
+
export function appTitle(payload: unknown): string | undefined {
|
|
73
|
+
const named = (payload as { name?: unknown }).name;
|
|
74
|
+
if (typeof named === "string" && named.trim()) return named;
|
|
75
|
+
const nodes = (payload as { nodes?: Array<{ component?: string; props?: Record<string, unknown> }> }).nodes;
|
|
76
|
+
if (!Array.isArray(nodes)) return undefined;
|
|
77
|
+
for (const node of nodes) {
|
|
78
|
+
if (node.component === "Text" && node.props?.variant === "heading" && typeof node.props.text === "string") {
|
|
79
|
+
return node.props.text;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A stable signature for a tool part — same tool + same input = the same call. */
|
|
86
|
+
function toolSignature(part: Extract<UIMessage["parts"][number], { toolCallId: string }>): string {
|
|
87
|
+
const input = "input" in part ? part.input : undefined;
|
|
88
|
+
let serialized: string;
|
|
89
|
+
try {
|
|
90
|
+
serialized = JSON.stringify(input);
|
|
91
|
+
} catch {
|
|
92
|
+
serialized = String(input);
|
|
93
|
+
}
|
|
94
|
+
return `${toolName(part)}::${serialized}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** ENG-216 — collapse runs of consecutive identical tool chips (e.g. eight
|
|
98
|
+
`host_listClientDocuments` calls) into one entry carrying a count. The
|
|
99
|
+
latest part in the run is kept so the chip icon reflects the final state. */
|
|
100
|
+
export function collapseToolRuns(
|
|
101
|
+
parts: UIMessage["parts"],
|
|
102
|
+
): { part: UIMessage["parts"][number]; index: number; count: number }[] {
|
|
103
|
+
const items: { part: UIMessage["parts"][number]; index: number; count: number }[] = [];
|
|
104
|
+
parts.forEach((part, index) => {
|
|
105
|
+
const previous = items.at(-1);
|
|
106
|
+
if (
|
|
107
|
+
isToolUIPart(part)
|
|
108
|
+
&& previous !== undefined
|
|
109
|
+
&& isToolUIPart(previous.part)
|
|
110
|
+
&& toolSignature(previous.part) === toolSignature(part)
|
|
111
|
+
) {
|
|
112
|
+
previous.count += 1;
|
|
113
|
+
previous.part = part;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
items.push({ part, index, count: 1 });
|
|
117
|
+
});
|
|
118
|
+
return items;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** The plain text a user turn carried, joined across its text parts — the seed
|
|
122
|
+
for "edit last message" (ENG-215). */
|
|
123
|
+
export function userText(message: UIMessage): string {
|
|
124
|
+
return message.parts
|
|
125
|
+
.filter((part): part is Extract<UIMessage["parts"][number], { type: "text" }> => part.type === "text")
|
|
126
|
+
.map(part => part.text)
|
|
127
|
+
.join("");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** What "copy this turn" yields for an assistant message: its text parts (the
|
|
131
|
+
markdown source), blank-line separated — tool beats and views don't copy. */
|
|
132
|
+
export function assistantText(message: UIMessage): string {
|
|
133
|
+
return message.parts
|
|
134
|
+
.filter((part): part is Extract<UIMessage["parts"][number], { type: "text" }> => part.type === "text")
|
|
135
|
+
.map(part => part.text)
|
|
136
|
+
.join("\n\n");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** ENG-216 — the in-thread approval preview is built client-side (the wire part
|
|
140
|
+
carries no descriptor), so format args as readable `Label: value` lines
|
|
141
|
+
instead of the raw JSON with literal \n escapes end users were reading. */
|
|
142
|
+
export function preview(input: unknown): string {
|
|
143
|
+
// ENG-216 — readable `Label: value` lines instead of raw JSON. ENG-218 — then
|
|
144
|
+
// bound the result before it reaches the DOM: a huge argument blob (dumped
|
|
145
|
+
// rows, base64) otherwise renders unbounded inside the approval card's <pre>,
|
|
146
|
+
// blowing up layout and the node count.
|
|
147
|
+
const formatted = previewArgs(input);
|
|
148
|
+
return formatted.length > LONG_TEXT_CAP
|
|
149
|
+
? `${truncateHead(formatted)}\n… (${(formatted.length / 1000).toFixed(0)}k chars, truncated)`
|
|
150
|
+
: formatted;
|
|
151
|
+
}
|