@deepseek-harness-tui/dsh-tui 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/README.md +74 -21
  2. package/bin/dsh-tui.js +115 -25
  3. package/cordis.patch.yml +69 -17
  4. package/cordis.yml +50 -12
  5. package/lib/types/activityPrefs.d.ts +1 -1
  6. package/lib/types/activityPrefs.js +3 -3
  7. package/lib/types/cc/figures.d.ts +27 -20
  8. package/lib/types/cc/figures.d.ts.map +1 -1
  9. package/lib/types/cc/figures.js +43 -34
  10. package/lib/types/cc/format.d.ts +18 -9
  11. package/lib/types/cc/format.d.ts.map +1 -1
  12. package/lib/types/cc/format.js +26 -18
  13. package/lib/types/cc/markdown.d.ts +31 -16
  14. package/lib/types/cc/markdown.d.ts.map +1 -1
  15. package/lib/types/cc/markdown.js +283 -260
  16. package/lib/types/cc/terminal.d.ts +10 -7
  17. package/lib/types/cc/terminal.d.ts.map +1 -1
  18. package/lib/types/cc/terminal.js +62 -50
  19. package/lib/types/command-trees.d.ts +3 -0
  20. package/lib/types/command-trees.d.ts.map +1 -0
  21. package/lib/types/command-trees.js +4 -0
  22. package/lib/types/commands.d.ts +37 -1
  23. package/lib/types/commands.d.ts.map +1 -1
  24. package/lib/types/commands.js +68 -3
  25. package/lib/types/components/ActivityLine.d.ts +1 -1
  26. package/lib/types/components/ActivityLine.d.ts.map +1 -1
  27. package/lib/types/components/ActivityPicker.d.ts.map +1 -1
  28. package/lib/types/components/ActivityPicker.js +3 -4
  29. package/lib/types/components/BtwPanel.d.ts +16 -0
  30. package/lib/types/components/BtwPanel.d.ts.map +1 -0
  31. package/lib/types/components/BtwPanel.js +47 -0
  32. package/lib/types/components/CommandSuggestions.d.ts +4 -2
  33. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  34. package/lib/types/components/CommandSuggestions.js +2 -2
  35. package/lib/types/components/EffortSlider.d.ts +15 -0
  36. package/lib/types/components/EffortSlider.d.ts.map +1 -0
  37. package/lib/types/components/EffortSlider.js +17 -0
  38. package/lib/types/components/GoalTodoPanel.d.ts +1 -1
  39. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  40. package/lib/types/components/HelpMenu.d.ts +5 -2
  41. package/lib/types/components/HelpMenu.d.ts.map +1 -1
  42. package/lib/types/components/HelpMenu.js +8 -3
  43. package/lib/types/components/HistorySearchDialog.d.ts +1 -1
  44. package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
  45. package/lib/types/components/HistorySearchDialog.js +21 -10
  46. package/lib/types/components/InterruptedByUser.d.ts +2 -2
  47. package/lib/types/components/InterruptedByUser.d.ts.map +1 -1
  48. package/lib/types/components/InterruptedByUser.js +4 -3
  49. package/lib/types/components/LoadedContextPanel.d.ts +1 -1
  50. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  51. package/lib/types/components/LogoV2.d.ts.map +1 -1
  52. package/lib/types/components/LogoV2.js +2 -1
  53. package/lib/types/components/Markdown.d.ts +11 -11
  54. package/lib/types/components/Markdown.d.ts.map +1 -1
  55. package/lib/types/components/Markdown.js +63 -57
  56. package/lib/types/components/MarkdownTable.d.ts +1 -1
  57. package/lib/types/components/MarkdownTable.js +2 -2
  58. package/lib/types/components/MessageList.d.ts +10 -2
  59. package/lib/types/components/MessageList.d.ts.map +1 -1
  60. package/lib/types/components/MessageList.js +17 -10
  61. package/lib/types/components/ModelPicker.d.ts +4 -1
  62. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  63. package/lib/types/components/ModelPicker.js +16 -4
  64. package/lib/types/components/OverlayAbove.d.ts +20 -0
  65. package/lib/types/components/OverlayAbove.d.ts.map +1 -0
  66. package/lib/types/components/OverlayAbove.js +18 -0
  67. package/lib/types/components/PresetPicker.d.ts +1 -1
  68. package/lib/types/components/PresetPicker.d.ts.map +1 -1
  69. package/lib/types/components/PresetPicker.js +2 -3
  70. package/lib/types/components/PromptInput.d.ts +5 -4
  71. package/lib/types/components/PromptInput.d.ts.map +1 -1
  72. package/lib/types/components/PromptInput.js +186 -39
  73. package/lib/types/components/ResumePicker.d.ts +15 -4
  74. package/lib/types/components/ResumePicker.d.ts.map +1 -1
  75. package/lib/types/components/ResumePicker.js +25 -9
  76. package/lib/types/components/RewindPicker.d.ts +1 -1
  77. package/lib/types/components/RewindPicker.d.ts.map +1 -1
  78. package/lib/types/components/RewindPicker.js +14 -5
  79. package/lib/types/components/SearchBox.d.ts +1 -1
  80. package/lib/types/components/SearchBox.js +1 -1
  81. package/lib/types/components/Spinner/GlimmerMessage.d.ts +1 -2
  82. package/lib/types/components/Spinner/GlimmerMessage.d.ts.map +1 -1
  83. package/lib/types/components/Spinner/GlimmerMessage.js +1 -2
  84. package/lib/types/components/Spinner/SpinnerAnimationRow.d.ts +1 -1
  85. package/lib/types/components/Spinner/SpinnerAnimationRow.js +2 -2
  86. package/lib/types/components/Spinner/SpinnerGlyph.d.ts +1 -1
  87. package/lib/types/components/Spinner/SpinnerGlyph.js +1 -1
  88. package/lib/types/components/Spinner/spinnerUtils.d.ts +13 -18
  89. package/lib/types/components/Spinner/spinnerUtils.d.ts.map +1 -1
  90. package/lib/types/components/Spinner/spinnerUtils.js +67 -71
  91. package/lib/types/components/Spinner/useStalledAnimation.d.ts +1 -2
  92. package/lib/types/components/Spinner/useStalledAnimation.d.ts.map +1 -1
  93. package/lib/types/components/Spinner/useStalledAnimation.js +1 -2
  94. package/lib/types/components/StreamingMarkdown.d.ts +1 -1
  95. package/lib/types/components/StreamingMarkdown.js +1 -1
  96. package/lib/types/components/ThemePicker.d.ts +13 -9
  97. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  98. package/lib/types/components/ThemePicker.js +21 -15
  99. package/lib/types/components/ThinkingToggle.d.ts +1 -1
  100. package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
  101. package/lib/types/components/ThinkingToggle.js +8 -8
  102. package/lib/types/components/ToolUseLoader.d.ts +1 -1
  103. package/lib/types/components/ToolUseLoader.js +1 -1
  104. package/lib/types/components/WorkingSpinner.d.ts +2 -2
  105. package/lib/types/components/WorkingSpinner.js +2 -2
  106. package/lib/types/components/WorkspaceFlowPicker.d.ts +15 -0
  107. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -0
  108. package/lib/types/components/WorkspaceFlowPicker.js +19 -0
  109. package/lib/types/components/WorkspacePicker.d.ts +9 -0
  110. package/lib/types/components/WorkspacePicker.d.ts.map +1 -0
  111. package/lib/types/components/WorkspacePicker.js +13 -0
  112. package/lib/types/components/approvals/ApprovalPanel.d.ts +1 -1
  113. package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
  114. package/lib/types/components/approvals/ApprovalPanel.js +2 -1
  115. package/lib/types/components/design-system/Byline.d.ts +1 -1
  116. package/lib/types/components/design-system/Byline.js +1 -1
  117. package/lib/types/components/design-system/Divider.d.ts +1 -1
  118. package/lib/types/components/design-system/Divider.js +1 -1
  119. package/lib/types/components/design-system/HintLine.d.ts +12 -0
  120. package/lib/types/components/design-system/HintLine.d.ts.map +1 -0
  121. package/lib/types/components/design-system/HintLine.js +15 -0
  122. package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +1 -1
  123. package/lib/types/components/design-system/KeyboardShortcutHint.js +1 -1
  124. package/lib/types/components/design-system/ListItem.d.ts +2 -2
  125. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  126. package/lib/types/components/design-system/ListItem.js +35 -3
  127. package/lib/types/components/design-system/LoadingState.d.ts +1 -2
  128. package/lib/types/components/design-system/LoadingState.d.ts.map +1 -1
  129. package/lib/types/components/design-system/LoadingState.js +1 -2
  130. package/lib/types/components/design-system/Pane.d.ts +2 -2
  131. package/lib/types/components/design-system/Pane.js +2 -2
  132. package/lib/types/components/design-system/ProgressBar.d.ts +1 -2
  133. package/lib/types/components/design-system/ProgressBar.d.ts.map +1 -1
  134. package/lib/types/components/design-system/ProgressBar.js +1 -2
  135. package/lib/types/components/design-system/StatusIcon.d.ts +2 -2
  136. package/lib/types/components/design-system/StatusIcon.js +2 -2
  137. package/lib/types/components/design-system/ThemeProvider.d.ts +1 -1
  138. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  139. package/lib/types/components/design-system/ThemeProvider.js +87 -26
  140. package/lib/types/components/design-system/ThemedBox.d.ts +1 -1
  141. package/lib/types/components/design-system/ThemedBox.js +1 -1
  142. package/lib/types/components/design-system/ThemedText.d.ts +2 -2
  143. package/lib/types/components/design-system/ThemedText.js +2 -2
  144. package/lib/types/components/listWindow.d.ts +26 -0
  145. package/lib/types/components/listWindow.d.ts.map +1 -0
  146. package/lib/types/components/listWindow.js +47 -0
  147. package/lib/types/components/messages/AssistantTextMessage.d.ts +1 -2
  148. package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
  149. package/lib/types/components/messages/AssistantTextMessage.js +1 -2
  150. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -2
  151. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  152. package/lib/types/components/messages/AssistantThinkingMessage.js +6 -6
  153. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +12 -4
  154. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  155. package/lib/types/components/messages/AssistantToolUseMessage.js +9 -5
  156. package/lib/types/components/messages/MessageMetadata.d.ts +1 -1
  157. package/lib/types/components/messages/MessageMetadata.js +1 -1
  158. package/lib/types/components/messages/UserPromptMessage.d.ts +1 -1
  159. package/lib/types/components/messages/UserPromptMessage.js +1 -1
  160. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +5 -1
  161. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  162. package/lib/types/components/questions/AskUserQuestionPanel.js +11 -9
  163. package/lib/types/components/questions/PlanReviewPanel.d.ts +1 -1
  164. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  165. package/lib/types/components/questions/PlanReviewPanel.js +3 -2
  166. package/lib/types/components/trajectory/HotspotView.d.ts +14 -0
  167. package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -0
  168. package/lib/types/components/trajectory/HotspotView.js +83 -0
  169. package/lib/types/components/trajectory/Inspector.d.ts +31 -0
  170. package/lib/types/components/trajectory/Inspector.d.ts.map +1 -0
  171. package/lib/types/components/trajectory/Inspector.js +67 -0
  172. package/lib/types/components/trajectory/Ledger.d.ts +20 -0
  173. package/lib/types/components/trajectory/Ledger.d.ts.map +1 -0
  174. package/lib/types/components/trajectory/Ledger.js +112 -0
  175. package/lib/types/components/trajectory/MiniWake.d.ts +24 -0
  176. package/lib/types/components/trajectory/MiniWake.d.ts.map +1 -0
  177. package/lib/types/components/trajectory/MiniWake.js +99 -0
  178. package/lib/types/components/trajectory/WaveBand.d.ts +33 -0
  179. package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -0
  180. package/lib/types/components/trajectory/WaveBand.js +145 -0
  181. package/lib/types/customTheme.d.ts +6 -6
  182. package/lib/types/customTheme.d.ts.map +1 -1
  183. package/lib/types/customTheme.js +15 -12
  184. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -0
  185. package/lib/types/{channel.d.ts → dsh-adapter/channel.d.ts} +184 -43
  186. package/lib/types/dsh-adapter/channel.d.ts.map +1 -0
  187. package/lib/types/{channel.js → dsh-adapter/channel.js} +972 -201
  188. package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -0
  189. package/lib/types/{childStderr.js → dsh-adapter/childStderr.js} +1 -1
  190. package/lib/types/dsh-adapter/command-trees.d.ts +27 -0
  191. package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -0
  192. package/lib/types/dsh-adapter/command-trees.js +42 -0
  193. package/lib/types/dsh-adapter/compat/index.d.ts +22 -0
  194. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -0
  195. package/lib/types/{compat → dsh-adapter/compat}/index.js +7 -4
  196. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +86 -0
  197. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -0
  198. package/lib/types/dsh-adapter/compat/sessionLog.js +347 -0
  199. package/lib/types/dsh-adapter/contract.d.ts +20 -0
  200. package/lib/types/dsh-adapter/contract.d.ts.map +1 -0
  201. package/lib/types/dsh-adapter/contract.js +109 -0
  202. package/lib/types/dsh-adapter/index.d.ts +80 -0
  203. package/lib/types/dsh-adapter/index.d.ts.map +1 -0
  204. package/lib/types/dsh-adapter/index.js +45 -0
  205. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -0
  206. package/lib/types/dsh-adapter/packaged-skills.d.ts.map +1 -0
  207. package/lib/types/{plugin.d.ts → dsh-adapter/plugin.d.ts} +17 -0
  208. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -0
  209. package/lib/types/{plugin.js → dsh-adapter/plugin.js} +280 -80
  210. package/lib/types/dsh-adapter/presets.d.ts.map +1 -0
  211. package/lib/types/dsh-adapter/providerWizard.d.ts +91 -0
  212. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -0
  213. package/lib/types/dsh-adapter/providerWizard.js +332 -0
  214. package/lib/types/{questions.d.ts → dsh-adapter/questions.d.ts} +7 -2
  215. package/lib/types/dsh-adapter/questions.d.ts.map +1 -0
  216. package/lib/types/{questions.js → dsh-adapter/questions.js} +15 -7
  217. package/lib/types/dsh-adapter/sideQuestion.d.ts +38 -0
  218. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -0
  219. package/lib/types/dsh-adapter/sideQuestion.js +69 -0
  220. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +46 -0
  221. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts.map +1 -0
  222. package/lib/types/dsh-adapter/trajectory/aggregate.js +207 -0
  223. package/lib/types/dsh-adapter/trajectory/guards.d.ts +177 -0
  224. package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -0
  225. package/lib/types/dsh-adapter/trajectory/guards.js +235 -0
  226. package/lib/types/dsh-adapter/trajectory/index.d.ts +16 -0
  227. package/lib/types/dsh-adapter/trajectory/index.d.ts.map +1 -0
  228. package/lib/types/dsh-adapter/trajectory/index.js +15 -0
  229. package/lib/types/dsh-adapter/trajectory/inspect.d.ts +40 -0
  230. package/lib/types/dsh-adapter/trajectory/inspect.d.ts.map +1 -0
  231. package/lib/types/dsh-adapter/trajectory/inspect.js +160 -0
  232. package/lib/types/dsh-adapter/trajectory/projection.d.ts +128 -0
  233. package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -0
  234. package/lib/types/dsh-adapter/trajectory/projection.js +653 -0
  235. package/lib/types/dsh-adapter/trajectory/types.d.ts +232 -0
  236. package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -0
  237. package/lib/types/dsh-adapter/trajectory/types.js +70 -0
  238. package/lib/types/dsh-adapter/trajectory/wave.d.ts +45 -0
  239. package/lib/types/dsh-adapter/trajectory/wave.d.ts.map +1 -0
  240. package/lib/types/dsh-adapter/trajectory/wave.js +210 -0
  241. package/lib/types/dsh-adapter/types.d.ts +23 -0
  242. package/lib/types/dsh-adapter/types.d.ts.map +1 -0
  243. package/lib/types/dsh-adapter/types.js +1 -0
  244. package/lib/types/dsh-adapter/workspace.d.ts +22 -0
  245. package/lib/types/dsh-adapter/workspace.d.ts.map +1 -0
  246. package/lib/types/dsh-adapter/workspace.js +16 -0
  247. package/lib/types/dsh-adapter/workspaces.d.ts +118 -0
  248. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -0
  249. package/lib/types/dsh-adapter/workspaces.js +290 -0
  250. package/lib/types/effortPrefs.d.ts +1 -1
  251. package/lib/types/effortPrefs.js +3 -3
  252. package/lib/types/history.js +2 -2
  253. package/lib/types/hooks/useBlink.d.ts +1 -1
  254. package/lib/types/hooks/useBlink.js +1 -1
  255. package/lib/types/i18n.d.ts +977 -36
  256. package/lib/types/i18n.d.ts.map +1 -1
  257. package/lib/types/i18n.js +307 -30
  258. package/lib/types/index.d.ts +1 -69
  259. package/lib/types/index.d.ts.map +1 -1
  260. package/lib/types/index.js +3 -31
  261. package/lib/types/ink/components/App.d.ts.map +1 -1
  262. package/lib/types/ink/components/App.js +33 -19
  263. package/lib/types/ink/dom.d.ts +15 -0
  264. package/lib/types/ink/dom.d.ts.map +1 -1
  265. package/lib/types/ink/dom.js +32 -0
  266. package/lib/types/ink/hooks/use-input.d.ts.map +1 -1
  267. package/lib/types/ink/hooks/use-input.js +8 -0
  268. package/lib/types/ink/hooks/use-terminal-size.d.ts +1 -1
  269. package/lib/types/ink/hooks/use-terminal-size.js +1 -1
  270. package/lib/types/ink/ink.d.ts.map +1 -1
  271. package/lib/types/ink/ink.js +109 -28
  272. package/lib/types/ink/input-suppression.d.ts +20 -0
  273. package/lib/types/ink/input-suppression.d.ts.map +1 -0
  274. package/lib/types/ink/input-suppression.js +26 -0
  275. package/lib/types/ink/log-update.js +21 -6
  276. package/lib/types/ink/parse-keypress.d.ts +31 -0
  277. package/lib/types/ink/parse-keypress.d.ts.map +1 -1
  278. package/lib/types/ink/parse-keypress.js +442 -8
  279. package/lib/types/ink/terminal-querier.d.ts +5 -1
  280. package/lib/types/ink/terminal-querier.d.ts.map +1 -1
  281. package/lib/types/ink/terminal-querier.js +27 -3
  282. package/lib/types/ink/terminal.d.ts +18 -0
  283. package/lib/types/ink/terminal.d.ts.map +1 -1
  284. package/lib/types/ink/terminal.js +32 -4
  285. package/lib/types/ink/termio/csi.d.ts +10 -0
  286. package/lib/types/ink/termio/csi.d.ts.map +1 -1
  287. package/lib/types/ink/termio/csi.js +20 -0
  288. package/lib/types/ink/termio/tokenize.js +10 -0
  289. package/lib/types/modelPrefs.d.ts +1 -1
  290. package/lib/types/modelPrefs.js +3 -3
  291. package/lib/types/presetPrefs.d.ts +1 -1
  292. package/lib/types/presetPrefs.js +3 -3
  293. package/lib/types/screens/Chat.d.ts +20 -4
  294. package/lib/types/screens/Chat.d.ts.map +1 -1
  295. package/lib/types/screens/Chat.js +655 -55
  296. package/lib/types/screens/StatusLine.d.ts +17 -2
  297. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  298. package/lib/types/screens/StatusLine.js +12 -4
  299. package/lib/types/screens/TrajectoryScene.d.ts +16 -0
  300. package/lib/types/screens/TrajectoryScene.d.ts.map +1 -0
  301. package/lib/types/screens/TrajectoryScene.js +305 -0
  302. package/lib/types/sessionHistory.d.ts +9 -1
  303. package/lib/types/sessionHistory.d.ts.map +1 -1
  304. package/lib/types/sessionHistory.js +56 -16
  305. package/lib/types/sessionModes.d.ts +29 -0
  306. package/lib/types/sessionModes.d.ts.map +1 -0
  307. package/lib/types/sessionModes.js +45 -0
  308. package/lib/types/theme.d.ts +27 -3
  309. package/lib/types/theme.d.ts.map +1 -1
  310. package/lib/types/theme.js +48 -4
  311. package/lib/types/themePrefs.d.ts +3 -3
  312. package/lib/types/themePrefs.js +5 -5
  313. package/lib/types/trajectory/format.d.ts +100 -0
  314. package/lib/types/trajectory/format.d.ts.map +1 -0
  315. package/lib/types/trajectory/format.js +213 -0
  316. package/lib/types/trajectory/motion.d.ts +99 -0
  317. package/lib/types/trajectory/motion.d.ts.map +1 -0
  318. package/lib/types/trajectory/motion.js +143 -0
  319. package/lib/types/trajectory/query.d.ts +83 -0
  320. package/lib/types/trajectory/query.d.ts.map +1 -0
  321. package/lib/types/trajectory/query.js +187 -0
  322. package/lib/types/trajectoryPrefs.d.ts +36 -0
  323. package/lib/types/trajectoryPrefs.d.ts.map +1 -0
  324. package/lib/types/trajectoryPrefs.js +65 -0
  325. package/lib/types/update.d.ts +3 -3
  326. package/lib/types/update.d.ts.map +1 -1
  327. package/lib/types/update.js +18 -7
  328. package/lib/types/utils/clipboard.d.ts +101 -29
  329. package/lib/types/utils/clipboard.d.ts.map +1 -1
  330. package/lib/types/utils/clipboard.js +533 -55
  331. package/lib/types/utils/debug.d.ts +1 -1
  332. package/lib/types/utils/debug.js +2 -2
  333. package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
  334. package/lib/types/utils/execFileNoThrow.js +16 -6
  335. package/lib/types/utils/externalEditor.d.ts +115 -0
  336. package/lib/types/utils/externalEditor.d.ts.map +1 -0
  337. package/lib/types/utils/externalEditor.js +270 -0
  338. package/lib/types/utils/fullscreen.d.ts +2 -2
  339. package/lib/types/utils/fullscreen.js +3 -3
  340. package/lib/types/utils/loaded-context.d.ts +1 -1
  341. package/lib/types/utils/loaded-context.d.ts.map +1 -1
  342. package/lib/types/utils/modifiers.d.ts +24 -0
  343. package/lib/types/utils/modifiers.d.ts.map +1 -1
  344. package/lib/types/utils/modifiers.js +27 -0
  345. package/lib/types/utils/paths.d.ts +45 -0
  346. package/lib/types/utils/paths.d.ts.map +1 -0
  347. package/lib/types/utils/paths.js +69 -0
  348. package/lib/types/utils/shellQuote.d.ts +14 -0
  349. package/lib/types/utils/shellQuote.d.ts.map +1 -0
  350. package/lib/types/utils/shellQuote.js +39 -0
  351. package/lib/types/utils/workspaceRoot.d.ts +21 -0
  352. package/lib/types/utils/workspaceRoot.d.ts.map +1 -0
  353. package/lib/types/utils/workspaceRoot.js +47 -0
  354. package/lib/types/workspaces.d.ts +3 -0
  355. package/lib/types/workspaces.d.ts.map +1 -0
  356. package/lib/types/workspaces.js +4 -0
  357. package/package.json +26 -8
  358. package/lib/types/approvals.d.ts.map +0 -1
  359. package/lib/types/channel.d.ts.map +0 -1
  360. package/lib/types/childStderr.d.ts.map +0 -1
  361. package/lib/types/compat/index.d.ts +0 -20
  362. package/lib/types/compat/index.d.ts.map +0 -1
  363. package/lib/types/compat/sessionLog.d.ts +0 -40
  364. package/lib/types/compat/sessionLog.d.ts.map +0 -1
  365. package/lib/types/compat/sessionLog.js +0 -226
  366. package/lib/types/invariant.d.ts.map +0 -1
  367. package/lib/types/packaged-skills.d.ts.map +0 -1
  368. package/lib/types/plugin.d.ts.map +0 -1
  369. package/lib/types/presets.d.ts.map +0 -1
  370. package/lib/types/questions.d.ts.map +0 -1
  371. /package/lib/types/{approvals.d.ts → dsh-adapter/approvals.d.ts} +0 -0
  372. /package/lib/types/{approvals.js → dsh-adapter/approvals.js} +0 -0
  373. /package/lib/types/{childStderr.d.ts → dsh-adapter/childStderr.d.ts} +0 -0
  374. /package/lib/types/{invariant.d.ts → dsh-adapter/invariant.d.ts} +0 -0
  375. /package/lib/types/{invariant.js → dsh-adapter/invariant.js} +0 -0
  376. /package/lib/types/{packaged-skills.d.ts → dsh-adapter/packaged-skills.d.ts} +0 -0
  377. /package/lib/types/{packaged-skills.js → dsh-adapter/packaged-skills.js} +0 -0
  378. /package/lib/types/{presets.d.ts → dsh-adapter/presets.d.ts} +0 -0
  379. /package/lib/types/{presets.js → dsh-adapter/presets.js} +0 -0
