@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,766 @@
1
+ "use client";
2
+
3
+ // The boot styles (.dboot-overlay included) ship with the loader, not with one
4
+ // skin: a host on any skin mounts this overlay, and without them it renders
5
+ // unpositioned at the top of the page with the wordmark clipped.
6
+ import "../../styles/digichat-boot-loader.css";
7
+ import { useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
8
+ import { DIGICHAT } from "@digithings-ai/hero-banner/definitions";
9
+ import { HeroBanner } from "@digithings-ai/hero-banner/web";
10
+ import { DisclosureChevron } from "./disclosure-chevron";
11
+ import { DotMatrix } from "./DotMatrix";
12
+ import {
13
+ DIGI_CHAT_BOOT_STEP_EVENT,
14
+ DIGI_CHAT_READY_EVENT,
15
+ digichatBootClockMs,
16
+ digichatBootSteps,
17
+ hasDigichatReady,
18
+ signalDigichatReady,
19
+ } from "./boot-signal";
20
+
21
+ /**
22
+ * Boot-lab variants: short local loaders used to iterate on the universal
23
+ * boot animation. `?boot=<variant>` selects one at runtime; the server can
24
+ * also thread it so first paint never shows the classic loader (the outline
25
+ * bleed the classic pass caused).
26
+ *
27
+ * The tool-chain family (`toolchain`, `tooltask`, `toolreason`, `toolfull`)
28
+ * is the skin-proof one: simulated tool calls drawn with the chat's own
29
+ * DotMatrix states and row anatomy (`aui-tool-fallback-trigger`,
30
+ * `tool-group-trigger`, `reasoning-trigger`), so whatever skin dresses the
31
+ * chat dresses the boot too. After the simulated commands finish a
32
+ * `connect to digichat` row keeps ticking until the app's real ready signal
33
+ * lands, which keeps 30-60s cold starts honest; `?bootdelay=<seconds>`
34
+ * emulates a slow container locally.
35
+ *
36
+ * `banner` is the standard boot for every digichat deployment: the digichat
37
+ * hero banner's LOADING pass, the same cover the digithings.ai site shell
38
+ * (ChatEmbedShell) has always shown — no copy, no spinner. `classic` opts
39
+ * back into the pre-banner welcome loader (`DigichatBootLoader`).
40
+ */
41
+ export type BootLabVariant =
42
+ | "banner"
43
+ | "terminal"
44
+ | "waking"
45
+ | "booting"
46
+ | "spinner"
47
+ | "spinneronly"
48
+ | "dots"
49
+ | "bootlog"
50
+ | "scramble"
51
+ | "toolchain"
52
+ | "tooltask"
53
+ | "toolreason"
54
+ | "toolfull";
55
+
56
+ const VARIANTS: readonly BootLabVariant[] = [
57
+ "banner",
58
+ "terminal",
59
+ "waking",
60
+ "booting",
61
+ "spinner",
62
+ "spinneronly",
63
+ "dots",
64
+ "bootlog",
65
+ "scramble",
66
+ "toolchain",
67
+ "tooltask",
68
+ "toolreason",
69
+ "toolfull",
70
+ ];
71
+
72
+ /** Copy per variant; null = the variant draws its own rows. */
73
+ const LABELS: Record<BootLabVariant, string | null> = {
74
+ banner: null,
75
+ terminal: "loading",
76
+ waking: "waking up…",
77
+ booting: "booting up…",
78
+ spinner: "loading",
79
+ spinneronly: null,
80
+ dots: "loading",
81
+ bootlog: "digichat --boot",
82
+ scramble: "loading",
83
+ toolchain: null,
84
+ tooltask: null,
85
+ toolreason: null,
86
+ toolfull: null,
87
+ };
88
+
89
+ /** Variants whose label types itself in (the terminal DNA). */
90
+ const TYPED: ReadonlySet<BootLabVariant> = new Set([
91
+ "terminal",
92
+ "waking",
93
+ "booting",
94
+ ]);
95
+
96
+ const TYPE_MS = 46;
97
+ const SETTLE_HOLD_MS = 180;
98
+
99
+ /** Facts the deployment actually reports; rows without facts stay detail-less. */
100
+ export type BootFacts = {
101
+ starters?: number;
102
+ model?: string;
103
+ models?: number;
104
+ toolLabels?: readonly string[];
105
+ mcpServers?: number;
106
+ backend?: string;
107
+ /**
108
+ * Sleep-on-idle services the host wakes before revealing the chat. When
109
+ * set, a "wake up services" row waits on the real `services` boot step.
110
+ */
111
+ services?: readonly string[];
112
+ };
113
+
114
+ /** Real milestones the app reports while the container comes up. */
115
+ type BootMilestone =
116
+ | "image"
117
+ | "config"
118
+ | "runtime"
119
+ | "loop"
120
+ | "services"
121
+ | "backend";
122
+
123
+ /**
124
+ * Container/agent commands; one row each, in order. Rows adapt to the facts
125
+ * the deployment actually reports (and only those) - extra rows appear when
126
+ * the deployment carries tools or MCP servers, so different deployments show
127
+ * different steps and numbers. Never invent counts. Each row carries the real
128
+ * milestone that completes it (`ms` is the beat it keeps before that milestone
129
+ * lands, and the cap when no signal ever does).
130
+ */
131
+ export function toolChainRows(
132
+ facts?: BootFacts,
133
+ ): readonly {
134
+ label: string;
135
+ detail?: string;
136
+ milestone: BootMilestone;
137
+ ms: number;
138
+ }[] {
139
+ const rows: {
140
+ label: string;
141
+ detail?: string;
142
+ milestone: BootMilestone;
143
+ ms: number;
144
+ }[] = [
145
+ { label: "pull digichat image", milestone: "image", ms: 1320 },
146
+ {
147
+ label: "mount deployment configuration",
148
+ milestone: "config",
149
+ ms: 640,
150
+ detail: facts?.starters ? `${facts.starters} starters` : undefined,
151
+ },
152
+ {
153
+ label: "warm up chat runtime",
154
+ milestone: "runtime",
155
+ ms: 880,
156
+ detail: facts?.model
157
+ ? facts.model
158
+ : facts?.models
159
+ ? `${facts.models} models`
160
+ : undefined,
161
+ },
162
+ ];
163
+ if (facts?.toolLabels?.length) {
164
+ rows.push({
165
+ label: "wire in the tools",
166
+ milestone: "loop",
167
+ ms: 760,
168
+ detail: facts.toolLabels.join(", "),
169
+ });
170
+ }
171
+ if (facts?.mcpServers) {
172
+ rows.push({
173
+ label: "attach mcp servers",
174
+ milestone: "loop",
175
+ ms: 720,
176
+ detail: `${facts.mcpServers} servers`,
177
+ });
178
+ }
179
+ if (facts?.services) {
180
+ rows.push({
181
+ label: "wake up services",
182
+ milestone: "services",
183
+ ms: 0,
184
+ detail: facts.services.length ? facts.services.join(", ") : undefined,
185
+ });
186
+ }
187
+ rows.push({
188
+ label: "wire in the backend",
189
+ milestone: "backend",
190
+ ms: 1402,
191
+ detail: facts?.backend ? `${facts.backend} backend` : undefined,
192
+ });
193
+ return rows;
194
+ }
195
+
196
+ /** The tool-chain family shares the long-load behaviour below. */
197
+ const TOOLCHAIN_VARIANTS: ReadonlySet<BootLabVariant> = new Set([
198
+ "toolchain",
199
+ "tooltask",
200
+ "toolreason",
201
+ "toolfull",
202
+ ]);
203
+
204
+ const REASONING_LABEL = "waking up the container";
205
+ /** Readiness cap: embedded surfaces wait for the app handshake; standalone
206
+ * surfaces never send one, so they settle on their own sooner. Embedded
207
+ * surfaces that pass the cap surface a failure + retry instead of settling. */
208
+ const EMBEDDED_CAP_MS = 120_000;
209
+ const STANDALONE_CAP_MS = 3_000;
210
+ /** Same-window failure signal: the app may dispatch it when the boot dies.
211
+ * The embed does not emit it yet; `?bootfail=<seconds>` demos it locally. */
212
+ const BOOT_FAILED_EVENT = "digichat:boot-failed";
213
+
214
+ /**
215
+ * The standard boot animation for every digichat deployment: the digichat
216
+ * hero banner's LOADING pass.
217
+ */
218
+ export const DEFAULT_BOOT_LAB_VARIANT: BootLabVariant = "banner";
219
+
220
+ /** `?boot=classic` opts back into the pre-banner welcome loader. */
221
+ const CLASSIC_BOOT = "classic";
222
+
223
+ /**
224
+ * Resolve the lab variant: an explicit value (the `bootLabVariant` prop,
225
+ * threaded from a deployment's `chrome.loading` or the embed's `?boot=`)
226
+ * wins; otherwise fall back to `?boot=` on the URL; otherwise the standard
227
+ * banner. A deployment that names nothing gets the banner, never the old
228
+ * tool-chain lab default. `null` means the classic loader on purpose
229
+ * (`?boot=classic`).
230
+ */
231
+ export function resolveBootLabVariant(
232
+ explicit?: string | null,
233
+ ): BootLabVariant | null {
234
+ const value =
235
+ explicit != null
236
+ ? explicit
237
+ : typeof window === "undefined"
238
+ ? null
239
+ : new URL(window.location.href).searchParams.get("boot");
240
+ if (value == null) return DEFAULT_BOOT_LAB_VARIANT;
241
+ if (value === CLASSIC_BOOT) return null;
242
+ return (VARIANTS as readonly string[]).includes(value)
243
+ ? (value as BootLabVariant)
244
+ : DEFAULT_BOOT_LAB_VARIANT;
245
+ }
246
+
247
+ /** `?bootdelay=<seconds>`: emulate a slow container locally (lab only). */
248
+ function resolveBootDelayMs(): number {
249
+ if (typeof window === "undefined") return 0;
250
+ const raw = new URL(window.location.href).searchParams.get("bootdelay");
251
+ const seconds = raw == null ? 0 : Number(raw);
252
+ return Number.isFinite(seconds) && seconds > 0
253
+ ? Math.min(seconds, 300) * 1000
254
+ : 0;
255
+ }
256
+
257
+ /** `?bootfail=<seconds>`: force the boot into its failed state (lab only). */
258
+ function resolveBootFailMs(): number {
259
+ if (typeof window === "undefined") return 0;
260
+ const raw = new URL(window.location.href).searchParams.get("bootfail");
261
+ const seconds = raw == null ? 0 : Number(raw);
262
+ return Number.isFinite(seconds) && seconds > 0
263
+ ? Math.min(seconds, 300) * 1000
264
+ : 0;
265
+ }
266
+
267
+ function useReducedMotion(): boolean {
268
+ const [reduced, setReduced] = useState(false);
269
+ useEffect(() => {
270
+ const query = window.matchMedia("(prefers-reduced-motion: reduce)");
271
+ setReduced(query.matches);
272
+ const onChange = (event: MediaQueryListEvent) => setReduced(event.matches);
273
+ query.addEventListener("change", onChange);
274
+ return () => query.removeEventListener("change", onChange);
275
+ }, []);
276
+ return reduced;
277
+ }
278
+
279
+ function useSettle(ready: boolean, onSettled: () => void) {
280
+ const settledRef = useRef(false);
281
+ useEffect(() => {
282
+ if (!ready || settledRef.current) return;
283
+ settledRef.current = true;
284
+ const timer = setTimeout(() => {
285
+ signalDigichatReady();
286
+ onSettled();
287
+ }, SETTLE_HOLD_MS);
288
+ return () => clearTimeout(timer);
289
+ }, [ready, onSettled]);
290
+ }
291
+
292
+ /**
293
+ * The app's real ready signal: the embed dispatches it once the runtime is
294
+ * up. Standalone surfaces never send one, so they fall back to a short cap.
295
+ */
296
+ function useAppReady(enabled: boolean): { ready: boolean; timedOut: boolean } {
297
+ const [ready, setReady] = useState(false);
298
+ const [timedOut, setTimedOut] = useState(false);
299
+ useEffect(() => {
300
+ if (!enabled) return;
301
+ if (hasDigichatReady()) {
302
+ setReady(true);
303
+ return;
304
+ }
305
+ const onReady = () => setReady(true);
306
+ window.addEventListener(DIGI_CHAT_READY_EVENT, onReady, { once: true });
307
+ const standalone = window.parent === window;
308
+ // Standalone surfaces never receive the handshake, so they settle on
309
+ // their own; embedded surfaces that time out surface a failure + retry.
310
+ const cap = setTimeout(() => {
311
+ if (standalone) setReady(true);
312
+ else setTimedOut(true);
313
+ }, standalone ? STANDALONE_CAP_MS : EMBEDDED_CAP_MS);
314
+ return () => {
315
+ window.removeEventListener(DIGI_CHAT_READY_EVENT, onReady);
316
+ clearTimeout(cap);
317
+ };
318
+ }, [enabled]);
319
+ return { ready, timedOut };
320
+ }
321
+
322
+ /** The boot failed: the app dispatched `digichat:boot-failed` (or the lab
323
+ * knob forced it); `failAfterMs` also demos the state locally. */
324
+ function useAppFailure(enabled: boolean, failAfterMs: number): boolean {
325
+ const [failed, setFailed] = useState(false);
326
+ useEffect(() => {
327
+ if (!enabled) return;
328
+ const onFailed = () => setFailed(true);
329
+ window.addEventListener(BOOT_FAILED_EVENT, onFailed);
330
+ const timer =
331
+ failAfterMs > 0 ? setTimeout(onFailed, failAfterMs) : undefined;
332
+ return () => {
333
+ window.removeEventListener(BOOT_FAILED_EVENT, onFailed);
334
+ if (timer !== undefined) clearTimeout(timer);
335
+ };
336
+ }, [enabled, failAfterMs]);
337
+ return failed;
338
+ }
339
+
340
+ /** Hold `value` back by `delayMs` after it flips true (the lab knob). */
341
+ function useDelayedTrue(value: boolean, delayMs: number): boolean {
342
+ const [delayed, setDelayed] = useState(false);
343
+ useEffect(() => {
344
+ if (!value) {
345
+ setDelayed(false);
346
+ return;
347
+ }
348
+ if (delayMs === 0) {
349
+ setDelayed(true);
350
+ return;
351
+ }
352
+ const timer = setTimeout(() => setDelayed(true), delayMs);
353
+ return () => clearTimeout(timer);
354
+ }, [value, delayMs]);
355
+ return delayed;
356
+ }
357
+
358
+ function TypedLabel({ text, instant }: { text: string; instant: boolean }) {
359
+ const [count, setCount] = useState(instant ? text.length : 0);
360
+ useEffect(() => {
361
+ if (instant) {
362
+ setCount(text.length);
363
+ return;
364
+ }
365
+ const interval = setInterval(() => {
366
+ setCount((current) => {
367
+ if (current >= text.length) {
368
+ clearInterval(interval);
369
+ return current;
370
+ }
371
+ return current + 1;
372
+ });
373
+ }, TYPE_MS);
374
+ return () => clearInterval(interval);
375
+ }, [text, instant]);
376
+ return <>{text.slice(0, count)}</>;
377
+ }
378
+
379
+ function SpinnerLine({ label }: { label?: string | null }) {
380
+ return (
381
+ <span className="dboot-lab-line dboot-lab-spin">
382
+ <DotMatrix state="loading" decorative className="!size-3" />
383
+ {label ? <span>{label}</span> : null}
384
+ </span>
385
+ );
386
+ }
387
+
388
+ function DotsLine() {
389
+ const [count, setCount] = useState(0);
390
+ useEffect(() => {
391
+ const interval = setInterval(() => setCount((c) => (c + 1) % 4), 420);
392
+ return () => clearInterval(interval);
393
+ }, []);
394
+ return (
395
+ <span className="dboot-lab-line">
396
+ loading<span className="dboot-lab-dots" aria-hidden="true">{".".repeat(count)}</span>
397
+ </span>
398
+ );
399
+ }
400
+
401
+ function BootLog() {
402
+ const [step, setStep] = useState(0);
403
+ useEffect(() => {
404
+ const timers = [
405
+ setTimeout(() => setStep(1), 620),
406
+ setTimeout(() => setStep(2), 1240),
407
+ ];
408
+ return () => timers.forEach(clearTimeout);
409
+ }, []);
410
+ return (
411
+ <span className="dboot-lab-lines">
412
+ <span className="dboot-lab-line">$ digichat --boot</span>
413
+ {step > 0 ? (
414
+ <span className="dboot-lab-line dboot-lab-muted">ok</span>
415
+ ) : null}
416
+ </span>
417
+ );
418
+ }
419
+
420
+ const SCRAMBLE_GLYPHS = "▚▞█▓▒░<>/\\|=+*";
421
+
422
+ function ScrambleLine({ text, instant }: { text: string; instant: boolean }) {
423
+ const [display, setDisplay] = useState(instant ? text : "");
424
+ useEffect(() => {
425
+ if (instant) {
426
+ setDisplay(text);
427
+ return;
428
+ }
429
+ let frame = 0;
430
+ const total = text.length * 2;
431
+ const interval = setInterval(() => {
432
+ frame += 1;
433
+ const reveal = Math.floor((frame / total) * text.length);
434
+ setDisplay(
435
+ text.slice(0, reveal) +
436
+ Array.from(
437
+ { length: text.length - reveal },
438
+ (_, index) =>
439
+ SCRAMBLE_GLYPHS[(frame + index) % SCRAMBLE_GLYPHS.length],
440
+ ).join(""),
441
+ );
442
+ if (frame >= total) {
443
+ clearInterval(interval);
444
+ setDisplay(text);
445
+ }
446
+ }, 40);
447
+ return () => clearInterval(interval);
448
+ }, [text, instant]);
449
+ return <span className="dboot-lab-line">{display}</span>;
450
+ }
451
+
452
+ /** Live elapsed ms while `active` (the running tool duration the chat shows). */
453
+ function useLiveMs(active: boolean): number {
454
+ const [ms, setMs] = useState(0);
455
+ useEffect(() => {
456
+ if (!active) return;
457
+ const started = Date.now();
458
+ const interval = setInterval(() => setMs(Date.now() - started), 120);
459
+ return () => clearInterval(interval);
460
+ }, [active]);
461
+ return ms;
462
+ }
463
+
464
+ /**
465
+ * One simulated tool call: the same row anatomy as the message tool calls
466
+ * (`aui-tool-fallback-trigger` + DotMatrix states), so any skin styles it.
467
+ */
468
+ function ToolChainRow({
469
+ label,
470
+ detail,
471
+ durationMs,
472
+ done,
473
+ shown = true,
474
+ failed = false,
475
+ }: {
476
+ label: string;
477
+ detail?: string;
478
+ durationMs: number;
479
+ done: boolean;
480
+ shown?: boolean;
481
+ failed?: boolean;
482
+ }) {
483
+ const liveMs = useLiveMs(shown && !done && !failed);
484
+ const ms = done ? durationMs : liveMs;
485
+ return (
486
+ <div
487
+ className="aui-tool-fallback-trigger group/trigger text-muted-foreground flex w-full items-center gap-2 py-1.5 text-xs"
488
+ data-slot="tool-fallback-trigger"
489
+ data-visible={shown ? "true" : "false"}
490
+ >
491
+ <DotMatrix
492
+ state={failed ? "error" : done ? "success" : "tool"}
493
+ decorative
494
+ className="aui-tool-fallback-trigger-icon !size-3 shrink-0"
495
+ />
496
+ <span
497
+ className="aui-tool-fallback-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none"
498
+ data-slot="tool-fallback-trigger-label"
499
+ >
500
+ {label}
501
+ {detail ? <span className="ml-1 opacity-60">· {detail}</span> : null}
502
+ </span>
503
+ <span className="aui-tool-fallback-duration text-muted-foreground text-xs tabular-nums">
504
+ {(ms / 1000).toFixed(1)}s
505
+ </span>
506
+ </div>
507
+ );
508
+ }
509
+
510
+ /** A reasoning row above the calls (the reasoning trigger anatomy). */
511
+ function ReasoningRow({
512
+ active,
513
+ durationMs,
514
+ }: {
515
+ active: boolean;
516
+ durationMs: number;
517
+ }) {
518
+ return (
519
+ <div
520
+ className="aui-reasoning-trigger group/trigger text-muted-foreground flex w-full items-center gap-2 py-1.5 text-xs"
521
+ data-slot="reasoning-trigger"
522
+ >
523
+ <span
524
+ className="aui-reasoning-trigger-icon inline-flex size-3 shrink-0 items-center justify-center"
525
+ data-slot="reasoning-trigger-icon"
526
+ >
527
+ <DotMatrix
528
+ state={active ? "thinking" : "thought"}
529
+ decorative
530
+ className="!size-3"
531
+ />
532
+ </span>
533
+ <span
534
+ className={
535
+ "aui-reasoning-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none tabular-nums" +
536
+ (active ? " shimmer motion-reduce:animate-none" : "")
537
+ }
538
+ data-slot="reasoning-trigger-label"
539
+ >
540
+ {REASONING_LABEL}
541
+ {active ? "" : ` (${(durationMs / 1000).toFixed(1)}s)`}
542
+ </span>
543
+ <DisclosureChevron />
544
+ </div>
545
+ );
546
+ }
547
+
548
+ function useBootSteps(): ReadonlySet<string> {
549
+ const [steps, setSteps] = useState<ReadonlySet<string>>(
550
+ () => new Set(digichatBootSteps()),
551
+ );
552
+ useEffect(() => {
553
+ const onStep = () => setSteps(new Set(digichatBootSteps()));
554
+ window.addEventListener(DIGI_CHAT_BOOT_STEP_EVENT, onStep);
555
+ return () => window.removeEventListener(DIGI_CHAT_BOOT_STEP_EVENT, onStep);
556
+ }, []);
557
+ return steps;
558
+ }
559
+
560
+ function ToolChain({
561
+ instant,
562
+ ready,
563
+ failed,
564
+ showReasoning,
565
+ facts,
566
+ onDone,
567
+ }: {
568
+ instant: boolean;
569
+ ready: boolean;
570
+ failed: boolean;
571
+ showReasoning: boolean;
572
+ facts?: BootFacts;
573
+ onDone: () => void;
574
+ }) {
575
+ const rows = useMemo(() => toolChainRows(facts), [facts]);
576
+ const steps = useBootSteps();
577
+ const mountClock = useRef(digichatBootClockMs());
578
+ const [doneAt, setDoneAt] = useState<(number | null)[]>(() =>
579
+ rows.map(() => (instant ? mountClock.current : null)),
580
+ );
581
+ const [tick, setTick] = useState(0);
582
+ const pending = doneAt.some((value) => value === null);
583
+ const firstPending = doneAt.findIndex((value) => value === null);
584
+ const chainDone = !pending;
585
+ // Poll while rows are open: each row flips when its real milestone lands.
586
+ // Image rows and tool/MCP rows keep a short beat so the chain stays
587
+ // readable, config/runtime fall back to a cap so a missed signal cannot
588
+ // wedge the boot, and the backend row waits for the app's real ready edge.
589
+ useEffect(() => {
590
+ if (instant || !pending) return;
591
+ const interval = setInterval(() => setTick((value) => value + 1), 250);
592
+ return () => clearInterval(interval);
593
+ }, [instant, pending]);
594
+ useEffect(() => {
595
+ if (instant || !pending) return;
596
+ setDoneAt((current) => {
597
+ const index = current.findIndex((value) => value === null);
598
+ if (index === -1) return current;
599
+ const row = rows[index];
600
+ if (row === undefined) return current;
601
+ const previousDone = index === 0 ? mountClock.current : current[index - 1];
602
+ if (previousDone === null || previousDone === undefined) return current;
603
+ const now = digichatBootClockMs();
604
+ const reached =
605
+ row.milestone === "backend"
606
+ ? ready
607
+ : row.milestone === "services"
608
+ ? // No timed fallback: only the host's real edge completes it.
609
+ steps.has("services") || ready
610
+ : row.milestone === "config" || row.milestone === "runtime"
611
+ ? steps.has(row.milestone) || now - previousDone >= row.ms * 2
612
+ : now - previousDone >= row.ms;
613
+ if (!reached) return current;
614
+ const next = [...current];
615
+ next[index] = now;
616
+ return next;
617
+ });
618
+ }, [tick, instant, pending, ready, rows, steps]);
619
+ useEffect(() => {
620
+ if (chainDone) onDone();
621
+ }, [chainDone, onDone]);
622
+ // The last row waits on the real ready edge - that is the honest "connect"
623
+ // beat; a failed boot leaves its X up instead of settling.
624
+ const completedMs =
625
+ chainDone && doneAt[rows.length - 1] != null
626
+ ? doneAt[rows.length - 1]! - mountClock.current
627
+ : 0;
628
+ return (
629
+ <span className="dboot-lab-tools">
630
+ {showReasoning ? (
631
+ <ReasoningRow active={!chainDone && !failed} durationMs={completedMs} />
632
+ ) : null}
633
+ {rows.map((row, index) => {
634
+ const done = doneAt[index] != null;
635
+ const start =
636
+ index === 0
637
+ ? mountClock.current
638
+ : doneAt[index - 1] ?? mountClock.current;
639
+ // Every row mounts with the chain; unseen rows only hide their paint
640
+ // (visibility), so the block keeps its final height from the first
641
+ // frame and new steps appear below the last one without nudging the
642
+ // rows above.
643
+ const shown = firstPending === -1 || index <= firstPending;
644
+ return (
645
+ <ToolChainRow
646
+ key={row.label}
647
+ label={row.label}
648
+ detail={row.detail}
649
+ durationMs={done ? doneAt[index]! - start : 0}
650
+ done={done}
651
+ shown={shown}
652
+ failed={
653
+ failed &&
654
+ index === (firstPending === -1 ? rows.length - 1 : firstPending)
655
+ }
656
+ />
657
+ );
658
+ })}
659
+ </span>
660
+ );
661
+ }
662
+
663
+ /**
664
+ * The standard boot cover: the digichat hero banner alone, centered both
665
+ * ways, exactly as the site shell draws it (ChatEmbedShell) — no copy and no
666
+ * spinner. The wrapper is what gives the canvas a width; HeroBanner sizes
667
+ * itself to its container. `replayLoading` plays the definition's LOADING
668
+ * pass on mount; under reduced motion it stays off and HeroBanner paints the
669
+ * settled mark without starting a timer.
670
+ */
671
+ function BootBanner({ replayLoading }: { replayLoading: boolean }) {
672
+ return (
673
+ <div
674
+ style={{
675
+ display: "flex",
676
+ alignItems: "center",
677
+ justifyContent: "center",
678
+ width: "100%",
679
+ height: "100%",
680
+ }}
681
+ >
682
+ <div style={{ width: "min(560px, 72vw)" }}>
683
+ <HeroBanner def={DIGICHAT} replayLoading={replayLoading} />
684
+ </div>
685
+ <span className="sr-only">Loading chat…</span>
686
+ </div>
687
+ );
688
+ }
689
+
690
+ export function BootLabOverlay({
691
+ variant,
692
+ ready,
693
+ onSettled,
694
+ accent,
695
+ facts,
696
+ readyEdge,
697
+ }: {
698
+ variant: BootLabVariant;
699
+ ready: boolean;
700
+ onSettled: () => void;
701
+ accent?: string;
702
+ facts?: BootFacts;
703
+ /**
704
+ * The real ready edge when the app runs in another document (an iframe
705
+ * host): this document's ready event never fires there and the standalone
706
+ * self-settle would flip the backend row on its cap instead of the honest
707
+ * beat, so the host passes its own signal (the embed's postMessage) here.
708
+ */
709
+ readyEdge?: boolean;
710
+ }) {
711
+ const reduced = useReducedMotion();
712
+ const isToolchain = TOOLCHAIN_VARIANTS.has(variant);
713
+ const [chainDone, setChainDone] = useState(!isToolchain);
714
+ const [bootDelayMs] = useState(resolveBootDelayMs);
715
+ const [failAfterMs] = useState(resolveBootFailMs);
716
+ const hostOwnsReady = readyEdge !== undefined;
717
+ // `?bootfail` forces the failure demo: ignore the real ready signal so the
718
+ // boot cannot settle before the forced failure lands.
719
+ const app = useAppReady(isToolchain && failAfterMs === 0 && !hostOwnsReady);
720
+ const delayedReady = useDelayedTrue(app.ready, bootDelayMs);
721
+ const appReady = hostOwnsReady ? (readyEdge as boolean) : delayedReady;
722
+ const appFailed = useAppFailure(isToolchain && !hostOwnsReady, failAfterMs);
723
+ const failed = isToolchain && !hostOwnsReady && (appFailed || app.timedOut);
724
+ // The tool chain runs to completion and then waits for the real ready
725
+ // signal, so long cold starts keep a live row instead of looking done.
726
+ // A failed boot never settles: the overlay keeps the error + retry up.
727
+ const active = isToolchain ? ready && chainDone && appReady && !failed : ready;
728
+ useSettle(active, onSettled);
729
+ const label = LABELS[variant];
730
+ return (
731
+ <div
732
+ className="dboot-lab"
733
+ data-digichat-boot=""
734
+ data-variant={variant}
735
+ role="status"
736
+ style={accent ? ({ "--dboot-caret": accent } as CSSProperties) : undefined}
737
+ >
738
+ {variant === "banner" ? <BootBanner replayLoading={!reduced} /> : null}
739
+ {variant === "spinner" ? <SpinnerLine label={label} /> : null}
740
+ {variant === "spinneronly" ? <SpinnerLine /> : null}
741
+ {variant === "dots" ? <DotsLine /> : null}
742
+ {variant === "bootlog" ? <BootLog /> : null}
743
+ {variant === "scramble" && label ? (
744
+ <ScrambleLine text={label} instant={reduced} />
745
+ ) : null}
746
+ {isToolchain ? (
747
+ <ToolChain
748
+ instant={reduced}
749
+ ready={appReady}
750
+ failed={failed}
751
+ showReasoning={variant === "toolreason" || variant === "toolfull"}
752
+ facts={facts}
753
+ onDone={() => setChainDone(true)}
754
+ />
755
+ ) : null}
756
+ {TYPED.has(variant) && label ? (
757
+ <span className="dboot-lab-line">
758
+ <span>
759
+ <TypedLabel text={label} instant={reduced} />
760
+ </span>
761
+ <span className="dboot-lab-caret" aria-hidden="true" />
762
+ </span>
763
+ ) : null}
764
+ </div>
765
+ );
766
+ }