@deepseek-harness-tui/dsh-tui 0.9.3 → 0.10.0-beta.2

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 (267) hide show
  1. package/README.md +24 -6
  2. package/cordis.patch.yml +117 -39
  3. package/cordis.yml +13 -10
  4. package/lib/types/api.d.ts +7 -0
  5. package/lib/types/api.d.ts.map +1 -0
  6. package/lib/types/api.js +1 -0
  7. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  8. package/lib/types/cc/hyperlink.js +42 -4
  9. package/lib/types/cc/markdown.d.ts.map +1 -1
  10. package/lib/types/cc/markdown.js +15 -5
  11. package/lib/types/commands.d.ts +6 -0
  12. package/lib/types/commands.d.ts.map +1 -1
  13. package/lib/types/commands.js +12 -8
  14. package/lib/types/components/MessageList.d.ts +8 -4
  15. package/lib/types/components/MessageList.d.ts.map +1 -1
  16. package/lib/types/components/MessageList.js +94 -32
  17. package/lib/types/components/PermissionsPicker.d.ts +6 -7
  18. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  19. package/lib/types/components/PermissionsPicker.js +20 -14
  20. package/lib/types/components/PromptEditor.d.ts +46 -0
  21. package/lib/types/components/PromptEditor.d.ts.map +1 -0
  22. package/lib/types/components/PromptEditor.js +60 -0
  23. package/lib/types/components/PromptInput.d.ts +12 -0
  24. package/lib/types/components/PromptInput.d.ts.map +1 -1
  25. package/lib/types/components/PromptInput.js +1240 -205
  26. package/lib/types/components/RewindPicker.js +1 -1
  27. package/lib/types/components/SplitDiffView.d.ts +11 -1
  28. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  29. package/lib/types/components/SplitDiffView.js +9 -2
  30. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  31. package/lib/types/components/StreamingMarkdown.js +140 -3
  32. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  33. package/lib/types/components/SubagentDashboard.js +2 -2
  34. package/lib/types/components/SubagentDetailScene.js +1 -1
  35. package/lib/types/components/ThemePicker.d.ts +13 -15
  36. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  37. package/lib/types/components/ThemePicker.js +24 -26
  38. package/lib/types/components/Tooltip.d.ts +67 -0
  39. package/lib/types/components/Tooltip.d.ts.map +1 -0
  40. package/lib/types/components/Tooltip.js +220 -0
  41. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  42. package/lib/types/components/approvals/ApprovalPanel.js +1 -1
  43. package/lib/types/components/design-system/Divider.d.ts +14 -1
  44. package/lib/types/components/design-system/Divider.d.ts.map +1 -1
  45. package/lib/types/components/design-system/Divider.js +86 -8
  46. package/lib/types/components/design-system/ThemeProvider.d.ts +5 -2
  47. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  48. package/lib/types/components/design-system/ThemeProvider.js +52 -16
  49. package/lib/types/components/design-system/ThemedBox.d.ts +23 -2
  50. package/lib/types/components/design-system/ThemedBox.d.ts.map +1 -1
  51. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +11 -6
  52. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  53. package/lib/types/components/messages/AssistantThinkingMessage.js +10 -6
  54. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +13 -1
  55. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  56. package/lib/types/components/messages/AssistantToolUseMessage.js +37 -6
  57. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  58. package/lib/types/components/messages/UserPromptMessage.js +7 -1
  59. package/lib/types/components/questions/AskUserQuestionPanel.js +1 -1
  60. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  61. package/lib/types/components/questions/PlanReviewPanel.js +29 -3
  62. package/lib/types/components/sessions/SessionListRow.d.ts +8 -1
  63. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  64. package/lib/types/components/sessions/SessionListRow.js +9 -2
  65. package/lib/types/components/sessions/SessionPreview.d.ts.map +1 -1
  66. package/lib/types/components/sessions/SessionPreview.js +5 -3
  67. package/lib/types/components/sessions/WorkspaceListRow.d.ts +17 -0
  68. package/lib/types/components/sessions/WorkspaceListRow.d.ts.map +1 -0
  69. package/lib/types/components/sessions/WorkspaceListRow.js +27 -0
  70. package/lib/types/components/smoothReveal.d.ts +97 -0
  71. package/lib/types/components/smoothReveal.d.ts.map +1 -0
  72. package/lib/types/components/smoothReveal.js +279 -0
  73. package/lib/types/customTheme.d.ts +4 -0
  74. package/lib/types/customTheme.d.ts.map +1 -1
  75. package/lib/types/customTheme.js +9 -5
  76. package/lib/types/dsh-adapter/approvals.d.ts +114 -2
  77. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  78. package/lib/types/dsh-adapter/approvals.js +241 -3
  79. package/lib/types/dsh-adapter/channel.d.ts +59 -2
  80. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  81. package/lib/types/dsh-adapter/channel.js +499 -80
  82. package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -1
  83. package/lib/types/dsh-adapter/childStderr.js +9 -0
  84. package/lib/types/dsh-adapter/contract.d.ts +17 -13
  85. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  86. package/lib/types/dsh-adapter/contract.js +36 -27
  87. package/lib/types/dsh-adapter/credentialRefGuard.d.ts +40 -0
  88. package/lib/types/dsh-adapter/credentialRefGuard.d.ts.map +1 -0
  89. package/lib/types/dsh-adapter/credentialRefGuard.js +43 -0
  90. package/lib/types/dsh-adapter/effect-ledger.d.ts +1 -1
  91. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  92. package/lib/types/dsh-adapter/effect-ledger.js +1 -0
  93. package/lib/types/dsh-adapter/extensions.d.ts +4 -1
  94. package/lib/types/dsh-adapter/extensions.d.ts.map +1 -1
  95. package/lib/types/dsh-adapter/extensions.js +8 -1
  96. package/lib/types/dsh-adapter/index.d.ts +11 -1
  97. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  98. package/lib/types/dsh-adapter/index.js +2 -0
  99. package/lib/types/dsh-adapter/plugin-test-utils.d.ts +62 -0
  100. package/lib/types/dsh-adapter/plugin-test-utils.d.ts.map +1 -0
  101. package/lib/types/dsh-adapter/plugin-test-utils.js +61 -0
  102. package/lib/types/dsh-adapter/plugin.d.ts +20 -0
  103. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  104. package/lib/types/dsh-adapter/plugin.js +174 -39
  105. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  106. package/lib/types/dsh-adapter/plugins-info.js +12 -0
  107. package/lib/types/dsh-adapter/preset-resolution.d.ts +49 -0
  108. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -0
  109. package/lib/types/dsh-adapter/preset-resolution.js +42 -0
  110. package/lib/types/dsh-adapter/presets.d.ts +0 -26
  111. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  112. package/lib/types/dsh-adapter/presets.js +4 -14
  113. package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -1
  114. package/lib/types/dsh-adapter/promptDebug.js +4 -1
  115. package/lib/types/dsh-adapter/providerGuard.d.ts +75 -0
  116. package/lib/types/dsh-adapter/providerGuard.d.ts.map +1 -0
  117. package/lib/types/dsh-adapter/providerGuard.js +104 -0
  118. package/lib/types/dsh-adapter/questions-answerer.d.ts +49 -0
  119. package/lib/types/dsh-adapter/questions-answerer.d.ts.map +1 -0
  120. package/lib/types/dsh-adapter/questions-answerer.js +61 -0
  121. package/lib/types/dsh-adapter/recap.d.ts.map +1 -1
  122. package/lib/types/dsh-adapter/recap.js +12 -6
  123. package/lib/types/dsh-adapter/sanitize.d.ts.map +1 -1
  124. package/lib/types/dsh-adapter/sanitize.js +6 -1
  125. package/lib/types/dsh-adapter/sessions/digest.d.ts +21 -1
  126. package/lib/types/dsh-adapter/sessions/digest.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/sessions/digest.js +229 -3
  128. package/lib/types/dsh-adapter/sessions/frames.d.ts +3 -0
  129. package/lib/types/dsh-adapter/sessions/frames.d.ts.map +1 -1
  130. package/lib/types/dsh-adapter/sessions/frames.js +34 -19
  131. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/sessions/list.js +148 -31
  133. package/lib/types/dsh-adapter/sessions/store.d.ts +8 -0
  134. package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
  135. package/lib/types/dsh-adapter/sessions/store.js +24 -4
  136. package/lib/types/dsh-adapter/sessions/types.d.ts +3 -0
  137. package/lib/types/dsh-adapter/sessions/types.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  139. package/lib/types/dsh-adapter/settings-sections.js +13 -1
  140. package/lib/types/dsh-adapter/settingsEditor.d.ts +6 -0
  141. package/lib/types/dsh-adapter/settingsEditor.d.ts.map +1 -1
  142. package/lib/types/dsh-adapter/settingsEditor.js +15 -3
  143. package/lib/types/dsh-adapter/subagents.d.ts +4 -0
  144. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  145. package/lib/types/dsh-adapter/subagents.js +8 -0
  146. package/lib/types/dsh-adapter/themes.d.ts +51 -0
  147. package/lib/types/dsh-adapter/themes.d.ts.map +1 -0
  148. package/lib/types/dsh-adapter/themes.js +272 -0
  149. package/lib/types/dsh-adapter/toast.d.ts +67 -0
  150. package/lib/types/dsh-adapter/toast.d.ts.map +1 -0
  151. package/lib/types/dsh-adapter/toast.js +141 -0
  152. package/lib/types/dsh-adapter/types.d.ts +1 -1
  153. package/lib/types/extensions.d.ts +4 -0
  154. package/lib/types/extensions.d.ts.map +1 -1
  155. package/lib/types/extensions.js +5 -1
  156. package/lib/types/history.d.ts.map +1 -1
  157. package/lib/types/history.js +7 -2
  158. package/lib/types/hooks/useRuntimeThemeSnapshot.d.ts +10 -0
  159. package/lib/types/hooks/useRuntimeThemeSnapshot.d.ts.map +1 -0
  160. package/lib/types/hooks/useRuntimeThemeSnapshot.js +32 -0
  161. package/lib/types/i18n.d.ts +199 -41
  162. package/lib/types/i18n.d.ts.map +1 -1
  163. package/lib/types/i18n.js +82 -20
  164. package/lib/types/ink/components/App.d.ts +20 -0
  165. package/lib/types/ink/components/App.d.ts.map +1 -1
  166. package/lib/types/ink/components/App.js +142 -13
  167. package/lib/types/ink/components/Box.d.ts +39 -2
  168. package/lib/types/ink/components/Box.d.ts.map +1 -1
  169. package/lib/types/ink/components/Box.js +61 -37
  170. package/lib/types/ink/events/context-menu-event.d.ts +19 -0
  171. package/lib/types/ink/events/context-menu-event.d.ts.map +1 -0
  172. package/lib/types/ink/events/context-menu-event.js +20 -0
  173. package/lib/types/ink/events/drag-event.d.ts +44 -0
  174. package/lib/types/ink/events/drag-event.d.ts.map +1 -0
  175. package/lib/types/ink/events/drag-event.js +39 -0
  176. package/lib/types/ink/events/event-handlers.d.ts +8 -0
  177. package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
  178. package/lib/types/ink/events/event-handlers.js +8 -0
  179. package/lib/types/ink/hit-test.d.ts +69 -0
  180. package/lib/types/ink/hit-test.d.ts.map +1 -1
  181. package/lib/types/ink/hit-test.js +260 -6
  182. package/lib/types/ink/ink.d.ts +25 -0
  183. package/lib/types/ink/ink.d.ts.map +1 -1
  184. package/lib/types/ink/ink.js +74 -10
  185. package/lib/types/ink/parse-keypress.d.ts +20 -0
  186. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  187. package/lib/types/ink/parse-keypress.js +190 -22
  188. package/lib/types/ink/renderer.d.ts.map +1 -1
  189. package/lib/types/ink/renderer.js +15 -1
  190. package/lib/types/ink/screen.d.ts +7 -0
  191. package/lib/types/ink/screen.d.ts.map +1 -1
  192. package/lib/types/ink/screen.js +8 -1
  193. package/lib/types/ink/termio/osc.d.ts +2 -1
  194. package/lib/types/ink/termio/osc.d.ts.map +1 -1
  195. package/lib/types/ink/termio/osc.js +26 -5
  196. package/lib/types/plugin-spec/registry.d.ts +1 -1
  197. package/lib/types/plugin-spec/registry.js +1 -1
  198. package/lib/types/presetPrefs.d.ts +6 -5
  199. package/lib/types/presetPrefs.d.ts.map +1 -1
  200. package/lib/types/presetPrefs.js +10 -5
  201. package/lib/types/screens/Chat.d.ts +4 -1
  202. package/lib/types/screens/Chat.d.ts.map +1 -1
  203. package/lib/types/screens/Chat.js +169 -68
  204. package/lib/types/screens/SessionBrowser.d.ts +9 -4
  205. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  206. package/lib/types/screens/SessionBrowser.js +483 -75
  207. package/lib/types/screens/SessionTree.d.ts.map +1 -1
  208. package/lib/types/screens/SessionTree.js +5 -1
  209. package/lib/types/screens/Settings.d.ts.map +1 -1
  210. package/lib/types/screens/Settings.js +5 -1
  211. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  212. package/lib/types/screens/StatusLine.js +5 -1
  213. package/lib/types/screens/chatOverlay.d.ts +3 -2
  214. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  215. package/lib/types/screens/chatOverlay.js +2 -0
  216. package/lib/types/sessionPins.d.ts +33 -0
  217. package/lib/types/sessionPins.d.ts.map +1 -0
  218. package/lib/types/sessionPins.js +181 -0
  219. package/lib/types/sessions/format.d.ts +2 -0
  220. package/lib/types/sessions/format.d.ts.map +1 -1
  221. package/lib/types/sessions/format.js +9 -0
  222. package/lib/types/sessions/view.d.ts +42 -6
  223. package/lib/types/sessions/view.d.ts.map +1 -1
  224. package/lib/types/sessions/view.js +133 -35
  225. package/lib/types/test-utils.d.ts +2 -0
  226. package/lib/types/test-utils.d.ts.map +1 -0
  227. package/lib/types/test-utils.js +8 -0
  228. package/lib/types/theme.d.ts +22 -5
  229. package/lib/types/theme.d.ts.map +1 -1
  230. package/lib/types/theme.js +57 -7
  231. package/lib/types/themeCatalog.d.ts +36 -0
  232. package/lib/types/themeCatalog.d.ts.map +1 -0
  233. package/lib/types/themeCatalog.js +157 -0
  234. package/lib/types/tips.d.ts.map +1 -1
  235. package/lib/types/tips.js +114 -18
  236. package/lib/types/update.d.ts +159 -3
  237. package/lib/types/update.d.ts.map +1 -1
  238. package/lib/types/update.js +497 -16
  239. package/lib/types/utils/debug.d.ts.map +1 -1
  240. package/lib/types/utils/debug.js +2 -1
  241. package/lib/types/utils/keymap.d.ts +1 -1
  242. package/lib/types/utils/keymap.d.ts.map +1 -1
  243. package/lib/types/utils/keymap.js +19 -2
  244. package/lib/types/utils/urlGuard.d.ts +28 -0
  245. package/lib/types/utils/urlGuard.d.ts.map +1 -0
  246. package/lib/types/utils/urlGuard.js +21 -0
  247. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +3 -0
  248. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +7 -11
  249. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +16 -1
  250. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +23 -2
  251. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +5 -5
  252. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/pi-ai.d.ts +23 -0
  253. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/pi-ai.js +27 -0
  254. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +17 -3
  255. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +36 -4
  256. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +11 -12
  257. package/package.json +114 -74
  258. package/lib/types/dsh-adapter/packaged-skills.d.ts +0 -19
  259. package/lib/types/dsh-adapter/packaged-skills.d.ts.map +0 -1
  260. package/lib/types/dsh-adapter/packaged-skills.js +0 -78
  261. package/skills/audit/SKILL.md +0 -24
  262. package/skills/bug/SKILL.md +0 -27
  263. package/skills/pr-comments/SKILL.md +0 -20
  264. package/skills/practice/SKILL.md +0 -22
  265. package/skills/release-notes/SKILL.md +0 -25
  266. package/skills/review/SKILL.md +0 -25
  267. package/skills/vuln-check/SKILL.md +0 -25
