@adecore/agents-react 0.0.1 → 0.17.0-beta.1

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 (513) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +53 -0
  3. package/dist/agents/AccountDot.d.ts +4 -0
  4. package/dist/agents/AccountDot.js +8 -0
  5. package/dist/agents/AgentIcon.d.ts +6 -0
  6. package/dist/agents/AgentIcon.js +20 -0
  7. package/dist/agents/ModelOptionControl.d.ts +15 -0
  8. package/dist/agents/ModelOptionControl.js +33 -0
  9. package/dist/agents/ProviderLogo.d.ts +8 -0
  10. package/dist/agents/ProviderLogo.js +8 -0
  11. package/dist/agents/account-limits.d.ts +7 -0
  12. package/dist/agents/account-limits.js +40 -0
  13. package/dist/agents/accounts.d.ts +22 -0
  14. package/dist/agents/accounts.js +113 -0
  15. package/dist/agents/model-name.d.ts +12 -0
  16. package/dist/agents/model-name.js +56 -0
  17. package/dist/agents/model-options.d.ts +5 -0
  18. package/dist/agents/model-options.js +15 -0
  19. package/dist/agents/provider-paths.d.ts +2 -0
  20. package/dist/agents/provider-paths.js +8 -0
  21. package/dist/agents/status-look.d.ts +13 -0
  22. package/dist/agents/status-look.js +24 -0
  23. package/dist/chat/account-choice.d.ts +11 -0
  24. package/dist/chat/account-choice.js +30 -0
  25. package/dist/chat/actions.d.ts +6 -0
  26. package/dist/chat/actions.js +68 -0
  27. package/dist/chat/activity.d.ts +5 -0
  28. package/dist/chat/activity.js +6 -0
  29. package/dist/chat/attachments.d.ts +23 -0
  30. package/dist/chat/attachments.js +86 -0
  31. package/dist/chat/bookmarks.d.ts +14 -0
  32. package/dist/chat/bookmarks.js +73 -0
  33. package/dist/chat/chat-client.d.ts +55 -0
  34. package/dist/chat/chat-client.js +279 -0
  35. package/dist/chat/chat-references.d.ts +5 -0
  36. package/dist/chat/chat-references.js +5 -0
  37. package/dist/chat/drafts.d.ts +29 -0
  38. package/dist/chat/drafts.js +116 -0
  39. package/dist/chat/forks.d.ts +2 -0
  40. package/dist/chat/forks.js +28 -0
  41. package/dist/chat/guards.d.ts +12 -0
  42. package/dist/chat/guards.js +69 -0
  43. package/dist/chat/logic/ansi.d.ts +13 -0
  44. package/dist/chat/logic/ansi.js +185 -0
  45. package/dist/chat/logic/answers.d.ts +1 -0
  46. package/dist/chat/logic/answers.js +8 -0
  47. package/dist/chat/logic/bookmarks.d.ts +5 -0
  48. package/dist/chat/logic/bookmarks.js +33 -0
  49. package/dist/chat/logic/context-usage.d.ts +12 -0
  50. package/dist/chat/logic/context-usage.js +21 -0
  51. package/dist/chat/logic/fork.d.ts +45 -0
  52. package/dist/chat/logic/fork.js +148 -0
  53. package/dist/chat/logic/handback.d.ts +2 -0
  54. package/dist/chat/logic/handback.js +8 -0
  55. package/dist/chat/logic/json.d.ts +1 -0
  56. package/dist/chat/logic/json.js +4 -0
  57. package/dist/chat/logic/limit.d.ts +7 -0
  58. package/dist/chat/logic/limit.js +34 -0
  59. package/dist/chat/logic/resume-compaction.d.ts +14 -0
  60. package/dist/chat/logic/resume-compaction.js +47 -0
  61. package/dist/chat/logic/scrubber.d.ts +50 -0
  62. package/dist/chat/logic/scrubber.js +220 -0
  63. package/dist/chat/logic/thread-cards.d.ts +3 -0
  64. package/dist/chat/logic/thread-cards.js +59 -0
  65. package/dist/chat/logic/timeline-copy.d.ts +4 -0
  66. package/dist/chat/logic/timeline-copy.js +59 -0
  67. package/dist/chat/logic/timeline-target.d.ts +12 -0
  68. package/dist/chat/logic/timeline-target.js +34 -0
  69. package/dist/chat/logic/timeline.d.ts +115 -0
  70. package/dist/chat/logic/timeline.js +343 -0
  71. package/dist/chat/logic/tool-catalog.d.ts +10 -0
  72. package/dist/chat/logic/tool-catalog.js +44 -0
  73. package/dist/chat/logic/tools.d.ts +15 -0
  74. package/dist/chat/logic/tools.js +82 -0
  75. package/dist/chat/logic/welcome.d.ts +2 -0
  76. package/dist/chat/logic/welcome.js +10 -0
  77. package/dist/chat/logic/workflow.d.ts +14 -0
  78. package/dist/chat/logic/workflow.js +47 -0
  79. package/dist/chat/mentions.d.ts +65 -0
  80. package/dist/chat/mentions.js +184 -0
  81. package/dist/chat/persisted-json.d.ts +5 -0
  82. package/dist/chat/persisted-json.js +58 -0
  83. package/dist/chat/preferences.d.ts +27 -0
  84. package/dist/chat/preferences.js +139 -0
  85. package/dist/chat/quote.d.ts +2 -0
  86. package/dist/chat/quote.js +25 -0
  87. package/dist/chat/recent-messages.d.ts +17 -0
  88. package/dist/chat/recent-messages.js +36 -0
  89. package/dist/chat/resume-compaction-dismissals.d.ts +3 -0
  90. package/dist/chat/resume-compaction-dismissals.js +14 -0
  91. package/dist/chat/runtime-modes.d.ts +4 -0
  92. package/dist/chat/runtime-modes.js +15 -0
  93. package/dist/chat/stash.d.ts +24 -0
  94. package/dist/chat/stash.js +91 -0
  95. package/dist/chat/subagent-conversation.d.ts +41 -0
  96. package/dist/chat/subagent-conversation.js +167 -0
  97. package/dist/chat/subagent-list.d.ts +19 -0
  98. package/dist/chat/subagent-list.js +106 -0
  99. package/dist/chat/subagent-support.d.ts +6 -0
  100. package/dist/chat/subagent-support.js +14 -0
  101. package/dist/chat/subagent-view.d.ts +35 -0
  102. package/dist/chat/subagent-view.js +96 -0
  103. package/dist/chat/thumbnails.d.ts +10 -0
  104. package/dist/chat/thumbnails.js +89 -0
  105. package/dist/chat/timeline-flash.d.ts +12 -0
  106. package/dist/chat/timeline-flash.js +16 -0
  107. package/dist/chat/timeline-scroll.d.ts +27 -0
  108. package/dist/chat/timeline-scroll.js +152 -0
  109. package/dist/chat/ui/AccountPill.d.ts +3 -0
  110. package/dist/chat/ui/AccountPill.js +23 -0
  111. package/dist/chat/ui/AnsiOutput.d.ts +5 -0
  112. package/dist/chat/ui/AnsiOutput.js +9 -0
  113. package/dist/chat/ui/BookmarkMarker.d.ts +8 -0
  114. package/dist/chat/ui/BookmarkMarker.js +57 -0
  115. package/dist/chat/ui/BookmarkSubmenu.d.ts +3 -0
  116. package/dist/chat/ui/BookmarkSubmenu.js +33 -0
  117. package/dist/chat/ui/ChatActivity.d.ts +7 -0
  118. package/dist/chat/ui/ChatActivity.js +84 -0
  119. package/dist/chat/ui/ChatReferenceChip.d.ts +4 -0
  120. package/dist/chat/ui/ChatReferenceChip.js +16 -0
  121. package/dist/chat/ui/CodeBlock.d.ts +4 -0
  122. package/dist/chat/ui/CodeBlock.js +132 -0
  123. package/dist/chat/ui/Composer.d.ts +15 -0
  124. package/dist/chat/ui/Composer.js +856 -0
  125. package/dist/chat/ui/ComposerInput.d.ts +29 -0
  126. package/dist/chat/ui/ComposerInput.js +127 -0
  127. package/dist/chat/ui/DiffPool.d.ts +5 -0
  128. package/dist/chat/ui/DiffPool.js +26 -0
  129. package/dist/chat/ui/EditDiff.d.ts +4 -0
  130. package/dist/chat/ui/EditDiff.js +21 -0
  131. package/dist/chat/ui/FadingWords.d.ts +3 -0
  132. package/dist/chat/ui/FadingWords.js +5 -0
  133. package/dist/chat/ui/ImageView.d.ts +6 -0
  134. package/dist/chat/ui/ImageView.js +81 -0
  135. package/dist/chat/ui/LimitState.d.ts +8 -0
  136. package/dist/chat/ui/LimitState.js +112 -0
  137. package/dist/chat/ui/Markdown.d.ts +18 -0
  138. package/dist/chat/ui/Markdown.js +159 -0
  139. package/dist/chat/ui/MessageActions.d.ts +9 -0
  140. package/dist/chat/ui/MessageActions.js +53 -0
  141. package/dist/chat/ui/Pickers.d.ts +21 -0
  142. package/dist/chat/ui/Pickers.js +111 -0
  143. package/dist/chat/ui/PromptComposer.d.ts +13 -0
  144. package/dist/chat/ui/PromptComposer.js +56 -0
  145. package/dist/chat/ui/QuoteButton.d.ts +7 -0
  146. package/dist/chat/ui/QuoteButton.js +74 -0
  147. package/dist/chat/ui/ResumeCompactionDock.d.ts +5 -0
  148. package/dist/chat/ui/ResumeCompactionDock.js +14 -0
  149. package/dist/chat/ui/RunSettings.d.ts +28 -0
  150. package/dist/chat/ui/RunSettings.js +153 -0
  151. package/dist/chat/ui/Scrubber.d.ts +17 -0
  152. package/dist/chat/ui/Scrubber.js +118 -0
  153. package/dist/chat/ui/SubagentControls.d.ts +11 -0
  154. package/dist/chat/ui/SubagentControls.js +36 -0
  155. package/dist/chat/ui/SubagentInfo.d.ts +4 -0
  156. package/dist/chat/ui/SubagentInfo.js +34 -0
  157. package/dist/chat/ui/SubagentStopButton.d.ts +7 -0
  158. package/dist/chat/ui/SubagentStopButton.js +34 -0
  159. package/dist/chat/ui/SubagentTimeline.d.ts +4 -0
  160. package/dist/chat/ui/SubagentTimeline.js +107 -0
  161. package/dist/chat/ui/Timeline.d.ts +6 -0
  162. package/dist/chat/ui/Timeline.js +424 -0
  163. package/dist/chat/ui/TimelineMenu.d.ts +12 -0
  164. package/dist/chat/ui/TimelineMenu.js +54 -0
  165. package/dist/chat/ui/UnifiedDiff.d.ts +11 -0
  166. package/dist/chat/ui/UnifiedDiff.js +66 -0
  167. package/dist/chat/ui/UploadThumb.d.ts +4 -0
  168. package/dist/chat/ui/UploadThumb.js +11 -0
  169. package/dist/chat/ui/Welcome.d.ts +4 -0
  170. package/dist/chat/ui/Welcome.js +16 -0
  171. package/dist/chat/ui/chips.d.ts +4 -0
  172. package/dist/chat/ui/chips.js +11 -0
  173. package/dist/chat/ui/code-lines.d.ts +18 -0
  174. package/dist/chat/ui/code-lines.js +46 -0
  175. package/dist/chat/ui/code-streaming.d.ts +1 -0
  176. package/dist/chat/ui/code-streaming.js +3 -0
  177. package/dist/chat/ui/code-theme.d.ts +3 -0
  178. package/dist/chat/ui/code-theme.js +12 -0
  179. package/dist/chat/ui/composer/chips.d.ts +6 -0
  180. package/dist/chat/ui/composer/chips.js +31 -0
  181. package/dist/chat/ui/composer/editor.d.ts +11 -0
  182. package/dist/chat/ui/composer/editor.js +98 -0
  183. package/dist/chat/ui/composer/insert.d.ts +2 -0
  184. package/dist/chat/ui/composer/insert.js +19 -0
  185. package/dist/chat/ui/composer/keys.d.ts +30 -0
  186. package/dist/chat/ui/composer/keys.js +100 -0
  187. package/dist/chat/ui/diff-theme.d.ts +2 -0
  188. package/dist/chat/ui/diff-theme.js +20 -0
  189. package/dist/chat/ui/file-links.d.ts +5 -0
  190. package/dist/chat/ui/file-links.js +20 -0
  191. package/dist/chat/ui/find-reveal.d.ts +7 -0
  192. package/dist/chat/ui/find-reveal.js +13 -0
  193. package/dist/chat/ui/full-diff.d.ts +6 -0
  194. package/dist/chat/ui/full-diff.js +19 -0
  195. package/dist/chat/ui/icons.d.ts +4 -0
  196. package/dist/chat/ui/icons.js +20 -0
  197. package/dist/chat/ui/markdown-blocks.d.ts +6 -0
  198. package/dist/chat/ui/markdown-blocks.js +103 -0
  199. package/dist/chat/ui/quote-selection.d.ts +3 -0
  200. package/dist/chat/ui/quote-selection.js +46 -0
  201. package/dist/chat/ui/rehype-chips.d.ts +23 -0
  202. package/dist/chat/ui/rehype-chips.js +32 -0
  203. package/dist/chat/ui/rehype-fade.d.ts +23 -0
  204. package/dist/chat/ui/rehype-fade.js +36 -0
  205. package/dist/chat/ui/remark-html-as-text.d.ts +8 -0
  206. package/dist/chat/ui/remark-html-as-text.js +26 -0
  207. package/dist/chat/ui/reply-context.d.ts +5 -0
  208. package/dist/chat/ui/reply-context.js +2 -0
  209. package/dist/chat/ui/reveal.d.ts +13 -0
  210. package/dist/chat/ui/reveal.js +114 -0
  211. package/dist/chat/ui/rows/ForksRow.d.ts +4 -0
  212. package/dist/chat/ui/rows/ForksRow.js +38 -0
  213. package/dist/chat/ui/rows/MessageRows.d.ts +40 -0
  214. package/dist/chat/ui/rows/MessageRows.js +204 -0
  215. package/dist/chat/ui/rows/Rows.d.ts +12 -0
  216. package/dist/chat/ui/rows/Rows.js +61 -0
  217. package/dist/chat/ui/rows/SubagentRow.d.ts +17 -0
  218. package/dist/chat/ui/rows/SubagentRow.js +101 -0
  219. package/dist/chat/ui/rows/TaskRow.d.ts +8 -0
  220. package/dist/chat/ui/rows/TaskRow.js +63 -0
  221. package/dist/chat/ui/rows/WorkRows.d.ts +47 -0
  222. package/dist/chat/ui/rows/WorkRows.js +168 -0
  223. package/dist/chat/ui/rows/WorkflowRow.d.ts +8 -0
  224. package/dist/chat/ui/rows/WorkflowRow.js +48 -0
  225. package/dist/chat/ui/rows/row-rhythm.d.ts +6 -0
  226. package/dist/chat/ui/rows/row-rhythm.js +34 -0
  227. package/dist/chat/ui/useToggleSet.d.ts +6 -0
  228. package/dist/chat/ui/useToggleSet.js +25 -0
  229. package/dist/host.d.ts +195 -0
  230. package/dist/host.js +55 -0
  231. package/dist/lazy.d.ts +6 -0
  232. package/dist/lazy.js +57 -0
  233. package/dist/locales/en/agent-chat.json +446 -0
  234. package/dist/locales/en/agent-prompts.json +42 -0
  235. package/dist/locales/en/agent-providers.json +131 -0
  236. package/dist/locales/en/agent-usage.json +131 -0
  237. package/dist/locales/nl/agent-chat.json +446 -0
  238. package/dist/locales/nl/agent-prompts.json +42 -0
  239. package/dist/locales/nl/agent-providers.json +131 -0
  240. package/dist/locales/nl/agent-usage.json +131 -0
  241. package/dist/locales.d.ts +5 -0
  242. package/dist/locales.js +20 -0
  243. package/dist/mounted-registry.d.ts +7 -0
  244. package/dist/mounted-registry.js +39 -0
  245. package/dist/port-transport.d.ts +6 -0
  246. package/dist/port-transport.js +129 -0
  247. package/dist/prompts/logic/focus.d.ts +2 -0
  248. package/dist/prompts/logic/focus.js +23 -0
  249. package/dist/prompts/logic/keys.d.ts +42 -0
  250. package/dist/prompts/logic/keys.js +94 -0
  251. package/dist/prompts/logic/prompts.d.ts +34 -0
  252. package/dist/prompts/logic/prompts.fixtures.d.ts +5 -0
  253. package/dist/prompts/logic/prompts.fixtures.js +79 -0
  254. package/dist/prompts/logic/prompts.js +32 -0
  255. package/dist/prompts/logic/subjects.d.ts +50 -0
  256. package/dist/prompts/logic/subjects.js +63 -0
  257. package/dist/prompts/logic/useFocusAfterAnswer.d.ts +6 -0
  258. package/dist/prompts/logic/useFocusAfterAnswer.js +28 -0
  259. package/dist/prompts/logic/usePromptSession.d.ts +24 -0
  260. package/dist/prompts/logic/usePromptSession.js +87 -0
  261. package/dist/prompts/ui/ApprovalBody.d.ts +13 -0
  262. package/dist/prompts/ui/ApprovalBody.js +34 -0
  263. package/dist/prompts/ui/PromptActions.d.ts +27 -0
  264. package/dist/prompts/ui/PromptActions.js +18 -0
  265. package/dist/prompts/ui/PromptCard.d.ts +16 -0
  266. package/dist/prompts/ui/PromptCard.js +50 -0
  267. package/dist/prompts/ui/PromptView.d.ts +2 -0
  268. package/dist/prompts/ui/PromptView.js +47 -0
  269. package/dist/prompts/ui/QuestionBody.d.ts +9 -0
  270. package/dist/prompts/ui/QuestionBody.js +87 -0
  271. package/dist/providers/AccountColors.d.ts +5 -0
  272. package/dist/providers/AccountColors.js +8 -0
  273. package/dist/providers/AccountDetail.d.ts +12 -0
  274. package/dist/providers/AccountDetail.js +69 -0
  275. package/dist/providers/AccountVariables.d.ts +8 -0
  276. package/dist/providers/AccountVariables.js +43 -0
  277. package/dist/providers/AddAccountForm.d.ts +10 -0
  278. package/dist/providers/AddAccountForm.js +54 -0
  279. package/dist/providers/CliDetail.d.ts +12 -0
  280. package/dist/providers/CliDetail.js +54 -0
  281. package/dist/providers/ProvidersPane.d.ts +9 -0
  282. package/dist/providers/ProvidersPane.js +86 -0
  283. package/dist/providers/account-actions.d.ts +7 -0
  284. package/dist/providers/account-actions.js +57 -0
  285. package/dist/providers/parts.d.ts +9 -0
  286. package/dist/providers/parts.js +18 -0
  287. package/dist/providers/provider-abilities.d.ts +2 -0
  288. package/dist/providers/provider-abilities.js +7 -0
  289. package/dist/providers/variables.d.ts +13 -0
  290. package/dist/providers/variables.js +63 -0
  291. package/dist/scope.d.ts +11 -0
  292. package/dist/scope.js +10 -0
  293. package/dist/settings/sections.d.ts +13 -0
  294. package/dist/settings/sections.js +32 -0
  295. package/dist/state/chats.d.ts +44 -0
  296. package/dist/state/chats.js +199 -0
  297. package/dist/state/provider-accounts.d.ts +17 -0
  298. package/dist/state/provider-accounts.js +67 -0
  299. package/dist/state/providers.d.ts +17 -0
  300. package/dist/state/providers.js +33 -0
  301. package/dist/state/usage.d.ts +44 -0
  302. package/dist/state/usage.js +121 -0
  303. package/dist/storage.d.ts +20 -0
  304. package/dist/storage.js +89 -0
  305. package/dist/theme.css +196 -0
  306. package/dist/transport.d.ts +24 -0
  307. package/dist/transport.js +18 -0
  308. package/dist/ui/PlainTextarea.d.ts +2 -0
  309. package/dist/ui/PlainTextarea.js +5 -0
  310. package/dist/usage/LimitsList.d.ts +18 -0
  311. package/dist/usage/LimitsList.js +73 -0
  312. package/dist/usage/UsageBreakdown.d.ts +9 -0
  313. package/dist/usage/UsageBreakdown.js +67 -0
  314. package/dist/usage/UsageChart.d.ts +10 -0
  315. package/dist/usage/UsageChart.js +47 -0
  316. package/dist/usage/UsageDialog.d.ts +6 -0
  317. package/dist/usage/UsageDialog.js +12 -0
  318. package/dist/usage/UsageLimits.d.ts +1 -0
  319. package/dist/usage/UsageLimits.js +57 -0
  320. package/dist/usage/UsageLimitsCard.d.ts +4 -0
  321. package/dist/usage/UsageLimitsCard.js +26 -0
  322. package/dist/usage/UsagePage.d.ts +7 -0
  323. package/dist/usage/UsagePage.js +154 -0
  324. package/dist/usage/UsagePane.d.ts +3 -0
  325. package/dist/usage/UsagePane.js +21 -0
  326. package/dist/usage/UsageSummary.d.ts +12 -0
  327. package/dist/usage/UsageSummary.js +15 -0
  328. package/dist/usage/UsageTiles.d.ts +7 -0
  329. package/dist/usage/UsageTiles.js +19 -0
  330. package/dist/usage/format.d.ts +13 -0
  331. package/dist/usage/format.js +55 -0
  332. package/dist/usage/limit-groups.d.ts +22 -0
  333. package/dist/usage/limit-groups.js +86 -0
  334. package/dist/usage/limits.d.ts +4 -0
  335. package/dist/usage/limits.js +58 -0
  336. package/dist/usage/money.d.ts +1 -0
  337. package/dist/usage/money.js +13 -0
  338. package/dist/usage/summary.d.ts +34 -0
  339. package/dist/usage/summary.js +94 -0
  340. package/package.json +895 -3
  341. package/src/agents/AccountDot.tsx +14 -0
  342. package/src/agents/AgentIcon.tsx +26 -0
  343. package/src/agents/ModelOptionControl.tsx +68 -0
  344. package/src/agents/ProviderLogo.tsx +20 -0
  345. package/src/agents/account-limits.ts +61 -0
  346. package/src/agents/accounts.ts +137 -0
  347. package/src/agents/model-name.ts +70 -0
  348. package/src/agents/model-options.ts +21 -0
  349. package/src/agents/provider-paths.ts +10 -0
  350. package/src/agents/status-look.ts +43 -0
  351. package/src/chat/account-choice.ts +44 -0
  352. package/src/chat/actions.ts +72 -0
  353. package/src/chat/activity.ts +8 -0
  354. package/src/chat/attachments.ts +118 -0
  355. package/src/chat/bookmarks.ts +87 -0
  356. package/src/chat/chat-client.ts +345 -0
  357. package/src/chat/chat-references.ts +11 -0
  358. package/src/chat/drafts.ts +165 -0
  359. package/src/chat/forks.ts +33 -0
  360. package/src/chat/guards.ts +84 -0
  361. package/src/chat/logic/ansi.ts +206 -0
  362. package/src/chat/logic/answers.ts +8 -0
  363. package/src/chat/logic/bookmarks.ts +42 -0
  364. package/src/chat/logic/context-usage.ts +36 -0
  365. package/src/chat/logic/fork.ts +200 -0
  366. package/src/chat/logic/handback.ts +10 -0
  367. package/src/chat/logic/json.ts +4 -0
  368. package/src/chat/logic/limit.ts +46 -0
  369. package/src/chat/logic/resume-compaction.ts +71 -0
  370. package/src/chat/logic/scrubber.ts +289 -0
  371. package/src/chat/logic/thread-cards.ts +64 -0
  372. package/src/chat/logic/timeline-copy.ts +65 -0
  373. package/src/chat/logic/timeline-target.ts +52 -0
  374. package/src/chat/logic/timeline.ts +419 -0
  375. package/src/chat/logic/tool-catalog.ts +62 -0
  376. package/src/chat/logic/tools.ts +102 -0
  377. package/src/chat/logic/welcome.ts +13 -0
  378. package/src/chat/logic/workflow.ts +66 -0
  379. package/src/chat/mentions.ts +232 -0
  380. package/src/chat/persisted-json.ts +67 -0
  381. package/src/chat/preferences.ts +179 -0
  382. package/src/chat/quote.ts +26 -0
  383. package/src/chat/recent-messages.ts +59 -0
  384. package/src/chat/resume-compaction-dismissals.ts +17 -0
  385. package/src/chat/runtime-modes.ts +18 -0
  386. package/src/chat/stash.ts +122 -0
  387. package/src/chat/subagent-conversation.ts +203 -0
  388. package/src/chat/subagent-list.ts +141 -0
  389. package/src/chat/subagent-support.ts +21 -0
  390. package/src/chat/subagent-view.ts +137 -0
  391. package/src/chat/thumbnails.ts +108 -0
  392. package/src/chat/timeline-flash.ts +33 -0
  393. package/src/chat/timeline-scroll.ts +199 -0
  394. package/src/chat/ui/AccountPill.tsx +31 -0
  395. package/src/chat/ui/AnsiOutput.tsx +18 -0
  396. package/src/chat/ui/BookmarkMarker.tsx +108 -0
  397. package/src/chat/ui/BookmarkSubmenu.tsx +53 -0
  398. package/src/chat/ui/ChatActivity.tsx +198 -0
  399. package/src/chat/ui/ChatReferenceChip.tsx +28 -0
  400. package/src/chat/ui/CodeBlock.tsx +175 -0
  401. package/src/chat/ui/Composer.tsx +1326 -0
  402. package/src/chat/ui/ComposerInput.tsx +187 -0
  403. package/src/chat/ui/DiffPool.tsx +36 -0
  404. package/src/chat/ui/EditDiff.tsx +30 -0
  405. package/src/chat/ui/FadingWords.tsx +18 -0
  406. package/src/chat/ui/ImageView.tsx +159 -0
  407. package/src/chat/ui/LimitState.tsx +165 -0
  408. package/src/chat/ui/Markdown.tsx +258 -0
  409. package/src/chat/ui/MessageActions.tsx +88 -0
  410. package/src/chat/ui/Pickers.tsx +272 -0
  411. package/src/chat/ui/PromptComposer.tsx +119 -0
  412. package/src/chat/ui/QuoteButton.tsx +103 -0
  413. package/src/chat/ui/ResumeCompactionDock.tsx +28 -0
  414. package/src/chat/ui/RunSettings.tsx +546 -0
  415. package/src/chat/ui/Scrubber.tsx +265 -0
  416. package/src/chat/ui/SubagentControls.tsx +66 -0
  417. package/src/chat/ui/SubagentInfo.tsx +67 -0
  418. package/src/chat/ui/SubagentStopButton.tsx +45 -0
  419. package/src/chat/ui/SubagentTimeline.tsx +170 -0
  420. package/src/chat/ui/Timeline.tsx +628 -0
  421. package/src/chat/ui/TimelineMenu.tsx +124 -0
  422. package/src/chat/ui/UnifiedDiff.tsx +99 -0
  423. package/src/chat/ui/UploadThumb.tsx +13 -0
  424. package/src/chat/ui/Welcome.tsx +22 -0
  425. package/src/chat/ui/chips.ts +15 -0
  426. package/src/chat/ui/code-lines.ts +60 -0
  427. package/src/chat/ui/code-streaming.ts +4 -0
  428. package/src/chat/ui/code-theme.ts +15 -0
  429. package/src/chat/ui/composer/chips.ts +43 -0
  430. package/src/chat/ui/composer/editor.ts +118 -0
  431. package/src/chat/ui/composer/insert.ts +22 -0
  432. package/src/chat/ui/composer/keys.ts +144 -0
  433. package/src/chat/ui/diff-theme.ts +23 -0
  434. package/src/chat/ui/file-links.ts +24 -0
  435. package/src/chat/ui/find-reveal.ts +23 -0
  436. package/src/chat/ui/full-diff.ts +25 -0
  437. package/src/chat/ui/icons.tsx +24 -0
  438. package/src/chat/ui/markdown-blocks.ts +123 -0
  439. package/src/chat/ui/quote-selection.ts +53 -0
  440. package/src/chat/ui/rehype-chips.ts +62 -0
  441. package/src/chat/ui/rehype-fade.ts +64 -0
  442. package/src/chat/ui/remark-html-as-text.ts +36 -0
  443. package/src/chat/ui/reply-context.ts +4 -0
  444. package/src/chat/ui/reveal.ts +135 -0
  445. package/src/chat/ui/rows/ForksRow.tsx +79 -0
  446. package/src/chat/ui/rows/MessageRows.tsx +415 -0
  447. package/src/chat/ui/rows/Rows.tsx +81 -0
  448. package/src/chat/ui/rows/SubagentRow.tsx +209 -0
  449. package/src/chat/ui/rows/TaskRow.tsx +91 -0
  450. package/src/chat/ui/rows/WorkRows.tsx +445 -0
  451. package/src/chat/ui/rows/WorkflowRow.tsx +120 -0
  452. package/src/chat/ui/rows/row-rhythm.ts +37 -0
  453. package/src/chat/ui/useToggleSet.ts +39 -0
  454. package/src/host.ts +324 -0
  455. package/src/lazy.tsx +64 -0
  456. package/src/locales/en/agent-chat.json +446 -0
  457. package/src/locales/en/agent-prompts.json +42 -0
  458. package/src/locales/en/agent-providers.json +131 -0
  459. package/src/locales/en/agent-usage.json +131 -0
  460. package/src/locales/nl/agent-chat.json +446 -0
  461. package/src/locales/nl/agent-prompts.json +42 -0
  462. package/src/locales/nl/agent-providers.json +131 -0
  463. package/src/locales/nl/agent-usage.json +131 -0
  464. package/src/locales.ts +33 -0
  465. package/src/mounted-registry.ts +45 -0
  466. package/src/port-transport.ts +146 -0
  467. package/src/prompts/logic/focus.ts +25 -0
  468. package/src/prompts/logic/keys.ts +116 -0
  469. package/src/prompts/logic/prompts.fixtures.ts +84 -0
  470. package/src/prompts/logic/prompts.ts +58 -0
  471. package/src/prompts/logic/subjects.ts +122 -0
  472. package/src/prompts/logic/useFocusAfterAnswer.ts +38 -0
  473. package/src/prompts/logic/usePromptSession.ts +114 -0
  474. package/src/prompts/ui/ApprovalBody.tsx +109 -0
  475. package/src/prompts/ui/PromptActions.tsx +109 -0
  476. package/src/prompts/ui/PromptCard.tsx +101 -0
  477. package/src/prompts/ui/PromptView.tsx +111 -0
  478. package/src/prompts/ui/QuestionBody.tsx +174 -0
  479. package/src/providers/AccountColors.tsx +8 -0
  480. package/src/providers/AccountDetail.tsx +209 -0
  481. package/src/providers/AccountVariables.tsx +126 -0
  482. package/src/providers/AddAccountForm.tsx +121 -0
  483. package/src/providers/CliDetail.tsx +157 -0
  484. package/src/providers/ProvidersPane.tsx +236 -0
  485. package/src/providers/account-actions.ts +67 -0
  486. package/src/providers/parts.tsx +25 -0
  487. package/src/providers/provider-abilities.ts +9 -0
  488. package/src/providers/variables.ts +87 -0
  489. package/src/scope.ts +30 -0
  490. package/src/settings/sections.ts +47 -0
  491. package/src/state/chats.ts +279 -0
  492. package/src/state/provider-accounts.ts +87 -0
  493. package/src/state/providers.ts +50 -0
  494. package/src/state/usage.ts +196 -0
  495. package/src/storage.ts +113 -0
  496. package/src/theme.css +196 -0
  497. package/src/transport.ts +50 -0
  498. package/src/ui/PlainTextarea.tsx +6 -0
  499. package/src/usage/LimitsList.tsx +232 -0
  500. package/src/usage/UsageBreakdown.tsx +210 -0
  501. package/src/usage/UsageChart.tsx +113 -0
  502. package/src/usage/UsageDialog.tsx +20 -0
  503. package/src/usage/UsageLimits.tsx +145 -0
  504. package/src/usage/UsageLimitsCard.tsx +36 -0
  505. package/src/usage/UsagePage.tsx +276 -0
  506. package/src/usage/UsagePane.tsx +52 -0
  507. package/src/usage/UsageSummary.tsx +50 -0
  508. package/src/usage/UsageTiles.tsx +34 -0
  509. package/src/usage/format.ts +71 -0
  510. package/src/usage/limit-groups.ts +119 -0
  511. package/src/usage/limits.ts +71 -0
  512. package/src/usage/money.ts +14 -0
  513. package/src/usage/summary.ts +137 -0
