@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +175 -123
  2. package/bin/dsh-tui.js +748 -22
  3. package/cordis.patch.yml +42 -13
  4. package/cordis.yml +5 -2
  5. package/lib/types/activityPrefs.d.ts +24 -0
  6. package/lib/types/activityPrefs.d.ts.map +1 -1
  7. package/lib/types/activityPrefs.js +50 -1
  8. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  9. package/lib/types/adapter/channel/session-projection.js +2 -0
  10. package/lib/types/adapter/channel/state.d.ts.map +1 -1
  11. package/lib/types/adapter/channel/state.js +3 -1
  12. package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
  13. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  14. package/lib/types/adapter/channel/ui-policy.js +6 -2
  15. package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
  16. package/lib/types/adapter/kernel/host-facade.js +1 -0
  17. package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
  18. package/lib/types/adapter/kernel/replay.js +3 -0
  19. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  20. package/lib/types/adapter/kernel/runtime.js +2 -0
  21. package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
  22. package/lib/types/adapter/kernel/slices/workspace.js +1 -0
  23. package/lib/types/adapter/ports/channel-ui.d.ts +29 -5
  24. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  25. package/lib/types/adapter/ports/channel-view.d.ts +66 -12
  26. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  27. package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
  28. package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
  29. package/lib/types/adapter/ports/channel.d.ts +4 -1
  30. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  31. package/lib/types/adapter/ports/workspace.d.ts +2 -0
  32. package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
  33. package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
  34. package/lib/types/adapter/upstream/workspace-driver.js +10 -2
  35. package/lib/types/commands.d.ts.map +1 -1
  36. package/lib/types/commands.js +1 -0
  37. package/lib/types/components/ActivityLine.d.ts +7 -2
  38. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  39. package/lib/types/components/ActivityLine.js +0 -8
  40. package/lib/types/components/ContextBarView.d.ts +15 -7
  41. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  42. package/lib/types/components/ContextBarView.js +26 -22
  43. package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
  44. package/lib/types/components/ImagePreviewOverlay.js +11 -5
  45. package/lib/types/components/Markdown.d.ts +11 -1
  46. package/lib/types/components/Markdown.d.ts.map +1 -1
  47. package/lib/types/components/Markdown.js +20 -2
  48. package/lib/types/components/MermaidDiagram.d.ts +13 -0
  49. package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
  50. package/lib/types/components/MermaidDiagram.js +61 -0
  51. package/lib/types/components/MessageList.d.ts +26 -1
  52. package/lib/types/components/MessageList.d.ts.map +1 -1
  53. package/lib/types/components/MessageList.js +74 -8
  54. package/lib/types/components/PageMargin.d.ts +1 -1
  55. package/lib/types/components/PromptInput.d.ts +37 -1
  56. package/lib/types/components/PromptInput.d.ts.map +1 -1
  57. package/lib/types/components/PromptInput.js +291 -30
  58. package/lib/types/components/ScrollbarGutter.d.ts +20 -5
  59. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  60. package/lib/types/components/ScrollbarGutter.js +88 -10
  61. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  62. package/lib/types/components/SplitDiffView.js +2 -1
  63. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  64. package/lib/types/components/StreamingMarkdown.js +30 -28
  65. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  66. package/lib/types/components/SubagentCard.js +12 -6
  67. package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
  68. package/lib/types/components/SubagentDetailScene.js +8 -3
  69. package/lib/types/components/Tooltip.d.ts.map +1 -1
  70. package/lib/types/components/Tooltip.js +45 -7
  71. package/lib/types/components/design-system/HintLine.d.ts +1 -2
  72. package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
  73. package/lib/types/components/design-system/HintLine.js +1 -2
  74. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
  75. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  76. package/lib/types/components/messages/AssistantThinkingMessage.js +2 -1
  77. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
  78. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  79. package/lib/types/components/messages/AssistantToolUseMessage.js +30 -26
  80. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  81. package/lib/types/components/messages/UserPromptMessage.js +5 -7
  82. package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
  83. package/lib/types/components/messages/useImageInspection.js +19 -9
  84. package/lib/types/components/promptDraftCache.d.ts +102 -0
  85. package/lib/types/components/promptDraftCache.d.ts.map +1 -0
  86. package/lib/types/components/promptDraftCache.js +76 -0
  87. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
  88. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  89. package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
  90. package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
  91. package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
  92. package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
  93. package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
  94. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  95. package/lib/types/components/sessions/SessionListRow.js +52 -5
  96. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
  97. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
  98. package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
  99. package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
  100. package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
  101. package/lib/types/dsh-adapter/activity-store.js +359 -0
  102. package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
  103. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
  104. package/lib/types/dsh-adapter/bundled-presets.js +80 -0
  105. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
  106. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  107. package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
  108. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
  109. package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
  110. package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
  111. package/lib/types/dsh-adapter/channel/background-action.d.ts +1 -1
  112. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  113. package/lib/types/dsh-adapter/channel/background-action.js +53 -29
  114. package/lib/types/dsh-adapter/channel/binding-events.d.ts +8 -6
  115. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  116. package/lib/types/dsh-adapter/channel/binding-events.js +5 -4
  117. package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
  118. package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
  119. package/lib/types/dsh-adapter/channel/binding.js +78 -18
  120. package/lib/types/dsh-adapter/channel/compaction.d.ts +0 -1
  121. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  122. package/lib/types/dsh-adapter/channel/compaction.js +0 -2
  123. package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
  124. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
  126. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
  127. package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
  128. package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
  129. package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
  130. package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
  131. package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
  132. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
  133. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
  135. package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
  136. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  137. package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
  138. package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
  139. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
  141. package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
  142. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  143. package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
  144. package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
  145. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/channel/projection.js +29 -19
  147. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  148. package/lib/types/dsh-adapter/channel/reports.js +4 -12
  149. package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
  150. package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
  151. package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
  152. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  153. package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
  154. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +4 -1
  155. package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
  156. package/lib/types/dsh-adapter/channel/session-live-adoption.js +2 -0
  157. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
  158. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/session-metadata.js +6 -4
  160. package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
  161. package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/session-reset.js +0 -1
  163. package/lib/types/dsh-adapter/channel/session-resume.d.ts +12 -3
  164. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  165. package/lib/types/dsh-adapter/channel/session-resume.js +292 -94
  166. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  167. package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
  168. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  169. package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
  170. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  171. package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
  172. package/lib/types/dsh-adapter/channel/state.d.ts +6 -1
  173. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  174. package/lib/types/dsh-adapter/channel/state.js +3 -3
  175. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +21 -1
  176. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  177. package/lib/types/dsh-adapter/channel/subagent-projection.js +173 -6
  178. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/transcript.js +6 -12
  180. package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
  181. package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
  182. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
  183. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  184. package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
  185. package/lib/types/dsh-adapter/channel.d.ts +1 -1
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  187. package/lib/types/dsh-adapter/channel.js +82 -20
  188. package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
  189. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  190. package/lib/types/dsh-adapter/compat/index.js +1 -1
  191. package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
  192. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
  193. package/lib/types/dsh-adapter/compat/messages.js +15 -0
  194. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
  195. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  196. package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
  197. package/lib/types/dsh-adapter/compat/settings.d.ts +35 -0
  198. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
  199. package/lib/types/dsh-adapter/compat/settings.js +57 -0
  200. package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
  201. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
  202. package/lib/types/dsh-adapter/compat/shell.js +11 -0
  203. package/lib/types/dsh-adapter/contract.d.ts +5 -4
  204. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/contract.js +17 -6
  206. package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
  207. package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
  208. package/lib/types/dsh-adapter/ide-channel.js +556 -0
  209. package/lib/types/dsh-adapter/index.d.ts +18 -3
  210. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/index.js +32 -5
  212. package/lib/types/dsh-adapter/plugin.d.ts +4 -1
  213. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  214. package/lib/types/dsh-adapter/plugin.js +197 -49
  215. package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
  216. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  217. package/lib/types/dsh-adapter/preset-resolution.js +10 -0
  218. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
  219. package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
  220. package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
  221. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  222. package/lib/types/dsh-adapter/sessionTree.js +3 -2
  223. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  224. package/lib/types/dsh-adapter/settings-sections.js +7 -4
  225. package/lib/types/dsh-adapter/subagents.d.ts +16 -3
  226. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  227. package/lib/types/dsh-adapter/subagents.js +92 -29
  228. package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
  229. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  230. package/lib/types/dsh-adapter/workspaces.js +116 -0
  231. package/lib/types/effortPrefs.d.ts +15 -3
  232. package/lib/types/effortPrefs.d.ts.map +1 -1
  233. package/lib/types/effortPrefs.js +37 -3
  234. package/lib/types/history.d.ts +13 -1
  235. package/lib/types/history.d.ts.map +1 -1
  236. package/lib/types/history.js +15 -2
  237. package/lib/types/homePrefs.d.ts +15 -0
  238. package/lib/types/homePrefs.d.ts.map +1 -0
  239. package/lib/types/homePrefs.js +53 -0
  240. package/lib/types/i18n.d.ts +347 -297
  241. package/lib/types/i18n.d.ts.map +1 -1
  242. package/lib/types/i18n.js +133 -85
  243. package/lib/types/ink/colorize.d.ts +10 -0
  244. package/lib/types/ink/colorize.d.ts.map +1 -1
  245. package/lib/types/ink/colorize.js +21 -0
  246. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  247. package/lib/types/ink/components/ScrollBox.js +12 -1
  248. package/lib/types/ink/dom.d.ts +1 -0
  249. package/lib/types/ink/dom.d.ts.map +1 -1
  250. package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
  251. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  252. package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
  253. package/lib/types/ink/ink.d.ts.map +1 -1
  254. package/lib/types/ink/ink.js +36 -1
  255. package/lib/types/ink/log-update.d.ts.map +1 -1
  256. package/lib/types/ink/log-update.js +19 -1
  257. package/lib/types/ink/output.d.ts +10 -1
  258. package/lib/types/ink/output.d.ts.map +1 -1
  259. package/lib/types/ink/output.js +109 -17
  260. package/lib/types/ink/render-border.d.ts +6 -1
  261. package/lib/types/ink/render-border.d.ts.map +1 -1
  262. package/lib/types/ink/render-border.js +25 -9
  263. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  264. package/lib/types/ink/render-node-to-output.js +48 -6
  265. package/lib/types/ink/renderer.d.ts +6 -0
  266. package/lib/types/ink/renderer.d.ts.map +1 -1
  267. package/lib/types/ink/renderer.js +2 -1
  268. package/lib/types/ink/selection.d.ts +88 -0
  269. package/lib/types/ink/selection.d.ts.map +1 -1
  270. package/lib/types/ink/selection.js +164 -0
  271. package/lib/types/ink/sixel-graphics.d.ts +19 -1
  272. package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
  273. package/lib/types/ink/sixel-graphics.js +124 -12
  274. package/lib/types/ink/terminal-image.d.ts +18 -1
  275. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  276. package/lib/types/ink/terminal.d.ts +17 -0
  277. package/lib/types/ink/terminal.d.ts.map +1 -1
  278. package/lib/types/ink/terminal.js +20 -1
  279. package/lib/types/screens/Chat.d.ts +20 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +296 -76
  282. package/lib/types/screens/SessionSupervisor.d.ts +84 -0
  283. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
  284. package/lib/types/screens/SessionSupervisor.js +350 -0
  285. package/lib/types/screens/SessionTree.js +2 -2
  286. package/lib/types/screens/Settings.d.ts.map +1 -1
  287. package/lib/types/screens/Settings.js +32 -9
  288. package/lib/types/screens/StatusLine.d.ts +18 -1
  289. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  290. package/lib/types/screens/StatusLine.js +38 -19
  291. package/lib/types/screens/StatusMetrics.d.ts +79 -22
  292. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  293. package/lib/types/screens/StatusMetrics.js +153 -88
  294. package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
  295. package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
  296. package/lib/types/screens/sessionSupervisor/model.js +69 -0
  297. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
  298. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
  299. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
  300. package/lib/types/sessionMounts.d.ts +272 -0
  301. package/lib/types/sessionMounts.d.ts.map +1 -0
  302. package/lib/types/sessionMounts.js +706 -0
  303. package/lib/types/sessions/format.d.ts.map +1 -1
  304. package/lib/types/sessions/format.js +4 -1
  305. package/lib/types/sessions/resumeFailure.d.ts +38 -0
  306. package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
  307. package/lib/types/sessions/resumeFailure.js +58 -0
  308. package/lib/types/terminal-utils/mermaid.d.ts +44 -0
  309. package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
  310. package/lib/types/terminal-utils/mermaid.js +83 -0
  311. package/lib/types/tips.d.ts.map +1 -1
  312. package/lib/types/tips.js +175 -19
  313. package/lib/types/tuiDisplayPrefs.d.ts +7 -9
  314. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
  315. package/lib/types/tuiDisplayPrefs.js +31 -28
  316. package/lib/types/update.d.ts +61 -0
  317. package/lib/types/update.d.ts.map +1 -1
  318. package/lib/types/update.js +194 -0
  319. package/lib/types/utils/fold-long-lines.d.ts +1 -1
  320. package/lib/types/utils/fold-long-lines.js +1 -1
  321. package/lib/types/utils/imageResize.d.ts +90 -0
  322. package/lib/types/utils/imageResize.d.ts.map +1 -0
  323. package/lib/types/utils/imageResize.js +272 -0
  324. package/lib/types/utils/keymap.d.ts +5 -1
  325. package/lib/types/utils/keymap.d.ts.map +1 -1
  326. package/lib/types/utils/keymap.js +23 -0
  327. package/lib/types/working-activity.d.ts +10 -9
  328. package/lib/types/working-activity.d.ts.map +1 -1
  329. package/lib/types/working-activity.js +17 -10
  330. package/lib/types/workspaces.d.ts +2 -1
  331. package/lib/types/workspaces.d.ts.map +1 -1
  332. package/lib/types/workspaces.js +1 -1
  333. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
  334. package/package.json +126 -105
  335. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  336. package/presets/liangshen/agent.cordis.yml +15 -0
  337. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
  338. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
  339. package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
  340. package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
  341. package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
  342. package/lib/types/dsh-adapter/channel/activity.js +0 -113
  343. package/lib/types/screens/AgentView.d.ts +0 -23
  344. package/lib/types/screens/AgentView.d.ts.map +0 -1
  345. package/lib/types/screens/AgentView.js +0 -546
  346. package/lib/types/screens/SessionBrowser.d.ts +0 -42
  347. package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
  348. package/lib/types/screens/SessionBrowser.js +0 -911
  349. package/lib/types/terminal-utils/terminal.d.ts +0 -18
  350. package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
  351. package/lib/types/terminal-utils/terminal.js +0 -96
