@flamingo-stack/openframe-frontend-core 0.0.458-snapshot.20260720215024 → 0.0.458

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 (281) hide show
  1. package/dist/{chunk-BLZZXZNM.cjs → chunk-5USSSRAL.cjs} +26 -26
  2. package/dist/{chunk-BLZZXZNM.cjs.map → chunk-5USSSRAL.cjs.map} +1 -1
  3. package/dist/{chunk-CGNDAJ7V.js → chunk-6B27O3ZB.js} +4 -4
  4. package/dist/{chunk-P5JQDFRM.cjs → chunk-7IRPMNRL.cjs} +60 -60
  5. package/dist/chunk-7IRPMNRL.cjs.map +1 -0
  6. package/dist/{chunk-4XDWNAZW.cjs → chunk-DQ3EHM6G.cjs} +9 -9
  7. package/dist/{chunk-4XDWNAZW.cjs.map → chunk-DQ3EHM6G.cjs.map} +1 -1
  8. package/dist/{chunk-7KSEINAE.cjs → chunk-FTXDIDNX.cjs} +15 -15
  9. package/dist/{chunk-7KSEINAE.cjs.map → chunk-FTXDIDNX.cjs.map} +1 -1
  10. package/dist/{chunk-4R6H2U77.js → chunk-H7ETLG65.js} +4 -4
  11. package/dist/{chunk-LAOO7XHO.js → chunk-HWTUVLYB.js} +2 -2
  12. package/dist/{chunk-F2NMWV44.js → chunk-IDKDOQZL.js} +2 -2
  13. package/dist/{chunk-BQ7PMWLM.cjs → chunk-KIIOBK7G.cjs} +27 -28
  14. package/dist/chunk-KIIOBK7G.cjs.map +1 -0
  15. package/dist/{chunk-QO2XD3FR.js → chunk-KQGFKG6Y.js} +2 -2
  16. package/dist/{chunk-3N3TMZ62.cjs → chunk-L676XVP4.cjs} +7 -7
  17. package/dist/{chunk-3N3TMZ62.cjs.map → chunk-L676XVP4.cjs.map} +1 -1
  18. package/dist/{chunk-F7F43U7Q.cjs → chunk-LDAOPWXZ.cjs} +11 -11
  19. package/dist/{chunk-F7F43U7Q.cjs.map → chunk-LDAOPWXZ.cjs.map} +1 -1
  20. package/dist/{chunk-ADD3FPDG.cjs → chunk-MKLP2SOZ.cjs} +4886 -7004
  21. package/dist/chunk-MKLP2SOZ.cjs.map +1 -0
  22. package/dist/{chunk-VXJH5TDN.js → chunk-QL7ODLJA.js} +10 -10
  23. package/dist/chunk-QL7ODLJA.js.map +1 -0
  24. package/dist/{chunk-OR5AMXYN.js → chunk-R5QYMUKN.js} +2 -2
  25. package/dist/{chunk-REWRUV3K.js → chunk-TNLFAJPA.js} +9673 -11791
  26. package/dist/chunk-TNLFAJPA.js.map +1 -0
  27. package/dist/{chunk-XF5ROTMQ.js → chunk-U2YDR5DT.js} +2 -2
  28. package/dist/{chunk-PXZ7YQ5V.cjs → chunk-VTQSB6QB.cjs} +5 -5
  29. package/dist/{chunk-PXZ7YQ5V.cjs.map → chunk-VTQSB6QB.cjs.map} +1 -1
  30. package/dist/{chunk-UI7CIUAR.js → chunk-WGJPTFRH.js} +2 -2
  31. package/dist/{chunk-WCE66C2Z.cjs → chunk-XUNJILJT.cjs} +62 -62
  32. package/dist/{chunk-WCE66C2Z.cjs.map → chunk-XUNJILJT.cjs.map} +1 -1
  33. package/dist/{chunk-APF5QBAU.js → chunk-YQBPIUZU.js} +2 -2
  34. package/dist/{chunk-TA7MFVUS.cjs → chunk-YV2YA3QH.cjs} +31 -31
  35. package/dist/{chunk-TA7MFVUS.cjs.map → chunk-YV2YA3QH.cjs.map} +1 -1
  36. package/dist/{chunk-QSGZE6AZ.cjs → chunk-ZDJ4ZUQ4.cjs} +37 -37
  37. package/dist/{chunk-QSGZE6AZ.cjs.map → chunk-ZDJ4ZUQ4.cjs.map} +1 -1
  38. package/dist/{chunk-LJKZIIK4.js → chunk-ZHQQRYMB.js} +5 -6
  39. package/dist/chunk-ZHQQRYMB.js.map +1 -0
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chart.d.ts +1 -1
  43. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  44. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  45. package/dist/components/chat/hooks/index.d.ts +1 -0
  46. package/dist/components/chat/hooks/index.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
  48. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +48 -15
  49. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  50. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +6 -0
  51. package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -0
  52. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +47 -3
  53. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  54. package/dist/components/chat/index.cjs +2 -10
  55. package/dist/components/chat/index.cjs.map +1 -1
  56. package/dist/components/chat/index.d.ts +0 -1
  57. package/dist/components/chat/index.d.ts.map +1 -1
  58. package/dist/components/chat/index.js +13 -21
  59. package/dist/components/chat/types/api.types.d.ts +81 -1
  60. package/dist/components/chat/types/api.types.d.ts.map +1 -1
  61. package/dist/components/chat/types/processing.types.d.ts +90 -2
  62. package/dist/components/chat/types/processing.types.d.ts.map +1 -1
  63. package/dist/components/chat/utils/chunk-parser.d.ts +25 -0
  64. package/dist/components/chat/utils/chunk-parser.d.ts.map +1 -0
  65. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +6 -34
  66. package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
  67. package/dist/components/chat/utils/index.d.ts +3 -2
  68. package/dist/components/chat/utils/index.d.ts.map +1 -1
  69. package/dist/components/chat/utils/process-historical-messages.d.ts +11 -59
  70. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  71. package/dist/components/contact/index.cjs +3 -3
  72. package/dist/components/contact/index.js +2 -2
  73. package/dist/components/docs/index.cjs +5 -5
  74. package/dist/components/docs/index.js +4 -4
  75. package/dist/components/embeds/index.cjs +3 -3
  76. package/dist/components/embeds/index.js +2 -2
  77. package/dist/components/faq/index.cjs +3 -3
  78. package/dist/components/faq/index.js +2 -2
  79. package/dist/components/features/index.cjs +2 -2
  80. package/dist/components/features/index.js +1 -1
  81. package/dist/components/help-center-pages/index.cjs +20 -20
  82. package/dist/components/help-center-pages/index.js +11 -11
  83. package/dist/components/index.cjs +129 -171
  84. package/dist/components/index.cjs.map +1 -1
  85. package/dist/components/index.js +21 -63
  86. package/dist/components/index.js.map +1 -1
  87. package/dist/components/navigation/index.cjs +2 -2
  88. package/dist/components/navigation/index.js +1 -1
  89. package/dist/components/onboarding-guides/index.cjs +5 -5
  90. package/dist/components/onboarding-guides/index.js +4 -4
  91. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  92. package/dist/components/related-content/index.cjs +3 -3
  93. package/dist/components/related-content/index.js +2 -2
  94. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  95. package/dist/components/tickets/index.cjs +5 -5
  96. package/dist/components/tickets/index.js +4 -4
  97. package/dist/components/ui/index.cjs +2 -44
  98. package/dist/components/ui/index.cjs.map +1 -1
  99. package/dist/components/ui/index.d.ts +2 -1
  100. package/dist/components/ui/index.d.ts.map +1 -1
  101. package/dist/components/ui/index.js +13 -55
  102. package/dist/components/ui/rich-markdown-renderer.d.ts +34 -0
  103. package/dist/components/ui/rich-markdown-renderer.d.ts.map +1 -0
  104. package/dist/components/ui/simple-markdown-renderer.d.ts +73 -0
  105. package/dist/components/ui/simple-markdown-renderer.d.ts.map +1 -0
  106. package/dist/index.cjs +2 -60
  107. package/dist/index.cjs.map +1 -1
  108. package/dist/index.js +13 -71
  109. package/dist/utils/index.cjs +40 -169
  110. package/dist/utils/index.cjs.map +1 -1
  111. package/dist/utils/index.d.ts +0 -1
  112. package/dist/utils/index.d.ts.map +1 -1
  113. package/dist/utils/index.js +41 -162
  114. package/dist/utils/index.js.map +1 -1
  115. package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
  116. package/package.json +1 -7
  117. package/src/components/chat/__tests__/chat-message-list.test.tsx +5 -293
  118. package/src/components/chat/chat-message-enhanced.tsx +17 -111
  119. package/src/components/chat/chat-message-list.tsx +113 -367
  120. package/src/components/chat/embeddable-chat.tsx +0 -6
  121. package/src/components/chat/hooks/.index.md +1 -1
  122. package/src/components/chat/hooks/.use-nats-chat-adapter.md +1 -1
  123. package/src/components/chat/hooks/.use-realtime-chunk-processor.md +50 -0
  124. package/src/components/chat/hooks/index.ts +1 -0
  125. package/src/components/chat/hooks/use-chat.ts +0 -8
  126. package/src/components/chat/hooks/use-nats-chat-adapter.ts +822 -243
  127. package/src/components/chat/hooks/use-realtime-chunk-processor.ts +479 -0
  128. package/src/components/chat/hooks/use-sse-chat-adapter.ts +666 -318
  129. package/src/components/chat/index.ts +0 -5
  130. package/src/components/chat/thinking-display.tsx +1 -1
  131. package/src/components/chat/types/.api.types.md +3 -1
  132. package/src/components/chat/types/.processing.types.md +23 -6
  133. package/src/components/chat/types/api.types.ts +73 -6
  134. package/src/components/chat/types/processing.types.ts +52 -11
  135. package/src/components/chat/utils/.chunk-parser.md +51 -0
  136. package/src/components/chat/utils/.index.md +5 -0
  137. package/src/components/chat/utils/chunk-parser.ts +255 -0
  138. package/src/components/chat/utils/extract-incomplete-message-state.ts +5 -63
  139. package/src/components/chat/utils/index.ts +8 -5
  140. package/src/components/chat/utils/process-historical-messages.ts +383 -352
  141. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +4 -22
  142. package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
  143. package/src/components/shared/product-release/release-detail-page.tsx +4 -19
  144. package/src/components/ui/.simple-markdown-renderer.md +40 -0
  145. package/src/components/ui/index.ts +2 -1
  146. package/src/components/ui/release-changelog-section.tsx +1 -1
  147. package/src/components/ui/rich-markdown-renderer.tsx +1223 -0
  148. package/src/components/ui/simple-markdown-renderer.tsx +965 -0
  149. package/src/components/ui/ticket-info-section.tsx +1 -1
  150. package/src/utils/index.ts +0 -1
  151. package/src/utils/markdown-section-extractor.ts +56 -41
  152. package/dist/chat-protocol/decode.d.ts +0 -58
  153. package/dist/chat-protocol/decode.d.ts.map +0 -1
  154. package/dist/chat-protocol/encode.d.ts +0 -44
  155. package/dist/chat-protocol/encode.d.ts.map +0 -1
  156. package/dist/chat-protocol/env-flag.d.ts +0 -35
  157. package/dist/chat-protocol/env-flag.d.ts.map +0 -1
  158. package/dist/chat-protocol/events.d.ts +0 -192
  159. package/dist/chat-protocol/events.d.ts.map +0 -1
  160. package/dist/chat-protocol/frames.d.ts +0 -206
  161. package/dist/chat-protocol/frames.d.ts.map +0 -1
  162. package/dist/chat-protocol/index.cjs +0 -493
  163. package/dist/chat-protocol/index.cjs.map +0 -1
  164. package/dist/chat-protocol/index.d.ts +0 -18
  165. package/dist/chat-protocol/index.d.ts.map +0 -1
  166. package/dist/chat-protocol/index.js +0 -477
  167. package/dist/chat-protocol/index.js.map +0 -1
  168. package/dist/chat-protocol/ip-normalize.d.ts +0 -44
  169. package/dist/chat-protocol/ip-normalize.d.ts.map +0 -1
  170. package/dist/chat-protocol/nats-decoder.d.ts +0 -26
  171. package/dist/chat-protocol/nats-decoder.d.ts.map +0 -1
  172. package/dist/chunk-ADD3FPDG.cjs.map +0 -1
  173. package/dist/chunk-BQ7PMWLM.cjs.map +0 -1
  174. package/dist/chunk-LJKZIIK4.js.map +0 -1
  175. package/dist/chunk-P5JQDFRM.cjs.map +0 -1
  176. package/dist/chunk-REWRUV3K.js.map +0 -1
  177. package/dist/chunk-VXJH5TDN.js.map +0 -1
  178. package/dist/components/chat/stream/chat-dialog-store.d.ts +0 -184
  179. package/dist/components/chat/stream/chat-dialog-store.d.ts.map +0 -1
  180. package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -367
  181. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +0 -1
  182. package/dist/components/chat/stream/delta-batcher.d.ts +0 -51
  183. package/dist/components/chat/stream/delta-batcher.d.ts.map +0 -1
  184. package/dist/components/chat/stream/index.d.ts +0 -17
  185. package/dist/components/chat/stream/index.d.ts.map +0 -1
  186. package/dist/components/chat/stream/message-mutations.d.ts +0 -77
  187. package/dist/components/chat/stream/message-mutations.d.ts.map +0 -1
  188. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +0 -22
  189. package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +0 -1
  190. package/dist/components/ui/markdown/base-components.d.ts +0 -56
  191. package/dist/components/ui/markdown/base-components.d.ts.map +0 -1
  192. package/dist/components/ui/markdown/engine.d.ts +0 -99
  193. package/dist/components/ui/markdown/engine.d.ts.map +0 -1
  194. package/dist/components/ui/markdown/heading-ids.d.ts +0 -65
  195. package/dist/components/ui/markdown/heading-ids.d.ts.map +0 -1
  196. package/dist/components/ui/markdown/index.d.ts +0 -18
  197. package/dist/components/ui/markdown/index.d.ts.map +0 -1
  198. package/dist/components/ui/markdown/mermaid-diagram.d.ts +0 -79
  199. package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +0 -1
  200. package/dist/components/ui/markdown/rich/embed-overrides.d.ts +0 -14
  201. package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +0 -1
  202. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +0 -40
  203. package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +0 -1
  204. package/dist/components/ui/markdown/rich/shortcodes.d.ts +0 -8
  205. package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +0 -1
  206. package/dist/components/ui/markdown/sanitize.d.ts +0 -153
  207. package/dist/components/ui/markdown/sanitize.d.ts.map +0 -1
  208. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +0 -23
  209. package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +0 -1
  210. package/dist/components/ui/markdown/streaming.d.ts +0 -78
  211. package/dist/components/ui/markdown/streaming.d.ts.map +0 -1
  212. package/dist/components/ui/markdown/text-size.d.ts +0 -34
  213. package/dist/components/ui/markdown/text-size.d.ts.map +0 -1
  214. package/dist/utils/markdown-fences.d.ts +0 -42
  215. package/dist/utils/markdown-fences.d.ts.map +0 -1
  216. package/dist/utils/markdown-heading-id.d.ts +0 -85
  217. package/dist/utils/markdown-heading-id.d.ts.map +0 -1
  218. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -307
  219. package/src/chat-protocol/__tests__/chat-protocol.test.ts +0 -515
  220. package/src/chat-protocol/__tests__/env-flag.test.ts +0 -52
  221. package/src/chat-protocol/__tests__/ip-normalize.test.ts +0 -136
  222. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +0 -228
  223. package/src/chat-protocol/decode.ts +0 -277
  224. package/src/chat-protocol/encode.ts +0 -71
  225. package/src/chat-protocol/env-flag.ts +0 -39
  226. package/src/chat-protocol/events.ts +0 -228
  227. package/src/chat-protocol/frames.ts +0 -238
  228. package/src/chat-protocol/index.ts +0 -21
  229. package/src/chat-protocol/ip-normalize.ts +0 -146
  230. package/src/chat-protocol/nats-decoder.ts +0 -252
  231. package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +0 -207
  232. package/src/components/chat/__tests__/chat-pending-turn.test.tsx +0 -209
  233. package/src/components/chat/hooks/__tests__/__snapshots__/persisted-state-v1-golden.test.ts.snap +0 -297
  234. package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
  235. package/src/components/chat/hooks/__tests__/persisted-state-v1-golden.test.ts +0 -272
  236. package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +0 -318
  237. package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +0 -937
  238. package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +0 -756
  239. package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +0 -460
  240. package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +0 -894
  241. package/src/components/chat/stream/__tests__/delta-batcher.test.ts +0 -255
  242. package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +0 -98
  243. package/src/components/chat/stream/chat-dialog-store.ts +0 -536
  244. package/src/components/chat/stream/chat-stream-reducer.ts +0 -1796
  245. package/src/components/chat/stream/delta-batcher.ts +0 -159
  246. package/src/components/chat/stream/index.ts +0 -55
  247. package/src/components/chat/stream/message-mutations.ts +0 -338
  248. package/src/components/chat/stream/use-chat-stream-reducer.ts +0 -126
  249. package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +0 -418
  250. package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +0 -599
  251. package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +0 -317
  252. package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +0 -270
  253. package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +0 -2420
  254. package/src/components/ui/__tests__/markdown-parity.test.tsx +0 -2528
  255. package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +0 -115
  256. package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +0 -95
  257. package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +0 -309
  258. package/src/components/ui/markdown/__tests__/streaming.test.tsx +0 -388
  259. package/src/components/ui/markdown/base-components.tsx +0 -341
  260. package/src/components/ui/markdown/engine.tsx +0 -315
  261. package/src/components/ui/markdown/heading-ids.ts +0 -239
  262. package/src/components/ui/markdown/index.ts +0 -49
  263. package/src/components/ui/markdown/mermaid-diagram.tsx +0 -291
  264. package/src/components/ui/markdown/rich/embed-overrides.tsx +0 -199
  265. package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +0 -184
  266. package/src/components/ui/markdown/rich/shortcodes.ts +0 -170
  267. package/src/components/ui/markdown/sanitize.ts +0 -3499
  268. package/src/components/ui/markdown/simple-markdown-renderer.tsx +0 -28
  269. package/src/components/ui/markdown/streaming.ts +0 -362
  270. package/src/components/ui/markdown/text-size.ts +0 -106
  271. package/src/utils/markdown-fences.ts +0 -127
  272. package/src/utils/markdown-heading-id.ts +0 -348
  273. /package/dist/{chunk-CGNDAJ7V.js.map → chunk-6B27O3ZB.js.map} +0 -0
  274. /package/dist/{chunk-4R6H2U77.js.map → chunk-H7ETLG65.js.map} +0 -0
  275. /package/dist/{chunk-LAOO7XHO.js.map → chunk-HWTUVLYB.js.map} +0 -0
  276. /package/dist/{chunk-F2NMWV44.js.map → chunk-IDKDOQZL.js.map} +0 -0
  277. /package/dist/{chunk-QO2XD3FR.js.map → chunk-KQGFKG6Y.js.map} +0 -0
  278. /package/dist/{chunk-OR5AMXYN.js.map → chunk-R5QYMUKN.js.map} +0 -0
  279. /package/dist/{chunk-XF5ROTMQ.js.map → chunk-U2YDR5DT.js.map} +0 -0
  280. /package/dist/{chunk-UI7CIUAR.js.map → chunk-WGJPTFRH.js.map} +0 -0
  281. /package/dist/{chunk-APF5QBAU.js.map → chunk-YQBPIUZU.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-section-extractor.d.ts","sourceRoot":"","sources":["../../src/utils/markdown-section-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4DAA4D;IAC5D,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAUD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,eAAe,EAAE,CA+CnB"}
1
+ {"version":3,"file":"markdown-section-extractor.d.ts","sourceRoot":"","sources":["../../src/utils/markdown-section-extractor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4DAA4D;IAC5D,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAUD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,eAAe,EAAE,CAoEnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.458-snapshot.20260720215024",
3
+ "version": "0.0.458",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -102,12 +102,6 @@
102
102
  "require": "./dist/platform-domains.cjs",
103
103
  "default": "./dist/platform-domains.js"
104
104
  },
105
- "./chat-protocol": {
106
- "types": "./dist/chat-protocol/index.d.ts",
107
- "import": "./dist/chat-protocol/index.js",
108
- "require": "./dist/chat-protocol/index.cjs",
109
- "default": "./dist/chat-protocol/index.js"
110
- },
111
105
  "./components/ui/file-manager": {
112
106
  "types": "./dist/components/ui/file-manager/index.d.ts",
113
107
  "import": "./dist/components/ui/file-manager/index.js",
@@ -1,4 +1,4 @@
1
- import { act, render } from '@testing-library/react'
1
+ import { render } from '@testing-library/react'
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest'
3
3
  import type { Message } from '../types/message.types'
4
4
 
@@ -26,16 +26,9 @@ vi.mock('use-stick-to-bottom', () => ({
26
26
 
27
27
  // Keep the row renderer trivial — these tests exercise ChatMessageList's
28
28
  // scroll orchestration, not markdown rendering.
29
- // Forwards the ref because the list registers each row element for the
30
- // per-message `scrollAnchor: 'top'` path.
31
- vi.mock('../chat-message-enhanced', async () => {
32
- const { forwardRef } = await import('react')
33
- return {
34
- ChatMessageEnhanced: forwardRef<HTMLDivElement, { content: string }>(({ content }, ref) => (
35
- <div ref={ref}>{content}</div>
36
- )),
37
- }
38
- })
29
+ vi.mock('../chat-message-enhanced', () => ({
30
+ ChatMessageEnhanced: ({ content }: { content: string }) => <div>{content}</div>,
31
+ }))
39
32
 
40
33
  import { ChatMessageList } from '../chat-message-list'
41
34
 
@@ -47,36 +40,7 @@ class ObserverStub {
47
40
  disconnect() {}
48
41
  }
49
42
  vi.stubGlobal('IntersectionObserver', ObserverStub)
50
-
51
- // Recording RO so the bottom-follow tests can drive a resize by hand.
52
- const resizeCallbacks: Array<() => void> = []
53
- class RecordingResizeObserver {
54
- constructor(cb: () => void) {
55
- resizeCallbacks.push(cb)
56
- }
57
- observe() {}
58
- unobserve() {}
59
- disconnect() {}
60
- }
61
- vi.stubGlobal('ResizeObserver', RecordingResizeObserver)
62
- /** Fire every live ResizeObserver callback — same effect as any content
63
- * or scroller-box size change in the real DOM. */
64
- const fireResize = () => {
65
- for (const cb of resizeCallbacks) cb()
66
- }
67
-
68
- /** jsdom has no layout, so every box metric reads 0. The jump-to-bottom
69
- * button is driven off real geometry, so the tests supply it. */
70
- const setGeometry = (geo: { scrollHeight: number; clientHeight: number; scrollTop: number }) => {
71
- const el = scrollRefMock.current
72
- if (!el) throw new Error('scroller not mounted')
73
- for (const [key, value] of Object.entries(geo)) {
74
- Object.defineProperty(el, key, { value, configurable: true, writable: true })
75
- }
76
- }
77
-
78
- // jsdom has no layout, so `scrollIntoView` is undefined.
79
- Element.prototype.scrollIntoView = vi.fn()
43
+ vi.stubGlobal('ResizeObserver', ObserverStub)
80
44
 
81
45
  const msg = (id: string, role: Message['role']): Message => ({
82
46
  id,
@@ -126,255 +90,3 @@ describe('ChatMessageList force-scroll decisions', () => {
126
90
  expect(scrollToBottom).not.toHaveBeenCalled()
127
91
  })
128
92
  })
129
-
130
- // The library's own `isAtBottom` lock is lost silently when the scroller's
131
- // box changes (source chips mounting below it) or when a card settling out
132
- // of its skeleton produces a resize-driven scroll the library reads as a
133
- // user gesture. The list therefore owns the INTENT and re-asserts on every
134
- // geometry change until a real gesture releases it.
135
- describe('ChatMessageList bottom-follow intent', () => {
136
- beforeEach(() => {
137
- scrollToBottom.mockClear()
138
- resizeCallbacks.length = 0
139
- })
140
-
141
- const sendTurn = () => {
142
- const initial = [msg('m1', 'user'), msg('m2', 'assistant')]
143
- const view = render(<ChatMessageList dialogId="d1" messages={initial} />)
144
- // A user send arms the follow intent for the whole turn.
145
- view.rerender(<ChatMessageList dialogId="d1" messages={[...initial, msg('m3', 'user')]} />)
146
- scrollToBottom.mockClear()
147
- return view
148
- }
149
-
150
- it('re-asserts the bottom on geometry changes after the send', () => {
151
- sendTurn()
152
- fireResize()
153
- expect(scrollToBottom).toHaveBeenCalled()
154
- })
155
-
156
- it('keeps re-asserting for late async growth (cards + covers resolving)', () => {
157
- sendTurn()
158
- fireResize()
159
- fireResize()
160
- fireResize()
161
- expect(scrollToBottom).toHaveBeenCalledTimes(3)
162
- })
163
-
164
- it('releases the intent once the user scrolls up', () => {
165
- sendTurn()
166
- scrollRefMock.current?.dispatchEvent(
167
- new WheelEvent('wheel', { deltaY: -120, bubbles: true }),
168
- )
169
- fireResize()
170
- expect(scrollToBottom).not.toHaveBeenCalled()
171
- })
172
-
173
- it('ignores downward wheel (never an escape from the bottom)', () => {
174
- sendTurn()
175
- scrollRefMock.current?.dispatchEvent(
176
- new WheelEvent('wheel', { deltaY: 120, bubbles: true }),
177
- )
178
- fireResize()
179
- expect(scrollToBottom).toHaveBeenCalled()
180
- })
181
-
182
- it('does not follow when autoScroll is off (passive demo hosts)', () => {
183
- const initial = [msg('m1', 'user'), msg('m2', 'assistant')]
184
- const { rerender } = render(
185
- <ChatMessageList dialogId="d1" messages={initial} autoScroll={false} />,
186
- )
187
- rerender(
188
- <ChatMessageList dialogId="d1" messages={[...initial, msg('m3', 'user')]} autoScroll={false} />,
189
- )
190
- scrollToBottom.mockClear()
191
- fireResize()
192
- expect(scrollToBottom).not.toHaveBeenCalled()
193
- })
194
-
195
- it('hides jump-to-bottom while the thread is at the bottom', () => {
196
- const view = sendTurn()
197
- setGeometry({ scrollHeight: 1000, clientHeight: 500, scrollTop: 500 })
198
- act(() => fireResize())
199
- expect(view.queryByLabelText('Scroll to latest message')).toBeNull()
200
- })
201
-
202
- it('shows jump-to-bottom once the thread is away from the bottom', () => {
203
- const view = sendTurn()
204
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 500 })
205
- act(() => fireResize())
206
- expect(view.queryByLabelText('Scroll to latest message')).not.toBeNull()
207
- })
208
-
209
- it('re-arms the intent when the user clicks jump-to-bottom', () => {
210
- const view = sendTurn()
211
- // User scrolls away: intent released, button appears.
212
- scrollRefMock.current?.dispatchEvent(
213
- new WheelEvent('wheel', { deltaY: -120, bubbles: true }),
214
- )
215
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 500 })
216
- act(() => fireResize())
217
- expect(scrollToBottom).not.toHaveBeenCalled()
218
-
219
- const button = view.getByLabelText('Scroll to latest message')
220
- act(() => {
221
- button.click()
222
- })
223
- expect(scrollToBottom).toHaveBeenCalled()
224
-
225
- // …and the click re-armed the lock, so growth follows again.
226
- scrollToBottom.mockClear()
227
- act(() => fireResize())
228
- expect(scrollToBottom).toHaveBeenCalled()
229
- })
230
-
231
- // A drag that ends OUTSIDE the window (button released off-screen, or the
232
- // tab losing focus mid-drag) never delivers `pointerup`, so a naive
233
- // `pointerDown` flag stays true forever. Afterwards the very thing this
234
- // component exists for — a fetch-mode card settling from skeleton to a
235
- // SHORTER height, which clamps scrollTop down — is misread as a scroll-up
236
- // gesture and silently drops the lock.
237
- const dragThenScrollDown = (endEvent: { target: 'window'; type: string }) => {
238
- sendTurn()
239
- // Park away from the bottom so the at-bottom re-arm below can't mask the
240
- // result, and seed `lastScrollTop`.
241
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 4000 })
242
- window.dispatchEvent(new Event('pointerdown'))
243
- act(() => {
244
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
245
- })
246
- // Drag ends where we can't see it.
247
- if (endEvent.target === 'window') window.dispatchEvent(new Event(endEvent.type))
248
- // Resize clamp: content shrank, scrollTop drops. NOT a gesture.
249
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 3800 })
250
- act(() => {
251
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
252
- })
253
- scrollToBottom.mockClear()
254
- act(() => fireResize())
255
- }
256
-
257
- it('keeps the intent when a pointercancel ended the drag (resize clamp is not a gesture)', () => {
258
- dragThenScrollDown({ target: 'window', type: 'pointercancel' })
259
- expect(scrollToBottom).toHaveBeenCalled()
260
- })
261
-
262
- it('keeps the intent when the window lost focus mid-drag', () => {
263
- dragThenScrollDown({ target: 'window', type: 'blur' })
264
- expect(scrollToBottom).toHaveBeenCalled()
265
- })
266
-
267
- // Focus events do not bubble but they DO capture, so a capture-phase `blur`
268
- // listener on `window` fires for EVERY element blur in the document — the
269
- // classic focus-delegation idiom. Registering the drag-end `blur` that way
270
- // made any focus change during a pointer hold (most commonly the chat input
271
- // blurring as the user presses down on the scrollbar) clear `pointerDown`,
272
- // which is exactly what re-opens the yank-back-mid-drag bug. Only a TRUE
273
- // window blur (which targets `window` itself) may end the drag.
274
- it('a descendant element losing focus does not end the drag', () => {
275
- sendTurn()
276
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 4000 })
277
- window.dispatchEvent(new Event('pointerdown'))
278
- act(() => {
279
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
280
- })
281
- // The chat input loses focus as the pointer goes down elsewhere.
282
- const input = document.createElement('input')
283
- document.body.appendChild(input)
284
- input.focus()
285
- input.blur()
286
- input.remove()
287
- // The drag is still live, so this held scroll-up IS a gesture.
288
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 3800 })
289
- act(() => {
290
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
291
- })
292
- scrollToBottom.mockClear()
293
- act(() => fireResize())
294
- expect(scrollToBottom).not.toHaveBeenCalled()
295
- window.dispatchEvent(new Event('pointerup'))
296
- })
297
-
298
- it('still disarms on a genuine scrollbar drag upward', () => {
299
- sendTurn()
300
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 4000 })
301
- window.dispatchEvent(new Event('pointerdown'))
302
- act(() => {
303
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
304
- })
305
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 3800 })
306
- act(() => {
307
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
308
- })
309
- scrollToBottom.mockClear()
310
- act(() => fireResize())
311
- expect(scrollToBottom).not.toHaveBeenCalled()
312
- window.dispatchEvent(new Event('pointerup'))
313
- })
314
-
315
- // Scrolling back down to the live end by hand expresses exactly the intent
316
- // the jump-to-bottom button does — the lock has to re-arm, or the thread
317
- // renders at-bottom (button hidden) and then silently drifts away.
318
- it('re-arms the intent when the user scrolls back to the bottom by hand', () => {
319
- sendTurn()
320
- scrollRefMock.current?.dispatchEvent(new WheelEvent('wheel', { deltaY: -120, bubbles: true }))
321
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 500 })
322
- act(() => fireResize())
323
- expect(scrollToBottom).not.toHaveBeenCalled()
324
-
325
- // …and back down to the end.
326
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 19500 })
327
- act(() => {
328
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
329
- })
330
- scrollToBottom.mockClear()
331
- act(() => fireResize())
332
- expect(scrollToBottom).toHaveBeenCalled()
333
- })
334
-
335
- it('does not re-arm while the user is still parked above the bottom', () => {
336
- sendTurn()
337
- scrollRefMock.current?.dispatchEvent(new WheelEvent('wheel', { deltaY: -120, bubbles: true }))
338
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 8000 })
339
- act(() => {
340
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
341
- })
342
- scrollToBottom.mockClear()
343
- act(() => fireResize())
344
- expect(scrollToBottom).not.toHaveBeenCalled()
345
- })
346
-
347
- // A short scrollbar drag that starts at the live end and stays inside the
348
- // 70px band disarms on the gesture and would immediately re-arm on the very
349
- // same scroll event if the re-arm didn't wait for the drag to END — yanking
350
- // the reader back down mid-drag, a miniature of the bug this block exists
351
- // to prevent.
352
- it('does not re-arm mid-drag when the drag stays inside the bottom band', () => {
353
- sendTurn()
354
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 19500 })
355
- act(() => {
356
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
357
- })
358
- window.dispatchEvent(new Event('pointerdown'))
359
- setGeometry({ scrollHeight: 20000, clientHeight: 500, scrollTop: 19460 })
360
- act(() => {
361
- scrollRefMock.current?.dispatchEvent(new Event('scroll'))
362
- })
363
- scrollToBottom.mockClear()
364
- act(() => fireResize())
365
- expect(scrollToBottom).not.toHaveBeenCalled()
366
- window.dispatchEvent(new Event('pointerup'))
367
- })
368
-
369
- it('releases the intent for a top-anchored turn (it parks at the message top)', () => {
370
- const initial = [msg('m1', 'user'), msg('m2', 'assistant')]
371
- const { rerender } = render(<ChatMessageList dialogId="d1" messages={initial} />)
372
- const sent = [...initial, msg('m3', 'user')]
373
- rerender(<ChatMessageList dialogId="d1" messages={sent} />)
374
- const anchored: Message = { ...msg('m4', 'assistant'), scrollAnchor: 'top' }
375
- rerender(<ChatMessageList dialogId="d1" messages={[...sent, anchored]} />)
376
- scrollToBottom.mockClear()
377
- fireResize()
378
- expect(scrollToBottom).not.toHaveBeenCalled()
379
- })
380
- })
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import React, { forwardRef, memo, useEffect, useMemo, useRef } from "react"
3
+ import React, { forwardRef, memo, useMemo, useRef } from "react"
4
4
  import { cn } from "../../utils/cn"
