@flamingo-stack/openframe-frontend-core 0.0.692 → 0.0.693-snapshot.20261002120603

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 (205) hide show
  1. package/dist/chat-protocol/events.d.ts +3 -0
  2. package/dist/chat-protocol/events.d.ts.map +1 -1
  3. package/dist/chat-protocol/frames.d.ts +6 -0
  4. package/dist/chat-protocol/frames.d.ts.map +1 -1
  5. package/dist/chat-protocol/index.cjs +26 -1
  6. package/dist/chat-protocol/index.cjs.map +1 -1
  7. package/dist/chat-protocol/index.d.ts +1 -0
  8. package/dist/chat-protocol/index.d.ts.map +1 -1
  9. package/dist/chat-protocol/index.js +23 -2
  10. package/dist/chat-protocol/index.js.map +1 -1
  11. package/dist/chat-protocol/leading-frames.d.ts.map +1 -1
  12. package/dist/chat-protocol/progress.d.ts +35 -0
  13. package/dist/chat-protocol/progress.d.ts.map +1 -0
  14. package/dist/{chunk-GDZ7IC5B.js → chunk-234IIQIS.js} +2 -2
  15. package/dist/{chunk-KDCIYRZV.cjs → chunk-2EQED5SZ.cjs} +34 -34
  16. package/dist/{chunk-KDCIYRZV.cjs.map → chunk-2EQED5SZ.cjs.map} +1 -1
  17. package/dist/{chunk-JUNOY5HK.js → chunk-2HX6AADM.js} +15 -17
  18. package/dist/chunk-2HX6AADM.js.map +1 -0
  19. package/dist/{chunk-X5XFKI6N.js → chunk-33L2IR62.js} +3 -3
  20. package/dist/{chunk-A5NHAHV6.js → chunk-42LIHMRA.js} +4 -4
  21. package/dist/{chunk-MIZU2OTO.cjs → chunk-63BLVGXZ.cjs} +4 -4
  22. package/dist/{chunk-MIZU2OTO.cjs.map → chunk-63BLVGXZ.cjs.map} +1 -1
  23. package/dist/{chunk-TEIHEFXP.js → chunk-6ZSDKDOV.js} +8 -8
  24. package/dist/{chunk-UVUNBXS6.js → chunk-7IINE3MK.js} +48 -5
  25. package/dist/chunk-7IINE3MK.js.map +1 -0
  26. package/dist/{chunk-N3526CTH.cjs → chunk-7TO3CWPM.cjs} +3 -3
  27. package/dist/{chunk-N3526CTH.cjs.map → chunk-7TO3CWPM.cjs.map} +1 -1
  28. package/dist/{chunk-TXFGG47A.js → chunk-7VO6NC67.js} +4 -4
  29. package/dist/{chunk-SC44YJCF.js → chunk-A7RKT5SO.js} +2 -2
  30. package/dist/{chunk-Y7ZEVTLC.js → chunk-BW6YBATM.js} +141 -71
  31. package/dist/chunk-BW6YBATM.js.map +1 -0
  32. package/dist/{chunk-GZRU2A4L.cjs → chunk-C27F6GBZ.cjs} +790 -720
  33. package/dist/chunk-C27F6GBZ.cjs.map +1 -0
  34. package/dist/{chunk-DVSPRY2V.cjs → chunk-ESMDIJIN.cjs} +3 -3
  35. package/dist/{chunk-DVSPRY2V.cjs.map → chunk-ESMDIJIN.cjs.map} +1 -1
  36. package/dist/{chunk-EXWS2QSD.cjs → chunk-FNGX5WZM.cjs} +497 -474
  37. package/dist/chunk-FNGX5WZM.cjs.map +1 -0
  38. package/dist/{chunk-RK47E3PP.js → chunk-GWQCUC53.js} +4 -4
  39. package/dist/{chunk-AVAZ6BD6.js → chunk-HBMGSGZY.js} +6 -6
  40. package/dist/{chunk-HM7ZGABI.js → chunk-HEBLLLLD.js} +2 -2
  41. package/dist/{chunk-7BNWMOPM.cjs → chunk-HJZ3UTUE.cjs} +83 -83
  42. package/dist/{chunk-7BNWMOPM.cjs.map → chunk-HJZ3UTUE.cjs.map} +1 -1
  43. package/dist/{chunk-ATREVNIN.cjs → chunk-JB25CCOB.cjs} +47 -47
  44. package/dist/{chunk-ATREVNIN.cjs.map → chunk-JB25CCOB.cjs.map} +1 -1
  45. package/dist/{chunk-Q25VYAEL.cjs → chunk-JISKS7RJ.cjs} +26 -26
  46. package/dist/{chunk-Q25VYAEL.cjs.map → chunk-JISKS7RJ.cjs.map} +1 -1
  47. package/dist/{chunk-WTYQCT4A.cjs → chunk-K5GSLGV2.cjs} +18 -18
  48. package/dist/{chunk-WTYQCT4A.cjs.map → chunk-K5GSLGV2.cjs.map} +1 -1
  49. package/dist/{chunk-CG7OWW7X.cjs → chunk-K5K2FRQK.cjs} +19 -19
  50. package/dist/{chunk-CG7OWW7X.cjs.map → chunk-K5K2FRQK.cjs.map} +1 -1
  51. package/dist/{chunk-CKUPANVU.cjs → chunk-KBSL4FCL.cjs} +9 -9
  52. package/dist/{chunk-CKUPANVU.cjs.map → chunk-KBSL4FCL.cjs.map} +1 -1
  53. package/dist/{chunk-SDORFSFK.cjs → chunk-KDUDL4PB.cjs} +37 -37
  54. package/dist/{chunk-SDORFSFK.cjs.map → chunk-KDUDL4PB.cjs.map} +1 -1
  55. package/dist/{chunk-5XPK2QGU.cjs → chunk-KJHIFF6H.cjs} +16 -16
  56. package/dist/{chunk-5XPK2QGU.cjs.map → chunk-KJHIFF6H.cjs.map} +1 -1
  57. package/dist/{chunk-MCNQKS6I.js → chunk-LHYOESIQ.js} +4 -4
  58. package/dist/{chunk-DUURFYGS.cjs → chunk-LPFU6U7O.cjs} +5 -5
  59. package/dist/{chunk-DUURFYGS.cjs.map → chunk-LPFU6U7O.cjs.map} +1 -1
  60. package/dist/{chunk-ZAV2F4VX.js → chunk-N7HFUBOV.js} +3 -3
  61. package/dist/{chunk-53O6PQ3F.cjs → chunk-NDLFK57D.cjs} +7 -7
  62. package/dist/{chunk-53O6PQ3F.cjs.map → chunk-NDLFK57D.cjs.map} +1 -1
  63. package/dist/{chunk-Z7QCNCBN.js → chunk-O4RDXDVS.js} +12 -12
  64. package/dist/{chunk-F6LXGP6S.cjs → chunk-Q2B2MGFU.cjs} +7 -7
  65. package/dist/{chunk-F6LXGP6S.cjs.map → chunk-Q2B2MGFU.cjs.map} +1 -1
  66. package/dist/{chunk-CKO6NKNE.js → chunk-QP54LMXJ.js} +38 -15
  67. package/dist/{chunk-CKO6NKNE.js.map → chunk-QP54LMXJ.js.map} +1 -1
  68. package/dist/{chunk-QRA2JXE4.cjs → chunk-RE6PGOSS.cjs} +6 -8
  69. package/dist/chunk-RE6PGOSS.cjs.map +1 -0
  70. package/dist/{chunk-C2SVJVEB.js → chunk-SH5GPYSV.js} +2 -2
  71. package/dist/{chunk-KQZMM3QJ.cjs → chunk-SJFB4Z4L.cjs} +105 -105
  72. package/dist/{chunk-KQZMM3QJ.cjs.map → chunk-SJFB4Z4L.cjs.map} +1 -1
  73. package/dist/{chunk-7EPGJOKN.js → chunk-TA3JJFEO.js} +4 -4
  74. package/dist/{chunk-LYJJH4D6.js → chunk-TBR3UTFY.js} +6 -6
  75. package/dist/{chunk-USKQURNF.cjs → chunk-TG3VBMDG.cjs} +3 -3
  76. package/dist/{chunk-USKQURNF.cjs.map → chunk-TG3VBMDG.cjs.map} +1 -1
  77. package/dist/{chunk-IQTQIBZ3.js → chunk-TV5SZJ3N.js} +12 -12
  78. package/dist/{chunk-RLNNV46K.js → chunk-TXSQLORA.js} +6 -6
  79. package/dist/{chunk-LYQULSK4.js → chunk-UCXZRJIE.js} +7 -7
  80. package/dist/{chunk-I27PWVWE.cjs → chunk-WT4HURQN.cjs} +46 -3
  81. package/dist/chunk-WT4HURQN.cjs.map +1 -0
  82. package/dist/{chunk-XAOAYDGR.js → chunk-WZJWIZVH.js} +4 -4
  83. package/dist/{chunk-PKZGXRU2.js → chunk-XKNKGBUX.js} +10 -8
  84. package/dist/{chunk-PKZGXRU2.js.map → chunk-XKNKGBUX.js.map} +1 -1
  85. package/dist/{chunk-LNKLB7GM.cjs → chunk-XNTQHC26.cjs} +28 -28
  86. package/dist/{chunk-LNKLB7GM.cjs.map → chunk-XNTQHC26.cjs.map} +1 -1
  87. package/dist/{chunk-2YVTGPM7.js → chunk-XZILGCXJ.js} +2 -2
  88. package/dist/{chunk-DKJDO7YM.cjs → chunk-Y5AFMYYN.cjs} +46 -44
  89. package/dist/chunk-Y5AFMYYN.cjs.map +1 -0
  90. package/dist/{chunk-FTK3S57R.cjs → chunk-ZCPMWXIB.cjs} +25 -25
  91. package/dist/{chunk-FTK3S57R.cjs.map → chunk-ZCPMWXIB.cjs.map} +1 -1
  92. package/dist/{chunk-RTKF5AYA.cjs → chunk-ZUGAHQDB.cjs} +7 -7
  93. package/dist/{chunk-RTKF5AYA.cjs.map → chunk-ZUGAHQDB.cjs.map} +1 -1
  94. package/dist/components/case-studies/index.cjs +21 -21
  95. package/dist/components/case-studies/index.js +8 -8
  96. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  97. package/dist/components/chat/chat-typing-indicator.d.ts.map +1 -1
  98. package/dist/components/chat/cycling-phrase.d.ts.map +1 -1
  99. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  100. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  101. package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
  102. package/dist/components/chat/index.cjs +5 -5
  103. package/dist/components/chat/index.js +4 -4
  104. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +1 -1
  105. package/dist/components/chat/stream/chat-stream-reducer.d.ts +4 -0
  106. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
  107. package/dist/components/chat/types/component.types.d.ts +2 -0
  108. package/dist/components/chat/types/component.types.d.ts.map +1 -1
  109. package/dist/components/chat/types/unified-chat-state.types.d.ts +5 -0
  110. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  111. package/dist/components/contact/index.cjs +9 -9
  112. package/dist/components/contact/index.js +8 -8
  113. package/dist/components/docs/index.cjs +12 -12
  114. package/dist/components/docs/index.js +11 -11
  115. package/dist/components/embeds/index.cjs +9 -9
  116. package/dist/components/embeds/index.js +8 -8
  117. package/dist/components/faq/index.cjs +10 -10
  118. package/dist/components/faq/index.js +9 -9
  119. package/dist/components/features/index.cjs +8 -8
  120. package/dist/components/features/index.js +7 -7
  121. package/dist/components/help-center-pages/index.cjs +107 -107
  122. package/dist/components/help-center-pages/index.js +22 -22
  123. package/dist/components/index.cjs +69 -69
  124. package/dist/components/index.js +22 -22
  125. package/dist/components/meeting-scheduler/index.cjs +59 -59
  126. package/dist/components/meeting-scheduler/index.js +9 -9
  127. package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
  128. package/dist/components/navigation/index.cjs +11 -11
  129. package/dist/components/navigation/index.js +10 -10
  130. package/dist/components/onboarding-guides/index.cjs +12 -12
  131. package/dist/components/onboarding-guides/index.js +11 -11
  132. package/dist/components/related-content/index.cjs +6 -6
  133. package/dist/components/related-content/index.js +5 -5
  134. package/dist/components/tickets/index.cjs +13 -13
  135. package/dist/components/tickets/index.js +12 -12
  136. package/dist/components/ui/index.cjs +8 -8
  137. package/dist/components/ui/index.js +7 -7
  138. package/dist/components/ui/markdown/engine.d.ts +0 -21
  139. package/dist/components/ui/markdown/engine.d.ts.map +1 -1
  140. package/dist/hooks/index.cjs +6 -6
  141. package/dist/hooks/index.cjs.map +1 -1
  142. package/dist/hooks/index.js +5 -5
  143. package/dist/hooks/use-authed-asset-src.d.ts.map +1 -1
  144. package/dist/index.cjs +15 -15
  145. package/dist/index.cjs.map +1 -1
  146. package/dist/index.js +12 -12
  147. package/dist/tailwind.config.cjs +14 -1
  148. package/dist/tailwind.config.cjs.map +1 -1
  149. package/dist/tailwind.config.js +14 -1
  150. package/dist/tailwind.config.js.map +1 -1
  151. package/eslint-config/README.md +13 -0
  152. package/eslint-config/base.js +15 -0
  153. package/eslint-config/webview-performance.js +75 -0
  154. package/package.json +1 -1
  155. package/src/chat-protocol/__tests__/progress.test.ts +39 -0
  156. package/src/chat-protocol/events.ts +3 -0
  157. package/src/chat-protocol/frames.ts +7 -0
  158. package/src/chat-protocol/index.ts +2 -0
  159. package/src/chat-protocol/leading-frames.ts +4 -1
  160. package/src/chat-protocol/progress.ts +55 -0
  161. package/src/components/chat/chat-message-enhanced.tsx +1 -1
  162. package/src/components/chat/chat-message-list.tsx +65 -15
  163. package/src/components/chat/chat-typing-indicator.tsx +18 -29
  164. package/src/components/chat/cycling-phrase.tsx +1 -11
  165. package/src/components/chat/embeddable-chat.tsx +14 -6
  166. package/src/components/chat/hooks/use-sse-chat-adapter.ts +2 -0
  167. package/src/components/chat/hooks/use-unified-chat.ts +1 -0
  168. package/src/components/chat/stream/__tests__/chat-stream-reducer-progress.test.ts +40 -0
  169. package/src/components/chat/stream/chat-dialog-store.ts +1 -0
  170. package/src/components/chat/stream/chat-stream-reducer.ts +13 -0
  171. package/src/components/chat/types/component.types.ts +2 -0
  172. package/src/components/chat/types/unified-chat-state.types.ts +6 -0
  173. package/src/components/navigation/app-layout-drawer.tsx +53 -7
  174. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +29 -29
  175. package/src/components/ui/markdown/engine.tsx +56 -12
  176. package/src/hooks/use-authed-asset-src.ts +58 -6
  177. package/tailwind.config.ts +13 -0
  178. package/dist/chunk-DKJDO7YM.cjs.map +0 -1
  179. package/dist/chunk-EXWS2QSD.cjs.map +0 -1
  180. package/dist/chunk-GZRU2A4L.cjs.map +0 -1
  181. package/dist/chunk-I27PWVWE.cjs.map +0 -1
  182. package/dist/chunk-JUNOY5HK.js.map +0 -1
  183. package/dist/chunk-QRA2JXE4.cjs.map +0 -1
  184. package/dist/chunk-UVUNBXS6.js.map +0 -1
  185. package/dist/chunk-Y7ZEVTLC.js.map +0 -1
  186. /package/dist/{chunk-GDZ7IC5B.js.map → chunk-234IIQIS.js.map} +0 -0
  187. /package/dist/{chunk-X5XFKI6N.js.map → chunk-33L2IR62.js.map} +0 -0
  188. /package/dist/{chunk-A5NHAHV6.js.map → chunk-42LIHMRA.js.map} +0 -0
  189. /package/dist/{chunk-TEIHEFXP.js.map → chunk-6ZSDKDOV.js.map} +0 -0
  190. /package/dist/{chunk-TXFGG47A.js.map → chunk-7VO6NC67.js.map} +0 -0
  191. /package/dist/{chunk-SC44YJCF.js.map → chunk-A7RKT5SO.js.map} +0 -0
  192. /package/dist/{chunk-RK47E3PP.js.map → chunk-GWQCUC53.js.map} +0 -0
  193. /package/dist/{chunk-AVAZ6BD6.js.map → chunk-HBMGSGZY.js.map} +0 -0
  194. /package/dist/{chunk-HM7ZGABI.js.map → chunk-HEBLLLLD.js.map} +0 -0
  195. /package/dist/{chunk-MCNQKS6I.js.map → chunk-LHYOESIQ.js.map} +0 -0
  196. /package/dist/{chunk-ZAV2F4VX.js.map → chunk-N7HFUBOV.js.map} +0 -0
  197. /package/dist/{chunk-Z7QCNCBN.js.map → chunk-O4RDXDVS.js.map} +0 -0
  198. /package/dist/{chunk-C2SVJVEB.js.map → chunk-SH5GPYSV.js.map} +0 -0
  199. /package/dist/{chunk-7EPGJOKN.js.map → chunk-TA3JJFEO.js.map} +0 -0
  200. /package/dist/{chunk-LYJJH4D6.js.map → chunk-TBR3UTFY.js.map} +0 -0
  201. /package/dist/{chunk-IQTQIBZ3.js.map → chunk-TV5SZJ3N.js.map} +0 -0
  202. /package/dist/{chunk-RLNNV46K.js.map → chunk-TXSQLORA.js.map} +0 -0
  203. /package/dist/{chunk-LYQULSK4.js.map → chunk-UCXZRJIE.js.map} +0 -0
  204. /package/dist/{chunk-XAOAYDGR.js.map → chunk-WZJWIZVH.js.map} +0 -0
  205. /package/dist/{chunk-2YVTGPM7.js.map → chunk-XZILGCXJ.js.map} +0 -0