@@ -1,12 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { Box, Text, NoSelect } from '../ui.js';
4
+ import { FRAME_INTERVAL_MS } from '../ink/constants.js';
4
5
  import { RAIL_MIN_TERMINAL_WIDTH, RAIL_WIDTH } from '../ink/timeline-rail.js';
5
6
  /** Thumb glyph across the 2-col gutter: solid, clearly positional —
6
7
  * deliberately distinct from the timeline's ━━ active tick. */
7
8
  const THUMB = '██';
8
9
  /** Rest time before the hover position chip pops (anti-flash sweep gate). */
9
10
  const CHIP_DWELL_MS = 250;
11
+ /**
12
+ * Post-landing settle reads (see the subscribe effect): how many deferred
13
+ * re-reads follow a landing before giving up. The re-pinning Ink pass lands
14
+ * a frame or two after the commit, so a single read can still catch the
15
+ * pre-landing geometry — the bound only exists so a frame that never
16
+ * settles cannot chain renders forever.
17
+ */
18
+ const PIN_SETTLE_CHECKS = 3;
10
19
  /**
11
20
  * Proportional scrollbar for the fullscreen transcript's gutter — the
12
21
  * `scrollbar` option of the `dsh-tui.scrollGutter` setting (the timeline
@@ -17,19 +26,38 @@ const CHIP_DWELL_MS = 250;
17
26
  * - clicking the track scrolls the clicked position to the viewport top
18
27
  * (classic scrollbar semantics — the thumb centers under the click
19
28
  * through the follow-up renders);
29
+ * - dragging the track scrubs the transcript: the drag protocol's
30
+ * per-target localRow maps through the SAME trackScrollTop as a click
31
+ * (absolute mapping — drag to point, no grabbed thumb offset), so a
32
+ * drag is a continuous run of click-to-position jumps. The mapping only
33
+ * reads the render-time maxScroll/trackH and never re-reads scrollTop
34
+ * mid-gesture, so a throttled/clamped scrollTo cannot feed back into the
35
+ * pointer mapping (no jitter). Dragging the thumb therefore lands the
36
+ * pointer's row at the viewport top, exactly like clicking that row;
37
+ * - a landing (drag or the back-to-bottom affordance) breaks and re-pins
38
+ * sticky, which unmounts the chrome that had shrunk the transcript row;
39
+ * the re-pinning Ink pass follows the commit and fires no subscriber
40
+ * notify, so the gutter re-reads the handle once that frame lands (see
41
+ * the subscribe effect). Without it the thumb stays painted from the
42
+ * shrunken viewport and floats a few rows above the bottom until an
43
+ * unrelated render (hover) re-reads the handle;
20
44
  * - the gutter is permanent while scrollable (Qwen's rule: an
21
45
  * auto-hiding gutter that changes content width rewraps everything);
22
46
  * hidden below 60 terminal columns or when the content fits (inline
23
47
  * mode keeps the terminal's native scrollback);
24
48
  * - NoSelect fences the glyphs out of click-drag text selection; the
25
- * wheel over the gutter scrolls the transcript.
26
- *
27
- * Thumb dragging is intentionally NOT implemented (Grok's MVP rule): a
28
- * proportional thumb encodes position, and the tick rail remains the
29
- * semantic navigator. Click-to-position covers the same need.
49
+ * wheel over the gutter scrolls the transcript. Because the track is a
50
+ * drag target, an unmodified left drag scrubs instead of selecting, and
51
+ * multi-clicks on the track no longer feed the select-line chain;
52
+ * Shift/Alt/Ctrl drags never open a drag session and keep the
53
+ * selection path.
30
54
  */