@@ -18,11 +18,13 @@ import { stripNarration } from '../utils/narration.js';
18
18
  import { stringWidth } from '../ink/stringWidth.js';
19
19
  import { truncateToWidth } from '../ink/truncateToWidth.js';
20
20
  import { clipPreview } from '../ink/timeline-rail.js';
21
+ import { getRevealVersion, revealLengthOf, revealTextOf, subscribeReveal } from './smoothReveal.js';
21
22
  /**
22
23
  * Transcript rows rendered in the Claude Code visual language: user prompts
23
24
  * on a grey bubble with a `❯` pointer, assistant text with a `●` bullet and
24
- * markdown, thinking folded to `⚓ Thinking (ctrl+o to expand)`, tool calls as
25
- * status-dot cards. `expanded` (Ctrl+O) shows full reasoning + full tool
25
+ * markdown, thinking as a live three-line/full toggle then a settled
26
+ * `⚓ Thinking (ctrl+o to expand)` row, and tool calls as status-dot cards.
27
+ * `expanded` (Ctrl+O) shows full reasoning + full tool
26
28
  * args/results; `expandedRows` (message-selection mode, Enter) expands single
27
29
  * rows; `selectedId` highlights the selected row.
28
30
  */
@@ -47,13 +49,44 @@ const DEFAULT_ROW_HEIGHT = 2;
47
49
  /** Cold-start estimate of the header block above the rows; corrected by the
48
50
  * first layout measurement. */
