zidane-ui 9.1.13 → 9.1.14

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 (309) hide show
  1. package/dist/adapters/index.d.ts +2 -2
  2. package/dist/adapters/index.js +2 -2
  3. package/dist/adapters/live.d.ts +29 -3
  4. package/dist/adapters/live.js +9 -1
  5. package/dist/adapters/server-composer-host.js +17 -2
  6. package/dist/adapters/server-extensions-host.d.ts +0 -1
  7. package/dist/adapters/server-extensions-host.js +5 -16
  8. package/dist/adapters/server-git-host.js +7 -16
  9. package/dist/adapters/server-host.js +181 -43
  10. package/dist/adapters/server-machines-host.d.ts +2 -0
  11. package/dist/adapters/server-machines-host.js +24 -25
  12. package/dist/adapters/server-onboarding-host.d.ts +1 -1
  13. package/dist/adapters/server-onboarding-host.js +3 -4
  14. package/dist/adapters/server-session-host.js +22 -3
  15. package/dist/adapters/server-settings-accounts.js +2 -2
  16. package/dist/adapters/server-settings-host.js +3 -3
  17. package/dist/adapters/server-settings-performance.js +7 -9
  18. package/dist/adapters/server-settings-sections.js +13 -14
  19. package/dist/adapters/server-sidebar-host.js +2 -2
  20. package/dist/adapters/sse-host.js +68 -3
  21. package/dist/adapters/sse-protocol.d.ts +12 -2
  22. package/dist/adapters/sse-protocol.js +4 -2
  23. package/dist/app/AppHostProvider.js +4 -3
  24. package/dist/app/ModalProvider.d.ts +13 -3
  25. package/dist/app/ModalProvider.js +103 -24
  26. package/dist/app/NoticeStack.d.ts +33 -0
  27. package/dist/app/NoticeStack.js +90 -0
  28. package/dist/app/index.d.ts +3 -2
  29. package/dist/app/index.js +3 -2
  30. package/dist/appearance/AppearanceProvider.js +2 -2
  31. package/dist/appearance/headless/index.js +1 -1
  32. package/dist/approvals/headless/index.js +2 -2
  33. package/dist/chat/SessionFilterMenu.d.ts +1 -1
  34. package/dist/chat/SessionFilterMenu.js +2 -1
  35. package/dist/chat/Transcript.js +1 -1
  36. package/dist/chat/composer/Composer.js +9 -6
  37. package/dist/chat/composer/ComposerEditor.js +1 -1
  38. package/dist/chat/composer/ConversationBadges.js +1 -1
  39. package/dist/chat/composer/ModelChainList.js +17 -8
  40. package/dist/chat/composer/ModelChainTooltip.js +5 -2
  41. package/dist/chat/composer/use-composer-stores.js +1 -1
  42. package/dist/chat/composer/use-draft-target.d.ts +20 -1
  43. package/dist/chat/composer/use-draft-target.js +122 -6
  44. package/dist/chat/composer/use-new-session-defaults.d.ts +5 -1
  45. package/dist/chat/composer/use-new-session-defaults.js +17 -4
  46. package/dist/chat/composer/use-run-meter.js +1 -1
  47. package/dist/chat/composer/use-send-prompt.js +1 -1
  48. package/dist/chat/headless/chip-labels.d.ts +1 -0
  49. package/dist/chat/headless/chip-labels.js +1 -0
  50. package/dist/chat/headless/composer/index.js +2 -2
  51. package/dist/chat/headless/draft-target.d.ts +21 -1
  52. package/dist/chat/headless/fixture-host.js +17 -2
  53. package/dist/chat/headless/host.d.ts +3 -3
  54. package/dist/chat/headless/index.d.ts +9 -9
  55. package/dist/chat/headless/index.js +15 -15
  56. package/dist/chat/headless/labels.d.ts +13 -4
  57. package/dist/chat/headless/labels.js +8 -5
  58. package/dist/chat/headless/session-list.d.ts +20 -6
  59. package/dist/chat/headless/session-list.js +1 -0
  60. package/dist/chat/headless/sidebar/directory.d.ts +56 -14
  61. package/dist/chat/headless/sidebar/directory.js +149 -70
  62. package/dist/chat/headless/sidebar/index.d.ts +3 -3
  63. package/dist/chat/headless/sidebar/index.js +3 -3
  64. package/dist/chat/headless/sidebar/labels.d.ts +15 -6
  65. package/dist/chat/headless/sidebar/types.d.ts +3 -1
  66. package/dist/chat/headless/sidebar/view.d.ts +13 -5
  67. package/dist/chat/headless/sidebar/view.js +31 -11
  68. package/dist/chat/headless/streams/actions.d.ts +5 -3
  69. package/dist/chat/headless/streams/actions.js +3 -2
  70. package/dist/chat/headless/streams/index.d.ts +3 -3
  71. package/dist/chat/headless/streams/merge.d.ts +6 -10
  72. package/dist/chat/headless/streams/merge.js +7 -21
  73. package/dist/chat/headless/streams/session-streams.d.ts +29 -4
  74. package/dist/chat/headless/streams/session-streams.js +86 -0
  75. package/dist/chat/headless/streams/store.d.ts +162 -16
  76. package/dist/chat/headless/streams/store.js +334 -38
  77. package/dist/chat/headless/streams/types.d.ts +10 -7
  78. package/dist/chat/headless/transcript-labels.d.ts +1 -0
  79. package/dist/chat/interactions/PlanCard.js +10 -3
  80. package/dist/chat/interactions/QuestionForm.js +7 -3
  81. package/dist/chat/interactions/card-ui.d.ts +5 -3
  82. package/dist/chat/interactions/card-ui.js +9 -7
  83. package/dist/chat/sidebar/SessionSidebar.js +5 -5
  84. package/dist/chat/sidebar/SidebarFilterMenu.js +3 -1
  85. package/dist/chat/sidebar/SidebarFrame.d.ts +4 -0
  86. package/dist/chat/sidebar/SidebarFrame.js +27 -9
  87. package/dist/chat/sidebar/SidebarGroupHeader.js +1 -1
  88. package/dist/chat/sidebar/SidebarHostProvider.d.ts +8 -5
  89. package/dist/chat/sidebar/SidebarHostProvider.js +13 -9
  90. package/dist/chat/sidebar/SidebarToggleButton.js +7 -3
  91. package/dist/chat/sidebar/index.d.ts +2 -2
  92. package/dist/chat/sidebar/session-menu.js +4 -4
  93. package/dist/chat/sidebar/useSaveViewAsSpace.js +2 -2
  94. package/dist/chat/testing/contract.js +2 -2
  95. package/dist/chat/transcript/AuthFailureCard.js +11 -8
  96. package/dist/chat/transcript/BadgeMenu.js +13 -2
  97. package/dist/chat/transcript/MermaidDiagram.js +7 -3
  98. package/dist/chat/transcript/fold.d.ts +4 -0
  99. package/dist/chat/transcript/fold.js +53 -22
  100. package/dist/chat/transcript/script-input.d.ts +1 -1
  101. package/dist/chat/transcript/shell-block.js +8 -4
  102. package/dist/chat/transcript/useStickToBottom.js +12 -0
  103. package/dist/components/BrowserSignIn.js +23 -21
  104. package/dist/components/Form.d.ts +6 -4
  105. package/dist/components/Form.js +16 -8
  106. package/dist/components/LoadError.d.ts +4 -2
  107. package/dist/components/LoadError.js +13 -9
  108. package/dist/components/Notice.d.ts +29 -0
  109. package/dist/components/Notice.js +63 -0
  110. package/dist/components/PanelEmpty.d.ts +1 -1
  111. package/dist/components/PanelEmpty.js +4 -2
  112. package/dist/components/Restricted.d.ts +1 -1
  113. package/dist/components/palette/PaletteList.js +8 -1
  114. package/dist/components/palette/PalettePanel.js +14 -6
  115. package/dist/core.css +24 -5
  116. package/dist/dist/{index-Bq87OcGy.d.ts → index-C6rzc-tt.d.ts} +28 -3
  117. package/dist/dist/index.d.ts +2 -2
  118. package/dist/dist/{timeout-B5pO5I5a.d.ts → timeout-Cz9dRF8Q.d.ts} +1 -1
  119. package/dist/extensions/ExtensionSettingsPage.js +2 -5
  120. package/dist/extensions/ExtensionSettingsSection.js +5 -4
  121. package/dist/extensions/ExtensionSettingsSidebar.js +3 -7
  122. package/dist/extensions/SettingsWireForm.d.ts +1 -7
  123. package/dist/extensions/SettingsWireForm.js +7 -5
  124. package/dist/extensions/headless/fixture-host.d.ts +1 -5
  125. package/dist/extensions/headless/fixture-host.js +2 -5
  126. package/dist/extensions/headless/host.d.ts +1 -11
  127. package/dist/extensions/headless/index.d.ts +3 -3
  128. package/dist/extensions/headless/index.js +6 -6
  129. package/dist/extensions/headless/select.d.ts +1 -11
  130. package/dist/extensions/headless/select.js +1 -18
  131. package/dist/extensions/hooks.js +1 -1
  132. package/dist/files/EditorColumn.js +13 -2
  133. package/dist/files/MediaDiff.js +1 -1
  134. package/dist/files/TreeColumn.js +13 -20
  135. package/dist/files/useEntryActions.js +1 -1
  136. package/dist/files/useOpenFiles.js +3 -1
  137. package/dist/git/BranchMenu.js +6 -4
  138. package/dist/git/ImportRepoDialog.js +18 -9
  139. package/dist/git/MoveSessionDialog.js +16 -8
  140. package/dist/git/RemoteFolderPicker.js +35 -17
  141. package/dist/git/SyncChip.js +17 -17
  142. package/dist/git/WherePicker.d.ts +16 -1
  143. package/dist/git/WherePicker.js +81 -37
  144. package/dist/git/headless/environment.d.ts +33 -3
  145. package/dist/git/headless/environment.js +33 -5
  146. package/dist/git/headless/index.d.ts +2 -2
  147. package/dist/git/headless/index.js +2 -2
  148. package/dist/git/headless/labels.d.ts +15 -2
  149. package/dist/git/headless/labels.js +17 -4
  150. package/dist/git/useEnvironmentChoices.d.ts +3 -1
  151. package/dist/git/useEnvironmentChoices.js +7 -4
  152. package/dist/index.d.ts +2 -1
  153. package/dist/index.js +2 -1
  154. package/dist/keybindings/KeyCommands.js +1 -1
  155. package/dist/keybindings/KeybindingsProvider.js +1 -1
  156. package/dist/keybindings/headless/index.js +2 -2
  157. package/dist/keybindings/headless/overrides.js +1 -1
  158. package/dist/labels.d.ts +5 -0
  159. package/dist/labels.js +5 -0
  160. package/dist/machines/AddMachineDialog.d.ts +34 -0
  161. package/dist/machines/AddMachineDialog.js +464 -0
  162. package/dist/machines/Banners.d.ts +33 -4
  163. package/dist/machines/Banners.js +64 -3
  164. package/dist/machines/DaemonMenu.js +27 -4
  165. package/dist/machines/HostCapabilities.d.ts +1 -3
  166. package/dist/machines/HostCapabilities.js +24 -45
  167. package/dist/machines/HostSyncPanel.js +124 -130
  168. package/dist/machines/HostsSection.d.ts +4 -1
  169. package/dist/machines/HostsSection.js +30 -7
  170. package/dist/machines/MachinesExplainer.d.ts +17 -0
  171. package/dist/machines/MachinesExplainer.js +71 -0
  172. package/dist/machines/MachinesProvider.d.ts +14 -2
  173. package/dist/machines/MachinesProvider.js +35 -1
  174. package/dist/machines/ServerAddedCard.d.ts +31 -0
  175. package/dist/machines/ServerAddedCard.js +72 -0
  176. package/dist/machines/ServerCard.js +91 -215
  177. package/dist/machines/ServerMachinesPanel.d.ts +2 -2
  178. package/dist/machines/ServerMachinesPanel.js +184 -323
  179. package/dist/machines/ServerUpdatePanel.js +51 -40
  180. package/dist/machines/ShareThisComputerForm.d.ts +19 -0
  181. package/dist/machines/ShareThisComputerForm.js +133 -0
  182. package/dist/machines/SyncOutcomeBadge.js +1 -1
  183. package/dist/machines/TokensPanel.d.ts +5 -3
  184. package/dist/machines/TokensPanel.js +98 -78
  185. package/dist/machines/headless/fixture-host.d.ts +19 -3
  186. package/dist/machines/headless/fixture-host.js +43 -6
  187. package/dist/machines/headless/fixtures.js +4 -6
  188. package/dist/machines/headless/host.d.ts +40 -19
  189. package/dist/machines/headless/index.d.ts +3 -3
  190. package/dist/machines/headless/index.js +3 -3
  191. package/dist/machines/headless/labels.d.ts +63 -20
  192. package/dist/machines/headless/labels.js +88 -25
  193. package/dist/machines/headless/messages.js +8 -0
  194. package/dist/machines/headless/stores.d.ts +9 -2
  195. package/dist/machines/headless/stores.js +28 -1
  196. package/dist/machines/index.d.ts +7 -3
  197. package/dist/machines/index.js +8 -4
  198. package/dist/machines/testing/contract.d.ts +15 -3
  199. package/dist/machines/testing/contract.js +68 -14
  200. package/dist/motion/grow.d.ts +8 -1
  201. package/dist/motion/grow.js +10 -4
  202. package/dist/onboarding/headless/labels.d.ts +13 -0
  203. package/dist/onboarding/headless/labels.js +8 -0
  204. package/dist/onboarding/sources/SourceBrowser.js +11 -7
  205. package/dist/onboarding/steps/ImportStep.js +4 -1
  206. package/dist/onboarding/steps/ReadyStep.js +9 -2
  207. package/dist/onboarding/steps/connect/KeyForm.js +6 -2
  208. package/dist/onboarding/steps/connect/ProviderPanel.js +6 -2
  209. package/dist/onboarding/steps/connect/ProviderReady.js +25 -20
  210. package/dist/onboarding/steps/tasks.js +17 -14
  211. package/dist/palette/app-sources.js +1 -1
  212. package/dist/server/sse-handler.js +141 -19
  213. package/dist/session/ArtifactsPanel.js +40 -18
  214. package/dist/session/PlanTracker.js +13 -8
  215. package/dist/session/ProjectHome.js +13 -11
  216. package/dist/session/RemindersPanel.js +35 -17
  217. package/dist/session/RunningWorkDialog.js +6 -2
  218. package/dist/session/SecretsPanel.js +29 -10
  219. package/dist/session/SessionDetailsDialog.d.ts +1 -1
  220. package/dist/session/SessionDetailsDialog.js +18 -10
  221. package/dist/session/SideChat.js +10 -7
  222. package/dist/session/TurnDetailsDialog.js +19 -5
  223. package/dist/session/UsagePanel.js +10 -4
  224. package/dist/session/headless/host.d.ts +2 -0
  225. package/dist/session/headless/index.js +2 -2
  226. package/dist/session/headless/labels.d.ts +19 -1
  227. package/dist/session/headless/labels.js +15 -1
  228. package/dist/session/headless/queue.js +2 -1
  229. package/dist/session/headless/reminder-labels.d.ts +4 -0
  230. package/dist/session/headless/reminder-labels.js +4 -0
  231. package/dist/settings/SettingsRestricted.d.ts +1 -1
  232. package/dist/settings/SettingsRestricted.js +4 -4
  233. package/dist/settings/SettingsShell.d.ts +7 -0
  234. package/dist/settings/SettingsShell.js +6 -1
  235. package/dist/settings/headless/fixture-performance.d.ts +1 -1
  236. package/dist/settings/headless/host.d.ts +2 -2
  237. package/dist/settings/headless/index.js +1 -1
  238. package/dist/settings/headless/labels.d.ts +3 -3
  239. package/dist/settings/headless/labels.js +3 -3
  240. package/dist/settings/headless/performance.d.ts +3 -4
  241. package/dist/settings/headless/search.d.ts +1 -1
  242. package/dist/settings/index.d.ts +2 -1
  243. package/dist/settings/index.js +2 -1
  244. package/dist/settings/sections/appearance/AppearanceSection.js +2 -2
  245. package/dist/settings/sections/claude-import/ClaudeImportDialog.js +1 -1
  246. package/dist/settings/sections/editor/EditorSection.js +8 -5
  247. package/dist/settings/sections/editor/labels.d.ts +1 -0
  248. package/dist/settings/sections/editor/labels.js +1 -0
  249. package/dist/settings/sections/environments/EnvironmentsSection.js +21 -14
  250. package/dist/settings/sections/environments/labels.d.ts +1 -0
  251. package/dist/settings/sections/environments/labels.js +2 -1
  252. package/dist/settings/sections/extensions/ChangeOriginDialog.js +1 -1
  253. package/dist/settings/sections/extensions/CreateExtensionDialog.js +1 -1
  254. package/dist/settings/sections/extensions/ExtensionConfigRows.d.ts +1 -3
  255. package/dist/settings/sections/extensions/ExtensionConfigRows.js +20 -19
  256. package/dist/settings/sections/extensions/ExtensionOptionsSection.js +2 -1
  257. package/dist/settings/sections/extensions/ExtensionsSection.js +1 -1
  258. package/dist/settings/sections/extensions/options-labels.d.ts +2 -1
  259. package/dist/settings/sections/extensions/options-labels.js +2 -1
  260. package/dist/settings/sections/host-catalog/HostCatalogSection.js +1 -1
  261. package/dist/settings/sections/index.d.ts +2 -1
  262. package/dist/settings/sections/index.js +2 -1
  263. package/dist/settings/sections/instructions/InstructionsSection.js +1 -1
  264. package/dist/settings/sections/logs/LogsSection.d.ts +2 -2
  265. package/dist/settings/sections/logs/LogsSection.js +2 -2
  266. package/dist/settings/sections/mcp/McpSection.d.ts +1 -1
  267. package/dist/settings/sections/mcp/McpSection.js +13 -7
  268. package/dist/settings/sections/mcp/McpServerRow.js +21 -14
  269. package/dist/settings/sections/mcp/labels.d.ts +8 -2
  270. package/dist/settings/sections/mcp/labels.js +8 -2
  271. package/dist/settings/sections/models/ModelRows.js +1 -1
  272. package/dist/settings/sections/models/NewChatPlaceRow.d.ts +26 -0
  273. package/dist/settings/sections/models/NewChatPlaceRow.js +78 -0
  274. package/dist/settings/sections/models/SpacesDefaultsSection.js +15 -3
  275. package/dist/settings/sections/models/labels.d.ts +7 -0
  276. package/dist/settings/sections/models/labels.js +7 -0
  277. package/dist/settings/sections/models/model-test.js +7 -4
  278. package/dist/settings/sections/performance/PerformanceSection.js +16 -6
  279. package/dist/settings/sections/performance/labels.d.ts +1 -1
  280. package/dist/settings/sections/performance/labels.js +1 -1
  281. package/dist/settings/sections/providers/ProvidersSection.d.ts +1 -1
  282. package/dist/settings/sections/providers/ProvidersSection.js +15 -8
  283. package/dist/settings/sections/providers/ServerProvidersSection.d.ts +1 -1
  284. package/dist/settings/sections/providers/ServerProvidersSection.js +12 -6
  285. package/dist/settings/sections/providers/labels.d.ts +2 -2
  286. package/dist/settings/sections/providers/labels.js +2 -2
  287. package/dist/settings/sections/shared/catalog.js +1 -1
  288. package/dist/settings/sections/skills/SkillsSection.js +1 -1
  289. package/dist/settings/testing/performance.contract.js +8 -12
  290. package/dist/styles.css +32 -3
  291. package/dist/terminal/HostTerminalSurface.js +17 -7
  292. package/dist/terminal/TerminalPanel.js +30 -17
  293. package/dist/terminal/TerminalSurface.js +11 -4
  294. package/dist/terminal/headless/labels.d.ts +5 -0
  295. package/dist/terminal/headless/labels.js +5 -0
  296. package/dist/terminal/headless/store.d.ts +1 -1
  297. package/dist/terminal/headless/store.js +6 -3
  298. package/dist/workspace/LayoutBudget.d.ts +5 -1
  299. package/dist/workspace/LayoutBudget.js +14 -1
  300. package/dist/workspace/PanelContentView.d.ts +1 -1
  301. package/dist/workspace/PanelContentView.js +17 -6
  302. package/dist/workspace/WorkspaceProvider.js +4 -3
  303. package/dist/workspace/extension-tabs.js +1 -1
  304. package/dist/workspace/headless/index.js +1 -1
  305. package/dist/workspace/headless/labels.d.ts +1 -0
  306. package/dist/workspace/headless/labels.js +1 -0
  307. package/package.json +3 -3
  308. package/src/styles/motion.css +8 -0
  309. package/src/styles/primitives.css +7 -0