31
55
  export function ScrollbarGutter({ handle, terminalWidth, }) {
32
56
  const [, setTick] = React.useState(0);
57
+ // Geometry the last render painted with. The Ink render pass runs AFTER
58
+ // React's commit, so the commit that lands a pinned view can paint from
59
+ // geometry that pass is about to change (see the subscribe effect).
60
+ const geomRef = React.useRef('');
33
61
  // Hover readout: the row under the pointer brightens the thumb when it is
34
62
  // the hovered one, and floats a `62% · 340/540` chip left of the gutter
35
63
  // naming the position a click there would jump to. The chip is
@@ -53,12 +81,57 @@ export function ScrollbarGutter({ handle, terminalWidth, }) {
53
81
  React.useEffect(() => {
54
82
  if (!handle)
55
83
  return;
56
- return handle.subscribe(() => setTick(t => t + 1));
84
+ const readGeom = () => `${handle.getScrollTop()}:${handle.getScrollHeight()}:${handle.getViewportHeight()}`;
85
+ let timer = null;
86
+ let checksLeft = 0;
87
+ // Landing settle re-read. Reaching the bottom breaks and then re-pins
88
+ // sticky; the commit that consumes the notification paints while the
89
+ // chrome that shrank the transcript row (`PinnedTurnHeader` +
90
+ // "return to bottom" pill, both `!isSticky`) is still mounted, and the
91
+ // NEXT Ink pass then grows the viewport back and re-pins scrollTop to
92
+ // the taller maxScroll — with NO subscriber notify, because sticky
93
+ // never flips again (ScrollBox's subscribe contract). Nothing would
94
+ // re-read the handle, so the thumb stays painted from the shrunken
95
+ // viewport and floats above the bottom until an unrelated render
96
+ // (hover) rescues it. Re-read once that pass has landed and re-render
97
+ // if the geometry moved; only pinned notifications arm this (a landing
98
+ // is the one shape that can be re-pinned after the commit), so the
99
+ // cost is a couple of timers per landing, never per scroll frame.
100
+ const settle = () => {
101
+ timer = null;
102
+ if (readGeom() !== geomRef.current)
103
+ setTick(t => t + 1);
104
+ if (--checksLeft > 0)
105
+ timer = setTimeout(settle, FRAME_INTERVAL_MS);
106
+ };
107
+ const unsubscribe = handle.subscribe(() => {
108
+ setTick(t => t + 1);
109
+ if (!handle.isSticky())
110
+ return;
111
+ checksLeft = PIN_SETTLE_CHECKS;
112
+ if (timer === null)
113
+ timer = setTimeout(settle, FRAME_INTERVAL_MS);
114
+ });
115
+ return () => {
116
+ unsubscribe();
117
+ if (timer !== null)
118
+ clearTimeout(timer);
119
+ };
57
120
  }, [handle]);
121
+ // Geometry the last COMMITTED render painted with: captured during render,
122
+ // but the ref write happens in the layout effect below — this root is a
123
+ // ConcurrentRoot, so a render pass can be discarded, and a render-phase
124
+ // write would leak a frame that never painted into settle()'s diff.
125
+ const viewport = handle === null ? 0 : handle.getViewportHeight();
126
+ const content = handle === null ? 0 : handle.getScrollHeight();
127
+ const scrollTop = handle === null ? 0 : handle.getScrollTop();
128
+ const geom = handle === null ? null : `${scrollTop}:${content}:${viewport}`;
129
+ React.useLayoutEffect(() => {
130
+ if (geom !== null)
131
+ geomRef.current = geom;
132
+ }, [geom]);
58
133
  if (!handle)
59
134
  return null;
60
- const viewport = handle.getViewportHeight();
61
- const content = handle.getScrollHeight();
62
135
  const maxScroll = Math.max(0, content - viewport);
63
136
  if (viewport < 2 || content <= viewport || terminalWidth < RAIL_MIN_TERMINAL_WIDTH)
64
137
  return null;
@@ -67,10 +140,12 @@ export function ScrollbarGutter({ handle, terminalWidth, }) {
67
140
  // top follows scrollTop over the scroll range.
68
141
  const thumbH = Math.max(2, Math.round((viewport * viewport) / content));
69
142
  const trackH = Math.max(1, viewport - thumbH);
70
- const thumbTop = Math.round((handle.getScrollTop() / Math.max(1, maxScroll)) * trackH);
143
+ const thumbTop = Math.round((scrollTop / Math.max(1, maxScroll)) * trackH);
71
144
  const thumbBottom = Math.min(viewport, thumbTop + thumbH);
72
145
  // Clicking the track maps the clicked row's position on the track back
73
146
  // to a scrollTop and scrolls that content position to the viewport top.
147
+ // Dragging reuses the same mapping per motion through the drag protocol's
148
+ // target-relative localRow (the outer track is the single drag target).
74
149
  const trackScrollTop = (y) => {
75
150
  if (y <= 0)
76
151
  return 0;
@@ -78,6 +153,9 @@ export function ScrollbarGutter({ handle, terminalWidth, }) {
78
153
  return maxScroll;
79
154
  return Math.round((y / trackH) * maxScroll);
80
155
  };
156
+ const applyDragRow = (event) => {
157
+ handle.scrollTo(trackScrollTop(event.localRow));
158
+ };
81
159
  const rows = [];
82
160
  for (let y = 0; y < viewport; y++) {
83
161
  const inThumb = y >= thumbTop && y < thumbBottom;
@@ -115,5 +193,5 @@ export function ScrollbarGutter({ handle, terminalWidth, }) {
115
193
  return (_jsx(NoSelect, { children: _jsxs("ink-box", { onWheel: e => {
116
194
  if (e.deltaY !== 0)
117
195
  handle.scrollBy(e.deltaY);
118
- }, style: { flexDirection: 'column', flexShrink: 0, width: RAIL_WIDTH }, children: [rows, hoverChip] }) }));
196
+ }, onDragStart: applyDragRow, onDragMove: applyDragRow, onDragEnd: applyDragRow, style: { flexDirection: 'column', flexShrink: 0, width: RAIL_WIDTH }, children: [rows, hoverChip] }) }));
119
197
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAO7D,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAG/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAwR3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAuB,EACvB,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C,GAAG,KAAK,CAAC,SAAS,CAwFlB"}
1
+ {"version":3,"file":"SplitDiffView.d.ts","sourceRoot":"","sources":["../../../src/components/SplitDiffView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAO7D,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAI/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAwR3D,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAuB,EACvB,MAAM,GACP,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IACvC,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C,GAAG,KAAK,CAAC,SAAS,CAwFlB"}
@@ -10,6 +10,7 @@ import { highlightLines, syntaxThemeSignature } from '../terminal-utils/syntaxRu
10
10
  export { chalkFromToken } from '../terminal-utils/syntaxTheme.js';
11
11
  export { parseAnsiRuns, highlightLines } from '../terminal-utils/syntaxRuns.js';
12
12
  import { getTheme } from '../theme.js';
13
+ import { t } from '../i18n.js';
13
14
  import { useTheme } from './design-system/ThemeProvider.js';
14
15
  import { revealLinesOf } from './smoothReveal.js';
15
16
  /** Replace tabs so width math and alignment hold (pi convention). */
@@ -274,5 +275,5 @@ export function SplitDiffView({ diffs, width, maxRows, verbose, toolBackground =
274
275
  ? undefined
275
276
  : { segments: newRuns !== undefined ? mergeRuns(newRuns, row.newWords) : row.newWords };
276
277
  return (_jsxs(Box, { flexDirection: "row", children: [_jsx(PaneLine, { side: oldSide, kind: row.kind === 'add' ? 'context' : row.kind, tone: "old", width: paneWidth, toolBackground: toolBackground }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { dimColor: true, children: "\u2502" }) }), _jsx(PaneLine, { side: newSide, kind: row.kind === 'del' ? 'context' : row.kind, tone: "new", width: paneWidth, toolBackground: toolBackground, padLeft: true })] }, index));
277
- }), hidden > 0 && (_jsx(Text, { dimColor: true, children: `… +${hidden} lines (ctrl+o to expand)` }))] }));
278
+ }), hidden > 0 && (_jsx(Text, { dimColor: true, children: t('lines-folded-expand', { n: hidden }) }))] }));
278
279
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAqMzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAyIlB"}
1
+ {"version":3,"file":"StreamingMarkdown.d.ts","sourceRoot":"","sources":["../../../src/components/StreamingMarkdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAuMzB,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAyIlB"}
@@ -4,7 +4,7 @@ import { marked } from 'marked';
4
4
  import Box from '../ink/components/Box.js';
5
5
  import { formatToken, stripPromptXMLTags } from '../terminal-utils/markdown.js';
6
6
  import { t } from '../i18n.js';
7
- import { Markdown } from './Markdown.js';
7
+ import { isStandaloneToken, Markdown } from './Markdown.js';
8
8
  /**
9
9
  * Renders streaming markdown in sealed groups of completed top-level blocks.
10
10
  * Only the unsealed group and growing final block change as text arrives.
@@ -50,7 +50,7 @@ function clipSuffixTail(suffix, cut) {
50
50
  const UNSAFE_BOUNDARY = {
51
51
  safe: false,
52
52
  gap: 0,
53
- endsWithTable: false,
53
+ endsWithNode: false,
54
54
  trailingEmptyTextNode: false,
55
55
  };
56
56
  /**
@@ -70,8 +70,8 @@ function blankTokenNewlines(type) {
70
70
  * Analyze the candidate stable tokens using the same formatter as Markdown.
71
71
  * Both split halves trim their outer whitespace, so the trailing newline count
72
72
  * determines the Yoga gap: one newline merely starts the next row; every
73
- * additional newline is one genuinely blank row. Tables are separate layout
74
- * nodes and therefore keep Markdown's fixed one-row node gap.
73
+ * additional newline is one genuinely blank row. Standalone nodes are
74
+ * separate layout nodes and therefore keep Markdown's fixed one-row node gap.
75
75
  *
76
76
  * Only the LAST token that can produce visible text decides the outcome, so
77
77
  * the region is walked backwards and formatted one token at a time instead of
@@ -79,14 +79,14 @@ function blankTokenNewlines(type) {
79
79
  * boundary. `formatToken` runs once for the common case.
80
80
  */
81
81
  function analyzeStableBoundary(tokens, suffixIndex) {
82
- // A table resets the accumulated text, so only the segment after the last
83
- // one matters; anything before it is already folded into the table branch.
82
+ // A standalone node resets the accumulated text, so only the segment after
83
+ // the last one matters; anything before it is already folded into the node branch.
84
84
  let segmentStart = 0;
85
- let hasTable = false;
85
+ let hasNode = false;
86
86
  for (let i = suffixIndex - 1; i >= 0; i--) {
87
- if (tokens[i].type === 'table') {
87
+ if (isStandaloneToken(tokens[i])) {
88
88
  segmentStart = i + 1;
89
- hasTable = true;
89
+ hasNode = true;
90
90
  break;
91
91
  }
92
92
  }
@@ -116,17 +116,17 @@ function analyzeStableBoundary(tokens, suffixIndex) {
116
116
  return {
117
117
  safe: true,
118
118
  gap: Math.max(0, trailingNewlines - 1),
119
- endsWithTable: false,
119
+ endsWithNode: false,
120
120
  trailingEmptyTextNode: false,
121
121
  };
122
122
  }
123
- if (hasTable) {
123
+ if (hasNode) {
124
124
  return {
125
125
  safe: true,
126
126
  gap: 1,
127
- endsWithTable: true,
128
- // Whitespace after the table still occupies a zero-height text node
129
- // between two tables.
127
+ endsWithNode: true,
128
+ // Whitespace after the node still occupies a zero-height text node
129
+ // between two standalone nodes.
130
130
  trailingEmptyTextNode: blankNewlines > 0,
131
131
  };
132
132
  }
@@ -141,14 +141,16 @@ function analyzeStableBoundary(tokens, suffixIndex) {
141
141
  function analyzeSuffixStart(tokens, startIndex) {
142
142
  let leadingNewlines = 0;
143
143
  for (let i = startIndex; i < tokens.length; i++) {
144
- const type = tokens[i]?.type;
145
- if (type === 'table')
146
- return { kind: 'table', leadingNewlines };
147
- if (type === 'space' || type === 'br') {
144
+ const token = tokens[i];
145
+ if (token === undefined)
146
+ break;
147
+ if (isStandaloneToken(token))
148
+ return { kind: 'node', leadingNewlines };
149
+ if (token.type === 'space' || token.type === 'br') {
148
150
  leadingNewlines += 1;
149
151
  continue;
150
152
  }
151
- if (type === 'def' || type === 'del' || type === 'html')
153
+ if (token.type === 'def' || token.type === 'del' || token.type === 'html')
152
154
  continue;
153
155
  return { kind: 'text', leadingNewlines };
154
156
  }
@@ -157,10 +159,10 @@ function analyzeSuffixStart(tokens, startIndex) {
157
159
  function gapBetween(boundary, start) {
158
160
  if (start.kind === undefined)
159
161
  return 0;
160
- if (boundary.endsWithTable) {
161
- return start.kind === 'table' && (boundary.trailingEmptyTextNode || start.leadingNewlines > 0) ? 2 : 1;
162
+ if (boundary.endsWithNode) {
163
+ return start.kind === 'node' && (boundary.trailingEmptyTextNode || start.leadingNewlines > 0) ? 2 : 1;
162
164
  }
163
- return start.kind === 'table' ? 1 : boundary.gap + start.leadingNewlines;
165
+ return start.kind === 'node' ? 1 : boundary.gap + start.leadingNewlines;
164
166
  }
165
167
  export function StreamingMarkdown({ children, dimColor = false, }) {
166
168
  // The prefix tracks source offsets; its rendered blocks are sealed once
@@ -173,7 +175,7 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
173
175
  const cutRef = React.useRef(0);
174
176
  const boundaryGapRef = React.useRef(0);
175
177
  const prefixVisibleRef = React.useRef(false);
176
- const prefixEndsWithTableRef = React.useRef(false);
178
+ const prefixEndsWithNodeRef = React.useRef(false);
177
179
  const prefixTrailingEmptyTextRef = React.useRef(false);
178
180
  const stripped = stripPromptXMLTags(children);
179
181
  // Reset if text was replaced (defensive; normally unmount handles this)
@@ -182,7 +184,7 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
182
184
  cutRef.current = 0;
183
185
  boundaryGapRef.current = 0;
184
186
  prefixVisibleRef.current = false;
185
- prefixEndsWithTableRef.current = false;
187
+ prefixEndsWithNodeRef.current = false;
186
188
  prefixTrailingEmptyTextRef.current = false;
187
189
  blocksRef.current = {
188
190
  blocks: [], end: 0, tokens: [], tail: '', tailGap: 0,
@@ -241,7 +243,7 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
241
243
  prefixRef.current = stripped.substring(0, boundary + advance);
242
244
  boundaryGapRef.current = stableBoundary.gap;
243
245
  prefixVisibleRef.current = true;
244
- prefixEndsWithTableRef.current = stableBoundary.endsWithTable;
246
+ prefixEndsWithNodeRef.current = stableBoundary.endsWithNode;
245
247
  prefixTrailingEmptyTextRef.current = stableBoundary.trailingEmptyTextNode;
246
248
  suffixTokenIndex = lastContentIdx;
247
249
  }
@@ -257,12 +259,12 @@ export function StreamingMarkdown({ children, dimColor = false, }) {
257
259
  ? { kind: 'text', leadingNewlines: 0 }
258
260
  : analyzeSuffixStart(tokens, suffixTokenIndex);
259
261
  const boundaryGap = prefixVisibleRef.current && suffixStart.kind !== undefined
260
- ? prefixEndsWithTableRef.current
261
- ? suffixStart.kind === 'table' &&
262
+ ? prefixEndsWithNodeRef.current
263
+ ? suffixStart.kind === 'node' &&
262
264
  (prefixTrailingEmptyTextRef.current || suffixStart.leadingNewlines > 0)
263
265
  ? 2
264
266
  : 1
265
- : suffixStart.kind === 'table'
267
+ : suffixStart.kind === 'node'
266
268
  ? 1
267
269
  : boundaryGapRef.current + suffixStart.leadingNewlines
268
270
  : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CA0C/F"}
1
+ {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAAG,QAAQ,EAAE,aAAa,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAAE;AAEpH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAgD/F"}
@@ -9,7 +9,11 @@ function formatDuration(ms) {
9
9
  }
10
10
  export function SubagentCard({ subagent, focused, onClick }) {
11
11
  const running = subagent.status === 'running' || subagent.status === 'starting';
12
- const elapsed = subagent.completedAt ? subagent.completedAt - subagent.startedAt : Date.now() - subagent.startedAt;
12
+ // Only a live run ticks; discovered history (`unknown`) has no end time to
13
+ // count from, so it must not accumulate a fake growing duration.
14
+ const elapsed = running
15
+ ? Date.now() - subagent.startedAt
16
+ : subagent.completedAt !== undefined ? subagent.completedAt - subagent.startedAt : undefined;
13
17
  const total = subagent.tokens?.total ?? ((subagent.tokens?.input ?? 0) + (subagent.tokens?.output ?? 0) || 0);
14
18
  // Mouse affordance: clickable cards tint on hover; the keyboard-focused
15
19
  // card keeps its brand-color header (no double highlight).
@@ -22,12 +26,14 @@ export function SubagentCard({ subagent, focused, onClick }) {
22
26
  const liveLine = running ? subagent.output[subagent.output.length - 1] : undefined;
23
27
  const minimal = isMinimalMode();
24
28
  const glyph = running ? (minimal ? '·' : '🟡')
25
- : subagent.status === 'failed' || subagent.status === 'cancelled' ? (minimal ? '×' : '🔴')
26
- : (minimal ? '✓' : '🟢');
29
+ : subagent.status === 'unknown' ? (minimal ? '·' : '⚪')
30
+ : subagent.status === 'failed' || subagent.status === 'cancelled' ? (minimal ? '×' : '🔴')
31
+ : (minimal ? '✓' : '🟢');
27
32
  const glyphColor = minimal ? undefined
28
33
  : running ? 'warning'
29
- : subagent.status === 'failed' || subagent.status === 'cancelled' ? 'error'
30
- : 'success';
34
+ : subagent.status === 'unknown' ? 'subtle'
35
+ : subagent.status === 'failed' || subagent.status === 'cancelled' ? 'error'
36
+ : 'success';
31
37
  const hoverTint = onClick !== undefined && hovered && !focused;
32
- return _jsxs(Box, { flexDirection: "column", paddingLeft: 1, marginBottom: 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: glyphColor, children: glyph }), _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsx(Text, { dimColor: true, children: ` · ${formatDuration(elapsed)} · ${total || '—'} tok · ${subagent.toolCalls.length} tools` })] })] }), liveLine && _jsx(Text, { dimColor: true, wrap: "truncate", children: ` │ ${liveLine}` })] });
38
+ return _jsxs(Box, { flexDirection: "column", paddingLeft: 1, marginBottom: 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: glyphColor, children: glyph }), _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', total || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] })] }), liveLine && _jsx(Text, { dimColor: true, wrap: "truncate", children: ` │ ${liveLine}` })] });
33
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentDetailScene.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDetailScene.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAuGhE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,aAAa,CAAA;IACvB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,WAAW,GACZ,EAAE,wBAAwB,GAAG,KAAK,CAAC,SAAS,CA8M5C"}
1
+ {"version":3,"file":"SubagentDetailScene.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDetailScene.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAwGhE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,aAAa,CAAA;IACvB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,WAAW,GACZ,EAAE,wBAAwB,GAAG,KAAK,CAAC,SAAS,CAiN5C"}
@@ -28,6 +28,8 @@ function statusGlyph(status) {
28
28
  return { glyph: minimal ? '×' : '🔴', color: minimal ? undefined : 'error', label: 'failed' };
29
29
  if (status === 'cancelled')
30
30
  return { glyph: minimal ? '×' : '🔴', color: minimal ? undefined : 'error', label: 'cancelled' };
31
+ if (status === 'unknown')
32
+ return { glyph: minimal ? '·' : '⚪', color: minimal ? undefined : 'subtle', label: 'history' };
31
33
  return { glyph: minimal ? '·' : '🟡', color: minimal ? undefined : 'warning', label: 'running' };
32
34
  }
33
35
  const PAGES = ['summary', 'output', 'tools'];
@@ -37,7 +39,7 @@ function StatRow({ label, children }) {
37
39
  }
38
40
  /** Two-column key/value stats grid (Kimi Code settled summary style). */
39
41
  function StatGrid({ subagent, totalTokens, elapsed, statusLabel, statusColor }) {
40
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatRow, { label: t('subagent-status-label'), children: _jsx(Text, { color: statusColor, children: statusLabel }) }), _jsx(StatRow, { label: t('subagent-model'), children: _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }) }), _jsx(StatRow, { label: t('subagent-duration'), children: _jsx(Text, { children: formatDuration(elapsed) }) }), _jsx(StatRow, { label: "tokens", children: _jsxs(Text, { children: [totalTokens || '—', subagent.tokens?.input !== undefined ? ` (in ${subagent.tokens.input} · out ${subagent.tokens.output ?? 0})` : ''] }) }), _jsx(StatRow, { label: t('subagent-tools'), children: _jsx(Text, { children: subagent.toolCalls.length }) }), _jsx(StatRow, { label: t('subagent-started'), children: _jsx(Text, { children: formatTimestamp(subagent.startedAt) }) }), subagent.completedAt !== undefined && (_jsx(StatRow, { label: t('subagent-completed'), children: _jsx(Text, { children: formatTimestamp(subagent.completedAt) }) }))] }));
42
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatRow, { label: t('subagent-status-label'), children: _jsx(Text, { color: statusColor, children: statusLabel }) }), _jsx(StatRow, { label: t('subagent-model'), children: _jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }) }), _jsx(StatRow, { label: t('subagent-duration'), children: _jsx(Text, { children: elapsed !== undefined ? formatDuration(elapsed) : '—' }) }), _jsx(StatRow, { label: "tokens", children: _jsxs(Text, { children: [totalTokens || '—', subagent.tokens?.input !== undefined ? ` (in ${subagent.tokens.input} · out ${subagent.tokens.output ?? 0})` : ''] }) }), _jsx(StatRow, { label: t('subagent-tools'), children: _jsx(Text, { children: subagent.toolCalls.length }) }), _jsx(StatRow, { label: t('subagent-started'), children: _jsx(Text, { children: formatTimestamp(subagent.startedAt) }) }), subagent.completedAt !== undefined && (_jsx(StatRow, { label: t('subagent-completed'), children: _jsx(Text, { children: formatTimestamp(subagent.completedAt) }) }))] }));
41
43
  }