@@ -16,13 +16,12 @@ import {
16
16
  useDebounce,
17
17
  useHeaderHeight,
18
18
  useIsTruncated,
19
- useIsomorphicLayoutEffect,
20
19
  useMarqueeEngine,
21
20
  useMediaQuery,
22
21
  useNearViewport,
23
22
  useResetOnPageHidden,
24
23
  useSuppressCloneFocus
25
- } from "./chunk-JUNOY5HK.js";
24
+ } from "./chunk-2HX6AADM.js";
26
25
  import {
27
26
  useRouter
28
27
  } from "./chunk-XXMHLZ3Y.js";
@@ -198,7 +197,7 @@ import {
198
197
  trustFrameworkMonitoringEntry,
199
198
  trustFrameworksSummary,
200
199
  useCoverImageFallback
201
- } from "./chunk-2YVTGPM7.js";
200
+ } from "./chunk-XZILGCXJ.js";
202
201
  import {
203
202
  next_image_default
204
203
  } from "./chunk-MDKCTSDS.js";
@@ -213,8 +212,9 @@ import {
213
212
  getPlatformDisplayName,
214
213
  setEmbedProxyAuth,
215
214
  useAuthedAssetSrc,
216
- useAuthedImageSrc
217
- } from "./chunk-UVUNBXS6.js";
215
+ useAuthedImageSrc,
216
+ useIsomorphicLayoutEffect
217
+ } from "./chunk-7IINE3MK.js";
218
218
  import {
219
219
  OpenFrameLogo
220
220
  } from "./chunk-OTX6XNSA.js";