@@ -3,9 +3,11 @@ import { inheritRowIdentity } from "../transcript/collapse.js";
3
3
  import { mergeLiveTail } from "./merge.js";
4
4
  import { mergePromptPreviews, missingPreviewData } from "./prompt-previews.js";
5
5
  import { defaultFrameScheduler } from "./scheduler.js";
6
- import { discardThinking, finalizeStreamingMarkdownForOwner, reconcileEvents, retagUserPromptEventsFromRefs } from "zidane/chat/pure";
6
+ import { applyHistoryOp, applyHistorySince, discardThinking, finalizeStreamingMarkdownForOwner, readFreshness, reconcileEvents } from "zidane/chat/pure";
7
7
  //#region src/chat/headless/streams/store.ts
8
8
  const PARENT_OWNER = "parent";
9
+ /** Numberings a window remembers leaving (`_retiredHistoryIds`). */
10
+ const RETIRED_HISTORY_IDS = 8;
9
11
  /**
10
12
  * Module-level stable empty array — returned by `getEventsSnapshot` when
11
13
  * the session has no entry yet. Keeping this reference identical across
@@ -13,12 +15,39 @@ const PARENT_OWNER = "parent";
13
15
  * consumer mounts before its session hydrates.
14
16
  */
15
17
  const EMPTY_EVENTS = Object.freeze([]);