49
51
  const DEFAULT_HEADER_LINES = 14;
50
- /** Stable fallbacks for the stream-fold props: verify/repro harnesses and
51
- * embedders render MessageList with prop sets that predate them, and the
52
+ /** Stable fallbacks for the stream-view toggle props: verify/repro harnesses
53
+ * and embedders render MessageList with prop sets that predate them, and the
52
54
  * render must not throw (same rule as Chat's stubbed channel APIs). Module
53
55
  * scope keeps the identities stable so MemoRow's shallow compare and the
54
56
  * toggle callback's deps never churn. */
55
- const NO_STREAM_FOLDED = new Set();
56
- const NOOP_TOGGLE_STREAM_FOLD = (_rowId) => { };
57
+ const NO_STREAM_VIEW_TOGGLED = new Set();
58
+ const NOOP_TOGGLE_STREAM_VIEW = (_rowId) => { };
59
+ // --- smooth-streaming display text -----------------------------------------
60
+ // Render-phase reads of the shared reveal cursors (see smoothReveal.ts for
61
+ // why the cursors live outside React). `active` gates cursor CREATION to
62
+ // live-arrived content (streaming rows, live-settled rows marked `fresh`,
63
+ // replayed history paints complete); once created, a cursor keeps revealing
64
+ // until it catches up — settling mid-reveal must not snap (that is the
65
+ // "non-streaming delivery becomes a smooth flow" contract).
66
+ function assistantRevealText(row, enabled) {
67
+ const stripped = stripNarration(row.text);
68
+ return revealTextOf(`a${row.id}`, stripped, {
69
+ enabled,
70
+ active: row.streaming === true || row.fresh === true,
71
+ });
72
+ }
73
+ function reasoningRevealText(row, enabled) {
74
+ return revealTextOf(`r${row.id}`, row.text, { enabled, active: row.streaming === true });
75
+ }
76
+ /** Display length only (layout signature; no slice allocation). */
77
+ function revealDisplayLen(row, enabled) {
78
+ if (row.kind === 'assistant') {
79
+ const stripped = stripNarration(row.text);
80
+ return revealLengthOf(`a${row.id}`, stripped, {
81
+ enabled,
82
+ active: row.streaming === true || row.fresh === true,
83
+ });
84
+ }
85
+ if (row.kind === 'reasoning') {
86
+ return revealLengthOf(`r${row.id}`, row.text, { enabled, active: row.streaming === true });
87
+ }
88
+ return row.text.length;
89
+ }
57
90
  /**
58
91
  * Per-kind layout signature PARTS: the O(1) identity of every input that
59
92
  * decides a row's rendered HEIGHT (see sigRef in MessageList). Fields are
@@ -75,11 +108,13 @@ const NOOP_TOGGLE_STREAM_FOLD = (_rowId) => { };
75
108
  * (parts.slice()).
76
109
  */