@@ -2,14 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Box from '../ink/components/Box.js';
3
3
  import Text from '../ink/components/Text.js';
4
4
  import { localizedDescription } from '../commands.js';
5
+ import { t } from '../i18n.js';
5
6
  import { modLabel } from '../utils/modifiers.js';
6
7
  /**
7
- * The `?` help menu, ported from the leak's `PromptInputHelpMenu.tsx`
8
+ * The `?` help menu, mirroring Claude Code's `PromptInputHelpMenu.tsx`
8
9
  * (three-column shortcut layout, trimmed to the keys dsh-tui actually binds).
9
10
  * The command column lists the merged slash-command surface: built-in
10
11
  * commands plus plugin-registered ones from the DSH registry (plan/goal/…).
11
- * Modifier labels follow the platform convention: ⌘ on macOS, ctrl elsewhere.
12
+ * Skill entries (user-invocable skills merged for `/` completion, issue
13
+ * #86) are hidden — a skills directory can hold dozens of entries and the
14
+ * menu is for chrome commands. Modifier labels follow the platform
15
+ * convention: ⌘ on macOS, ctrl elsewhere.
12
16
  */
13
17
  export function HelpMenu({ commands, }) {
14
- return (_jsxs(Box, { paddingX: 2, flexDirection: "row", gap: 4, children: [_jsxs(Box, { flexDirection: "column", width: 26, flexShrink: 0, children: [_jsx(Box, { children: _jsx(Text, { dimColor: true, children: "/ for commands" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "? for this help" }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [modLabel, "o for verbose output"] }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [modLabel, "t to toggle context"] }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [modLabel, "r to search history"] }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "ctrl+c to interrupt" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "ctrl+d to exit" }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [modLabel, "l to redraw"] }) })] }), _jsxs(Box, { flexDirection: "column", width: 24, flexShrink: 0, children: [_jsx(Box, { children: _jsx(Text, { dimColor: true, children: "esc to clear input" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 for history" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2190/\u2192 to move cursor" }) }), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: [modLabel, "\u2190/\u2192 for word jumps"] }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "tab to complete command" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "shift+tab to cycle effort" }) })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsx(Text, { dimColor: true, children: "commands:" }), commands.map(command => (_jsx(Box, { children: _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["/", command.name, " \u2014 ", localizedDescription(command)] }) }, command.name)))] })] }));
18
+ const chrome = commands.filter(command => !command.skill);
19
+ return (_jsxs(Box, { paddingX: 2, flexDirection: "row", gap: 4, children: [_jsxs(Box, { flexDirection: "column", width: 26, flexShrink: 0, children: [_jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-for-commands') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-this-help') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-verbose-output', { mod: modLabel }) }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-toggle-context', { mod: modLabel }) }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-search-history', { mod: modLabel }) }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-interrupt') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-exit') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-redraw', { mod: modLabel }) }) })] }), _jsxs(Box, { flexDirection: "column", width: 24, flexShrink: 0, children: [_jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-clear-input') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-history-nav') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-move-cursor') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-word-jumps', { mod: modLabel }) }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-complete-command') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-cycle-mode') }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: t('help-open-editor') }) })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsx(Text, { dimColor: true, children: t('help-commands-title') }), chrome.map(command => (_jsx(Box, { children: _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["/", command.name, " \u2014 ", localizedDescription(command)] }) }, command.name)))] })] }));
15
20
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { type HistoryEntry } from '../history.js';
3
3
  /**
4
- * The ctrl+r history search dialog, in the shape of the leak's
4
+ * The ctrl+r history search dialog, in the shape of Claude Code's
5
5
  * HistorySearchDialog/FuzzyPicker: a permission-colored Pane with a bold
6
6
  * title, the ⌕ SearchBox, the filtered history as ListItem rows (newest
7
7
  * first), and the ↑/↓ · Enter · Esc hint line. Keyboard handling lives in
@@ -1 +1 @@
1
- {"version":3,"file":"HistorySearchDialog.d.ts","sourceRoot":"","sources":["../../../src/components/HistorySearchDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAsClB"}
1
+ {"version":3,"file":"HistorySearchDialog.d.ts","sourceRoot":"","sources":["../../../src/components/HistorySearchDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;IAChC,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,KAAK,CAAC,SAAS,CAmDlB"}
@@ -1,14 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from '../ui.js';
2
+ import { t } from '../i18n.js';
3
+ import { Box, Text, useTerminalSize } from '../ui.js';
3
4
  import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
4
5
  import { Pane } from './design-system/Pane.js';
5
6
  import { ListItem } from './design-system/ListItem.js';
6
- import { Byline } from './design-system/Byline.js';
7
- import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
7
+ import { HintLine } from './design-system/HintLine.js';
8
8
  import { SearchBox } from './SearchBox.js';
9
+ import { listWindow } from './listWindow.js';
9
10
  import { historyEntryId } from '../history.js';
10
11
  /**
11
- * The ctrl+r history search dialog, in the shape of the leak's
12
+ * The ctrl+r history search dialog, in the shape of Claude Code's
12
13
  * HistorySearchDialog/FuzzyPicker: a permission-colored Pane with a bold
13
14
  * title, the ⌕ SearchBox, the filtered history as ListItem rows (newest
14
15
  * first), and the ↑/↓ · Enter · Esc hint line. Keyboard handling lives in
@@ -16,16 +17,26 @@ import { historyEntryId } from '../history.js';
16
17
  */