42
44
  /** Tool args line: JSON-looking args get cli-highlight syntax colors (loaded
43
45
  * lazily through the shared promise); anything else stays a dim flat line. */
@@ -77,7 +79,10 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
77
79
  const { rows, columns } = useTerminalSize();
78
80
  const [page, setPage] = React.useState('summary');
79
81
  const isRunning = subagent.status === 'running' || subagent.status === 'starting';
80
- const elapsed = subagent.completedAt ? subagent.completedAt - subagent.startedAt : Date.now() - subagent.startedAt;
82
+ // Only a live run ticks; discovered history (`unknown`) shows no duration.
83
+ const elapsed = isRunning
84
+ ? Date.now() - subagent.startedAt
85
+ : subagent.completedAt !== undefined ? subagent.completedAt - subagent.startedAt : undefined;
81
86
  const info = statusGlyph(subagent.status);
82
87
  const totalTokens = subagent.tokens?.total ?? ((subagent.tokens?.input ?? 0) + (subagent.tokens?.output ?? 0) || 0);
83
88
  const pageIndex = PAGES.indexOf(page);
@@ -137,6 +142,6 @@ export function SubagentDetailScene({ subagent, onBack, onInterrupt, }) {
137
142
  const active = page === name;
138
143
  return (_jsxs(React.Fragment, { children: [_jsx(Box, { onClick: () => setPage(name), backgroundColor: !active ? 'userMessageBackgroundHover' : undefined, children: _jsx(Text, { color: active ? 'accent' : undefined, bold: active, inverse: active, children: ` ${label} ` }) }), _jsx(Text, { dimColor: true, children: name === PAGES[PAGES.length - 1] ? '' : '│' })] }, name));
139
144
  };