@@ -3785,6 +3785,25 @@ function resolveTextSizeConfig(config) {
3785
3785
  // src/components/ui/markdown/engine.tsx
3786
3786
  import { jsx as jsx15 } from "react/jsx-runtime";
3787
3787
  var NO_BROKEN_LINKS = [];
3788
+ var BARE_FENCE_LANGUAGE = "code";
3789
+ function rehypeLabelBareFences() {
3790
+ const visit4 = (node) => {
3791
+ for (const child of node.children) {
3792
+ if (child.type !== "element") continue;
3793
+ if (child.tagName === "pre") {
3794
+ for (const code of child.children) {
3795
+ if (code.type !== "element" || code.tagName !== "code") continue;
3796
+ const classes = Array.isArray(code.properties.className) ? code.properties.className : [];
3797
+ if (!classes.some((c) => String(c).startsWith("language-"))) {
3798
+ code.properties.className = [...classes, `language-${BARE_FENCE_LANGUAGE}`];
3799
+ }
3800
+ }
3801
+ }
3802
+ visit4(child);
3803
+ }
3804
+ };
3805
+ return (tree) => visit4(tree);
3806
+ }
3788
3807
  var StreamingBlockRenderer = memo(function StreamingBlockRendererImpl({
3789
3808
  text: text2,
3790
3809
  remarkPlugins,
@@ -3834,19 +3853,27 @@ var MarkdownEngineImpl = ({
3834
3853
  () => [remarkGfm, remarkBreaks, ...additionalRemarkPlugins ?? []],
3835
3854
  [additionalRemarkPlugins]
3836
3855
  );
3837
- const rehypePlugins = useMemo4(() => {
3856
+ const { rehypePlugins, liveRehypePlugins } = useMemo4(() => {
3838
3857
  const schema = buildSanitizeSchema({
3839
3858
  extraAllowedHtmlTags: extraTagsKey ? extraTagsKey.split("|") : void 0
3840
3859
  });
3841
- return [
3842
- // ORDER MATTERS: rehype-raw parses embedded raw HTML into HAST;
3843
- // rehypeSanitize is the allow-list boundary; rehypeStripUnsafe is
3844
- // defense-in-depth (srcset scanning, iframe[srcdoc]); highlight last.
3845
- rehypeRaw,
3846
- [rehypeSanitize, schema],
3847
- rehypeStripUnsafe,
3848
- [rehypeHighlight, { detect: true, ignoreMissing: true }]
3860
+ const safe = [rehypeRaw, [rehypeSanitize, schema], rehypeStripUnsafe, rehypeLabelBareFences];
3861
+ const highlighted = [
3862
+ ...safe,
3863
+ // No language detection: it ran highlightAuto over every registered
3864
+ // grammar for each unlabelled fence (~2.5x the cost of opening a
3865
+ // thread) and often guessed wrong (PowerShell shown as "VBNET").
3866
+ [rehypeHighlight, { plainText: [BARE_FENCE_LANGUAGE] }]
3849
3867
  ];
3868
+ return {
3869
+ rehypePlugins: highlighted,
3870
+ // The streaming tail re-parses on every chunk, and a code fence being
3871
+ // typed is one tail block — highlighting it every chunk was the
3872
+ // costliest step of a streamed reply. It is highlighted once it
3873
+ // completes: every block before the tail and the final parse use
3874
+ // `rehypePlugins`.
3875
+ liveRehypePlugins: safe
3876
+ };
3850
3877
  }, [extraTagsKey]);
3851
3878
  const components = useMemo4(
3852
3879
  () => ({
@@ -3872,7 +3899,7 @@ var MarkdownEngineImpl = ({
3872
3899
  // aria-live: readers announce coherent appended chunks, not per-token
3873
3900
  // spam (polite + additions). Streaming caret/pulse affordances live in
3874
3901
  // chat components and honor prefers-reduced-motion there.
3875
- /* @__PURE__ */ jsx15("div", { "aria-live": "polite", "aria-relevant": "additions text", children: streamingBlocks.map((block) => (
3902
+ /* @__PURE__ */ jsx15("div", { "aria-live": "polite", "aria-relevant": "additions text", children: streamingBlocks.map((block, i) => (
3876
3903
  // Each unit is parsed on its own, so hast positions restart at 1;
3877
3904
  // the offset maps them back onto the document-wide heading-id map.
3878
3905
  /* @__PURE__ */ jsx15(HeadingLineOffsetContext.Provider, { value: block.startLine - 1, children: block.memoizable ? /* @__PURE__ */ jsx15(
@@ -3887,7 +3914,7 @@ var MarkdownEngineImpl = ({
3887
3914
  ReactMarkdown,
3888
3915
  {
3889
3916
  remarkPlugins,
3890
- rehypePlugins,
3917
+ rehypePlugins: i === streamingBlocks.length - 1 ? liveRehypePlugins : rehypePlugins,
3891
3918
  urlTransform: cardAwareUrlTransform,
3892
3919
  components,
3893
3920
  children: block.text
@@ -5406,50 +5433,40 @@ var ChatTypingIndicator = forwardRef14(
5406
5433
  md: "h-6",
5407
5434
  lg: "h-8"
5408
5435
  };
5409
- const dotAnimation = `
5410
- @keyframes dotPulse {
5411
- 0%, 80%, 100% {
5412
- transform: scale(1);
5413
- opacity: 0.7;
5414
- }
5415
- 40% {
5416
- transform: scale(1.5);
5417
- opacity: 1;
5418
- }
5419
- }
5420
- `;
5421
5436
  return /* @__PURE__ */ jsxs19("div", { ref, className: cn("flex items-center gap-2", className), ...props, children: [
5422
- /* @__PURE__ */ jsx28("style", { dangerouslySetInnerHTML: { __html: dotAnimation } }),
5423
5437
  showText && /* @__PURE__ */ jsx28("span", { className: "text-ods-text-secondary text-h6", children: "Assistant is typing" }),
5424
5438
  /* @__PURE__ */ jsxs19("div", { className: cn("inline-flex items-center justify-center gap-1", containerSizeClasses[size2]), children: [
5425
5439
  /* @__PURE__ */ jsx28(
5426
5440
  "div",
5427
5441
  {
5428
- className: cn(dotSizeClasses[size2], "rounded-full", dotClassName || "bg-ods-text-primary"),
5429
- style: {
5430
- animation: "dotPulse 1.4s ease-in-out infinite",
5431
- animationDelay: "0ms"
5432
- }
5442
+ className: cn(
5443
+ dotSizeClasses[size2],
5444
+ "animate-dot-pulse rounded-full",
5445
+ dotClassName || "bg-ods-text-primary"
5446
+ ),
5447
+ style: { animationDelay: "0ms" }
5433
5448
  }
5434
5449
  ),
5435
5450
  /* @__PURE__ */ jsx28(
5436
5451
  "div",
5437
5452
  {
5438
- className: cn(dotSizeClasses[size2], "rounded-full", dotClassName || "bg-ods-text-primary"),
5439
- style: {
5440
- animation: "dotPulse 1.4s ease-in-out infinite",
5441
- animationDelay: "200ms"
5442
- }
5453
+ className: cn(
5454
+ dotSizeClasses[size2],
5455
+ "animate-dot-pulse rounded-full",
5456
+ dotClassName || "bg-ods-text-primary"
5457
+ ),
5458
+ style: { animationDelay: "200ms" }
5443
5459
  }
5444
5460
  ),
5445
5461
  /* @__PURE__ */ jsx28(
5446
5462
  "div",
5447
5463
  {
5448
- className: cn(dotSizeClasses[size2], "rounded-full", dotClassName || "bg-ods-text-primary"),
5449
- style: {
5450
- animation: "dotPulse 1.4s ease-in-out infinite",
5451
- animationDelay: "400ms"
5452
- }
5464
+ className: cn(
5465
+ dotSizeClasses[size2],
5466
+ "animate-dot-pulse rounded-full",
5467
+ dotClassName || "bg-ods-text-primary"
5468
+ ),
5469
+ style: { animationDelay: "400ms" }
5453
5470
  }
5454
5471
  )
5455
5472
  ] })
@@ -7710,7 +7727,7 @@ var ChatMessageEnhanced = forwardRef17(
7710
7727
  "span",
7711
7728
  {
7712
7729
  className: cn(
7713
- "flex-1 !font-mono !font-medium text-h3",
7730
+ "min-w-0 flex-1 truncate !font-mono !font-medium text-h3",
7714
7731
  authorType === "system" ? "text-ods-open-yellow" : authorType === "admin" ? "text-ods-open-yellow" : authorType === "mingo" ? "text-ods-flamingo-cyan" : authorType === "fae" ? "text-ods-flamingo-pink" : "text-ods-text-secondary"
7715
7732
  ),
7716
7733
  children: [
@@ -7917,11 +7934,6 @@ function ChatMessageListSkeleton({
7917
7934
  // src/components/chat/cycling-phrase.tsx
7918
7935
  import { useEffect as useEffect7, useMemo as useMemo10, useState as useState13 } from "react";
7919
7936
  import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
7920
- var BLINK_KEYFRAMES = `
7921
- @keyframes cyclingCursorBlink {
7922
- 50% { opacity: 0; }
7923
- }
7924
- `;
7925
7937
  function CyclingPhrase({ words, className, charMs = 60, holdMs = 4500 }) {
7926
7938
  const [wordIndex, setWordIndex] = useState13(0);
7927
7939
  const [text2, setText] = useState13("");
@@ -7962,19 +7974,17 @@ function CyclingPhrase({ words, className, charMs = 60, holdMs = 4500 }) {
7962
7974
  "span",
7963
7975
  {
7964
7976
  "aria-hidden": true,
7965
- className: "inline-block bg-current align-baseline",
7977
+ className: "inline-block animate-cursor-blink bg-current align-baseline",
7966
7978
  style: {
7967
7979
  width: "0.6em",
7968
7980
  height: "1em",
7969
7981
  verticalAlign: "-0.1em",
7970
7982
  marginLeft: "1px",
7971
- marginRight: "1px",
7972
- animation: "cyclingCursorBlink 1s steps(1) infinite"
7983
+ marginRight: "1px"
7973
7984
  }
7974
7985
  }
7975
7986
  );
7976
7987
  return /* @__PURE__ */ jsxs27("span", { className: cn("relative inline-block whitespace-nowrap", className), children: [
7977
- /* @__PURE__ */ jsx38("style", { dangerouslySetInnerHTML: { __html: BLINK_KEYFRAMES } }),
7978
7988
  /* @__PURE__ */ jsxs27("span", { "aria-hidden": true, className: "invisible", children: [
7979
7989
  placeholder,
7980
7990
  "..."
@@ -8004,6 +8014,8 @@ var STREAMING_WORDS = [
8004
8014
  ];
8005
8015
  var BOTTOM_THRESHOLD_PX = 70;
8006
8016
  var FOLLOW_RETAIN_MS = 350;
8017
+ var GROWTH_WATCH_IDLE_MS = 1e4;
8018
+ var MEDIA_SETTLE_EVENTS = ["load", "error", "loadedmetadata"];
8007
8019
  function hasNonEmptyContent(content) {
8008
8020
  if (typeof content === "string") return content.length > 0;
8009
8021
  if (!Array.isArray(content)) return false;
@@ -8021,6 +8033,7 @@ var ChatMessageList = forwardRef18(
8021
8033
  dialogId,
8022
8034
  isLoading = false,
8023
8035
  isTyping = false,
8036
+ typingMessage,
8024
8037
  autoScroll = true,
8025
8038
  overscrollContain = true,
8026
8039
  pinBottom = false,
@@ -8080,6 +8093,7 @@ var ChatMessageList = forwardRef18(
8080
8093
  const dialogIdRef = useRef6(dialogId);
8081
8094
  dialogIdRef.current = dialogId;
8082
8095
  const followBottomRef = useRef6(false);
8096
+ const kickGrowthWatchRef = useRef6(null);
8083
8097
  const [atBottom, setAtBottom] = useState14(true);
8084
8098
  const prevRenderRef = useRef6({ dialogId: void 0, messageCount: 0, lastMessageId: void 0 });
8085
8099
  const loadOlderAnchorRef = useRef6(null);
@@ -8131,19 +8145,33 @@ var ChatMessageList = forwardRef18(
8131
8145
  }
8132
8146
  measure();
8133
8147
  };
8134
- const ro = new ResizeObserver(reassert);
8135
- ro.observe(content);
8136
- ro.observe(scroller);
8137
8148
  let growthRaf = 0;
8138
8149
  let lastScrollHeight = scroller.scrollHeight;
8139
- const watchGrowth = () => {
8140
- growthRaf = requestAnimationFrame(watchGrowth);
8150
+ let lastGrowthAt = performance.now();
8151
+ const watchGrowth = (now) => {
8141
8152
  const height = scroller.scrollHeight;
8142
- if (height === lastScrollHeight) return;
8143
- lastScrollHeight = height;
8144
- reassert();
8153
+ if (height !== lastScrollHeight) {
8154
+ lastScrollHeight = height;
8155
+ lastGrowthAt = now;
8156
+ reassert();
8157
+ } else if (now - lastGrowthAt > GROWTH_WATCH_IDLE_MS) {
8158
+ growthRaf = 0;
8159
+ return;
8160
+ }
8161
+ growthRaf = requestAnimationFrame(watchGrowth);
8162
+ };
8163
+ const kick = () => {
8164
+ lastGrowthAt = performance.now();
8165
+ if (!growthRaf) growthRaf = requestAnimationFrame(watchGrowth);
8145
8166
  };
8146
- growthRaf = requestAnimationFrame(watchGrowth);
8167
+ kick();
8168
+ kickGrowthWatchRef.current = kick;
8169
+ const ro = new ResizeObserver(() => {
8170
+ kick();
8171
+ reassert();
8172
+ });
8173
+ ro.observe(content);
8174
+ ro.observe(scroller);
8147
8175
  const disarm = () => {
8148
8176
  followBottomRef.current = false;
8149
8177
  stopScroll();
@@ -8179,6 +8207,7 @@ var ChatMessageList = forwardRef18(
8179
8207
  rearmIfAtBottom();
8180
8208
  };
8181
8209
  const onScroll = () => {
8210
+ kick();
8182
8211
  const st = scroller.scrollTop;
8183
8212
  if (pointerDown && st < lastScrollTop) disarm();
8184
8213
  lastScrollTop = st;
@@ -8195,23 +8224,29 @@ var ChatMessageList = forwardRef18(
8195
8224
  scroller.addEventListener("touchmove", onTouchMove, { passive: true });
8196
8225
  window.addEventListener("pointerdown", onPointerDown, winCapture);
8197
8226
  scroller.addEventListener("scroll", onScroll, { passive: true });
8227
+ for (const type of MEDIA_SETTLE_EVENTS) scroller.addEventListener(type, kick, { capture: true, passive: true });
8198
8228
  window.addEventListener("pointerup", endPointer, winCapture);
8199
8229
  window.addEventListener("pointercancel", endPointer, winCapture);
8200
8230
  window.addEventListener("blur", endPointer, { passive: true });
8201
8231
  return () => {
8202
8232
  ro.disconnect();
8203
8233
  cancelAnimationFrame(growthRaf);
8234
+ kickGrowthWatchRef.current = null;
8204
8235
  scroller.removeEventListener("wheel", onWheel);
8205
8236
  scroller.removeEventListener("keydown", onKeyDown);
8206
8237
  scroller.removeEventListener("touchstart", onTouchStart);
8207
8238
  scroller.removeEventListener("touchmove", onTouchMove);
8208
8239
  window.removeEventListener("pointerdown", onPointerDown, { capture: true });
8209
8240
  scroller.removeEventListener("scroll", onScroll);
8241
+ for (const type of MEDIA_SETTLE_EVENTS) scroller.removeEventListener(type, kick, { capture: true });
8210
8242
  window.removeEventListener("pointerup", endPointer, { capture: true });
8211
8243
  window.removeEventListener("pointercancel", endPointer, { capture: true });
8212
8244
  window.removeEventListener("blur", endPointer);
8213
8245
  };
8214
8246
  }, [autoScroll, scrollRef, contentRef, scrollToBottom, stopScroll, isLoading]);
8247
+ useEffect8(() => {
8248
+ kickGrowthWatchRef.current?.();
8249
+ }, [messages, isTyping]);
8215
8250
  const pinPrevHeightRef = useRef6(0);
8216
8251
  useLayoutEffect4(() => {
8217
8252
  if (!pinBottom) {
@@ -8466,7 +8501,7 @@ var ChatMessageList = forwardRef18(
8466
8501
  "aria-live": "polite",
8467
8502
  children: [
8468
8503
  /* @__PURE__ */ jsx39(DotsLoaderIcon, { className: "h-6 w-6" }),
8469
- /* @__PURE__ */ jsx39(CyclingPhrase, { words: STREAMING_WORDS, className: "text-h6" })
8504
+ typingMessage ? /* @__PURE__ */ jsx39("span", { className: "text-h6", "aria-atomic": "true", children: typingMessage }) : /* @__PURE__ */ jsx39(CyclingPhrase, { words: STREAMING_WORDS, className: "text-h6" })
8470
8505
  ]
8471
8506
  }
8472
8507
  ),
@@ -19310,6 +19345,26 @@ var FRAME_TERMINATOR = "\0";
19310
19345
  var END_OF_LEADING = "";
19311
19346
  var TRAILER_SENTINEL = "";
19312
19347
 
19348
+ // src/chat-protocol/progress.ts
19349
+ var CHAT_PROGRESS_STAGES = ["understanding", "searching", "searching_again", "reading"];
19350
+ function isChatProgressStage(value) {
19351
+ return typeof value === "string" && CHAT_PROGRESS_STAGES.includes(value);
19352
+ }
19353
+ function chatProgressOf(frame) {
19354
+ if (!isChatProgressStage(frame.stage)) return null;
19355
+ const count = typeof frame.count === "number" && Number.isFinite(frame.count) && frame.count > 0 ? Math.floor(frame.count) : void 0;
19356
+ return count === void 0 ? { stage: frame.stage } : { stage: frame.stage, count };
19357
+ }
19358
+ var PROGRESS_LABEL = {
19359
+ understanding: () => "Understanding your question",
19360
+ searching: (count) => count ? `Searching ${count} ${count === 1 ? "source" : "sources"}` : "Searching",
19361
+ searching_again: () => "Searching more broadly",
19362
+ reading: (count) => count ? `Reading ${count} ${count === 1 ? "result" : "results"}` : "Reading the results"
19363
+ };
19364
+ function chatProgressLabel(progress) {
19365
+ return PROGRESS_LABEL[progress.stage](progress.count);
19366
+ }
19367
+
19313
19368
  // src/chat-protocol/leading-frames.ts
19314
19369
  function escapeThinkingTags(text2) {
19315
19370
  return text2.replace(/</g, "&lt;");
@@ -19322,7 +19377,8 @@ function frameNum(value) {
19322
19377
  }
19323
19378
  function mapLeadingFrame(meta, out) {
19324
19379
  if (meta.status === "thinking") {
19325
- out.push({ type: "status", phase: "thinking" });
19380
+ const progress = chatProgressOf(meta);
19381
+ out.push(progress ? { type: "status", phase: "thinking", progress } : { type: "status", phase: "thinking" });
19326
19382
  } else if (meta.kind === "thinking-delta" && typeof meta.text === "string") {
19327
19383
  out.push({ type: "thinking-delta", text: meta.text });
19328
19384
  } else if (meta.kind === "usage" && meta.stage === "start") {
@@ -20603,6 +20659,7 @@ function createChatStreamReducer(options = {}) {
20603
20659
  } = options;
20604
20660
  let messages = [];
20605
20661
  let streamingPhase = "idle";
20662
+ let streamingProgress = null;
20606
20663
  let dialogTokenUsage = null;
20607
20664
  let liveModel = null;
20608
20665
  let approvalStatuses = {
@@ -20661,6 +20718,8 @@ function createChatStreamReducer(options = {}) {
20661
20718
  stateCache = {
20662
20719
  messages,
20663
20720
  streamingPhase,
20721
+ // A stage describes the wait before the first token only.
20722
+ streamingProgress: streamingPhase === "thinking" ? streamingProgress : null,
20664
20723
  turnMeta: { meta: metaMap, sources: sourcesMap, sendCount },
20665
20724
  dialogTokenUsage,
20666
20725
  liveModel,
@@ -21281,6 +21340,10 @@ function createChatStreamReducer(options = {}) {
21281
21340
  const sendIdx = sendCount - 1;
21282
21341
  switch (event.type) {
21283
21342
  case "status":
21343
+ if (event.progress) {
21344
+ streamingProgress = event.progress;
21345
+ invalidate();
21346
+ }
21284
21347
  setPhaseInternal("thinking");
21285
21348
  break;
21286
21349
  case "thinking-delta":
@@ -21513,6 +21576,7 @@ function createChatStreamReducer(options = {}) {
21513
21576
  { id: nextId("assistant"), role: "assistant", content: "", segments: [] }
21514
21577
  ];
21515
21578
  streamingPhase = "thinking";
21579
+ streamingProgress = null;
21516
21580
  invalidate();
21517
21581
  },
21518
21582
  clearThread() {
@@ -21557,6 +21621,7 @@ function createChatStreamReducer(options = {}) {
21557
21621
  sendCount += 1;
21558
21622
  sseCurrentText = "";
21559
21623
  streamingPhase = "thinking";
21624
+ streamingProgress = null;
21560
21625
  invalidate();
21561
21626
  },
21562
21627
  endSseTurn() {
@@ -21652,6 +21717,7 @@ var MAX_PENDING_RETAIN_KEYS = 256;
21652
21717
  var EMPTY_STATE = Object.freeze({
21653
21718
  messages: Object.freeze([]),
21654
21719
  streamingPhase: "idle",
21720
+ streamingProgress: null,
21655
21721
  turnMeta: Object.freeze({
21656
21722
  meta: /* @__PURE__ */ new Map(),
21657
21723
  sources: /* @__PURE__ */ new Map(),
@@ -22839,6 +22905,8 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
22839
22905
  stopMessage,
22840
22906
  clearMessages,
22841
22907
  streamingPhase,
22908
+ /** The stage the pending turn reports before its first token, or null. */
22909
+ streamingProgress: state.streamingProgress,
22842
22910
  /** True while the mount-time rebuild from the server transcript runs. */
22843
22911
  isHydratingHistory,
22844
22912
  /** Provider key for the lib's `<ModelDisplay>` icon. */
@@ -24392,6 +24460,7 @@ function useUnifiedChat(options) {
24392
24460
  messages: activeState.messages,
24393
24461
  isLoading: activeState.isLoading,
24394
24462
  streamingPhase: activeState.streamingPhase,
24463
+ streamingProgress: activeState.streamingProgress ?? null,
24395
24464
  sendMessage,
24396
24465
  stopMessage,
24397
24466
  clearMessages,
@@ -26037,6 +26106,7 @@ function EmbeddableChatInner({
26037
26106
  const {
26038
26107
  messages: rawMessages,
26039
26108
  isLoading: chatLoading,
26109
+ streamingProgress,
26040
26110
  sendMessage: sendMessageRaw,
26041
26111
  discussRef,
26042
26112
  stopMessage,
@@ -26412,19 +26482,19 @@ function EmbeddableChatInner({
26412
26482
  );
26413
26483
  const [portalHost, setPortalHost] = useState49(null);
26414
26484
  const [panelBoundary, setPanelBoundary] = useState49(null);
26415
- const [panelWidth, setPanelWidth] = useState49(0);
26485
+ const [canSplit, setCanSplit] = useState49(false);
26416
26486
  useEffect38(() => {
26417
26487
  if (!panelBoundary || typeof ResizeObserver === "undefined") return void 0;
26418
26488
  const ro = new ResizeObserver((entries) => {
26419
26489
  const w = entries[0]?.contentRect?.width;
26420
- if (typeof w === "number") setPanelWidth(w);
26490
+ if (typeof w === "number") setCanSplit(w >= SPLIT_MIN_WIDTH);
26421
26491
  });
26422
26492
  ro.observe(panelBoundary);
26423
26493
  return () => ro.disconnect();
26424
26494
  }, [panelBoundary]);
26425
26495
  const setPanelNode = useCallback28((node) => {
26426
26496
  setPanelBoundary(node);
26427
- if (node) setPanelWidth(node.clientWidth);
26497
+ if (node) setCanSplit(node.clientWidth >= SPLIT_MIN_WIDTH);
26428
26498
  }, []);
26429
26499
  const [railCollapsed, setRailCollapsed] = useState49(false);
26430
26500
  const railStorageHydrated = useIsHydrated();
@@ -26448,7 +26518,6 @@ function EmbeddableChatInner({
26448
26518
  }, []);
26449
26519
  const [railSearchOpen, setRailSearchOpen] = useState49(false);
26450
26520
  const splitEligible = historyListMode;
26451
- const canSplit = panelWidth >= SPLIT_MIN_WIDTH;
26452
26521
  const wideMingo = splitEligible && canSplit && !previewMode;
26453
26522
  const splitActive = wideMingo && !railCollapsed;
26454
26523
  const railPresence = useRailPresence(splitActive);
@@ -26586,7 +26655,7 @@ function EmbeddableChatInner({
26586
26655
  // expand toggle + the chat-block header (the fill column shows
26587
26656
  // the chat / new-chat welcome). No back chevron — chat-list
26588
26657
  // navigation is the rail toggle. Shown whenever the panel is wide
26589
- // enough to split (`panelWidth ≥ SPLIT_MIN_WIDTH`), NOT gated on
26658
+ // enough to split (width ≥ `SPLIT_MIN_WIDTH`), NOT gated on
26590
26659
  // the viewport `md` breakpoint — otherwise a 720–799px panel on a
26591
26660
  // sub-`md` viewport would split the body yet drop to the mobile
26592
26661
  // single-bar header (no rail search / collapse controls).
@@ -26777,6 +26846,7 @@ function EmbeddableChatInner({
26777
26846
  {
26778
26847
  messages,
26779
26848
  isTyping: chatLoading,
26849
+ typingMessage: streamingProgress ? chatProgressLabel(streamingProgress) : void 0,
26780
26850
  pendingApprovals,
26781
26851
  autoScroll: !previewMode,
26782
26852
  pinBottom: previewMode,
@@ -27706,4 +27776,4 @@ export {
27706
27776
  EmbeddableChat,
27707
27777
  ProxyCredentialsPanel
27708
27778
  };
27709
- //# sourceMappingURL=chunk-Y7ZEVTLC.js.map
27779
+ //# sourceMappingURL=chunk-BW6YBATM.js.map