77
110
  const signatureScratch = [];
78
- function signatureParts(row, columns, expanded, expandedRows, streamFolded, thinkingVisible, thinkingFold, diffLayout, foldTerminalCommand, model, failureHintRowId, failureHint) {
111
+ function signatureParts(row, columns, expanded, expandedRows, streamViewToggledRows, thinkingVisible, thinkingFold, diffLayout, foldTerminalCommand, model, failureHintRowId, failureHint, displayTextLen) {
79
112
  signatureScratch.length = 0;
80
113
  // Universal height inputs: width reflows every row; kind switches height
81
- // semantics wholesale; text length drives wrapping.
82
- signatureScratch.push(columns, row.kind, row.text?.length ?? 0);
114
+ // semantics wholesale; text length drives wrapping. `displayTextLen` is the
115
+ // REVEALED length while smooth streaming is painting (the height follows
116
+ // what is on screen, not what has arrived).
117
+ signatureScratch.push(columns, row.kind, displayTextLen);
83
118
  switch (row.kind) {
84
119
  case 'assistant':
85
120
  // Streaming vs settled swaps renderers; Ctrl+O/per-row expand adds the
@@ -88,10 +123,9 @@ function signatureParts(row, columns, expanded, expandedRows, streamFolded, thin
88
123
  signatureScratch.push(row.streaming === true, expanded, expandedRows.has(row.id), expanded ? model : '');
89
124
  break;
90
125
  case 'reasoning':
91
- // thinkingFold (preview vs full) and the visibility filter change the
92
- // folded card's height; streaming shows verbose live unless the user
93
- // clicked it folded (streamFolded collapses to the ticker/header).
94
- signatureScratch.push(row.streaming === true, expanded, expandedRows.has(row.id), streamFolded.has(row.id), thinkingVisible, thinkingFold);
126
+ // thinkingFold (preview vs full), its per-row live override, and the
127
+ // visibility filter all change the card's height.
128
+ signatureScratch.push(row.streaming === true, expanded, expandedRows.has(row.id), streamViewToggledRows.has(row.id), thinkingVisible, thinkingFold);
95
129
  break;
96
130
  case 'tool': {
97
131
  const tool = row.tool;
@@ -119,7 +153,7 @@ function signatureParts(row, columns, expanded, expandedRows, streamFolded, thin
119
153
  }
120
154
  return signatureScratch;
121
155
  }
122
- export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, streamFoldedRows = NO_STREAM_FOLDED, onToggleStreamFold = NOOP_TOGGLE_STREAM_FOLD, model, diffLayout = 'auto', thinkingFold = 'preview', toolBackground = 'none', foldTerminalCommand = false, activityFrames, showAll, onToggleAll, onLoadOlder, thinkingVisible = true, historyPaintEnabled = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, onTimeline, failureHintRowId, failureHint, onOpenSubagent, onOpenFile, }) {
156
+ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, streamViewToggledRows = NO_STREAM_VIEW_TOGGLED, onToggleStreamView = NOOP_TOGGLE_STREAM_VIEW, model, diffLayout = 'auto', thinkingFold = 'preview', toolBackground = 'none', foldTerminalCommand = false, smoothStreaming = false, activityFrames, showAll, onToggleAll, onLoadOlder, thinkingVisible = true, historyPaintEnabled = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, onTimeline, failureHintRowId, failureHint, onOpenSubagent, onOpenFile, }) {
123
157
  const hiddenCount = rows.length - MAX_RENDERED_ROWS;
124
158
  // The thinking filter runs BEFORE virtualization so window indices line up.
125
159
  //
@@ -225,6 +259,13 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
225
259
  };
226
260
  // --- layout virtualization ---------------------------------------------
227
261
  const { columns, rows: termRows } = useTerminalSize();
262
+ // Smooth-reveal wakeups: the scheduler's tick bumps this store, re-running
263
+ // MessageList so the revealed `text`/line-count reads below feed fresh
264
+ // values through the same MemoRow-prop pipeline an arriving chunk uses —
265
+ // memo miss → re-render → post-commit height re-measure. Without this
266
+ // subscription a reveal living in child state would change row heights
267
+ // invisibly to the virtualization (stale cached heights → blank bands).
268
+ React.useSyncExternalStore(subscribeReveal, getRevealVersion);
228
269
  // Measured row heights, remembered after a row unmounts so virtualization
229
270
  // can compute total content height. Bounded: row ids grow monotonically
230
271
  // and rows are never removed from the transcript (foldRows keeps the
@@ -318,7 +359,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
318
359
  // reasoning height at once, remounting the widened window over rows
319
360
  // whose rendering never changed (Yoga spike + measure churn for
320
361
  // nothing). Base parts cover the universal height inputs.
321
- const parts = signatureParts(row, columns, expanded, expandedRows, streamFoldedRows, thinkingVisible, thinkingFold, diffLayout, foldTerminalCommand, model, failureHintRowId, failureHint);
362
+ const parts = signatureParts(row, columns, expanded, expandedRows, streamViewToggledRows, thinkingVisible, thinkingFold, diffLayout, foldTerminalCommand, model, failureHintRowId, failureHint, revealDisplayLen(row, smoothStreaming));
322
363
  const cachedParts = sigs.get(row.id);
323
364
  let same = false;
324
365
  if (cachedParts !== undefined && cachedParts.length === parts.length) {
@@ -832,7 +873,27 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
832
873
  const addMargin = margins.get(row.id) === true;
833
874
  const tool = row.tool;
834
875
  const subagent = row.kind === 'subagent' ? row.subagent : undefined;
835
- return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, executionTarget: row.executionTarget, streaming: row.streaming === true, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, subagent: subagent, onToggleRow: onToggleRow, onToggleStreamFold: onToggleStreamFold, streamFolded: streamFoldedRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenFile: onOpenFile, setRowRef: setRowRef }, row.id));
876
+ // Smooth reveal feeds the SAME flattened text prop a chunk feeds,
877
+ // and keeps the streaming layout alive until the reveal catches up
878
+ // (settling mid-reveal must not snap — a one-shot non-streaming
879
+ // delivery still paints as a flow).
880
+ let displayText = row.text;
881
+ let displayStreaming = row.streaming === true;
882
+ if (row.kind === 'assistant' && smoothStreaming) {
883
+ const stripped = stripNarration(row.text);
884
+ displayText = revealTextOf(`a${row.id}`, stripped, {
885
+ enabled: true,
886
+ active: displayStreaming || row.fresh === true,
887
+ });
888
+ displayStreaming = displayStreaming || displayText.length !== stripped.length;
889
+ }
890
+ else if (row.kind === 'assistant') {
891
+ displayText = stripNarration(row.text);
892
+ }
893
+ else if (row.kind === 'reasoning' && smoothStreaming) {
894
+ displayText = revealTextOf(`r${row.id}`, row.text, { enabled: true, active: displayStreaming });
895
+ }
896
+ return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: displayText, textFull: row.kind === 'reasoning' ? row.text : undefined, executionTarget: row.executionTarget, streaming: displayStreaming, durationMs: row.durationMs, time: row.time, addMargin: addMargin, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, smoothStreaming: smoothStreaming, fresh: row.fresh === true, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, subagent: subagent, onToggleRow: onToggleRow, onToggleStreamView: onToggleStreamView, streamViewToggled: streamViewToggledRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenFile: onOpenFile, setRowRef: setRowRef }, row.id));
836
897
  }), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