18
+ /**
19
+ * Finds the pending entry an echo answers. It is the entry with the echo's
20
+ * message id (its `clientMessageId`, else `origin.messageId`). Else it is
21
+ * the first entry with the echo's text and no message id of its own. If the
22
+ * echo carries no message id, the first entry with its text matches. Returns
23
+ * -1 for a genuine remote send.
24
+ */
25
+ function pendingEchoIndex(pending, echo) {
26
+ const messageId = echo.clientMessageId ?? echo.origin?.messageId;
27
+ if (messageId !== void 0) {
28
+ const byId = pending.findIndex((p) => p.clientMessageId === messageId);
29
+ if (byId !== -1) return byId;
30
+ return pending.findIndex((p) => p.clientMessageId === void 0 && p.text === echo.text);
31
+ }
32
+ return pending.findIndex((p) => p.text === echo.text);
33
+ }
16
34
  /** Page-state snapshot for a session with no hydrated page — stable identity. */
17
35
  const NO_PAGE = Object.freeze({
18
36
  firstSeq: 0,
19
37
  hasMore: false,
20
38
  loadingEarlier: false
21
39
  });
40
+ /** Builds a window's page state from a page it took. It holds the cursor and the history position of the cursor (the page's, else `fallback`). */
41
+ function pageState(page, loadingEarlier, fallback) {
42
+ const at = page.pos !== void 0 ? page : fallback;
43
+ return {
44
+ firstSeq: page.firstSeq,
45
+ hasMore: page.hasMore,
46
+ loadingEarlier,
47
+ ...at?.pos !== void 0 ? { pos: at.pos } : {},
48
+ ...at?.pos !== void 0 && at.historyId !== void 0 ? { historyId: at.historyId } : {}
49
+ };
50
+ }
22
51
  /**
23
52
  * Markdown merge options by default. No 64 KB segmenting: a reloaded
24
53
  * transcript shows each message whole (the renderer chunks long text
@@ -95,15 +124,17 @@ var SessionStreamStore = class {
95
124
  _runSeq = /* @__PURE__ */ new Map();