140
- return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: info.color, bold: true, children: info.glyph }), _jsx(Text, { bold: true, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { color: info.color, children: info.label }), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onBack })] }), _jsxs(Text, { children: [_jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsx(Text, { dimColor: true, children: ` · ${formatDuration(elapsed)} · ${totalTokens || '—'} tok · ${subagent.toolCalls.length} tools` })] }), _jsxs(Text, { dimColor: true, children: [`${t('subagent-started')} ${formatTimestamp(subagent.startedAt)}`
145
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: info.color, bold: true, children: info.glyph }), _jsx(Text, { bold: true, children: `${t('subagent-card-prefix')}${subagent.description}` }), _jsx(Text, { dimColor: true, children: "\u00B7" }), _jsx(Text, { color: info.color, children: info.label }), _jsx(Box, { flexGrow: 1 }), _jsx(ExitButton, { onClick: onBack })] }), _jsxs(Text, { children: [_jsx(Text, { children: subagent.model ?? subagent.provider ?? 'default' }), _jsxs(Text, { dimColor: true, children: [elapsed !== undefined ? ` · ${formatDuration(elapsed)} · ` : ' · ', totalTokens || '—', " tok \u00B7 ", subagent.toolCalls.length, " tools"] })] }), _jsxs(Text, { dimColor: true, children: [`${t('subagent-started')} ${formatTimestamp(subagent.startedAt)}`
141
146
  + (subagent.completedAt ? ` · ${t('subagent-completed')} ${formatTimestamp(subagent.completedAt)}` : ''), ` · id ${subagent.agentId}`] }), subagent.error && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { color: "error", wrap: "wrap", children: `${t('subagent-error-label')}: ${subagent.error}` }) })), _jsxs(Box, { flexDirection: "row", gap: 0, marginTop: 1, children: [tab('summary', t('subagent-tab-summary')), tab('output', t('subagent-output-label')), tab('tools', t('subagent-tools')), _jsx(Text, { dimColor: true, children: ` ${pageIndex + 1}/${PAGES.length}` })] }), _jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(20, Math.min(72, columns - 6))) }), _jsx(Box, { flexDirection: "column", paddingX: 1, maxHeight: Math.max(10, rows - 14), children: _jsxs(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: [page === 'summary' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(StatGrid, { subagent: subagent, totalTokens: totalTokens, elapsed: elapsed, statusLabel: info.label, statusColor: info.color }), subagent.summary && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, bold: true, children: '─ summary ' }), _jsx(Text, { wrap: "wrap", children: subagent.summary })] })), !subagent.summary && (_jsx(Text, { dimColor: true, children: isRunning ? t('subagent-no-output') : t('subagent-no-summary') }))] })), page === 'output' && (subagent.outputEvents.length === 0 && subagent.output.length === 0 ? (_jsx(Text, { dimColor: true, children: t('subagent-no-output') })) : (subagent.outputEvents.map((line, index) => (_jsxs(Text, { wrap: "wrap", dimColor: line.kind === 'thinking' || line.kind === 'system', color: line.kind === 'error' ? 'error' : undefined, children: [line.kind === 'thinking' ? ' ⌁ ' : ' ', line.text, !line.settled && isRunning ? ' ▍' : ''] }, index))))), page === 'tools' && (subagent.toolCalls.length === 0 ? (_jsx(Text, { dimColor: true, children: t('subagent-no-tools') })) : (subagent.toolCalls.map((tool, index) => (_jsxs(Box, { flexDirection: "column", marginTop: index === 0 ? 0 : 1, children: [_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: tool.status === 'failed' ? 'error' : tool.status === 'running' ? 'warning' : 'success', children: tool.status === 'running' ? '·' : tool.status === 'failed' ? '×' : '✓' }), _jsx(Text, { color: toolNameColor(tool.name), children: tool.name }), tool.endedAt && _jsx(Text, { dimColor: true, children: formatDuration(tool.endedAt - tool.startedAt) })] }), tool.argsPreview && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(JsonArgsText, { raw: tool.argsPreview }) })), tool.resultPreview && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: `⎿ ${tool.resultPreview}` }) })), tool.error && (_jsx(Box, { flexDirection: "row", paddingLeft: 2, children: _jsx(Text, { color: "error", wrap: "wrap", children: tool.error }) }))] }, tool.id ?? index)))))] }) }), _jsx(Divider, { color: "subtle", title: "" }), _jsxs(Box, { marginTop: 0, flexDirection: "row", children: [_jsx(Text, { dimColor: true, children: `←/→ ${t('subagent-hint-page')} · ↑/↓ ${t('subagent-hint-scroll')}` }), isRunning && onInterrupt && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Box, { onClick: () => onInterrupt(subagent.agentId), children: _jsx(Text, { dimColor: true, bold: true, color: "warning", children: "X interrupt" }) })] })), _jsx(Text, { dimColor: true, children: ` · Esc ${t('subagent-hint-back')}` })] })] }));