837
898
  }
838
899
  /** Load-earlier / show-previous divider row with a mouse hover tint — the
@@ -841,7 +902,7 @@ function ClickableDivider({ title, onClick }) {
841
902
  const [hovered, setHovered] = useState(false);
842
903
  return (_jsx(Box, { marginTop: 1, onClick: onClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), backgroundColor: hovered ? 'userMessageBackgroundHover' : undefined, children: _jsx(Divider, { title: title }) }));
843
904
  }
844
- function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, subagent, onToggleRow, onToggleStreamFold, streamFolded, onOpenSubagent, onOpenFile, setRowRef, }) {
905
+ function TranscriptRow({ rowId, kind, text, textFull, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, diffLayout, smoothStreaming, fresh, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, subagent, onToggleRow, onToggleStreamView, streamViewToggled, onOpenSubagent, onOpenFile, setRowRef, }) {
845
906
  const ref = React.useCallback((el) => {
846
907
  setRowRef(rowId, el);
847
908
  }, [setRowRef, rowId]);
@@ -854,13 +915,13 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
854
915
  return;
855
916
  onToggleRow(rowId);
856
917
  }, [onToggleRow, rowId]);
857
- // 流式 reasoning 行:点击折叠/展开 live 视图(默认展开,与落定行的
858
- // 默认折叠相反——所以走独立开关,落定后语义自动回到 foldOnClick)。
859
- const streamFoldOnClick = React.useCallback((event) => {
918
+ // 流式 reasoning 行:点击在三行预览/全文间切换。它反转 thinkingFold
919
+ // 的默认值,落定后语义自动回到 foldOnClick。
920
+ const streamViewOnClick = React.useCallback((event) => {
860
921
  if (event.cellIsBlank)
861
922
  return;
862
- onToggleStreamFold(rowId);
863
- }, [onToggleStreamFold, rowId]);
923
+ onToggleStreamView(rowId);
924
+ }, [onToggleStreamView, rowId]);
864
925
  // 子代理卡:点击打开详情场景(不是折叠)。
865
926
  const openSubagent = React.useCallback(() => {
866
927
  if (subagent !== undefined)
@@ -873,15 +934,16 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
873
934
  return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(UserPromptMessage, { text: text, addMargin: addMargin, isSelected: isSelected }) }));
874
935
  case 'assistant':
875
936
  return streaming ? (_jsxs(Box, { alignItems: "flex-start", flexDirection: "row", marginTop: addMargin ? 1 : 0, width: "100%", backgroundColor: background, ref: ref, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: "text", children: "\u25CF" }) }), _jsx(Box, { flexDirection: "column", children: _jsx(StreamingMarkdown, { children: stripNarration(text) }) })] })) : (_jsxs(Box, { width: "100%", flexDirection: "column", backgroundColor: background, ref: ref, children: [expanded && (_jsx(Box, { flexDirection: "row", justifyContent: "flex-end", gap: 1, marginTop: 1, children: _jsx(MessageMetadata, { timestamp: time, model: model }) })), _jsx(AssistantTextMessage, { text: stripNarration(text), addMargin: addMargin, isSelected: isSelected, isExpanded: isExpanded })] }));
876
- case 'reasoning':
877
- return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, addMargin: addMargin, streaming: streaming, preview: streaming &&
878
- !streamFolded &&
879
- thinkingFold === 'preview' &&
880
- !isExpanded,
881
- // Streaming reasoning shows expanded live (click collapses to the
882
- // ticker/header via streamFolded); settled rows keep the
883
- // fold-on-settle default and expand via expandedRows/Ctrl+O.
884
- verbose: isExpanded || expanded || (streaming && !streamFolded), durationMs: durationMs, isSelected: isSelected, onClick: streaming ? streamFoldOnClick : foldOnClick }) }));
937
+ case 'reasoning': {
938
+ // The setting chooses the live default; a row click reverses it. Global
939
+ // or per-row transcript expansion always wins and shows the full text.
940
+ const streamPreview = streaming && !expanded && !isExpanded &&
941
+ (streamViewToggled ? thinkingFold === 'full' : thinkingFold === 'preview');
942
+ return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantThinkingMessage, { thinking: text, textFull: textFull, addMargin: addMargin, streaming: streaming, preview: streamPreview,
943
+ // Settled rows keep the fold-on-settle default and expand via
944
+ // expandedRows/Ctrl+O; a live row is always preview or full.
945
+ verbose: isExpanded || expanded || (streaming && !streamPreview), durationMs: durationMs, isSelected: isSelected, onClick: streaming ? streamViewOnClick : foldOnClick }) }));
946
+ }
885
947
  case 'tool': {
886
948
  if (toolCallId === undefined ||
887
949
  toolName === undefined ||
@@ -906,7 +968,7 @@ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, duration
906
968
  startedAt: toolStartedAt,
907
969
  durationMs: toolDurationMs,
908
970
  };
909
- return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded, footnote: toolFootnote, diffLayout: diffLayout, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, onClick: foldOnClick, onOpenFile: onOpenFile }) }));
971
+ return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded, footnote: toolFootnote, diffLayout: diffLayout, toolBackground: toolBackground, smoothReveal: smoothStreaming, fresh: fresh, foldTerminalCommand: foldTerminalCommand, onClick: foldOnClick, onOpenFile: onOpenFile }) }));
910
972
  }
911
973
  case 'notice':
912
974
  return (_jsx(Box, { marginTop: 1, ref: ref, children: _jsx(Divider, { title: ` ${text} ` }) }));
@@ -1,18 +1,17 @@
1
1
  import React from 'react';
2
+ import type { PermissionPresetOption } from '../dsh-adapter/channel.js';
2
3
  /**
3
4
  * `/permission` sandbox-preset picker. The command itself is registered by
4
5
  * the harness side (dsh-sandbox-policy / dsh-base permission-presets row);
5
6
  * bare `/permission` opens this picker and Enter dispatches
6
7
  * `/permission <preset>` through the same external-command path a hand-typed
7
- * argument takes. The list mirrors the `sandbox/mode` vocabulary the session
8
- * modes use (`sessionModes.ts`), so the ✓ mark stays consistent with the
9
- * mode the TUI derives from the session log.
8
+ * argument takes. The roster comes from the adapter snapshot so host plugins
9
+ * can contribute additional preset identities without UI changes.
10
10
  */
