@buoy-gg/ask-buoy 7.0.38 → 7.0.40

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 (306) hide show
  1. package/lib/commonjs/blocks/AskBlocks.js +338 -1
  2. package/lib/commonjs/blocks/AskBlocks.js.map +1 -0
  3. package/lib/commonjs/blocks/BlockRenderer.js +262 -1
  4. package/lib/commonjs/blocks/BlockRenderer.js.map +1 -0
  5. package/lib/commonjs/blocks/ChromePrototypes.js +514 -1
  6. package/lib/commonjs/blocks/ChromePrototypes.js.map +1 -0
  7. package/lib/commonjs/blocks/DataBlocks.js +781 -1
  8. package/lib/commonjs/blocks/DataBlocks.js.map +1 -0
  9. package/lib/commonjs/blocks/ExtraBlocks.js +1860 -1
  10. package/lib/commonjs/blocks/ExtraBlocks.js.map +1 -0
  11. package/lib/commonjs/blocks/MediaBlocks.js +156 -1
  12. package/lib/commonjs/blocks/MediaBlocks.js.map +1 -0
  13. package/lib/commonjs/blocks/ReceiptBlocks.js +586 -1
  14. package/lib/commonjs/blocks/ReceiptBlocks.js.map +1 -0
  15. package/lib/commonjs/blocks/blockText.js +60 -1
  16. package/lib/commonjs/blocks/blockText.js.map +1 -0
  17. package/lib/commonjs/blocks/blockText.test.js +53 -1
  18. package/lib/commonjs/blocks/blockText.test.js.map +1 -0
  19. package/lib/commonjs/blocks/context.js +42 -1
  20. package/lib/commonjs/blocks/context.js.map +1 -0
  21. package/lib/commonjs/blocks/icons.js +96 -1
  22. package/lib/commonjs/blocks/icons.js.map +1 -0
  23. package/lib/commonjs/blocks/index.js +95 -1
  24. package/lib/commonjs/blocks/index.js.map +1 -0
  25. package/lib/commonjs/blocks/listRow.test.js +55 -1
  26. package/lib/commonjs/blocks/listRow.test.js.map +1 -0
  27. package/lib/commonjs/blocks/pageState.js +34 -1
  28. package/lib/commonjs/blocks/pageState.js.map +1 -0
  29. package/lib/commonjs/blocks/pageState.test.js +57 -1
  30. package/lib/commonjs/blocks/pageState.test.js.map +1 -0
  31. package/lib/commonjs/blocks/primitives.js +457 -1
  32. package/lib/commonjs/blocks/primitives.js.map +1 -0
  33. package/lib/commonjs/blocks/primitivesIndex.js +62 -1
  34. package/lib/commonjs/blocks/primitivesIndex.js.map +1 -0
  35. package/lib/commonjs/components/ApprovalCard.js +297 -1
  36. package/lib/commonjs/components/ApprovalCard.js.map +1 -0
  37. package/lib/commonjs/components/AskBuoyHeader.js +196 -1
  38. package/lib/commonjs/components/AskBuoyHeader.js.map +1 -0
  39. package/lib/commonjs/components/AskBuoyIcon.js +19 -1
  40. package/lib/commonjs/components/AskBuoyIcon.js.map +1 -0
  41. package/lib/commonjs/components/AskBuoyModal.js +479 -1
  42. package/lib/commonjs/components/AskBuoyModal.js.map +1 -0
  43. package/lib/commonjs/components/AskBuoySettings.js +181 -1
  44. package/lib/commonjs/components/AskBuoySettings.js.map +1 -0
  45. package/lib/commonjs/components/ChangesBar.js +211 -1
  46. package/lib/commonjs/components/ChangesBar.js.map +1 -0
  47. package/lib/commonjs/components/Composer.js +255 -1
  48. package/lib/commonjs/components/Composer.js.map +1 -0
  49. package/lib/commonjs/components/EmptyState.js +161 -1
  50. package/lib/commonjs/components/EmptyState.js.map +1 -0
  51. package/lib/commonjs/components/KeyboardPad.js +80 -1
  52. package/lib/commonjs/components/KeyboardPad.js.map +1 -0
  53. package/lib/commonjs/components/Markdown.js +310 -1
  54. package/lib/commonjs/components/Markdown.js.map +1 -0
  55. package/lib/commonjs/components/MessageList.js +970 -1
  56. package/lib/commonjs/components/MessageList.js.map +1 -0
  57. package/lib/commonjs/components/QueuedMessages.js +145 -1
  58. package/lib/commonjs/components/QueuedMessages.js.map +1 -0
  59. package/lib/commonjs/components/ThinkingStrip.js +223 -1
  60. package/lib/commonjs/components/ThinkingStrip.js.map +1 -0
  61. package/lib/commonjs/components/TypingDots.js +63 -1
  62. package/lib/commonjs/components/TypingDots.js.map +1 -0
  63. package/lib/commonjs/components/markdownParse.js +131 -1
  64. package/lib/commonjs/components/markdownParse.js.map +1 -0
  65. package/lib/commonjs/components/markdownParse.test.js +99 -1
  66. package/lib/commonjs/components/markdownParse.test.js.map +1 -0
  67. package/lib/commonjs/components/useCopyAction.js +50 -1
  68. package/lib/commonjs/components/useCopyAction.js.map +1 -0
  69. package/lib/commonjs/index.js +252 -1
  70. package/lib/commonjs/index.js.map +1 -0
  71. package/lib/commonjs/preset.js +91 -1
  72. package/lib/commonjs/preset.js.map +1 -0
  73. package/lib/commonjs/store/activityGroups.js +110 -1
  74. package/lib/commonjs/store/activityGroups.js.map +1 -0
  75. package/lib/commonjs/store/activityGroups.test.js +78 -1
  76. package/lib/commonjs/store/activityGroups.test.js.map +1 -0
  77. package/lib/commonjs/store/askBuoySettings.js +72 -1
  78. package/lib/commonjs/store/askBuoySettings.js.map +1 -0
  79. package/lib/commonjs/store/askBuoyStore.js +589 -1
  80. package/lib/commonjs/store/askBuoyStore.js.map +1 -0
  81. package/lib/commonjs/store/blockPlacement.js +64 -1
  82. package/lib/commonjs/store/blockPlacement.js.map +1 -0
  83. package/lib/commonjs/store/blockPlacement.test.js +123 -1
  84. package/lib/commonjs/store/blockPlacement.test.js.map +1 -0
  85. package/lib/commonjs/store/queue.test.js +150 -1
  86. package/lib/commonjs/store/queue.test.js.map +1 -0
  87. package/lib/commonjs/store/resetConversation.js +77 -1
  88. package/lib/commonjs/store/resetConversation.js.map +1 -0
  89. package/lib/commonjs/store/restorePending.test.js +63 -1
  90. package/lib/commonjs/store/restorePending.test.js.map +1 -0
  91. package/lib/commonjs/store/restoredIds.test.js +47 -1
  92. package/lib/commonjs/store/restoredIds.test.js.map +1 -0
  93. package/lib/commonjs/store/suggestions.js +54 -1
  94. package/lib/commonjs/store/suggestions.js.map +1 -0
  95. package/lib/commonjs/store/suggestions.test.js +58 -1
  96. package/lib/commonjs/store/suggestions.test.js.map +1 -0
  97. package/lib/commonjs/store/systemLine.test.js +77 -1
  98. package/lib/commonjs/store/systemLine.test.js.map +1 -0
  99. package/lib/commonjs/store/ticketPrompt.js +17 -1
  100. package/lib/commonjs/store/ticketPrompt.js.map +1 -0
  101. package/lib/commonjs/store/traceText.js +81 -1
  102. package/lib/commonjs/store/traceText.js.map +1 -0
  103. package/lib/commonjs/store/traceText.test.js +112 -1
  104. package/lib/commonjs/store/traceText.test.js.map +1 -0
  105. package/lib/commonjs/store/transcriptPersistence.js +297 -1
  106. package/lib/commonjs/store/transcriptPersistence.js.map +1 -0
  107. package/lib/commonjs/store/transcriptPersistence.test.js +333 -1
  108. package/lib/commonjs/store/transcriptPersistence.test.js.map +1 -0
  109. package/lib/commonjs/store/turnRendering.test.js +151 -1
  110. package/lib/commonjs/store/turnRendering.test.js.map +1 -0
  111. package/lib/commonjs/store/useAskBuoy.js +651 -1
  112. package/lib/commonjs/store/useAskBuoy.js.map +1 -0
  113. package/lib/commonjs/store/useAskBuoySettings.js +14 -1
  114. package/lib/commonjs/store/useAskBuoySettings.js.map +1 -0
  115. package/lib/commonjs/sync/askBuoySyncAdapter.js +153 -1
  116. package/lib/commonjs/sync/askBuoySyncAdapter.js.map +1 -0
  117. package/lib/commonjs/sync/askBuoySyncAdapter.test.js +141 -1
  118. package/lib/commonjs/sync/askBuoySyncAdapter.test.js.map +1 -0
  119. package/lib/commonjs/sync/wire.js +58 -1
  120. package/lib/commonjs/sync/wire.js.map +1 -0
  121. package/lib/commonjs/types.js +6 -1
  122. package/lib/commonjs/types.js.map +1 -0
  123. package/lib/module/blocks/AskBlocks.js +331 -1
  124. package/lib/module/blocks/AskBlocks.js.map +1 -0
  125. package/lib/module/blocks/BlockRenderer.js +257 -1
  126. package/lib/module/blocks/BlockRenderer.js.map +1 -0
  127. package/lib/module/blocks/ChromePrototypes.js +503 -1
  128. package/lib/module/blocks/ChromePrototypes.js.map +1 -0
  129. package/lib/module/blocks/DataBlocks.js +767 -1
  130. package/lib/module/blocks/DataBlocks.js.map +1 -0
  131. package/lib/module/blocks/ExtraBlocks.js +1833 -1
  132. package/lib/module/blocks/ExtraBlocks.js.map +1 -0
  133. package/lib/module/blocks/MediaBlocks.js +151 -1
  134. package/lib/module/blocks/MediaBlocks.js.map +1 -0
  135. package/lib/module/blocks/ReceiptBlocks.js +574 -1
  136. package/lib/module/blocks/ReceiptBlocks.js.map +1 -0
  137. package/lib/module/blocks/blockText.js +55 -1
  138. package/lib/module/blocks/blockText.js.map +1 -0
  139. package/lib/module/blocks/blockText.test.js +53 -1
  140. package/lib/module/blocks/blockText.test.js.map +1 -0
  141. package/lib/module/blocks/context.js +35 -1
  142. package/lib/module/blocks/context.js.map +1 -0
  143. package/lib/module/blocks/icons.js +91 -1
  144. package/lib/module/blocks/icons.js.map +1 -0
  145. package/lib/module/blocks/index.js +8 -1
  146. package/lib/module/blocks/index.js.map +1 -0
  147. package/lib/module/blocks/listRow.test.js +56 -1
  148. package/lib/module/blocks/listRow.test.js.map +1 -0
  149. package/lib/module/blocks/pageState.js +30 -1
  150. package/lib/module/blocks/pageState.js.map +1 -0
  151. package/lib/module/blocks/pageState.test.js +56 -1
  152. package/lib/module/blocks/pageState.test.js.map +1 -0
  153. package/lib/module/blocks/primitives.js +445 -1
  154. package/lib/module/blocks/primitives.js.map +1 -0
  155. package/lib/module/blocks/primitivesIndex.js +5 -1
  156. package/lib/module/blocks/primitivesIndex.js.map +1 -0
  157. package/lib/module/components/ApprovalCard.js +292 -1
  158. package/lib/module/components/ApprovalCard.js.map +1 -0
  159. package/lib/module/components/AskBuoyHeader.js +193 -1
  160. package/lib/module/components/AskBuoyHeader.js.map +1 -0
  161. package/lib/module/components/AskBuoyIcon.js +8 -1
  162. package/lib/module/components/AskBuoyIcon.js.map +1 -0
  163. package/lib/module/components/AskBuoyModal.js +474 -1
  164. package/lib/module/components/AskBuoyModal.js.map +1 -0
  165. package/lib/module/components/AskBuoySettings.js +176 -1
  166. package/lib/module/components/AskBuoySettings.js.map +1 -0
  167. package/lib/module/components/ChangesBar.js +206 -1
  168. package/lib/module/components/ChangesBar.js.map +1 -0
  169. package/lib/module/components/Composer.js +250 -1
  170. package/lib/module/components/Composer.js.map +1 -0
  171. package/lib/module/components/EmptyState.js +156 -1
  172. package/lib/module/components/EmptyState.js.map +1 -0
  173. package/lib/module/components/KeyboardPad.js +75 -1
  174. package/lib/module/components/KeyboardPad.js.map +1 -0
  175. package/lib/module/components/Markdown.js +305 -1
  176. package/lib/module/components/Markdown.js.map +1 -0
  177. package/lib/module/components/MessageList.js +964 -1
  178. package/lib/module/components/MessageList.js.map +1 -0
  179. package/lib/module/components/QueuedMessages.js +140 -1
  180. package/lib/module/components/QueuedMessages.js.map +1 -0
  181. package/lib/module/components/ThinkingStrip.js +218 -1
  182. package/lib/module/components/ThinkingStrip.js.map +1 -0
  183. package/lib/module/components/TypingDots.js +58 -1
  184. package/lib/module/components/TypingDots.js.map +1 -0
  185. package/lib/module/components/markdownParse.js +125 -1
  186. package/lib/module/components/markdownParse.js.map +1 -0
  187. package/lib/module/components/markdownParse.test.js +98 -1
  188. package/lib/module/components/markdownParse.test.js.map +1 -0
  189. package/lib/module/components/useCopyAction.js +46 -1
  190. package/lib/module/components/useCopyAction.js.map +1 -0
  191. package/lib/module/index.js +34 -1
  192. package/lib/module/index.js.map +1 -0
  193. package/lib/module/preset.js +74 -1
  194. package/lib/module/preset.js.map +1 -0
  195. package/lib/module/store/activityGroups.js +103 -1
  196. package/lib/module/store/activityGroups.js.map +1 -0
  197. package/lib/module/store/activityGroups.test.js +77 -1
  198. package/lib/module/store/activityGroups.test.js.map +1 -0
  199. package/lib/module/store/askBuoySettings.js +67 -1
  200. package/lib/module/store/askBuoySettings.js.map +1 -0
  201. package/lib/module/store/askBuoyStore.js +583 -1
  202. package/lib/module/store/askBuoyStore.js.map +1 -0
  203. package/lib/module/store/blockPlacement.js +59 -1
  204. package/lib/module/store/blockPlacement.js.map +1 -0
  205. package/lib/module/store/blockPlacement.test.js +122 -1
  206. package/lib/module/store/blockPlacement.test.js.map +1 -0
  207. package/lib/module/store/queue.test.js +149 -1
  208. package/lib/module/store/queue.test.js.map +1 -0
  209. package/lib/module/store/resetConversation.js +72 -1
  210. package/lib/module/store/resetConversation.js.map +1 -0
  211. package/lib/module/store/restorePending.test.js +62 -1
  212. package/lib/module/store/restorePending.test.js.map +1 -0
  213. package/lib/module/store/restoredIds.test.js +46 -1
  214. package/lib/module/store/restoredIds.test.js.map +1 -0
  215. package/lib/module/store/suggestions.js +49 -1
  216. package/lib/module/store/suggestions.js.map +1 -0
  217. package/lib/module/store/suggestions.test.js +57 -1
  218. package/lib/module/store/suggestions.test.js.map +1 -0
  219. package/lib/module/store/systemLine.test.js +76 -1
  220. package/lib/module/store/systemLine.test.js.map +1 -0
  221. package/lib/module/store/ticketPrompt.js +13 -1
  222. package/lib/module/store/ticketPrompt.js.map +1 -0
  223. package/lib/module/store/traceText.js +75 -1
  224. package/lib/module/store/traceText.js.map +1 -0
  225. package/lib/module/store/traceText.test.js +111 -1
  226. package/lib/module/store/traceText.test.js.map +1 -0
  227. package/lib/module/store/transcriptPersistence.js +287 -1
  228. package/lib/module/store/transcriptPersistence.js.map +1 -0
  229. package/lib/module/store/transcriptPersistence.test.js +332 -1
  230. package/lib/module/store/transcriptPersistence.test.js.map +1 -0
  231. package/lib/module/store/turnRendering.test.js +150 -1
  232. package/lib/module/store/turnRendering.test.js.map +1 -0
  233. package/lib/module/store/useAskBuoy.js +646 -1
  234. package/lib/module/store/useAskBuoy.js.map +1 -0
  235. package/lib/module/store/useAskBuoySettings.js +9 -1
  236. package/lib/module/store/useAskBuoySettings.js.map +1 -0
  237. package/lib/module/sync/askBuoySyncAdapter.js +148 -1
  238. package/lib/module/sync/askBuoySyncAdapter.js.map +1 -0
  239. package/lib/module/sync/askBuoySyncAdapter.test.js +140 -1
  240. package/lib/module/sync/askBuoySyncAdapter.test.js.map +1 -0
  241. package/lib/module/sync/wire.js +47 -1
  242. package/lib/module/sync/wire.js.map +1 -0
  243. package/lib/module/types.js +4 -1
  244. package/lib/module/types.js.map +1 -0
  245. package/lib/typescript/blocks/AskBlocks.d.ts.map +1 -0
  246. package/lib/typescript/blocks/BlockRenderer.d.ts.map +1 -0
  247. package/lib/typescript/blocks/ChromePrototypes.d.ts.map +1 -0
  248. package/lib/typescript/blocks/DataBlocks.d.ts.map +1 -0
  249. package/lib/typescript/blocks/ExtraBlocks.d.ts.map +1 -0
  250. package/lib/typescript/blocks/MediaBlocks.d.ts.map +1 -0
  251. package/lib/typescript/blocks/ReceiptBlocks.d.ts.map +1 -0
  252. package/lib/typescript/blocks/blockText.d.ts.map +1 -0
  253. package/lib/typescript/blocks/blockText.test.d.ts.map +1 -0
  254. package/lib/typescript/blocks/context.d.ts.map +1 -0
  255. package/lib/typescript/blocks/icons.d.ts.map +1 -0
  256. package/lib/typescript/blocks/index.d.ts.map +1 -0
  257. package/lib/typescript/blocks/listRow.test.d.ts.map +1 -0
  258. package/lib/typescript/blocks/pageState.d.ts.map +1 -0
  259. package/lib/typescript/blocks/pageState.test.d.ts.map +1 -0
  260. package/lib/typescript/blocks/primitives.d.ts.map +1 -0
  261. package/lib/typescript/blocks/primitivesIndex.d.ts.map +1 -0
  262. package/lib/typescript/components/ApprovalCard.d.ts.map +1 -0
  263. package/lib/typescript/components/AskBuoyHeader.d.ts.map +1 -0
  264. package/lib/typescript/components/AskBuoyIcon.d.ts.map +1 -0
  265. package/lib/typescript/components/AskBuoyModal.d.ts.map +1 -0
  266. package/lib/typescript/components/AskBuoySettings.d.ts.map +1 -0
  267. package/lib/typescript/components/ChangesBar.d.ts.map +1 -0
  268. package/lib/typescript/components/Composer.d.ts.map +1 -0
  269. package/lib/typescript/components/EmptyState.d.ts.map +1 -0
  270. package/lib/typescript/components/KeyboardPad.d.ts.map +1 -0
  271. package/lib/typescript/components/Markdown.d.ts.map +1 -0
  272. package/lib/typescript/components/MessageList.d.ts.map +1 -0
  273. package/lib/typescript/components/QueuedMessages.d.ts.map +1 -0
  274. package/lib/typescript/components/ThinkingStrip.d.ts.map +1 -0
  275. package/lib/typescript/components/TypingDots.d.ts.map +1 -0
  276. package/lib/typescript/components/markdownParse.d.ts.map +1 -0
  277. package/lib/typescript/components/markdownParse.test.d.ts.map +1 -0
  278. package/lib/typescript/components/useCopyAction.d.ts.map +1 -0
  279. package/lib/typescript/index.d.ts.map +1 -0
  280. package/lib/typescript/preset.d.ts.map +1 -0
  281. package/lib/typescript/store/activityGroups.d.ts.map +1 -0
  282. package/lib/typescript/store/activityGroups.test.d.ts.map +1 -0
  283. package/lib/typescript/store/askBuoySettings.d.ts.map +1 -0
  284. package/lib/typescript/store/askBuoyStore.d.ts.map +1 -0
  285. package/lib/typescript/store/blockPlacement.d.ts.map +1 -0
  286. package/lib/typescript/store/blockPlacement.test.d.ts.map +1 -0
  287. package/lib/typescript/store/queue.test.d.ts.map +1 -0
  288. package/lib/typescript/store/resetConversation.d.ts.map +1 -0
  289. package/lib/typescript/store/restorePending.test.d.ts.map +1 -0
  290. package/lib/typescript/store/restoredIds.test.d.ts.map +1 -0
  291. package/lib/typescript/store/suggestions.d.ts.map +1 -0
  292. package/lib/typescript/store/suggestions.test.d.ts.map +1 -0
  293. package/lib/typescript/store/systemLine.test.d.ts.map +1 -0
  294. package/lib/typescript/store/ticketPrompt.d.ts.map +1 -0
  295. package/lib/typescript/store/traceText.d.ts.map +1 -0
  296. package/lib/typescript/store/traceText.test.d.ts.map +1 -0
  297. package/lib/typescript/store/transcriptPersistence.d.ts.map +1 -0
  298. package/lib/typescript/store/transcriptPersistence.test.d.ts.map +1 -0
  299. package/lib/typescript/store/turnRendering.test.d.ts.map +1 -0
  300. package/lib/typescript/store/useAskBuoy.d.ts.map +1 -0
  301. package/lib/typescript/store/useAskBuoySettings.d.ts.map +1 -0
  302. package/lib/typescript/sync/askBuoySyncAdapter.d.ts.map +1 -0
  303. package/lib/typescript/sync/askBuoySyncAdapter.test.d.ts.map +1 -0
  304. package/lib/typescript/sync/wire.d.ts.map +1 -0
  305. package/lib/typescript/types.d.ts.map +1 -0
  306. package/package.json +8 -8