@@ -0,0 +1,144 @@
1
+ import type { SyntaxNode, Tree } from '@lezer/common';
2
+
3
+ export type EnterAction = 'send' | 'newline' | 'continue-list' | 'leave-list';
4
+
5
+ export interface EnterKeys {
6
+ shift: boolean;
7
+ /* Cmd on macOS, Ctrl elsewhere. */
8
+ mod: boolean;
9
+ }
10
+
11
+ export interface ListItem {
12
+ /* The indentation, the marker and the space after it, a task's box included. */
13
+ prefix: string;
14
+ /* The prefix the next item starts with: the next number, and an unchecked box for a task. */
15
+ next: string;
16
+ /* Nothing but the prefix on the line. */
17
+ empty: boolean;
18
+ }
19
+
20
+ export interface EnterContext {
21
+ inOpenFence: boolean;
22
+ /* The list item on the caret's line, or null outside a list and in code. */
23
+ list: ListItem | null;
24
+ /* The caret's offset in its line. */
25
+ column: number;
26
+ }
27
+
28
+ const LIST_ITEM = /^([ \t]*)(?:([-*+])|(\d{1,9})([.)]))([ \t]+)(\[[ xX]\](?:[ \t]+|$))?/;
29
+
30
+ /* The list item a line starts, if it starts one. */
31
+ export function listItemAt(line: string): ListItem | null {
32
+ const match = LIST_ITEM.exec(line);
33
+ if (match === null) {
34
+ return null;
35
+ }
36
+ const [prefix, indent, bullet, number, delimiter, space, task] = match;
37
+ const marker = bullet ?? `${Number(number) + 1}${delimiter}`;
38
+ return { prefix, next: `${indent}${marker}${space}${task ? '[ ] ' : ''}`, empty: line.slice(prefix.length).trim() === '' };
39
+ }
40
+
41
+ /*
42
+ * Enter sends, except where whoever types is still writing: inside a fence nobody has closed yet
43
+ * it adds a line, and in a list it starts the next item, or leaves the list from an empty one, so
44
+ * a second Enter breaks out. Shift adds a plain line and Mod sends from anywhere.
45
+ */
46
+ export function enterAction(keys: EnterKeys, { inOpenFence, list, column }: EnterContext): EnterAction {
47
+ if (keys.mod) {
48
+ return 'send';
49
+ }
50
+ if (keys.shift || inOpenFence) {
51
+ return 'newline';
52
+ }
53
+ if (list === null) {
54
+ return 'send';
55
+ }
56
+ // A caret in front of the marker moves the item down rather than splitting its marker.
57
+ if (column < list.prefix.length) {
58
+ return 'newline';
59
+ }
60
+ return list.empty ? 'leave-list' : 'continue-list';
61
+ }
62
+
63
+ /* Whether `pos` sits inside a fenced code block that has an opening fence and no closing one yet. */
64
+ export function inOpenFence(tree: Tree, pos: number): boolean {
65
+ for (let node: SyntaxNode | null = tree.resolveInner(pos, -1); node !== null; node = node.parent) {
66
+ if (node.name === 'FencedCode') {
67
+ return pos > node.from && node.getChildren('CodeMark').length < 2;
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+
73
+ /* Whether `pos` sits in the body of a fenced code block, open or closed: below its opening line and before its end. */
74
+ export function inFenceBody(tree: Tree, text: string, pos: number): boolean {
75
+ for (let node: SyntaxNode | null = tree.resolveInner(pos, -1); node !== null; node = node.parent) {
76
+ if (node.name === 'FencedCode') {
77
+ const openingEnd = text.indexOf('\n', node.from);
78
+ return openingEnd !== -1 && pos > openingEnd && (pos < node.to || node.getChildren('CodeMark').length < 2);
79
+ }
80
+ }
81
+ return false;
82
+ }
83
+
84
+ /* The spaces Tab inserts at `column`, up to the next stop of four, the way a code editor lines up. */
85
+ export function tabSpaces(column: number): string {
86
+ return ' '.repeat(4 - (column % 4));
87
+ }
88
+
89
+ const INLINE_BLOCK = /^(Paragraph|ATXHeading\d|SetextHeading\d)$/;
90
+
91
+ /*
92
+ * Whether `pos` sits inside code: a fence, open or closed, or a code span. The parser only calls a
93
+ * span code once it is closed, so a backtick nobody has closed yet earlier in the same paragraph
94
+ * counts as well: whoever types after it is writing code.
95
+ */
96
+ export function inCode(tree: Tree, text: string, pos: number): boolean {
97
+ let blockFrom: number | null = null;
98
+ for (let node: SyntaxNode | null = tree.resolveInner(pos, -1); node !== null; node = node.parent) {
99
+ if (node.name === 'FencedCode') {
100
+ return pos > node.from && (pos < node.to || node.getChildren('CodeMark').length < 2);
101
+ }
102
+ if (node.name === 'InlineCode' && pos > node.from && pos < node.to) {
103
+ return true;
104
+ }
105
+ if (blockFrom === null && INLINE_BLOCK.test(node.name)) {
106
+ blockFrom = node.from;
107
+ }
108
+ }
109
+ let from = blockFrom ?? text.lastIndexOf('\n', pos - 1) + 1;
110
+ tree.iterate({
111
+ from,
112
+ to: pos,
113
+ enter: (node) => {
114
+ if (node.name === 'InlineCode' && node.to <= pos) {
115
+ from = Math.max(from, node.to);
116
+ }
117
+ }
118
+ });
119
+ return /(^|[^\\])`/.test(text.slice(from, pos));
120
+ }
121
+
122
+ export interface RecallContext {
123
+ key: string;
124
+ text: string;
125
+ from: number;
126
+ to: number;
127
+ /* A prompt taken back from the thread sits in the box and nobody has edited it. */
128
+ recalled: boolean;
129
+ }
130
+
131
+ /*
132
+ * Which way the arrow walks through earlier prompts, or null when the arrow just moves the caret.
133
+ * Only an empty box or an unedited recall walks, so an arrow in a prompt being written never
134
+ * throws it away.
135
+ */
136
+ export function recallDirection({ key, text, from, to, recalled }: RecallContext): -1 | 1 | null {
137
+ if (key === 'ArrowUp' && (text === '' || (recalled && from === 0))) {
138
+ return -1;
139
+ }
140
+ if (key === 'ArrowDown' && recalled && to === text.length) {
141
+ return 1;
142
+ }
143
+ return null;
144
+ }
@@ -0,0 +1,23 @@
1
+ import { useMemo } from 'react';
2
+ import { registerCustomTheme, type ThemesType } from '@pierre/diffs';
3
+ import { chatHost } from '../../host';
4
+
5
+ let registered = false;
6
+
7
+ /* The library resolves Shiki's bundled themes by id on its own; the app's own it only knows by registration, done once the host is set. */
8
+ function registerThemes(): void {
9
+ if (registered) {
10
+ return;
11
+ }
12
+ registered = true;
13
+ for (const theme of chatHost().code.custom) {
14
+ registerCustomTheme(theme.name, () => Promise.resolve(theme));
15
+ }
16
+ }
17
+
18
+ /* The code themes a diff is drawn in, the same pair a chat's code blocks use. */
19
+ export function useDiffTheme(): ThemesType {
20
+ registerThemes();
21
+ const { light, dark } = chatHost().code.useThemes();
22
+ return useMemo(() => ({ light, dark }), [light, dark]);
23
+ }
@@ -0,0 +1,24 @@
1
+ import { createContext, useContext, useMemo } from 'react';
2
+ import { chatHost, type FileRef } from '../../host';
3
+
4
+ /*
5
+ * The folder a relative reference in rendered text counts from: a chat's own cwd, which is a
6
+ * worktree as often as it is the project, or the folder of the file an app is drawing. Null where
7
+ * nobody said, and there only an absolute path is a link.
8
+ */
9
+ export const FileLinkContext = createContext<string | null>(null);
10
+
11
+ export function useFileLinkCwd(): string | null {
12
+ return useContext(FileLinkContext);
13
+ }
14
+
15
+ /* The reference a piece of text names, only where this spot on screen could open it. */
16
+ export function useFileLinkTarget(text: string): FileRef | null {
17
+ const cwd = useFileLinkCwd();
18
+ return useMemo(() => chatHost().fileLinks?.target(text, cwd) ?? null, [text, cwd]);
19
+ }
20
+
21
+ /* A reference followed, the way the app opens a file or a folder. */
22
+ export function openFileLink(cwd: string | null, ref: FileRef): void {
23
+ chatHost().fileLinks?.open(cwd, ref);
24
+ }
@@ -0,0 +1,23 @@
1
+ import { createContext, useContext, useEffect } from 'react';
2
+
3
+ /* The line that always shows, the text of a message, or what shows only once a row is opened. */
4
+ export type ChatFindField = 'summary' | 'text' | 'output';
5
+
6
+ export interface FindReveal {
7
+ itemId: string;
8
+ field: ChatFindField;
9
+ }
10
+
11
+ /* The hit the find bar is on, so the row that folds it away can open. */
12
+ export const FindRevealContext = createContext<FindReveal | null>(null);
13
+
14
+ /* Opens a fold of this item while the find bar is on a hit inside it; it stays open once the bar moves on, as if a person opened it. */
15
+ export function useOpenForFind(itemId: string, field: ChatFindField, setOpen: (open: boolean) => void): void {
16
+ const reveal = useContext(FindRevealContext);
17
+ const wanted = reveal !== null && reveal.itemId === itemId && reveal.field === field;
18
+ useEffect(() => {
19
+ if (wanted) {
20
+ setOpen(true);
21
+ }
22
+ }, [wanted, reveal, setOpen]);
23
+ }
@@ -0,0 +1,25 @@
1
+ import { processFile, type FileDiffMetadata } from '@pierre/diffs';
2
+
3
+ /* The two whole texts a patch was made between. */
4
+ export interface DiffContents {
5
+ readonly old: string;
6
+ readonly new: string;
7
+ }
8
+
9
+ /*
10
+ * A patch laid over the two whole texts it was made between, which is what lets a reader unfold
11
+ * the lines between its hunks. The hunks stay the patch's own, so a patch made without whitespace
12
+ * keeps its counts. Null when there is no hunk to lay over them, and the patch alone is drawn.
13
+ */
14
+ export function fullFileDiff(patch: string, name: string, contents: DiffContents): FileDiffMetadata | null {
15
+ try {
16
+ const parsed = processFile(patch, {
17
+ oldFile: { name, contents: contents.old },
18
+ newFile: { name, contents: contents.new },
19
+ throwOnError: true
20
+ });
21
+ return parsed === undefined || parsed.isPartial || parsed.hunks.length === 0 ? null : parsed;
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+ import { Hammer, Wrench } from 'lucide-react';
3
+ import { toolEntry } from '../logic/tool-catalog';
4
+ import { Icon } from '@adecore/ui';
5
+
6
+ const SIZE = 12;
7
+
8
+ /* A pending dock draws its mark a step up from the lines of a transcript, at the size a sidebar
9
+ row uses, because it is a thing to answer rather than a thing to read past. */
10
+ export const DOCK_ICON_SIZE = 14;
11
+
12
+ /* The gutter every row in the thread opens with: 16 wide, on the line box of its first row of text,
13
+ so the mark of a tool call, a note and a fold all sit in one column and their labels start at the
14
+ same x. The same box the menu rows and the toasts use. */
15
+ export const ROW_GUTTER = 'grid h-5 w-4 shrink-0 place-items-center';
16
+
17
+ /* The icon that says what a tool call is about; unknown tools get the wrench. */
18
+ export function toolIcon(name: string, size: number = SIZE): ReactNode {
19
+ const known = toolEntry(name);
20
+ if (known !== undefined) {
21
+ return <Icon icon={known.icon} size={size} />;
22
+ }
23
+ return name.startsWith('mcp__') ? <Icon icon={Hammer} size={size} /> : <Icon icon={Wrench} size={size} />;
24
+ }
@@ -0,0 +1,123 @@
1
+ export interface MarkdownBlock {
2
+ text: string;
3
+ /* The block ends inside a code fence that has not closed yet. */
4
+ openFence: boolean;
5
+ }
6
+
7
+ interface OpenFence {
8
+ marker: string;
9
+ length: number;
10
+ indent: number;
11
+ }
12
+
13
+ const FENCE = /^([ \t]*)(`{3,}|~{3,})(.*)$/;
14
+ // Spaces and tabs only: a line that holds a no-break space is text to markdown, not a blank line.
15
+ const BLANK = /^[ \t]*$/;
16
+ // A line that continues what stood before the blank line: an indented paragraph of a list item, or
17
+ // the next item of a loose list. Splitting there would change what the markdown means.
18
+ const CONTINUES = /^([ \t]|[-*+][ \t]|\d+[.)][ \t])/;
19
+ // A reference or footnote definition may be used anywhere in the text, so a block cannot stand alone.
20
+ const DEFINITION = /^ {0,3}\[[^\]]+\]:/m;
21
+ // How much deeper than its opening a closing fence may sit; deeper than that it is a line of code.
22
+ const CLOSING_INDENT = 3;
23
+ // A section title: an ATX heading, or a line of only bold text, which models write as a heading too.
24
+ const HEADING = /^ {0,3}#{1,6}(?:[ \t]|$)/;
25
+ const BOLD_LINE = /^ {0,3}\*\*(?:[^*]|\*(?!\*))+\*\*:?[ \t]*$/;
26
+
27
+ /*
28
+ * A reply cut into blocks at blank lines outside a code fence, so each block parses on its own and
29
+ * only the one still growing is parsed again. Joined back together the blocks are the text.
30
+ */
31
+ export function splitMarkdownBlocks(text: string): MarkdownBlock[] {
32
+ if (DEFINITION.test(text)) {
33
+ return [{ text, openFence: isFenceOpenAtEnd(text) }];
34
+ }
35
+ const lines = text.split('\n');
36
+ const blocks: MarkdownBlock[] = [];
37
+ let start = 0;
38
+ let offset = 0;
39
+ let fence: OpenFence | null = null;
40
+ let afterBlank = false;
41
+
42
+ lines.forEach((line, index) => {
43
+ if (fence === null && afterBlank && !BLANK.test(line) && !CONTINUES.test(line)) {
44
+ blocks.push({ text: text.slice(start, offset), openFence: false });
45
+ start = offset;
46
+ }
47
+ fence = nextFence(fence, line);
48
+ afterBlank = fence === null && BLANK.test(line) && index > 0;
49
+ offset += line.length + 1;
50
+ });
51
+ blocks.push({ text: text.slice(start), openFence: fence !== null });
52
+ return blocks;
53
+ }
54
+
55
+ /*
56
+ * The blocks of a reply still being written that will not change any more: every block but the last.
57
+ * A block is only known to be closed once the line after its blank line starts, since that line may
58
+ * still turn out to continue it (a list item, an indented paragraph). A section title waits for the
59
+ * block under it, so it never sits alone above a block that is still streaming.
60
+ */
61
+ export function settledBlocksText(text: string): string {
62
+ return withoutTrailingTitles(
63
+ splitMarkdownBlocks(text)
64
+ .slice(0, -1)
65
+ .map((block) => block.text)
66
+ .join('')
67
+ );
68
+ }
69
+
70
+ function withoutTrailingTitles(text: string): string {
71
+ const lines = text.split('\n');
72
+ let end = lines.length;
73
+ for (let index = lines.length - 1; index >= 0; index--) {
74
+ const line = lines[index]!;
75
+ if (BLANK.test(line)) {
76
+ continue;
77
+ }
78
+ // A bold line right under a line of text continues that paragraph.
79
+ const title = HEADING.test(line) || (BOLD_LINE.test(line) && (index === 0 || BLANK.test(lines[index - 1]!)));
80
+ if (!title) {
81
+ break;
82
+ }
83
+ end = index;
84
+ }
85
+ if (end === lines.length) {
86
+ return text;
87
+ }
88
+ return lines
89
+ .slice(0, end)
90
+ .map((line) => `${line}\n`)
91
+ .join('');
92
+ }
93
+
94
+ /* The fence a line leaves open: it opens one, closes the one that is open, or changes nothing. */
95
+ function nextFence(fence: OpenFence | null, line: string): OpenFence | null {
96
+ const match = FENCE.exec(line);
97
+ if (!match) {
98
+ return fence;
99
+ }
100
+ const indent = match[1]!.length;
101
+ const run = match[2]!;
102
+ const rest = match[3]!;
103
+ if (fence === null) {
104
+ // A backtick fence's info string may not hold a backtick, or the line is inline code.
105
+ if (run[0] === '`' && rest.includes('`')) {
106
+ return null;
107
+ }
108
+ return { marker: run[0]!, length: run.length, indent };
109
+ }
110
+ // A closing fence carries no info string, and a line far deeper than the opening is code.
111
+ if (run[0] === fence.marker && run.length >= fence.length && BLANK.test(rest) && indent <= fence.indent + CLOSING_INDENT) {
112
+ return null;
113
+ }
114
+ return fence;
115
+ }
116
+
117
+ function isFenceOpenAtEnd(text: string): boolean {
118
+ let fence: OpenFence | null = null;
119
+ for (const line of text.split('\n')) {
120
+ fence = nextFence(fence, line);
121
+ }
122
+ return fence !== null;
123
+ }
@@ -0,0 +1,53 @@
1
+ import { createContext } from 'react';
2
+ import { quoteOf } from '../quote';
3
+
4
+ /* The text of an answer (`rows/MessageRows.tsx`), the only part of a thread a selection quotes from. */
5
+ const ANSWER = '[data-quote-answer]';
6
+
7
+ export type QuoteTaker = (quote: string) => void;
8
+
9
+ /* Registers the composer below a thread as the one its quote button hands a quote to, until the returned call. */
10
+ export const QuoteTakerContext = createContext<((take: QuoteTaker) => () => void) | null>(null);
11
+
12
+ function answerAt(node: Node): Element | null {
13
+ return (node instanceof Element ? node : node.parentElement)?.closest(ANSWER) ?? null;
14
+ }
15
+
16
+ /*
17
+ * Whether the range selects text a person can see outside the answer. A triple-click on a paragraph
18
+ * ends at the start of the next row, past a heading only a screen reader reads, and still means the
19
+ * paragraph alone.
20
+ */
21
+ function selectsOutside(range: Range, answer: Element): boolean {
22
+ const walker = document.createTreeWalker(range.commonAncestorContainer, NodeFilter.SHOW_TEXT);
23
+ for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
24
+ if (!range.intersectsNode(node) || answer.contains(node)) {
25
+ continue;
26
+ }
27
+ const text = node.textContent ?? '';
28
+ const start = node === range.startContainer ? range.startOffset : 0;
29
+ const end = node === range.endContainer ? range.endOffset : text.length;
30
+ const parent = node.parentElement;
31
+ if (text.slice(start, end).trim() !== '' && parent !== null && getComputedStyle(parent).userSelect !== 'none') {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }
37
+
38
+ /* The quote the selection makes, when it lies in one answer of this thread. */
39
+ export function selectedAnswerQuote(selection: Selection | null, thread: HTMLElement | null): string | null {
40
+ if (thread === null || selection === null || selection.isCollapsed || selection.rangeCount === 0) {
41
+ return null;
42
+ }
43
+ const range = selection.getRangeAt(0);
44
+ const answer = answerAt(range.startContainer) ?? answerAt(range.endContainer);
45
+ if (answer === null || !thread.contains(answer)) {
46
+ return null;
47
+ }
48
+ const inside = answer.contains(range.startContainer) && answer.contains(range.endContainer);
49
+ if (!inside && selectsOutside(range, answer)) {
50
+ return null;
51
+ }
52
+ return quoteOf(selection.toString());
53
+ }
@@ -0,0 +1,62 @@
1
+ import { chipText, tokenizeChips, type ChipSegment } from '../mentions';
2
+
3
+ /* Just the part of hast this plugin touches; the package's own types are not a dependency of the client. */
4
+ interface HastText {
5
+ type: 'text';
6
+ value: string;
7
+ }
8
+
9
+ interface HastElement {
10
+ type: 'element';
11
+ tagName: string;
12
+ properties: Record<string, unknown>;
13
+ children: HastNode[];
14
+ }
15
+
16
+ type HastNode = HastText | HastElement | { type: 'comment' | 'doctype' | 'raw'; value?: string };
17
+
18
+ interface HastParent {
19
+ children: HastNode[];
20
+ }
21
+
22
+ export interface ChipOptions {
23
+ mentions?: string[];
24
+ skills?: string[];
25
+ }
26
+
27
+ // Inline code overrules a chip: `@a.ts` between backticks is code, not a mention.
28
+ const SKIPPED = new Set(['code', 'pre']);
29
+
30
+ /* A chip as an element: the renderer reads `data-chip` and `data-value`, the text keeps the sigil. */
31
+ function chipElement(segment: Exclude<ChipSegment, { kind: 'text' }>): HastElement {
32
+ return {
33
+ type: 'element',
34
+ tagName: 'span',
35
+ properties: { dataChip: segment.kind, dataValue: segment.kind === 'mention' ? segment.path : segment.name },
36
+ children: [{ type: 'text', value: chipText(segment) }]
37
+ };
38
+ }
39
+
40
+ function split(parent: HastParent, mentions: string[], skills: string[]): void {
41
+ parent.children = parent.children.flatMap((child): HastNode[] => {
42
+ if (child.type === 'text') {
43
+ return tokenizeChips(child.value, mentions, skills).map((segment) =>
44
+ segment.kind === 'text' ? { type: 'text', value: segment.text } : chipElement(segment)
45
+ );
46
+ }
47
+ if (child.type === 'element' && !SKIPPED.has(child.tagName)) {
48
+ split(child, mentions, skills);
49
+ }
50
+ return [child];
51
+ });
52
+ }
53
+
54
+ /* The `@path` and `$name` tokens a person picked in the composer, cut out of the text as chips. */
55
+ export function rehypeChips({ mentions = [], skills = [] }: ChipOptions = {}) {
56
+ return (tree: HastParent) => {
57
+ if (mentions.length === 0 && skills.length === 0) {
58
+ return;
59
+ }
60
+ split(tree, mentions, skills);
61
+ };
62
+ }
@@ -0,0 +1,64 @@
1
+ /* Just the part of hast this plugin touches; the package's own types are not a dependency of the client. */
2
+ interface HastText {
3
+ type: 'text';
4
+ value: string;
5
+ }
6
+
7
+ interface HastElement {
8
+ type: 'element';
9
+ tagName: string;
10
+ properties: Record<string, unknown>;
11
+ children: HastNode[];
12
+ }
13
+
14
+ type HastNode = HastText | HastElement | { type: 'comment' | 'doctype' | 'raw'; value?: string };
15
+
16
+ interface HastParent {
17
+ children: HastNode[];
18
+ }
19
+
20
+ export const FADE_CLASS = 'chat-fade';
21
+
22
+ // A reply written out of sight, which appears in one piece rather than a word at a time.
23
+ export const WHOLE_FADE_CLASS = 'chat-fade-whole';
24
+
25
+ // Code is read as one string by the renderer, so a span inside it would come out as "[object Object]".
26
+ const SKIPPED = new Set(['code', 'pre']);
27
+
28
+ const WHITESPACE = /^\s+$/;
29
+
30
+ /* A text cut into its words and the whitespace between them, in order. */
31
+ export function wordSegments(text: string): string[] {
32
+ return text.split(/(\s+)/).filter((segment) => segment !== '');
33
+ }
34
+
35
+ export function isWhitespace(segment: string): boolean {
36
+ return WHITESPACE.test(segment);
37
+ }
38
+
39
+ function wrap(parent: HastParent): void {
40
+ parent.children = parent.children.flatMap((child): HastNode[] => {
41
+ if (child.type === 'text') {
42
+ return wordSegments(child.value).map((segment) =>
43
+ isWhitespace(segment)
44
+ ? { type: 'text', value: segment }
45
+ : { type: 'element', tagName: 'span', properties: { className: [FADE_CLASS] }, children: [{ type: 'text', value: segment }] }
46
+ );
47
+ }
48
+ if (child.type === 'element' && !SKIPPED.has(child.tagName)) {
49
+ wrap(child);
50
+ }
51
+ return [child];
52
+ });
53
+ }
54
+
55
+ /*
56
+ * Every word of a reply that is still streaming in a span that fades in. Words only ever arrive at
57
+ * the end, and the renderer keys a span by its place among the spans beside it, so the spans already
58
+ * on screen keep their element and their fade does not start again.
59
+ */
60
+ export function rehypeFadeWords() {
61
+ return (tree: HastParent) => {
62
+ wrap(tree);
63
+ };
64
+ }
@@ -0,0 +1,36 @@
1
+ /* Just the part of mdast this plugin touches; the package's own types are not a dependency of the client. */
2
+ interface MdastNode {
3
+ type: string;
4
+ value?: string;
5
+ children?: MdastNode[];
6
+ position?: unknown;
7
+ }
8
+
9
+ // Parents whose children are blocks, where a bare text node would stand outside any paragraph.
10
+ const FLOW_PARENTS = new Set(['root', 'blockquote', 'listItem', 'footnoteDefinition']);
11
+
12
+ function literal(parent: MdastNode): void {
13
+ if (parent.children === undefined) {
14
+ return;
15
+ }
16
+ const flow = FLOW_PARENTS.has(parent.type);
17
+ parent.children = parent.children.map((child): MdastNode => {
18
+ if (child.type !== 'html') {
19
+ literal(child);
20
+ return child;
21
+ }
22
+ const text = { ...child, type: 'text' };
23
+ return flow ? { type: 'paragraph', position: child.position, children: [text] } : text;
24
+ });
25
+ }
26
+
27
+ /*
28
+ * Raw HTML in a message as the characters a person typed. react-markdown drops an `html` node, so
29
+ * "the <span> element" without backticks would lose the tag. Runs before `remark-breaks`, so the
30
+ * newlines of an HTML block still become line breaks.
31
+ */
32
+ export function remarkHtmlAsText() {
33
+ return (tree: MdastNode) => {
34
+ literal(tree);
35
+ };
36
+ }
@@ -0,0 +1,4 @@
1
+ import { createContext } from 'react';
2
+ import type { ChatInfo } from '@adecore/agent-contracts';
3
+
4
+ export const ReplyContext = createContext<{ provider: ChatInfo['provider']; chatId?: string } | null>(null);