96
125
  _pages = /* @__PURE__ */ new Map();
97
126
  /**
98
- * Texts of user prompts THIS window appended optimistically that still
99
- * await their host echo. The host stamps `echo: true` on the broadcast
100
- * of the sender's own prompt (send / steer paths) for EVERY peer — it
101
- * cannot know which window originated the send — so the dedupe lives
102
- * here: one pending entry consumes one echo (keeping the local copy,
103
- * which carries refs + attachments the canonical event doesn't).
127
+ * User prompts THIS window appended optimistically that still await their
128
+ * host echo. The host stamps `echo: true` on the broadcast of the sender's
129
+ * own prompt (send / steer paths) for EVERY peer. It cannot know which
130
+ * window sent the prompt, so the dedupe lives here. One pending entry
131
+ * consumes one echo and keeps the local copy, which carries refs and
132
+ * attachments that the canonical event does not.
104
133
  * Echo-tagged prompts with NO pending match are genuine remote sends
105
134
  * (another window, a daemon-drained queued prompt) and must render.
106
- * Leftovers (failed sends) are cleared at `run:end`.
135
+ * The echo matches by the sender's message id when both carry one, else
136
+ * by text, and gives the local row its turn id. Leftovers (failed sends)
137
+ * are cleared at `run:end`.
107
138
  */
108
139
  _pendingEcho = /* @__PURE__ */ new Map();
109
140
  /**
@@ -111,6 +142,39 @@ var SessionStreamStore = class {
111
142
  * the prompt shows up in the transcript (see `prompt-previews.ts`).
112
143
  */
113
144
  _promptPreviews = /* @__PURE__ */ new Map();
145
+ /** The history position each window applied last (`applyHistory`). It is the window's bookmark in the session's history. */
146
+ _historyPos = /* @__PURE__ */ new Map();
147
+ /** The numbering of each window's `_historyPos` (`HistoryPosition.historyId`), when known. */
148
+ _historyId = /* @__PURE__ */ new Map();
149
+ /** Windows to fetch again when their run ends (`takeRefetchDue`, `markRefetchDue`). */
150
+ _refetchDue = /* @__PURE__ */ new Set();
151
+ /**
152
+ * Windows whose rows are behind their history position. A write asked for a
153
+ * tail read that has not landed yet (in flight, failed, or waiting for the
154
+ * run's end). The position stays the newest write seen, so a read older than
155
+ * it is stale. But it is not a bookmark. The reconnect ladder reads the tail,
156
+ * and a later write also reads the tail instead of applying in place.
157
+ */
158
+ _tailDue = /* @__PURE__ */ new Set();
159
+ /** Per window, the numberings it left for another numbering. A read in one of them is older than the window. */
160
+ _retiredHistoryIds = /* @__PURE__ */ new Map();
161
+ /**
162
+ * Windows that saw their current run start (`run:start`, live or replayed).
163
+ * If a run ends in a hydrated window that never saw it start, the window
164
+ * missed the run's first rows. This happens after a drop that main could not
165
+ * replay, or when the window opened mid-run. The rows it read meanwhile also
166
+ * sit below the rows it streamed since. So it reads its tail at the run's
167
+ * end (`takeRefetchDue`).
168
+ */
169
+ _runStarted = /* @__PURE__ */ new Set();
170
+ /**
171
+ * Windows that streamed rows since their last run boundary (a run's start or
172
+ * end, a page read). With `_running`, it tells a run whose start went by
173
+ * apart from a send that the host refused before it started. A refused send
174
+ * streams nothing, and its error row lives only in this store. Reading the
175
+ * tail drops that row.
176
+ */
177
+ _runActivity = /* @__PURE__ */ new Set();
114
178
  _listenersBySession = /* @__PURE__ */ new Map();
115
179
  _listenersForHas = /* @__PURE__ */ new Set();