142
147
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAqBlE,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IAC5C,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAA;CAAE,CAAA;AAEnE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,YAAY,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAYD,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAKjE;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,IAAI,YAAY,GAAG,IAAI,CAExD;AAcD,mEAAmE;AACnE,wBAAgB,YAAY,IAAI,IAAI,CAMnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAuC5F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,GAAG,KAAK,CAAC,SAAS,CAGlB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,eAAe,EACf,qBAAqB,GACtB,GAAE;IACD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,+EAA+E;IAC/E,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CACxD,GAAG,KAAK,CAAC,SAAS,CA4EvB"}
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AA0BlE,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IAC5C,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAA;CAAE,CAAA;AAEnE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,YAAY,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAYD,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAKjE;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,IAAI,YAAY,GAAG,IAAI,CAExD;AAcD,mEAAmE;AACnE,wBAAgB,YAAY,IAAI,IAAI,CAMnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAuC5F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,GAAG,KAAK,CAAC,SAAS,CAGlB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,eAAe,EACf,qBAAqB,GACtB,GAAE;IACD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,+EAA+E;IAC/E,qBAAqB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CACxD,GAAG,KAAK,CAAC,SAAS,CA8GvB"}
@@ -3,6 +3,8 @@ import React from 'react';
3
3
  import stripAnsi from 'strip-ansi';