5
5
  import { isToday } from "../../utils/date-utils"
6
6
  import { formatDate, formatTime } from "../../utils/format-date"
@@ -11,7 +11,7 @@ import { ApprovalBatchMessage } from "./approval-batch-message"
11
11
  import { ErrorMessageDisplay } from "./error-message-display"
12
12
  import { ContextCompactionDisplay } from "./context-compaction-display"
13
13
  import { ThinkingDisplay } from "./thinking-display"
14
- import { SimpleMarkdownRenderer } from "../ui/markdown/simple-markdown-renderer"
14
+ import { SimpleMarkdownRenderer } from "../ui/simple-markdown-renderer"
15
15
  import type { ChatRef } from "./chat-ref.types"
16
16
  import { remarkCardLinks } from "./remark-card-links"
17
17
  import { remarkMentionChips } from "./remark-mention-chips"
@@ -163,9 +163,9 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
163
163
  | { kind: 'text'; text: string }
164
164
  | { kind: 'block'; key: string; node: React.ReactNode }
165
165
  const partsBySegment = new Map<number, SegmentPart[]>()
166
- const usedKeys = new Set<string>()
167
- if (!render) return { inlineByKey, partsBySegment, usedKeys }
166
+ if (!render) return { inlineByKey, partsBySegment }
168
167
  const cache = renderedCardNodeCache.current