@@ -1 +1,970 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.MessageList=MessageList,exports.transcriptToText=transcriptToText;var _react=require("react"),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_agentCore=require("@buoy-gg/agent-core"),_BlockRenderer=require("../blocks/BlockRenderer"),_blockText=require("../blocks/blockText"),_activityGroups=require("../store/activityGroups"),_blockPlacement=require("../store/blockPlacement"),_askBuoyStore=require("../store/askBuoyStore"),_Markdown=require("./Markdown"),_ThinkingStrip=require("./ThinkingStrip"),_TypingDots=require("./TypingDots"),_useCopyAction=require("./useCopyAction"),_traceText=require("../store/traceText"),_useAskBuoySettings=require("../store/useAskBuoySettings"),_jsxRuntime=require("react/jsx-runtime");function StatusMark({status:e}){switch(e){case"running":return(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_sharedUi.night.color.textSecondary});case"ok":return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.mark,styles.markOk],children:(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:10,color:_sharedUi.night.color.onAccent})});case"failed":return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.mark,styles.markFailed],children:(0,_jsxRuntime.jsx)(_sharedUi.X,{size:10,color:_sharedUi.night.color.text})});case"refused":return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.mark,styles.markRefused],children:(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:10,color:_sharedUi.night.color.onAccent})});case"declined":case"stopped":return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.mark,styles.markNotRun],children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.markNotRunBar})})}}function statusText(e){return"running"===e.status?{text:"",tone:"muted"}:"refused"===e.status?{text:"Refused",tone:"warning"}:"failed"===e.status?{text:"Failed",tone:"danger"}:"declined"===e.status?{text:"You declined",tone:"muted"}:"stopped"===e.status?{text:"Not run — stopped",tone:"muted"}:"verified"===e.verification?.status?{text:"Verified",tone:"ok"}:"unverified"===e.verification?.status?{text:"Done · not yet visible",tone:"muted"}:"failed"===e.verification?.status?{text:"Done · check failed",tone:"warning"}:{text:e.summary||"Done",tone:"muted"}}const isExceptional=e=>"failed"===e.status||"refused"===e.status||"declined"===e.status||"stopped"===e.status;function ActivityRow({call:e,receipts:t,last:s}){const[r,i]=(0,_react.useState)(!1),o=statusText(e),n=r?_sharedUi.ChevronDown:_sharedUi.ChevronRight,a="failed"===e.status&&e.summary&&"Failed"!==e.summary?e.summary:null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.row,!s&&styles.rowDivider],children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-ask-buoy-tool-${e.toolId}`,accessibilityRole:"button",accessibilityLabel:`${e.label}, ${o.text||"running"}`,accessibilityState:{expanded:r},onPress:()=>i(e=>!e),children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowLine,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.markSlot,children:(0,_jsxRuntime.jsx)(StatusMark,{status:e.status})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e.label}),o.text?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.rowStatus,"danger"===o.tone&&styles.rowStatusDanger,"warning"===o.tone&&styles.rowStatusWarning,"ok"===o.tone&&styles.rowStatusOk],numberOfLines:1,children:o.text}):null,(0,_jsxRuntime.jsx)(n,{size:12,color:_sharedUi.night.color.textTertiary})]}),r&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowDetail,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTool,children:(0,_agentCore.toolTitle)(e.toolId).toUpperCase()}),e.description?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowDescription,children:e.description}):null,a?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowFailure,children:a}):null,e.verification?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.rowDescription,"failed"===e.verification.status&&styles.rowFailure,"verified"===e.verification.status&&styles.rowVerified],testID:`buoy-ask-buoy-verification-${e.verification.status}`,children:e.verification.detail}):null]})]}),r&&t.length>0&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowReceipts,testID:`buoy-ask-buoy-tool-receipt-${e.toolId}`,children:t.map(e=>(0,_jsxRuntime.jsx)(_BlockRenderer.BlockRenderer,{block:e},e.id))})]})}function ReadsGroup({label:e,count:t,calls:s,receipts:r,last:i}){const[o,n]=(0,_react.useState)(!1),a=o?_sharedUi.ChevronDown:_sharedUi.ChevronRight;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:!i&&!o&&styles.rowDivider,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-reads-group",accessibilityRole:"button",accessibilityLabel:`${e}, ${t} reads`,accessibilityState:{expanded:o},onPress:()=>n(e=>!e),style:[styles.row,o&&styles.rowDivider],children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowLine,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.markSlot,children:(0,_jsxRuntime.jsx)(StatusMark,{status:"ok"})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowTitle,children:e}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.rowStatus,numberOfLines:1,children:[t," reads"]}),(0,_jsxRuntime.jsx)(a,{size:12,color:_sharedUi.night.color.textTertiary})]})}),o&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.groupBody,children:s.map((e,t)=>(0,_jsxRuntime.jsx)(ActivityRow,{call:e,receipts:r.get(e.id)??[],last:i&&t===s.length-1},e.id))})]})}function ActivityCard({calls:e,receipts:t}){const s=(0,_activityGroups.groupCalls)(e);return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.card,testID:"buoy-ask-buoy-activity",children:s.map((e,r)=>"reads"===e.kind?(0,_jsxRuntime.jsx)(ReadsGroup,{label:e.label,count:e.count,calls:e.calls,receipts:t,last:r===s.length-1},e.id):(0,_jsxRuntime.jsx)(ActivityRow,{call:e.call,receipts:t.get(e.call.id)??[],last:r===s.length-1},e.call.id))})}function Blocks({blocks:e}){return 0===e.length?null:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.blocks,children:e.map(({block:e})=>(0,_jsxRuntime.jsx)(_BlockRenderer.BlockRenderer,{block:e},e.id))})}function SystemLine({message:e}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.systemLine,testID:"buoy-ask-buoy-system-line",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.systemText,children:e.text})})}function UserMessage({message:e}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.userWrap,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.userBubble,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.userText,selectable:!0,children:e.text})})})}function AssistantMessage({message:e,onRetry:t,waitingOnUser:s}){const{showThinking:r}=(0,_useAskBuoySettings.useAskBuoySettings)(),i=!!e.streaming&&!s,{nested:o,afterText:n,ask:a}=(0,_blockPlacement.placeBlocks)(e.blocks,e.toolCalls.map(e=>e.id));return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.assistantWrap,children:[e.toolCalls.length>0&&(0,_jsxRuntime.jsx)(ActivityCard,{calls:e.toolCalls,receipts:o}),e.text.length>0&&(0,_jsxRuntime.jsx)(_Markdown.Markdown,{text:e.text,style:styles.assistantText}),(0,_jsxRuntime.jsx)(Blocks,{blocks:n}),(0,_jsxRuntime.jsx)(Blocks,{blocks:a}),r&&!e.streaming&&(0,_jsxRuntime.jsx)(_ThinkingStrip.ThinkingStrip,{message:e}),i&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.waitingRow,children:[(0,_jsxRuntime.jsx)(_TypingDots.TypingDots,{}),e.waiting?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.waitingText,testID:"buoy-ask-buoy-waiting",children:e.waiting}):null]}),e.error&&(0,_jsxRuntime.jsx)(ErrorNote,{error:e.error,onRetry:t}),e.stopped&&!e.error&&(0,_jsxRuntime.jsx)(StoppedNote,{onRetry:t,changed:e.toolCalls.some(e=>"ok"===e.status&&!!e.effect&&"read"!==e.effect)})]})}function StoppedNote({onRetry:e,changed:t}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stoppedBox,testID:"buoy-ask-buoy-stopped",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stoppedText,children:t?"Stopped. Changes already made are listed above.":"Stopped."}),e&&(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-retry",accessibilityRole:"button",accessibilityLabel:"Try again",onPress:e,style:({pressed:e})=>[styles.retry,e&&styles.retryPressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.retryText,children:"Try again"})})]})}function ErrorNote({error:e,onRetry:t}){const s=/fetch failed|network|ECONN|timed? ?out|socket/i.test(e)?"Couldn't reach your AI endpoint. Check the connection and try again.":"Something went wrong with that turn.";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.errorBox,testID:"buoy-ask-buoy-error",children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:14,color:_sharedUi.night.color.danger}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.errorBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.errorText,children:s}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.errorDetail,selectable:!0,children:e}),t&&(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-retry",accessibilityRole:"button",accessibilityLabel:"Try again",onPress:t,style:({pressed:e})=>[styles.retry,e&&styles.retryPressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.retryText,children:"Try again"})})]})]})}function transcriptToText(e,t=!1){const s=[];for(const r of e)if("user"!==r.role)if(r.system)s.push(` — ${r.text}`);else{if(t)s.push(...(0,_traceText.traceToText)(r));else for(const e of r.toolCalls){const t=isExceptional(e)?` (${e.status})`:"";s.push(` · ${e.label}${e.summary?` — ${e.summary}`:""}${t}`)}r.text&&s.push(`Ask Buoy: ${r.text}`);for(const e of(0,_blockText.blocksToText)(r.blocks.map(e=>e.block)))s.push(e);r.error&&s.push(` ! ${r.error}`),r.stopped&&!r.error&&s.push(" ! Stopped by the user.")}else s.push(`You: ${r.text}`);return s.join("\n")}function CopyPill({testID:e,label:t,getText:s}){const{copied:r,copy:i}=(0,_useCopyAction.useCopyAction)(s);return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:e,accessibilityRole:"button",accessibilityLabel:t,onPress:i,style:({pressed:e})=>[styles.copyBtn,styles.iconBtn,e&&styles.copyPressed],children:[r?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:11,color:_sharedUi.night.color.accent}):(0,_jsxRuntime.jsx)(_sharedUi.Copy,{size:11,color:_sharedUi.night.color.textSecondary}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.copyText,r&&styles.copiedText],children:r?"Copied":t})]})}function TranscriptActions({message:e}){const{showThinking:t}=(0,_useAskBuoySettings.useAskBuoySettings)(),s=(0,_react.useCallback)(()=>transcriptToText(_askBuoyStore.askBuoyStore.getState().messages,t),[t]),r=(0,_activityGroups.turnFooter)(e);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.transcriptActions,children:[r?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.turnFooter,testID:"buoy-ask-buoy-turn-footer",children:r}):null,(0,_jsxRuntime.jsx)(CopyPill,{testID:"buoy-ask-buoy-copy",label:"Copy conversation",getText:s})]})}const Row=(0,_react.memo)(function({message:e,onRetry:t,waitingOnUser:s}){if("user"===e.role)return(0,_jsxRuntime.jsx)(UserMessage,{message:e});if(e.system)return(0,_jsxRuntime.jsx)(SystemLine,{message:e});const r=!e.streaming&&!e.error;return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(AssistantMessage,{message:e,onRetry:t,waitingOnUser:s}),r&&(0,_jsxRuntime.jsx)(TranscriptActions,{message:e})]})});function MessageList({messages:e,ListHeaderComponent:t,ListEmptyComponent:s,ListFooterComponent:r,onRetry:i,waitingOnUser:o}){const n=(0,_react.useRef)(null),a=(0,_react.useRef)(!0),l=(0,_react.useRef)(!1),c=(0,_react.useCallback)(e=>{const{contentOffset:t,contentSize:s,layoutMeasurement:r}=e.nativeEvent,i=s.height-r.height-t.y;a.current=i<80},[]),d=(0,_react.useCallback)(()=>{l.current=!0},[]),u=(0,_react.useCallback)(e=>{l.current&&c(e)},[c]),h=(0,_react.useCallback)(e=>{l.current=!1,c(e)},[c]),x=(0,_react.useCallback)(()=>{a.current&&(n.current?.scrollToEnd({animated:!1}),requestAnimationFrame(()=>n.current?.scrollToEnd({animated:!1})))},[]),y=e[e.length-1],g=y?`${y.id}:${y.text.length}:${y.toolCalls.length}:${y.error??""}`:"";return(0,_react.useEffect)(()=>{x()},[g,x]),(0,_jsxRuntime.jsx)(_reactNative.FlatList,{ref:n,testID:"buoy-ask-buoy-messages-scroll",style:styles.list,contentContainerStyle:styles.listContent,data:e,keyExtractor:e=>e.id,renderItem:({item:e})=>(0,_jsxRuntime.jsx)(Row,{message:e,onRetry:e.id===y?.id?i:void 0,waitingOnUser:e.id===y?.id&&o}),onScroll:u,onScrollBeginDrag:d,onScrollEndDrag:h,onMomentumScrollEnd:c,scrollEventThrottle:32,onContentSizeChange:x,keyboardShouldPersistTaps:"handled",keyboardDismissMode:"interactive",ListHeaderComponent:t,ListEmptyComponent:s,ListFooterComponent:r})}const styles=_reactNative.StyleSheet.create({list:{flex:1,backgroundColor:"transparent"},listContent:{paddingHorizontal:_sharedUi.night.gutter,paddingTop:12,paddingBottom:16,gap:16,flexGrow:1},userWrap:{alignItems:"flex-end"},userBubble:{maxWidth:"84%",paddingHorizontal:14,paddingVertical:9,borderRadius:18,borderBottomRightRadius:6,backgroundColor:_sharedUi.night.color.accentFill,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.accentBorder},userText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,lineHeight:21},systemLine:{alignSelf:"stretch",paddingHorizontal:12,paddingVertical:7,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.fill},systemText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.micro,lineHeight:16,textAlign:"center"},assistantWrap:{alignItems:"stretch",gap:10},blocks:{gap:10},waitingRow:{flexDirection:"row",alignItems:"center",gap:8},waitingText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},assistantText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,lineHeight:22,paddingHorizontal:2},card:{borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},row:{paddingHorizontal:12,paddingVertical:10},rowDivider:{borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.separator},rowLine:{flexDirection:"row",alignItems:"center",gap:10},markSlot:{width:18,height:18,alignItems:"center",justifyContent:"center"},mark:{width:16,height:16,borderRadius:8,alignItems:"center",justifyContent:"center"},markOk:{backgroundColor:_sharedUi.night.color.accent},markFailed:{backgroundColor:_sharedUi.night.color.danger},markRefused:{backgroundColor:_sharedUi.night.color.warning},markNotRun:{borderWidth:1.5,borderColor:_sharedUi.night.color.textTertiary},markNotRunBar:{width:7,height:1.5,borderRadius:1,backgroundColor:_sharedUi.night.color.textSecondary},rowTitle:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,lineHeight:19},rowStatus:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,maxWidth:120},rowStatusDanger:{color:_sharedUi.night.color.danger},rowStatusWarning:{color:_sharedUi.night.color.warning},rowStatusOk:{color:_sharedUi.night.color.accent},rowVerified:{color:_sharedUi.night.color.accent},rowDetail:{paddingLeft:28,paddingTop:8,gap:4},rowTool:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"600",letterSpacing:.8},rowDescription:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18},rowFailure:{color:_sharedUi.night.color.danger,fontSize:_sharedUi.night.font.caption,lineHeight:18},rowReceipts:{paddingTop:10,gap:10},groupBody:{paddingLeft:14,backgroundColor:_sharedUi.night.color.fill},stoppedBox:{alignItems:"flex-start",gap:2,paddingHorizontal:12,paddingVertical:8},stoppedText:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.caption,lineHeight:18},errorBox:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:12,paddingVertical:10,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.dangerSoft},errorBody:{flex:1,gap:4},errorText:{color:_sharedUi.night.color.danger,fontSize:_sharedUi.night.font.caption,fontWeight:"600",lineHeight:18},errorDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.micro,lineHeight:15},retry:{alignSelf:"flex-start",marginTop:6,paddingHorizontal:14,paddingVertical:7,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.button},retryPressed:{opacity:.7},retryText:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},transcriptActions:{flexDirection:"row",alignItems:"center",gap:10,marginTop:8},turnFooter:{flex:1,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontVariant:["tabular-nums"]},copyBtn:{paddingHorizontal:10,paddingVertical:5,borderRadius:_sharedUi.night.radius.badge,backgroundColor:_sharedUi.night.color.fill},iconBtn:{flexDirection:"row",alignItems:"center",gap:4,paddingHorizontal:8},copyPressed:{opacity:.7},copyText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},copiedText:{color:_sharedUi.night.color.accent}});
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MessageList = MessageList;
7
+ exports.transcriptToText = transcriptToText;
8
+ var _react = require("react");
9
+ var _reactNative = require("react-native");
10
+ var _sharedUi = require("@buoy-gg/shared-ui");
11
+ var _agentCore = require("@buoy-gg/agent-core");
12
+ var _BlockRenderer = require("../blocks/BlockRenderer");
13
+ var _blockText = require("../blocks/blockText");
14
+ var _activityGroups = require("../store/activityGroups");
15
+ var _blockPlacement = require("../store/blockPlacement");
16
+ var _askBuoyStore = require("../store/askBuoyStore");
17
+ var _Markdown = require("./Markdown");
18
+ var _ThinkingStrip = require("./ThinkingStrip");
19
+ var _TypingDots = require("./TypingDots");
20
+ var _useCopyAction = require("./useCopyAction");
21
+ var _traceText = require("../store/traceText");
22
+ var _useAskBuoySettings = require("../store/useAskBuoySettings");
23
+ var _jsxRuntime = require("react/jsx-runtime");
24
+ /**
25
+ * The transcript.
26
+ *
27
+ * Owns the ONLY scroller in the sheet. JsModal's default wrapper uses
28
+ * `contentContainerStyle: { flexGrow: 1 }`, so a `flex: 1` scroller nested
29
+ * inside resolves against the CONTENT rather than the viewport: it grows to
30
+ * full content height, never scrolls, and the outer wrapper scrolls instead.
31
+ * That is invisible to a human and fatal to Detox ("View is not scrollable at
32
+ * the given start point"). The sheet passes `disableScrollWrapper` and this
33
+ * list is the one scroller.
34
+ *
35
+ * Layout, and why:
36
+ * - The user's messages are bubbles on the right; the assistant's text is
37
+ * plain, full-width prose on the left. A grey bubble around every answer
38
+ * cost 28pt of width per line and made the two sides look like the same
39
+ * speaker.
40
+ * - Tool calls render as an ACTIVITY CARD above the answer they produced —
41
+ * one row per call, a status mark, a short human title ("Open /bag") and a
42
+ * result word ("Done", "12 items", "Not found"). Nothing in a row is
43
+ * truncated to the point of being unreadable: the title wraps, and tapping
44
+ * the row expands it to the catalog's full sentence plus the tool it ran on.
45
+ * The previous version showed the model-facing sentence cut off at two
46
+ * lines with the result's JSON key names beside it, which was unreadable
47
+ * AND uninformative.
48
+ * - What a READ step returned (the receipt — "10 cached queries", a store's
49
+ * key/values) lives INSIDE that step's row and shows only when the row is
50
+ * expanded. Rendered as a standalone card under the activity list it read
51
+ * as part of the answer: a question about one Pokémon produced a wall of
52
+ * ten cache entries that a non-technical tester had no way to relate to
53
+ * what they asked. The step row already says "10 items"; tapping it is the
54
+ * ask for the detail. Receipts of WRITES (a diff of what changed) are drawn
55
+ * in full — that is the thing the user must see without asking.
56
+ * - CARDS COME LAST, AFTER THE PROSE. A turn reads activity → explanation →
57
+ * the thing itself, which is the order a person would say it in. It used to
58
+ * be the other way round, and on a long turn the answer — a grid of 28 shop
59
+ * items — landed at the TOP with five paragraphs of narration underneath it,
60
+ * so the finished answer arrived before the sentence explaining it. Ask
61
+ * blocks (choice/confirm/input) stay last of all: they are the question the
62
+ * turn ends on.
63
+ */
64
+
65
+ function StatusMark({
66
+ status
67
+ }) {
68
+ switch (status) {
69
+ case "running":
70
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
71
+ size: "small",
72
+ color: _sharedUi.night.color.textSecondary
73
+ });
74
+ case "ok":
75
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
76
+ style: [styles.mark, styles.markOk],
77
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Check, {
78
+ size: 10,
79
+ color: _sharedUi.night.color.onAccent
80
+ })
81
+ });
82
+ case "failed":
83
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
84
+ style: [styles.mark, styles.markFailed],
85
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
86
+ size: 10,
87
+ color: _sharedUi.night.color.text
88
+ })
89
+ });
90
+ case "refused":
91
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
92
+ style: [styles.mark, styles.markRefused],
93
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
94
+ size: 10,
95
+ color: _sharedUi.night.color.onAccent
96
+ })
97
+ });
98
+ // A grey ring with a bar — drawn, not an icon, so the shape is distinct
99
+ // from every outcome the MODEL produced. `declined` had no case at all:
100
+ // the row rendered a blank slot, and later nobody could tell whether the
101
+ // person or the policy had stopped it.
102
+ case "declined":
103
+ case "stopped":
104
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
105
+ style: [styles.mark, styles.markNotRun],
106
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
107
+ style: styles.markNotRunBar
108
+ })
109
+ });
110
+ }
111
+ }
112
+
113
+ /** The trailing word: what happened, in one glance. */
114
+ function statusText(call) {
115
+ if (call.status === "running") return {
116
+ text: "",
117
+ tone: "muted"
118
+ };
119
+ if (call.status === "refused") return {
120
+ text: "Refused",
121
+ tone: "warning"
122
+ };
123
+ if (call.status === "failed") return {
124
+ text: "Failed",
125
+ tone: "danger"
126
+ };
127
+ if (call.status === "declined") return {
128
+ text: "You declined",
129
+ tone: "muted"
130
+ };
131
+ if (call.status === "stopped") return {
132
+ text: "Not run — stopped",
133
+ tone: "muted"
134
+ };
135
+ // The outcome check, when the action had one: the difference between "the
136
+ // adapter said ok" and "the app now shows it". See agent-core engine/verify.ts.
137
+ if (call.verification?.status === "verified") return {
138
+ text: "Verified",
139
+ tone: "ok"
140
+ };
141
+ if (call.verification?.status === "unverified") return {
142
+ text: "Done · not yet visible",
143
+ tone: "muted"
144
+ };
145
+ if (call.verification?.status === "failed") return {
146
+ text: "Done · check failed",
147
+ tone: "warning"
148
+ };
149
+ return {
150
+ text: call.summary || "Done",
151
+ tone: "muted"
152
+ };
153
+ }
154
+
155
+ /** Rows that never fold: anything that did not simply succeed. */
156
+ const isExceptional = c => c.status === "failed" || c.status === "refused" || c.status === "declined" || c.status === "stopped";
157
+ function ActivityRow({
158
+ call,
159
+ receipts,
160
+ last
161
+ }) {
162
+ const [open, setOpen] = (0, _react.useState)(false);
163
+ const status = statusText(call);
164
+ const Chevron = open ? _sharedUi.ChevronDown : _sharedUi.ChevronRight;
165
+ const failureDetail = call.status === "failed" && call.summary && call.summary !== "Failed" ? call.summary : null;
166
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
167
+ style: [styles.row, !last && styles.rowDivider],
168
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
169
+ testID: `buoy-ask-buoy-tool-${call.toolId}`,
170
+ accessibilityRole: "button",
171
+ accessibilityLabel: `${call.label}, ${status.text || "running"}`,
172
+ accessibilityState: {
173
+ expanded: open
174
+ },
175
+ onPress: () => setOpen(v => !v),
176
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
177
+ style: styles.rowLine,
178
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
179
+ style: styles.markSlot,
180
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(StatusMark, {
181
+ status: call.status
182
+ })
183
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
184
+ style: styles.rowTitle,
185
+ children: call.label
186
+ }), status.text ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
187
+ style: [styles.rowStatus, status.tone === "danger" && styles.rowStatusDanger, status.tone === "warning" && styles.rowStatusWarning, status.tone === "ok" && styles.rowStatusOk],
188
+ numberOfLines: 1,
189
+ children: status.text
190
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(Chevron, {
191
+ size: 12,
192
+ color: _sharedUi.night.color.textTertiary
193
+ })]
194
+ }), open && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
195
+ style: styles.rowDetail,
196
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
197
+ style: styles.rowTool,
198
+ children: (0, _agentCore.toolTitle)(call.toolId).toUpperCase()
199
+ }), call.description ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
200
+ style: styles.rowDescription,
201
+ children: call.description
202
+ }) : null, failureDetail ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
203
+ style: styles.rowFailure,
204
+ children: failureDetail
205
+ }) : null, call.verification ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
206
+ style: [styles.rowDescription, call.verification.status === "failed" && styles.rowFailure, call.verification.status === "verified" && styles.rowVerified],
207
+ testID: `buoy-ask-buoy-verification-${call.verification.status}`,
208
+ children: call.verification.detail
209
+ }) : null]
210
+ })]
211
+ }), open && receipts.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
212
+ style: styles.rowReceipts,
213
+ testID: `buoy-ask-buoy-tool-receipt-${call.toolId}`,
214
+ children: receipts.map(block => /*#__PURE__*/(0, _jsxRuntime.jsx)(_BlockRenderer.BlockRenderer, {
215
+ block: block
216
+ }, block.id))
217
+ })]
218
+ });
219
+ }
220
+
221
+ /**
222
+ * Consecutive successful reads fold into one row — "Looked at Network and
223
+ * Storage · 3 reads" — expandable to the individual rows. Everything else
224
+ * (running, failed, refused, declined, stopped, any write) is always its own
225
+ * row, and a group never crosses a write. See store/activityGroups.ts for the
226
+ * rule and why the old "Did 7 things" fold was replaced.
227
+ */
228
+ function ReadsGroup({
229
+ label,
230
+ count,
231
+ calls,
232
+ receipts,
233
+ last
234
+ }) {
235
+ const [open, setOpen] = (0, _react.useState)(false);
236
+ const Chevron = open ? _sharedUi.ChevronDown : _sharedUi.ChevronRight;
237
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
238
+ style: !last && !open && styles.rowDivider,
239
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
240
+ testID: "buoy-ask-buoy-reads-group",
241
+ accessibilityRole: "button",
242
+ accessibilityLabel: `${label}, ${count} reads`,
243
+ accessibilityState: {
244
+ expanded: open
245
+ },
246
+ onPress: () => setOpen(v => !v),
247
+ style: [styles.row, open && styles.rowDivider],
248
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
249
+ style: styles.rowLine,
250
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
251
+ style: styles.markSlot,
252
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(StatusMark, {
253
+ status: "ok"
254
+ })
255
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
256
+ style: styles.rowTitle,
257
+ children: label
258
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
259
+ style: styles.rowStatus,
260
+ numberOfLines: 1,
261
+ children: [count, " reads"]
262
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Chevron, {
263
+ size: 12,
264
+ color: _sharedUi.night.color.textTertiary
265
+ })]
266
+ })
267
+ }), open && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
268
+ style: styles.groupBody,
269
+ children: calls.map((c, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(ActivityRow, {
270
+ call: c,
271
+ receipts: receipts.get(c.id) ?? [],
272
+ last: last && i === calls.length - 1
273
+ }, c.id))
274
+ })]
275
+ });
276
+ }
277
+ function ActivityCard({
278
+ calls,
279
+ receipts
280
+ }) {
281
+ const items = (0, _activityGroups.groupCalls)(calls);
282
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
283
+ style: styles.card,
284
+ testID: "buoy-ask-buoy-activity",
285
+ children: items.map((item, i) => item.kind === "reads" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ReadsGroup, {
286
+ label: item.label,
287
+ count: item.count,
288
+ calls: item.calls,
289
+ receipts: receipts,
290
+ last: i === items.length - 1
291
+ }, item.id) : /*#__PURE__*/(0, _jsxRuntime.jsx)(ActivityRow, {
292
+ call: item.call,
293
+ receipts: receipts.get(item.call.id) ?? [],
294
+ last: i === items.length - 1
295
+ }, item.call.id))
296
+ });
297
+ }
298
+
299
+ /** Write receipts and model blocks render between the activity card and the prose; Ask blocks last. */
300
+ function Blocks({
301
+ blocks
302
+ }) {
303
+ if (blocks.length === 0) return null;
304
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
305
+ style: styles.blocks,
306
+ children: blocks.map(({
307
+ block
308
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_BlockRenderer.BlockRenderer, {
309
+ block: block
310
+ }, block.id))
311
+ });
312
+ }
313
+
314
+ /** A line from Buoy, not the model. Dim, centred, no footer, no copy pill. */
315
+ function SystemLine({
316
+ message
317
+ }) {
318
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
319
+ style: styles.systemLine,
320
+ testID: "buoy-ask-buoy-system-line",
321
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
322
+ style: styles.systemText,
323
+ children: message.text
324
+ })
325
+ });
326
+ }
327
+ function UserMessage({
328
+ message
329
+ }) {
330
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
331
+ style: styles.userWrap,
332
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
333
+ style: styles.userBubble,
334
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
335
+ style: styles.userText,
336
+ selectable: true,
337
+ children: message.text
338
+ })
339
+ })
340
+ });
341
+ }
342
+ function AssistantMessage({
343
+ message,
344
+ onRetry,
345
+ waitingOnUser
346
+ }) {
347
+ const {
348
+ showThinking
349
+ } = (0, _useAskBuoySettings.useAskBuoySettings)();
350
+ /**
351
+ * The dots run for the WHOLE turn, not just the wait for the first token.
352
+ *
353
+ * They used to hide as soon as any prose arrived and while a tool call was
354
+ * running. A turn that says "pulling the catalogue up — one moment" and
355
+ * then works for another minute is the normal shape of this tool, and it
356
+ * spent that minute with nothing moving at the bottom of the chat: the
357
+ * activity card had already collapsed to "Did 16 things", so the only clue
358
+ * anything was still happening was the Stop button and the header
359
+ * subtitle. The row spinner in the activity card says which STEP is
360
+ * running; this says the TURN is.
361
+ *
362
+ * The one state it stays out of is a turn waiting on the user — an
363
+ * approval or an Ask block. Nothing is loading there.
364
+ */
365
+ const waiting = !!message.streaming && !waitingOnUser;
366
+ const {
367
+ nested,
368
+ afterText,
369
+ ask: askBlocks
370
+ } = (0, _blockPlacement.placeBlocks)(message.blocks, message.toolCalls.map(c => c.id));
371
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
372
+ style: styles.assistantWrap,
373
+ children: [message.toolCalls.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(ActivityCard, {
374
+ calls: message.toolCalls,
375
+ receipts: nested
376
+ }), message.text.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Markdown.Markdown, {
377
+ text: message.text,
378
+ style: styles.assistantText
379
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Blocks, {
380
+ blocks: afterText
381
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Blocks, {
382
+ blocks: askBlocks
383
+ }), showThinking && !message.streaming && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ThinkingStrip.ThinkingStrip, {
384
+ message: message
385
+ }), waiting && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
386
+ style: styles.waitingRow,
387
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_TypingDots.TypingDots, {}), message.waiting ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
388
+ style: styles.waitingText,
389
+ testID: "buoy-ask-buoy-waiting",
390
+ children: message.waiting
391
+ }) : null]
392
+ }), message.error && /*#__PURE__*/(0, _jsxRuntime.jsx)(ErrorNote, {
393
+ error: message.error,
394
+ onRetry: onRetry
395
+ }), message.stopped && !message.error && /*#__PURE__*/(0, _jsxRuntime.jsx)(StoppedNote, {
396
+ onRetry: onRetry,
397
+ changed: message.toolCalls.some(c => c.status === "ok" && !!c.effect && c.effect !== "read")
398
+ })]
399
+ });
400
+ }
401
+
402
+ /**
403
+ * A turn the user stopped.
404
+ *
405
+ * Deliberately not the error box: they pressed the button. The whole point is
406
+ * that it is quiet — a muted line, the same Try-again affordance, and none of
407
+ * the red "check your connection" advice that a cancelled fetch used to
408
+ * produce. When a write had already landed before the tap, the line says so:
409
+ * Stop cannot pull a dispatched change back out of the app, and "Stopped."
410
+ * alone read as if nothing had happened.
411
+ */
412
+ function StoppedNote({
413
+ onRetry,
414
+ changed
415
+ }) {
416
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
417
+ style: styles.stoppedBox,
418
+ testID: "buoy-ask-buoy-stopped",
419
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
420
+ style: styles.stoppedText,
421
+ children: changed ? "Stopped. Changes already made are listed above." : "Stopped."
422
+ }), onRetry && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
423
+ testID: "buoy-ask-buoy-retry",
424
+ accessibilityRole: "button",
425
+ accessibilityLabel: "Try again",
426
+ onPress: onRetry,
427
+ style: ({
428
+ pressed
429
+ }) => [styles.retry, pressed && styles.retryPressed],
430
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
431
+ style: styles.retryText,
432
+ children: "Try again"
433
+ })
434
+ })]
435
+ });
436
+ }
437
+
438
+ /**
439
+ * A failed turn. The headline is for the tester ("couldn't reach the
440
+ * endpoint"); the raw message stays underneath for whoever gets the bug
441
+ * report, because "fetch failed: UnexpectedException: The network connection
442
+ * was lost" is what a developer needs and nothing a tester can act on.
443
+ */
444
+ function ErrorNote({
445
+ error,
446
+ onRetry
447
+ }) {
448
+ const network = /fetch failed|network|ECONN|timed? ?out|socket/i.test(error);
449
+ const headline = network ? "Couldn't reach your AI endpoint. Check the connection and try again." : "Something went wrong with that turn.";
450
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
451
+ style: styles.errorBox,
452
+ testID: "buoy-ask-buoy-error",
453
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
454
+ size: 14,
455
+ color: _sharedUi.night.color.danger
456
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
457
+ style: styles.errorBody,
458
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
459
+ style: styles.errorText,
460
+ children: headline
461
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
462
+ style: styles.errorDetail,
463
+ selectable: true,
464
+ children: error
465
+ }), onRetry && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
466
+ testID: "buoy-ask-buoy-retry",
467
+ accessibilityRole: "button",
468
+ accessibilityLabel: "Try again",
469
+ onPress: onRetry,
470
+ style: ({
471
+ pressed
472
+ }) => [styles.retry, pressed && styles.retryPressed],
473
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
474
+ style: styles.retryText,
475
+ children: "Try again"
476
+ })
477
+ })]
478
+ })]
479
+ });
480
+ }
481
+
482
+ /**
483
+ * The whole conversation as plain text — the only thing Copy ever produces,
484
+ * and the only way a session leaves the DEVICE (what it saves to disk for a
485
+ * reload goes nowhere — see `transcriptPersistence`).
486
+ *
487
+ * Plain text on purpose. This lands in a Slack message, a ticket comment or a
488
+ * notes file, all of which are read by a person; a JSON document is a worse
489
+ * version of that everywhere except a parser, and nothing here parses it.
490
+ *
491
+ * With `Show agent thinking` on it carries the working too — the reasoning and
492
+ * each step with its parameters — because reading the run somewhere that is
493
+ * not a phone is the entire point of that setting.
494
+ */
495
+ function transcriptToText(messages, withTrace = false) {
496
+ const lines = [];
497
+ for (const m of messages) {
498
+ if (m.role === "user") {
499
+ lines.push(`You: ${m.text}`);
500
+ continue;
501
+ }
502
+ if (m.system) {
503
+ lines.push(` — ${m.text}`);
504
+ continue;
505
+ }
506
+ if (withTrace) {
507
+ lines.push(...(0, _traceText.traceToText)(m));
508
+ } else {
509
+ for (const c of m.toolCalls) {
510
+ const status = isExceptional(c) ? ` (${c.status})` : "";
511
+ lines.push(` · ${c.label}${c.summary ? ` — ${c.summary}` : ""}${status}`);
512
+ }
513
+ }
514
+ if (m.text) lines.push(`Ask Buoy: ${m.text}`);
515
+ // The cards, too. A finding is the thing a ticket wants and it used to be
516
+ // the one thing the paste left out.
517
+ for (const t of (0, _blockText.blocksToText)(m.blocks.map(p => p.block))) lines.push(t);
518
+ if (m.error) lines.push(` ! ${m.error}`);
519
+ if (m.stopped && !m.error) lines.push(" ! Stopped by the user.");
520
+ }
521
+ return lines.join("\n");
522
+ }
523
+
524
+ /** Copy, with the result visible for a moment. Shares the header's behaviour. */
525
+ function CopyPill({
526
+ testID,
527
+ label,
528
+ getText
529
+ }) {
530
+ const {
531
+ copied,
532
+ copy
533
+ } = (0, _useCopyAction.useCopyAction)(getText);
534
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
535
+ testID: testID,
536
+ accessibilityRole: "button",
537
+ accessibilityLabel: label,
538
+ onPress: copy,
539
+ style: ({
540
+ pressed
541
+ }) => [styles.copyBtn, styles.iconBtn, pressed && styles.copyPressed],
542
+ children: [copied ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Check, {
543
+ size: 11,
544
+ color: _sharedUi.night.color.accent
545
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Copy, {
546
+ size: 11,
547
+ color: _sharedUi.night.color.textSecondary
548
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
549
+ style: [styles.copyText, copied && styles.copiedText],
550
+ children: copied ? "Copied" : label
551
+ })]
552
+ });
553
+ }
554
+
555
+ /**
556
+ * Under a finished answer: the turn's footer and one Copy.
557
+ *
558
+ * The footer — "48s · 6 actions · 1 declined" — is always on. Duration and
559
+ * counts used to exist only inside the opt-in thinking strip, so nothing
560
+ * separated one turn from the next and "how long did that take?" had no
561
+ * answer without a setting. See `turnFooter` for what is counted and why.
562
+ *
563
+ * Copy is on EVERY answer rather than only the newest, because the moment you
564
+ * decide to keep a conversation is usually a few replies after the one that
565
+ * went wrong, and scrolling to the bottom to find the button is friction at
566
+ * exactly the wrong time. It copies the WHOLE chat, and now says so: labelled
567
+ * "Copy" it read as "copy this answer", and a paste into Slack brought the
568
+ * full transcript. The text is built on press from the live store, so this
569
+ * component takes no `messages` prop and a streaming answer no longer
570
+ * re-renders every finished one.
571
+ */
572
+ function TranscriptActions({
573
+ message
574
+ }) {
575
+ const {
576
+ showThinking
577
+ } = (0, _useAskBuoySettings.useAskBuoySettings)();
578
+ const getText = (0, _react.useCallback)(() => transcriptToText(_askBuoyStore.askBuoyStore.getState().messages, showThinking), [showThinking]);
579
+ const footer = (0, _activityGroups.turnFooter)(message);
580
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
581
+ style: styles.transcriptActions,
582
+ children: [footer ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
583
+ style: styles.turnFooter,
584
+ testID: "buoy-ask-buoy-turn-footer",
585
+ children: footer
586
+ }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(CopyPill, {
587
+ testID: "buoy-ask-buoy-copy",
588
+ label: "Copy conversation",
589
+ getText: getText
590
+ })]
591
+ });
592
+ }
593
+
594
+ /**
595
+ * Memoised: a streaming answer changes the store on every token, and every
596
+ * row re-rendered for it. Props are the message itself (a new object when it
597
+ * changes), the retry handler (only the newest row gets one) and the waiting
598
+ * flag — nothing that changes when a DIFFERENT message streams.
599
+ */
600
+ const Row = /*#__PURE__*/(0, _react.memo)(function Row({
601
+ message,
602
+ onRetry,
603
+ waitingOnUser
604
+ }) {
605
+ if (message.role === "user") return /*#__PURE__*/(0, _jsxRuntime.jsx)(UserMessage, {
606
+ message: message
607
+ });
608
+ if (message.system) return /*#__PURE__*/(0, _jsxRuntime.jsx)(SystemLine, {
609
+ message: message
610
+ });
611
+ const finished = !message.streaming && !message.error;
612
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
613
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(AssistantMessage, {
614
+ message: message,
615
+ onRetry: onRetry,
616
+ waitingOnUser: waitingOnUser
617
+ }), finished && /*#__PURE__*/(0, _jsxRuntime.jsx)(TranscriptActions, {
618
+ message: message
619
+ })]
620
+ });
621
+ });
622
+ function MessageList({
623
+ messages,
624
+ ListHeaderComponent,
625
+ ListEmptyComponent,
626
+ ListFooterComponent,
627
+ onRetry,
628
+ waitingOnUser
629
+ }) {
630
+ const ref = (0, _react.useRef)(null);
631
+ // Only auto-scroll when the user is already at the bottom. Yanking them back
632
+ // down while they are reading an earlier answer is the classic chat-UI sin.
633
+ //
634
+ // "At the bottom" is decided from the USER's gestures, not from every scroll
635
+ // event. An animated scrollToEnd fires intermediate events while the content
636
+ // is still growing under it, and reading those as "the user scrolled up"
637
+ // silently unpinned the list mid-answer — the reply then streamed in below
638
+ // the fold and the last thing on screen was the question.
639
+ const pinned = (0, _react.useRef)(true);
640
+ const dragging = (0, _react.useRef)(false);
641
+ const measure = (0, _react.useCallback)(e => {
642
+ const {
643
+ contentOffset,
644
+ contentSize,
645
+ layoutMeasurement
646
+ } = e.nativeEvent;
647
+ const distance = contentSize.height - layoutMeasurement.height - contentOffset.y;
648
+ pinned.current = distance < 80;
649
+ }, []);
650
+ const onScrollBeginDrag = (0, _react.useCallback)(() => {
651
+ dragging.current = true;
652
+ }, []);
653
+ const onScroll = (0, _react.useCallback)(e => {
654
+ if (dragging.current) measure(e);
655
+ }, [measure]);
656
+ const onScrollEndDrag = (0, _react.useCallback)(e => {
657
+ dragging.current = false;
658
+ measure(e);
659
+ }, [measure]);
660
+ const scrollToEnd = (0, _react.useCallback)(() => {
661
+ if (!pinned.current) return;
662
+ // The size change fires before the new row has finished laying out its
663
+ // wrapped text; one frame later the end really is the end.
664
+ ref.current?.scrollToEnd({
665
+ animated: false
666
+ });
667
+ requestAnimationFrame(() => ref.current?.scrollToEnd({
668
+ animated: false
669
+ }));
670
+ }, []);
671
+
672
+ // A row can grow without the list reporting a size change in the same tick
673
+ // (an error box appended to the last message). Follow the transcript too.
674
+ const last = messages[messages.length - 1];
675
+ const tail = last ? `${last.id}:${last.text.length}:${last.toolCalls.length}:${last.error ?? ""}` : "";
676
+ (0, _react.useEffect)(() => {
677
+ scrollToEnd();
678
+ }, [tail, scrollToEnd]);
679
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
680
+ ref: ref,
681
+ testID: "buoy-ask-buoy-messages-scroll",
682
+ style: styles.list,
683
+ contentContainerStyle: styles.listContent,
684
+ data: messages,
685
+ keyExtractor: m => m.id,
686
+ renderItem: ({
687
+ item
688
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
689
+ message: item,
690
+ onRetry: item.id === last?.id ? onRetry : undefined,
691
+ waitingOnUser: item.id === last?.id ? waitingOnUser : false
692
+ }),
693
+ onScroll: onScroll,
694
+ onScrollBeginDrag: onScrollBeginDrag,
695
+ onScrollEndDrag: onScrollEndDrag,
696
+ onMomentumScrollEnd: measure,
697
+ scrollEventThrottle: 32,
698
+ onContentSizeChange: scrollToEnd
699
+ // Mandatory with a focused input below: without it the first tap after
700
+ // typing only dismisses the keyboard and the button never fires.
701
+ ,
702
+ keyboardShouldPersistTaps: "handled",
703
+ keyboardDismissMode: "interactive",
704
+ ListHeaderComponent: ListHeaderComponent,
705
+ ListEmptyComponent: ListEmptyComponent,
706
+ ListFooterComponent: ListFooterComponent
707
+ });
708
+ }
709
+ const styles = _reactNative.StyleSheet.create({
710
+ list: {
711
+ flex: 1,
712
+ backgroundColor: "transparent"
713
+ },
714
+ listContent: {
715
+ paddingHorizontal: _sharedUi.night.gutter,
716
+ paddingTop: 12,
717
+ paddingBottom: 16,
718
+ gap: 16,
719
+ flexGrow: 1
720
+ },
721
+ // User
722
+ userWrap: {
723
+ alignItems: "flex-end"
724
+ },
725
+ userBubble: {
726
+ maxWidth: "84%",
727
+ paddingHorizontal: 14,
728
+ paddingVertical: 9,
729
+ borderRadius: 18,
730
+ borderBottomRightRadius: 6,
731
+ backgroundColor: _sharedUi.night.color.accentFill,
732
+ borderWidth: _reactNative.StyleSheet.hairlineWidth,
733
+ borderColor: _sharedUi.night.color.accentBorder
734
+ },
735
+ userText: {
736
+ color: _sharedUi.night.color.text,
737
+ fontSize: _sharedUi.night.font.row,
738
+ lineHeight: 21
739
+ },
740
+ // Buoy's own lines
741
+ systemLine: {
742
+ alignSelf: "stretch",
743
+ paddingHorizontal: 12,
744
+ paddingVertical: 7,
745
+ borderRadius: _sharedUi.night.radius.row,
746
+ backgroundColor: _sharedUi.night.color.fill
747
+ },
748
+ systemText: {
749
+ color: _sharedUi.night.color.textSecondary,
750
+ fontSize: _sharedUi.night.font.micro,
751
+ lineHeight: 16,
752
+ textAlign: "center"
753
+ },
754
+ // Assistant
755
+ assistantWrap: {
756
+ alignItems: "stretch",
757
+ gap: 10
758
+ },
759
+ blocks: {
760
+ gap: 10
761
+ },
762
+ waitingRow: {
763
+ flexDirection: "row",
764
+ alignItems: "center",
765
+ gap: 8
766
+ },
767
+ waitingText: {
768
+ color: _sharedUi.night.color.textSecondary,
769
+ fontSize: _sharedUi.night.font.caption
770
+ },
771
+ assistantText: {
772
+ color: _sharedUi.night.color.text,
773
+ fontSize: _sharedUi.night.font.row,
774
+ lineHeight: 22,
775
+ paddingHorizontal: 2
776
+ },
777
+ // Activity card
778
+ card: {
779
+ borderRadius: _sharedUi.night.radius.card,
780
+ borderWidth: _reactNative.StyleSheet.hairlineWidth,
781
+ borderColor: _sharedUi.night.color.border,
782
+ backgroundColor: _sharedUi.night.color.surface,
783
+ overflow: "hidden"
784
+ },
785
+ row: {
786
+ paddingHorizontal: 12,
787
+ paddingVertical: 10
788
+ },
789
+ rowDivider: {
790
+ borderBottomWidth: _reactNative.StyleSheet.hairlineWidth,
791
+ borderBottomColor: _sharedUi.night.color.separator
792
+ },
793
+ rowLine: {
794
+ flexDirection: "row",
795
+ alignItems: "center",
796
+ gap: 10
797
+ },
798
+ markSlot: {
799
+ width: 18,
800
+ height: 18,
801
+ alignItems: "center",
802
+ justifyContent: "center"
803
+ },
804
+ mark: {
805
+ width: 16,
806
+ height: 16,
807
+ borderRadius: 8,
808
+ alignItems: "center",
809
+ justifyContent: "center"
810
+ },
811
+ markOk: {
812
+ backgroundColor: _sharedUi.night.color.accent
813
+ },
814
+ markFailed: {
815
+ backgroundColor: _sharedUi.night.color.danger
816
+ },
817
+ markRefused: {
818
+ backgroundColor: _sharedUi.night.color.warning
819
+ },
820
+ markNotRun: {
821
+ borderWidth: 1.5,
822
+ borderColor: _sharedUi.night.color.textTertiary
823
+ },
824
+ markNotRunBar: {
825
+ width: 7,
826
+ height: 1.5,
827
+ borderRadius: 1,
828
+ backgroundColor: _sharedUi.night.color.textSecondary
829
+ },
830
+ rowTitle: {
831
+ flex: 1,
832
+ color: _sharedUi.night.color.text,
833
+ fontSize: _sharedUi.night.font.body,
834
+ lineHeight: 19
835
+ },
836
+ rowStatus: {
837
+ color: _sharedUi.night.color.textTertiary,
838
+ fontSize: _sharedUi.night.font.caption,
839
+ maxWidth: 120
840
+ },
841
+ rowStatusDanger: {
842
+ color: _sharedUi.night.color.danger
843
+ },
844
+ rowStatusWarning: {
845
+ color: _sharedUi.night.color.warning
846
+ },
847
+ rowStatusOk: {
848
+ color: _sharedUi.night.color.accent
849
+ },
850
+ rowVerified: {
851
+ color: _sharedUi.night.color.accent
852
+ },
853
+ rowDetail: {
854
+ paddingLeft: 28,
855
+ paddingTop: 8,
856
+ gap: 4
857
+ },
858
+ rowTool: {
859
+ color: _sharedUi.night.color.textTertiary,
860
+ fontSize: _sharedUi.night.font.micro,
861
+ fontWeight: "600",
862
+ letterSpacing: 0.8
863
+ },
864
+ rowDescription: {
865
+ color: _sharedUi.night.color.textSecondary,
866
+ fontSize: _sharedUi.night.font.caption,
867
+ lineHeight: 18
868
+ },
869
+ rowFailure: {
870
+ color: _sharedUi.night.color.danger,
871
+ fontSize: _sharedUi.night.font.caption,
872
+ lineHeight: 18
873
+ },
874
+ rowReceipts: {
875
+ paddingTop: 10,
876
+ gap: 10
877
+ },
878
+ groupBody: {
879
+ paddingLeft: 14,
880
+ backgroundColor: _sharedUi.night.color.fill
881
+ },
882
+ stoppedBox: {
883
+ alignItems: "flex-start",
884
+ gap: 2,
885
+ paddingHorizontal: 12,
886
+ paddingVertical: 8
887
+ },
888
+ stoppedText: {
889
+ color: _sharedUi.night.color.textTertiary,
890
+ fontSize: _sharedUi.night.font.caption,
891
+ lineHeight: 18
892
+ },
893
+ // Error
894
+ errorBox: {
895
+ flexDirection: "row",
896
+ alignItems: "flex-start",
897
+ gap: 8,
898
+ paddingHorizontal: 12,
899
+ paddingVertical: 10,
900
+ borderRadius: _sharedUi.night.radius.row,
901
+ backgroundColor: _sharedUi.night.color.dangerSoft
902
+ },
903
+ errorBody: {
904
+ flex: 1,
905
+ gap: 4
906
+ },
907
+ errorText: {
908
+ color: _sharedUi.night.color.danger,
909
+ fontSize: _sharedUi.night.font.caption,
910
+ fontWeight: "600",
911
+ lineHeight: 18
912
+ },
913
+ errorDetail: {
914
+ color: _sharedUi.night.color.textSecondary,
915
+ fontSize: _sharedUi.night.font.micro,
916
+ lineHeight: 15
917
+ },
918
+ retry: {
919
+ alignSelf: "flex-start",
920
+ marginTop: 6,
921
+ paddingHorizontal: 14,
922
+ paddingVertical: 7,
923
+ borderRadius: _sharedUi.night.radius.row,
924
+ backgroundColor: _sharedUi.night.color.button
925
+ },
926
+ retryPressed: {
927
+ opacity: 0.7
928
+ },
929
+ retryText: {
930
+ color: _sharedUi.night.color.accent,
931
+ fontSize: _sharedUi.night.font.caption,
932
+ fontWeight: "600"
933
+ },
934
+ transcriptActions: {
935
+ flexDirection: "row",
936
+ alignItems: "center",
937
+ gap: 10,
938
+ marginTop: 8
939
+ },
940
+ turnFooter: {
941
+ flex: 1,
942
+ color: _sharedUi.night.color.textTertiary,
943
+ fontSize: _sharedUi.night.font.micro,
944
+ fontVariant: ["tabular-nums"]
945
+ },
946
+ copyBtn: {
947
+ paddingHorizontal: 10,
948
+ paddingVertical: 5,
949
+ borderRadius: _sharedUi.night.radius.badge,
950
+ backgroundColor: _sharedUi.night.color.fill
951
+ },
952
+ iconBtn: {
953
+ flexDirection: "row",
954
+ alignItems: "center",
955
+ gap: 4,
956
+ paddingHorizontal: 8
957
+ },
958
+ copyPressed: {
959
+ opacity: 0.7
960
+ },
961
+ copyText: {
962
+ color: _sharedUi.night.color.textSecondary,
963
+ fontSize: _sharedUi.night.font.micro,
964
+ fontWeight: "600"
965
+ },
966
+ copiedText: {
967
+ color: _sharedUi.night.color.accent
968
+ }
969
+ });
970
+ //# sourceMappingURL=MessageList.js.map