4
4
  import { Box, Text, useTerminalSize } from '../ui.js';
5
5
  import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
6
+ import { useSelection } from '../ink/hooks/use-selection.js';
7
+ import { hasSelection } from '../ink/selection.js';
6
8
  import { stringWidth } from '../ink/stringWidth.js';
7
9
  import { getGraphemeSegmenter } from '../utils/intl.js';
8
10
  import { PageInsetContext } from './PageMargin.js';
@@ -17,6 +19,11 @@ import { PageInsetContext } from './PageMargin.js';
17
19
  * content already visible next to the pointer is noise, not detail (the
18
20
  * tool-call header gates on folded/clipped content for this reason).
19
21
  *
22
+ * Tooltips and text selection are mutually exclusive: a drag-copy reads the
23
+ * painted screen, and the card REPLACES the cells it covers, so
24
+ * {@link TooltipLayer} hides all tooltips while a selection drag or an
25
+ * active selection exists (see its subscription on selection mutations).
26
+ *
20
27
  * Hover events only exist in fullscreen (alternate screen + mouse
21
28
  * tracking); inline mode never fires the handlers, so the store can only
22
29
  * be written from a live fullscreen tree.
@@ -135,6 +142,29 @@ export function TooltipLayer({ invalidationKey, subscribeInvalidation, } = {}) {
135
142
  const { columns, rows } = useTerminalSize();
136
143
  const terminalFocused = useTerminalFocus();
137
144
  const tooltip = React.useSyncExternalStore(subscribeTooltip, getTooltipSnapshot);
145
+ // A text selection and a floating tooltip are mutually exclusive: the copy
146
+ // reads the PAINTED screen, and the tooltip card REPLACES the cells of the
147
+ // text it covers — dragging across a shown tooltip (or letting one pop
148
+ // mid-drag via its dwell timer) puts the tooltip fragment in the clipboard
149
+ // instead of the message text. Every selection mutation (drag start, each
150
+ // motion event, release, clear) funnels through this notification, so the
151
+ // layer goes dark the instant a drag begins and stays dark until the
152
+ // selection settles. The render guard below is belt-and-suspenders: a
153
+ // dwell that fires between two motion events must still never paint.
154
+ const selection = useSelection();
155
+ const selectionBusy = React.useSyncExternalStore(selection.subscribe, () => {
156
+ const state = selection.getState();
157
+ return state !== null && (state.isDragging || hasSelection(state));
158
+ }, () => false);
159
+ React.useEffect(() => {
160
+ return selection.subscribe(() => {
161
+ // Every selection mutation (drag start, motion, release, clear) resets
162
+ // the tooltip system wholesale: while busy the card must never paint,
163
+ // and the settle must also invalidate dwell timers armed while dark,
164
+ // so a finished copy is not immediately followed by a surprise card.
165
+ clearTooltip();
166
+ });
167
+ }, [selection]);
138
168
  // Remounts and modal/screen transitions invalidate shown AND pending tips.
139
169
  React.useEffect(() => {
140
170
  clearTooltip();
@@ -157,6 +187,9 @@ export function TooltipLayer({ invalidationKey, subscribeInvalidation, } = {}) {
157
187
  }, [columns, rows]);
158
188
  if (tooltip === null)
159
189
  return null;
190
+ // Never paint over an active drag/selection (see the subscription above).
191
+ if (selectionBusy)
192
+ return null;
160
193
  // A bordered card needs at least one content cell plus two border cells.
161
194
  // Below that, hiding is safer than creating geometry wider/taller than the
162
195
  // terminal (Yoga would clip unpredictably on 1–2 column/row resize states).
@@ -176,14 +209,19 @@ export function TooltipLayer({ invalidationKey, subscribeInvalidation, } = {}) {
176
209
  const height = lines.length + 2;
177
210
  // Prefer resting on the row ABOVE the anchor; when there is no room
178
211
  // (anchor at the top of the screen), drop below it, clamped on-screen.
179
- // The anchor coordinates are SCREEN coordinates (pointer events) while
180
- // the absolute box is placed relative to the content-area origin — under
181
- // PageMargin (root page inset) the offset must be added back, and the
182
- // clamp bounds run over the inset content area.
212
+ // The anchor is SCREEN geometry (pointer events) while the absolute box is
213
+ // placed relative to the inset content-area origin, and useTerminalSize()
214
+ // already reports the content size: convert the anchor into content
215
+ // coordinates first, then clamp inside the content area. Adding the inset
216
+ // (the earlier bug) moved the whole card by the page margin — with the
217
+ // default margin one row low and two columns right, so its bottom border
218
+ // landed ON the hovered row and that row's glyphs showed beside the card.
183
219
  const inset = React.useContext(PageInsetContext);
184
- const topAbove = tooltip.anchorRow - height;
185
- const top = Math.max(inset.y, Math.min(topAbove >= 0 ? topAbove : tooltip.anchorRow + 1, inset.y + Math.max(0, rows - height)));
186
- const left = Math.max(inset.x, Math.min(tooltip.anchorCol, inset.x + Math.max(0, columns - width)));
220
+ const anchorRow = tooltip.anchorRow - inset.y;
221
+ const anchorCol = tooltip.anchorCol - inset.x;
222
+ const topAbove = anchorRow - height;
223
+ const top = Math.max(0, Math.min(topAbove >= 0 ? topAbove : anchorRow + 1, Math.max(0, rows - height)));
224
+ const left = Math.max(0, Math.min(anchorCol, Math.max(0, columns - width)));
187
225
  return (_jsx(Box, { position: "absolute", left: left, top: top, width: width, height: height, flexDirection: "column", flexShrink: 0, borderStyle: "round", borderColor: "permission", backgroundColor: "toolCardBackground", children: lines.map((line, index) => (_jsx(Text, { wrap: "truncate-end", children: line === '' ? ' ' : line }, index))) }));
188
226
  }
189
227
  /**
@@ -2,8 +2,7 @@ import React from 'react';
2
2
  /**
3
3
  * Localized shortcut-hint line: renders a `t('hint-*')` string, with the
4
4
  * `**primary shortcut**` segment (the main action's key, wrapped in `**` in
5
- * the dict) in bold — the visual hierarchy KeyboardShortcutHint's `bold`
6
- * prop used to give. Wrap in `<Text dimColor italic>` for the common dim
5
+ * the dict) in bold. Wrap in `<Text dimColor italic>` for the common dim
7
6
  * styling, like the Byline it replaces.
8
7
  */
9
8
  export declare function HintLine({ text }: {
@@ -1 +1 @@
1
- {"version":3,"file":"HintLine.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/HintLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAUpE"}
1
+ {"version":3,"file":"HintLine.d.ts","sourceRoot":"","sources":["../../../../src/components/design-system/HintLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAUpE"}
@@ -3,8 +3,7 @@ import Text from './ThemedText.js';
3
3
  /**
4
4
  * Localized shortcut-hint line: renders a `t('hint-*')` string, with the
5
5
  * `**primary shortcut**` segment (the main action's key, wrapped in `**` in
6
- * the dict) in bold — the visual hierarchy KeyboardShortcutHint's `bold`
7
- * prop used to give. Wrap in `<Text dimColor italic>` for the common dim
6
+ * the dict) in bold. Wrap in `<Text dimColor italic>` for the common dim
8
7
  * styling, like the Byline it replaces.
9
8
  */
10
9
  export function HintLine({ text }) {
@@ -26,7 +26,8 @@ type Props = {
26
26
  onClick?(event: ClickEvent): void;
27
27
  };
28
28
  /**
29
- * Thinking block: settled rows fold to `⚓ Thinking (ctrl+o to expand)`;
29
+ * Thinking block: settled rows fold to `⚓ Thinking` plus the localized
30
+ * ctrl+o expand hint (hint-expand-ctrl-o);
30
31
  * streaming rows switch between a three-line preview and the full reasoning
31
32
  * text on click. The live leading mark is a rotating braille spinner
32
33
  * (`⠋⠙⠹…`, Kimi Code style), settling back to the static anchor (`⚓`). When
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantThinkingMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantThinkingMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAUjE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB;;;sDAGkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4CAA4C;IAC5C,eAAe,EAAE,OAAO,CAAA;IACxB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAA;IAChB;;4CAEwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;8EAE0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,OAAO,EACP,SAAiB,EACjB,OAAe,EACf,UAAU,EACV,UAAkB,EAClB,OAAO,GACR,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAuIzB"}
1
+ {"version":3,"file":"AssistantThinkingMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantThinkingMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAUjE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB;;;sDAGkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4CAA4C;IAC5C,eAAe,EAAE,OAAO,CAAA;IACxB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAA;IAChB;;4CAEwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;8EAE0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,OAAO,EACP,SAAiB,EACjB,OAAe,EACf,UAAU,EACV,UAAkB,EAClB,OAAO,GACR,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAuIzB"}
@@ -17,7 +17,8 @@ import { isMinimalMode } from '../../minimalMode.js';
17
17
  * to exactly this many rows, keeps the block height stream-independent. */
18
18
  const PREVIEW_ROWS = 3;
19
19
  /**
20
- * Thinking block: settled rows fold to `⚓ Thinking (ctrl+o to expand)`;
20
+ * Thinking block: settled rows fold to `⚓ Thinking` plus the localized
21
+ * ctrl+o expand hint (hint-expand-ctrl-o);
21
22
  * streaming rows switch between a three-line preview and the full reasoning
22
23
  * text on click. The live leading mark is a rotating braille spinner
23
24
  * (`⠋⠙⠹…`, Kimi Code style), settling back to the static anchor (`⚓`). When
@@ -15,8 +15,8 @@ type Props = {
15
15
  isExpanded?: boolean;
16
16
  /**
17
17
  * Mouse click (fullscreen): toggles the row's expansion — same action as
18
- * clicking other transcript rows. Also makes the `(ctrl+o to expand)`
19
- * hint actionable with the mouse.
18
+ * clicking other transcript rows. Also makes the localized ctrl+o expand
19
+ * hint (lines-folded-expand) actionable with the mouse.
20
20
  */
21
21
  onClick?(event: ClickEvent): void;
22
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantToolUseMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantToolUseMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAA8C,OAAO,EAAE,MAAM,8BAA8B,CAAA;AASvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAIjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,CAAA;IACb,4CAA4C;IAC5C,eAAe,EAAE,OAAO,CAAA;IACxB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,2EAA2E;IAC3E,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;8CAC0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAsFD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,CAKtD;AAsVD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,EACJ,eAAe,EACf,OAAO,EACP,UAAkB,EAClB,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,cAAuB,EACvB,UAAU,EACV,mBAA2B,EAC3B,YAAoB,EACpB,KAAa,EACb,aAAa,GACd,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA2PzB"}
1
+ {"version":3,"file":"AssistantToolUseMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/AssistantToolUseMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAA8C,OAAO,EAAE,MAAM,8BAA8B,CAAA;AASvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAIjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,CAAA;IACb,4CAA4C;IAC5C,eAAe,EAAE,OAAO,CAAA;IACxB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC,2EAA2E;IAC3E,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB;8CAC0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AA2FD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,KAAK,CAKtD;AAsVD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,EACJ,eAAe,EACf,OAAO,EACP,UAAkB,EAClB,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAmB,EACnB,cAAuB,EACvB,UAAU,EACV,mBAA2B,EAC3B,YAAoB,EACpB,KAAa,EACb,aAAa,GACd,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA2PzB"}