17
18
  export function HistorySearchDialog({ query, cursorOffset, matches, focusIndex, }) {
18
19
  const isTerminalFocused = useTerminalFocus();
19
- return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, color: "permission", children: "Search history" }), _jsx(SearchBox, { query: query, cursorOffset: cursorOffset, isFocused: true, isTerminalFocused: isTerminalFocused, placeholder: "Type to search\u2026" }), matches.length === 0 ? (_jsx(Text, { dimColor: true, children: "No matching commands" })) : (matches.map((entry, index) => (_jsx(ListItem, { isFocused: index === focusIndex, description: formatRelativeAge(entry.ts), children: entry.text }, historyEntryId(entry))))), _jsx(Text, { dimColor: true, italic: true, children: _jsxs(Byline, { children: [_jsx(KeyboardShortcutHint, { shortcut: "\u2191/\u2193", action: "navigate" }), _jsx(KeyboardShortcutHint, { shortcut: "Enter", action: "select", bold: true }), _jsx(KeyboardShortcutHint, { shortcut: "Esc", action: "cancel" })] }) })] }) }));
20
+ const { rows: terminalRows } = useTerminalSize();
21
+ // 焦点窗口化按行预算:每项恒 2 行(命令 + age 描述,ListItem 保证单行
22
+ // 截断),容器 gap={1} 项间再空 1 行。只数项数会把焦点裁出浮层(二次
23
+ // 审查实证)。
24
+ // 框架行:浮层预留 8 + Pane 2 + 标题 1 + gap 1 + SearchBox 3(圆角边框)
25
+ // + gap 1 + gap 1 + 页脚 1 = 18。
26
+ const { start, end } = listWindow(matches.map(() => 2), focusIndex, Math.max(terminalRows - 18, 2), 1);
27
+ return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, color: "permission", children: t('history-search-title') }), _jsx(SearchBox, { query: query, cursorOffset: cursorOffset, isFocused: true, isTerminalFocused: isTerminalFocused, placeholder: t('history-search-placeholder') }), matches.length === 0 ? (_jsx(Text, { dimColor: true, children: t('history-search-empty') })) : (matches.slice(start, end).map((entry, index) => {
28
+ const absoluteIndex = start + index;
29
+ return (_jsx(ListItem, { isFocused: absoluteIndex === focusIndex, description: formatRelativeAge(entry.ts), showScrollUp: absoluteIndex === start && start > 0, showScrollDown: absoluteIndex === end - 1 && end < matches.length, children: entry.text }, historyEntryId(entry)));
30
+ })), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-history-search') }) })] }) }));
20
31
  }