116
180
  /**
@@ -242,27 +306,178 @@ var SessionStreamStore = class {
242
306
  return this._pages.get(sessionId) ?? NO_PAGE;
243
307
  }
244
308
  /**
245
- * Hydrate one replay page as the session's full window — the
246
- * `loadEvents` (tail page) path. One notify covers both the events
247
- * swap and the page-state swap.
309
+ * Hydrate one replay page as the session's full window (the
310
+ * `loadEvents` tail page path). One notify covers both the events
311
+ * swap and the page-state swap. Returns `false` and changes nothing
312
+ * when the page is older than a write the window applied since.
248
313
  *
249
314
  * @param sessionId - The session.
250
315
  * @param page - The persisted page.
251
316
  */
252
317
  setEventsPage(sessionId, page) {
318
+ if (this._freshness(sessionId, page) === "stale") return false;
319
+ if (page.pos !== void 0) this._setHistoryPos(sessionId, page.pos, page.historyId);
320
+ this._tailDue.delete(sessionId);
253
321
  const had = this._events.has(sessionId);
254
322
  const wasHydrated = this._pages.has(sessionId);
255
323
  const prior = this._events.get(sessionId) ?? [];
256
- const next = wasHydrated ? reconcileEvents(prior, page.events) : mergeLiveTail(prior, page.events);
324
+ const next = wasHydrated ? reconcileEvents(prior, page.events) : mergeLiveTail(this._withoutSavedLocalPrompts(sessionId, prior, page.events), page.events);
257
325
  inheritRowIdentity(prior, next);
258
326
  this._events.set(sessionId, next);
259
- this._pages.set(sessionId, {
260
- firstSeq: page.firstSeq,
261
- hasMore: page.hasMore,
262
- loadingEarlier: false
263
- });
327
+ this._pages.set(sessionId, pageState(page, false));
328
+ this._runActivity.delete(sessionId);
264
329
  this._notifySession(sessionId);
265
330
  if (!had || !wasHydrated) this._notifyHas();
331
+ return true;
332
+ }
333
+ /**
334
+ * Applies one history write (`history:changed`) to the session's window.
335
+ * It uses the shared rule (`applyHistoryOp`, `zidane/chat/pure`). A
336
+ * streamed append changes nothing. An append that never streamed adds the
337
+ * rows it carries. A rewrite or a missed write asks for a fetch.
338
+ *
339
+ * Returns `true` when the caller must fetch the session's tail now and
340
+ * replace the window with it (`setEventsPage`). A window whose run streams
341
+ * fetches at the run's end instead (`takeRefetchDue`), and a window never
342
+ * hydrated is left to its first read.
343
+ *
344
+ * @param sessionId - The session.
345
+ * @param change - The write, as the signal carries it.
346
+ */
347
+ applyHistory(sessionId, change) {
348
+ const events = this._events.get(sessionId) ?? [];
349
+ const context = this._historyContext(sessionId);
350
+ const result = applyHistoryOp(events, change, context);
351
+ return this._applyHistoryResult(sessionId, events, result, context);
352
+ }
353
+ /**
354
+ * Applies a shared history rule's answer to the window. Its position moves
355
+ * first. Then its rows change, or it asks for a tail read. It returns `true`
356
+ * for a read now. While the run streams, the read waits for the run's end.
357
+ * A window whose rows are behind (`_tailDue`) reads its tail on any write
358
+ * that moves it. It does not apply the write to rows that miss the earlier one.
359
+ */
360
+ _applyHistoryResult(sessionId, events, result, context) {
361
+ this._setHistoryPos(sessionId, result.pos, result.historyId);
362
+ if (!this._pages.has(sessionId)) return false;
363
+ const moved = result.pos !== context.pos || result.historyId !== context.historyId;
364
+ if ("refetch" in result || moved && this._tailDue.has(sessionId)) {
365
+ this._tailDue.add(sessionId);
366
+ if (!this._running.get(sessionId)) return true;
367
+ this._refetchDue.add(sessionId);
368
+ return false;
369
+ }
370
+ if (result.rows !== events) {
371
+ this._events.set(sessionId, result.rows);
372
+ this._notifySession(sessionId);
373
+ }
374
+ return false;
375
+ }
376
+ /**
377
+ * Applies the reconnect ladder's second step to the session's window. That
378
+ * step brings the rows of the turns appended after its position
379
+ * (`sessions.historySince`, the shared `applyHistorySince`). Returns `true`
380
+ * when the caller must fetch the tail now (as {@link applyHistory} does).
381
+ *
382
+ * @param sessionId - The session.
383
+ * @param since - The rows and the position they bring the window to.
384
+ */
385
+ applyHistorySince(sessionId, since) {
386
+ const events = this._events.get(sessionId) ?? [];
387
+ const context = this._historyContext(sessionId);
388
+ const result = applyHistorySince(events, since, context);
389
+ return this._applyHistoryResult(sessionId, events, result, context);
390
+ }
391
+ /**
392
+ * Moves the window to `pos` after an adapter's own hydrate replaced it with
393
+ * a tail read at `pos`. Returns `stale` if the read is older than a write
394
+ * the window applied since. The adapter then reads it again.
395
+ *
396
+ * @param sessionId - The session.
397
+ * @param pos - The read's position, when the host named one.
398
+ * @param historyId - The numbering `pos` counts in, when the host named one.
399
+ */
400
+ adoptHistoryPos(sessionId, pos, historyId) {
401
+ const read = {
402
+ ...pos !== void 0 ? { pos } : {},
403
+ ...historyId !== void 0 ? { historyId } : {}
404
+ };
405
+ if (this._freshness(sessionId, read) === "stale") return "stale";
406
+ if (pos !== void 0) this._setHistoryPos(sessionId, pos, historyId);
407
+ this._tailDue.delete(sessionId);
408
+ return "fresh";
409
+ }
410
+ /** `readFreshness` against what the window applied, and the numberings it left. */
411
+ _freshness(sessionId, read) {
412
+ return readFreshness(read, this._historyPos.get(sessionId), this._historyId.get(sessionId), this._retiredHistoryIds.get(sessionId));
413
+ }
414
+ /** What the window applied last, for the shared history rules. */
415
+ _historyContext(sessionId) {
416
+ const pos = this._historyPos.get(sessionId);
417
+ const historyId = this._historyId.get(sessionId);
418
+ return {
419
+ ...pos !== void 0 ? { pos } : {},
420
+ ...historyId !== void 0 ? { historyId } : {}
421
+ };
422
+ }
423
+ /** Sets the window at `pos` of numbering `historyId`. If the numbering is unknown, none is kept. */
424
+ _setHistoryPos(sessionId, pos, historyId) {
425
+ this._historyPos.set(sessionId, pos);
426
+ const left = this._historyId.get(sessionId);
427
+ if (left !== void 0 && historyId !== void 0 && historyId !== left) {
428
+ const retired = this._retiredHistoryIds.get(sessionId) ?? /* @__PURE__ */ new Set();
429
+ retired.delete(historyId);
430
+ retired.add(left);
431
+ if (retired.size > RETIRED_HISTORY_IDS) retired.delete(retired.values().next().value);
432
+ this._retiredHistoryIds.set(sessionId, retired);
433
+ }
434
+ if (historyId !== void 0) this._historyId.set(sessionId, historyId);
435
+ else this._historyId.delete(sessionId);
436
+ }
437
+ /**
438
+ * Whether the session's window must be fetched again now that its run ended
439
+ * (see `applyHistory`, `markRefetchDue`). Clears the flag.
440
+ *
441
+ * @param sessionId - The session.
442
+ */
443
+ takeRefetchDue(sessionId) {
444
+ if (this._running.get(sessionId)) return false;
445
+ return this._refetchDue.delete(sessionId);
446
+ }
447
+ /**
448
+ * Asks for the session's window to be read again at its run's end (`takeRefetchDue`). It is for a read dropped
449
+ * because a run streamed when it came back, or for a read that kept coming back older than the window.
450
+ *
451
+ * @param sessionId - The session.
452
+ */
453
+ markRefetchDue(sessionId) {
454
+ this._refetchDue.add(sessionId);
455
+ }
456
+ /**
457
+ * Whether the session's rows are behind its history position. This is so
458
+ * when a write asked for a tail read that has not landed (in flight, failed,
459
+ * or waiting for the run's end). The reconnect ladder then reads the tail.
460
+ *
461
+ * @param sessionId - The session.
462
+ */
463
+ isTailDue(sessionId) {
464
+ return this._tailDue.has(sessionId);
465
+ }
466
+ /**
467
+ * The history position the session's window applied last. It is `undefined` before its first `history:changed` or positioned page.
468
+ *
469
+ * @param sessionId - The session.
470
+ */
471
+ getHistoryPosSnapshot(sessionId) {
472
+ return this._historyPos.get(sessionId);
473
+ }
474
+ /**
475
+ * The numbering of {@link getHistoryPosSnapshot}'s position, when known.
476
+ *
477
+ * @param sessionId - The session.
478
+ */
479
+ getHistoryIdSnapshot(sessionId) {
480
+ return this._historyId.get(sessionId);
266
481
  }