11
- export declare const PERMISSION_PRESET_IDS: readonly ["read-only", "workspace-write", "danger-full-access"];
12
- export type PermissionPresetId = (typeof PERMISSION_PRESET_IDS)[number];
13
- export declare function PermissionsPicker({ focusIndex, currentMode, cwd, onPick, }: {
11
+ export declare function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }: {
12
+ options: readonly PermissionPresetOption[];
14
13
  focusIndex: number;
15
- currentMode: string | undefined;
14
+ currentValue: string | undefined;
16
15
  cwd: string;
17
16
  /** Mouse pick (fullscreen): clicked row's absolute index (Chat applies
18
17
  * the same code path as the keyboard Enter). */
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,iEAIxB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEvE,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,WAAW,EACX,GAAG,EACH,MAAM,GACP,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA4BlB"}
1
+ {"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAEvE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,UAAU,EACV,YAAY,EACZ,GAAG,EACH,MAAM,GACP,EAAE;IACD,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;IACX;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CAwClB"}
@@ -9,19 +9,25 @@ import { HintLine } from './design-system/HintLine.js';
9
9
  * the harness side (dsh-sandbox-policy / dsh-base permission-presets row);
10
10
  * bare `/permission` opens this picker and Enter dispatches
11
11
  * `/permission <preset>` through the same external-command path a hand-typed
12
- * argument takes. The list mirrors the `sandbox/mode` vocabulary the session
13
- * modes use (`sessionModes.ts`), so the ✓ mark stays consistent with the
14
- * mode the TUI derives from the session log.
12
+ * argument takes. The roster comes from the adapter snapshot so host plugins
13
+ * can contribute additional preset identities without UI changes.
15
14
  */
16
- export const PERMISSION_PRESET_IDS = [
17
- 'read-only',
18
- 'workspace-write',
19
- 'danger-full-access',
20
- ];
21
- export function PermissionsPicker({ focusIndex, currentMode, cwd, onPick, }) {
22
- return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('permission-picker-title') }) }), _jsx(Select, { options: [
23
- { value: 'read-only', label: t('permission-preset-readonly'), description: t('permission-preset-readonly-desc') },
24
- { value: 'workspace-write', label: t('permission-preset-workspace-write'), description: t('permission-preset-workspace-write-desc') },
25
- { value: 'danger-full-access', label: t('permission-preset-full-access'), description: t('permission-preset-full-access-desc') },
26
- ], focusIndex: focusIndex, selectedValue: currentMode, onPick: onPick ? index => onPick(index) : undefined }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) }), _jsx(Text, { dimColor: true, children: t('permission-root-hint', { cwd }) })] }) }));
15
+ export function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }) {
16
+ return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('permission-picker-title') }) }), _jsx(Select, { options: options.map(option => ({
17
+ value: option.value,
18
+ label: option.value === 'read-only'
19
+ ? t('permission-preset-readonly')
20
+ : option.value === 'workspace-write'
21
+ ? t('permission-preset-workspace-write')
22
+ : option.value === 'danger-full-access'
23
+ ? t('permission-preset-full-access')
24
+ : option.name,
25
+ description: option.value === 'read-only'
26
+ ? t('permission-preset-readonly-desc')
27
+ : option.value === 'workspace-write'
28
+ ? t('permission-preset-workspace-write-desc')
29
+ : option.value === 'danger-full-access'
30
+ ? t('permission-preset-full-access-desc')
31
+ : option.description ?? option.name,
32
+ })), focusIndex: focusIndex, selectedValue: currentValue, onPick: onPick ? index => onPick(index) : undefined }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) }), _jsx(Text, { dimColor: true, children: t('permission-root-hint', { cwd }) })] }) }));
27
33
  }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import type { Color } from '../ink/styles.js';