21
- /** "now", "5m ago", "2h ago", "3d ago" — like CC's formatRelativeTimeAgo. */
32
+ /** Relative age like CC's formatRelativeTimeAgo ("now" / "5m ago" / …), localized. */
22
33
  function formatRelativeAge(ts) {
23
34
  const elapsed = Date.now() - ts;
24
35
  if (elapsed < 60_000)
25
- return 'now';
36
+ return t('time-now');
26
37
  if (elapsed < 3_600_000)
27
- return `${Math.floor(elapsed / 60_000)}m ago`;
38
+ return t('time-minutes-ago', { n: Math.floor(elapsed / 60_000) });
28
39
  if (elapsed < 86_400_000)
29
- return `${Math.floor(elapsed / 3_600_000)}h ago`;
30
- return `${Math.floor(elapsed / 86_400_000)}d ago`;
40
+ return t('time-hours-ago', { n: Math.floor(elapsed / 3_600_000) });
41
+ return t('time-days-ago', { n: Math.floor(elapsed / 86_400_000) });
31
42
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  /**
3
- * The dim "interrupted" row shown when the user stops a turn, ported from
4
- * the leak's `InterruptedByUser.tsx`.
3
+ * The dim "interrupted" row shown when the user stops a turn, mirroring
4
+ * Claude Code's `InterruptedByUser.tsx`.
5
5
  */
6
6
  export declare function InterruptedByUser(): React.ReactNode;
7
7
  //# sourceMappingURL=InterruptedByUser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InterruptedByUser.d.ts","sourceRoot":"","sources":["../../../src/components/InterruptedByUser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,KAAK,CAAC,SAAS,CAOnD"}
1
+ {"version":3,"file":"InterruptedByUser.d.ts","sourceRoot":"","sources":["../../../src/components/InterruptedByUser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,KAAK,CAAC,SAAS,CAOnD"}
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Text } from '../ui.js';
3
+ import { t } from '../i18n.js';
3
4
  /**
4
- * The dim "interrupted" row shown when the user stops a turn, ported from
5
- * the leak's `InterruptedByUser.tsx`.
5
+ * The dim "interrupted" row shown when the user stops a turn, mirroring
6
+ * Claude Code's `InterruptedByUser.tsx`.
6
7
  */
7
8
  export function InterruptedByUser() {
8
- return (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Interrupted " }), _jsx(Text, { dimColor: true, children: "\u00B7 What should DeepSeek do instead?" })] }));
9
+ return (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: t('interrupted-by-user') }), _jsx(Text, { dimColor: true, children: t('interrupted-ask-next') })] }));
9
10
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { LoadedContext } from '../channel.js';
2
+ import type { LoadedContext } from '../dsh-adapter/channel.js';
3
3
  /**
4
4
  * The startup context panel: a collapsed one-line summary of what a
5
5
  * fresh conversation will load for the current agent (system prompt
@@ -1 +1 @@
1
- {"version":3,"file":"LoadedContextPanel.d.ts","sourceRoot":"","sources":["../../../src/components/LoadedContextPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,eAAe,CAAA;AA+BtE;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAO,EACP,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,aAAa,CAAA;IACtB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,GAAG,KAAK,CAAC,SAAS,CAkElB"}
1
+ {"version":3,"file":"LoadedContextPanel.d.ts","sourceRoot":"","sources":["../../../src/components/LoadedContextPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,2BAA2B,CAAA;AA+BlF;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAO,EACP,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,aAAa,CAAA;IACtB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,GAAG,KAAK,CAAC,SAAS,CAkElB"}
@@ -1 +1 @@
1
- {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAoDzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,MAAM,EACN,GAAG,EACH,SAAiB,GAClB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CA+ElB"}
1
+ {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAqDzB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,MAAM,EACN,GAAG,EACH,SAAiB,GAClB,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAiFlB"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { t as tr } from '../i18n.js';
4
+ import { modLabel } from '../utils/modifiers.js';
4
5
  import { readFileSync } from 'node:fs';
5
6
  import { dirname, join } from 'node:path';
6
7
  import { fileURLToPath } from 'node:url';
@@ -91,5 +92,5 @@ export function LogoV2({ model, effort, cwd, skipIntro = false, }) {
91
92
  const t = settled ? 0 : time;
92
93
  const bigDeepSeek = renderBigText('DEEPSEEK', t, wordmarkRGB, taglineRGB, FLASH, 60);
93
94
  const bigHarness = renderBigText('HARNESS', t, taglineRGB, PALE, FLASH, 60);
94
- return (_jsxs(Box, { ref: ref, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 2, width: "100%", alignItems: "center", children: [showWhale && _jsx(WhaleArt, { frameIndex: frameIndex, width: FULL_WHALE_WIDTH }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] }), bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `ds-${index}`))), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `h-${index}`))), _jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: "Tip: " }), "/model", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-model'), " \u00B7 "] }), "/help", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-help'), " \u00B7 "] }), "Tab", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-tab')] })] })] })] }), _jsx(Box, { marginTop: 1, paddingLeft: showWhale ? WELCOME_PAD : 2, children: _jsx(Text, { children: sweep(tr('logo-tagline'), t, taglineRGB, FLASH, 60) }) })] }));
95
+ return (_jsxs(Box, { ref: ref, flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 2, width: "100%", alignItems: "center", children: [showWhale && _jsx(WhaleArt, { frameIndex: frameIndex, width: FULL_WHALE_WIDTH }), _jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] }), bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `ds-${index}`))), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, `h-${index}`))), _jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), "/model", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-model'), " \u00B7 "] }), "/help", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-help'), " \u00B7 "] }), `${modLabel}t`, _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-trace'), " \u00B7 "] }), "Tab", _jsxs(Text, { dimColor: true, children: [" ", tr('logo-tip-tab')] })] })] })] }), _jsx(Box, { marginTop: 1, paddingLeft: showWhale ? WELCOME_PAD : 2, children: _jsx(Text, { children: sweep(tr('logo-tagline'), t, taglineRGB, FLASH, 60) }) })] }));
95
96
  }
@@ -1,23 +1,23 @@
1
1
  import React from 'react';
2
2
  /**
3
- * Markdown renderer ported from Claude Code (the leak's `Markdown.tsx`):
4
- * marked lexer + ANSI formatter, tables rendered as flexbox-style bordered
5
- * components, async syntax highlighting via cli-highlight. The ANSI strings
6
- * render inside raw `Text` (the ported Ink core preserves ANSI in children;
7
- * the fork's `Ansi` span parser drops SGR 1 bold).
3
+ * Markdown 渲染组件:marked 分词 + ANSI 格式化。
4
+ *
5
+ * 表格 token 交给 MarkdownTable 渲染为带边框的 flexbox 布局;
6
+ * 其余块级内容由 formatToken 转成 ANSI 字符串,合并后包进单个
7
+ * Text(整段去首尾空白)。代码块高亮由 cli-highlight 异步提供,
8
+ * 加载完成后自动触发一次重渲染。无 markdown 语法的纯文本走快速
9
+ * 路径,直接合成段落 token,省掉 lexer 调用。
8
10
  */