267
482
  /**
268
483
  * Splice an OLDER page in front of the hydrated window (lazy scrollback).
@@ -274,11 +489,7 @@ var SessionStreamStore = class {
274
489
  const existing = this._events.get(sessionId) ?? [];
275
490
  const wasHydrated = this._pages.has(sessionId);
276
491
  this._events.set(sessionId, [...page.events, ...existing]);
277
- this._pages.set(sessionId, {
278
- firstSeq: page.firstSeq,
279
- hasMore: page.hasMore,
280
- loadingEarlier: false
281
- });
492
+ this._pages.set(sessionId, pageState(page, false, this._pages.get(sessionId)));
282
493
  this._notifySession(sessionId);
283
494
  if (!wasHydrated) this._notifyHas();
284
495
  }
@@ -356,6 +567,13 @@ var SessionStreamStore = class {
356
567
  this._retry.clear();
357
568
  this._systemMd.clear();
358
569
  this._pages.clear();
570
+ this._historyPos.clear();
571
+ this._historyId.clear();
572
+ this._refetchDue.clear();
573
+ this._tailDue.clear();
574
+ this._retiredHistoryIds.clear();
575
+ this._runStarted.clear();
576
+ this._runActivity.clear();
359
577
  this._pendingEcho.clear();
360
578
  for (const sessionId of sessionIds) this._notifySession(sessionId);
361
579
  if (had) this._notifyHas();
@@ -374,6 +592,13 @@ var SessionStreamStore = class {
374
592
  this._retry.delete(sessionId);
375
593
  this._systemMd.delete(sessionId);
376
594
  this._pages.delete(sessionId);
595
+ this._historyPos.delete(sessionId);
596
+ this._historyId.delete(sessionId);
597
+ this._refetchDue.delete(sessionId);
598
+ this._tailDue.delete(sessionId);
599
+ this._retiredHistoryIds.delete(sessionId);
600
+ this._runStarted.delete(sessionId);
601
+ this._runActivity.delete(sessionId);
377
602
  this._notifySession(sessionId);
378
603
  if (!had || wasHydrated) this._notifyHas();
379
604
  }
@@ -403,6 +628,13 @@ var SessionStreamStore = class {
403
628
  this._fallback.delete(sessionId);
404
629
  this._retry.delete(sessionId);
405
630
  this._pages.delete(sessionId);
631
+ this._historyPos.delete(sessionId);
632
+ this._historyId.delete(sessionId);
633
+ this._refetchDue.delete(sessionId);
634
+ this._tailDue.delete(sessionId);
635
+ this._retiredHistoryIds.delete(sessionId);
636
+ this._runStarted.delete(sessionId);
637
+ this._runActivity.delete(sessionId);
406
638
  this._notifySession(sessionId);
407
639
  dropped = true;
408
640
  }
@@ -425,6 +657,13 @@ var SessionStreamStore = class {
425
657
  this._pages.delete(sessionId);
426
658
  this._pendingEcho.delete(sessionId);
427
659
  this._promptPreviews.delete(sessionId);
660
+ this._historyPos.delete(sessionId);
661
+ this._historyId.delete(sessionId);
662
+ this._refetchDue.delete(sessionId);
663
+ this._tailDue.delete(sessionId);
664
+ this._retiredHistoryIds.delete(sessionId);
665
+ this._runStarted.delete(sessionId);
666
+ this._runActivity.delete(sessionId);
428
667
  if (had) {
429
668
  this._notifySession(sessionId);
430
669
  this._notifyHas();
@@ -493,8 +732,9 @@ var SessionStreamStore = class {
493
732
  * @param text - The prompt text.
494
733
  * @param refs - The completions the prompt used (skills, files), for its chips.
495
734
  * @param rawAttachments - The prompt's attachments. Omitted for a pushed queued prompt, which takes the previews this client remembered for it.
735
+ * @param clientMessageId - The id the send gave the message (`SendOptions.clientMessageId`). The store matches the echo by it.
496
736
  */
