@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,148 @@
1
+ import i18next from 'i18next';
2
+ /* The providers whose chat a machine can fork, and go on with in a fork, are the ones with a conversation the CLI keeps. */
3
+ export const FORKABLE_PROVIDERS = new Set(['claude', 'codex']);
4
+ function turnsOf(items, order) {
5
+ return order.flatMap((id) => {
6
+ const item = items[id];
7
+ return item?.kind === 'turn' ? [item] : [];
8
+ });
9
+ }
10
+ /*
11
+ * Why a chat cannot be forked after this turn right now, or null when it can. A turn still running,
12
+ * or any turn in the chat, is a transcript that grows while it would be copied.
13
+ */
14
+ export function forkRefusal(info, turn) {
15
+ if (info === null || turn?.kind !== 'turn') {
16
+ return i18next.t('agent-chat:fork.refusal.notInConversation');
17
+ }
18
+ if (!FORKABLE_PROVIDERS.has(info.provider)) {
19
+ return i18next.t('agent-chat:fork.refusal.cliCannotFork');
20
+ }
21
+ if (info.agentSessionId === null) {
22
+ return i18next.t('agent-chat:fork.refusal.noConversation');
23
+ }
24
+ if (turn.state === 'running' || info.activeTurnId !== null) {
25
+ return i18next.t('agent-chat:fork.refusal.turnRunning');
26
+ }
27
+ return null;
28
+ }
29
+ /* Why a fork cannot write a summary for its original right now, or null when it can. */
30
+ export function summaryRefusal(state) {
31
+ if (!state.originalPresent) {
32
+ return i18next.t('agent-chat:fork.refusal.originalGone');
33
+ }
34
+ if (state.busy) {
35
+ return i18next.t('agent-chat:fork.refusal.turnRunning');
36
+ }
37
+ return null;
38
+ }
39
+ /* The forks this client knows of that went on after this turn of this chat, in the order it holds them. */
40
+ export function forkIdsAfter(infos, chatId, turnId) {
41
+ const ids = [];
42
+ for (const info of infos) {
43
+ if (info.forkOf?.chatId === chatId && info.forkOf.turnId === turnId) {
44
+ ids.push(info.chatId);
45
+ }
46
+ }
47
+ return ids;
48
+ }
49
+ /* The turns of this chat that at least one fork this client knows of went on after. */
50
+ export function forkedTurnIds(infos, chatId) {
51
+ const turns = new Set();
52
+ for (const info of infos) {
53
+ if (info.forkOf?.chatId === chatId) {
54
+ turns.add(info.forkOf.turnId);
55
+ }
56
+ }
57
+ return turns;
58
+ }
59
+ /* The last turn that ended, which is where a fork from the node's menu goes on after. */
60
+ export function lastSettledTurn(items, order) {
61
+ return turnsOf(items, order).findLast((turn) => turn.state !== 'running')?.id ?? null;
62
+ }
63
+ export function forkPointOf(items, order, turnId, whole) {
64
+ const turns = turnsOf(items, order);
65
+ const index = turns.findIndex((turn) => turn.id === turnId);
66
+ const turn = turns[index];
67
+ if (turn === undefined) {
68
+ return null;
69
+ }
70
+ const asked = order.map((id) => items[id]).find((item) => item?.kind === 'user' && item.turnId === turnId);
71
+ const text = asked?.kind === 'user' ? asked.text : (turn.label ?? '');
72
+ const prompt = text
73
+ .split('\n')
74
+ .find((line) => line.trim() !== '')
75
+ ?.trim() ?? null;
76
+ return { turnId, number: index + 1, total: turns.length, counted: whole, last: index === turns.length - 1, prompt };
77
+ }
78
+ /* The line at the top of the dialog: which turn, and what it was about. */
79
+ export function forkPointLabel(point, maxPrompt = 60) {
80
+ const where = point.last
81
+ ? i18next.t('agent-chat:fork.point.afterLast')
82
+ : point.counted
83
+ ? i18next.t('agent-chat:fork.point.afterTurn', { number: point.number, total: point.total })
84
+ : i18next.t('agent-chat:fork.point.afterThis');
85
+ if (point.prompt === null) {
86
+ return where;
87
+ }
88
+ const prompt = point.prompt.length > maxPrompt ? `${point.prompt.slice(0, maxPrompt - 1)}…` : point.prompt;
89
+ return i18next.t('agent-chat:fork.point.about', { where, prompt });
90
+ }
91
+ /* The turn a row of the thread belongs to, which is the turn "Fork from here" on that row goes on after. */
92
+ export function turnIdOfRow(row) {
93
+ switch (row.kind) {
94
+ case 'turn-start':
95
+ case 'turn-fold':
96
+ return row.turn.id;
97
+ case 'changed-files':
98
+ case 'forks':
99
+ return row.turnId;
100
+ case 'work':
101
+ case 'work-live':
102
+ case 'workflow':
103
+ return row.tool.turnId;
104
+ case 'work-group':
105
+ return row.tools[0]?.turnId ?? null;
106
+ case 'user':
107
+ case 'assistant':
108
+ case 'thinking':
109
+ case 'subagent':
110
+ case 'approval':
111
+ case 'question':
112
+ return row.item.turnId;
113
+ default:
114
+ return null;
115
+ }
116
+ }
117
+ /* What the dialog offers, first the default: a view forks into a view, and a node into a node or, when asked, a view. */
118
+ export function forkShapes(origin) {
119
+ return origin === 'view' ? ['view'] : ['node', 'view'];
120
+ }
121
+ export function forkPayload(input) {
122
+ return {
123
+ chatId: input.chatId,
124
+ turnId: input.turnId,
125
+ title: input.title,
126
+ ...(input.shape === 'view' ? { asView: true } : {}),
127
+ ...(input.cli && input.cli.chosen.provider !== input.cli.original.provider ? { provider: input.cli.chosen.provider } : {}),
128
+ ...(input.cli && (input.cli.chosen.provider !== input.cli.original.provider || input.cli.chosen.selection.model !== input.cli.original.selection.model)
129
+ ? { selection: input.cli.chosen.selection }
130
+ : {}),
131
+ ...(input.cli?.chosen.account !== undefined &&
132
+ (input.cli.chosen.provider !== input.cli.original.provider || input.cli.chosen.account !== input.cli.original.account)
133
+ ? { account: input.cli.chosen.account }
134
+ : {}),
135
+ ...(input.worktree ? { worktree: { branch: input.worktree.branch }, ...(input.worktree.filesAfterTurn ? { filesAfterTurn: true } : {}) } : {})
136
+ };
137
+ }
138
+ /* Why a branch cannot be the fork's, or null when it can. */
139
+ export function branchRefusal(branch, taken) {
140
+ const name = branch.trim();
141
+ if (name === '') {
142
+ return i18next.t('agent-chat:fork.branch.unnamed');
143
+ }
144
+ if (taken.includes(name)) {
145
+ return i18next.t('agent-chat:fork.branch.taken');
146
+ }
147
+ return null;
148
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatItem } from '@adecore/agent-contracts';
2
+ export declare function handbackReportOf(item: ChatItem): string | null;
@@ -0,0 +1,8 @@
1
+ /* The report a `SubagentHandback` call carries in `input.message` (Claude Code 2.1.273), or null for any other item. */
2
+ export function handbackReportOf(item) {
3
+ if (item.kind !== 'tool' || item.name !== 'SubagentHandback' || typeof item.input !== 'object' || item.input === null) {
4
+ return null;
5
+ }
6
+ const message = item.input.message;
7
+ return typeof message === 'string' && message.trim() !== '' ? message : null;
8
+ }
@@ -0,0 +1 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,4 @@
1
+ /* A plain object, which is what a tool's input and a stored record are and an array is not. */
2
+ export function isRecord(value) {
3
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
4
+ }
@@ -0,0 +1,7 @@
1
+ import type { ChatInfo } from '@adecore/agent-contracts';
2
+ export interface LimitView {
3
+ pill: string;
4
+ title: string;
5
+ detail: string | null;
6
+ }
7
+ export declare function limitView(info: Pick<ChatInfo, 'limit' | 'resumeAt' | 'activeTurnId'>, now: number): LimitView | null;
@@ -0,0 +1,34 @@
1
+ import i18next from 'i18next';
2
+ import { formatMoment } from '@adecore/ui/format';
3
+ /*
4
+ * What a chat that stopped on a limit says about it, from its info alone, so a header that never holds
5
+ * the thread says the same as the chat. Null while the last turn stopped on nothing, or a turn runs.
6
+ */
7
+ export function limitView(info, now) {
8
+ const limit = info.limit;
9
+ if (limit === undefined || info.activeTurnId !== null) {
10
+ return null;
11
+ }
12
+ const resumes = info.resumeAt === undefined ? null : formatMoment(info.resumeAt, now);
13
+ if (limit.kind === 'overload') {
14
+ return {
15
+ pill: resumes === null ? i18next.t('agent-chat:limit.overload.pill') : i18next.t('agent-chat:limit.overload.pillRetry', { time: resumes }),
16
+ title: i18next.t('agent-chat:limit.overload.title'),
17
+ detail: resumes === null ? i18next.t('agent-chat:limit.overload.sendAgain') : i18next.t('agent-chat:limit.overload.retries', { time: resumes })
18
+ };
19
+ }
20
+ const resets = limit.resetsAt === undefined ? null : formatMoment(limit.resetsAt, now);
21
+ return {
22
+ pill: resumes !== null
23
+ ? i18next.t('agent-chat:limit.usage.pillResumes', { time: resumes })
24
+ : resets !== null
25
+ ? i18next.t('agent-chat:limit.usage.pillUntil', { time: resets })
26
+ : i18next.t('agent-chat:limit.usage.pill'),
27
+ title: i18next.t('agent-chat:limit.usage.title'),
28
+ detail: resumes !== null
29
+ ? i18next.t('agent-chat:limit.usage.resumes', { time: resumes })
30
+ : resets !== null
31
+ ? i18next.t('agent-chat:limit.usage.resets', { time: resets })
32
+ : null
33
+ };
34
+ }
@@ -0,0 +1,14 @@
1
+ import type { ChatInfo, ChatItem, ProviderCapabilities } from '@adecore/agent-contracts';
2
+ export declare const RESUME_COMPACTION_TOKENS = 100000;
3
+ export declare const RESUME_COMPACTION_IDLE_MS: number;
4
+ export interface ResumeCompactionOffer {
5
+ turnId: string;
6
+ tokens: number;
7
+ }
8
+ export declare function resumeCompactionOffer({ info, compaction, items, dismissedTurnId, now }: {
9
+ info: ChatInfo;
10
+ compaction: ProviderCapabilities['compaction'] | undefined;
11
+ items: readonly ChatItem[];
12
+ dismissedTurnId: string | null;
13
+ now: number;
14
+ }): ResumeCompactionOffer | null;
@@ -0,0 +1,47 @@
1
+ /*
2
+ * An absolute count, not a share of the window: reading a thread again costs per token, so 100k in a
3
+ * window of 1M is as expensive as 100k in a window of 200k.
4
+ */
5
+ export const RESUME_COMPACTION_TOKENS = 100_000;
6
+ /* The longest prompt cache Claude keeps is an hour, so past this the whole thread is read again anyway. */
7
+ export const RESUME_COMPACTION_IDLE_MS = 70 * 60_000;
8
+ function lastTurn(items) {
9
+ for (let i = items.length - 1; i >= 0; i--) {
10
+ const item = items[i];
11
+ if (item.kind === 'turn') {
12
+ return item;
13
+ }
14
+ }
15
+ return null;
16
+ }
17
+ /*
18
+ * Whether to offer compacting before the next message. The caller passes `now`, so this stays pure
19
+ * and the test needs no clock.
20
+ */
21
+ export function resumeCompactionOffer({ info, compaction, items, dismissedTurnId, now }) {
22
+ if (compaction === undefined || compaction === 'none') {
23
+ return null;
24
+ }
25
+ if (info.activeTurnId !== null || (info.queue ?? []).length > 0) {
26
+ return null;
27
+ }
28
+ if (info.usage.contextTokens < RESUME_COMPACTION_TOKENS) {
29
+ return null;
30
+ }
31
+ const turn = lastTurn(items);
32
+ if (turn === null || turn.endedAt === null || turn.id === dismissedTurnId) {
33
+ return null;
34
+ }
35
+ if (now - turn.endedAt < RESUME_COMPACTION_IDLE_MS) {
36
+ return null;
37
+ }
38
+ /*
39
+ * `contextTokens` keeps the old number until the next request, so without this the offer would
40
+ * come straight back after a compaction. A native compaction is a turn without a message of the
41
+ * person, which is why this looks at the turn and not at the last thing that was said.
42
+ */
43
+ if (items.some((item) => item.kind === 'compaction' && item.turnId === turn.id)) {
44
+ return null;
45
+ }
46
+ return { turnId: turn.id, tokens: info.usage.contextTokens };
47
+ }
@@ -0,0 +1,50 @@
1
+ import type { ChatBookmark } from '@adecore/agent-contracts';
2
+ import type { TimelineRow } from './timeline.js';
3
+ export type TickKind = 'person' | 'wake' | 'bookmark';
4
+ export interface ScrubberTick {
5
+ id: string;
6
+ rowIndex: number;
7
+ kind: TickKind;
8
+ text: string;
9
+ createdAt: number;
10
+ turnId: string | null;
11
+ bookmark: ChatBookmark | null;
12
+ }
13
+ export declare const SCRUBBER_MIN_TICKS = 3;
14
+ export declare const TICK_HEIGHT_PX = 2;
15
+ export declare const STRIP_WIDTH_PX = 24;
16
+ export declare const STRIP_INSET_PX = 8;
17
+ export declare function ticksOf(rows: readonly TimelineRow[], marks?: ReadonlyMap<string, ChatBookmark>): ScrubberTick[];
18
+ export interface TickSlot {
19
+ first: number;
20
+ last: number;
21
+ kind: TickKind;
22
+ marked: boolean;
23
+ found: boolean;
24
+ y: number;
25
+ }
26
+ export interface ScrubberLayout {
27
+ top: number;
28
+ pitch: number;
29
+ count: number;
30
+ slots: TickSlot[];
31
+ }
32
+ export declare function layoutTicks(kinds: readonly TickKind[], height: number, marked?: readonly boolean[], found?: readonly boolean[]): ScrubberLayout;
33
+ export declare function tickOfRow(ticks: readonly ScrubberTick[], rowIndex: number): number | null;
34
+ export declare function ticksWithHits(ticks: readonly ScrubberTick[], hitRows: readonly number[]): boolean[];
35
+ export declare function messageAt(layout: ScrubberLayout, y: number): number | null;
36
+ export declare function slotOf(layout: ScrubberLayout, message: number): number | null;
37
+ export declare function tickWidth(kind: TickKind, distanceFromPointer: number | null): number;
38
+ export interface ReadingPosition {
39
+ starts: readonly number[];
40
+ scrollTop: number;
41
+ visibleHeight: number;
42
+ }
43
+ export interface MessageRange {
44
+ first: number;
45
+ last: number;
46
+ }
47
+ export declare function messagesInView({ starts, scrollTop, visibleHeight }: ReadingPosition): MessageRange | null;
48
+ export declare function slotInView(slot: TickSlot, range: MessageRange | null): boolean;
49
+ export declare function stepMessage(starts: readonly number[], eligible: (index: number) => boolean, scrollTop: number, direction: -1 | 1): number | null;
50
+ export declare function threadPaddingLeft(width: number, strip: boolean): number;
@@ -0,0 +1,220 @@
1
+ /* With fewer messages than this the thread is short enough to scroll through, and the strip is noise. */
2
+ export const SCRUBBER_MIN_TICKS = 3;
3
+ export const TICK_HEIGHT_PX = 2;
4
+ const PITCH_PX = 8;
5
+ const MIN_PITCH_PX = 4;
6
+ /* The thread's content column in a view of its own (`.chat-column-content`) and the scroller's padding around it (`px-4`). */
7
+ const CONTENT_MAX_WIDTH_PX = 768;
8
+ const THREAD_PADDING_PX = 16;
9
+ export const STRIP_WIDTH_PX = 24;
10
+ /* The strip's distance from the view's left edge, and the air it keeps between itself and the thread's text. */
11
+ export const STRIP_INSET_PX = 8;
12
+ const STRIP_CLEARANCE_PX = STRIP_INSET_PX + STRIP_WIDTH_PX + STRIP_INSET_PX;
13
+ const WIDTH_HOVERED_PX = 16;
14
+ const WIDTH_NEAR_PERSON_PX = 12;
15
+ const WIDTH_NEAR_WAKE_PX = 8;
16
+ const WIDTH_PERSON_PX = 8;
17
+ const WIDTH_WAKE_PX = 5;
18
+ /* `marks` is what `bookmarkRows` answers: the bookmark drawn at a row, by row id. */
19
+ export function ticksOf(rows, marks = new Map()) {
20
+ return rows.flatMap((row, rowIndex) => {
21
+ const bookmark = marks.get(row.id) ?? null;
22
+ if (row.kind === 'user') {
23
+ // A message of only attachments still has a place in the thread; its names stand in for the text.
24
+ const text = row.item.text !== '' ? row.item.text : (row.item.attachments ?? []).map((attachment) => attachment.name).join(', ');
25
+ return [{ id: row.id, rowIndex, kind: 'person', text, createdAt: row.item.createdAt, turnId: row.item.turnId, bookmark }];
26
+ }
27
+ // The other turns nobody asked for (a sub-agent that finished, the CLI going on) are no place to return to.
28
+ if (row.kind === 'turn-start' && ((row.turn.taskIds?.length ?? 0) > 0 || (row.turn.messageFrom?.length ?? 0) > 0)) {
29
+ return [{ id: row.id, rowIndex, kind: 'wake', text: row.label, createdAt: row.turn.createdAt, turnId: row.turn.id, bookmark: null }];
30
+ }
31
+ if (bookmark === null) {
32
+ return [];
33
+ }
34
+ if (row.kind === 'assistant') {
35
+ return [{ id: row.id, rowIndex, kind: 'bookmark', text: row.item.text, createdAt: row.item.createdAt, turnId: row.item.turnId, bookmark }];
36
+ }
37
+ // The fold of a turn a marked reply is hidden in; the card reads the start the bookmark kept.
38
+ const turnId = row.kind === 'turn-fold' ? row.turn.id : null;
39
+ return [{ id: row.id, rowIndex, kind: 'bookmark', text: bookmark.excerpt, createdAt: bookmark.createdAt, turnId, bookmark }];
40
+ });
41
+ }
42
+ /* `marked` and `found` say per message whether it has a bookmark and whether a find hit falls under it; absent, none has. */
43
+ export function layoutTicks(kinds, height, marked = [], found = []) {
44
+ const count = kinds.length;
45
+ const room = Math.max(0, Math.floor(height));
46
+ const slotCount = Math.min(count, Math.floor(room / MIN_PITCH_PX));
47
+ if (slotCount === 0) {
48
+ return { top: 0, pitch: MIN_PITCH_PX, count, slots: [] };
49
+ }
50
+ const pitch = Math.min(PITCH_PX, Math.floor(room / slotCount));
51
+ const top = Math.floor((room - slotCount * pitch) / 2);
52
+ const inset = Math.floor((pitch - TICK_HEIGHT_PX) / 2);
53
+ const slots = [];
54
+ for (let i = 0; i < slotCount; i++) {
55
+ const first = Math.floor((i * count) / slotCount);
56
+ const last = Math.floor(((i + 1) * count) / slotCount) - 1;
57
+ // A merged tick is the person's as soon as one message in it is, since those are what the strip is for.
58
+ const run = kinds.slice(first, last + 1);
59
+ const kind = run.includes('person') ? 'person' : run.includes('bookmark') ? 'bookmark' : 'wake';
60
+ slots.push({
61
+ first,
62
+ last,
63
+ kind,
64
+ marked: marked.slice(first, last + 1).includes(true),
65
+ found: found.slice(first, last + 1).includes(true),
66
+ y: top + i * pitch + inset
67
+ });
68
+ }
69
+ return { top, pitch, count, slots };
70
+ }
71
+ /*
72
+ * The tick whose stretch of the thread a row falls in: a tick stands for its row and every row up to
73
+ * the next tick's, and a row above the first tick counts under the first. Null without ticks.
74
+ */
75
+ export function tickOfRow(ticks, rowIndex) {
76
+ if (ticks.length === 0) {
77
+ return null;
78
+ }
79
+ let low = 0;
80
+ let high = ticks.length - 1;
81
+ let found = 0;
82
+ while (low <= high) {
83
+ const middle = (low + high) >> 1;
84
+ if (ticks[middle].rowIndex <= rowIndex) {
85
+ found = middle;
86
+ low = middle + 1;
87
+ }
88
+ else {
89
+ high = middle - 1;
90
+ }
91
+ }
92
+ return found;
93
+ }
94
+ /* Per tick, whether any of the rows has a find hit in its stretch. */
95
+ export function ticksWithHits(ticks, hitRows) {
96
+ const found = ticks.map(() => false);
97
+ for (const row of hitRows) {
98
+ const tick = tickOfRow(ticks, row);
99
+ if (tick !== null) {
100
+ found[tick] = true;
101
+ }
102
+ }
103
+ return found;
104
+ }
105
+ /* The message under a height in the strip; inside a merged tick the height picks among its messages. */
106
+ export function messageAt(layout, y) {
107
+ const { slots, top, pitch } = layout;
108
+ if (slots.length === 0) {
109
+ return null;
110
+ }
111
+ const offset = y - top;
112
+ const index = Math.min(slots.length - 1, Math.max(0, Math.floor(offset / pitch)));
113
+ const slot = slots[index];
114
+ const fraction = Math.min(1, Math.max(0, (offset - index * pitch) / pitch));
115
+ return slot.first + Math.min(slot.last - slot.first, Math.floor(fraction * (slot.last - slot.first + 1)));
116
+ }
117
+ export function slotOf(layout, message) {
118
+ const { slots } = layout;
119
+ let low = 0;
120
+ let high = slots.length - 1;
121
+ while (low <= high) {
122
+ const middle = (low + high) >> 1;
123
+ const slot = slots[middle];
124
+ if (message < slot.first) {
125
+ high = middle - 1;
126
+ }
127
+ else if (message > slot.last) {
128
+ low = middle + 1;
129
+ }
130
+ else {
131
+ return middle;
132
+ }
133
+ }
134
+ return null;
135
+ }
136
+ /*
137
+ * At rest every tick of a kind is as long as the next, so length never competes with the brightness
138
+ * that says what is on screen. Only a pointer on the strip magnifies, the way a dock does, one step out.
139
+ */
140
+ export function tickWidth(kind, distanceFromPointer) {
141
+ if (distanceFromPointer === 0) {
142
+ return WIDTH_HOVERED_PX;
143
+ }
144
+ if (distanceFromPointer === 1) {
145
+ return kind === 'wake' ? WIDTH_NEAR_WAKE_PX : WIDTH_NEAR_PERSON_PX;
146
+ }
147
+ return kind === 'wake' ? WIDTH_WAKE_PX : WIDTH_PERSON_PX;
148
+ }
149
+ /* The last index whose start lies at or above a line, or -1. The starts only grow. */
150
+ function lastAtOrAbove(starts, line) {
151
+ let low = 0;
152
+ let high = starts.length - 1;
153
+ let found = -1;
154
+ while (low <= high) {
155
+ const middle = (low + high) >> 1;
156
+ if (starts[middle] <= line) {
157
+ found = middle;
158
+ low = middle + 1;
159
+ }
160
+ else {
161
+ high = middle - 1;
162
+ }
163
+ }
164
+ return found;
165
+ }
166
+ /*
167
+ * The messages on screen. A message counts from its own start to the start of the next one, so the
168
+ * question whose answer fills the screen is in view even after it scrolled out at the top.
169
+ */
170
+ export function messagesInView({ starts, scrollTop, visibleHeight }) {
171
+ const bottom = scrollTop + visibleHeight;
172
+ if (starts.length === 0 || visibleHeight <= 0 || starts[0] >= bottom) {
173
+ return null;
174
+ }
175
+ const first = Math.max(0, lastAtOrAbove(starts, scrollTop));
176
+ let last = lastAtOrAbove(starts, bottom);
177
+ // A row that starts on the very last line has not a pixel on screen yet.
178
+ if (starts[last] >= bottom) {
179
+ last--;
180
+ }
181
+ return { first, last: Math.max(first, last) };
182
+ }
183
+ /* Whether a drawn tick covers any of the messages on screen. */
184
+ export function slotInView(slot, range) {
185
+ return range !== null && slot.last >= range.first && slot.first <= range.last;
186
+ }
187
+ /*
188
+ * The message a step back or forward lands on, among the ones `eligible` allows. A jump puts a
189
+ * message's start at the top, so back from there is the one before it, and back from the middle of
190
+ * a long answer is the question it belongs to. A pixel of slack absorbs rounding in the scroller.
191
+ */
192
+ export function stepMessage(starts, eligible, scrollTop, direction) {
193
+ if (direction === -1) {
194
+ for (let i = lastAtOrAbove(starts, scrollTop - 1.5); i >= 0; i--) {
195
+ if (eligible(i)) {
196
+ return i;
197
+ }
198
+ }
199
+ return null;
200
+ }
201
+ for (let i = lastAtOrAbove(starts, scrollTop + 1) + 1; i < starts.length; i++) {
202
+ if (eligible(i)) {
203
+ return i;
204
+ }
205
+ }
206
+ return null;
207
+ }
208
+ /*
209
+ * The left padding of the thread in a view that draws the strip at its left edge. A wide view keeps
210
+ * the usual padding, since its centered column already clears the strip; a narrower one pads until
211
+ * the column's text starts clear of it, so nothing is ever drawn under the strip.
212
+ */
213
+ export function threadPaddingLeft(width, strip) {
214
+ if (!strip) {
215
+ return THREAD_PADDING_PX;
216
+ }
217
+ // The column's margin is half of what the padding leaves, so the padding counts the clearance twice.
218
+ const padding = 2 * STRIP_CLEARANCE_PX + CONTENT_MAX_WIDTH_PX + THREAD_PADDING_PX - Math.floor(width);
219
+ return Math.min(STRIP_CLEARANCE_PX, Math.max(THREAD_PADDING_PX, padding));
220
+ }
@@ -0,0 +1,3 @@
1
+ import type { ThreadCard } from '../../host.js';
2
+ import type { TimelineRow } from './timeline.js';
3
+ export declare function withThreadCards(rows: TimelineRow[], cards: readonly ThreadCard[]): TimelineRow[];
@@ -0,0 +1,59 @@
1
+ /*
2
+ * When what a row shows began, or null for a row that only follows the one before it: a turn's
3
+ * changed files and forks, a note, a report. The working row closes the thread, so every card goes
4
+ * above it.
5
+ */
6
+ function rowTime(row) {
7
+ switch (row.kind) {
8
+ case 'user':
9
+ case 'assistant':
10
+ case 'thinking':
11
+ case 'approval':
12
+ case 'question':
13
+ case 'subagent':
14
+ return row.item.createdAt;
15
+ case 'turn-start':
16
+ case 'turn-fold':
17
+ return row.turn.createdAt;
18
+ case 'work':
19
+ case 'work-live':
20
+ case 'workflow':
21
+ return row.tool.createdAt;
22
+ case 'work-group':
23
+ return row.tools[0]?.createdAt ?? null;
24
+ case 'working':
25
+ return Number.POSITIVE_INFINITY;
26
+ default:
27
+ return null;
28
+ }
29
+ }
30
+ /* Prefixed, so a card never shares a key with a row of the chat's own. */
31
+ function cardRow(card) {
32
+ return { kind: 'app-card', id: `app-card-${card.id}`, card };
33
+ }
34
+ /*
35
+ * The thread's rows with an app's cards among them: a card goes right before the first row that
36
+ * began after it, so in a folded turn it lands under the fold, and in an open one between its calls.
37
+ * Without cards the rows come back as they are, the same array.
38
+ */
39
+ export function withThreadCards(rows, cards) {
40
+ if (cards.length === 0) {
41
+ return rows;
42
+ }
43
+ // Sorting is stable, so cards of the same moment keep the order the app gave them.
44
+ const pending = [...cards].sort((first, second) => first.at - second.at);
45
+ const merged = [];
46
+ let next = 0;
47
+ for (const row of rows) {
48
+ const time = rowTime(row);
49
+ while (time !== null && next < pending.length && pending[next].at < time) {
50
+ merged.push(cardRow(pending[next]));
51
+ next += 1;
52
+ }
53
+ merged.push(row);
54
+ }
55
+ for (; next < pending.length; next++) {
56
+ merged.push(cardRow(pending[next]));
57
+ }
58
+ return merged;
59
+ }
@@ -0,0 +1,4 @@
1
+ import type { TimelineRow } from './timeline.js';
2
+ export declare function stripMarkdown(text: string): string;
3
+ export declare function messageTextOf(row: TimelineRow): string | null;
4
+ export declare function markdownOf(row: TimelineRow): string | null;