@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.
Files changed (424) hide show
  1. package/README.md +48 -2
  2. package/package.json +143 -4
  3. package/src/components/NavShell.tsx +776 -0
  4. package/src/components/SocialRow.tsx +87 -0
  5. package/src/components/Spinner.tsx +27 -0
  6. package/src/components/StackLogo.tsx +40 -0
  7. package/src/components/Terminal.tsx +110 -0
  8. package/src/components/TerminalManifest.tsx +212 -0
  9. package/src/components/ThemeProvider.tsx +271 -0
  10. package/src/components/account/AuthCard.tsx +309 -0
  11. package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
  12. package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
  13. package/src/components/brand/BrandWordmark.tsx +32 -0
  14. package/src/components/changelog/ReleaseRail.tsx +81 -0
  15. package/src/components/changelog/index.ts +1 -0
  16. package/src/components/chat/ChatCodeBlock.tsx +67 -0
  17. package/src/components/chat/ChatMarkdown.tsx +66 -0
  18. package/src/components/chat/ChatMarkdownSource.tsx +203 -0
  19. package/src/components/chat/ChatMermaidBlock.tsx +202 -0
  20. package/src/components/chat/ChatMessage.tsx +77 -0
  21. package/src/components/chat/ChatPlayback.tsx +422 -0
  22. package/src/components/chat/ChatStreamCursor.tsx +25 -0
  23. package/src/components/chat/ChatThinking.tsx +113 -0
  24. package/src/components/chat/ChatToolCall.tsx +190 -0
  25. package/src/components/chat/ChatTranscript.tsx +60 -0
  26. package/src/components/chat/ChatWidgetFrame.tsx +107 -0
  27. package/src/components/chat/DigichatBootLoader.tsx +683 -0
  28. package/src/components/chat/DigichatLauncher.tsx +361 -0
  29. package/src/components/chat/DigichatThread.tsx +118 -0
  30. package/src/components/chat/DigichatThreadList.tsx +54 -0
  31. package/src/components/chat/DigichatWordmark.tsx +24 -0
  32. package/src/components/chat/DotMatrix.tsx +650 -0
  33. package/src/components/chat/boot-lab.tsx +766 -0
  34. package/src/components/chat/boot-signal.ts +144 -0
  35. package/src/components/chat/chat-surfaces.ts +52 -0
  36. package/src/components/chat/connection-status.ts +40 -0
  37. package/src/components/chat/digichat-wordmark.ts +355 -0
  38. package/src/components/chat/disclosure-chevron.tsx +49 -0
  39. package/src/components/chat/followable-href.ts +9 -0
  40. package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
  41. package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
  42. package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
  43. package/src/components/chat/gallery-thread/cn.ts +1 -0
  44. package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
  45. package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
  46. package/src/components/chat/gallery-thread/css.d.ts +6 -0
  47. package/src/components/chat/gallery-thread/file.tsx +238 -0
  48. package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
  49. package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
  50. package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
  51. package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
  52. package/src/components/chat/gallery-thread/image.tsx +519 -0
  53. package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
  54. package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
  55. package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
  56. package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
  57. package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
  58. package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
  59. package/src/components/chat/gallery-thread/source.tsx +76 -0
  60. package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
  61. package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
  62. package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
  63. package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
  64. package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
  65. package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
  66. package/src/components/chat/gallery-thread/work-status.ts +66 -0
  67. package/src/components/chat/overlay-scrollbar.tsx +86 -0
  68. package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
  69. package/src/components/chat/skins/SOURCE.md +36 -0
  70. package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
  71. package/src/components/chat/skins/base/aui-default/README.md +45 -0
  72. package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
  73. package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
  74. package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
  75. package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
  76. package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
  77. package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
  78. package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
  79. package/src/components/chat/skins/base/docs-model-options.ts +6 -0
  80. package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
  81. package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
  82. package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
  83. package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
  84. package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
  85. package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
  86. package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
  87. package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
  88. package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
  89. package/src/components/chat/skins/base/markdown-text.tsx +294 -0
  90. package/src/components/chat/skins/base/model.ts +1 -0
  91. package/src/components/chat/skins/base/thread.tsx +1050 -0
  92. package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
  93. package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
  94. package/src/components/chat/skins/base/ui/badge.tsx +51 -0
  95. package/src/components/chat/skins/base/ui/button.tsx +67 -0
  96. package/src/components/chat/skins/base/ui/command.tsx +185 -0
  97. package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
  98. package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
  99. package/src/components/chat/skins/base/ui/popover.tsx +97 -0
  100. package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
  101. package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
  102. package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
  103. package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
  104. package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
  105. package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
  106. package/src/components/chat/skins/chatgpt.tsx +448 -0
  107. package/src/components/chat/skins/claude.tsx +380 -0
  108. package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
  109. package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
  110. package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
  111. package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
  112. package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
  113. package/src/components/chat/skins/digichat.tsx +144 -0
  114. package/src/components/chat/skins/expo-react-native.tsx +29 -0
  115. package/src/components/chat/skins/gemini.tsx +322 -0
  116. package/src/components/chat/skins/grok-icon.tsx +34 -0
  117. package/src/components/chat/skins/grok.tsx +369 -0
  118. package/src/components/chat/skins/index.ts +46 -0
  119. package/src/components/chat/skins/perplexity.tsx +462 -0
  120. package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
  121. package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
  122. package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
  123. package/src/components/chat/skins/react-ink.tsx +97 -0
  124. package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
  125. package/src/components/chat/skins/thread-skin-view.tsx +156 -0
  126. package/src/components/chat/skins/thread-skins.ts +143 -0
  127. package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
  128. package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
  129. package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
  130. package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
  131. package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
  132. package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
  133. package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
  134. package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
  135. package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
  136. package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
  137. package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
  138. package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
  139. package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
  140. package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
  141. package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
  142. package/src/components/chat/stock/SOURCE.md +90 -0
  143. package/src/components/chat/stock/artifacts-panel.tsx +305 -0
  144. package/src/components/chat/stock/attachment.aui.tsx +280 -0
  145. package/src/components/chat/stock/chat-notice.tsx +143 -0
  146. package/src/components/chat/stock/chat-private-mode.tsx +64 -0
  147. package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
  148. package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
  149. package/src/components/chat/stock/file.tsx +265 -0
  150. package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
  151. package/src/components/chat/stock/image.tsx +531 -0
  152. package/src/components/chat/stock/index.ts +129 -0
  153. package/src/components/chat/stock/json-view.tsx +140 -0
  154. package/src/components/chat/stock/markdown-text.tsx +319 -0
  155. package/src/components/chat/stock/message-error.aui.tsx +96 -0
  156. package/src/components/chat/stock/message-export-menu.tsx +156 -0
  157. package/src/components/chat/stock/palette-row-preview.tsx +26 -0
  158. package/src/components/chat/stock/reasoning.aui.tsx +120 -0
  159. package/src/components/chat/stock/reasoning.tsx +335 -0
  160. package/src/components/chat/stock/skin-chrome.tsx +81 -0
  161. package/src/components/chat/stock/skin-credit.tsx +63 -0
  162. package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
  163. package/src/components/chat/stock/skin-palette-context.ts +16 -0
  164. package/src/components/chat/stock/skin-runtime.tsx +52 -0
  165. package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
  166. package/src/components/chat/stock/skin-types.ts +217 -0
  167. package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
  168. package/src/components/chat/stock/stock-send-gate.tsx +94 -0
  169. package/src/components/chat/stock/stock-shape.tsx +39 -0
  170. package/src/components/chat/stock/thread.aui.tsx +645 -0
  171. package/src/components/chat/stock/tool-display.ts +6 -0
  172. package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
  173. package/src/components/chat/stock/tool-group.aui.tsx +244 -0
  174. package/src/components/chat/stock/tool-surface.ts +120 -0
  175. package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
  176. package/src/components/chat/stock/ui/avatar.tsx +108 -0
  177. package/src/components/chat/stock/ui/button.tsx +81 -0
  178. package/src/components/chat/stock/ui/collapsible.tsx +21 -0
  179. package/src/components/chat/stock/ui/dialog.tsx +163 -0
  180. package/src/components/chat/stock/ui/skeleton.tsx +13 -0
  181. package/src/components/chat/stock/ui/textarea.tsx +20 -0
  182. package/src/components/chat/stock/ui/tooltip.tsx +68 -0
  183. package/src/components/chat/stock/use-attachment-src.ts +42 -0
  184. package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
  185. package/src/components/chat/strip-model-boilerplate.ts +42 -0
  186. package/src/components/chat/suggestion-cycle.tsx +230 -0
  187. package/src/components/chat/suggestion-scroll-row.tsx +81 -0
  188. package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
  189. package/src/components/chat/trace-grouping/chain-state.ts +141 -0
  190. package/src/components/chat/trace-grouping/index.ts +32 -0
  191. package/src/components/chat/trace-grouping/tool-row.ts +74 -0
  192. package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
  193. package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
  194. package/src/components/chat/trace-i18n/core.ts +48 -0
  195. package/src/components/chat/trace-i18n/index.tsx +23 -0
  196. package/src/components/chat/trace-i18n/locales/en.ts +24 -0
  197. package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
  198. package/src/components/chat/trace-i18n/types.ts +35 -0
  199. package/src/components/chat/trace-spacing.ts +249 -0
  200. package/src/components/chat/transcript/activity-view.ts +375 -0
  201. package/src/components/chat/transcript/chat-export.ts +133 -0
  202. package/src/components/chat/transcript/index.ts +10 -0
  203. package/src/components/chat/transcript/save-file.ts +209 -0
  204. package/src/components/chat/transcript/transcript-markdown.ts +428 -0
  205. package/src/components/chat/transcript/types.ts +81 -0
  206. package/src/components/chat/turn-outcome.ts +52 -0
  207. package/src/components/chat/use-warmup-phase.ts +18 -0
  208. package/src/components/chat/work-status-lead.tsx +49 -0
  209. package/src/components/chrome.tsx +264 -0
  210. package/src/components/command-palette/CommandPalette.tsx +404 -0
  211. package/src/components/command-palette/index.ts +6 -0
  212. package/src/components/contact/ContactMailto.tsx +112 -0
  213. package/src/components/contact/index.ts +5 -0
  214. package/src/components/conviction/ConvictionMeter.tsx +40 -0
  215. package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
  216. package/src/components/conviction/index.ts +7 -0
  217. package/src/components/data-layout/BentoGrid.tsx +52 -0
  218. package/src/components/data-layout/CardRail.tsx +150 -0
  219. package/src/components/data-layout/DotMatrixStat.tsx +65 -0
  220. package/src/components/data-layout/FeatureCell.tsx +80 -0
  221. package/src/components/data-layout/MediaFrame.tsx +125 -0
  222. package/src/components/data-layout/ModuleGrid.tsx +735 -0
  223. package/src/components/data-layout/Odometer.tsx +149 -0
  224. package/src/components/data-layout/ProductFrame.tsx +79 -0
  225. package/src/components/data-layout/TestimonialWall.tsx +139 -0
  226. package/src/components/data-layout/index.ts +19 -0
  227. package/src/components/data-layout/treemap.ts +368 -0
  228. package/src/components/deck/DeckStack.tsx +243 -0
  229. package/src/components/desk/DataTable.tsx +373 -0
  230. package/src/components/desk/KpiGrid.tsx +80 -0
  231. package/src/components/desk/Sparkline.tsx +63 -0
  232. package/src/components/desk/StateBlock.tsx +132 -0
  233. package/src/components/desk/index.ts +18 -0
  234. package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
  235. package/src/components/diagrams/ArchitectureTour.tsx +912 -0
  236. package/src/components/diagrams/TerminalSchematic.tsx +192 -0
  237. package/src/components/diagrams/architecture-svg.tsx +384 -0
  238. package/src/components/diagrams/index.ts +30 -0
  239. package/src/components/diagrams/mermaid-theme.ts +115 -0
  240. package/src/components/diagrams/tour-camera.ts +171 -0
  241. package/src/components/docs/CodeTabs.tsx +90 -0
  242. package/src/components/docs/CopyCommand.tsx +151 -0
  243. package/src/components/docs/DocsLayout.tsx +197 -0
  244. package/src/components/docs/DocsSearch.tsx +97 -0
  245. package/src/components/docs/Endpoint.tsx +135 -0
  246. package/src/components/document/DocumentFrame.tsx +43 -0
  247. package/src/components/document/GlyphList.tsx +51 -0
  248. package/src/components/document/PageTitle.tsx +44 -0
  249. package/src/components/document/Prose.tsx +38 -0
  250. package/src/components/document/Section.tsx +55 -0
  251. package/src/components/document/index.ts +13 -0
  252. package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
  253. package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
  254. package/src/components/effects-chrome/Pipeline.tsx +226 -0
  255. package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
  256. package/src/components/effects-chrome/StackingPanels.tsx +101 -0
  257. package/src/components/effects-chrome/TabStrip.tsx +232 -0
  258. package/src/components/effects-chrome/ToastStack.tsx +201 -0
  259. package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
  260. package/src/components/effects-chrome/index.ts +35 -0
  261. package/src/components/emblems.tsx +188 -0
  262. package/src/components/faviconTheme.ts +23 -0
  263. package/src/components/figure/Figure.tsx +38 -0
  264. package/src/components/figure/index.ts +2 -0
  265. package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
  266. package/src/components/finance-charts/EquityCurve.tsx +71 -0
  267. package/src/components/finance-charts/PriceChart.tsx +119 -0
  268. package/src/components/finance-charts/chart-host.tsx +236 -0
  269. package/src/components/finance-charts/chart-scale.ts +93 -0
  270. package/src/components/finance-charts/demo-data.ts +88 -0
  271. package/src/components/finance-charts/index.ts +46 -0
  272. package/src/components/finance-charts/lw-chart.tsx +292 -0
  273. package/src/components/finance-composites/MarketBar.tsx +243 -0
  274. package/src/components/finance-composites/OrderBook.tsx +133 -0
  275. package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
  276. package/src/components/finance-composites/SortableTable.tsx +144 -0
  277. package/src/components/finance-composites/StockTicker.tsx +65 -0
  278. package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
  279. package/src/components/finance-composites/index.ts +28 -0
  280. package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
  281. package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
  282. package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
  283. package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
  284. package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
  285. package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
  286. package/src/components/finance-tearsheet/charts.tsx +2624 -0
  287. package/src/components/finance-tearsheet/demo-data.ts +177 -0
  288. package/src/components/finance-tearsheet/format.ts +41 -0
  289. package/src/components/finance-tearsheet/index.ts +120 -0
  290. package/src/components/finance-tearsheet/print.ts +52 -0
  291. package/src/components/finance-tearsheet/risk-bands.ts +48 -0
  292. package/src/components/finance-tearsheet/stats.ts +35 -0
  293. package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
  294. package/src/components/finance-tearsheet/types.ts +58 -0
  295. package/src/components/footer/FooterCells.tsx +109 -0
  296. package/src/components/footer/index.ts +6 -0
  297. package/src/components/graph.tsx +158 -0
  298. package/src/components/icons.tsx +98 -0
  299. package/src/components/landing/PixelWordmark.tsx +36 -0
  300. package/src/components/logos.ts +39 -0
  301. package/src/components/marquee/Marquee.tsx +204 -0
  302. package/src/components/metrics/PerfMetrics.tsx +68 -0
  303. package/src/components/metrics/StatCounter.tsx +104 -0
  304. package/src/components/page-geometry.tsx +177 -0
  305. package/src/components/pricing/Pricing.tsx +174 -0
  306. package/src/components/pricing/PricingMatrix.tsx +219 -0
  307. package/src/components/prose/index.ts +2 -0
  308. package/src/components/prose/prose.tsx +86 -0
  309. package/src/components/repo-activity/RepoActivity.tsx +599 -0
  310. package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
  311. package/src/components/repo-activity/demo.ts +201 -0
  312. package/src/components/repo-activity/fetch.ts +211 -0
  313. package/src/components/repo-activity/heatmap.ts +123 -0
  314. package/src/components/repo-activity/index.ts +28 -0
  315. package/src/components/repo-activity/types.ts +99 -0
  316. package/src/components/stages/NumberedStages.tsx +116 -0
  317. package/src/components/symbols/marks.tsx +116 -0
  318. package/src/components/symbols/terminal-lockup.tsx +136 -0
  319. package/src/components/symbols/terminal-marks.tsx +226 -0
  320. package/src/components/terminal/ChatResponseLoader.tsx +67 -0
  321. package/src/components/terminal/ContainerBootLoader.tsx +82 -0
  322. package/src/components/terminal/TerminalStepCaret.tsx +202 -0
  323. package/src/components/themeInit.ts +24 -0
  324. package/src/components/typography/MotionReveal.tsx +108 -0
  325. package/src/components/typography/TypewriterReveal.tsx +101 -0
  326. package/src/components/typography/WordReveal.tsx +143 -0
  327. package/src/data/modules.ts +378 -0
  328. package/src/data/subsystems.ts +101 -0
  329. package/src/index.ts +587 -0
  330. package/src/lib/base-path.ts +60 -0
  331. package/src/lib/cx.ts +25 -0
  332. package/src/lib/gloomberb.ts +69 -0
  333. package/src/lib/record.ts +19 -0
  334. package/src/lib/stub-payload.ts +183 -0
  335. package/src/lib/useBodyScrollLock.ts +44 -0
  336. package/src/lib/utils.ts +6 -0
  337. package/src/motion/primitives.tsx +105 -0
  338. package/src/motion/scroll-glide.ts +62 -0
  339. package/src/motion/scrolly-core.ts +38 -0
  340. package/src/motion/scrolly.tsx +95 -0
  341. package/src/navigation/HashScrollManager.tsx +167 -0
  342. package/src/navigation/hashScroll.ts +78 -0
  343. package/src/replay/browser.ts +280 -0
  344. package/src/replay/chat-export-run.ts +121 -0
  345. package/src/replay/export-format.ts +25 -0
  346. package/src/replay/export-mount.ts +32 -0
  347. package/src/replay/filename.ts +54 -0
  348. package/src/replay/index.ts +21 -0
  349. package/src/replay/redact-dom.ts +178 -0
  350. package/src/replay/redact.ts +113 -0
  351. package/src/replay/snapshot.ts +659 -0
  352. package/src/styles/account-auth.css +339 -0
  353. package/src/styles/brand-wordmark.css +11 -0
  354. package/src/styles/card-rail.css +120 -0
  355. package/src/styles/chat-aui.css +1143 -0
  356. package/src/styles/chat-core.css +469 -0
  357. package/src/styles/chat-digichat.css +2531 -0
  358. package/src/styles/chat-math.css +70 -0
  359. package/src/styles/chat-skin-palette.css +138 -0
  360. package/src/styles/chat-stock-menu.css +37 -0
  361. package/src/styles/chat-widgets.css +190 -0
  362. package/src/styles/command-palette.css +372 -0
  363. package/src/styles/controls-core.css +2261 -0
  364. package/src/styles/controls-overlay.css +603 -0
  365. package/src/styles/data-layout.css +288 -0
  366. package/src/styles/deck.css +141 -0
  367. package/src/styles/diagrams.css +1860 -0
  368. package/src/styles/digichat-app-theme.css +250 -0
  369. package/src/styles/digichat-boot-loader.css +487 -0
  370. package/src/styles/digichat-launcher.css +377 -0
  371. package/src/styles/docs.css +165 -0
  372. package/src/styles/effects-chrome.css +888 -0
  373. package/src/styles/finance-composites.css +214 -0
  374. package/src/styles/finance-tearsheet-overlay.css +90 -0
  375. package/src/styles/finance-tearsheet.css +945 -0
  376. package/src/styles/marquee.css +168 -0
  377. package/src/styles/metrics.css +82 -0
  378. package/src/styles/nav-shell.css +551 -0
  379. package/src/styles/pricing.css +79 -0
  380. package/src/styles/repo-activity.css +575 -0
  381. package/src/styles/stages.css +69 -0
  382. package/src/styles/terminal-loaders.css +122 -0
  383. package/src/styles/terminal-manifest.css +228 -0
  384. package/src/styles/web-theme.css +1007 -0
  385. package/src/styles/word-reveal.css +204 -0
  386. package/src/theme/apply-theme.ts +214 -0
  387. package/src/theme/index.ts +27 -0
  388. package/src/theme/palette-registry.ts +855 -0
  389. package/src/theme/tui-prefs.ts +64 -0
  390. package/src/ui/alert.tsx +78 -0
  391. package/src/ui/avatar.tsx +104 -0
  392. package/src/ui/badge.tsx +75 -0
  393. package/src/ui/breadcrumb.tsx +61 -0
  394. package/src/ui/button.tsx +67 -0
  395. package/src/ui/card.tsx +139 -0
  396. package/src/ui/checkbox.tsx +27 -0
  397. package/src/ui/collapsible.tsx +32 -0
  398. package/src/ui/date-pager.tsx +325 -0
  399. package/src/ui/dialog.tsx +157 -0
  400. package/src/ui/dropdown-menu.tsx +267 -0
  401. package/src/ui/empty-state.tsx +165 -0
  402. package/src/ui/field.tsx +104 -0
  403. package/src/ui/form.tsx +36 -0
  404. package/src/ui/icon-button.tsx +36 -0
  405. package/src/ui/index.ts +34 -0
  406. package/src/ui/input.tsx +33 -0
  407. package/src/ui/kbd.tsx +30 -0
  408. package/src/ui/label.tsx +32 -0
  409. package/src/ui/pager.tsx +119 -0
  410. package/src/ui/pagination.tsx +126 -0
  411. package/src/ui/radio-group.tsx +51 -0
  412. package/src/ui/search-bar.tsx +85 -0
  413. package/src/ui/segmented-control.tsx +76 -0
  414. package/src/ui/select.tsx +257 -0
  415. package/src/ui/separator.tsx +24 -0
  416. package/src/ui/sheet.tsx +141 -0
  417. package/src/ui/skeleton.tsx +76 -0
  418. package/src/ui/slider.tsx +76 -0
  419. package/src/ui/switch.tsx +31 -0
  420. package/src/ui/table.tsx +179 -0
  421. package/src/ui/tabs.tsx +89 -0
  422. package/src/ui/tags-input.tsx +168 -0
  423. package/src/ui/textarea.tsx +17 -0
  424. 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, "&amp;")
399
+ .replace(/</g, "&lt;")
400
+ .replace(/>/g, "&gt;")
401
+ .replace(/"/g, "&quot;");
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
+ }