3
+ import type { Theme } from '../theme.js';
4
+ /**
5
+ * 全屏草稿编辑的挂载层。编辑状态(value/caret/选区/折叠)全部住在
6
+ * PromptInput 内部,展开视图却必须盖住整棵 Chat 树的每个后绘兄弟
7
+ * (StatusLine、OverlayAbove、TooltipLayer)——渲染器按树序绘制,
8
+ * absolute 浮层只有作为根 Box 的最后一个孩子才天然压过一切
9
+ * (TooltipLayer 的同款契约)。PromptInput 因此把展开视图的 React
10
+ * 节点发布到这个 module 级 store,`PromptEditorLayer`(挂在 Chat 根
11
+ * Box 末尾)订阅并渲染;节点是 PromptInput 每次渲染的新鲜闭包,
12
+ * 命中/拖拽/按钮 handler 无需任何额外的状态同步管道。
13
+ *
14
+ * 节点写入用 useInsertionEffect:sink 的同步重渲染发生在 layout
15
+ * 阶段之前,PromptInput 的 useDeclaredCursor(layout effect)读到
16
+ * 的 ref 已经指向编辑区的 Box,首帧光标声明即正确。
17
+ */
18
+ type EditorNode = React.ReactNode | null;
19
+ /** Publish (or withdraw, with null) the fullscreen editor subtree. */
20
+ export declare function setPromptEditorNode(node: EditorNode): void;
21
+ /**
22
+ * The fullscreen sink, mounted once at the very end of Chat's root Box.
23
+ * The absolute cover is `opaque` so its padding/blank cells never bleed
24
+ * the covered transcript through, and it swallows stray clicks so the
25
+ * conversation underneath cannot react to a click meant for the editor.
26
+ */
27
+ export declare function PromptEditorLayer(): React.ReactNode;
28
+ /**
29
+ * A mouse-friendly pill button for the editor chrome (send / collapse /
30
+ * the ⤢ close affordance). Hover swaps the surface so the affordance
31
+ * reads at a glance — the same interaction language as the transcript's
32
+ * clickable rows and the session browser's menu items.
33
+ */
34
+ export declare function EditorButton({ label, hint, onClick, primary, accent, }: {
35
+ /** Button text, e.g. `⏎ 发送`. */
36
+ label: string;
37
+ /** Dim trailing hint inside the pill, e.g. `Ctrl+Enter`. */
38
+ hint?: string;
39
+ onClick: () => void;
40
+ /** Filled variant (the primary action); default is the outline look. */
41
+ primary?: boolean;
42
+ /** Accent theme token / raw color for the filled variant. */
43
+ accent?: keyof Theme | Color;
44
+ }): React.ReactNode;
45
+ export {};
46
+ //# sourceMappingURL=PromptEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptEditor.d.ts","sourceRoot":"","sources":["../../../src/components/PromptEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC;;;;;;;;;;;;;GAaG;AAEH,KAAK,UAAU,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAA;AAKxC,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAI1D;AAaD;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,KAAK,CAAC,SAAS,CAqBnD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,GACP,EAAE;IACD,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,KAAK,GAAG,KAAK,CAAA;CAC7B,GAAG,KAAK,CAAC,SAAS,CAmClB"}
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Box, Text } from '../ui.js';
4
+ let editorNode = null;
5
+ const listeners = new Set();
6
+ /** Publish (or withdraw, with null) the fullscreen editor subtree. */
7
+ export function setPromptEditorNode(node) {
8
+ if (node === editorNode)
9
+ return;
10
+ editorNode = node;
11
+ for (const listener of listeners)
12
+ listener();
13
+ }
14
+ function subscribe(callback) {
15
+ listeners.add(callback);
16
+ return () => {
17
+ listeners.delete(callback);
18
+ };
19
+ }
20
+ function snapshot() {
21
+ return editorNode;
22
+ }
23
+ /**
24
+ * The fullscreen sink, mounted once at the very end of Chat's root Box.
25
+ * The absolute cover is `opaque` so its padding/blank cells never bleed
26
+ * the covered transcript through, and it swallows stray clicks so the
27
+ * conversation underneath cannot react to a click meant for the editor.
28
+ */
29
+ export function PromptEditorLayer() {
30
+ const node = React.useSyncExternalStore(subscribe, snapshot);
31
+ if (node === null)
32
+ return null;
33
+ return (_jsx(Box, { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", flexDirection: "column", flexShrink: 0, overflow: "hidden", opaque: true, onClick: (event) => {
34
+ event.stopImmediatePropagation();
35
+ }, children: node }));
36
+ }
37
+ /**
38
+ * A mouse-friendly pill button for the editor chrome (send / collapse /
39
+ * the ⤢ close affordance). Hover swaps the surface so the affordance
40
+ * reads at a glance — the same interaction language as the transcript's
41
+ * clickable rows and the session browser's menu items.
42
+ */
43
+ export function EditorButton({ label, hint, onClick, primary, accent, }) {
44
+ const [hovered, setHovered] = React.useState(false);
45
+ const text = hint === undefined ? ` ${label} ` : ` ${label} ${hint} `;
46
+ return (_jsx(Box, { flexShrink: 0, backgroundColor: primary
47
+ ? hovered
48
+ ? 'userMessageBackgroundHover'
49
+ : (accent ?? 'claude')
50
+ : hovered
51
+ ? 'userMessageBackgroundHover'
52
+ : undefined, onClick: (event) => {
53
+ event.stopImmediatePropagation();
54
+ onClick();
55
+ }, onMouseEnter: () => {
56
+ setHovered(true);
57
+ }, onMouseLeave: () => {
58
+ setHovered(false);
59
+ }, children: _jsx(Text, { bold: primary || hovered, color: primary && !hovered ? 'inverseText' : undefined, dimColor: !primary && !hovered, children: text }) }));
60
+ }
@@ -9,6 +9,18 @@ import type { Channel } from '../dsh-adapter/channel.js';
9
9
  export interface PromptController {
10
10
  hasText(): boolean;
11
11
  clear(): void;
12
+ /**
13
+ * Copy the active mouse selection to the system clipboard (OSC 52 + the
14
+ * native fallback) and KEEP the selection for further editing. Returns
15
+ * true when a selection existed and consumed the key; Chat's Ctrl+C
16
+ * branch calls this first, before its clear/exit semantics.
17
+ */
18
+ consumeSelectionCopy(): boolean;
19
+ /** Toggle vim editing mode (`/vim`); returns the new state (true = on). */
20
+ toggleVim(): boolean;
21
+ /** True while vim mode is on (either submode). Esc belongs to vim then —
22
+ * Chat's working-turn Esc interrupt must yield in BOTH submodes. */
23
+ vimActive(): boolean;
12
24
  }
13
25
  export interface PromptInputProps {
14
26
  channel: Channel;
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAmBzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAmJxD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,KAAK,IAAI,IAAI,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACrD,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,8EAA8E;IAC9E,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,GACd,EAAE,gBAAgB,qBAi9ClB"}
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAwBzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AA4OxD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,KAAK,IAAI,IAAI,CAAA;IACb;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,IAAI,OAAO,CAAA;IACpB;yEACqE;IACrE,SAAS,IAAI,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACrD,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,8EAA8E;IAC9E,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,GACd,EAAE,gBAAgB,qBA85ElB"}