497
- appendUserPrompt(sessionId, text, refs, rawAttachments) {
737
+ appendUserPrompt(sessionId, text, refs, rawAttachments, clientMessageId) {
498
738
  const had = this._events.has(sessionId);
499
739
  const events = this._events.get(sessionId)?.slice() ?? [];
500
740
  const attachments = rawAttachments === void 0 || missingPreviewData(rawAttachments) ? mergePromptPreviews(rawAttachments, this.takePromptPreviews(sessionId, text)) : rawAttachments;
@@ -506,7 +746,11 @@ var SessionStreamStore = class {
506
746
  };
507
747
  events.push(event);
508
748
  const pending = this._pendingEcho.get(sessionId) ?? [];
509
- pending.push(text);
749
+ pending.push({
750
+ text,
751
+ ...clientMessageId !== void 0 ? { clientMessageId } : {},
752
+ event
753
+ });
510
754
  this._pendingEcho.set(sessionId, pending);
511
755
  this._events.set(sessionId, events);
512
756
  this._notifySession(sessionId);
@@ -522,7 +766,7 @@ var SessionStreamStore = class {
522
766
  */
523
767
  dropPendingEcho(sessionId, text) {
524
768
  const pending = this._pendingEcho.get(sessionId);
525
- const index = pending?.indexOf(text) ?? -1;
769
+ const index = pending?.findIndex((p) => p.text === text) ?? -1;
526
770
  if (pending && index !== -1) pending.splice(index, 1);
527
771
  }
528
772
  /**
@@ -592,6 +836,8 @@ var SessionStreamStore = class {
592
836
  this._notifyHas();
593
837
  }
594
838
  this._running.set(signal.sessionId, true);
839
+ this._runStarted.add(signal.sessionId);
840
+ this._runActivity.delete(signal.sessionId);
595
841
  this._runSeq.set(signal.sessionId, (this._runSeq.get(signal.sessionId) ?? 0) + 1);
596
842
  this._fallback.delete(signal.sessionId);
597
843
  this._notifySession(signal.sessionId);
@@ -606,8 +852,12 @@ var SessionStreamStore = class {
606
852
  ...signal.detail ? { detail: signal.detail } : {}
607
853
  }];
608
854
  const had = this._events.has(signal.sessionId);
855
+ const wasRunning = this._running.get(signal.sessionId) === true;
609
856
  this._events.set(signal.sessionId, next);
610
857
  this._running.set(signal.sessionId, false);
858
+ const sawStart = this._runStarted.delete(signal.sessionId);
859
+ const streamed = this._runActivity.delete(signal.sessionId);
860
+ if (!sawStart && (wasRunning || streamed) && this._pages.has(signal.sessionId)) this._refetchDue.add(signal.sessionId);
611
861
  this._retry.delete(signal.sessionId);
612
862
  this._pendingEcho.delete(signal.sessionId);
613
863
  this._notifySession(signal.sessionId);
@@ -624,11 +874,13 @@ var SessionStreamStore = class {
624
874
  return;
625
875
  }
626
876
  case "event": {
877
+ if (signal.event.kind === "separator" && signal.echo && this._separateLocalPrompt(signal.sessionId)) return;
627
878
  if (signal.event.kind === "user-prompt" && signal.echo) {
628
879
  const pending = this._pendingEcho.get(signal.sessionId);
629
- const index = pending?.indexOf(signal.event.text) ?? -1;
880
+ const index = pending ? pendingEchoIndex(pending, signal.event) : -1;
630
881
  if (pending && index !== -1) {
631
- pending.splice(index, 1);
882
+ const [local] = pending.splice(index, 1);
883
+ if (signal.event.turnId !== void 0) this._bindLocalPrompt(signal.sessionId, local.event, signal.event.turnId);
632
884
  return;
633
885
  }
634
886
  }
@@ -643,6 +895,7 @@ var SessionStreamStore = class {
643
895
  const had = this._events.has(signal.sessionId);
644
896
  const prior = this._events.get(signal.sessionId) ?? [];
645
897
  this._events.set(signal.sessionId, this._append(prior, event));
898
+ this._runActivity.add(signal.sessionId);
646
899
  if (this._batch) this._notifySoon(signal.sessionId);
647
900
  else this._notifySession(signal.sessionId);
648
901
  if (!had) this._notifyHas();
@@ -662,17 +915,6 @@ var SessionStreamStore = class {
662
915
  if (signal.discardTurnId) this._discardThinking(signal.sessionId, signal.source, signal.discardTurnId);
663
916
  this._notifySession(signal.sessionId);
664
917
  return;
665
- case "prompt-turns": {
666
- const events = this._events.get(signal.sessionId);
667
- if (!events || events.length === 0) return;
668
- const next = retagUserPromptEventsFromRefs(events, signal.refs);
669
- if (next !== events) {
670
- inheritRowIdentity(events, next);
671
- this._events.set(signal.sessionId, next);
672
- this._notifySession(signal.sessionId);
673
- }
674
- return;
675
- }
676
918
  case "stream:retry:cleared":
677
919
  if (this._retry.get(signal.sessionId)?.source === signal.source) {
678
920
  this._retry.delete(signal.sessionId);
@@ -742,6 +984,60 @@ var SessionStreamStore = class {
742
984
  this._pendingNotify.clear();
743
985
  for (const id of ids) this._notifySession(id);
744
986
  }
987
+ /**
988
+ * Returns `live` without the prompts that this client appended and that the
989
+ * page already holds. These prompts still await their echo. They match by the
990
+ * send's message id, which the saved prompt carries (`origin.messageId`).
991
+ * Their pending entries stay, so the echo is still consumed. It binds
992
+ * nothing, because the row is gone.
993
+ */
994
+ _withoutSavedLocalPrompts(sessionId, live, page) {
995
+ const pending = this._pendingEcho.get(sessionId);
996
+ if (!pending?.length) return live;
997
+ const saved = /* @__PURE__ */ new Set();
998
+ for (const event of page) {
999
+ const messageId = event.kind === "user-prompt" ? event.clientMessageId ?? event.origin?.messageId : void 0;
1000
+ if (messageId !== void 0) saved.add(messageId);
1001
+ }
1002
+ const superseded = new Set(pending.flatMap((p) => p.clientMessageId !== void 0 && saved.has(p.clientMessageId) ? [p.event] : []));
1003
+ return superseded.size === 0 ? live : live.filter((event) => !superseded.has(event));
1004
+ }
1005
+ /**
1006
+ * Puts the host's exchange separator before the oldest prompt that this
1007
+ * client appended and whose echo has not come yet (`appendUserPrompt`).
1008
+ * Returns false when no such prompt is on show. The separator then appends
1009
+ * like any event.
1010
+ */
1011
+ _separateLocalPrompt(sessionId) {
1012
+ const local = this._pendingEcho.get(sessionId)?.[0]?.event;
1013
+ const events = this._events.get(sessionId);
1014
+ const at = local && events ? events.indexOf(local) : -1;
1015
+ if (!events || at === -1) return false;
1016
+ if (events[at - 1]?.kind !== "separator") {
1017
+ const next = events.slice();
1018
+ next.splice(at, 0, {
1019
+ kind: "separator",
1020
+ text: ""
1021
+ });
1022
+ this._events.set(sessionId, next);
1023
+ this._notifySession(sessionId);
1024
+ }
1025
+ return true;
1026
+ }
1027
+ /** Gives this client's optimistic prompt row the turn id its echo carries. A row that a reload replaced is left alone. */
1028
+ _bindLocalPrompt(sessionId, local, turnId) {
1029
+ const events = this._events.get(sessionId);
1030
+ const at = events?.indexOf(local) ?? -1;
1031
+ if (!events || at === -1) return;
1032
+ const next = events.slice();
1033
+ next[at] = {
1034
+ ...local,
1035
+ turnId
1036
+ };
1037
+ inheritRowIdentity(events, next);
1038
+ this._events.set(sessionId, next);
1039
+ this._notifySession(sessionId);
1040
+ }
745
1041
  /** Drop a stalled attempt's reasoning lane: the retry (or next model) streams its own, and the saved turn never holds it. */
746
1042
  _discardThinking(sessionId, source, turnId) {
747
1043
  const events = this._events.get(sessionId);
@@ -1,5 +1,4 @@
1
1
  import { ChatEvent } from "../host.js";
2
- import { PromptTurnRef } from "zidane/chat/pure";
3
2
  import { StreamEvent, SystemMdFile } from "zidane/chat";
4
3
  //#region src/chat/headless/streams/types.d.ts
5
4
  /** The model serving a run after it fell back from the one picked. */
@@ -31,6 +30,10 @@ interface SessionPageState {
31
30
  hasMore: boolean;
32
31
  /** Whether a fetch of the previous page is in flight. */
33
32
  loadingEarlier: boolean;
33
+ /** The history position at which the cursor (`firstSeq`) was taken. An older page whose `floor` is past it is of another history. */
34
+ pos?: number;
35
+ /** The numbering `pos` counts in. An older page of another numbering is of another history. */
36
+ historyId?: string;
34
37
  }
35
38
  /** One page of a session's persisted transcript (the tail, or the page before a sequence number). */
36
39
  interface SessionStreamPage {
@@ -40,6 +43,12 @@ interface SessionStreamPage {
40
43
  firstSeq: number;
41
44
  /** Whether older turns exist before the page. */
42
45
  hasMore: boolean;
46
+ /** The history position the page was read at (`SessionEventsPage.pos`), when the host named one. */
47
+ pos?: number;
48
+ /** The session's floor when the page was read (set with `pos`). */
49
+ floor?: number;
50
+ /** The numbering `pos` counts in (`HistoryPosition.historyId`). */
51
+ historyId?: string;
43
52
  }
44
53
  /**
45
54
  * The live signals the session stream store reduces: zidane's host signals
@@ -101,12 +110,6 @@ type SessionStreamSignal<K extends string = string> =
101
110
  sessionId: K;
102
111
  source: string;
103
112
  } |
104
- /** Prompt turns just persisted: binds them to their live `user-prompt` rows. */
105
- {
106
- kind: 'prompt-turns';
107
- sessionId: K;
108
- refs: readonly PromptTurnRef[];
109
- } |
110
113
  /** The `SYSTEM.md` override the session's prompt was composed with, or `null`. */
111
114
  {
112
115
  kind: 'system-md';
@@ -32,6 +32,7 @@ declare const TRANSCRIPT_LABELS: {
32
32
  interactionAnsweredBy: (who: string) => string;
33
33
  badgePathUnavailable: string;
34
34
  badgeNoComposer: string;
35
+ badgeActionFailed: string;
35
36
  badgeCopied: string;
36
37
  badgeOpenIn: (app: string) => string;
37
38
  badgeOpenInBrowserPane: string;
@@ -1,3 +1,4 @@
1
+ import { errorMessage } from "../../components/report-error.js";
1
2
  import { useChatLabels } from "../useChatLabels.js";
2
3
  import { useTranscriptRenderers } from "../transcript/renderers.js";
3
4
  import { BTN, BTN_DANGER, BTN_PRIMARY, CardError, INPUT, useAutoFocus } from "./card-ui.js";
@@ -43,7 +44,7 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
43
44
  ...comment.trim() ? { comment: comment.trim() } : {}
44
45
  });
45
46
  } catch (err) {
46
- setError(err.message ?? String(err));
47
+ setError(errorMessage(err));
47
48
  setBusy(false);
48
49
  }
49
50
  };
@@ -82,7 +83,10 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
82
83
  className: BTN,
83
84
  children: labels.back
84
85
  }),
85
- /* @__PURE__ */ jsx(CardError, { error }),
86
+ /* @__PURE__ */ jsx(CardError, {
87
+ error: error && labels.answerSendFailed,
88
+ detail: error
89
+ }),
86
90
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
87
91
  /* @__PURE__ */ jsx("button", {
88
92
  type: "button",
@@ -110,7 +114,10 @@ function PlanCard({ request, autoFocus = false, onAnswer, Markdown, className, s
110
114
  className: BTN_DANGER,
111
115
  children: labels.planReject
112
116
  }),
113
- /* @__PURE__ */ jsx(CardError, { error }),
117
+ /* @__PURE__ */ jsx(CardError, {
118
+ error: error && labels.answerSendFailed,
119
+ detail: error
120
+ }),
114
121
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
115
122
  /* @__PURE__ */ jsx("button", {
116
123
  type: "button",
@@ -1,3 +1,4 @@
1
+ import { errorMessage } from "../../components/report-error.js";
1
2
  import { useChatLabels } from "../useChatLabels.js";
2
3
  import { useTranscriptRenderers } from "../transcript/renderers.js";
3
4
  import { BTN_GHOST_LEADING, BTN_PRIMARY, CardError, INPUT, useAutoFocus } from "./card-ui.js";
@@ -71,7 +72,7 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
71
72
  ...instructions.trim() ? { instructions: instructions.trim() } : {}
72
73
  });
73
74
  } catch (err) {
74
- setError(err.message ?? String(err));
75
+ setError(errorMessage(err));
75
76
  setBusy(false);
76
77
  }
77
78
  };
@@ -99,7 +100,7 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
99
100
  try {
100
101
  await onDismiss();
101
102
  } catch (err) {
102
- setError(err.message ?? String(err));
103
+ setError(errorMessage(err));
103
104
  setBusy(false);
104
105
  }
105
106
  };