168
+ const usedKeys = new Set<string>()
169
169
  // Card keys already emitted as a hoisted block (`b-<key>`). The same
170
170
  // marker can legitimately appear twice in one message (LLM references
171
171
  // the same entity twice); we hoist the FIRST occurrence and skip the
@@ -275,99 +275,20 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
275
275
  partsBySegment.set(segIdx, parts)
276
276
  }
277
277
  })
278
- return { inlineByKey, partsBySegment, usedKeys }
279
- }, [hasMarkerSupport, chatRefs, renderEntityCard, segments])
280
-
281
- // Drop cached nodes for markers no longer present so the cache can't grow
282
- // unbounded as a long message's markers change. Deliberately an EFFECT,
283
- // not part of the memo above: pruning is a mutation, and doing it in the
284
- // render phase is non-idempotent (StrictMode's double-invoke, or a render
285
- // React throws away, would evict nodes the committed tree still uses and
286
- // remount the cards it was built to preserve).
287
- useEffect(() => {
288
- const cache = renderedCardNodeCache.current
289
- const usedKeys = renderingPlan?.usedKeys
290
- if (!usedKeys) return
291
- if (cache.size <= usedKeys.size) return
292
- for (const k of [...cache.keys()]) {
293
- if (!usedKeys.has(k)) cache.delete(k)
278
+ // Drop cached nodes for markers no longer present so the cache can't
279
+ // grow unbounded as a long message's markers change.
280
+ if (cache.size > usedKeys.size) {
281
+ for (const k of cache.keys()) {
282
+ if (!usedKeys.has(k)) cache.delete(k)
283
+ }
294
284
  }
295
- }, [renderingPlan])
296
-
297
- // The plan is read through a REF inside the `<a>` override, not captured
298
- // in the override's closure. `renderingPlan` is rebuilt on every text
299
- // delta (its `segments` dep is a fresh array per delta), so depending on
300
- // it here would give `cardComponentOverrides` a new identity every token
301
- // — which re-creates the markdown engine's `components` memo and defeats
302
- // its per-block `StreamingBlockRenderer` memoization for the WHOLE
303
- // message, on every token. The ref keeps the override identity stable
304
- // while still reading the current plan at call time.
305
- const renderingPlanRef = useRef(renderingPlan)
306
- renderingPlanRef.current = renderingPlan
307
- const chatRefsRef = useRef(chatRefs)
308
- chatRefsRef.current = chatRefs
309
-
310
- // Ref-SET token. The override reads `chatRefsRef` at CALL time, but the
311
- // markdown engine memoizes completed blocks on the override map's
312
- // identity — so on a COMPLETED (no longer streaming) message, a ref that
313
- // resolves late would never be re-read: nothing else about the renderer's
314
- // props changes, the engine's memo bails, and the pill stays stuck on its
315
- // fallback (`refMatch.title`, or the raw cardId) forever. Streaming is
316
- // covered because `card://` blocks are excluded from the block cache; the
317
- // completed path has no other escape.
318
- //
319
- // The token fingerprints VALUES, not just the key set: a later refs frame
320
- // REPLACES the whole map for a send index, and the enrichment case that
321
- // matters most — a `title` going from the raw cardId to the resolved
322
- // document title — keeps the key set IDENTICAL. A key-only token would be
323
- // unchanged, the override map would keep its identity, the engine's
324
- // completed-block memo would bail, and the pill would stay on its fallback
325
- // forever. Every `ChatRef` field is included because the host's
326
- // `renderEntityCard` receives the whole ref and may render any of them.
327
- //
328
- // Still STABLE per text delta (the refs map doesn't change while tokens
329
- // stream), and the cost is one pass over a handful of refs per CHANGED
330
- // `chatRefs` identity — the dep list is unchanged.
331
- //
332
- // Fields are joined by `JSON.stringify`, NOT by a separator character.
333
- // `title`, `preview` and `url` are free-form HOST strings, so any
334
- // delimiter we pick is one the data may also contain: joined with a plain
335
- // space, `title: 'a b'` + empty `url` fingerprints identically to
336
- // `title: 'a'` + `url: 'b'`, silently reintroducing the stale-pill memo
337
- // bail this token exists to fix. (An earlier revision used a literal NUL
338
- // byte as the separator: collision-free in practice, but it made the
339
- // source file itself binary to grep and diff tooling.) `JSON.stringify`
340
- // escapes every field, so no value can forge a boundary.
341
- //
342
- // Caveat worth stating: `JSON.stringify` on `metadata` is key-ORDER
343
- // dependent: two structurally equal objects built in different insertion
344
- // orders fingerprint differently. Acceptable here because every refs map
345
- // arrives from ONE decoder with a fixed field order, and the failure mode
346
- // is a redundant re-render, never a stale pill.
347
- const refsKey = useMemo(
348
- () =>
349
- Object.entries(chatRefs ?? {})
350
- .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
351
- .map(([k, v]) =>
352
- JSON.stringify([
353
- k,
354
- v.type,
355
- v.sourceRepo ?? null,
356
- v.id,
357
- v.title,
358
- v.url ?? null,
359
- v.targetPlatform ?? null,
360
- v.date ?? null,
361
- v.preview ?? null,
362
- v.metadata ?? null,
363
- ]),
364
- )
365
- .join('|'),
366
- [chatRefs],
367
- )
285
+ return { inlineByKey, partsBySegment }
286
+ }, [hasMarkerSupport, chatRefs, renderEntityCard, segments])
368
287
 
