@ruimte/agents-react 0.0.0 → 0.7.0

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 (312) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +142 -1
  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/ProviderLogo.d.ts +8 -0
  8. package/dist/agents/ProviderLogo.js +8 -0
  9. package/dist/agents/account-limits.d.ts +7 -0
  10. package/dist/agents/account-limits.js +26 -0
  11. package/dist/agents/accounts.d.ts +22 -0
  12. package/dist/agents/accounts.js +103 -0
  13. package/dist/agents/model-name.d.ts +6 -0
  14. package/dist/agents/model-name.js +44 -0
  15. package/dist/agents/provider-paths.d.ts +2 -0
  16. package/dist/agents/provider-paths.js +8 -0
  17. package/dist/agents/status-look.d.ts +13 -0
  18. package/dist/agents/status-look.js +22 -0
  19. package/dist/chat/account-choice.d.ts +11 -0
  20. package/dist/chat/account-choice.js +30 -0
  21. package/dist/chat/actions.d.ts +6 -0
  22. package/dist/chat/actions.js +64 -0
  23. package/dist/chat/activity.d.ts +5 -0
  24. package/dist/chat/activity.js +4 -0
  25. package/dist/chat/attachments.d.ts +23 -0
  26. package/dist/chat/attachments.js +70 -0
  27. package/dist/chat/bookmarks.d.ts +14 -0
  28. package/dist/chat/bookmarks.js +73 -0
  29. package/dist/chat/chat-client.d.ts +53 -0
  30. package/dist/chat/chat-client.js +232 -0
  31. package/dist/chat/chat-references.d.ts +5 -0
  32. package/dist/chat/chat-references.js +5 -0
  33. package/dist/chat/drafts.d.ts +29 -0
  34. package/dist/chat/drafts.js +104 -0
  35. package/dist/chat/forks.d.ts +2 -0
  36. package/dist/chat/forks.js +26 -0
  37. package/dist/chat/guards.d.ts +12 -0
  38. package/dist/chat/guards.js +63 -0
  39. package/dist/chat/logic/answers.d.ts +3 -0
  40. package/dist/chat/logic/answers.js +14 -0
  41. package/dist/chat/logic/bookmarks.d.ts +5 -0
  42. package/dist/chat/logic/bookmarks.js +31 -0
  43. package/dist/chat/logic/context-usage.d.ts +12 -0
  44. package/dist/chat/logic/context-usage.js +20 -0
  45. package/dist/chat/logic/fork.d.ts +44 -0
  46. package/dist/chat/logic/fork.js +138 -0
  47. package/dist/chat/logic/handback.d.ts +2 -0
  48. package/dist/chat/logic/handback.js +8 -0
  49. package/dist/chat/logic/json.d.ts +1 -0
  50. package/dist/chat/logic/json.js +2 -0
  51. package/dist/chat/logic/limit.d.ts +7 -0
  52. package/dist/chat/logic/limit.js +34 -0
  53. package/dist/chat/logic/resume-compaction.d.ts +14 -0
  54. package/dist/chat/logic/resume-compaction.js +47 -0
  55. package/dist/chat/logic/scrubber.d.ts +50 -0
  56. package/dist/chat/logic/scrubber.js +216 -0
  57. package/dist/chat/logic/timeline-copy.d.ts +4 -0
  58. package/dist/chat/logic/timeline-copy.js +51 -0
  59. package/dist/chat/logic/timeline-target.d.ts +12 -0
  60. package/dist/chat/logic/timeline-target.js +34 -0
  61. package/dist/chat/logic/timeline.d.ts +110 -0
  62. package/dist/chat/logic/timeline.js +339 -0
  63. package/dist/chat/logic/tool-catalog.d.ts +10 -0
  64. package/dist/chat/logic/tool-catalog.js +40 -0
  65. package/dist/chat/logic/tools.d.ts +15 -0
  66. package/dist/chat/logic/tools.js +79 -0
  67. package/dist/chat/logic/workflow.d.ts +14 -0
  68. package/dist/chat/logic/workflow.js +47 -0
  69. package/dist/chat/mentions.d.ts +46 -0
  70. package/dist/chat/mentions.js +128 -0
  71. package/dist/chat/persisted-json.d.ts +5 -0
  72. package/dist/chat/persisted-json.js +24 -0
  73. package/dist/chat/preferences.d.ts +23 -0
  74. package/dist/chat/preferences.js +110 -0
  75. package/dist/chat/quote.d.ts +2 -0
  76. package/dist/chat/quote.js +25 -0
  77. package/dist/chat/recent-messages.d.ts +17 -0
  78. package/dist/chat/recent-messages.js +28 -0
  79. package/dist/chat/resume-compaction-dismissals.d.ts +3 -0
  80. package/dist/chat/resume-compaction-dismissals.js +14 -0
  81. package/dist/chat/runtime-modes.d.ts +4 -0
  82. package/dist/chat/runtime-modes.js +11 -0
  83. package/dist/chat/stash.d.ts +24 -0
  84. package/dist/chat/stash.js +88 -0
  85. package/dist/chat/subagent-conversation.d.ts +38 -0
  86. package/dist/chat/subagent-conversation.js +150 -0
  87. package/dist/chat/subagent-list.d.ts +16 -0
  88. package/dist/chat/subagent-list.js +76 -0
  89. package/dist/chat/subagent-support.d.ts +6 -0
  90. package/dist/chat/subagent-support.js +14 -0
  91. package/dist/chat/subagent-view.d.ts +33 -0
  92. package/dist/chat/subagent-view.js +65 -0
  93. package/dist/chat/thumbnails.d.ts +10 -0
  94. package/dist/chat/thumbnails.js +87 -0
  95. package/dist/chat/timeline-scroll.d.ts +16 -0
  96. package/dist/chat/timeline-scroll.js +100 -0
  97. package/dist/chat/ui/AccountPill.d.ts +3 -0
  98. package/dist/chat/ui/AccountPill.js +24 -0
  99. package/dist/chat/ui/BookmarkMarker.d.ts +8 -0
  100. package/dist/chat/ui/BookmarkMarker.js +59 -0
  101. package/dist/chat/ui/BookmarkSubmenu.d.ts +3 -0
  102. package/dist/chat/ui/BookmarkSubmenu.js +44 -0
  103. package/dist/chat/ui/ChatActivity.d.ts +3 -0
  104. package/dist/chat/ui/ChatActivity.js +87 -0
  105. package/dist/chat/ui/ChatReferenceChip.d.ts +4 -0
  106. package/dist/chat/ui/ChatReferenceChip.js +17 -0
  107. package/dist/chat/ui/CodeBlock.d.ts +4 -0
  108. package/dist/chat/ui/CodeBlock.js +130 -0
  109. package/dist/chat/ui/Composer.d.ts +14 -0
  110. package/dist/chat/ui/Composer.js +821 -0
  111. package/dist/chat/ui/ComposerInput.d.ts +28 -0
  112. package/dist/chat/ui/ComposerInput.js +118 -0
  113. package/dist/chat/ui/DiffPool.d.ts +5 -0
  114. package/dist/chat/ui/DiffPool.js +26 -0
  115. package/dist/chat/ui/EditDiff.d.ts +4 -0
  116. package/dist/chat/ui/EditDiff.js +21 -0
  117. package/dist/chat/ui/FadingWords.d.ts +3 -0
  118. package/dist/chat/ui/FadingWords.js +5 -0
  119. package/dist/chat/ui/ImageView.d.ts +6 -0
  120. package/dist/chat/ui/ImageView.js +85 -0
  121. package/dist/chat/ui/LimitState.d.ts +8 -0
  122. package/dist/chat/ui/LimitState.js +117 -0
  123. package/dist/chat/ui/Markdown.d.ts +18 -0
  124. package/dist/chat/ui/Markdown.js +158 -0
  125. package/dist/chat/ui/MessageActions.d.ts +9 -0
  126. package/dist/chat/ui/MessageActions.js +56 -0
  127. package/dist/chat/ui/Pickers.d.ts +15 -0
  128. package/dist/chat/ui/Pickers.js +110 -0
  129. package/dist/chat/ui/PromptComposer.d.ts +13 -0
  130. package/dist/chat/ui/PromptComposer.js +48 -0
  131. package/dist/chat/ui/QuoteButton.d.ts +7 -0
  132. package/dist/chat/ui/QuoteButton.js +76 -0
  133. package/dist/chat/ui/ResumeCompactionDock.d.ts +5 -0
  134. package/dist/chat/ui/ResumeCompactionDock.js +15 -0
  135. package/dist/chat/ui/RunSettings.d.ts +25 -0
  136. package/dist/chat/ui/RunSettings.js +148 -0
  137. package/dist/chat/ui/Scrubber.d.ts +17 -0
  138. package/dist/chat/ui/Scrubber.js +121 -0
  139. package/dist/chat/ui/SubagentControls.d.ts +11 -0
  140. package/dist/chat/ui/SubagentControls.js +37 -0
  141. package/dist/chat/ui/SubagentStopButton.d.ts +7 -0
  142. package/dist/chat/ui/SubagentStopButton.js +36 -0
  143. package/dist/chat/ui/SubagentTimeline.d.ts +4 -0
  144. package/dist/chat/ui/SubagentTimeline.js +92 -0
  145. package/dist/chat/ui/Timeline.d.ts +5 -0
  146. package/dist/chat/ui/Timeline.js +318 -0
  147. package/dist/chat/ui/TimelineMenu.d.ts +12 -0
  148. package/dist/chat/ui/TimelineMenu.js +61 -0
  149. package/dist/chat/ui/UnifiedDiff.d.ts +8 -0
  150. package/dist/chat/ui/UnifiedDiff.js +51 -0
  151. package/dist/chat/ui/UploadThumb.d.ts +4 -0
  152. package/dist/chat/ui/UploadThumb.js +11 -0
  153. package/dist/chat/ui/chips.d.ts +4 -0
  154. package/dist/chat/ui/chips.js +11 -0
  155. package/dist/chat/ui/code-lines.d.ts +18 -0
  156. package/dist/chat/ui/code-lines.js +46 -0
  157. package/dist/chat/ui/code-streaming.d.ts +1 -0
  158. package/dist/chat/ui/code-streaming.js +3 -0
  159. package/dist/chat/ui/code-theme.d.ts +3 -0
  160. package/dist/chat/ui/code-theme.js +10 -0
  161. package/dist/chat/ui/composer/chips.d.ts +6 -0
  162. package/dist/chat/ui/composer/chips.js +29 -0
  163. package/dist/chat/ui/composer/editor.d.ts +11 -0
  164. package/dist/chat/ui/composer/editor.js +94 -0
  165. package/dist/chat/ui/composer/keys.d.ts +30 -0
  166. package/dist/chat/ui/composer/keys.js +98 -0
  167. package/dist/chat/ui/diff-theme.d.ts +2 -0
  168. package/dist/chat/ui/diff-theme.js +20 -0
  169. package/dist/chat/ui/file-links.d.ts +5 -0
  170. package/dist/chat/ui/file-links.js +18 -0
  171. package/dist/chat/ui/find-reveal.d.ts +7 -0
  172. package/dist/chat/ui/find-reveal.js +13 -0
  173. package/dist/chat/ui/icons.d.ts +4 -0
  174. package/dist/chat/ui/icons.js +20 -0
  175. package/dist/chat/ui/markdown-blocks.d.ts +6 -0
  176. package/dist/chat/ui/markdown-blocks.js +101 -0
  177. package/dist/chat/ui/quote-selection.d.ts +3 -0
  178. package/dist/chat/ui/quote-selection.js +44 -0
  179. package/dist/chat/ui/rehype-chips.d.ts +23 -0
  180. package/dist/chat/ui/rehype-chips.js +28 -0
  181. package/dist/chat/ui/rehype-fade.d.ts +23 -0
  182. package/dist/chat/ui/rehype-fade.js +30 -0
  183. package/dist/chat/ui/remark-html-as-text.d.ts +8 -0
  184. package/dist/chat/ui/remark-html-as-text.js +24 -0
  185. package/dist/chat/ui/reveal.d.ts +13 -0
  186. package/dist/chat/ui/reveal.js +112 -0
  187. package/dist/chat/ui/rows/ForksRow.d.ts +4 -0
  188. package/dist/chat/ui/rows/ForksRow.js +40 -0
  189. package/dist/chat/ui/rows/MessageRows.d.ts +36 -0
  190. package/dist/chat/ui/rows/MessageRows.js +190 -0
  191. package/dist/chat/ui/rows/Rows.d.ts +12 -0
  192. package/dist/chat/ui/rows/Rows.js +49 -0
  193. package/dist/chat/ui/rows/SubagentRow.d.ts +15 -0
  194. package/dist/chat/ui/rows/SubagentRow.js +98 -0
  195. package/dist/chat/ui/rows/WorkRows.d.ts +46 -0
  196. package/dist/chat/ui/rows/WorkRows.js +143 -0
  197. package/dist/chat/ui/rows/WorkflowRow.d.ts +7 -0
  198. package/dist/chat/ui/rows/WorkflowRow.js +37 -0
  199. package/dist/chat/ui/rows/row-rhythm.d.ts +3 -0
  200. package/dist/chat/ui/rows/row-rhythm.js +14 -0
  201. package/dist/chat/ui/useToggleSet.d.ts +6 -0
  202. package/dist/chat/ui/useToggleSet.js +25 -0
  203. package/dist/host.d.ts +167 -0
  204. package/dist/host.js +41 -0
  205. package/dist/lazy.d.ts +5 -0
  206. package/dist/lazy.js +35 -0
  207. package/dist/locales/en/agent-chat.json +417 -0
  208. package/dist/locales/en/agent-prompts.json +42 -0
  209. package/dist/locales/en/agent-providers.json +131 -0
  210. package/dist/locales/en/agent-usage.json +131 -0
  211. package/dist/locales/nl/agent-chat.json +417 -0
  212. package/dist/locales/nl/agent-prompts.json +42 -0
  213. package/dist/locales/nl/agent-providers.json +131 -0
  214. package/dist/locales/nl/agent-usage.json +131 -0
  215. package/dist/locales.d.ts +5 -0
  216. package/dist/locales.js +18 -0
  217. package/dist/mounted-registry.d.ts +7 -0
  218. package/dist/mounted-registry.js +39 -0
  219. package/dist/port-transport.d.ts +6 -0
  220. package/dist/port-transport.js +120 -0
  221. package/dist/prompts/logic/focus.d.ts +1 -0
  222. package/dist/prompts/logic/focus.js +17 -0
  223. package/dist/prompts/logic/keys.d.ts +42 -0
  224. package/dist/prompts/logic/keys.js +84 -0
  225. package/dist/prompts/logic/prompts.d.ts +34 -0
  226. package/dist/prompts/logic/prompts.fixtures.d.ts +5 -0
  227. package/dist/prompts/logic/prompts.fixtures.js +73 -0
  228. package/dist/prompts/logic/prompts.js +22 -0
  229. package/dist/prompts/logic/subjects.d.ts +49 -0
  230. package/dist/prompts/logic/subjects.js +56 -0
  231. package/dist/prompts/logic/useFocusAfterAnswer.d.ts +6 -0
  232. package/dist/prompts/logic/useFocusAfterAnswer.js +28 -0
  233. package/dist/prompts/logic/usePromptSession.d.ts +24 -0
  234. package/dist/prompts/logic/usePromptSession.js +87 -0
  235. package/dist/prompts/ui/ApprovalBody.d.ts +13 -0
  236. package/dist/prompts/ui/ApprovalBody.js +35 -0
  237. package/dist/prompts/ui/PromptActions.d.ts +26 -0
  238. package/dist/prompts/ui/PromptActions.js +19 -0
  239. package/dist/prompts/ui/PromptCard.d.ts +16 -0
  240. package/dist/prompts/ui/PromptCard.js +50 -0
  241. package/dist/prompts/ui/PromptView.d.ts +2 -0
  242. package/dist/prompts/ui/PromptView.js +47 -0
  243. package/dist/prompts/ui/QuestionBody.d.ts +9 -0
  244. package/dist/prompts/ui/QuestionBody.js +87 -0
  245. package/dist/providers/AccountColors.d.ts +5 -0
  246. package/dist/providers/AccountColors.js +8 -0
  247. package/dist/providers/AccountDetail.d.ts +12 -0
  248. package/dist/providers/AccountDetail.js +76 -0
  249. package/dist/providers/AccountVariables.d.ts +8 -0
  250. package/dist/providers/AccountVariables.js +48 -0
  251. package/dist/providers/AddAccountForm.d.ts +10 -0
  252. package/dist/providers/AddAccountForm.js +58 -0
  253. package/dist/providers/CliDetail.d.ts +11 -0
  254. package/dist/providers/CliDetail.js +62 -0
  255. package/dist/providers/ProvidersPane.d.ts +8 -0
  256. package/dist/providers/ProvidersPane.js +90 -0
  257. package/dist/providers/account-actions.d.ts +7 -0
  258. package/dist/providers/account-actions.js +53 -0
  259. package/dist/providers/parts.d.ts +9 -0
  260. package/dist/providers/parts.js +18 -0
  261. package/dist/providers/provider-abilities.d.ts +2 -0
  262. package/dist/providers/provider-abilities.js +7 -0
  263. package/dist/providers/variables.d.ts +13 -0
  264. package/dist/providers/variables.js +53 -0
  265. package/dist/scope.d.ts +11 -0
  266. package/dist/scope.js +10 -0
  267. package/dist/settings/sections.d.ts +13 -0
  268. package/dist/settings/sections.js +30 -0
  269. package/dist/state/chats.d.ts +32 -0
  270. package/dist/state/chats.js +124 -0
  271. package/dist/state/provider-accounts.d.ts +17 -0
  272. package/dist/state/provider-accounts.js +63 -0
  273. package/dist/state/providers.d.ts +17 -0
  274. package/dist/state/providers.js +29 -0
  275. package/dist/state/usage.d.ts +41 -0
  276. package/dist/state/usage.js +100 -0
  277. package/dist/theme.css +186 -0
  278. package/dist/transport.d.ts +24 -0
  279. package/dist/transport.js +16 -0
  280. package/dist/ui/PlainTextarea.d.ts +2 -0
  281. package/dist/ui/PlainTextarea.js +5 -0
  282. package/dist/usage/LimitsList.d.ts +18 -0
  283. package/dist/usage/LimitsList.js +69 -0
  284. package/dist/usage/UsageBreakdown.d.ts +9 -0
  285. package/dist/usage/UsageBreakdown.js +69 -0
  286. package/dist/usage/UsageChart.d.ts +10 -0
  287. package/dist/usage/UsageChart.js +49 -0
  288. package/dist/usage/UsageDialog.d.ts +6 -0
  289. package/dist/usage/UsageDialog.js +15 -0
  290. package/dist/usage/UsageLimits.d.ts +1 -0
  291. package/dist/usage/UsageLimits.js +62 -0
  292. package/dist/usage/UsageLimitsCard.d.ts +4 -0
  293. package/dist/usage/UsageLimitsCard.js +27 -0
  294. package/dist/usage/UsagePage.d.ts +7 -0
  295. package/dist/usage/UsagePage.js +161 -0
  296. package/dist/usage/UsagePane.d.ts +3 -0
  297. package/dist/usage/UsagePane.js +24 -0
  298. package/dist/usage/UsageSummary.d.ts +12 -0
  299. package/dist/usage/UsageSummary.js +15 -0
  300. package/dist/usage/UsageTiles.d.ts +7 -0
  301. package/dist/usage/UsageTiles.js +19 -0
  302. package/dist/usage/format.d.ts +14 -0
  303. package/dist/usage/format.js +50 -0
  304. package/dist/usage/limit-groups.d.ts +22 -0
  305. package/dist/usage/limit-groups.js +78 -0
  306. package/dist/usage/limits.d.ts +4 -0
  307. package/dist/usage/limits.js +58 -0
  308. package/dist/usage/money.d.ts +1 -0
  309. package/dist/usage/money.js +13 -0
  310. package/dist/usage/summary.d.ts +34 -0
  311. package/dist/usage/summary.js +90 -0
  312. package/package.json +639 -2