@@ -172,7 +173,10 @@ function QuestionForm({ request, autoFocus = false, onAnswer, onDismiss, Markdow
172
173
  className: BTN_GHOST_LEADING,
173
174
  children: labels.dismiss
174
175
  }),
175
- /* @__PURE__ */ jsx(CardError, { error }),
176
+ /* @__PURE__ */ jsx(CardError, {
177
+ error: error && labels.answerSendFailed,
178
+ detail: error
179
+ }),
176
180
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
177
181
  /* @__PURE__ */ jsx("button", {
178
182
  type: "button",
@@ -16,8 +16,10 @@ declare const FIELD = "zg-well text-zg-ui px-2.5";
16
16
  declare const INPUT = "zg-well text-zg-ui px-2.5 w-full placeholder:text-[var(--zg-text-subtle)]";
17
17
  /** Props for {@link CardError}. */
18
18
  interface CardErrorProps {
19
- /** The message to show, or `null` to render nothing. */
19
+ /** The message to show, worded for people, or `null` to render nothing. */
20
20
  error: string | null;
21
+ /** The raw words behind it (an exception's message): folded under Details. */
22
+ detail?: string | null;
21
23
  /** Extra classes on the root element. */
22
24
  className?: string;
23
25
  /** Inline styles on the root element, merged after the component's own. */
@@ -26,9 +28,9 @@ interface CardErrorProps {
26
28
  /**
27
29
  * Renders an inline error message, or nothing when there is none.
28
30
  *
29
- * @param props - Component props: the `error` text.
31
+ * @param props - Component props: the `error` message and its raw `detail`.
30
32
  */
31
- declare function CardError({ error, className, style }: CardErrorProps): import("react").JSX.Element | null;
33
+ declare function CardError({ error, detail, className, style }: CardErrorProps): import("react").JSX.Element | null;
32
34
  /**
33
35
  * Move keyboard focus to the card's first focusable control when asked
34
36
  * (the card became the head, or the user came through "Open inbox").