369
288
  const cardComponentOverrides = useMemo(() => {
370
289
  if (!hasMarkerSupport && !hasMentionSupport) return undefined
290
+ const refs = chatRefs ?? {}
291
+ const inlineByKey = renderingPlan?.inlineByKey
371
292
  return {
372
293
  // Override `<a>` to detect `card://` URLs emitted by `remarkCardLinks`.
373
294
  // The render result was pre-computed in `renderingPlan` so block-level
@@ -395,7 +316,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
395
316
  const cardType = stripped.slice(0, sepIdx)
396
317
  const cardId = stripped.slice(sepIdx + 1)
397
318
  const key = `${cardType}:${cardId}`
398
- const inline = renderingPlanRef.current?.inlineByKey.get(key)
319
+ const inline = inlineByKey?.get(key)
399
320
  if (inline != null) return inline
400
321
  // Three fallback cases — keep them DISTINCT, never blur them
401
322
  // together. Mixing them up (which the old code did by reaching
@@ -419,7 +340,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
419
340
  // title from an unrelated ref — that hides the bug and
420
341
  // deceives the reader into thinking they're looking at
421
342
  // a real card.
422
- const refMatch: ChatRef | undefined = chatRefsRef.current?.[key]
343
+ const refMatch: ChatRef | undefined = refs[key]
423
344
  if (refMatch) {
424
345
  return <span className="text-ods-text-primary">{refMatch.title}</span>
425
346
  }
@@ -461,13 +382,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
461
382
  )
462
383
  },
463
384
  }