9
11
  type Props = {
10
12
  children: string;
11
- /** When true, render all text content as dim */
13
+ /** 为 true 时全部文本内容以 dim 样式呈现 */
12
14
  dimColor?: boolean;
13
- /** False for the streaming tail (its content changes every chunk, so a
14
- * cache entry would never hit and would only pollute the token cache). */
15
+ /** 为 false 时跳过 token 缓存(流式尾部的内容逐帧变化,缓存必然失效) */
15
16
  cacheTokens?: boolean;
16
17
  };
17
18
  /**
18
- * Renders markdown content using a hybrid approach:
19
- * - Tables are rendered as bordered flexbox components
20
- * - Other content is rendered as ANSI strings via formatToken
19
+ * 混合渲染 Markdown 内容:表格用带边框的 flexbox 组件,其余内容由
20
+ * formatToken 生成 ANSI 字符串放入 Text。高亮对象异步就绪后自动刷新。
21
21
  */
22
22
  export declare function Markdown({ children, dimColor, cacheTokens }: Props): React.ReactNode;
23
23
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;;GAMG;AAEH,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;+EAC2E;IAC3E,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AA8DD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,WAAkB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAuDnG"}
1
+ {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../src/components/Markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;;;;;GAQG;AAEH,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AA4GD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAgB,EAAE,WAAkB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CA6BnG"}
@@ -5,30 +5,32 @@ import { Box, Text } from '../ui.js';
5
5
  import { configureMarked, formatToken, stripPromptXMLTags } from '../cc/markdown.js';
6
6
  import { getCliHighlightPromise } from '../cc/cliHighlight.js';
7
7
  import { MarkdownTable } from './MarkdownTable.js';
8
- // Module-level token cache — marked.lexer is the hot cost on remounts.
9
- // Messages are immutable; same content → same tokens.
8
+ // ---- token 缓存 ----
10
9
  //
11
- // Bounds: entry count alone was not enough. Token.raw/text values are
12
- // slices of the lexed input, so each entry pins its entire input string;
13
- // during streaming the input grows every frame, and the LRU kept 500
14
- // near-final snapshots ≈ 500 × message size resident (~500MB for a 1MB
15
- // message). A character budget caps retained bytes; oversized contents
16
- // skip the cache entirely (they are re-lexed on remount — rare, and
17
- // cheaper than the retention).
18
- const TOKEN_CACHE_MAX = 200;
19
- const TOKEN_CACHE_MAX_CHARS = 200_000;
20
- const TOKEN_CACHE_MAX_CONTENT = 20_000;
10
+ // marked.lexer 在组件重挂载时是最贵的开销;消息内容不可变,相同文本
11
+ // 必然产出相同 token,因此以原文为 key 缓存。
12
+ //
13
+ // 容量控制不能只看条数:Token 的 raw/text 字段是输入字符串的切片,
14
+ // 会钉住整段输入常驻内存;流式渲染时输入逐帧增长,若只按条数限流,
15
+ // LRU 会保留大量接近最终形态的快照(1MB 消息 ≈ 500 条 × 1MB ≈
16
+ // 500MB)。这里用字符预算限制保留量,超长内容干脆不缓存(重挂载时
17
+ // 重跑 lexer,极少发生且远比常驻便宜)。
18
+ const TOKEN_CACHE_CAPACITY = 200;
19
+ const TOKEN_CACHE_CHAR_BUDGET = 200_000;
20
+ const TOKEN_CACHE_MAX_SOURCE_LENGTH = 20_000;
21
21
  const tokenCache = new Map();
22
22
  let tokenCacheChars = 0;
23
- // Characters that indicate markdown syntax. If none are present, skip the
24
- // ~3ms marked.lexer call entirely — render as a single paragraph.
25
- const MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
26
- function hasMarkdownSyntax(s) {
27
- return MD_SYNTAX_RE.test(s.length > 500 ? s.slice(0, 500) : s);
23
+ // 语法探针:命中任意 markdown 结构标记才值得走 lexer;内容过长时
24
+ // 只探测开头一段,纯文本直接跳过约 3ms 的 lexer 调用。
25
+ const MD_SYNTAX_MARKERS = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
26
+ const SYNTAX_PROBE_WINDOW = 500;
27
+ function looksLikePlainText(s) {
28
+ const probe = s.length > SYNTAX_PROBE_WINDOW ? s.slice(0, SYNTAX_PROBE_WINDOW) : s;
29
+ return !MD_SYNTAX_MARKERS.test(probe);
28
30
  }
29
- function cachedLexer(content, cache) {
30
- // Fast path: plain text with no markdown syntax → single paragraph token.
31
- if (!hasMarkdownSyntax(content)) {
31
+ function lexWithCache(content, allowCache) {
32
+ // 快速路径:纯文本直接合成单个段落 token,不触碰 lexer。
33
+ if (looksLikePlainText(content)) {
32
34
  return [
33
35
  {
34
36
  type: 'paragraph',
@@ -38,23 +40,21 @@ function cachedLexer(content, cache) {
38
40
  },
39
41
  ];
40
42
  }
41
- if (!cache)
43
+ if (!allowCache)
42
44
  return marked.lexer(content);
43
- // The content string itself is the key: V8 caches the string hash in the
44
- // string header, so Map lookup is hash-free after the first insert, and
45
- // unlike sha256 there is no per-call digest allocation or collision risk.
45
+ // 直接用内容字符串做 key:V8 在字符串头缓存哈希,首次插入后 Map
46
+ // 查找无需再算哈希,也比 sha256 少一次摘要分配与碰撞风险。
46
47
  const hit = tokenCache.get(content);
47
48
  if (hit) {
48
- // Promote to MRU
49
- tokenCache.delete(content);
49
+ tokenCache.delete(content); // 提升为最近使用
50
50
  tokenCache.set(content, hit);
51
51
  return hit;
52
52
  }
53
53
  const tokens = marked.lexer(content);
54
- if (content.length > TOKEN_CACHE_MAX_CONTENT)
54
+ if (content.length > TOKEN_CACHE_MAX_SOURCE_LENGTH)
55
55
  return tokens;
56
- if (tokenCache.size >= TOKEN_CACHE_MAX ||
57
- tokenCacheChars + content.length > TOKEN_CACHE_MAX_CHARS) {
56
+ if (tokenCache.size >= TOKEN_CACHE_CAPACITY ||
57
+ tokenCacheChars + content.length > TOKEN_CACHE_CHAR_BUDGET) {
58
58
  tokenCache.clear();
59
59
  tokenCacheChars = 0;
60
60
  }
@@ -63,44 +63,50 @@ function cachedLexer(content, cache) {
63
63
  return tokens;
64
64
  }
65
65
  /**
66
- * Renders markdown content using a hybrid approach:
67
- * - Tables are rendered as bordered flexbox components
68
- * - Other content is rendered as ANSI strings via formatToken
66
+ * 把 lexer 产出的 token 列表转成 React 节点序列:table 独立渲染,
67
+ * 其余 token 的 ANSI 文本先累积拼接,再统一包成 Text(去除首尾空白)。
68
+ */
69
+ function renderTokensToNodes(tokens, highlight, dimColor) {
70
+ const nodes = [];
71
+ let ansiText = '';
72
+ const flushAnsiText = () => {
73
+ if (!ansiText)
74
+ return;
75
+ nodes.push(_jsx(Text, { dimColor: dimColor, children: ansiText.trim() }, nodes.length));
76
+ ansiText = '';
77
+ };
78
+ for (const token of tokens) {
79
+ if (token.type === 'table') {
80
+ flushAnsiText();
81
+ nodes.push(_jsx(MarkdownTable, { token: token, highlight: highlight }, nodes.length));
82
+ }
83
+ else {
84
+ ansiText += formatToken(token, 0, null, null, highlight);
85
+ }
86
+ }
87
+ flushAnsiText();
88
+ return nodes;
89
+ }
90
+ /**
91
+ * 混合渲染 Markdown 内容:表格用带边框的 flexbox 组件,其余内容由
92
+ * formatToken 生成 ANSI 字符串放入 Text。高亮对象异步就绪后自动刷新。
69
93
  */
70
94
  export function Markdown({ children, dimColor = false, cacheTokens = true }) {
71
95
  const [highlight, setHighlight] = React.useState(null);
72
96
  React.useEffect(() => {
73
- let alive = true;
97
+ let mounted = true;
74
98
  void getCliHighlightPromise().then((loaded) => {
75
- if (alive)
99
+ if (mounted)
76
100
  setHighlight(loaded);
77
101
  });
78
102
  return () => {
79
- alive = false;
103
+ mounted = false;
80
104
  };
81
105
  }, []);
82
106
  configureMarked();
83
- const elements = React.useMemo(() => {
84
- const tokens = cachedLexer(stripPromptXMLTags(children), cacheTokens);
85
- const elements = [];
86
- let nonTableContent = '';
87
- function flushNonTableContent() {
88
- if (nonTableContent) {
89
- elements.push(_jsx(Text, { dimColor: dimColor, children: nonTableContent.trim() }, elements.length));
90
- nonTableContent = '';
91
- }
92
- }
93
- for (const token of tokens) {
94
- if (token.type === 'table') {
95
- flushNonTableContent();
96
- elements.push(_jsx(MarkdownTable, { token: token, highlight: highlight }, elements.length));
97
- }
98
- else {
99
- nonTableContent += formatToken(token, 0, null, null, highlight);
100
- }
101
- }
102
- flushNonTableContent();
103
- return elements;
107
+ const renderedNodes = React.useMemo(() => {
108
+ const source = stripPromptXMLTags(children);
109
+ return renderTokensToNodes(lexWithCache(source, cacheTokens), highlight, dimColor);
104
110
  }, [children, dimColor, highlight, cacheTokens]);
105
- return (_jsx(Box, { flexDirection: "column", gap: 1, children: elements }));
111
+ return (_jsx(Box, { flexDirection: "column", gap: 1, children: renderedNodes }));
106
112
  }
@@ -9,7 +9,7 @@ type Props = {
9
9
  };
10
10
  /**
11
11
  * Renders a markdown table with proper column sizing, cell wrapping and box
12
- * borders (ported from the leak's `MarkdownTable.tsx`). Falls back to a
12
+ * borders, mirroring Claude Code's `MarkdownTable.tsx`. Falls back to a
13
13
  * vertical key-value format on narrow terminals.
14
14
  */
15
15
  export declare function MarkdownTable({ token, highlight, forceWidth, }: Props): React.ReactNode;
@@ -5,7 +5,7 @@ import Text from '../ink/components/Text.js';
5
5
  import { stringWidth } from '../ink/stringWidth.js';
6
6
  import stripAnsi from 'strip-ansi';
7
7
  import { formatToken, padAligned } from '../cc/markdown.js';
8
- /** Accounts for parent indentation and terminal resize races (from the leak). */
8
+ /** Accounts for parent indentation and terminal resize races (from Claude Code). */
9
9
  const SAFETY_MARGIN = 4;
10
10
  /** Minimum column width to prevent degenerate layouts */
11
11
  const MIN_COLUMN_WIDTH = 3;
@@ -39,7 +39,7 @@ function wrapText(text, width, options) {
39
39
  }
40
40
  /**
41
41
  * Renders a markdown table with proper column sizing, cell wrapping and box
42
- * borders (ported from the leak's `MarkdownTable.tsx`). Falls back to a
42
+ * borders, mirroring Claude Code's `MarkdownTable.tsx`. Falls back to a
43
43
  * vertical key-value format on narrow terminals.
44
44
  */
45
45
  export function MarkdownTable({ token, highlight, forceWidth, }) {
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import { type ScrollBoxHandle } from '../ui.js';
3
- import type { ChatRow } from '../channel.js';
3
+ import type { ChatRow } from '../dsh-adapter/channel.js';
4
4
  import type { DOMElement } from '../ink/dom.js';
5
- export declare function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, showAll, onToggleAll, onLoadOlder, thinkingVisible, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, }: {
5
+ export declare function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, showAll, onToggleAll, onLoadOlder, thinkingVisible, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }: {
6
6
  rows: readonly ChatRow[];
7
7
  expanded: boolean;
8
8
  expandedRows: ReadonlySet<number>;
@@ -26,6 +26,14 @@ export declare function MessageList({ rows, expanded, expandedRows, selectedId,
26
26
  newSinceRowId?: number | null;
27
27
  /** Reports how many new rows still sit below the viewport bottom edge. */
28
28
  onUnseenCount?: (count: number) => void;
29
+ /**
30
+ * Row id that should carry the trajectory footnote — the newest unseen
31
+ * failure, or null. Exactly one row ever carries it: repeating the pointer
32
+ * under every historical failure is the clutter this design avoids.
33
+ */
34
+ failureHintRowId?: number | null;
35
+ /** Footnote text, e.g. `ctrl+t for the full trajectory`. */
36
+ failureHint?: string;
29
37
  }): React.JSX.Element;
30
38
  /**
31
39
  * The header block pinned above the transcript: the DeepSeek pixel whale
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,eAAe,CAAA;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAwC/C,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,GACd,EAAE;IACD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB;2EACuE;IACvE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/D,oDAAoD;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC,qBAyOA;AAiQD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAMlB"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAyC,MAAM,2BAA2B,CAAA;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAuC/C,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAsB,EACtB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,SAAS,OAAO,EAAE,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB;2EACuE;IACvE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/D,oDAAoD;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACrC,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,qBAoPA;AAuQD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAM,EACN,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,KAAK,CAAC,SAAS,CAMlB"}
@@ -3,7 +3,6 @@ import React from 'react';
3
3
  import { t } from '../i18n.js';
4
4
  import { Box, Text, useTerminalSize } from '../ui.js';
5
5
  import { Divider } from './design-system/Divider.js';
6
- import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
7
6
  import { UserPromptMessage } from './messages/UserPromptMessage.js';
8
7
  import { AssistantTextMessage } from './messages/AssistantTextMessage.js';
9
8
  import { AssistantThinkingMessage } from './messages/AssistantThinkingMessage.js';
@@ -38,7 +37,7 @@ const DEFAULT_ROW_HEIGHT = 2;
38
37
  /** Cold-start estimate of the header block above the rows; corrected by the
39
38
  * first layout measurement. */
40
39
  const DEFAULT_HEADER_LINES = 14;
41
- export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, }) {
40
+ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggleRow, model, showAll, onToggleAll, onLoadOlder, thinkingVisible = true, registerRowRef, scrollHandle, forceMountRowId, newSinceRowId, onUnseenCount, failureHintRowId, failureHint, }) {
42
41
  const hiddenCount = rows.length - MAX_RENDERED_ROWS;
43
42
  // The thinking filter runs BEFORE virtualization so window indices line up.
44
43
  const visibleRows = (showAll || hiddenCount <= 0
@@ -78,6 +77,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
78
77
  const localRefs = React.useRef(new Map());
79
78
  /** Content-space offset of visibleRows[0] (header + dividers), measured. */
80
79
  const baseRef = React.useRef(null);
80
+ const measureQueuedRef = React.useRef(false);
81
81
  const [, setMeasureTick] = React.useState(0);
82
82
  const [, setScrollTick] = React.useState(0);
83
83
  // A width change reflows every row — all measurements are stale.
@@ -198,8 +198,15 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
198
198
  scrollHandle.setClampBounds(min, Math.max(min, base + mountedBottom - viewport));
199
199
  }
200
200
  }
201
- if (changed)
202
- setMeasureTick(t => t + 1);
201
+ if (changed && !measureQueuedRef.current) {
202
+ // Layout corrections can cascade for many rows. Yield between commits
203
+ // so React does not count the valid convergence as nested updates.
204
+ measureQueuedRef.current = true;
205
+ queueMicrotask(() => {
206
+ measureQueuedRef.current = false;
207
+ setMeasureTick(t => t + 1);
208
+ });
209
+ }
203
210
  });
204
211
  // useCallback: the reference feeds MemoRow's shallow compare; a fresh
205
212
  // closure per render would defeat every row's memo.
@@ -214,17 +221,17 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
214
221
  // Computed per render (cheap) but only forwarded to running rows, so
215
222
  // settled rows never see a changing prop.
216
223
  const nowSec = Math.floor(Date.now() / 1000);
217
- return (_jsxs(_Fragment, { children: [rows.some(row => row.folded) && (_jsx(Box, { marginTop: 1, onClick: onLoadOlder, children: _jsx(Divider, { title: t('load-earlier') }) })), !showAll && hiddenCount > 0 && (_jsx(Box, { marginTop: 1, onClick: onToggleAll, children: _jsx(Divider, { title: ` ctrl+e to show ${hiddenCount} previous messages ` }) })), topPad > 0 && _jsx(Box, { height: topPad, flexShrink: 0 }), visibleRows
224
+ return (_jsxs(_Fragment, { children: [rows.some(row => row.folded) && (_jsx(Box, { marginTop: 1, onClick: onLoadOlder, children: _jsx(Divider, { title: t('load-earlier') }) })), !showAll && hiddenCount > 0 && (_jsx(Box, { marginTop: 1, onClick: onToggleAll, children: _jsx(Divider, { title: t('show-previous-messages', { n: hiddenCount }) }) })), topPad > 0 && _jsx(Box, { height: topPad, flexShrink: 0 }), visibleRows
218
225
  .slice(start, end)
219
226
  .map((row) => {
220
227
  // CC addMargin: pre-pass result keeps windowed rows at full-mount
221
228
  // spacing; only the very first row of the whole list has none.
222
229
  const addMargin = margins.get(row.id) === true;
223
230
  const tool = row.tool;
224
- return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: row.text, 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, 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, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
231
+ 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, 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, nowSec: tool?.status === 'running' ? nowSec : undefined, onToggleRow: onToggleRow, setRowRef: setRowRef }, row.id));
225
232
  }), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
226
233
  }
227
- function TranscriptRow({ rowId, kind, text, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
234
+ function TranscriptRow({ rowId, kind, text, executionTarget, streaming, durationMs, time, addMargin, isSelected, isExpanded, expanded, model, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, onToggleRow, setRowRef, }) {
228
235
  const ref = React.useCallback((el) => {
229
236
  setRowRef(rowId, el);
230
237
  }, [setRowRef, rowId]);
@@ -266,7 +273,7 @@ function TranscriptRow({ rowId, kind, text, streaming, durationMs, time, addMarg
266
273
  startedAt: toolStartedAt,
267
274
  durationMs: toolDurationMs,
268
275
  };
269
- return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded }) }));
276
+ return (_jsx(Box, { flexDirection: "column", ref: ref, children: _jsx(AssistantToolUseMessage, { tool: tool, addMargin: addMargin, verbose: isExpanded || expanded, isSelected: isSelected, isExpanded: isExpanded, footnote: toolFootnote }) }));
270
277
  }
271
278
  case 'notice':
272
279
  return (_jsx(Box, { marginTop: 1, ref: ref, children: _jsx(Divider, { title: ` ${text} ` }) }));
@@ -274,14 +281,14 @@ function TranscriptRow({ rowId, kind, text, streaming, durationMs, time, addMarg
274
281
  return (_jsx(Box, { marginTop: 1, ref: ref, children: _jsx(InterruptedByUser, {}) }));
275
282
  case 'local':
276
283
  // `!` mode command echo, like CC's UserBashInputMessage.
277
- return (_jsx(Box, { marginTop: 1, backgroundColor: background, ref: ref, children: _jsxs(Text, { color: "bashBorder", children: ["! ", text] }) }));
284
+ return (_jsx(Box, { marginTop: 1, backgroundColor: background, ref: ref, children: _jsxs(Text, { color: "bashBorder", children: ["!", executionTarget ? ` [${executionTarget}]` : '', " ", text] }) }));
278
285
  case 'local-output':
279
286
  return (_jsx(Box, { paddingLeft: 2, backgroundColor: background, ref: ref, children: _jsx(Text, { dimColor: true, children: text }) }));
280
287
  case 'compact':
281
288
  // The post-compaction summary defaults to a folded one-liner with a
282
289
  // text preview; Ctrl+O (global) or message-selection Enter reveals
283
290
  // the full summary.
284
- return (_jsx(Box, { marginTop: addMargin ? 1 : 0, paddingLeft: 2, backgroundColor: background, ref: ref, onClick: onClick, children: expanded || isExpanded ? (_jsx(Text, { dimColor: true, children: text })) : (_jsxs(Text, { dimColor: true, italic: true, children: ["\u2234 ", t('compact-summary-folded'), " \u00B7 ", compactPreview(text), ' ', _jsx(KeyboardShortcutHint, { shortcut: "ctrl+o", action: "expand", parens: true })] })) }));
291
+ return (_jsx(Box, { marginTop: addMargin ? 1 : 0, paddingLeft: 2, backgroundColor: background, ref: ref, onClick: onClick, children: expanded || isExpanded ? (_jsx(Text, { dimColor: true, children: text })) : (_jsxs(Text, { dimColor: true, italic: true, children: ["\u2234 ", t('compact-summary-folded'), " \u00B7 ", compactPreview(text), ' ', t('hint-expand-ctrl-o')] })) }));
285
292
  }
286
293
  }
287
294
  /** Folded compact-summary preview: whitespace flattened, capped with an
@@ -1,10 +1,13 @@
1
1
  import React from 'react';
2
- import type { LlmModelInfo } from '@deepseek-ai/dsh-llm';
2
+ import type { LlmModelInfo } from '../dsh-adapter/types.js';
3
3
  /**
4
4
  * Model picker in the CC ModelPicker style: a permission-colored Pane with
5
5
  * the model list as Select rows (❯ focus pointer, ✓ on the active model,
6
6
  * descriptions), plus the Enter/Esc hint line. The DSH agent's model is
7
7
  * fixed at creation time, so a selection notifies "restart to apply".
8
+ *
9
+ * 长列表按焦点窗口化(Select 同款):picker 经 OverlayAbove 浮层挂载后有
10
+ * maxHeight 裁剪,全量渲染会让焦点行被裁掉(看不到焦点按 Enter)。
8
11
  */
9
12
  export declare function ModelPicker({ models, focusIndex, currentModel, }: {
10
13
  models: readonly LlmModelInfo[];
@@ -1 +1 @@
1
- {"version":3,"file":"ModelPicker.d.ts","sourceRoot":"","sources":["../../../src/components/ModelPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAMxD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,GACb,EAAE;IACD,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,KAAK,CAAC,SAAS,CA4BlB"}
1
+ {"version":3,"file":"ModelPicker.d.ts","sourceRoot":"","sources":["../../../src/components/ModelPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAM3D;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,UAAU,EACV,YAAY,GACb,EAAE;IACD,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,KAAK,CAAC,SAAS,CAuClB"}
@@ -1,15 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from '../ui.js';
2
+ import { t } from '../i18n.js';
3
+ import { Box, Text, useTerminalSize } from '../ui.js';
3
4
  import { Pane } from './design-system/Pane.js';
4
5
  import { ListItem } from './design-system/ListItem.js';
5
- import { Byline } from './design-system/Byline.js';
6
- import { KeyboardShortcutHint } from './design-system/KeyboardShortcutHint.js';
6
+ import { HintLine } from './design-system/HintLine.js';
7
+ import { listWindow } from './listWindow.js';
7
8
  /**
8
9
  * Model picker in the CC ModelPicker style: a permission-colored Pane with
9
10
  * the model list as Select rows (❯ focus pointer, ✓ on the active model,
10
11
  * descriptions), plus the Enter/Esc hint line. The DSH agent's model is
11
12
  * fixed at creation time, so a selection notifies "restart to apply".
13
+ *
14
+ * 长列表按焦点窗口化(Select 同款):picker 经 OverlayAbove 浮层挂载后有
15
+ * maxHeight 裁剪,全量渲染会让焦点行被裁掉(看不到焦点按 Enter)。
12
16
  */
13
17
  export function ModelPicker({ models, focusIndex, currentModel, }) {
14
- return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: "Model" }) }), models.map((model, index) => (_jsxs(ListItem, { isFocused: index === focusIndex, isSelected: `${model.provider}/${model.id}` === currentModel, description: model.description, children: [model.provider, " / ", model.name] }, `${model.provider}/${model.id}`)))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsxs(Byline, { children: [_jsx(KeyboardShortcutHint, { shortcut: "Enter", action: "confirm", bold: true }), _jsx(KeyboardShortcutHint, { shortcut: "Esc", action: "exit" })] }) })] }));
18
+ const { rows: terminalRows } = useTerminalSize();
19
+ // 焦点窗口化按行预算:ListItem 带 description 时占 2 行(正文+描述,均
20
+ // truncate 成单行),只数项数会把焦点裁出浮层(二次审查实证)。
21
+ // 框架行:浮层预留 8 + Pane 2 + 标题 2 + 页脚 1 = 13。
22
+ const { start, end } = listWindow(models.map(m => (m.description ? 2 : 1)), focusIndex, Math.max(terminalRows - 13, 2));
23
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('picker-title-model') }) }), models.slice(start, end).map((model, index) => {
24
+ const absoluteIndex = start + index;
25
+ return (_jsxs(ListItem, { isFocused: absoluteIndex === focusIndex, isSelected: `${model.provider}/${model.id}` === currentModel, description: model.description, showScrollUp: absoluteIndex === start && start > 0, showScrollDown: absoluteIndex === end - 1 && end < models.length, children: [model.provider, " / ", model.name] }, `${model.provider}/${model.id}`));
26
+ })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) })] }));
15
27
  }