@@ -0,0 +1,143 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Suspense, useEffect, useState } from 'react';
3
+ import clsx from 'clsx';
4
+ import i18next from 'i18next';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { ChevronRight, FileDiff, X } from 'lucide-react';
7
+ import { fileChanges, liveOutput, readImagePath, toolStartedAt, toolSummary, unifiedChanges } from '../../logic/tools';
8
+ import { useOpenForFind } from '../find-reveal';
9
+ import { chatHost } from '../../../host';
10
+ import { lazyNamed } from '../../../lazy';
11
+ import { useChatActions } from '../../actions';
12
+ import { formatClockDuration, formatElapsedShort } from '@ruimte/ui/format/duration';
13
+ import { ROW_GUTTER, toolIcon } from '../icons';
14
+ import { Icon } from '@ruimte/ui/Icon';
15
+ import { useTickingText } from '@ruimte/ui/useNow';
16
+ // The diff renderers carry shiki; they only load once a thread shows a file change.
17
+ const EditDiff = lazyNamed(() => import('../EditDiff'), 'default');
18
+ const UnifiedDiff = lazyNamed(() => import('../UnifiedDiff'), 'default');
19
+ const OUTPUT_LIMIT = 4000;
20
+ const clip = (text) => text.length > OUTPUT_LIMIT ? `${text.slice(0, OUTPUT_LIMIT)}\n${i18next.t('agent-chat:work.moreCharacters', { count: text.length - OUTPUT_LIMIT })}` : text;
21
+ export function ToggleLine({ icon, label, detail, open, onToggle, failed, live, trailing, className }) {
22
+ return (_jsxs("button", { className: clsx(
23
+ // Fix the width so long commands reach the truncation inside the negative margins.
24
+ '-mx-1 mb-0.5 flex h-7 w-[calc(100%+8px)] items-center gap-2 rounded-md px-1 text-left text-xs text-text-muted hover:bg-surface-hover', failed && 'text-status-error', className), onClick: onToggle, children: [_jsx("span", { className: clsx(ROW_GUTTER, live && 'text-accent'), children: icon }), _jsx("span", { className: clsx('shrink-0', live && 'chat-live-text'), children: label }), detail && (_jsx("span", { "data-find-field": "summary", className: "min-w-0 truncate font-mono text-text-faint", children: detail })), _jsx("span", { className: "grow" }), trailing, failed && _jsx(Icon, { icon: X, size: 12, className: "shrink-0" }), _jsx(Icon, { icon: ChevronRight, size: 12, className: clsx('shrink-0 text-text-faint transition-transform', open && 'rotate-90') })] }));
25
+ }
26
+ function ToolBody({ tool }) {
27
+ const { t } = useTranslation('agent-chat');
28
+ const patches = unifiedChanges(tool);
29
+ const changes = patches.length > 0 ? [] : fileChanges(tool.name, tool.input);
30
+ return (_jsxs("div", { className: "mt-1.5 mb-2 ml-6 overflow-hidden rounded-md border border-border bg-surface-raised", children: [patches.length > 0 ? (_jsx(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: patches.map((change, index) => (_jsx(UnifiedDiff, { change: change }, index))) })) : changes.length > 0 ? (_jsx(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: changes.map((change, index) => (_jsx(EditDiff, { change: change }, index))) })) : (_jsx("pre", { className: "max-h-64 overflow-auto px-3 py-2 font-mono text-code text-text-muted select-text", children: clip(JSON.stringify(tool.input, null, 2) ?? '') })), tool.output !== null && tool.output !== '' && patches.length === 0 && (_jsx("pre", { "data-find-field": "output", className: clsx('max-h-64 overflow-auto whitespace-pre-wrap border-t border-border px-3 py-2 font-mono text-code select-text', tool.state === 'error' ? 'text-term-red' : 'text-term-fg'), children: clip(tool.output) }))] }));
31
+ }
32
+ /* One settled tool call: a line, and its input and output behind it. An image the call looked at
33
+ is drawn under the line, because a picture says more about that read than its path does. */
34
+ export function WorkRow({ tool, nested, detail }) {
35
+ const [open, setOpen] = useState(false);
36
+ const image = tool.state === 'done' ? readImagePath(tool.name, tool.input) : null;
37
+ const { ReadImage } = chatHost();
38
+ useOpenForFind(tool.id, 'output', setOpen);
39
+ return (_jsxs("div", { "data-find-item": tool.id, className: nested ? 'ml-6' : undefined, children: [_jsx(ToggleLine, { icon: toolIcon(tool.name), label: tool.name, detail: detail ?? toolSummary(tool.name, tool.input), open: open, onToggle: () => setOpen((o) => !o), failed: tool.state === 'error' }), image !== null && ReadImage !== null && _jsx(ReadImage, { path: image }), open && _jsx(ToolBody, { tool: tool })] }));
40
+ }
41
+ /* "running for 12s" next to a live call. */
42
+ export function RunningFor({ startedAt }) {
43
+ const { t } = useTranslation('agent-chat');
44
+ const ref = useTickingText(() => t('work.runningFor', { elapsed: formatElapsedShort(Date.now() - startedAt) }));
45
+ return _jsx("span", { ref: ref, className: "shrink-0 text-xs text-text-faint tabular-nums" });
46
+ }
47
+ /* A call still running: its timer on the line, and for a provider that streams output, the last lines under it. */
48
+ export function WorkLiveRow({ tool }) {
49
+ const [open, setOpen] = useState(false);
50
+ const tail = liveOutput(tool);
51
+ return (_jsxs("div", { children: [_jsx(ToggleLine, { icon: toolIcon(tool.name), label: tool.name, detail: toolSummary(tool.name, tool.input) || tool.progress?.description || '', open: open, onToggle: () => setOpen((o) => !o), trailing: _jsx(RunningFor, { startedAt: toolStartedAt(tool) }), live: true }), open && _jsx(ToolBody, { tool: tool }), tail !== null && !open && (_jsx("pre", { className: "mt-1.5 mb-2 ml-6 max-h-48 overflow-auto rounded-md border border-border bg-surface-raised px-3 py-2 font-mono text-code whitespace-pre-wrap text-term-fg select-text", children: tail }))] }));
52
+ }
53
+ /* A run of tool calls as one line ("Read 4 files"); opening it lists every call. */
54
+ export function WorkGroupRow({ tools, summary, expanded, onToggle }) {
55
+ const failed = tools.some((tool) => tool.state === 'error');
56
+ return (_jsx("div", { children: _jsx(ToggleLine, { icon: toolIcon(tools[0].name), label: summary, open: expanded, onToggle: onToggle, failed: failed }) }));
57
+ }
58
+ /*
59
+ * A settled turn folded behind how long it took and what it did. A line and not a button, like the
60
+ * tool lines it hides; the work reads fainter than the time so the eye lands on the time first.
61
+ */
62
+ export function TurnFoldRow({ turn, label, work, expanded, onToggle }) {
63
+ return (_jsxs("button", { className: clsx('group -mx-1 mb-2 flex h-7 w-[calc(100%+8px)] min-w-0 items-center gap-2 rounded-md px-1 text-left text-xs text-text-muted hover:bg-surface-hover', turn.state === 'error' && 'text-status-error'), "aria-expanded": expanded, onClick: onToggle, children: [_jsx("span", { className: ROW_GUTTER, children: _jsx(Icon, { icon: ChevronRight, size: 12, className: clsx('transition-transform', expanded && 'rotate-90') }) }), _jsx("span", { className: "shrink-0 group-hover:text-text", children: label }), work.length > 0 && _jsx("span", { className: "min-w-0 truncate text-text-faint", children: work.map((part) => ` · ${part}`).join('') })] }));
64
+ }
65
+ const omittedLabel = (reason) => reason === 'binary' ? i18next.t('agent-chat:work.omitted.binary') : i18next.t('agent-chat:work.omitted.tooLarge');
66
+ /* One file of a turn's checkpoint diff: its patch, or the reason there is none. */
67
+ function CheckpointFileBody({ file }) {
68
+ const { t } = useTranslation('agent-chat');
69
+ if (file.omitted) {
70
+ return _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: omittedLabel(file.omitted) });
71
+ }
72
+ return (_jsx(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: _jsx(UnifiedDiff, { change: file }) }));
73
+ }
74
+ /*
75
+ * The files a settled turn changed, as a card; each file opens its diff in place. The host's
76
+ * checkpoint diff comes first (the working tree against the tree the turn started from), then the
77
+ * unified diffs the CLI reported, then the before and after of its own edits. A turn that has a
78
+ * checkpoint but no stored diff asks the host for one, which is also how a running turn gets it.
79
+ */
80
+ export function ChangedFilesRow({ tools, diff, checkpoint, chatId, turnId }) {
81
+ const { t } = useTranslation('agent-chat');
82
+ const [open, setOpen] = useState({});
83
+ const [fetched, setFetched] = useState(null);
84
+ const actions = useChatActions();
85
+ useEffect(() => {
86
+ if (diff !== null || !checkpoint) {
87
+ return;
88
+ }
89
+ let alive = true;
90
+ void actions
91
+ .turnDiff(chatId, turnId)
92
+ .then((answer) => {
93
+ if (alive) {
94
+ setFetched(answer);
95
+ }
96
+ })
97
+ .catch(() => undefined);
98
+ return () => {
99
+ alive = false;
100
+ };
101
+ }, [actions, chatId, turnId, diff, checkpoint]);
102
+ const checkpointDiff = diff ?? fetched;
103
+ if (checkpointDiff !== null && checkpointDiff.files.length > 0) {
104
+ return (_jsxs("div", { className: "mb-3 overflow-hidden rounded-lg border border-border bg-surface-raised", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-xs text-text-muted", children: [_jsx(Icon, { icon: FileDiff, size: 12 }), _jsx("span", { className: "font-medium text-text", children: t('work.changedFiles', { count: checkpointDiff.files.length }) }), checkpointDiff.truncated && _jsx("span", { className: "text-text-faint", children: t('work.andMore') })] }), checkpointDiff.files.map((file) => (_jsxs("div", { className: "border-t border-border", children: [_jsxs("button", { className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover", "data-file-path": file.path, onClick: () => setOpen((o) => ({ ...o, [file.path]: !o[file.path] })), children: [_jsx(Icon, { icon: ChevronRight, size: 12, className: clsx('shrink-0 text-text-faint transition-transform', open[file.path] && 'rotate-90') }), _jsx("span", { className: "min-w-0 truncate font-mono text-text", children: file.path }), _jsx("span", { className: "grow" }), _jsxs("span", { className: "text-term-green tabular-nums", children: ["+", file.added] }), _jsxs("span", { className: "text-term-red tabular-nums", children: ["-", file.deleted] })] }), open[file.path] && (_jsx("div", { className: "border-t border-border", children: _jsx(CheckpointFileBody, { file: file }) }))] }, file.path)))] }));
105
+ }
106
+ return _jsx(ProviderChangedFiles, { tools: tools, open: open, setOpen: setOpen });
107
+ }
108
+ /* The fallback card, built from what the CLI itself reported about its edits. */
109
+ function ProviderChangedFiles({ tools, open, setOpen }) {
110
+ const { t } = useTranslation('agent-chat');
111
+ const byPath = new Map();
112
+ const entryFor = (path) => {
113
+ const existing = byPath.get(path);
114
+ if (existing) {
115
+ return existing;
116
+ }
117
+ const created = { edits: [], patches: [] };
118
+ byPath.set(path, created);
119
+ return created;
120
+ };
121
+ for (const tool of tools) {
122
+ const patches = unifiedChanges(tool);
123
+ if (patches.length > 0) {
124
+ for (const patch of patches) {
125
+ entryFor(patch.path).patches.push(patch);
126
+ }
127
+ continue;
128
+ }
129
+ for (const change of fileChanges(tool.name, tool.input)) {
130
+ entryFor(change.path || tool.id).edits.push(change);
131
+ }
132
+ }
133
+ return (_jsxs("div", { className: "mb-3 overflow-hidden rounded-lg border border-border bg-surface-raised", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-xs text-text-muted", children: [_jsx(Icon, { icon: FileDiff, size: 12 }), _jsx("span", { className: "font-medium text-text", children: t('work.changedFiles', { count: byPath.size }) })] }), [...byPath].map(([path, entry]) => {
134
+ const count = entry.edits.length + entry.patches.length;
135
+ return (_jsxs("div", { className: "border-t border-border", children: [_jsxs("button", { className: "flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-text-muted hover:bg-surface-hover", "data-file-path": path, onClick: () => setOpen((o) => ({ ...o, [path]: !o[path] })), children: [_jsx(Icon, { icon: ChevronRight, size: 12, className: clsx('shrink-0 text-text-faint transition-transform', open[path] && 'rotate-90') }), _jsx("span", { className: "min-w-0 truncate font-mono text-text", children: path }), _jsx("span", { className: "grow" }), _jsx("span", { className: "text-text-faint", children: t('work.edits', { count }) })] }), open[path] && (_jsx("div", { className: "border-t border-border", children: _jsxs(Suspense, { fallback: _jsx("div", { className: "px-3 py-2 text-xs text-text-faint", children: t('work.loadingDiff') }), children: [entry.patches.map((change, index) => (_jsx(UnifiedDiff, { change: change }, `patch-${index}`))), entry.edits.map((change, index) => (_jsx(EditDiff, { change: change }, `edit-${index}`)))] }) }))] }, path));
136
+ })] }));
137
+ }
138
+ /* "Working for 00:14". */
139
+ export function WorkingRow({ startedAt }) {
140
+ const { t } = useTranslation('agent-chat');
141
+ const ref = useTickingText(() => formatClockDuration(Date.now() - startedAt));
142
+ return (_jsxs("div", { className: "-mx-1 mb-0.5 flex h-7 items-center gap-2 px-1 text-xs text-text-muted", children: [_jsx("span", { className: `${ROW_GUTTER} text-accent`, children: _jsx("span", { className: "h-2 w-2 rounded-full bg-status-running" }) }), _jsx("span", { className: "chat-live-text", children: t('work.workingFor') }), _jsx("span", { ref: ref, className: "tabular-nums" })] }));
143
+ }
@@ -0,0 +1,7 @@
1
+ import { type ChatToolItem, type ChatWorkflow } from '@ruimte/agent-contracts';
2
+ import type { SubagentStep } from '../../subagent-view';
3
+ export declare function WorkflowRow({ tool, workflow, onOpenAgent }: {
4
+ tool: ChatToolItem;
5
+ workflow: ChatWorkflow;
6
+ onOpenAgent?(step: SubagentStep): void;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Bot, ListTree } from 'lucide-react';
4
+ import { workflowAgentRef } from '@ruimte/agent-contracts';
5
+ import { workflowAgentTime, workflowPhases } from '../../logic/workflow';
6
+ import { useSubagentSupport } from '../../subagent-support';
7
+ import { ROW_GUTTER } from '../icons';
8
+ import { RunningFor, ToggleLine, WorkLiveRow, WorkRow } from './WorkRows';
9
+ import { useChatScope } from '../../../scope';
10
+ import { Icon } from '@ruimte/ui/Icon';
11
+ function AgentLine({ view, onOpen }) {
12
+ const { agent, state } = view;
13
+ const time = workflowAgentTime(view);
14
+ const running = state === 'running';
15
+ const agentId = agent.agentId;
16
+ // One still waiting has no transcript yet.
17
+ const open = onOpen !== undefined && agentId !== null ? () => onOpen({ toolUseId: workflowAgentRef(agentId), description: agent.label }) : () => undefined;
18
+ return (_jsx(ToggleLine, { icon: _jsx(Icon, { icon: Bot, size: 12 }), label: agent.label, detail: running ? (agent.lastTool ?? undefined) : undefined, open: false, onToggle: open, failed: state === 'failed', live: running, trailing: running && agent.startedAt !== null ? (_jsx(RunningFor, { startedAt: agent.startedAt })) : (_jsx("span", { className: "shrink-0 text-xs text-text-faint tabular-nums", children: time })) }));
19
+ }
20
+ function PhaseBlock({ phase, onOpen }) {
21
+ const { t } = useTranslation('agent-chat');
22
+ return (_jsxs("div", { children: [phase.title !== null && (_jsxs("div", { className: "mb-0.5 flex h-7 min-w-0 items-center gap-2 text-xs text-text-muted", children: [_jsx("span", { className: ROW_GUTTER, children: _jsx(Icon, { icon: ListTree, size: 12 }) }), _jsx("span", { className: "min-w-0 truncate", children: phase.title }), _jsx("span", { className: "grow" }), phase.agents.length === 0 && _jsx("span", { className: "shrink-0 text-text-faint", children: t('rows.workflow.notStarted') })] })), phase.agents.length > 0 && (_jsx("div", { className: phase.title === null ? undefined : 'ml-6', children: phase.agents.map((view) => (_jsx(AgentLine, { view: view, onOpen: onOpen }, view.agent.index))) }))] }));
23
+ }
24
+ /*
25
+ * A Workflow call with the phases its script announced under it, and in each phase the agents it
26
+ * started, in the style of the agents a sub-agent opened. They stay in sight whether the call's own
27
+ * body is open or not; pressing an agent opens its conversation, read from its run's folder.
28
+ */
29
+ export function WorkflowRow({ tool, workflow, onOpenAgent }) {
30
+ const { id } = useChatScope();
31
+ // A host that does not answer `chat.subagent` has no conversation to open for anyone.
32
+ const refused = useSubagentSupport((s) => s.unsupported[id] === true);
33
+ const running = tool.state === 'running';
34
+ const phases = workflowPhases(workflow, running);
35
+ const onOpen = refused ? undefined : onOpenAgent;
36
+ return (_jsxs("div", { children: [running ? _jsx(WorkLiveRow, { tool: tool }) : _jsx(WorkRow, { tool: tool, detail: workflow.name ?? undefined }), phases.length > 0 && (_jsx("div", { className: "ml-6", children: phases.map((phase) => (_jsx(PhaseBlock, { phase: phase, onOpen: onOpen }, phase.key))) }))] }));
37
+ }
@@ -0,0 +1,3 @@
1
+ import { type TimelineRow } from '../../logic/timeline';
2
+ export declare const FOLLOW_THRESHOLD_PX = 40;
3
+ export declare const rowRhythm: (row: TimelineRow, previous: TimelineRow | null) => string;
@@ -0,0 +1,14 @@
1
+ import clsx from 'clsx';
2
+ import { isBlock } from '../../logic/timeline';
3
+ /* Below this distance from the bottom a thread follows what the agent writes; above it the reader scrolled back on purpose. */
4
+ export const FOLLOW_THRESHOLD_PX = 40;
5
+ /*
6
+ * The gaps a row wears for where it sits: a question is followed by its answer gap, and a seam where
7
+ * the list rhythm of tool lines meets the block rhythm of prose gets the block gap. A question
8
+ * already carries the gap before it, and the row after one is the answer, so neither takes a seam.
9
+ */
10
+ export const rowRhythm = (row, previous) => {
11
+ const question = row.kind === 'user';
12
+ const seam = !question && previous !== null && previous.kind !== 'user' && isBlock(row) !== isBlock(previous);
13
+ return clsx(question && 'pb-(--chat-answer-gap)', seam && 'pt-(--chat-block-gap)');
14
+ };
@@ -0,0 +1,6 @@
1
+ export interface ToggleSet {
2
+ ids: ReadonlySet<string>;
3
+ toggle(id: string): void;
4
+ add(id: string): void;
5
+ }
6
+ export declare const useToggleSet: (onToggle?: () => void) => ToggleSet;
@@ -0,0 +1,25 @@
1
+ import { useCallback, useState } from 'react';
2
+ /*
3
+ * The ids of the folds a thread has open. `onToggle` is what a thread does about a person opening
4
+ * one, which is to stop following the end: a fold is a deliberate look back, not a reason to jump.
5
+ */
6
+ export const useToggleSet = (onToggle) => {
7
+ const [ids, setIds] = useState(() => new Set());
8
+ const toggle = useCallback((id) => {
9
+ setIds((current) => {
10
+ const next = new Set(current);
11
+ if (next.has(id)) {
12
+ next.delete(id);
13
+ }
14
+ else {
15
+ next.add(id);
16
+ }
17
+ return next;
18
+ });
19
+ onToggle?.();
20
+ }, [onToggle]);
21
+ const add = useCallback((id) => {
22
+ setIds((current) => new Set(current).add(id));
23
+ }, []);
24
+ return { ids, toggle, add };
25
+ };
package/dist/host.d.ts ADDED
@@ -0,0 +1,167 @@
1
+ import type { ComponentProps, ComponentType, ReactNode, RefObject } from 'react';
2
+ import type { Extension } from '@codemirror/state';
3
+ import type { EditorView } from '@codemirror/view';
4
+ import type { ThemeRegistration } from 'shiki';
5
+ import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatItem } from '@ruimte/agent-contracts';
6
+ import type { TimelineRow } from './chat/logic/timeline';
7
+ import type { FindReveal } from './chat/ui/find-reveal';
8
+ import type { PromptAction } from './prompts/logic/prompts';
9
+ import type { HostPrompt, PromptViewProps } from './prompts/logic/subjects';
10
+ export interface AccentChoice {
11
+ id: string;
12
+ color: string;
13
+ }
14
+ export interface ChatToast {
15
+ id?: string;
16
+ title: string;
17
+ description?: string;
18
+ kind: 'success' | 'error' | 'deleted';
19
+ action?: {
20
+ label: string;
21
+ run(): void;
22
+ };
23
+ }
24
+ export interface ChatActions {
25
+ clear(chatId: string, force: boolean): Promise<void>;
26
+ stopTurn(chatId: string, subagents: boolean): Promise<void>;
27
+ unqueue(chatId: string, messageId: string): Promise<void>;
28
+ sendNow(chatId: string, messageId: string): Promise<void>;
29
+ compact(chatId: string): Promise<void>;
30
+ configure(chatId: string, patch: Omit<ChatConfigurePayload, 'chatId'>): Promise<void>;
31
+ continueOn(chatId: string, account: string): Promise<void>;
32
+ turnDiff(chatId: string, turnId: string): Promise<ChatCheckpointDiff | null>;
33
+ stopSubagent(chatId: string, toolUseId: string): Promise<void>;
34
+ stopTask(chatId: string, taskId: string): Promise<void>;
35
+ approve(chatId: string, requestId: string, decision: 'allow' | 'allow-always' | 'deny', message?: string): Promise<void>;
36
+ answer(chatId: string, requestId: string, answers: Record<string, string>): Promise<void>;
37
+ dismiss(chatId: string, itemId: string): Promise<void>;
38
+ }
39
+ export interface FileRef {
40
+ path: string;
41
+ line?: number;
42
+ directory: boolean;
43
+ }
44
+ export interface ChatPlace {
45
+ title: string | null;
46
+ go(): void;
47
+ }
48
+ export interface SubagentTask {
49
+ status: 'open' | 'done' | 'failed' | 'cancelled';
50
+ createdAt: number;
51
+ settledAt: number | null;
52
+ paused?: {
53
+ until?: number;
54
+ };
55
+ }
56
+ export interface TimelineFindOptions {
57
+ chatId: string;
58
+ frame: RefObject<HTMLDivElement | null>;
59
+ thread: RefObject<HTMLDivElement | null>;
60
+ scroller: RefObject<HTMLDivElement | null>;
61
+ enabled: boolean;
62
+ rows: readonly TimelineRow[];
63
+ structure: Readonly<Record<string, ChatItem>> | undefined;
64
+ order: readonly string[] | undefined;
65
+ firstRowInView(): number;
66
+ openTurn(turnId: string): void;
67
+ openGroup(id: string): void;
68
+ openSubagent(id: string): void;
69
+ scrollToRow(index: number): void;
70
+ coveredHeight(): number;
71
+ stopFollowing(): void;
72
+ }
73
+ export interface TimelineFind {
74
+ open: boolean;
75
+ bar: ReactNode;
76
+ reveal: FindReveal | null;
77
+ hitRows: readonly number[];
78
+ currentRow: number | null;
79
+ }
80
+ export interface ComposerDictationProps {
81
+ targetRef: RefObject<HTMLElement | null>;
82
+ buttonContainer: HTMLElement | null | undefined;
83
+ disabled: boolean;
84
+ editor(): EditorView | null;
85
+ }
86
+ export type TextareaProps = ComponentProps<'textarea'> & {
87
+ buttonClassName?: string;
88
+ };
89
+ export interface ResourceUrl {
90
+ url: string | null;
91
+ failure: string | null;
92
+ }
93
+ export interface ChatHost {
94
+ accents: {
95
+ all: readonly AccentChoice[];
96
+ featured: readonly string[];
97
+ label(id: string): string;
98
+ current(): string;
99
+ };
100
+ isApplePlatform(): boolean;
101
+ isAppShortcut(event: KeyboardEvent): boolean;
102
+ notify(toast: ChatToast): void;
103
+ actions: ChatActions | null;
104
+ searchFiles: ((scopeId: string, cwd: string, query: string, limit: number) => Promise<string[]>) | null;
105
+ attachments: {
106
+ useUrl(scopeId: string, chatId: string, attachmentId: string): ResourceUrl;
107
+ read(scopeId: string, chatId: string, attachmentId: string): Promise<Blob>;
108
+ };
109
+ ReadImage: ComponentType<{
110
+ path: string;
111
+ }> | null;
112
+ code: {
113
+ useMode(): 'light' | 'dark';
114
+ useThemes(): {
115
+ light: string;
116
+ dark: string;
117
+ };
118
+ custom: ReadonlyArray<ThemeRegistration & {
119
+ name: string;
120
+ }>;
121
+ };
122
+ useStreaming(): 'words' | 'blocks' | 'whole';
123
+ fileLinks: {
124
+ target(text: string, cwd: string | null): FileRef | null;
125
+ open(cwd: string | null, ref: FileRef): void;
126
+ } | null;
127
+ useTimelineFind(options: TimelineFindOptions): TimelineFind;
128
+ dictation: {
129
+ Textarea: ComponentType<TextareaProps>;
130
+ composer: {
131
+ extensions: Extension;
132
+ Control: ComponentType<ComposerDictationProps>;
133
+ } | null;
134
+ };
135
+ prompts: {
136
+ useExtra(scopeId: string, chatId: string): readonly HostPrompt[];
137
+ render(prompt: HostPrompt, props: PromptViewProps): ReactNode;
138
+ answer(prompt: HostPrompt, action: PromptAction): Promise<void>;
139
+ };
140
+ useReferableChats(): ReadonlyArray<{
141
+ id: string;
142
+ title: string;
143
+ }>;
144
+ openLogin: ((scopeId: string, kind: AgentKind, accountId: string, name: string) => Promise<void>) | null;
145
+ useLoginBlocked(scopeId: string): string | null;
146
+ useProjectLook(scopeId: string, projectId: string | null): {
147
+ name: string;
148
+ mark: ReactNode;
149
+ } | null;
150
+ useChatPlace(chatId: string): ChatPlace;
151
+ useContextSources(chatId: string): ReadonlyArray<{
152
+ title: string;
153
+ }>;
154
+ tasks: {
155
+ useTasks(scopeId: string): Readonly<Record<string, SubagentTask>> | undefined;
156
+ useTask(scopeId: string, taskId: string | null): SubagentTask | null;
157
+ };
158
+ confirm: {
159
+ stopSubagents(scopeId: string, chatId: string, run: () => void): void;
160
+ stopTask(scopeId: string, childId: string, title: string, run: () => void): void;
161
+ };
162
+ fork: ((chatId: string, turnId: string) => void) | null;
163
+ openSettings(section: 'providers' | 'agents'): void;
164
+ useResumeAtReset(scopeId: string): boolean;
165
+ }
166
+ export declare const setChatHost: (patch: Partial<ChatHost>) => void;
167
+ export declare const chatHost: () => ChatHost;
package/dist/host.js ADDED
@@ -0,0 +1,41 @@
1
+ import { isApplePlatform } from '@ruimte/ui/platform';
2
+ import { PlainTextarea } from './ui/PlainTextarea';
3
+ const NO_PROMPTS = [];
4
+ const NO_CHATS = [];
5
+ const NO_ROWS = [];
6
+ const NO_FIND = { open: false, bar: null, reveal: null, hitRows: NO_ROWS, currentRow: null };
7
+ const NO_SOURCES = [];
8
+ const NO_URL = { url: null, failure: null };
9
+ const NOWHERE = { title: null, go: () => undefined };
10
+ const DEFAULT_HOST = {
11
+ accents: { all: [], featured: [], label: (id) => id, current: () => '' },
12
+ isApplePlatform,
13
+ isAppShortcut: () => false,
14
+ notify: () => undefined,
15
+ actions: null,
16
+ searchFiles: null,
17
+ attachments: { useUrl: () => NO_URL, read: () => Promise.reject(new Error('This app keeps no attached files')) },
18
+ ReadImage: null,
19
+ code: { useMode: () => 'light', useThemes: () => ({ light: 'github-light', dark: 'github-dark' }), custom: [] },
20
+ useStreaming: () => 'words',
21
+ fileLinks: null,
22
+ useTimelineFind: () => NO_FIND,
23
+ dictation: { Textarea: PlainTextarea, composer: null },
24
+ prompts: { useExtra: () => NO_PROMPTS, render: () => null, answer: () => Promise.reject(new Error('This app raises no prompts of its own')) },
25
+ useReferableChats: () => NO_CHATS,
26
+ openLogin: null,
27
+ useLoginBlocked: () => null,
28
+ useProjectLook: () => null,
29
+ useChatPlace: () => NOWHERE,
30
+ useContextSources: () => NO_SOURCES,
31
+ tasks: { useTasks: () => undefined, useTask: () => null },
32
+ confirm: { stopSubagents: (_scopeId, _chatId, run) => run(), stopTask: (_scopeId, _childId, _title, run) => run() },
33
+ fork: null,
34
+ openSettings: () => undefined,
35
+ useResumeAtReset: () => true
36
+ };
37
+ let host = DEFAULT_HOST;
38
+ export const setChatHost = (patch) => {
39
+ host = { ...host, ...patch };
40
+ };
41
+ export const chatHost = () => host;
package/dist/lazy.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { type ComponentProps, type ComponentType } from 'react';
2
+ type Loader = () => Promise<unknown>;
3
+ export declare const setLazyPrefetch: (next: (load: Loader) => void) => void;
4
+ export declare function lazyNamed<Module extends Record<Name, ComponentType<any>>, Name extends keyof Module>(load: () => Promise<Module>, name: Name): ComponentType<ComponentProps<Module[Name]>>;
5
+ export {};
package/dist/lazy.js ADDED
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { lazy } from 'react';
3
+ const loaders = [];
4
+ let register = null;
5
+ /*
6
+ * Hands every module the chat loads lazily to the app's prefetcher: the ones made so far, and each
7
+ * one made from now on. Without it they load on their first render, as `React.lazy` does.
8
+ */
9
+ export const setLazyPrefetch = (next) => {
10
+ register = next;
11
+ for (const load of loaders) {
12
+ next(load);
13
+ }
14
+ };
15
+ /*
16
+ * `React.lazy` for a module that exports its component by name, `default` included. Once the module
17
+ * is here the component is drawn straight away, since `React.lazy` suspends for a tick even on a
18
+ * module the prefetcher already fetched.
19
+ */
20
+ export function lazyNamed(load, name) {
21
+ let loaded = null;
22
+ const open = async () => {
23
+ const component = (await load())[name];
24
+ loaded ??= component;
25
+ return component;
26
+ };
27
+ loaders.push(open);
28
+ register?.(open);
29
+ const Lazy = lazy(async () => ({ default: await open() }));
30
+ const LazyNamed = (props) => {
31
+ const Component = loaded ?? Lazy;
32
+ return _jsx(Component, { ...props });
33
+ };
34
+ return LazyNamed;
35
+ }