@digithings-ai/ui 0.0.0-stage → 0.1.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 +48 -2
- package/package.json +143 -4
- package/src/components/NavShell.tsx +776 -0
- package/src/components/SocialRow.tsx +87 -0
- package/src/components/Spinner.tsx +27 -0
- package/src/components/StackLogo.tsx +40 -0
- package/src/components/Terminal.tsx +110 -0
- package/src/components/TerminalManifest.tsx +212 -0
- package/src/components/ThemeProvider.tsx +271 -0
- package/src/components/account/AuthCard.tsx +309 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
- package/src/components/brand/BrandWordmark.tsx +32 -0
- package/src/components/changelog/ReleaseRail.tsx +81 -0
- package/src/components/changelog/index.ts +1 -0
- package/src/components/chat/ChatCodeBlock.tsx +67 -0
- package/src/components/chat/ChatMarkdown.tsx +66 -0
- package/src/components/chat/ChatMarkdownSource.tsx +203 -0
- package/src/components/chat/ChatMermaidBlock.tsx +202 -0
- package/src/components/chat/ChatMessage.tsx +77 -0
- package/src/components/chat/ChatPlayback.tsx +422 -0
- package/src/components/chat/ChatStreamCursor.tsx +25 -0
- package/src/components/chat/ChatThinking.tsx +113 -0
- package/src/components/chat/ChatToolCall.tsx +190 -0
- package/src/components/chat/ChatTranscript.tsx +60 -0
- package/src/components/chat/ChatWidgetFrame.tsx +107 -0
- package/src/components/chat/DigichatBootLoader.tsx +683 -0
- package/src/components/chat/DigichatLauncher.tsx +361 -0
- package/src/components/chat/DigichatThread.tsx +118 -0
- package/src/components/chat/DigichatThreadList.tsx +54 -0
- package/src/components/chat/DigichatWordmark.tsx +24 -0
- package/src/components/chat/DotMatrix.tsx +650 -0
- package/src/components/chat/boot-lab.tsx +766 -0
- package/src/components/chat/boot-signal.ts +144 -0
- package/src/components/chat/chat-surfaces.ts +52 -0
- package/src/components/chat/connection-status.ts +40 -0
- package/src/components/chat/digichat-wordmark.ts +355 -0
- package/src/components/chat/disclosure-chevron.tsx +49 -0
- package/src/components/chat/followable-href.ts +9 -0
- package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
- package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
- package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
- package/src/components/chat/gallery-thread/cn.ts +1 -0
- package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
- package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
- package/src/components/chat/gallery-thread/css.d.ts +6 -0
- package/src/components/chat/gallery-thread/file.tsx +238 -0
- package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
- package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
- package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
- package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
- package/src/components/chat/gallery-thread/image.tsx +519 -0
- package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
- package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
- package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
- package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
- package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
- package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
- package/src/components/chat/gallery-thread/source.tsx +76 -0
- package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
- package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
- package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
- package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
- package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
- package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
- package/src/components/chat/gallery-thread/work-status.ts +66 -0
- package/src/components/chat/overlay-scrollbar.tsx +86 -0
- package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
- package/src/components/chat/skins/SOURCE.md +36 -0
- package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
- package/src/components/chat/skins/base/aui-default/README.md +45 -0
- package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
- package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
- package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
- package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
- package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
- package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
- package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
- package/src/components/chat/skins/base/docs-model-options.ts +6 -0
- package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
- package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
- package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
- package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
- package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
- package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
- package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
- package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
- package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
- package/src/components/chat/skins/base/markdown-text.tsx +294 -0
- package/src/components/chat/skins/base/model.ts +1 -0
- package/src/components/chat/skins/base/thread.tsx +1050 -0
- package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
- package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
- package/src/components/chat/skins/base/ui/badge.tsx +51 -0
- package/src/components/chat/skins/base/ui/button.tsx +67 -0
- package/src/components/chat/skins/base/ui/command.tsx +185 -0
- package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
- package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
- package/src/components/chat/skins/base/ui/popover.tsx +97 -0
- package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
- package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
- package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
- package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
- package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
- package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
- package/src/components/chat/skins/chatgpt.tsx +448 -0
- package/src/components/chat/skins/claude.tsx +380 -0
- package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
- package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
- package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
- package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
- package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
- package/src/components/chat/skins/digichat.tsx +144 -0
- package/src/components/chat/skins/expo-react-native.tsx +29 -0
- package/src/components/chat/skins/gemini.tsx +322 -0
- package/src/components/chat/skins/grok-icon.tsx +34 -0
- package/src/components/chat/skins/grok.tsx +369 -0
- package/src/components/chat/skins/index.ts +46 -0
- package/src/components/chat/skins/perplexity.tsx +462 -0
- package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
- package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
- package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
- package/src/components/chat/skins/react-ink.tsx +97 -0
- package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
- package/src/components/chat/skins/thread-skin-view.tsx +156 -0
- package/src/components/chat/skins/thread-skins.ts +143 -0
- package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
- package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
- package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
- package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
- package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
- package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
- package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
- package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
- package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
- package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
- package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
- package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
- package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
- package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
- package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
- package/src/components/chat/stock/SOURCE.md +90 -0
- package/src/components/chat/stock/artifacts-panel.tsx +305 -0
- package/src/components/chat/stock/attachment.aui.tsx +280 -0
- package/src/components/chat/stock/chat-notice.tsx +143 -0
- package/src/components/chat/stock/chat-private-mode.tsx +64 -0
- package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
- package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
- package/src/components/chat/stock/file.tsx +265 -0
- package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
- package/src/components/chat/stock/image.tsx +531 -0
- package/src/components/chat/stock/index.ts +129 -0
- package/src/components/chat/stock/json-view.tsx +140 -0
- package/src/components/chat/stock/markdown-text.tsx +319 -0
- package/src/components/chat/stock/message-error.aui.tsx +96 -0
- package/src/components/chat/stock/message-export-menu.tsx +156 -0
- package/src/components/chat/stock/palette-row-preview.tsx +26 -0
- package/src/components/chat/stock/reasoning.aui.tsx +120 -0
- package/src/components/chat/stock/reasoning.tsx +335 -0
- package/src/components/chat/stock/skin-chrome.tsx +81 -0
- package/src/components/chat/stock/skin-credit.tsx +63 -0
- package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
- package/src/components/chat/stock/skin-palette-context.ts +16 -0
- package/src/components/chat/stock/skin-runtime.tsx +52 -0
- package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
- package/src/components/chat/stock/skin-types.ts +217 -0
- package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
- package/src/components/chat/stock/stock-send-gate.tsx +94 -0
- package/src/components/chat/stock/stock-shape.tsx +39 -0
- package/src/components/chat/stock/thread.aui.tsx +645 -0
- package/src/components/chat/stock/tool-display.ts +6 -0
- package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
- package/src/components/chat/stock/tool-group.aui.tsx +244 -0
- package/src/components/chat/stock/tool-surface.ts +120 -0
- package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
- package/src/components/chat/stock/ui/avatar.tsx +108 -0
- package/src/components/chat/stock/ui/button.tsx +81 -0
- package/src/components/chat/stock/ui/collapsible.tsx +21 -0
- package/src/components/chat/stock/ui/dialog.tsx +163 -0
- package/src/components/chat/stock/ui/skeleton.tsx +13 -0
- package/src/components/chat/stock/ui/textarea.tsx +20 -0
- package/src/components/chat/stock/ui/tooltip.tsx +68 -0
- package/src/components/chat/stock/use-attachment-src.ts +42 -0
- package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
- package/src/components/chat/strip-model-boilerplate.ts +42 -0
- package/src/components/chat/suggestion-cycle.tsx +230 -0
- package/src/components/chat/suggestion-scroll-row.tsx +81 -0
- package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
- package/src/components/chat/trace-grouping/chain-state.ts +141 -0
- package/src/components/chat/trace-grouping/index.ts +32 -0
- package/src/components/chat/trace-grouping/tool-row.ts +74 -0
- package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
- package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
- package/src/components/chat/trace-i18n/core.ts +48 -0
- package/src/components/chat/trace-i18n/index.tsx +23 -0
- package/src/components/chat/trace-i18n/locales/en.ts +24 -0
- package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
- package/src/components/chat/trace-i18n/types.ts +35 -0
- package/src/components/chat/trace-spacing.ts +249 -0
- package/src/components/chat/transcript/activity-view.ts +375 -0
- package/src/components/chat/transcript/chat-export.ts +133 -0
- package/src/components/chat/transcript/index.ts +10 -0
- package/src/components/chat/transcript/save-file.ts +209 -0
- package/src/components/chat/transcript/transcript-markdown.ts +428 -0
- package/src/components/chat/transcript/types.ts +81 -0
- package/src/components/chat/turn-outcome.ts +52 -0
- package/src/components/chat/use-warmup-phase.ts +18 -0
- package/src/components/chat/work-status-lead.tsx +49 -0
- package/src/components/chrome.tsx +264 -0
- package/src/components/command-palette/CommandPalette.tsx +404 -0
- package/src/components/command-palette/index.ts +6 -0
- package/src/components/contact/ContactMailto.tsx +112 -0
- package/src/components/contact/index.ts +5 -0
- package/src/components/conviction/ConvictionMeter.tsx +40 -0
- package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
- package/src/components/conviction/index.ts +7 -0
- package/src/components/data-layout/BentoGrid.tsx +52 -0
- package/src/components/data-layout/CardRail.tsx +150 -0
- package/src/components/data-layout/DotMatrixStat.tsx +65 -0
- package/src/components/data-layout/FeatureCell.tsx +80 -0
- package/src/components/data-layout/MediaFrame.tsx +125 -0
- package/src/components/data-layout/ModuleGrid.tsx +735 -0
- package/src/components/data-layout/Odometer.tsx +149 -0
- package/src/components/data-layout/ProductFrame.tsx +79 -0
- package/src/components/data-layout/TestimonialWall.tsx +139 -0
- package/src/components/data-layout/index.ts +19 -0
- package/src/components/data-layout/treemap.ts +368 -0
- package/src/components/deck/DeckStack.tsx +243 -0
- package/src/components/desk/DataTable.tsx +373 -0
- package/src/components/desk/KpiGrid.tsx +80 -0
- package/src/components/desk/Sparkline.tsx +63 -0
- package/src/components/desk/StateBlock.tsx +132 -0
- package/src/components/desk/index.ts +18 -0
- package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
- package/src/components/diagrams/ArchitectureTour.tsx +912 -0
- package/src/components/diagrams/TerminalSchematic.tsx +192 -0
- package/src/components/diagrams/architecture-svg.tsx +384 -0
- package/src/components/diagrams/index.ts +30 -0
- package/src/components/diagrams/mermaid-theme.ts +115 -0
- package/src/components/diagrams/tour-camera.ts +171 -0
- package/src/components/docs/CodeTabs.tsx +90 -0
- package/src/components/docs/CopyCommand.tsx +151 -0
- package/src/components/docs/DocsLayout.tsx +197 -0
- package/src/components/docs/DocsSearch.tsx +97 -0
- package/src/components/docs/Endpoint.tsx +135 -0
- package/src/components/document/DocumentFrame.tsx +43 -0
- package/src/components/document/GlyphList.tsx +51 -0
- package/src/components/document/PageTitle.tsx +44 -0
- package/src/components/document/Prose.tsx +38 -0
- package/src/components/document/Section.tsx +55 -0
- package/src/components/document/index.ts +13 -0
- package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
- package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
- package/src/components/effects-chrome/Pipeline.tsx +226 -0
- package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
- package/src/components/effects-chrome/StackingPanels.tsx +101 -0
- package/src/components/effects-chrome/TabStrip.tsx +232 -0
- package/src/components/effects-chrome/ToastStack.tsx +201 -0
- package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
- package/src/components/effects-chrome/index.ts +35 -0
- package/src/components/emblems.tsx +188 -0
- package/src/components/faviconTheme.ts +23 -0
- package/src/components/figure/Figure.tsx +38 -0
- package/src/components/figure/index.ts +2 -0
- package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
- package/src/components/finance-charts/EquityCurve.tsx +71 -0
- package/src/components/finance-charts/PriceChart.tsx +119 -0
- package/src/components/finance-charts/chart-host.tsx +236 -0
- package/src/components/finance-charts/chart-scale.ts +93 -0
- package/src/components/finance-charts/demo-data.ts +88 -0
- package/src/components/finance-charts/index.ts +46 -0
- package/src/components/finance-charts/lw-chart.tsx +292 -0
- package/src/components/finance-composites/MarketBar.tsx +243 -0
- package/src/components/finance-composites/OrderBook.tsx +133 -0
- package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
- package/src/components/finance-composites/SortableTable.tsx +144 -0
- package/src/components/finance-composites/StockTicker.tsx +65 -0
- package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
- package/src/components/finance-composites/index.ts +28 -0
- package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
- package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
- package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
- package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
- package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
- package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
- package/src/components/finance-tearsheet/charts.tsx +2624 -0
- package/src/components/finance-tearsheet/demo-data.ts +177 -0
- package/src/components/finance-tearsheet/format.ts +41 -0
- package/src/components/finance-tearsheet/index.ts +120 -0
- package/src/components/finance-tearsheet/print.ts +52 -0
- package/src/components/finance-tearsheet/risk-bands.ts +48 -0
- package/src/components/finance-tearsheet/stats.ts +35 -0
- package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
- package/src/components/finance-tearsheet/types.ts +58 -0
- package/src/components/footer/FooterCells.tsx +109 -0
- package/src/components/footer/index.ts +6 -0
- package/src/components/graph.tsx +158 -0
- package/src/components/icons.tsx +98 -0
- package/src/components/landing/PixelWordmark.tsx +36 -0
- package/src/components/logos.ts +39 -0
- package/src/components/marquee/Marquee.tsx +204 -0
- package/src/components/metrics/PerfMetrics.tsx +68 -0
- package/src/components/metrics/StatCounter.tsx +104 -0
- package/src/components/page-geometry.tsx +177 -0
- package/src/components/pricing/Pricing.tsx +174 -0
- package/src/components/pricing/PricingMatrix.tsx +219 -0
- package/src/components/prose/index.ts +2 -0
- package/src/components/prose/prose.tsx +86 -0
- package/src/components/repo-activity/RepoActivity.tsx +599 -0
- package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
- package/src/components/repo-activity/demo.ts +201 -0
- package/src/components/repo-activity/fetch.ts +211 -0
- package/src/components/repo-activity/heatmap.ts +123 -0
- package/src/components/repo-activity/index.ts +28 -0
- package/src/components/repo-activity/types.ts +99 -0
- package/src/components/stages/NumberedStages.tsx +116 -0
- package/src/components/symbols/marks.tsx +116 -0
- package/src/components/symbols/terminal-lockup.tsx +136 -0
- package/src/components/symbols/terminal-marks.tsx +226 -0
- package/src/components/terminal/ChatResponseLoader.tsx +67 -0
- package/src/components/terminal/ContainerBootLoader.tsx +82 -0
- package/src/components/terminal/TerminalStepCaret.tsx +202 -0
- package/src/components/themeInit.ts +24 -0
- package/src/components/typography/MotionReveal.tsx +108 -0
- package/src/components/typography/TypewriterReveal.tsx +101 -0
- package/src/components/typography/WordReveal.tsx +143 -0
- package/src/data/modules.ts +378 -0
- package/src/data/subsystems.ts +101 -0
- package/src/index.ts +587 -0
- package/src/lib/base-path.ts +60 -0
- package/src/lib/cx.ts +25 -0
- package/src/lib/gloomberb.ts +69 -0
- package/src/lib/record.ts +19 -0
- package/src/lib/stub-payload.ts +183 -0
- package/src/lib/useBodyScrollLock.ts +44 -0
- package/src/lib/utils.ts +6 -0
- package/src/motion/primitives.tsx +105 -0
- package/src/motion/scroll-glide.ts +62 -0
- package/src/motion/scrolly-core.ts +38 -0
- package/src/motion/scrolly.tsx +95 -0
- package/src/navigation/HashScrollManager.tsx +167 -0
- package/src/navigation/hashScroll.ts +78 -0
- package/src/replay/browser.ts +280 -0
- package/src/replay/chat-export-run.ts +121 -0
- package/src/replay/export-format.ts +25 -0
- package/src/replay/export-mount.ts +32 -0
- package/src/replay/filename.ts +54 -0
- package/src/replay/index.ts +21 -0
- package/src/replay/redact-dom.ts +178 -0
- package/src/replay/redact.ts +113 -0
- package/src/replay/snapshot.ts +659 -0
- package/src/styles/account-auth.css +339 -0
- package/src/styles/brand-wordmark.css +11 -0
- package/src/styles/card-rail.css +120 -0
- package/src/styles/chat-aui.css +1143 -0
- package/src/styles/chat-core.css +469 -0
- package/src/styles/chat-digichat.css +2531 -0
- package/src/styles/chat-math.css +70 -0
- package/src/styles/chat-skin-palette.css +138 -0
- package/src/styles/chat-stock-menu.css +37 -0
- package/src/styles/chat-widgets.css +190 -0
- package/src/styles/command-palette.css +372 -0
- package/src/styles/controls-core.css +2261 -0
- package/src/styles/controls-overlay.css +603 -0
- package/src/styles/data-layout.css +288 -0
- package/src/styles/deck.css +141 -0
- package/src/styles/diagrams.css +1860 -0
- package/src/styles/digichat-app-theme.css +250 -0
- package/src/styles/digichat-boot-loader.css +487 -0
- package/src/styles/digichat-launcher.css +377 -0
- package/src/styles/docs.css +165 -0
- package/src/styles/effects-chrome.css +888 -0
- package/src/styles/finance-composites.css +214 -0
- package/src/styles/finance-tearsheet-overlay.css +90 -0
- package/src/styles/finance-tearsheet.css +945 -0
- package/src/styles/marquee.css +168 -0
- package/src/styles/metrics.css +82 -0
- package/src/styles/nav-shell.css +551 -0
- package/src/styles/pricing.css +79 -0
- package/src/styles/repo-activity.css +575 -0
- package/src/styles/stages.css +69 -0
- package/src/styles/terminal-loaders.css +122 -0
- package/src/styles/terminal-manifest.css +228 -0
- package/src/styles/web-theme.css +1007 -0
- package/src/styles/word-reveal.css +204 -0
- package/src/theme/apply-theme.ts +214 -0
- package/src/theme/index.ts +27 -0
- package/src/theme/palette-registry.ts +855 -0
- package/src/theme/tui-prefs.ts +64 -0
- package/src/ui/alert.tsx +78 -0
- package/src/ui/avatar.tsx +104 -0
- package/src/ui/badge.tsx +75 -0
- package/src/ui/breadcrumb.tsx +61 -0
- package/src/ui/button.tsx +67 -0
- package/src/ui/card.tsx +139 -0
- package/src/ui/checkbox.tsx +27 -0
- package/src/ui/collapsible.tsx +32 -0
- package/src/ui/date-pager.tsx +325 -0
- package/src/ui/dialog.tsx +157 -0
- package/src/ui/dropdown-menu.tsx +267 -0
- package/src/ui/empty-state.tsx +165 -0
- package/src/ui/field.tsx +104 -0
- package/src/ui/form.tsx +36 -0
- package/src/ui/icon-button.tsx +36 -0
- package/src/ui/index.ts +34 -0
- package/src/ui/input.tsx +33 -0
- package/src/ui/kbd.tsx +30 -0
- package/src/ui/label.tsx +32 -0
- package/src/ui/pager.tsx +119 -0
- package/src/ui/pagination.tsx +126 -0
- package/src/ui/radio-group.tsx +51 -0
- package/src/ui/search-bar.tsx +85 -0
- package/src/ui/segmented-control.tsx +76 -0
- package/src/ui/select.tsx +257 -0
- package/src/ui/separator.tsx +24 -0
- package/src/ui/sheet.tsx +141 -0
- package/src/ui/skeleton.tsx +76 -0
- package/src/ui/slider.tsx +76 -0
- package/src/ui/switch.tsx +31 -0
- package/src/ui/table.tsx +179 -0
- package/src/ui/tabs.tsx +89 -0
- package/src/ui/tags-input.tsx +168 -0
- package/src/ui/textarea.tsx +17 -0
- package/src/ui/tooltip.tsx +71 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared markdown serializer for digichat turn copy + full-thread export (#3465).
|
|
3
|
+
*
|
|
4
|
+
* Payload rules: keep fenced code / GFM tables; strip Foundry citation markers;
|
|
5
|
+
* optional Sources lines from citation cards (title + path only — never vault body,
|
|
6
|
+
* tool JSON, BYOK keys, or headers). Searching/tool rows and slash notes are omitted
|
|
7
|
+
* because callers only pass user/assistant text turns.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { REDACTED, redactString } from "../../../replay/redact";
|
|
11
|
+
import { stripFoundryCitationMarkers } from "./activity-view";
|
|
12
|
+
import { saveTextFile } from "./save-file";
|
|
13
|
+
|
|
14
|
+
export type TranscriptSource = {
|
|
15
|
+
title: string;
|
|
16
|
+
path: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type TranscriptTurn = {
|
|
20
|
+
role: "user" | "assistant";
|
|
21
|
+
content: string;
|
|
22
|
+
/** Citation cards already shown on that assistant turn (title + path only). */
|
|
23
|
+
sources?: readonly TranscriptSource[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type CopyMarkdownResult = "clipboard" | "download" | "postMessage" | "textarea";
|
|
27
|
+
|
|
28
|
+
const COPY_POST_MESSAGE_TYPE = "digichat:copy";
|
|
29
|
+
|
|
30
|
+
/** Single-turn markdown — the string already fed to MiniMarkdown / ChatMarkdown. */
|
|
31
|
+
export function serializeAssistantMarkdown(
|
|
32
|
+
content: string,
|
|
33
|
+
sources?: readonly TranscriptSource[],
|
|
34
|
+
): string {
|
|
35
|
+
const body = stripFoundryCitationMarkers(content).trim();
|
|
36
|
+
const sourceBlock = formatSources(sources);
|
|
37
|
+
if (!sourceBlock) return body;
|
|
38
|
+
return body ? `${body}\n\n${sourceBlock}` : sourceBlock;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Full thread: `## You` / `## digichat` per text turn, in order. */
|
|
42
|
+
export function serializeThreadMarkdown(turns: readonly TranscriptTurn[]): string {
|
|
43
|
+
const blocks: string[] = [];
|
|
44
|
+
for (const turn of turns) {
|
|
45
|
+
const heading = turn.role === "user" ? "## You" : "## digichat";
|
|
46
|
+
const body =
|
|
47
|
+
turn.role === "assistant"
|
|
48
|
+
? serializeAssistantMarkdown(turn.content, turn.sources)
|
|
49
|
+
: turn.content.trim();
|
|
50
|
+
if (!body) continue;
|
|
51
|
+
blocks.push(`${heading}\n\n${body}`);
|
|
52
|
+
}
|
|
53
|
+
return blocks.join("\n\n");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function formatSources(sources?: readonly TranscriptSource[]): string {
|
|
57
|
+
if (!sources?.length) return "";
|
|
58
|
+
const lines = sources
|
|
59
|
+
.map((s) => {
|
|
60
|
+
const title = (s.title || s.path || "").trim();
|
|
61
|
+
const path = (s.path || "").trim();
|
|
62
|
+
if (!title && !path) return null;
|
|
63
|
+
if (path && path !== title) return `- ${title} (${path})`;
|
|
64
|
+
return `- ${title || path}`;
|
|
65
|
+
})
|
|
66
|
+
.filter((line): line is string => Boolean(line));
|
|
67
|
+
if (!lines.length) return "";
|
|
68
|
+
return `### Sources\n\n${lines.join("\n")}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Iframe-safe download — always available when `document` exists. */
|
|
72
|
+
/** Save a text export. See `save-file.ts` for the phone and iframe paths. */
|
|
73
|
+
export function downloadTextFile(filename: string, text: string, mime: string): void {
|
|
74
|
+
saveTextFile(filename, text, mime);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function downloadMarkdown(filename: string, text: string): void {
|
|
78
|
+
downloadTextFile(
|
|
79
|
+
filename.endsWith(".md") ? filename : `${filename}.md`,
|
|
80
|
+
redactString(text),
|
|
81
|
+
"text/markdown;charset=utf-8",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Plain-text export — same serializer output with fence delimiters stripped. */
|
|
86
|
+
export function downloadPlainText(filename: string, markdown: string): void {
|
|
87
|
+
const name = filename.endsWith(".txt") ? filename : `${filename}.txt`;
|
|
88
|
+
downloadTextFile(
|
|
89
|
+
name,
|
|
90
|
+
markdownToPlainText(redactString(markdown)),
|
|
91
|
+
"text/plain;charset=utf-8",
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Minimal HTML export — pre-wrapped markdown, no renderer dependency. */
|
|
96
|
+
export function downloadHtml(
|
|
97
|
+
filename: string,
|
|
98
|
+
markdown: string,
|
|
99
|
+
title = "digichat transcript",
|
|
100
|
+
): void {
|
|
101
|
+
const name = filename.endsWith(".html") ? filename : `${filename}.html`;
|
|
102
|
+
downloadTextFile(
|
|
103
|
+
name,
|
|
104
|
+
markdownToHtmlDocument(redactString(markdown), redactString(title)),
|
|
105
|
+
"text/html;charset=utf-8",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function tryParentCopyPostMessage(text: string): boolean {
|
|
110
|
+
if (typeof window === "undefined") return false;
|
|
111
|
+
try {
|
|
112
|
+
if (window.parent && window.parent !== window) {
|
|
113
|
+
window.parent.postMessage({ type: COPY_POST_MESSAGE_TYPE, text }, "*");
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
/* cross-origin access or blocked */
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Selectable textarea fallback when clipboard + download both fail.
|
|
124
|
+
* Appends a temporary field, selects it, and focuses so the user can ⌘C.
|
|
125
|
+
*/
|
|
126
|
+
export function showSelectableTextareaFallback(text: string): void {
|
|
127
|
+
if (typeof document === "undefined") return;
|
|
128
|
+
const existing = document.getElementById("dc-copy-fallback");
|
|
129
|
+
existing?.remove();
|
|
130
|
+
const ta = document.createElement("textarea");
|
|
131
|
+
ta.id = "dc-copy-fallback";
|
|
132
|
+
ta.value = text;
|
|
133
|
+
ta.setAttribute("aria-label", "Copy markdown");
|
|
134
|
+
ta.readOnly = true;
|
|
135
|
+
Object.assign(ta.style, {
|
|
136
|
+
position: "fixed",
|
|
137
|
+
left: "0.5rem",
|
|
138
|
+
right: "0.5rem",
|
|
139
|
+
bottom: "0.5rem",
|
|
140
|
+
zIndex: "9999",
|
|
141
|
+
width: "auto",
|
|
142
|
+
maxHeight: "40vh",
|
|
143
|
+
font: "12px/1.4 ui-monospace, monospace",
|
|
144
|
+
padding: "0.5rem",
|
|
145
|
+
border: "1px solid currentColor",
|
|
146
|
+
background: "Canvas",
|
|
147
|
+
color: "CanvasText",
|
|
148
|
+
});
|
|
149
|
+
document.body.appendChild(ta);
|
|
150
|
+
ta.focus();
|
|
151
|
+
ta.select();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Copy markdown with embed-safe fallbacks (#3465).
|
|
156
|
+
*
|
|
157
|
+
* Order: clipboard → `.md` download → optional parent `digichat:copy` postMessage →
|
|
158
|
+
* selectable textarea. Never a silent no-op when `document` exists.
|
|
159
|
+
*
|
|
160
|
+
* The payload is redacted once, up front: every branch below hands the same
|
|
161
|
+
* redacted text to the clipboard, the download, the parent frame and the
|
|
162
|
+
* textarea fallback, so no branch can carry a secret out of the app.
|
|
163
|
+
*/
|
|
164
|
+
export async function copyMarkdownWithFallback(
|
|
165
|
+
text: string,
|
|
166
|
+
opts?: { filename?: string },
|
|
167
|
+
): Promise<CopyMarkdownResult> {
|
|
168
|
+
const filename = opts?.filename ?? "digichat.md";
|
|
169
|
+
const safe = redactString(text);
|
|
170
|
+
|
|
171
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
172
|
+
try {
|
|
173
|
+
await navigator.clipboard.writeText(safe);
|
|
174
|
+
return "clipboard";
|
|
175
|
+
} catch {
|
|
176
|
+
/* blocked in cross-origin iframes — continue */
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (typeof document !== "undefined") {
|
|
181
|
+
try {
|
|
182
|
+
downloadMarkdown(filename, safe);
|
|
183
|
+
tryParentCopyPostMessage(safe);
|
|
184
|
+
return "download";
|
|
185
|
+
} catch {
|
|
186
|
+
/* fall through */
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (tryParentCopyPostMessage(safe)) {
|
|
191
|
+
return "postMessage";
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
showSelectableTextareaFallback(safe);
|
|
195
|
+
return "textarea";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* ---------------------------------------------------------------------------
|
|
199
|
+
* Print + mailto + txt/html export (#3510). Reuses the #3465 serializers —
|
|
200
|
+
* no vault bodies, tool JSON, or BYOK payloads ever enter these strings.
|
|
201
|
+
* ------------------------------------------------------------------------- */
|
|
202
|
+
|
|
203
|
+
/** Safe `mailto:` body budget after `encodeURIComponent` (spec: ~1500–2000). */
|
|
204
|
+
export const MAILTO_MAX_ENCODED_LEN = 1800;
|
|
205
|
+
|
|
206
|
+
/** Appended when the mailto body is cut to fit the URL budget. */
|
|
207
|
+
export const MAILTO_TRUNCATION_NOTE = "…(truncated — download .md for full thread)";
|
|
208
|
+
|
|
209
|
+
export type TruncateForMailtoResult = { text: string; truncated: boolean };
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Move a cut back so it never lands inside a redaction marker.
|
|
213
|
+
*
|
|
214
|
+
* The body is redacted before it is cut, so the cut can land inside a
|
|
215
|
+
* `[redacted]` marker. A marker that the cut splits is dropped whole rather
|
|
216
|
+
* than shown half-written. A marker that ends before the cut is kept, and a
|
|
217
|
+
* `[` that is the user's own text is not a marker and is left alone.
|
|
218
|
+
*/
|
|
219
|
+
function cutOutsideMarker(body: string, cut: number): number {
|
|
220
|
+
for (let len = 1; len < REDACTED.length; len += 1) {
|
|
221
|
+
const start = cut - len;
|
|
222
|
+
if (start < 0) break;
|
|
223
|
+
const before = body.slice(start, cut);
|
|
224
|
+
const after = body.slice(cut, cut + (REDACTED.length - len));
|
|
225
|
+
if (before === REDACTED.slice(0, len) && after === REDACTED.slice(len)) return start;
|
|
226
|
+
}
|
|
227
|
+
return cut;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Cut `body` so `encodeURIComponent(text)` fits `maxEncoded` chars.
|
|
232
|
+
* Binary-searches the longest fitting prefix, then appends the truncation
|
|
233
|
+
* note. Pure — covered by vitest.
|
|
234
|
+
*/
|
|
235
|
+
export function truncateForMailto(
|
|
236
|
+
body: string,
|
|
237
|
+
maxEncoded: number = MAILTO_MAX_ENCODED_LEN,
|
|
238
|
+
): TruncateForMailtoResult {
|
|
239
|
+
if (encodeURIComponent(body).length <= maxEncoded) {
|
|
240
|
+
return { text: body, truncated: false };
|
|
241
|
+
}
|
|
242
|
+
const note = `\n\n${MAILTO_TRUNCATION_NOTE}`;
|
|
243
|
+
if (encodeURIComponent(note).length >= maxEncoded) {
|
|
244
|
+
let cut = note;
|
|
245
|
+
while (cut.length > 1 && encodeURIComponent(`${cut}…`).length >= maxEncoded) {
|
|
246
|
+
cut = cut.slice(0, -1);
|
|
247
|
+
}
|
|
248
|
+
return { text: cut, truncated: true };
|
|
249
|
+
}
|
|
250
|
+
let lo = 0;
|
|
251
|
+
let hi = body.length;
|
|
252
|
+
while (lo < hi) {
|
|
253
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
254
|
+
const candidate = body.slice(0, mid).trimEnd() + note;
|
|
255
|
+
if (encodeURIComponent(candidate).length <= maxEncoded) {
|
|
256
|
+
lo = mid;
|
|
257
|
+
} else {
|
|
258
|
+
hi = mid - 1;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const cut = cutOutsideMarker(body, lo);
|
|
262
|
+
return { text: `${body.slice(0, cut).trimEnd()}${note}`, truncated: true };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* `mailto:` URL with a short subject and a truncation-safe body. No network.
|
|
267
|
+
*
|
|
268
|
+
* The body is redacted before the cut: a secret that straddles the URL
|
|
269
|
+
* budget would otherwise leave its head behind in the body, and the
|
|
270
|
+
* redaction marker counts toward the budget like any other character.
|
|
271
|
+
*/
|
|
272
|
+
export function buildMailtoUrl(
|
|
273
|
+
subject: string,
|
|
274
|
+
body: string,
|
|
275
|
+
opts?: { maxEncoded?: number },
|
|
276
|
+
): string {
|
|
277
|
+
const { text } = truncateForMailto(
|
|
278
|
+
redactString(body),
|
|
279
|
+
opts?.maxEncoded ?? MAILTO_MAX_ENCODED_LEN,
|
|
280
|
+
);
|
|
281
|
+
return `mailto:?subject=${encodeURIComponent(redactString(subject))}&body=${encodeURIComponent(text)}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Last-assistant mailto — mirrors the per-turn copy payload. */
|
|
285
|
+
export function buildAnswerMailto(markdown: string, opts?: { maxEncoded?: number }): string {
|
|
286
|
+
return buildMailtoUrl("digichat answer", markdown, opts);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Full-thread mailto — mirrors the thread `.md` download payload. */
|
|
290
|
+
export function buildThreadMailto(markdown: string, opts?: { maxEncoded?: number }): string {
|
|
291
|
+
return buildMailtoUrl("digichat transcript", markdown, opts);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export type MailtoOpenResult = "mailto" | "download";
|
|
295
|
+
|
|
296
|
+
export type ExportFallbackOpts = {
|
|
297
|
+
fallbackMarkdown?: string;
|
|
298
|
+
fallbackFilename?: string;
|
|
299
|
+
/**
|
|
300
|
+
* When true (embed / sandboxed iframe), skip mailto/print and download
|
|
301
|
+
* immediately. Sandboxed embeds often expose `print` and allow `a.click()`
|
|
302
|
+
* without throwing, so a try/catch-only fallback would silently no-op.
|
|
303
|
+
*/
|
|
304
|
+
preferDownload?: boolean;
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Open a `mailto:` URL; on blocked navigation fall back to a `.md` download
|
|
309
|
+
* (same spirit as the #3465 clipboard fallback). Never throws when `document`
|
|
310
|
+
* exists — worst case the caller gets `"download"`.
|
|
311
|
+
*/
|
|
312
|
+
export function openMailtoWithFallback(
|
|
313
|
+
mailtoUrl: string,
|
|
314
|
+
opts?: ExportFallbackOpts,
|
|
315
|
+
): MailtoOpenResult {
|
|
316
|
+
const fallback = () => {
|
|
317
|
+
if (opts?.fallbackMarkdown !== undefined && typeof document !== "undefined") {
|
|
318
|
+
try {
|
|
319
|
+
downloadMarkdown(opts.fallbackFilename ?? "digichat-thread.md", opts.fallbackMarkdown);
|
|
320
|
+
} catch {
|
|
321
|
+
/* download also blocked — caller already has the markdown */
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
if (!mailtoUrl.startsWith("mailto:")) {
|
|
326
|
+
fallback();
|
|
327
|
+
return "download";
|
|
328
|
+
}
|
|
329
|
+
if (opts?.preferDownload || typeof document === "undefined") {
|
|
330
|
+
fallback();
|
|
331
|
+
return "download";
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const a = document.createElement("a");
|
|
335
|
+
a.href = mailtoUrl;
|
|
336
|
+
a.rel = "noopener";
|
|
337
|
+
document.body.appendChild(a);
|
|
338
|
+
a.click();
|
|
339
|
+
a.remove();
|
|
340
|
+
return "mailto";
|
|
341
|
+
} catch {
|
|
342
|
+
fallback();
|
|
343
|
+
return "download";
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export type PrintTranscriptResult = "print" | "download";
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* `window.print()` for the transcript; when print is unavailable/blocked
|
|
351
|
+
* (no window, embed sandbox), fall back to a `.md` download so the action
|
|
352
|
+
* is never a silent no-op.
|
|
353
|
+
*/
|
|
354
|
+
export function printTranscriptWithFallback(opts?: ExportFallbackOpts): PrintTranscriptResult {
|
|
355
|
+
const fallback = () => {
|
|
356
|
+
if (opts?.fallbackMarkdown !== undefined && typeof document !== "undefined") {
|
|
357
|
+
try {
|
|
358
|
+
downloadMarkdown(opts.fallbackFilename ?? "digichat-thread.md", opts.fallbackMarkdown);
|
|
359
|
+
} catch {
|
|
360
|
+
/* ignore — print already failed */
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
if (opts?.preferDownload) {
|
|
365
|
+
fallback();
|
|
366
|
+
return "download";
|
|
367
|
+
}
|
|
368
|
+
if (typeof window !== "undefined" && typeof window.print === "function") {
|
|
369
|
+
try {
|
|
370
|
+
window.print();
|
|
371
|
+
return "print";
|
|
372
|
+
} catch {
|
|
373
|
+
fallback();
|
|
374
|
+
return "download";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
fallback();
|
|
378
|
+
return "download";
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Lightweight markdown → plain text for `.txt` export. Strips fence
|
|
383
|
+
* delimiter lines only; prose (including code content) is kept as-is.
|
|
384
|
+
*
|
|
385
|
+
* A pure serializer: it does not redact. `downloadPlainText` redacts before
|
|
386
|
+
* it writes, so a caller that writes the result itself must redact too.
|
|
387
|
+
*/
|
|
388
|
+
export function markdownToPlainText(markdown: string): string {
|
|
389
|
+
return markdown
|
|
390
|
+
.split("\n")
|
|
391
|
+
.filter((line) => !line.trimStart().startsWith("```"))
|
|
392
|
+
.join("\n")
|
|
393
|
+
.trim();
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function escapeHtml(text: string): string {
|
|
397
|
+
return text
|
|
398
|
+
.replace(/&/g, "&")
|
|
399
|
+
.replace(/</g, "<")
|
|
400
|
+
.replace(/>/g, ">")
|
|
401
|
+
.replace(/"/g, """);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Minimal HTML document for `.html` export — the markdown pre-wrapped in
|
|
406
|
+
* `<pre>`. Deliberately no GFM renderer dependency.
|
|
407
|
+
*
|
|
408
|
+
* A pure serializer: it does not redact. `downloadHtml` redacts before it
|
|
409
|
+
* writes, so a caller that writes the result itself must redact too.
|
|
410
|
+
*/
|
|
411
|
+
export function markdownToHtmlDocument(markdown: string, title = "digichat transcript"): string {
|
|
412
|
+
const safeTitle = escapeHtml(title);
|
|
413
|
+
const safeBody = escapeHtml(markdown);
|
|
414
|
+
return [
|
|
415
|
+
"<!doctype html>",
|
|
416
|
+
'<html lang="en">',
|
|
417
|
+
"<head>",
|
|
418
|
+
'<meta charset="utf-8">',
|
|
419
|
+
`<title>${safeTitle}</title>`,
|
|
420
|
+
"</head>",
|
|
421
|
+
"<body>",
|
|
422
|
+
`<h1>${safeTitle}</h1>`,
|
|
423
|
+
`<pre>${safeBody}</pre>`,
|
|
424
|
+
"</body>",
|
|
425
|
+
"</html>",
|
|
426
|
+
"",
|
|
427
|
+
].join("\n");
|
|
428
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type VaultHitSummary = {
|
|
2
|
+
title: string;
|
|
3
|
+
path: string;
|
|
4
|
+
tier?: string;
|
|
5
|
+
year?: number;
|
|
6
|
+
snippet?: string;
|
|
7
|
+
/** Full note body from digivault_get_note — never an invented URL. */
|
|
8
|
+
body?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Why a `status` row exists, when it is about a tool. Absent means a quiet note
|
|
13
|
+
* about the turn — "results exist but this detail level withholds them" — and it
|
|
14
|
+
* is the only reading a status without an outcome may have.
|
|
15
|
+
*
|
|
16
|
+
* `query` is absent when the turn never knew one, never `""`. `state`:
|
|
17
|
+
* - `failed` the tool was asked and did not answer
|
|
18
|
+
* - `unreadable` the tool answered and this layer cannot read the answer; an
|
|
19
|
+
* honest unknown, and never an empty result
|
|
20
|
+
*/
|
|
21
|
+
export type DigiChatStatusOutcome = {
|
|
22
|
+
name: string;
|
|
23
|
+
query?: string;
|
|
24
|
+
state: "failed" | "unreadable";
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type DigiChatActivity =
|
|
28
|
+
| { kind: "status"; message: string; outcome?: DigiChatStatusOutcome }
|
|
29
|
+
| { kind: "tool_call"; name: string; query: string }
|
|
30
|
+
| {
|
|
31
|
+
kind: "tool_result";
|
|
32
|
+
name: string;
|
|
33
|
+
query: string;
|
|
34
|
+
hits: VaultHitSummary[];
|
|
35
|
+
count: number;
|
|
36
|
+
}
|
|
37
|
+
| { kind: "reasoning"; text: string }
|
|
38
|
+
| { kind: "trace"; label: string; done: boolean }
|
|
39
|
+
| {
|
|
40
|
+
kind: "brief";
|
|
41
|
+
themes: { label: string; summary: string }[];
|
|
42
|
+
questions?: string[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type DigiChatMessage = {
|
|
46
|
+
role: "user" | "assistant";
|
|
47
|
+
content: string;
|
|
48
|
+
activities?: DigiChatActivity[];
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Embed/controller adapter shape used by digichat's `useEmbedDigiChat` and
|
|
53
|
+
* activity projection. digichat 2.0 UI is `CliThread` (assistant-ui); this is
|
|
54
|
+
* not a mountable session component.
|
|
55
|
+
*/
|
|
56
|
+
export type DigiChatController = {
|
|
57
|
+
messages: DigiChatMessage[];
|
|
58
|
+
busy: boolean;
|
|
59
|
+
error: string | null;
|
|
60
|
+
quotaPrompt?: boolean;
|
|
61
|
+
send: (question: string, opts?: { forceTool?: string }) => void | Promise<void>;
|
|
62
|
+
stop?: () => void;
|
|
63
|
+
/** Error-row retry only — not last-turn regenerate chrome. */
|
|
64
|
+
onRetry?: () => void;
|
|
65
|
+
/**
|
|
66
|
+
* Re-answer the last user turn (drop trailing assistant, resend transcript).
|
|
67
|
+
* Omit on Foundry embeds until the turn-mutation API (#3475) — truncate-and-resend
|
|
68
|
+
* would append a duplicate user item on an append-only conversation.
|
|
69
|
+
*/
|
|
70
|
+
regenerate?: () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Replace the last user turn (and drop any following assistant), then send.
|
|
73
|
+
* Empty / whitespace-only text is a no-op. Omit on Foundry for the same reason
|
|
74
|
+
* as `regenerate`.
|
|
75
|
+
*/
|
|
76
|
+
editLastUser?: (text: string) => void | Promise<void>;
|
|
77
|
+
reset?: () => void;
|
|
78
|
+
modelLabel?: string;
|
|
79
|
+
providerIsSet?: boolean;
|
|
80
|
+
openSettings?: () => void;
|
|
81
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useAuiState } from "@assistant-ui/react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* How the current assistant turn stands, for the animations that follow it.
|
|
7
|
+
*
|
|
8
|
+
* - `running`: the turn is live, or waiting on the visitor (a tool approval).
|
|
9
|
+
* - `done`: the turn finished.
|
|
10
|
+
* - `stopped`: the visitor pressed stop, or the stream ended with a tool call
|
|
11
|
+
* still open. Nothing more will arrive for it.
|
|
12
|
+
* - `failed`: the turn ended on an error.
|
|
13
|
+
*
|
|
14
|
+
* A stopped or failed turn ends every animation it started: the work-chain
|
|
15
|
+
* marker, its "Working" title and the open tool rows all show their final
|
|
16
|
+
* state instead (DIG-4459).
|
|
17
|
+
*/
|
|
18
|
+
export type TurnOutcome = "running" | "done" | "stopped" | "failed";
|
|
19
|
+
|
|
20
|
+
type StatusLike = { readonly type?: string; readonly reason?: string } | null | undefined;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* assistant-ui's message status after the stream ends:
|
|
24
|
+
* - an error is `incomplete/error`;
|
|
25
|
+
* - a stop is `incomplete/cancelled`, except while a tool call has no result,
|
|
26
|
+
* when it is `requires-action/tool-calls` (getAutoStatus ranks pending tool
|
|
27
|
+
* calls above the cancel). Our tools run on the server, so a pending call
|
|
28
|
+
* with the thread idle is a call that will never finish.
|
|
29
|
+
* - `requires-action/interrupt` waits on the visitor and stays live.
|
|
30
|
+
*/
|
|
31
|
+
export function turnOutcome(status: StatusLike, threadRunning: boolean): TurnOutcome {
|
|
32
|
+
const type = status?.type;
|
|
33
|
+
if (type === "incomplete") return status?.reason === "error" ? "failed" : "stopped";
|
|
34
|
+
if (type === "requires-action") {
|
|
35
|
+
return status?.reason === "tool-calls" && !threadRunning ? "stopped" : "running";
|
|
36
|
+
}
|
|
37
|
+
if (type === "running") return "running";
|
|
38
|
+
return "done";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The outcome of the message in scope; `done` outside a message. */
|
|
42
|
+
export function useTurnOutcome(): TurnOutcome {
|
|
43
|
+
const status = useAuiState((s) => s.optional.message?.status as StatusLike);
|
|
44
|
+
const threadRunning = useAuiState((s) => s.optional.thread?.isRunning === true);
|
|
45
|
+
if (status === undefined) return "done";
|
|
46
|
+
return turnOutcome(status, threadRunning);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** A turn that ended before it finished: stopped by the visitor or failed. */
|
|
50
|
+
export function turnCutShort(outcome: TurnOutcome): boolean {
|
|
51
|
+
return outcome === "stopped" || outcome === "failed";
|
|
52
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
import {
|
|
5
|
+
DIGI_CHAT_WARMUP_EVENT,
|
|
6
|
+
getDigichatWarmupPhase,
|
|
7
|
+
type DigichatWarmupPhase,
|
|
8
|
+
} from "./boot-signal";
|
|
9
|
+
|
|
10
|
+
function subscribe(cb: () => void): () => void {
|
|
11
|
+
window.addEventListener(DIGI_CHAT_WARMUP_EVENT, cb);
|
|
12
|
+
return () => window.removeEventListener(DIGI_CHAT_WARMUP_EVENT, cb);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Current service warm-up phase (see setDigichatWarmupPhase). */
|
|
16
|
+
export function useDigichatWarmupPhase(): DigichatWarmupPhase {
|
|
17
|
+
return useSyncExternalStore(subscribe, getDigichatWarmupPhase, () => "idle");
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { DotMatrix, type DotMatrixState } from "./DotMatrix";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Marker and label shared by the pre-response loader and the Working / Worked
|
|
8
|
+
* header. Both rows render this, so the handoff is the label changing in the
|
|
9
|
+
* same slot beside the same 12px marker.
|
|
10
|
+
*
|
|
11
|
+
* `markerLabel` names the marker. Leave it out where the row is a control
|
|
12
|
+
* named by its visible text (the work chain trigger), so the glyph is
|
|
13
|
+
* decorative and the name is not read twice (DIG-4669).
|
|
14
|
+
*/
|
|
15
|
+
export function WorkStatusLead({
|
|
16
|
+
marker,
|
|
17
|
+
markerLabel,
|
|
18
|
+
label,
|
|
19
|
+
}: {
|
|
20
|
+
marker: DotMatrixState;
|
|
21
|
+
markerLabel?: string;
|
|
22
|
+
label?: ReactNode;
|
|
23
|
+
}) {
|
|
24
|
+
const showLabel =
|
|
25
|
+
label !== null &&
|
|
26
|
+
label !== undefined &&
|
|
27
|
+
!(typeof label === "string" && label.trim() === "");
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<span data-slot="aui_work-status-marker" className="aui-work-status-marker">
|
|
32
|
+
{markerLabel === undefined ? (
|
|
33
|
+
<DotMatrix state={marker} decorative className="!size-3 shrink-0" />
|
|
34
|
+
) : (
|
|
35
|
+
<DotMatrix
|
|
36
|
+
state={marker}
|
|
37
|
+
label={markerLabel}
|
|
38
|
+
className="!size-3 shrink-0"
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
</span>
|
|
42
|
+
{showLabel ? (
|
|
43
|
+
<span data-slot="aui_work-status-label" className="aui-work-status-label">
|
|
44
|
+
{label}
|
|
45
|
+
</span>
|
|
46
|
+
) : null}
|
|
47
|
+
</>
|
|
48
|
+
);
|
|
49
|
+
}
|