464
- // DEPS ARE DELIBERATELY MINIMAL — every one of them is stable across a
465
- // streaming turn (booleans + host-stable fn/component identities, both
466
- // enforced by this file's `memo` comparator). The rendering plan and the
467
- // refs MAP are read through refs above precisely so they do NOT appear
468
- // here; `refsKey` is the one ref-derived dep, and it only moves when the
469
- // ref set OR any ref VALUE does (see its definition).
470
- }, [hasMarkerSupport, hasMentionSupport, renderMention, NavLinkAnchor, refsKey])
385
+ }, [hasMarkerSupport, hasMentionSupport, renderMention, chatRefs, renderingPlan, NavLinkAnchor])
471
386
 
472
387
  const getAvatarProps = () => {
473
388
  const displayName = name || (isUser ? "User" : assistantType === 'mingo' ? "Mingo" : "Fae")
@@ -578,13 +493,6 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
578
493
  "min-w-0 w-full break-words text-h4",
579
494
  isError ? "text-ods-error" : "text-ods-text-primary",
580
495
  )
581
- // The engine's streaming path (atomic-block memoization +
582
- // fence tail-completion + aria-live) applies ONLY to the
583
- // actively streaming segment: last segment of a message
584
- // that is still typing. On completion `isTyping` flips
585
- // false and the engine does one authoritative
586
- // whole-document parse.
587
- const segmentIsStreaming = index === segments.length - 1 && !!isTyping
588
496
  // No block markers in this segment → single
589
497
  // SimpleMarkdownRenderer call (existing behaviour
590
498
  // preserved for the vast majority of messages).
@@ -596,7 +504,6 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
596
504
  textSize="compact"
597
505
  additionalRemarkPlugins={cardRemarkPlugins}
598
506
  componentOverrides={cardComponentOverrides}
599
- streaming={segmentIsStreaming}
600
507
  />
601
508
  </div>
602
509
  )
@@ -624,7 +531,6 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
624
531
  textSize="compact"
625
532
  additionalRemarkPlugins={cardRemarkPlugins}
626
533
  componentOverrides={cardComponentOverrides}
627
- streaming={segmentIsStreaming && pIdx === parts.length - 1}
628
534
  />
629
535
  )
630
536
  }